diff options
Diffstat (limited to 'node_modules/svgo/plugins/mergeStyles.js')
| -rw-r--r-- | node_modules/svgo/plugins/mergeStyles.js | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/node_modules/svgo/plugins/mergeStyles.js b/node_modules/svgo/plugins/mergeStyles.js new file mode 100644 index 00000000..1cc32015 --- /dev/null +++ b/node_modules/svgo/plugins/mergeStyles.js @@ -0,0 +1,98 @@ +'use strict'; + +/** + * @typedef {import('../lib/types').XastElement} XastElement + * @typedef {import('../lib/types').XastChild} XastChild + */ + +const { visitSkip, detachNodeFromParent } = require('../lib/xast.js'); + +exports.name = 'mergeStyles'; +exports.description = 'merge multiple style elements into one'; + +/** + * Merge multiple style elements into one. + * + * @author strarsis <strarsis@gmail.com> + * + * @type {import('./plugins-types').Plugin<'mergeStyles'>} + */ +exports.fn = () => { + /** + * @type {null | XastElement} + */ + let firstStyleElement = null; + let collectedStyles = ''; + /** + * @type {'text' | 'cdata'} + */ + let styleContentType = 'text'; + + return { + element: { + enter: (node, parentNode) => { + // skip <foreignObject> content + if (node.name === 'foreignObject') { + return visitSkip; + } + + // collect style elements + if (node.name !== 'style') { + return; + } + + // skip <style> with invalid type attribute + if ( + node.attributes.type != null && + node.attributes.type !== '' && + node.attributes.type !== 'text/css' + ) { + return; + } + + // extract style element content + let css = ''; + for (const child of node.children) { + if (child.type === 'text') { + css += child.value; + } + if (child.type === 'cdata') { + styleContentType = 'cdata'; + css += child.value; + } + } + + // remove empty style elements + if (css.trim().length === 0) { + detachNodeFromParent(node, parentNode); + return; + } + + // collect css and wrap with media query if present in attribute + if (node.attributes.media == null) { + collectedStyles += css; + } else { + collectedStyles += `@media ${node.attributes.media}{${css}}`; + delete node.attributes.media; + } + + // combine collected styles in the first style element + if (firstStyleElement == null) { + firstStyleElement = node; + } else { + detachNodeFromParent(node, parentNode); + /** + * @type {XastChild} + */ + const child = { type: styleContentType, value: collectedStyles }; + // TODO remove legacy parentNode in v4 + Object.defineProperty(child, 'parentNode', { + writable: true, + value: firstStyleElement, + }); + firstStyleElement.children = [child]; + } + }, + }, + }; +}; |
