1
0
mirror of https://github.com/svg/svgo.git synced 2026-01-27 07:02:06 +03:00
Files
svgo/plugins/mergeStyles.js
Seth Falco 1df2e0fa39 fix(cleanupIds): skip generated ids for malformed references (#1817)
I also had some chores pending which were trivial individually, I opted
to incorporate them here as well.

* In JSDocs, use the nullable syntax as it's more concise and familiar
from TypeScript usage.
* discord → Discord (proper nouns should match capitalization)
* Use actions/checkout v4 instead of v2
2023-11-04 12:56:20 +00:00

99 lines
2.5 KiB
JavaScript

'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 {?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];
}
},
},
};
};