1
0
mirror of https://github.com/svg/svgo.git synced 2025-04-19 10:22:15 +03:00
svgo/plugins/mergeStyles.js
Bogdan Chadkin 07f8d606e0
Implement preset-default plugin (#1513)
I saw complaints about `extendDefaultPlugins` api

- it cannot be used when svgo is installed globally
- it requires svgo to be installed when using svgo-loader or svgo-jsx
- it prevents using serializable config formats like json

In this diff I introduced the new plugin which is a bundle of all
default plugins.

```js
module.exports = {
  plugins: [
    'preset_default',
    // or
    {
      name: 'preset_default',
      floatPrecision: 4,
      overrides: {
        convertPathData: {
          applyTransforms: false
        }
      }
    }
  ]
}
```
2021-08-13 19:07:08 +03:00

87 lines
2.0 KiB
JavaScript

'use strict';
const { closestByName, detachNodeFromParent } = require('../lib/xast.js');
const JSAPI = require('../lib/svgo/jsAPI.js');
exports.name = 'mergeStyles';
exports.type = 'visitor';
exports.active = true;
exports.description = 'merge multiple style elements into one';
/**
* Merge multiple style elements into one.
*
* @author strarsis <strarsis@gmail.com>
*/
exports.fn = () => {
let firstStyleElement = null;
let collectedStyles = '';
let styleContentType = 'text';
const enterElement = (node, parentNode) => {
// 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;
}
// skip <foreignObject> content
if (closestByName(node, 'foreignObject')) {
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);
firstStyleElement.children = [
new JSAPI(
{ type: styleContentType, value: collectedStyles },
firstStyleElement
),
];
}
};
return {
element: {
enter: enterElement,
},
};
};