Skip to content

Commit 252aa45

Browse files
Fix tests
1 parent da41fdb commit 252aa45

13 files changed

+190
-46
lines changed

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"author": "USER_NAME",
88
"main": "src",
99
"engines": {
10-
"node": ">=10"
10+
"node": ">=12"
1111
},
1212
"scripts": {
1313
"version": "conventional-changelog -i changelog.md -s -r 0 && git add changelog.md",

Diff for: readme.md

+22-22
Original file line numberDiff line numberDiff line change
@@ -69,28 +69,28 @@ Result:
6969

7070
## Options
7171

72-
| Option | Default | Description |
73-
|:------------------------:|:---------------------------------:|:---------------------------------------------------------------------------------------------------------------|
74-
| **root** | `'./'` | String value as root path for components lookup. |
75-
| **roots** | `''` | Array of additional multi roots path from `options.root`. |
76-
| **namespaces** | `[]` | Array of namespace's root path, fallback path and custom path for override. |
77-
| **namespaceSeparator** | `::` | String value for namespace separator to be used with tag name. Example `<x-namespace::button>` |
78-
| **namespaceFallback** | `false` | Boolean value for use fallback path to defined roots in `options.roots`. |
79-
| **fileExtension** | `html` | String value for file extension of the components used for retrieve x-tag file. |
80-
| **tagPrefix** | `x-` | String for tag prefix. |
81-
| **tagRegExp** | `new RegExp('^x-'), 'i')` | Object for regex used to match x-tag. Set only `options.tagPrefix` to keep default. |
82-
| **slotTagName** | `slot` | String value for slot tag name. |
83-
| **fallbackSlotTagName** | `false` | Boolean or string value used to support posthtml-modules slot. Set to true to use `<content>` or set a string. |
84-
| **tagName** | `component` | String value for component tag. |
85-
| **tagNames** | `[]` | Array of additional component tag. Useful if you are migrating from extend and modules. |
86-
| **attribute** | `src` | String value for component attribute for set path. |
87-
| **attributes** | `[]` | Array of additional component path to be used for migrating from extend and modules. |
88-
| **expressions** | `{}` | Object to configure `posthtml-expressions`. You can pre-set locals or customize the delimiters for example. |
89-
| **plugins** | `[]` | PostHTML plugins to apply for every parsed components. |
90-
| **encoding** | `utf8` | String value for the encoding of the component. |
91-
| **scriptLocalAttribute** | `defaultLocals` | String value for set custom attribute parsed by the plugin to retrieve default locals in the components. |
92-
| **matcher** | `[]` | Array of object used to match the tags. Useful if you are migrating from extend and modules. |
93-
| **strict** | `true` | Boolean value for enable or disable throw an exception. |
72+
| Option | Default | Description |
73+
|:------------------------:|:-------------------------:|:---------------------------------------------------------------------------------------------------------------|
74+
| **root** | `'./'` | String value as root path for components lookup. |
75+
| **roots** | `''` | Array of additional multi roots path from `options.root`. |
76+
| **namespaces** | `[]` | Array of namespace's root path, fallback path and custom path for override. |
77+
| **namespaceSeparator** | `::` | String value for namespace separator to be used with tag name. Example `<x-namespace::button>` |
78+
| **namespaceFallback** | `false` | Boolean value for use fallback path to defined roots in `options.roots`. |
79+
| **fileExtension** | `html` | String value for file extension of the components used for retrieve x-tag file. |
80+
| **tagPrefix** | `x-` | String for tag prefix. |
81+
| **tagRegExp** | `new RegExp('^x-'), 'i')` | Object for regex used to match x-tag. Set only `options.tagPrefix` to keep default. |
82+
| **slotTagName** | `slot` | String value for slot tag name. |
83+
| **fallbackSlotTagName** | `false` | Boolean or string value used to support posthtml-modules slot. Set to true to use `<content>` or set a string. |
84+
| **tagName** | `component` | String value for component tag. |
85+
| **tagNames** | `[]` | Array of additional component tag. Useful if you are migrating from extend and modules. |
86+
| **attribute** | `src` | String value for component attribute for set path. |
87+
| **attributes** | `[]` | Array of additional component path to be used for migrating from extend and modules. |
88+
| **expressions** | `{}` | Object to configure `posthtml-expressions`. You can pre-set locals or customize the delimiters for example. |
89+
| **plugins** | `[]` | PostHTML plugins to apply for every parsed components. |
90+
| **encoding** | `utf8` | String value for the encoding of the component. |
91+
| **scriptLocalAttribute** | `props` | String value for set custom attribute parsed by the plugin to retrieve locals in the components. |
92+
| **matcher** | `[]` | Array of object used to match the tags. Useful if you are migrating from extend and modules. |
93+
| **strict** | `true` | Boolean value for enable or disable throw an exception. |
9494

9595
## Feature
9696

Diff for: src/index.js

+25-17
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ function processNodes(tree, options, messages) {
5353

5454
const html = parseToPostHtml(fs.readFileSync(filePath, options.encoding));
5555

56-
options.expressions.locals = {...options.locals}
56+
options.expressions.locals = {...options.locals};
5757

58-
const {attributes, locals} = parseLocals(options, node, html);
58+
const slotsLocals = parseSlotsLocals(options.slotTagName, html, node.content);
59+
const {attributes, locals} = parseLocals(options, slotsLocals, node, html);
5960

6061
options.expressions.locals = attributes;
61-
62-
options.expressions.locals.$slots = parseSlotsLocals(options.slotTagName, html, node.content);
62+
options.expressions.locals.$slots = slotsLocals;
6363

6464
const plugins = [...options.plugins, expressions(options.expressions)];
6565

@@ -82,9 +82,10 @@ function processNodes(tree, options, messages) {
8282
if (typeof nodeAttrs[attr] === 'undefined') {
8383
nodeAttrs[attr] = [];
8484
}
85+
8586
nodeAttrs[attr].push(attributes[attr]);
8687
} else if (['style'].includes(attr)) {
87-
// TODO append style ?
88+
// Append style ?
8889
nodeAttrs[attr] = attributes[attr];
8990
}
9091
}
@@ -107,12 +108,13 @@ function processNodes(tree, options, messages) {
107108

108109
/**
109110
* Parse locals from attributes, globals and via script
110-
* @param {Object} options - plugin options
111+
* @param {Object} options - Plugin options
112+
* @param {Object} slotsLocals - Slot locals
111113
* @param {Object} tree - PostHTML Node
112114
* @param {Array} html - PostHTML Tree Nodes
113-
* @return {Object} merged locals and default
115+
* @return {Object} - Merged locals and default
114116
*/
115-
function parseLocals(options, {attrs}, html) {
117+
function parseLocals(options, slotsLocals, {attrs}, html) {
116118
let attributes = {...attrs};
117119

118120
// Handle attributes to be merged with default
@@ -141,6 +143,7 @@ function parseLocals(options, {attrs}, html) {
141143
if (attribute === 'locals') {
142144
if (mergeAttributeWithDefault.includes(attribute)) {
143145
attributes = merge(attributes, parsed);
146+
mergeAttributeWithDefault.splice(mergeAttributeWithDefault.indexOf('locals'), 1);
144147
} else {
145148
Object.assign(attributes, parsed);
146149
}
@@ -155,8 +158,8 @@ function parseLocals(options, {attrs}, html) {
155158
// Merge with global
156159
attributes = merge(options.expressions.locals, attributes);
157160

158-
// Retrieve default locals from <script defaultLocals> and merge with attributes
159-
const {locals} = scriptDataLocals(html, {localsAttr: options.scriptLocalAttribute, removeScriptLocals: true, locals: {...attributes}});
161+
// Retrieve default locals from <script props> and merge with attributes
162+
const {locals} = scriptDataLocals(html, {localsAttr: options.scriptLocalAttribute, removeScriptLocals: true, locals: {...attributes, $slots: slotsLocals}});
160163

161164
// Merge default locals and attributes
162165
// or overrides locals with attributes
@@ -165,7 +168,12 @@ function parseLocals(options, {attrs}, html) {
165168
const attributesToBeMerged = Object.fromEntries(Object.entries(attributes).filter(([attribute]) => mergeAttributeWithDefault.includes(attribute)));
166169
const localsToBeMerged = Object.fromEntries(Object.entries(locals).filter(([local]) => mergeAttributeWithDefault.includes(local)));
167170
if (Object.keys(localsToBeMerged).length > 0) {
171+
console.log({localsToBeMerged, attributesToBeMerged});
172+
console.log(attributes);
168173
mergeAttributeWithDefault.forEach(attribute => {
174+
console.log(attribute);
175+
console.log(typeof localsToBeMerged[attribute]);
176+
console.log(typeof attributesToBeMerged[attribute]);
169177
attributes[attribute] = merge(localsToBeMerged[attribute], attributesToBeMerged[attribute]);
170178
});
171179
}
@@ -189,8 +197,9 @@ function parseLocals(options, {attrs}, html) {
189197
* @return {Object}
190198
*/
191199
function parseSlotsLocals(tag, html, content = []) {
192-
const slots = [];
193-
const getNodeName = (node) => {
200+
const slots = {};
201+
202+
const getNodeName = node => {
194203
let name = node.attrs && node.attrs.name;
195204

196205
if (!name) {
@@ -202,7 +211,7 @@ function parseSlotsLocals(tag, html, content = []) {
202211
}
203212

204213
return name;
205-
}
214+
};
206215

207216
match.call(html, {tag}, node => {
208217
const name = getNodeName(node);
@@ -230,7 +239,7 @@ function parseSlotsLocals(tag, html, content = []) {
230239

231240
slots[name] = {
232241
filled: true,
233-
locals: locals
242+
locals
234243
};
235244

236245
return node;
@@ -293,7 +302,6 @@ function mergeSlots(tree, node, strict, {slotTagName, fallbackSlotTagName}) {
293302
);
294303
}
295304

296-
297305
delete fillSlots[slotName];
298306
}
299307

@@ -410,7 +418,7 @@ module.exports = (options = {}) => {
410418
expressions: {},
411419
plugins: [],
412420
encoding: 'utf8',
413-
scriptLocalAttribute: 'defaultLocals',
421+
scriptLocalAttribute: 'props',
414422
matcher: [],
415423
strict: true
416424
},
@@ -470,7 +478,7 @@ module.exports = (options = {}) => {
470478
}
471479
}
472480

473-
options.locals = {...options.expressions.locals}
481+
options.locals = {...options.expressions.locals};
474482

475483
return function (tree) {
476484
tree = processNodes(tree, options, tree.messages);

Diff for: test/templates/components/child.html

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<script props>
2+
module.exports = {
3+
aBoolean: true,
4+
aString: 'My String',
5+
aString2: locals.aString2 === 'yes' ? 'I am string 2' : 'I am not string 2',
6+
anArray: ['one', 'two', 'three'],
7+
anArray2: ['one2', 'two2', 'three2'],
8+
anObject: { one: 'One', two: 'Two', three: 'Three'},
9+
anObject2: { one: 'One2', two: 'Two2', three: 'Three2'}
10+
};
11+
</script>
12+
<div>
13+
aBoolean
14+
value: {{ aBoolean }}
15+
type: {{ typeof aBoolean }}
16+
17+
aString
18+
value: {{ aString }}
19+
type: {{ typeof aString }}
20+
21+
aString2
22+
value: {{ aString2 }}
23+
type: {{ typeof aString2 }}
24+
25+
anArray
26+
value: {{ anArray }}
27+
type: {{ typeof anArray }}
28+
29+
anObject
30+
value: {{ anObject }}
31+
type: {{ typeof anObject }}
32+
33+
anArray2
34+
value: {{ anArray2 }}
35+
type: {{ typeof anArray2 }}
36+
37+
anObject2
38+
value: {{ anObject2 }}
39+
type: {{ typeof anObject2 }}
40+
</div>
41+
42+
<if condition="$slots.child.filled">
43+
<slot child></slot>
44+
</if>
45+
46+
<else>
47+
<slot></slot>
48+
</else>

Diff for: test/templates/components/component-locals-json-and-string.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<script defaultLocals>
1+
<script props>
22
module.exports = {
33
title: 'Default title',
44
items: ['default first item', 'default second item'],

Diff for: test/templates/components/component-locals.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<script defaultLocals>
1+
<script props>
22
module.exports = {
33
title: 'Default title',
44
body: 'Default body'

Diff for: test/templates/components/component-mapped-attributes.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<script defaultLocals>
1+
<script props>
22
module.exports = {
33
title: 'Default title',
44
body: 'Default body'

Diff for: test/templates/components/parent.html

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<script props>
2+
module.exports = {
3+
aBoolean: true,
4+
aString: 'My String',
5+
aString2: locals.aString2 === 'yes' ? 'I am string 2' : 'I am not string 2',
6+
anArray: ['one', 'two', 'three'],
7+
anArray2: ['one2', 'two2', 'three2'],
8+
anObject: { one: 'One', two: 'Two', three: 'Three'},
9+
anObject2: { one: 'One2', two: 'Two2', three: 'Three2'}
10+
};
11+
</script>
12+
PARENT:
13+
<div>
14+
aBoolean
15+
value: {{ aBoolean }}
16+
type: {{ typeof aBoolean }}
17+
18+
aString
19+
value: {{ aString }}
20+
type: {{ typeof aString }}
21+
22+
aString2
23+
value: {{ aString2 }}
24+
type: {{ typeof aString2 }}
25+
26+
anArray
27+
value: {{ anArray }}
28+
type: {{ typeof anArray }}
29+
30+
anObject
31+
value: {{ anObject }}
32+
type: {{ typeof anObject }}
33+
34+
anArray2
35+
value: {{ anArray2 }}
36+
type: {{ typeof anArray2 }}
37+
38+
anObject2
39+
value: {{ anObject2 }}
40+
type: {{ typeof anObject2 }}
41+
</div>
42+
43+
<if condition="$slots.child.filled">
44+
<x-child
45+
aBoolean="{{ typeof $slots.child.locals?.aBoolean !== 'undefined' ? $slots.child.locals.aBoolean : aBoolean }}"
46+
aString="{{ $slots.child.locals?.aString || aString }}"
47+
>
48+
<slot child></slot>
49+
</x-child>
50+
</if>
51+
<else>
52+
<slot></slot>
53+
</else>

Diff for: test/templates/components/script-locals.html

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script props>
2+
module.exports = {
3+
hasSlot: locals.$slots
4+
};
5+
</script>
6+
{{hasSlot}}{{typeof hasSlot}}
7+
{{$slots}}{{typeof $slots}}
8+
<div><slot first></slot><slot second></slot></div>

Diff for: test/templates/layouts/base-locals.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<script defaultLocals>
1+
<script props>
22
module.exports = {
33
title: 'Default title'
44
}

Diff for: test/templates/layouts/slot-condition.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<head><title>Slot Condition Layout</title></head>
33
<body>
44
<main><slot name="content"></slot></main>
5-
<if condition="slots.footer"><footer><slot name="footer">footer content</slot></footer></if>
5+
<if condition="$slots.footer.filled"><footer><slot name="footer">footer content</slot></footer></if>
66
<else><p>There is not footer defined.</p></else>
77
</body>
88
</html>

Diff for: test/test-locals.js

+27
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,30 @@ test('Must process component with locals as JSON and string', async t => {
4747

4848
t.is(html, expected);
4949
});
50+
51+
test('Must process parent and child locals via component', async t => {
52+
const actual = `<x-parent aString="I am custom aString for PARENT via component (1)"><x-child></x-child></x-parent>`;
53+
const expected = `PARENT:<div> aBoolean value: true type: boolean aString value: I am custom aString for PARENT via component (1) type: string aString2 value: I am not string 2 type: string anArray value: ["one","two","three"] type: object anObject value: {"one":"One","two":"Two","three":"Three"} type: object anArray2 value: ["one2","two2","three2"] type: object anObject2 value: {"one":"One2","two":"Two2","three":"Three2"} type: object</div> <div> aBoolean value: true type: boolean aString value: My String type: string aString2 value: I am not string 2 type: string anArray value: ["one","two","three"] type: object anObject value: {"one":"One","two":"Two","three":"Three"} type: object anArray2 value: ["one2","two2","three2"] type: object anObject2 value: {"one":"One2","two":"Two2","three":"Three2"} type: object</div>`;
54+
55+
const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
56+
57+
t.is(html, expected);
58+
});
59+
60+
test('Must process parent and child locals via slots', async t => {
61+
const actual = `<x-parent aString="I am custom aString for PARENT via component (1)"><slot name="child"></slot></x-parent>`;
62+
const expected = `PARENT:<div> aBoolean value: true type: boolean aString value: I am custom aString for PARENT via component (1) type: string aString2 value: I am not string 2 type: string anArray value: ["one","two","three"] type: object anObject value: {"one":"One","two":"Two","three":"Three"} type: object anArray2 value: ["one2","two2","three2"] type: object anObject2 value: {"one":"One2","two":"Two2","three":"Three2"} type: object</div> <div> aBoolean value: true type: boolean aString value: I am custom aString for PARENT via component (1) type: string aString2 value: I am not string 2 type: string anArray value: ["one","two","three"] type: object anObject value: {"one":"One","two":"Two","three":"Three"} type: object anArray2 value: ["one2","two2","three2"] type: object anObject2 value: {"one":"One2","two":"Two2","three":"Three2"} type: object</div>`;
63+
64+
const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
65+
66+
t.is(html, expected);
67+
});
68+
69+
test('Must has access to $slots in script locals', async t => {
70+
const actual = `<x-script-locals><slot first>first slot content...</slot></x-script-locals>`;
71+
const expected = `{"first":{"filled":true,"locals":{}},"second":{"filled":false}}object{"first":{"filled":true,"locals":{}},"second":{"filled":false}}object<div>first slot content...</div>`;
72+
73+
const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
74+
75+
t.is(html, expected);
76+
});

Diff for: test/test-slots.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ test('Must process with slots using shorthands names and types syntax together',
6969
});
7070

7171
test('Must process with default slot', async t => {
72-
const actual = `<component src="layouts/default-slot.html"><slot>Default Slot Content</slot><slot footer>Footer</slot></component>`;
72+
const actual = `<component src="layouts/default-slot.html">Default Slot Content<slot footer>Footer</slot></component>`;
7373
const expected = `<html><head><title>Default Slot Layout</title></head><body><main>Default Slot Content</main><footer>Footer</footer></body></html>`;
7474

7575
const html = await posthtml([plugin({root: './test/templates'})]).process(actual).then(result => clean(result.html));

0 commit comments

Comments
 (0)