posthtml-component
Advanced tools
Comparing version
{ | ||
"name": "posthtml-component", | ||
"version": "2.0.0", | ||
"version": "2.1.0-beta.1", | ||
"description": "Laravel Blade-inspired components for PostHTML with slots, attributes as props, custom tags and more.", | ||
@@ -42,3 +42,3 @@ "license": "MIT", | ||
"devDependencies": { | ||
"@biomejs/biome": "1.8.3", | ||
"@biomejs/biome": "1.9.4", | ||
"@vitest/coverage-v8": "^2.0.4", | ||
@@ -45,0 +45,0 @@ "conventional-changelog-cli": "^5.0.0", |
@@ -61,3 +61,3 @@ [npm]: https://www.npmjs.com/package/posthtml-component | ||
const posthtml = require('posthtml') | ||
const components = require('posthtml-components') | ||
const components = require('posthtml-component') | ||
const { readFileSync, writeFileSync } = require('node:fs') | ||
@@ -121,33 +121,33 @@ | ||
| Name | Type | Default | Description | | ||
|--------------------------|-------------------|----------------------------------------------|-----------------------------------------------------------------------------------------| | ||
| **root** | `String` | `'./'` | Root path for components lookup. | | ||
| **folders** | `String[]` | `['']` | Array of paths relative to `options.root` or defined namespaces. | | ||
| **tagPrefix** | `String` | `'x-'` | Tag prefix. | | ||
| **tag** | `String\|Boolean` | `false` | Component tag. Use with `options.attribute`. Boolean only `false`. | | ||
| **attribute** | `String` | `'src'` | Component attribute for setting path. | | ||
| **namespaces** | `String[]` | `[]` | Array of namespace root paths, fallback paths, and custom override paths. | | ||
| **namespaceSeparator** | `String` | `'::'` | Namespace separator for tag names. | | ||
| **fileExtension** | `String` | `'html'` | File extension for component files. | | ||
| **yield** | `String` | `'yield'` | Tag name for injecting main component content. | | ||
| **slot** | `String` | `'slot'` | Tag name for slots. | | ||
| **fill** | `String` | `'fill'` | Tag name for filling slots. | | ||
| **slotSeparator** | `String` | `':'` | Name separator for `<slot>` and `<fill>` tags. | | ||
| **push** | `String` | `'push'` | Tag name for `<push>`. | | ||
| **stack** | `String` | `'stack'` | Tag name for `<stack>`. | | ||
| **propsScriptAttribute** | `String` | `'props'` | Attribute in `<script props>` for retrieving component props. | | ||
| **propsContext** | `String` | `'props'` | Name of the object inside the script for processing props. | | ||
| **propsAttribute** | `String` | `'props'` | Attribute to define props as JSON. | | ||
| **propsSlot** | `String` | `'props'` | Used to retrieve props passed to slot via `$slots.slotName.props`. | | ||
| **parserOptions** | `Object` | `{recognizeSelfClosing: true}` | Pass options to `posthtml-parser`. | | ||
| **expressions** | `Object` | `{}` | Pass options to `posthtml-expressions`. | | ||
| **plugins** | `Array` | `[]` | PostHTML plugins to apply to every parsed component. | | ||
| **matcher** | `Object` | `[{tag: options.tagPrefix}]` | Array of objects used to match tags. | | ||
| **attrsParserRules** | `Object` | `{}` | Additional rules for attributes parser plugin. | | ||
| **strict** | `Boolean` | `true` | Toggle exception throwing. | | ||
| **mergeCustomizer** | `Function` | `function` | Callback for lodash `mergeWith` to merge `options.expressions.locals` and props. | | ||
| **utilities** | `Object` | `{merge: _.mergeWith, template: _.template}` | Utility methods passed to `<script props>`. | | ||
| **elementAttributes** | `Object` | `{}` | Object with tag names and function modifiers of `valid-attributes.js`. | | ||
| **safelistAttributes** | `String[]` | `['data-*']` | Array of attribute names to add to default valid attributes. | | ||
| **blocklistAttributes** | `String[]` | `[]` | Array of attribute names to remove from default valid attributes. | | ||
| Name | Type | Default | Description | | ||
|--------------------------|--------------------|----------------------------------------------|----------------------------------------------------------------------------------| | ||
| **root** | `String` | `'./'` | Root path where to look for components. | | ||
| **folders** | `String[]` | `['']` | Array of paths relative to `options.root` or defined namespaces. | | ||
| **fileExtension** | `String\|String[]` | `'html'` | Component file extensions to look for. | | ||
| **tagPrefix** | `String` | `'x-'` | Tag prefix. | | ||
| **tag** | `String\|Boolean` | `false` | Component tag. Use with `options.attribute`. Boolean only `false`. | | ||
| **attribute** | `String` | `'src'` | Attribute to use for defining path to component file. | | ||
| **namespaces** | `String[]` | `[]` | Array of namespace root paths, fallback paths, and custom override paths. | | ||
| **namespaceSeparator** | `String` | `'::'` | Namespace separator for tag names. | | ||
| **yield** | `String` | `'yield'` | Tag name for injecting main component content. | | ||
| **slot** | `String` | `'slot'` | Tag name for [slots](#slots) | | ||
| **fill** | `String` | `'fill'` | Tag name for filling slots. | | ||
| **slotSeparator** | `String` | `':'` | Name separator for `<slot>` and `<fill>` tags. | | ||
| **stack** | `String` | `'stack'` | Tag name for [`<stack>`](#stacks). | | ||
| **push** | `String` | `'push'` | Tag name for `<push>`. | | ||
| **propsScriptAttribute** | `String` | `'props'` | Attribute in `<script props>` for retrieving [component props](#props). | | ||
| **propsContext** | `String` | `'props'` | Name of the object inside the script for processing props. | | ||
| **propsAttribute** | `String` | `'props'` | Attribute name to define props as JSON on a component tag. | | ||
| **propsSlot** | `String` | `'props'` | Used to retrieve props passed to slot via `$slots.slotName.props`. | | ||
| **parserOptions** | `Object` | `{recognizeSelfClosing: true}` | Pass options to `posthtml-parser`. | | ||
| **expressions** | `Object` | `{}` | Pass options to `posthtml-expressions`. | | ||
| **plugins** | `Array` | `[]` | PostHTML plugins to apply to every parsed component. | | ||
| **matcher** | `Object` | `[{tag: options.tagPrefix}]` | Array of objects used to match tags. | | ||
| **attrsParserRules** | `Object` | `{}` | Additional rules for attributes parser plugin. | | ||
| **strict** | `Boolean` | `true` | Toggle exception throwing. | | ||
| **mergeCustomizer** | `Function` | `function` | Callback for lodash `mergeWith` to merge `options.expressions.locals` and props. | | ||
| **utilities** | `Object` | `{merge: _.mergeWith, template: _.template}` | Utility methods passed to `<script props>`. | | ||
| **elementAttributes** | `Object` | `{}` | Object with tag names and function modifiers of `valid-attributes.js`. | | ||
| **safelistAttributes** | `String[]` | `['data-*']` | Array of attribute names to add to default valid attributes. | | ||
| **blocklistAttributes** | `String[]` | `[]` | Array of attribute names to remove from default valid attributes. | | ||
@@ -160,5 +160,5 @@ ## Features | ||
If you to use components as 'includes', you may define a tag and src attribute name. | ||
If you want to use components as 'includes', you can define tag and `src` attribute names. | ||
Using our previous button component example, we can define the tag and attribute names and then use it in this way: | ||
Using our previous button component example, we can define the tag and attribute names and then use it like this: | ||
@@ -180,3 +180,3 @@ ```hbs | ||
require('posthtml')( | ||
require('posthtml-components')({ | ||
require('posthtml-component')({ | ||
root: './src', | ||
@@ -190,3 +190,3 @@ tag: 'component', | ||
If you need more control over tag matching, you can pass an array of matcher or single object via `options.matcher` like this: | ||
If you need more control over tag matching, you may pass an array of matcher or single object via `options.matcher`: | ||
@@ -197,6 +197,10 @@ ```js | ||
root: './src', | ||
matcher: [{tag: 'a-tag'}, {tag: 'another-one'}, {tag: new RegExp(`^app-`, 'i')}] | ||
matcher: [ | ||
{tag: 'a-tag'}, | ||
{tag: 'another-one'}, | ||
{tag: new RegExp(`^app-`, 'i')}, | ||
] | ||
}; | ||
require('posthtml')(require('posthtml-components')(options)) | ||
require('posthtml')(require('posthtml-component')(options)) | ||
.process(/* ... */) | ||
@@ -217,3 +221,3 @@ .then(/* ... */) | ||
require('posthtml')(require('posthtml-components')(options)) | ||
require('posthtml')(require('posthtml-component')(options)) | ||
.process(/* ... */) | ||
@@ -264,3 +268,3 @@ .then(/* ... */) | ||
require('posthtml')(require('posthtml-components')(options)) | ||
require('posthtml')(require('posthtml-component')(options)) | ||
.process('some HTML', options.parserOptions) | ||
@@ -270,3 +274,4 @@ .then(/* ... */) | ||
Important: as you can see, whatever `parserOptions` you pass to the plugin, must also be passed in the `process` method in your code, otherwise your PostHTML build will use `posthtml-parser` defaults and will override anything you've passed to `posthtml-component`. | ||
> [!IMPORTANT] | ||
> The `parserOptions` that you pass to the plugin must also be passed in the `process` method in your code, otherwise your PostHTML build will use `posthtml-parser` defaults and will override anything you've passed to `posthtml-component`. | ||
@@ -279,3 +284,3 @@ #### Self-closing tags | ||
// index.js | ||
require('posthtml')(require('posthtml-components')({root: './src'})) | ||
require('posthtml')(require('posthtml-component')({root: './src'})) | ||
.process('your HTML...', {recognizeSelfClosing: true}) | ||
@@ -300,3 +305,3 @@ .then(/* ... */) | ||
require('posthtml')(require('posthtml-components')(options)) | ||
require('posthtml')(require('posthtml-component')(options)) | ||
.process(/* ... */) | ||
@@ -840,3 +845,3 @@ .then(/* ... */) | ||
const posthtml = require('posthtml') | ||
const components = require('posthtml-components') | ||
const components = require('posthtml-component') | ||
@@ -843,0 +848,0 @@ const options = { |
@@ -16,12 +16,16 @@ 'use strict'; | ||
module.exports = (tag, options) => { | ||
const fileNameFromTag = tag | ||
.replace(options.tagPrefix, '') | ||
.split(folderSeparator) | ||
.join(path.sep) | ||
.concat(folderSeparator, options.fileExtension); | ||
const extensions = Array.isArray(options.fileExtension) ? options.fileExtension : [options.fileExtension]; | ||
const fileNamesFromTag = extensions.map(ext => | ||
tag | ||
.replace(options.tagPrefix, '') | ||
.split(folderSeparator) | ||
.join(path.sep) | ||
.concat(folderSeparator, ext) | ||
) | ||
try { | ||
return tag.includes(options.namespaceSeparator) ? | ||
searchInNamespaces(tag, fileNameFromTag.split(options.namespaceSeparator), options) : | ||
searchInFolders(tag, fileNameFromTag, options); | ||
return tag.includes(options.namespaceSeparator) | ||
? searchInNamespaces(tag, fileNamesFromTag, options) | ||
: searchInFolders(tag, fileNamesFromTag, options); | ||
} catch (error) { | ||
@@ -40,11 +44,13 @@ if (options.strict) { | ||
* @param {String} tag [tag name] | ||
* @param {String} fileNameFromTag [filename converted from tag name] | ||
* @param {Array} fileNamesFromTag [filename converted from tag name] | ||
* @param {Object} options [posthtml options] | ||
* @return {String|boolean} [custom tag root where the module is found] | ||
*/ | ||
function searchInFolders(tag, fileNameFromTag, options) { | ||
const componentPath = search(options.root, options.folders, fileNameFromTag, options.fileExtension); | ||
function searchInFolders(tag, fileNamesFromTag, options) { | ||
const componentPath = search(options.root, options.folders, fileNamesFromTag, options.fileExtension); | ||
if (!componentPath) { | ||
throw new Error(`[components] <${tag}> could not find ${fileNameFromTag} in the defined root paths (${options.folders.join(', ')})`); | ||
throw new Error( | ||
`[components] <${tag}> could not find ${fileNamesFromTag} in the defined root paths (${options.folders.join(', ')})` | ||
); | ||
} | ||
@@ -59,64 +65,88 @@ | ||
* @param {String} tag [tag name with namespace] | ||
* @param {String} namespace [tag's namespace] | ||
* @param {String} fileNameFromTag [filename converted from tag name] | ||
* @param {Array} namespaceAndFileNames Array of [namespace]::[filename] | ||
* @param {Object} options [posthtml options] | ||
* @return {String|boolean} [custom tag root where the module is found] | ||
*/ | ||
function searchInNamespaces(tag, [namespace, fileNameFromTag], options) { | ||
const namespaceOption = options.namespaces.find(n => n.name === namespace.replace(options.tagPrefix, '')); | ||
function searchInNamespaces(tag, namespaceAndFileNames, options) { | ||
let result = ''; | ||
if (!namespaceOption) { | ||
throw new Error(`[components] Unknown component namespace: ${namespace}.`); | ||
} | ||
for (const namespaceAndFileName of namespaceAndFileNames) { | ||
const [namespace, fileNameFromTag] = namespaceAndFileName.split('::'); | ||
let componentPath; | ||
const namespaceOption = options.namespaces.find(n => n.name === namespace.replace(options.tagPrefix, '')); | ||
// 1) Check in custom root | ||
if (namespaceOption.custom) { | ||
componentPath = search(namespaceOption.custom, options.folders, fileNameFromTag, options.fileExtension); | ||
} | ||
if (!namespaceOption) { | ||
throw new Error(`[components] Unknown component namespace: ${namespace}.`); | ||
} | ||
// 2) Check in base root | ||
if (!componentPath) { | ||
componentPath = search(namespaceOption.root, options.folders, fileNameFromTag, options.fileExtension); | ||
} | ||
let componentPath; | ||
// 3) Check in fallback root | ||
if (!componentPath && namespaceOption.fallback) { | ||
componentPath = search(namespaceOption.fallback, options.folders, fileNameFromTag, options.fileExtension); | ||
} | ||
// 1) Check in custom root | ||
if (namespaceOption.custom) { | ||
componentPath = search(namespaceOption.custom, options.folders, fileNameFromTag, options.fileExtension); | ||
} | ||
if (!componentPath && options.strict) { | ||
throw new Error(`[components] <${tag}> could not find ${fileNameFromTag} in the defined namespace base path ${namespaceOption.root}`); | ||
// 2) Check in base root | ||
if (!componentPath) { | ||
componentPath = search(namespaceOption.root, options.folders, fileNameFromTag, options.fileExtension); | ||
} | ||
// 3) Check in fallback root | ||
if (!componentPath && namespaceOption.fallback) { | ||
componentPath = search(namespaceOption.fallback, options.folders, fileNameFromTag, options.fileExtension); | ||
} | ||
if (!componentPath) { | ||
throw new Error(`[components] <${tag}> could not find ${fileNameFromTag} in the defined namespace paths.`); | ||
} | ||
result = componentPath; | ||
} | ||
return componentPath; | ||
return result; | ||
} | ||
/** | ||
* Main search component file function | ||
* Main component file search function | ||
* | ||
* @param {String} root Base root or namespace root from options | ||
* @param {Array} folders Folders from options | ||
* @param {String} fileName Filename converted from tag name | ||
* @param {String} extension File extension from options | ||
* @param {String} root Base root or namespace root from `options` | ||
* @param {Array} folders Folders to search in from `options` | ||
* @param {Array} fileNames Filenames converted from tag name | ||
* @param {Array} extensions File extension(s) from `options` | ||
* @return {String|boolean} [custom tag root where the module is found] | ||
*/ | ||
function search(root, folders, fileName, extension) { | ||
function search(root, folders, fileNames, extensions) { | ||
let componentPath; | ||
let componentFound = false; | ||
let componentFound = folders.some(folder => { | ||
componentPath = path.join(path.resolve(root, folder), fileName); | ||
return existsSync(componentPath); | ||
}); | ||
fileNames = Array.isArray(fileNames) ? fileNames : [fileNames]; | ||
if (!componentFound) { | ||
fileName = fileName.replace(`.${extension}`, `${path.sep}index.${extension}`); | ||
for (const fileName of fileNames) { | ||
componentFound = folders.some(folder => { | ||
componentPath = path.join(path.resolve(root, folder), fileName); | ||
return existsSync(componentPath); | ||
}); | ||
if (componentFound) break; | ||
} | ||
if (!componentFound) { | ||
for (const extension of extensions) { | ||
for (const fileName of fileNames) { | ||
const newFileName = fileName.replace(`.${extension}`, `${path.sep}index.${extension}`); | ||
componentFound = folders.some(folder => { | ||
componentPath = path.join(path.resolve(root, folder), newFileName); | ||
return existsSync(componentPath); | ||
}); | ||
if (componentFound) break; | ||
} | ||
if (componentFound) break; | ||
} | ||
} | ||
return componentFound ? componentPath : false; | ||
} |
@@ -77,6 +77,12 @@ 'use strict'; | ||
}; | ||
// Additional element attributes, in case already exist in valid-attributes.js it will replace all attributes | ||
// It should be an object with key as tag name and as value a function modifier which receive | ||
// the default attributes and return an array of attributes. Example: | ||
// { TAG: (attributes) => { attributes[] = 'attribute-name'; return attributes; } } | ||
/** | ||
* Additional element attributes. If they already exist in valid-attributes.js, | ||
* it will replace all attributes. It should be an object with tag name as | ||
* the key and a function modifier as the value, which will receive the | ||
* default attributes and return an array of attributes. | ||
* | ||
* Example: | ||
* { TAG: (attributes) => { attributes[] = 'attribute-name'; return attributes; } } | ||
*/ | ||
options.elementAttributes = isPlainObject(options.elementAttributes) ? options.elementAttributes : {}; | ||
@@ -86,5 +92,8 @@ options.safelistAttributes = Array.isArray(options.safelistAttributes) ? options.safelistAttributes : []; | ||
// Merge customizer callback passed to lodash mergeWith | ||
// for merge attribute `props` and all attributes starting with `merge:` | ||
// @see https://lodash.com/docs/4.17.15#mergeWith | ||
/** | ||
* Merge customizer callback passed to `lodash.mergeWith` for merging | ||
* attribute `props` and all attributes starting with `merge:`. | ||
* | ||
* @see {@link https://lodash.com/docs/4.17.15#mergeWith|Lodash} | ||
*/ | ||
options.mergeCustomizer = options.mergeCustomizer || ((objectValue, sourceValue) => { | ||
@@ -110,2 +119,3 @@ if (Array.isArray(objectValue)) { | ||
options.matcher = []; | ||
if (options.tagPrefix) { | ||
@@ -122,4 +132,6 @@ options.matcher.push({tag: options.tagPrefix}); | ||
options.namespaces = Array.isArray(options.namespaces) ? options.namespaces : [options.namespaces]; | ||
options.namespaces.forEach((namespace, index) => { | ||
options.namespaces[index].root = path.resolve(namespace.root); | ||
if (namespace.fallback) { | ||
@@ -155,3 +167,3 @@ options.namespaces[index].fallback = path.resolve(namespace.fallback); | ||
// Used for reset aware props | ||
// Used to reset aware props | ||
let processCounter = 0; | ||
@@ -163,3 +175,2 @@ | ||
*/ | ||
function processTree(options) { | ||
@@ -236,11 +247,14 @@ const filledSlots = {}; | ||
// Remove attributes when value is 'null' or 'undefined' | ||
// so we can conditionally add an attribute by setting value to 'undefined' or 'null'. | ||
/** | ||
* Remove attributes when value is 'null' or 'undefined' so we can | ||
* conditionally add an attribute by setting the value to | ||
* 'undefined' or 'null'. | ||
*/ | ||
walk.call(currentNode, node => { | ||
if (node && node.attrs) { | ||
each(node.attrs, (value, key) => { | ||
if (['undefined', 'null'].includes(value)) { | ||
for (const key in node.attrs) { | ||
if (node.attrs[key] === 'undefined' || node.attrs[key] === 'null') { | ||
delete node.attrs[key]; | ||
} | ||
}); | ||
} | ||
} | ||
@@ -247,0 +261,0 @@ |
@@ -11,3 +11,2 @@ 'use strict'; | ||
const difference = require('lodash/difference'); | ||
const each = require('lodash/each'); | ||
const has = require('lodash/has'); | ||
@@ -56,11 +55,12 @@ const extend = require('lodash/extend'); | ||
if (!isEmpty(options.elementAttributes)) { | ||
each(options.elementAttributes, (modifier, tagName) => { | ||
for (const tagName in options.elementAttributes) { | ||
const modifier = options.elementAttributes[tagName]; | ||
if (typeof modifier === 'function' && isString(tagName)) { | ||
tagName = tagName.toUpperCase(); | ||
const attributes = modifier(validAttributes.elementAttributes[tagName]); | ||
const upperTagName = tagName.toUpperCase(); | ||
const attributes = modifier(validAttributes.elementAttributes[upperTagName]); | ||
if (Array.isArray(attributes)) { | ||
validAttributes.elementAttributes[tagName] = attributes; | ||
validAttributes.elementAttributes[upperTagName] = attributes; | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
@@ -81,11 +81,14 @@ | ||
// Get additional specified attributes | ||
each(attributes, (value, attr) => { | ||
each(validAttributes.safelistAttributes, additionalAttr => { | ||
if (additionalAttr === attr || (additionalAttr.endsWith('*') && attr.startsWith(additionalAttr.replace('*', '')))) { | ||
mainNodeAttributes[attr] = value; | ||
for (const attr in attributes) { | ||
for (const additionalAttr of validAttributes.safelistAttributes) { | ||
if ( | ||
additionalAttr === attr | ||
|| (additionalAttr.endsWith('*') && attr.startsWith(additionalAttr.replace('*', ''))) | ||
) { | ||
mainNodeAttributes[attr] = attributes[attr]; | ||
} | ||
}); | ||
}); | ||
} | ||
} | ||
each(mainNodeAttributes, (value, key) => { | ||
for (const key in mainNodeAttributes) { | ||
if (['class', 'style'].includes(key)) { | ||
@@ -106,3 +109,3 @@ if (!has(nodeAttrs, key)) { | ||
delete attributes[key]; | ||
}); | ||
} | ||
@@ -112,9 +115,9 @@ // The plugin posthtml-attrs-parser compose() method expects a string, | ||
// So below we convert non string values to string. | ||
each(nodeAttrs, (value, key) => { | ||
for (const key in nodeAttrs) { | ||
if (key !== 'compose' && !isObject(nodeAttrs[key]) && !isString(nodeAttrs[key])) { | ||
nodeAttrs[key] = nodeAttrs[key].toString(); | ||
} | ||
}); | ||
} | ||
mainNode.attrs = nodeAttrs.compose(); | ||
}; |
'use strict'; | ||
const processScript = require('./process-script'); | ||
const pick = require('lodash/pick'); | ||
const each = require('lodash/each'); | ||
const assign = require('lodash/assign'); | ||
const mergeWith = require('lodash/mergeWith'); | ||
const processScript = require('./process-script'); | ||
@@ -26,9 +25,9 @@ const attributeTypes = ['aware', 'merge']; | ||
const attributesByTypeName = {}; | ||
each(attributeTypes, type => { | ||
for (const type of attributeTypes) { | ||
attributesByTypeName[type] = []; | ||
}); | ||
} | ||
each(attributes, (value, key, attrs) => { | ||
for (const key in attributes) { | ||
let newKey = key; | ||
each(attributeTypes, type => { | ||
for (const type of attributeTypes) { | ||
if (key.startsWith(`${type}:`)) { | ||
@@ -38,16 +37,16 @@ newKey = newKey.replace(`${type}:`, ''); | ||
} | ||
}); | ||
} | ||
if (newKey !== key) { | ||
attrs[newKey] = value; | ||
delete attrs[key]; | ||
attributes[newKey] = attributes[key]; | ||
delete attributes[key]; | ||
} | ||
}); | ||
} | ||
// Parse JSON attributes | ||
each(attributes, (value, key, attrs) => { | ||
for (const key in attributes) { | ||
try { | ||
attrs[key] = JSON.parse(value); | ||
attributes[key] = JSON.parse(attributes[key]); | ||
} catch {} | ||
}); | ||
} | ||
@@ -70,3 +69,13 @@ // Merge or extend attribute props | ||
// Process props from <script props> | ||
const {props} = processScript(nextNode, {props: {...attributes}, $slots: filledSlots, propsScriptAttribute: options.propsScriptAttribute, propsContext: options.propsContext, utilities: options.utilities}, componentPath.replace(`.${options.fileExtension}`, '.js')); | ||
const {props} = processScript( | ||
nextNode, | ||
{ | ||
props: {...attributes}, | ||
$slots: filledSlots, | ||
propsScriptAttribute: options.propsScriptAttribute, | ||
propsContext: options.propsContext, | ||
utilities: options.utilities | ||
}, | ||
componentPath.replace(`.${options.fileExtension}`, '.js') | ||
); | ||
@@ -73,0 +82,0 @@ if (props) { |
@@ -5,3 +5,2 @@ 'use strict'; | ||
const {render} = require('posthtml-render'); | ||
const each = require('lodash/each'); | ||
const omit = require('lodash/omit'); | ||
@@ -29,7 +28,9 @@ | ||
if (props) { | ||
each(props, (value, key, attrs) => { | ||
try { | ||
attrs[key] = JSON.parse(value); | ||
} catch {} | ||
}); | ||
for (const key in props) { | ||
if (props.hasOwnProperty(key)) { | ||
try { | ||
props[key] = JSON.parse(props[key]); | ||
} catch {} | ||
} | ||
} | ||
} | ||
@@ -36,0 +37,0 @@ |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
127014
0.63%4507
0.99%1068
0.47%2
100%