Skip to content

Commit

Permalink
Fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
thewebartisan7 committed Oct 15, 2022
1 parent da41fdb commit 252aa45
Show file tree
Hide file tree
Showing 13 changed files with 190 additions and 46 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"author": "USER_NAME",
"main": "src",
"engines": {
"node": ">=10"
"node": ">=12"
},
"scripts": {
"version": "conventional-changelog -i changelog.md -s -r 0 && git add changelog.md",
Expand Down
44 changes: 22 additions & 22 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,28 +69,28 @@ Result:

## Options

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

## Feature

Expand Down
42 changes: 25 additions & 17 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ function processNodes(tree, options, messages) {

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

options.expressions.locals = {...options.locals}
options.expressions.locals = {...options.locals};

const {attributes, locals} = parseLocals(options, node, html);
const slotsLocals = parseSlotsLocals(options.slotTagName, html, node.content);
const {attributes, locals} = parseLocals(options, slotsLocals, node, html);

options.expressions.locals = attributes;

options.expressions.locals.$slots = parseSlotsLocals(options.slotTagName, html, node.content);
options.expressions.locals.$slots = slotsLocals;

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

Expand All @@ -82,9 +82,10 @@ function processNodes(tree, options, messages) {
if (typeof nodeAttrs[attr] === 'undefined') {
nodeAttrs[attr] = [];
}

nodeAttrs[attr].push(attributes[attr]);
} else if (['style'].includes(attr)) {
// TODO append style ?
// Append style ?
nodeAttrs[attr] = attributes[attr];
}
}
Expand All @@ -107,12 +108,13 @@ function processNodes(tree, options, messages) {

/**
* Parse locals from attributes, globals and via script
* @param {Object} options - plugin options
* @param {Object} options - Plugin options
* @param {Object} slotsLocals - Slot locals
* @param {Object} tree - PostHTML Node
* @param {Array} html - PostHTML Tree Nodes
* @return {Object} merged locals and default
* @return {Object} - Merged locals and default
*/
function parseLocals(options, {attrs}, html) {
function parseLocals(options, slotsLocals, {attrs}, html) {
let attributes = {...attrs};

// Handle attributes to be merged with default
Expand Down Expand Up @@ -141,6 +143,7 @@ function parseLocals(options, {attrs}, html) {
if (attribute === 'locals') {
if (mergeAttributeWithDefault.includes(attribute)) {
attributes = merge(attributes, parsed);
mergeAttributeWithDefault.splice(mergeAttributeWithDefault.indexOf('locals'), 1);
} else {
Object.assign(attributes, parsed);
}
Expand All @@ -155,8 +158,8 @@ function parseLocals(options, {attrs}, html) {
// Merge with global
attributes = merge(options.expressions.locals, attributes);

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

// Merge default locals and attributes
// or overrides locals with attributes
Expand All @@ -165,7 +168,12 @@ function parseLocals(options, {attrs}, html) {
const attributesToBeMerged = Object.fromEntries(Object.entries(attributes).filter(([attribute]) => mergeAttributeWithDefault.includes(attribute)));
const localsToBeMerged = Object.fromEntries(Object.entries(locals).filter(([local]) => mergeAttributeWithDefault.includes(local)));
if (Object.keys(localsToBeMerged).length > 0) {
console.log({localsToBeMerged, attributesToBeMerged});
console.log(attributes);
mergeAttributeWithDefault.forEach(attribute => {
console.log(attribute);
console.log(typeof localsToBeMerged[attribute]);
console.log(typeof attributesToBeMerged[attribute]);
attributes[attribute] = merge(localsToBeMerged[attribute], attributesToBeMerged[attribute]);
});
}
Expand All @@ -189,8 +197,9 @@ function parseLocals(options, {attrs}, html) {
* @return {Object}
*/
function parseSlotsLocals(tag, html, content = []) {
const slots = [];
const getNodeName = (node) => {
const slots = {};

const getNodeName = node => {
let name = node.attrs && node.attrs.name;

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

return name;
}
};

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

slots[name] = {
filled: true,
locals: locals
locals
};

return node;
Expand Down Expand Up @@ -293,7 +302,6 @@ function mergeSlots(tree, node, strict, {slotTagName, fallbackSlotTagName}) {
);
}


delete fillSlots[slotName];
}

Expand Down Expand Up @@ -410,7 +418,7 @@ module.exports = (options = {}) => {
expressions: {},
plugins: [],
encoding: 'utf8',
scriptLocalAttribute: 'defaultLocals',
scriptLocalAttribute: 'props',
matcher: [],
strict: true
},
Expand Down Expand Up @@ -470,7 +478,7 @@ module.exports = (options = {}) => {
}
}

options.locals = {...options.expressions.locals}
options.locals = {...options.expressions.locals};

return function (tree) {
tree = processNodes(tree, options, tree.messages);
Expand Down
48 changes: 48 additions & 0 deletions test/templates/components/child.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<script props>
module.exports = {
aBoolean: true,
aString: 'My String',
aString2: locals.aString2 === 'yes' ? 'I am string 2' : 'I am not string 2',
anArray: ['one', 'two', 'three'],
anArray2: ['one2', 'two2', 'three2'],
anObject: { one: 'One', two: 'Two', three: 'Three'},
anObject2: { one: 'One2', two: 'Two2', three: 'Three2'}
};
</script>
<div>
aBoolean
value: {{ aBoolean }}
type: {{ typeof aBoolean }}

aString
value: {{ aString }}
type: {{ typeof aString }}

aString2
value: {{ aString2 }}
type: {{ typeof aString2 }}

anArray
value: {{ anArray }}
type: {{ typeof anArray }}

anObject
value: {{ anObject }}
type: {{ typeof anObject }}

anArray2
value: {{ anArray2 }}
type: {{ typeof anArray2 }}

anObject2
value: {{ anObject2 }}
type: {{ typeof anObject2 }}
</div>

<if condition="$slots.child.filled">
<slot child></slot>
</if>

<else>
<slot></slot>
</else>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<script defaultLocals>
<script props>
module.exports = {
title: 'Default title',
items: ['default first item', 'default second item'],
Expand Down
2 changes: 1 addition & 1 deletion test/templates/components/component-locals.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<script defaultLocals>
<script props>
module.exports = {
title: 'Default title',
body: 'Default body'
Expand Down
2 changes: 1 addition & 1 deletion test/templates/components/component-mapped-attributes.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<script defaultLocals>
<script props>
module.exports = {
title: 'Default title',
body: 'Default body'
Expand Down
53 changes: 53 additions & 0 deletions test/templates/components/parent.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<script props>
module.exports = {
aBoolean: true,
aString: 'My String',
aString2: locals.aString2 === 'yes' ? 'I am string 2' : 'I am not string 2',
anArray: ['one', 'two', 'three'],
anArray2: ['one2', 'two2', 'three2'],
anObject: { one: 'One', two: 'Two', three: 'Three'},
anObject2: { one: 'One2', two: 'Two2', three: 'Three2'}
};
</script>
PARENT:
<div>
aBoolean
value: {{ aBoolean }}
type: {{ typeof aBoolean }}

aString
value: {{ aString }}
type: {{ typeof aString }}

aString2
value: {{ aString2 }}
type: {{ typeof aString2 }}

anArray
value: {{ anArray }}
type: {{ typeof anArray }}

anObject
value: {{ anObject }}
type: {{ typeof anObject }}

anArray2
value: {{ anArray2 }}
type: {{ typeof anArray2 }}

anObject2
value: {{ anObject2 }}
type: {{ typeof anObject2 }}
</div>

<if condition="$slots.child.filled">
<x-child
aBoolean="{{ typeof $slots.child.locals?.aBoolean !== 'undefined' ? $slots.child.locals.aBoolean : aBoolean }}"
aString="{{ $slots.child.locals?.aString || aString }}"
>
<slot child></slot>
</x-child>
</if>
<else>
<slot></slot>
</else>
8 changes: 8 additions & 0 deletions test/templates/components/script-locals.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script props>
module.exports = {
hasSlot: locals.$slots
};
</script>
{{hasSlot}}{{typeof hasSlot}}
{{$slots}}{{typeof $slots}}
<div><slot first></slot><slot second></slot></div>
2 changes: 1 addition & 1 deletion test/templates/layouts/base-locals.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<script defaultLocals>
<script props>
module.exports = {
title: 'Default title'
}
Expand Down
2 changes: 1 addition & 1 deletion test/templates/layouts/slot-condition.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<head><title>Slot Condition Layout</title></head>
<body>
<main><slot name="content"></slot></main>
<if condition="slots.footer"><footer><slot name="footer">footer content</slot></footer></if>
<if condition="$slots.footer.filled"><footer><slot name="footer">footer content</slot></footer></if>
<else><p>There is not footer defined.</p></else>
</body>
</html>
27 changes: 27 additions & 0 deletions test/test-locals.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,30 @@ test('Must process component with locals as JSON and string', async t => {

t.is(html, expected);
});

test('Must process parent and child locals via component', async t => {
const actual = `<x-parent aString="I am custom aString for PARENT via component (1)"><x-child></x-child></x-parent>`;
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>`;

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

t.is(html, expected);
});

test('Must process parent and child locals via slots', async t => {
const actual = `<x-parent aString="I am custom aString for PARENT via component (1)"><slot name="child"></slot></x-parent>`;
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>`;

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

t.is(html, expected);
});

test('Must has access to $slots in script locals', async t => {
const actual = `<x-script-locals><slot first>first slot content...</slot></x-script-locals>`;
const expected = `{"first":{"filled":true,"locals":{}},"second":{"filled":false}}object{"first":{"filled":true,"locals":{}},"second":{"filled":false}}object<div>first slot content...</div>`;

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

t.is(html, expected);
});
2 changes: 1 addition & 1 deletion test/test-slots.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ test('Must process with slots using shorthands names and types syntax together',
});

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

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

0 comments on commit 252aa45

Please sign in to comment.