svgo-v2 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +294 -0
- package/bin/svgo +10 -0
- package/dist/svgo.browser.js +1 -0
- package/lib/css-tools.js +239 -0
- package/lib/parser.js +259 -0
- package/lib/path.js +347 -0
- package/lib/stringifier.js +326 -0
- package/lib/style.js +283 -0
- package/lib/svgo/coa.js +517 -0
- package/lib/svgo/config.js +138 -0
- package/lib/svgo/css-class-list.js +72 -0
- package/lib/svgo/css-select-adapter.d.ts +2 -0
- package/lib/svgo/css-select-adapter.js +120 -0
- package/lib/svgo/css-style-declaration.js +232 -0
- package/lib/svgo/jsAPI.d.ts +2 -0
- package/lib/svgo/jsAPI.js +443 -0
- package/lib/svgo/plugins.js +109 -0
- package/lib/svgo/tools.js +137 -0
- package/lib/svgo-node.js +106 -0
- package/lib/svgo.js +83 -0
- package/lib/types.ts +172 -0
- package/lib/xast.js +102 -0
- package/package.json +130 -0
- package/plugins/_applyTransforms.js +335 -0
- package/plugins/_collections.js +2168 -0
- package/plugins/_path.js +816 -0
- package/plugins/_transforms.js +379 -0
- package/plugins/addAttributesToSVGElement.js +87 -0
- package/plugins/addClassesToSVGElement.js +87 -0
- package/plugins/cleanupAttrs.js +55 -0
- package/plugins/cleanupEnableBackground.js +75 -0
- package/plugins/cleanupIDs.js +297 -0
- package/plugins/cleanupListOfValues.js +154 -0
- package/plugins/cleanupNumericValues.js +113 -0
- package/plugins/collapseGroups.js +135 -0
- package/plugins/convertColors.js +152 -0
- package/plugins/convertEllipseToCircle.js +39 -0
- package/plugins/convertPathData.js +1023 -0
- package/plugins/convertShapeToPath.js +175 -0
- package/plugins/convertStyleToAttrs.js +132 -0
- package/plugins/convertTransform.js +432 -0
- package/plugins/inlineStyles.js +379 -0
- package/plugins/mergePaths.js +104 -0
- package/plugins/mergeStyles.js +93 -0
- package/plugins/minifyStyles.js +148 -0
- package/plugins/moveElemsAttrsToGroup.js +130 -0
- package/plugins/moveGroupAttrsToElems.js +62 -0
- package/plugins/plugins.js +56 -0
- package/plugins/prefixIds.js +241 -0
- package/plugins/preset-default.js +80 -0
- package/plugins/removeAttributesBySelector.js +99 -0
- package/plugins/removeAttrs.js +159 -0
- package/plugins/removeComments.js +31 -0
- package/plugins/removeDesc.js +41 -0
- package/plugins/removeDimensions.js +43 -0
- package/plugins/removeDoctype.js +42 -0
- package/plugins/removeEditorsNSData.js +68 -0
- package/plugins/removeElementsByAttr.js +78 -0
- package/plugins/removeEmptyAttrs.js +33 -0
- package/plugins/removeEmptyContainers.js +58 -0
- package/plugins/removeEmptyText.js +57 -0
- package/plugins/removeHiddenElems.js +318 -0
- package/plugins/removeMetadata.js +29 -0
- package/plugins/removeNonInheritableGroupAttrs.js +38 -0
- package/plugins/removeOffCanvasPaths.js +138 -0
- package/plugins/removeRasterImages.js +33 -0
- package/plugins/removeScriptElement.js +29 -0
- package/plugins/removeStyleElement.js +29 -0
- package/plugins/removeTitle.js +29 -0
- package/plugins/removeUnknownsAndDefaults.js +218 -0
- package/plugins/removeUnusedNS.js +61 -0
- package/plugins/removeUselessDefs.js +65 -0
- package/plugins/removeUselessStrokeAndFill.js +144 -0
- package/plugins/removeViewBox.js +51 -0
- package/plugins/removeXMLNS.js +30 -0
- package/plugins/removeXMLProcInst.js +30 -0
- package/plugins/reusePaths.js +113 -0
- package/plugins/sortAttrs.js +113 -0
- package/plugins/sortDefsChildren.js +60 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { createPreset } = require('../lib/svgo/plugins.js');
|
|
4
|
+
|
|
5
|
+
const removeDoctype = require('./removeDoctype.js');
|
|
6
|
+
const removeXMLProcInst = require('./removeXMLProcInst.js');
|
|
7
|
+
const removeComments = require('./removeComments.js');
|
|
8
|
+
const removeMetadata = require('./removeMetadata.js');
|
|
9
|
+
const removeEditorsNSData = require('./removeEditorsNSData.js');
|
|
10
|
+
const cleanupAttrs = require('./cleanupAttrs.js');
|
|
11
|
+
const mergeStyles = require('./mergeStyles.js');
|
|
12
|
+
const inlineStyles = require('./inlineStyles.js');
|
|
13
|
+
const minifyStyles = require('./minifyStyles.js');
|
|
14
|
+
const cleanupIDs = require('./cleanupIDs.js');
|
|
15
|
+
const removeUselessDefs = require('./removeUselessDefs.js');
|
|
16
|
+
const cleanupNumericValues = require('./cleanupNumericValues.js');
|
|
17
|
+
const convertColors = require('./convertColors.js');
|
|
18
|
+
const removeUnknownsAndDefaults = require('./removeUnknownsAndDefaults.js');
|
|
19
|
+
const removeNonInheritableGroupAttrs = require('./removeNonInheritableGroupAttrs.js');
|
|
20
|
+
const removeUselessStrokeAndFill = require('./removeUselessStrokeAndFill.js');
|
|
21
|
+
const removeViewBox = require('./removeViewBox.js');
|
|
22
|
+
const cleanupEnableBackground = require('./cleanupEnableBackground.js');
|
|
23
|
+
const removeHiddenElems = require('./removeHiddenElems.js');
|
|
24
|
+
const removeEmptyText = require('./removeEmptyText.js');
|
|
25
|
+
const convertShapeToPath = require('./convertShapeToPath.js');
|
|
26
|
+
const convertEllipseToCircle = require('./convertEllipseToCircle.js');
|
|
27
|
+
const moveElemsAttrsToGroup = require('./moveElemsAttrsToGroup.js');
|
|
28
|
+
const moveGroupAttrsToElems = require('./moveGroupAttrsToElems.js');
|
|
29
|
+
const collapseGroups = require('./collapseGroups.js');
|
|
30
|
+
const convertPathData = require('./convertPathData.js');
|
|
31
|
+
const convertTransform = require('./convertTransform.js');
|
|
32
|
+
const removeEmptyAttrs = require('./removeEmptyAttrs.js');
|
|
33
|
+
const removeEmptyContainers = require('./removeEmptyContainers.js');
|
|
34
|
+
const mergePaths = require('./mergePaths.js');
|
|
35
|
+
const removeUnusedNS = require('./removeUnusedNS.js');
|
|
36
|
+
const sortDefsChildren = require('./sortDefsChildren.js');
|
|
37
|
+
const removeTitle = require('./removeTitle.js');
|
|
38
|
+
const removeDesc = require('./removeDesc.js');
|
|
39
|
+
|
|
40
|
+
const presetDefault = createPreset({
|
|
41
|
+
name: 'presetDefault',
|
|
42
|
+
plugins: [
|
|
43
|
+
removeDoctype,
|
|
44
|
+
removeXMLProcInst,
|
|
45
|
+
removeComments,
|
|
46
|
+
removeMetadata,
|
|
47
|
+
removeEditorsNSData,
|
|
48
|
+
cleanupAttrs,
|
|
49
|
+
mergeStyles,
|
|
50
|
+
inlineStyles,
|
|
51
|
+
minifyStyles,
|
|
52
|
+
cleanupIDs,
|
|
53
|
+
removeUselessDefs,
|
|
54
|
+
cleanupNumericValues,
|
|
55
|
+
convertColors,
|
|
56
|
+
removeUnknownsAndDefaults,
|
|
57
|
+
removeNonInheritableGroupAttrs,
|
|
58
|
+
removeUselessStrokeAndFill,
|
|
59
|
+
removeViewBox,
|
|
60
|
+
cleanupEnableBackground,
|
|
61
|
+
removeHiddenElems,
|
|
62
|
+
removeEmptyText,
|
|
63
|
+
convertShapeToPath,
|
|
64
|
+
convertEllipseToCircle,
|
|
65
|
+
moveElemsAttrsToGroup,
|
|
66
|
+
moveGroupAttrsToElems,
|
|
67
|
+
collapseGroups,
|
|
68
|
+
convertPathData,
|
|
69
|
+
convertTransform,
|
|
70
|
+
removeEmptyAttrs,
|
|
71
|
+
removeEmptyContainers,
|
|
72
|
+
mergePaths,
|
|
73
|
+
removeUnusedNS,
|
|
74
|
+
sortDefsChildren,
|
|
75
|
+
removeTitle,
|
|
76
|
+
removeDesc,
|
|
77
|
+
],
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
module.exports = presetDefault;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { querySelectorAll } = require('../lib/xast.js');
|
|
4
|
+
|
|
5
|
+
exports.name = 'removeAttributesBySelector';
|
|
6
|
+
exports.type = 'visitor';
|
|
7
|
+
exports.active = false;
|
|
8
|
+
exports.description =
|
|
9
|
+
'removes attributes of elements that match a css selector';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Removes attributes of elements that match a css selector.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <caption>A selector removing a single attribute</caption>
|
|
16
|
+
* plugins: [
|
|
17
|
+
* {
|
|
18
|
+
* name: "removeAttributesBySelector",
|
|
19
|
+
* params: {
|
|
20
|
+
* selector: "[fill='#00ff00']"
|
|
21
|
+
* attributes: "fill"
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* ]
|
|
25
|
+
*
|
|
26
|
+
* <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
|
|
27
|
+
* ↓
|
|
28
|
+
* <rect x="0" y="0" width="100" height="100" stroke="#00ff00"/>
|
|
29
|
+
*
|
|
30
|
+
* <caption>A selector removing multiple attributes</caption>
|
|
31
|
+
* plugins: [
|
|
32
|
+
* {
|
|
33
|
+
* name: "removeAttributesBySelector",
|
|
34
|
+
* params: {
|
|
35
|
+
* selector: "[fill='#00ff00']",
|
|
36
|
+
* attributes: [
|
|
37
|
+
* "fill",
|
|
38
|
+
* "stroke"
|
|
39
|
+
* ]
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
* ]
|
|
43
|
+
*
|
|
44
|
+
* <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
|
|
45
|
+
* ↓
|
|
46
|
+
* <rect x="0" y="0" width="100" height="100"/>
|
|
47
|
+
*
|
|
48
|
+
* <caption>Multiple selectors removing attributes</caption>
|
|
49
|
+
* plugins: [
|
|
50
|
+
* {
|
|
51
|
+
* name: "removeAttributesBySelector",
|
|
52
|
+
* params: {
|
|
53
|
+
* selectors: [
|
|
54
|
+
* {
|
|
55
|
+
* selector: "[fill='#00ff00']",
|
|
56
|
+
* attributes: "fill"
|
|
57
|
+
* },
|
|
58
|
+
* {
|
|
59
|
+
* selector: "#remove",
|
|
60
|
+
* attributes: [
|
|
61
|
+
* "stroke",
|
|
62
|
+
* "id"
|
|
63
|
+
* ]
|
|
64
|
+
* }
|
|
65
|
+
* ]
|
|
66
|
+
* }
|
|
67
|
+
* }
|
|
68
|
+
* ]
|
|
69
|
+
*
|
|
70
|
+
* <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
|
|
71
|
+
* ↓
|
|
72
|
+
* <rect x="0" y="0" width="100" height="100"/>
|
|
73
|
+
*
|
|
74
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|MDN CSS Selectors
|
|
75
|
+
*
|
|
76
|
+
* @author Bradley Mease
|
|
77
|
+
*
|
|
78
|
+
* @type {import('../lib/types').Plugin<any>}
|
|
79
|
+
*/
|
|
80
|
+
exports.fn = (root, params) => {
|
|
81
|
+
const selectors = Array.isArray(params.selectors)
|
|
82
|
+
? params.selectors
|
|
83
|
+
: [params];
|
|
84
|
+
for (const { selector, attributes } of selectors) {
|
|
85
|
+
const nodes = querySelectorAll(root, selector);
|
|
86
|
+
for (const node of nodes) {
|
|
87
|
+
if (node.type === 'element') {
|
|
88
|
+
if (Array.isArray(attributes)) {
|
|
89
|
+
for (const name of attributes) {
|
|
90
|
+
delete node.attributes[name];
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
delete node.attributes[attributes];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return {};
|
|
99
|
+
};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
exports.name = 'removeAttrs';
|
|
4
|
+
exports.type = 'visitor';
|
|
5
|
+
exports.active = false;
|
|
6
|
+
exports.description = 'removes specified attributes';
|
|
7
|
+
|
|
8
|
+
const DEFAULT_SEPARATOR = ':';
|
|
9
|
+
const ENOATTRS = `Warning: The plugin "removeAttrs" requires the "attrs" parameter.
|
|
10
|
+
It should have a pattern to remove, otherwise the plugin is a noop.
|
|
11
|
+
Config example:
|
|
12
|
+
|
|
13
|
+
plugins: [
|
|
14
|
+
{
|
|
15
|
+
name: "removeAttrs",
|
|
16
|
+
params: {
|
|
17
|
+
attrs: "(fill|stroke)"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Remove attributes
|
|
25
|
+
*
|
|
26
|
+
* @example elemSeparator
|
|
27
|
+
* format: string
|
|
28
|
+
*
|
|
29
|
+
* @example preserveCurrentColor
|
|
30
|
+
* format: boolean
|
|
31
|
+
*
|
|
32
|
+
* @example attrs:
|
|
33
|
+
*
|
|
34
|
+
* format: [ element* : attribute* : value* ]
|
|
35
|
+
*
|
|
36
|
+
* element : regexp (wrapped into ^...$), single * or omitted > all elements (must be present when value is used)
|
|
37
|
+
* attribute : regexp (wrapped into ^...$)
|
|
38
|
+
* value : regexp (wrapped into ^...$), single * or omitted > all values
|
|
39
|
+
*
|
|
40
|
+
* examples:
|
|
41
|
+
*
|
|
42
|
+
* > basic: remove fill attribute
|
|
43
|
+
* ---
|
|
44
|
+
* removeAttrs:
|
|
45
|
+
* attrs: 'fill'
|
|
46
|
+
*
|
|
47
|
+
* > remove fill attribute on path element
|
|
48
|
+
* ---
|
|
49
|
+
* attrs: 'path:fill'
|
|
50
|
+
*
|
|
51
|
+
* > remove fill attribute on path element where value is none
|
|
52
|
+
* ---
|
|
53
|
+
* attrs: 'path:fill:none'
|
|
54
|
+
*
|
|
55
|
+
*
|
|
56
|
+
* > remove all fill and stroke attribute
|
|
57
|
+
* ---
|
|
58
|
+
* attrs:
|
|
59
|
+
* - 'fill'
|
|
60
|
+
* - 'stroke'
|
|
61
|
+
*
|
|
62
|
+
* [is same as]
|
|
63
|
+
*
|
|
64
|
+
* attrs: '(fill|stroke)'
|
|
65
|
+
*
|
|
66
|
+
* [is same as]
|
|
67
|
+
*
|
|
68
|
+
* attrs: '*:(fill|stroke)'
|
|
69
|
+
*
|
|
70
|
+
* [is same as]
|
|
71
|
+
*
|
|
72
|
+
* attrs: '.*:(fill|stroke)'
|
|
73
|
+
*
|
|
74
|
+
* [is same as]
|
|
75
|
+
*
|
|
76
|
+
* attrs: '.*:(fill|stroke):.*'
|
|
77
|
+
*
|
|
78
|
+
*
|
|
79
|
+
* > remove all stroke related attributes
|
|
80
|
+
* ----
|
|
81
|
+
* attrs: 'stroke.*'
|
|
82
|
+
*
|
|
83
|
+
*
|
|
84
|
+
* @author Benny Schudel
|
|
85
|
+
*
|
|
86
|
+
* @type {import('../lib/types').Plugin<{
|
|
87
|
+
* elemSeparator?: string,
|
|
88
|
+
* preserveCurrentColor?: boolean,
|
|
89
|
+
* attrs: string | Array<string>
|
|
90
|
+
* }>}
|
|
91
|
+
*/
|
|
92
|
+
exports.fn = (root, params) => {
|
|
93
|
+
if (typeof params.attrs == 'undefined') {
|
|
94
|
+
console.warn(ENOATTRS);
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const elemSeparator =
|
|
99
|
+
typeof params.elemSeparator == 'string'
|
|
100
|
+
? params.elemSeparator
|
|
101
|
+
: DEFAULT_SEPARATOR;
|
|
102
|
+
const preserveCurrentColor =
|
|
103
|
+
typeof params.preserveCurrentColor == 'boolean'
|
|
104
|
+
? params.preserveCurrentColor
|
|
105
|
+
: false;
|
|
106
|
+
const attrs = Array.isArray(params.attrs) ? params.attrs : [params.attrs];
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
element: {
|
|
110
|
+
enter: (node) => {
|
|
111
|
+
for (let pattern of attrs) {
|
|
112
|
+
// if no element separators (:), assume it's attribute name, and apply to all elements *regardless of value*
|
|
113
|
+
if (pattern.includes(elemSeparator) === false) {
|
|
114
|
+
pattern = ['.*', elemSeparator, pattern, elemSeparator, '.*'].join(
|
|
115
|
+
''
|
|
116
|
+
);
|
|
117
|
+
// if only 1 separator, assume it's element and attribute name, and apply regardless of attribute value
|
|
118
|
+
} else if (pattern.split(elemSeparator).length < 3) {
|
|
119
|
+
pattern = [pattern, elemSeparator, '.*'].join('');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// create regexps for element, attribute name, and attribute value
|
|
123
|
+
const list = pattern.split(elemSeparator).map((value) => {
|
|
124
|
+
// adjust single * to match anything
|
|
125
|
+
if (value === '*') {
|
|
126
|
+
value = '.*';
|
|
127
|
+
}
|
|
128
|
+
return new RegExp(['^', value, '$'].join(''), 'i');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// matches element
|
|
132
|
+
if (list[0].test(node.name)) {
|
|
133
|
+
// loop attributes
|
|
134
|
+
for (const [name, value] of Object.entries(node.attributes)) {
|
|
135
|
+
const isFillCurrentColor =
|
|
136
|
+
preserveCurrentColor &&
|
|
137
|
+
name == 'fill' &&
|
|
138
|
+
value == 'currentColor';
|
|
139
|
+
const isStrokeCurrentColor =
|
|
140
|
+
preserveCurrentColor &&
|
|
141
|
+
name == 'stroke' &&
|
|
142
|
+
value == 'currentColor';
|
|
143
|
+
if (
|
|
144
|
+
!isFillCurrentColor &&
|
|
145
|
+
!isStrokeCurrentColor &&
|
|
146
|
+
// matches attribute name
|
|
147
|
+
list[1].test(name) &&
|
|
148
|
+
// matches attribute value
|
|
149
|
+
list[2].test(value)
|
|
150
|
+
) {
|
|
151
|
+
delete node.attributes[name];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { detachNodeFromParent } = require('../lib/xast.js');
|
|
4
|
+
|
|
5
|
+
exports.name = 'removeComments';
|
|
6
|
+
exports.type = 'visitor';
|
|
7
|
+
exports.active = true;
|
|
8
|
+
exports.description = 'removes comments';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Remove comments.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* <!-- Generator: Adobe Illustrator 15.0.0, SVG Export
|
|
15
|
+
* Plug-In . SVG Version: 6.00 Build 0) -->
|
|
16
|
+
*
|
|
17
|
+
* @author Kir Belevich
|
|
18
|
+
*
|
|
19
|
+
* @type {import('../lib/types').Plugin<void>}
|
|
20
|
+
*/
|
|
21
|
+
exports.fn = () => {
|
|
22
|
+
return {
|
|
23
|
+
comment: {
|
|
24
|
+
enter: (node, parentNode) => {
|
|
25
|
+
if (node.value.charAt(0) !== '!') {
|
|
26
|
+
detachNodeFromParent(node, parentNode);
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { detachNodeFromParent } = require('../lib/xast.js');
|
|
4
|
+
|
|
5
|
+
exports.name = 'removeDesc';
|
|
6
|
+
exports.type = 'visitor';
|
|
7
|
+
exports.active = true;
|
|
8
|
+
exports.description = 'removes <desc>';
|
|
9
|
+
|
|
10
|
+
const standardDescs = /^(Created with|Created using)/;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Removes <desc>.
|
|
14
|
+
* Removes only standard editors content or empty elements 'cause it can be used for accessibility.
|
|
15
|
+
* Enable parameter 'removeAny' to remove any description.
|
|
16
|
+
*
|
|
17
|
+
* https://developer.mozilla.org/en-US/docs/Web/SVG/Element/desc
|
|
18
|
+
*
|
|
19
|
+
* @author Daniel Wabyick
|
|
20
|
+
*
|
|
21
|
+
* @type {import('../lib/types').Plugin<{ removeAny?: boolean }>}
|
|
22
|
+
*/
|
|
23
|
+
exports.fn = (root, params) => {
|
|
24
|
+
const { removeAny = true } = params;
|
|
25
|
+
return {
|
|
26
|
+
element: {
|
|
27
|
+
enter: (node, parentNode) => {
|
|
28
|
+
if (node.name === 'desc') {
|
|
29
|
+
if (
|
|
30
|
+
removeAny ||
|
|
31
|
+
node.children.length === 0 ||
|
|
32
|
+
(node.children[0].type === 'text' &&
|
|
33
|
+
standardDescs.test(node.children[0].value))
|
|
34
|
+
) {
|
|
35
|
+
detachNodeFromParent(node, parentNode);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
exports.name = 'removeDimensions';
|
|
4
|
+
|
|
5
|
+
exports.type = 'perItem';
|
|
6
|
+
|
|
7
|
+
exports.active = false;
|
|
8
|
+
|
|
9
|
+
exports.description =
|
|
10
|
+
'removes width and height in presence of viewBox (opposite to removeViewBox, disable it first)';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Remove width/height attributes and add the viewBox attribute if it's missing
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* <svg width="100" height="50" />
|
|
17
|
+
* ↓
|
|
18
|
+
* <svg viewBox="0 0 100 50" />
|
|
19
|
+
*
|
|
20
|
+
* @param {Object} item current iteration item
|
|
21
|
+
* @return {Boolean} if true, with and height will be filtered out
|
|
22
|
+
*
|
|
23
|
+
* @author Benny Schudel
|
|
24
|
+
*/
|
|
25
|
+
exports.fn = function (item) {
|
|
26
|
+
if (item.type === 'element' && item.name === 'svg') {
|
|
27
|
+
if (item.attributes.viewBox != null) {
|
|
28
|
+
delete item.attributes.width;
|
|
29
|
+
delete item.attributes.height;
|
|
30
|
+
} else if (
|
|
31
|
+
item.attributes.width != null &&
|
|
32
|
+
item.attributes.height != null &&
|
|
33
|
+
Number.isNaN(Number(item.attributes.width)) === false &&
|
|
34
|
+
Number.isNaN(Number(item.attributes.height)) === false
|
|
35
|
+
) {
|
|
36
|
+
const width = Number(item.attributes.width);
|
|
37
|
+
const height = Number(item.attributes.height);
|
|
38
|
+
item.attributes.viewBox = `0 0 ${width} ${height}`;
|
|
39
|
+
delete item.attributes.width;
|
|
40
|
+
delete item.attributes.height;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { detachNodeFromParent } = require('../lib/xast.js');
|
|
4
|
+
|
|
5
|
+
exports.name = 'removeDoctype';
|
|
6
|
+
exports.type = 'visitor';
|
|
7
|
+
exports.active = true;
|
|
8
|
+
exports.description = 'removes doctype declaration';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Remove DOCTYPE declaration.
|
|
12
|
+
*
|
|
13
|
+
* "Unfortunately the SVG DTDs are a source of so many
|
|
14
|
+
* issues that the SVG WG has decided not to write one
|
|
15
|
+
* for the upcoming SVG 1.2 standard. In fact SVG WG
|
|
16
|
+
* members are even telling people not to use a DOCTYPE
|
|
17
|
+
* declaration in SVG 1.0 and 1.1 documents"
|
|
18
|
+
* https://jwatt.org/svg/authoring/#doctype-declaration
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
|
22
|
+
* q"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
26
|
+
* "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" [
|
|
27
|
+
* <!-- an internal subset can be embedded here -->
|
|
28
|
+
* ]>
|
|
29
|
+
*
|
|
30
|
+
* @author Kir Belevich
|
|
31
|
+
*
|
|
32
|
+
* @type {import('../lib/types').Plugin<void>}
|
|
33
|
+
*/
|
|
34
|
+
exports.fn = () => {
|
|
35
|
+
return {
|
|
36
|
+
doctype: {
|
|
37
|
+
enter: (node, parentNode) => {
|
|
38
|
+
detachNodeFromParent(node, parentNode);
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { detachNodeFromParent } = require('../lib/xast.js');
|
|
4
|
+
const { editorNamespaces } = require('./_collections.js');
|
|
5
|
+
|
|
6
|
+
exports.type = 'visitor';
|
|
7
|
+
exports.name = 'removeEditorsNSData';
|
|
8
|
+
exports.active = true;
|
|
9
|
+
exports.description = 'removes editors namespaces, elements and attributes';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Remove editors namespaces, elements and attributes.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <svg xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd">
|
|
16
|
+
* <sodipodi:namedview/>
|
|
17
|
+
* <path sodipodi:nodetypes="cccc"/>
|
|
18
|
+
*
|
|
19
|
+
* @author Kir Belevich
|
|
20
|
+
*
|
|
21
|
+
* @type {import('../lib/types').Plugin<{
|
|
22
|
+
* additionalNamespaces?: Array<string>
|
|
23
|
+
* }>}
|
|
24
|
+
*/
|
|
25
|
+
exports.fn = (_root, params) => {
|
|
26
|
+
let namespaces = editorNamespaces;
|
|
27
|
+
if (Array.isArray(params.additionalNamespaces)) {
|
|
28
|
+
namespaces = [...editorNamespaces, ...params.additionalNamespaces];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* @type {Array<string>}
|
|
32
|
+
*/
|
|
33
|
+
const prefixes = [];
|
|
34
|
+
return {
|
|
35
|
+
element: {
|
|
36
|
+
enter: (node, parentNode) => {
|
|
37
|
+
// collect namespace aliases from svg element
|
|
38
|
+
if (node.name === 'svg') {
|
|
39
|
+
for (const [name, value] of Object.entries(node.attributes)) {
|
|
40
|
+
if (name.startsWith('xmlns:') && namespaces.includes(value)) {
|
|
41
|
+
prefixes.push(name.slice('xmlns:'.length));
|
|
42
|
+
// <svg xmlns:sodipodi="">
|
|
43
|
+
delete node.attributes[name];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// remove editor attributes, for example
|
|
48
|
+
// <* sodipodi:*="">
|
|
49
|
+
for (const name of Object.keys(node.attributes)) {
|
|
50
|
+
if (name.includes(':')) {
|
|
51
|
+
const [prefix] = name.split(':');
|
|
52
|
+
if (prefixes.includes(prefix)) {
|
|
53
|
+
delete node.attributes[name];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// remove editor elements, for example
|
|
58
|
+
// <sodipodi:*>
|
|
59
|
+
if (node.name.includes(':')) {
|
|
60
|
+
const [prefix] = node.name.split(':');
|
|
61
|
+
if (prefixes.includes(prefix)) {
|
|
62
|
+
detachNodeFromParent(node, parentNode);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { detachNodeFromParent } = require('../lib/xast.js');
|
|
4
|
+
|
|
5
|
+
exports.name = 'removeElementsByAttr';
|
|
6
|
+
exports.type = 'visitor';
|
|
7
|
+
exports.active = false;
|
|
8
|
+
exports.description =
|
|
9
|
+
'removes arbitrary elements by ID or className (disabled by default)';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Remove arbitrary SVG elements by ID or className.
|
|
13
|
+
*
|
|
14
|
+
* @example id
|
|
15
|
+
* > single: remove element with ID of `elementID`
|
|
16
|
+
* ---
|
|
17
|
+
* removeElementsByAttr:
|
|
18
|
+
* id: 'elementID'
|
|
19
|
+
*
|
|
20
|
+
* > list: remove multiple elements by ID
|
|
21
|
+
* ---
|
|
22
|
+
* removeElementsByAttr:
|
|
23
|
+
* id:
|
|
24
|
+
* - 'elementID'
|
|
25
|
+
* - 'anotherID'
|
|
26
|
+
*
|
|
27
|
+
* @example class
|
|
28
|
+
* > single: remove all elements with class of `elementClass`
|
|
29
|
+
* ---
|
|
30
|
+
* removeElementsByAttr:
|
|
31
|
+
* class: 'elementClass'
|
|
32
|
+
*
|
|
33
|
+
* > list: remove all elements with class of `elementClass` or `anotherClass`
|
|
34
|
+
* ---
|
|
35
|
+
* removeElementsByAttr:
|
|
36
|
+
* class:
|
|
37
|
+
* - 'elementClass'
|
|
38
|
+
* - 'anotherClass'
|
|
39
|
+
*
|
|
40
|
+
* @author Eli Dupuis (@elidupuis)
|
|
41
|
+
*
|
|
42
|
+
* @type {import('../lib/types').Plugin<{
|
|
43
|
+
* id?: string | Array<string>,
|
|
44
|
+
* class?: string | Array<string>
|
|
45
|
+
* }>}
|
|
46
|
+
*/
|
|
47
|
+
exports.fn = (root, params) => {
|
|
48
|
+
const ids =
|
|
49
|
+
params.id == null ? [] : Array.isArray(params.id) ? params.id : [params.id];
|
|
50
|
+
const classes =
|
|
51
|
+
params.class == null
|
|
52
|
+
? []
|
|
53
|
+
: Array.isArray(params.class)
|
|
54
|
+
? params.class
|
|
55
|
+
: [params.class];
|
|
56
|
+
return {
|
|
57
|
+
element: {
|
|
58
|
+
enter: (node, parentNode) => {
|
|
59
|
+
// remove element if it's `id` matches configured `id` params
|
|
60
|
+
if (node.attributes.id != null && ids.length !== 0) {
|
|
61
|
+
if (ids.includes(node.attributes.id)) {
|
|
62
|
+
detachNodeFromParent(node, parentNode);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// remove element if it's `class` contains any of the configured `class` params
|
|
66
|
+
if (node.attributes.class && classes.length !== 0) {
|
|
67
|
+
const classList = node.attributes.class.split(' ');
|
|
68
|
+
for (const item of classes) {
|
|
69
|
+
if (classList.includes(item)) {
|
|
70
|
+
detachNodeFromParent(node, parentNode);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { attrsGroups } = require('./_collections.js');
|
|
4
|
+
|
|
5
|
+
exports.type = 'visitor';
|
|
6
|
+
exports.name = 'removeEmptyAttrs';
|
|
7
|
+
exports.active = true;
|
|
8
|
+
exports.description = 'removes empty attributes';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Remove attributes with empty values.
|
|
12
|
+
*
|
|
13
|
+
* @author Kir Belevich
|
|
14
|
+
*
|
|
15
|
+
* @type {import('../lib/types').Plugin<void>}
|
|
16
|
+
*/
|
|
17
|
+
exports.fn = () => {
|
|
18
|
+
return {
|
|
19
|
+
element: {
|
|
20
|
+
enter: (node) => {
|
|
21
|
+
for (const [name, value] of Object.entries(node.attributes)) {
|
|
22
|
+
if (
|
|
23
|
+
value === '' &&
|
|
24
|
+
// empty conditional processing attributes prevents elements from rendering
|
|
25
|
+
attrsGroups.conditionalProcessing.includes(name) === false
|
|
26
|
+
) {
|
|
27
|
+
delete node.attributes[name];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
};
|