diff --git a/readme.md b/readme.md index b11f3dd..2aed774 100644 --- a/readme.md +++ b/readme.md @@ -111,4 +111,4 @@ See [PostHTML Guidelines](https://github.com/posthtml/posthtml/tree/master/docs) ## Credits -Thanks to all PostHTML contributors and especially to `posthtml-extends` and `posthtml-modules` contributors, as part of code are ~~stolen~~ borrowed from these plugins. +Thanks to all PostHTML contributors and especially to `posthtml-extend` and `posthtml-modules` contributors, as part of code are ~~stolen~~ borrowed from these plugins. diff --git a/src/index.js b/src/index.js index 83e5409..d2b9509 100644 --- a/src/index.js +++ b/src/index.js @@ -53,7 +53,7 @@ function processNodes(tree, options, messages) { const html = parseToPostHtml(fs.readFileSync(filePath, options.encoding)); - const {attributes, defaultLocals} = parseLocals(options, node, html); + const {attributes, locals} = parseLocals(options, node, html); options.expressions.locals = attributes; @@ -75,7 +75,7 @@ function processNodes(tree, options, messages) { const nodeAttrs = parseAttrs(node.content[index].attrs); Object.keys(attributes).forEach(attr => { - if (typeof defaultLocals[attr] === 'undefined') { + if (typeof locals[attr] === 'undefined') { if (['class'].includes(attr)) { nodeAttrs[attr].push(attributes[attr]); } else if (['style'].includes(attr)) { @@ -109,26 +109,56 @@ function processNodes(tree, options, messages) { function parseLocals(options, {attrs}, html) { let attributes = {...attrs}; + // Handle attributes to be merged with default + // only for Array or Objects + const mergeAttributeWithDefault = []; + Object.keys(attributes).forEach(attribute => { + if (attribute.startsWith('merge:')) { + const newAttributeName = attribute.replace('merge:', ''); + attributes[newAttributeName] = attributes[attribute]; + delete attributes[attribute]; + mergeAttributeWithDefault.push(newAttributeName); + } + }); + + // Parse JSON attributes Object.keys(attributes).forEach(attribute => { try { // Use merge() ? - attributes = {...attributes, ...JSON.parse(attributes[attribute])}; + const parsed = JSON.parse(attributes[attribute]); + if (attribute === 'locals') { + if (mergeAttributeWithDefault.includes(attribute)) { + attributes = merge(attributes, parsed); + } else { + Object.assign(attributes, parsed); + } + } else { + attributes[attribute] = parsed; + } } catch {} }); delete attributes.locals; + // Merge with global attributes = merge(options.expressions.locals, attributes); // Retrieve default locals from +

{{title}}

+
{{ item }}
+
{{ i }}: {{ t }}
diff --git a/test/test-locals.js b/test/test-locals.js index 526d69a..5baba6a 100644 --- a/test/test-locals.js +++ b/test/test-locals.js @@ -31,3 +31,19 @@ test('Must process default attributes and map style and class for the first node t.is(html, expected); }); + +test('Must process component with locals as JSON and string', async t => { + const actual = ``; + const expected = `

Custom title from JSON and String

another itemyet anotherfirst itemsecond item
title: This is default main titlesubtitle: This is default subtitlesuptitle: This is custom suptitle
`; + + const html = await posthtml([plugin({root: './test/templates'})]).process(actual).then(result => clean(result.html)); + + t.is(html, expected); +});