diff --git a/.npmignore b/.npmignore index c0b7a47..524c858 100644 --- a/.npmignore +++ b/.npmignore @@ -16,4 +16,5 @@ ava.config.js changelog.md xo.config.js .lintstagedrc -.github \ No newline at end of file +.github +scripts \ No newline at end of file diff --git a/scripts/fetch-attributes.js b/scripts/fetch-attributes.js new file mode 100644 index 0000000..f6084aa --- /dev/null +++ b/scripts/fetch-attributes.js @@ -0,0 +1,79 @@ +/* eslint-disable no-undef */ +/* eslint-disable curly */ +/* eslint-disable padded-blocks */ +const elementAttributes = {}; + +// Exception +// tabindex seem to be allowed on any element according to https://www.w3schools.com/tags/att_global_tabindex.asp +// but here https://www.w3.org/TR/html4/index/attributes.html seem not +// So below we add this exception +const allowedAttributes = ['tabindex']; + +// Fetch valid html elements (not deprecated) +fetch('https://www.w3.org/TR/html4/index/elements.html').then(response => { + return response.text(); +}).then(html => { + const parser = new DOMParser(); + const doc = parser.parseFromString(html, 'text/html'); + const rows = doc.querySelectorAll('table tbody tr'); + + rows.forEach(row => { + const elementName = row.querySelector('td[title="Name"]'); + if (!elementName) return; + + const isDeprecated = row.querySelector('td[title="Depr."]'); + if (isDeprecated.textContent.trim() === 'D') return; + + elementAttributes[elementName.textContent.trim()] = [...allowedAttributes]; + }); + + console.log('Valid HTML elements', elementAttributes); + +}).catch(error => { + console.warn(error.message); +}); + +// Fetch valid HTML attributes (not deprecated) + +fetch('https://www.w3.org/TR/html4/index/attributes.html').then(response => { + return response.text(); +}).then(html => { + const parser = new DOMParser(); + const doc = parser.parseFromString(html, 'text/html'); + const rows = doc.querySelectorAll('table tbody tr'); + + rows.forEach(row => { + const attributeName = row.querySelector('td[title="Name"]'); + if (!attributeName) return; + + const isDeprecated = row.querySelector('td[title="Depr."]'); + if (isDeprecated.textContent.trim() === 'D') return; + + const relatedElements = row.querySelector('td[title="Related Elements"]').textContent.trim().split(','); + + const exclude = relatedElements[0].includes('All elements but'); + if (exclude) { + // Allowed in all but not in relatedElements + relatedElements[0].replace('All elements but', ''); + Object.keys(elementAttributes).forEach(elementName => { + // Skip element that doesn't support the attribute + if (relatedElements.includes(elementName)) return; + elementAttributes[elementName].push(attributeName.textContent.trim()); + }); + } else { + relatedElements.forEach(element => { + // Skip deprecated element + if (!elementAttributes[element]) return; + elementAttributes[element].push(attributeName.textContent.trim()); + }); + } + }); + + Object.keys(elementAttributes).forEach(element => { + elementAttributes[element].sort(); + }); + + console.log('elementAttributes', elementAttributes); +}).catch(error => { + console.warn(error.message); +}); diff --git a/src/process-attributes.js b/src/process-attributes.js index 9998cf2..f25d3d2 100644 --- a/src/process-attributes.js +++ b/src/process-attributes.js @@ -3,14 +3,16 @@ const {match} = require('posthtml/lib/api'); const parseAttrs = require('posthtml-attrs-parser'); const styleToObject = require('style-to-object'); -const omit = require('lodash/omit'); const keys = require('lodash/keys'); const union = require('lodash/union'); +const pick = require('lodash/pick'); +const difference = require('lodash/difference'); const each = require('lodash/each'); const has = require('lodash/has'); const extend = require('lodash/extend'); const isString = require('lodash/isString'); const isObject = require('lodash/isObject'); +const validAttributes = require('./valid-attributes'); /** * Map component attributes that it's not defined as props to first element of node @@ -43,7 +45,26 @@ module.exports = (currentNode, attributes, props, options, aware) => { const nodeAttrs = parseAttrs(mainNode.attrs, options.attrsParserRules); - const mainNodeAttributes = omit(attributes, union(keys(props), [options.attribute], keys(aware), keys(options.props), ['$slots'])); + // Attributes to be excluded + const excludeAttributes = union(validAttributes.blacklist, keys(props), [options.attribute], keys(aware), keys(options.props), ['$slots']); + // All valid HTML attributes for the main element + const allValidElementAttributes = validAttributes.elementAttributes[mainNode.tag.toUpperCase()]; + // Valid HTML attributes without the excluded + const validElementAttributes = difference(allValidElementAttributes, excludeAttributes); + // Add override attributes + validElementAttributes.push('override:style'); + validElementAttributes.push('override:class'); + // Pick valid attributes from passed + const mainNodeAttributes = pick(attributes, validElementAttributes); + + // Get additional specified attributes + each(attributes, (value, attr) => { + each(validAttributes.additionalAttributes, additionalAttr => { + if (additionalAttr === attr || (additionalAttr.endsWith('*') && attr.startsWith(additionalAttr.replace('*', '')))) { + mainNodeAttributes[attr] = value; + } + }); + }); each(mainNodeAttributes, (value, key) => { if (['class', 'style'].includes(key)) { diff --git a/src/valid-attributes.js b/src/valid-attributes.js new file mode 100644 index 0000000..be20f43 --- /dev/null +++ b/src/valid-attributes.js @@ -0,0 +1,102 @@ +/** + * List of valid HTML attributes that will be passed to first node of component or + * to the node with an attribute 'attributes'. + * Generated from https://www.w3.org/TR/html4/index/attributes.html + * + * @see https://jsfiddle.net/1r8czt2h/ + */ + +module.exports = { + elementAttributes: { + A: ['accesskey', 'charset', 'class', 'coords', 'dir', 'href', 'hreflang', 'id', 'lang', 'name', 'onblur', 'onclick', 'ondblclick', 'onfocus', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'rel', 'rev', 'shape', 'style', 'tabindex', 'tabindex', 'target', 'title', 'type'], + ABBR: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + ACRONYM: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + ADDRESS: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + AREA: ['alt', 'class', 'coords', 'dir', 'id', 'lang', 'nohref', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'shape', 'style', 'tabindex', 'title'], + B: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + BASE: ['class', 'dir', 'href', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + BDO: ['class', 'dir', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + BIG: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + BLOCKQUOTE: ['cite', 'class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + BODY: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onload', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onunload', 'style', 'tabindex', 'title'], + BR: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + BUTTON: ['class', 'dir', 'disabled', 'id', 'lang', 'name', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title', 'type', 'value'], + CAPTION: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + CITE: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + CODE: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + COL: ['align', 'char', 'charoff', 'class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'span', 'style', 'tabindex', 'title', 'valign', 'width'], + COLGROUP: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'span', 'style', 'tabindex', 'title', 'width'], + DD: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + DEL: ['cite', 'class', 'datetime', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + DFN: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + DIV: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + DL: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + DT: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + EM: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + FIELDSET: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + FORM: ['accept', 'accept-charset', 'action', 'class', 'dir', 'enctype', 'id', 'lang', 'method', 'name', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onreset', 'onsubmit', 'style', 'tabindex', 'title'], + FRAME: ['class', 'dir', 'frameborder', 'id', 'lang', 'longdesc', 'marginheight', 'marginwidth', 'name', 'noresize', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'scrolling', 'src', 'style', 'tabindex', 'title'], + FRAMESET: ['class', 'cols', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onload', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onunload', 'rows', 'style', 'tabindex', 'title'], + H1: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + H2: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + H3: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + H4: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + H5: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + H6: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + HEAD: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'profile', 'style', 'tabindex', 'title'], + HR: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + HTML: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + I: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + IFRAME: ['class', 'dir', 'height', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title', 'width'], + IMG: ['class', 'dir', 'height', 'id', 'ismap', 'lang', 'longdesc', 'name', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'src', 'style', 'tabindex', 'title', 'usemap', 'width'], + INPUT: ['alt', 'checked', 'class', 'dir', 'id', 'lang', 'maxlength', 'name', 'onchange', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onselect', 'readonly', 'size', 'src', 'style', 'tabindex', 'title', 'type', 'value'], + INS: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + KBD: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + LABEL: ['class', 'dir', 'for', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + LEGEND: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + LI: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + LINK: ['class', 'dir', 'id', 'lang', 'media', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + MAP: ['class', 'dir', 'id', 'lang', 'name', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + META: ['class', 'content', 'dir', 'http-equiv', 'id', 'lang', 'name', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'scheme', 'style', 'tabindex', 'title'], + NOFRAMES: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + NOSCRIPT: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + OBJECT: ['archive', 'class', 'classid', 'codebase', 'codetype', 'data', 'declare', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'standby', 'style', 'tabindex', 'title', 'type'], + OL: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + OPTGROUP: ['class', 'dir', 'id', 'label', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + OPTION: ['class', 'dir', 'id', 'label', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'selected', 'style', 'tabindex', 'title', 'value'], + P: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + PARAM: ['class', 'dir', 'id', 'lang', 'name', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title', 'type', 'value', 'valuetype'], + PRE: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + Q: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + SAMP: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + SCRIPT: ['class', 'defer', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'src', 'style', 'tabindex', 'title', 'type'], + SELECT: ['class', 'dir', 'id', 'lang', 'multiple', 'name', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'size', 'style', 'tabindex', 'title'], + SMALL: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + SPAN: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + STRONG: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + STYLE: ['class', 'dir', 'id', 'lang', 'media', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title', 'type'], + SUB: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + SUP: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + TABLE: ['border', 'cellpadding', 'cellspacing', 'class', 'dir', 'frame', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'rules', 'style', 'summary', 'tabindex', 'title', 'width'], + TBODY: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + TD: ['abbr', 'axis', 'class', 'colspan', 'dir', 'headers', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'rowspan', 'scope', 'style', 'tabindex', 'title'], + TEXTAREA: ['class', 'cols', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'readonly', 'rows', 'style', 'tabindex', 'title'], + TFOOT: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + TH: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + THEAD: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + TITLE: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + TR: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + TT: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + UL: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'], + VAR: ['class', 'dir', 'id', 'lang', 'onclick', 'ondblclick', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'style', 'tabindex', 'title'] + }, + + // Add additional attributes, use '*' in the end to check by startsWith + // Example: 'start-with-*' + additionalAttributes: [ + 'data-*' + ], + + // Skip this attributes + blacklist: [] +}; diff --git a/test/templates/components/component-mapped-attributes.html b/test/templates/components/component-mapped-attributes.html index 5ee3991..3e83fcc 100644 --- a/test/templates/components/component-mapped-attributes.html +++ b/test/templates/components/component-mapped-attributes.html @@ -4,4 +4,4 @@ body: props.body || 'Default body' } </script> -<div class="text-dark m-3">{{ title }} {{ body }}</div> +<div class="text-dark m-3" style="background: red">{{ title }} {{ body }}</div> diff --git a/test/test-attributes.js b/test/test-attributes.js index 99f345a..1988acb 100644 --- a/test/test-attributes.js +++ b/test/test-attributes.js @@ -7,7 +7,7 @@ const clean = html => html.replace(/(\n|\t)/g, '').trim(); test('Must merge and map attributes not props to first node', async t => { const actual = `<component src="components/component-mapped-attributes.html" data-something="Test an attribute" title="My Title" class="bg-light p-2" style="display: flex; font-size: 20px"></component>`; - const expected = `<div class="text-dark m-3 bg-light p-2" data-something="Test an attribute" style="display: flex; font-size: 20px">My Title Default body</div>`; + const expected = `<div class="text-dark m-3 bg-light p-2" style="background: red; display: flex; font-size: 20px" data-something="Test an attribute">My Title Default body</div>`; const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));