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,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var CSSClassList = function (node) {
|
|
4
|
+
this.parentNode = node;
|
|
5
|
+
this.classNames = new Set();
|
|
6
|
+
const value = node.attributes.class;
|
|
7
|
+
if (value != null) {
|
|
8
|
+
this.addClassValueHandler();
|
|
9
|
+
this.setClassValue(value);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// attr.class.value
|
|
14
|
+
|
|
15
|
+
CSSClassList.prototype.addClassValueHandler = function () {
|
|
16
|
+
Object.defineProperty(this.parentNode.attributes, 'class', {
|
|
17
|
+
get: this.getClassValue.bind(this),
|
|
18
|
+
set: this.setClassValue.bind(this),
|
|
19
|
+
enumerable: true,
|
|
20
|
+
configurable: true,
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
CSSClassList.prototype.getClassValue = function () {
|
|
25
|
+
var arrClassNames = Array.from(this.classNames);
|
|
26
|
+
return arrClassNames.join(' ');
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
CSSClassList.prototype.setClassValue = function (newValue) {
|
|
30
|
+
if (typeof newValue === 'undefined') {
|
|
31
|
+
this.classNames.clear();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
var arrClassNames = newValue.split(' ');
|
|
35
|
+
this.classNames = new Set(arrClassNames);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
CSSClassList.prototype.add = function (/* variadic */) {
|
|
39
|
+
this.addClassValueHandler();
|
|
40
|
+
Object.values(arguments).forEach(this._addSingle.bind(this));
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
CSSClassList.prototype._addSingle = function (className) {
|
|
44
|
+
this.classNames.add(className);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
CSSClassList.prototype.remove = function (/* variadic */) {
|
|
48
|
+
this.addClassValueHandler();
|
|
49
|
+
Object.values(arguments).forEach(this._removeSingle.bind(this));
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
CSSClassList.prototype._removeSingle = function (className) {
|
|
53
|
+
this.classNames.delete(className);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
CSSClassList.prototype.item = function (index) {
|
|
57
|
+
var arrClassNames = Array.from(this.classNames);
|
|
58
|
+
return arrClassNames[index];
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
CSSClassList.prototype.toggle = function (className, force) {
|
|
62
|
+
if (this.contains(className) || force === false) {
|
|
63
|
+
this.classNames.delete(className);
|
|
64
|
+
}
|
|
65
|
+
this.classNames.add(className);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
CSSClassList.prototype.contains = function (className) {
|
|
69
|
+
return this.classNames.has(className);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
module.exports = CSSClassList;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const isTag = (node) => {
|
|
4
|
+
return node.type === 'element';
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
const existsOne = (test, elems) => {
|
|
8
|
+
return elems.some((elem) => {
|
|
9
|
+
if (isTag(elem)) {
|
|
10
|
+
return test(elem) || existsOne(test, getChildren(elem));
|
|
11
|
+
} else {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const getAttributeValue = (elem, name) => {
|
|
18
|
+
return elem.attributes[name];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const getChildren = (node) => {
|
|
22
|
+
return node.children || [];
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const getName = (elemAst) => {
|
|
26
|
+
return elemAst.name;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const getParent = (node) => {
|
|
30
|
+
return node.parentNode || null;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const getSiblings = (elem) => {
|
|
34
|
+
var parent = getParent(elem);
|
|
35
|
+
return parent ? getChildren(parent) : [];
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const getText = (node) => {
|
|
39
|
+
if (node.children[0].type === 'text' && node.children[0].type === 'cdata') {
|
|
40
|
+
return node.children[0].value;
|
|
41
|
+
}
|
|
42
|
+
return '';
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const hasAttrib = (elem, name) => {
|
|
46
|
+
return elem.attributes[name] !== undefined;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const removeSubsets = (nodes) => {
|
|
50
|
+
let idx = nodes.length;
|
|
51
|
+
let node;
|
|
52
|
+
let ancestor;
|
|
53
|
+
let replace;
|
|
54
|
+
// Check if each node (or one of its ancestors) is already contained in the
|
|
55
|
+
// array.
|
|
56
|
+
while (--idx > -1) {
|
|
57
|
+
node = ancestor = nodes[idx];
|
|
58
|
+
// Temporarily remove the node under consideration
|
|
59
|
+
nodes[idx] = null;
|
|
60
|
+
replace = true;
|
|
61
|
+
while (ancestor) {
|
|
62
|
+
if (nodes.includes(ancestor)) {
|
|
63
|
+
replace = false;
|
|
64
|
+
nodes.splice(idx, 1);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
ancestor = getParent(ancestor);
|
|
68
|
+
}
|
|
69
|
+
// If the node has been found to be unique, re-insert it.
|
|
70
|
+
if (replace) {
|
|
71
|
+
nodes[idx] = node;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return nodes;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const findAll = (test, elems) => {
|
|
78
|
+
const result = [];
|
|
79
|
+
for (const elem of elems) {
|
|
80
|
+
if (isTag(elem)) {
|
|
81
|
+
if (test(elem)) {
|
|
82
|
+
result.push(elem);
|
|
83
|
+
}
|
|
84
|
+
result.push(...findAll(test, getChildren(elem)));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const findOne = (test, elems) => {
|
|
91
|
+
for (const elem of elems) {
|
|
92
|
+
if (isTag(elem)) {
|
|
93
|
+
if (test(elem)) {
|
|
94
|
+
return elem;
|
|
95
|
+
}
|
|
96
|
+
const result = findOne(test, getChildren(elem));
|
|
97
|
+
if (result) {
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const svgoCssSelectAdapter = {
|
|
106
|
+
isTag,
|
|
107
|
+
existsOne,
|
|
108
|
+
getAttributeValue,
|
|
109
|
+
getChildren,
|
|
110
|
+
getName,
|
|
111
|
+
getParent,
|
|
112
|
+
getSiblings,
|
|
113
|
+
getText,
|
|
114
|
+
hasAttrib,
|
|
115
|
+
removeSubsets,
|
|
116
|
+
findAll,
|
|
117
|
+
findOne,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
module.exports = svgoCssSelectAdapter;
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var csstree = require('css-tree-v2'),
|
|
4
|
+
csstools = require('../css-tools');
|
|
5
|
+
|
|
6
|
+
var CSSStyleDeclaration = function (node) {
|
|
7
|
+
this.parentNode = node;
|
|
8
|
+
|
|
9
|
+
this.properties = new Map();
|
|
10
|
+
this.hasSynced = false;
|
|
11
|
+
|
|
12
|
+
this.styleValue = null;
|
|
13
|
+
|
|
14
|
+
this.parseError = false;
|
|
15
|
+
const value = node.attributes.style;
|
|
16
|
+
if (value != null) {
|
|
17
|
+
this.addStyleValueHandler();
|
|
18
|
+
this.setStyleValue(value);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// attr.style.value
|
|
23
|
+
|
|
24
|
+
CSSStyleDeclaration.prototype.addStyleValueHandler = function () {
|
|
25
|
+
Object.defineProperty(this.parentNode.attributes, 'style', {
|
|
26
|
+
get: this.getStyleValue.bind(this),
|
|
27
|
+
set: this.setStyleValue.bind(this),
|
|
28
|
+
enumerable: true,
|
|
29
|
+
configurable: true,
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
CSSStyleDeclaration.prototype.getStyleValue = function () {
|
|
34
|
+
return this.getCssText();
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
CSSStyleDeclaration.prototype.setStyleValue = function (newValue) {
|
|
38
|
+
this.properties.clear(); // reset all existing properties
|
|
39
|
+
this.styleValue = newValue;
|
|
40
|
+
this.hasSynced = false; // raw css changed
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
CSSStyleDeclaration.prototype._loadCssText = function () {
|
|
44
|
+
if (this.hasSynced) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
this.hasSynced = true; // must be set here to prevent loop in setProperty(...)
|
|
48
|
+
|
|
49
|
+
if (!this.styleValue || this.styleValue.length === 0) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
var inlineCssStr = this.styleValue;
|
|
53
|
+
|
|
54
|
+
var declarations = {};
|
|
55
|
+
try {
|
|
56
|
+
declarations = csstree.parse(inlineCssStr, {
|
|
57
|
+
context: 'declarationList',
|
|
58
|
+
parseValue: false,
|
|
59
|
+
});
|
|
60
|
+
} catch (parseError) {
|
|
61
|
+
this.parseError = parseError;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
this.parseError = false;
|
|
65
|
+
|
|
66
|
+
var self = this;
|
|
67
|
+
declarations.children.each(function (declaration) {
|
|
68
|
+
try {
|
|
69
|
+
var styleDeclaration = csstools.csstreeToStyleDeclaration(declaration);
|
|
70
|
+
self.setProperty(
|
|
71
|
+
styleDeclaration.name,
|
|
72
|
+
styleDeclaration.value,
|
|
73
|
+
styleDeclaration.priority
|
|
74
|
+
);
|
|
75
|
+
} catch (styleError) {
|
|
76
|
+
if (styleError.message !== 'Unknown node type: undefined') {
|
|
77
|
+
self.parseError = styleError;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// only reads from properties
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get the textual representation of the declaration block (equivalent to .cssText attribute).
|
|
87
|
+
*
|
|
88
|
+
* @return {string} Textual representation of the declaration block (empty string for no properties)
|
|
89
|
+
*/
|
|
90
|
+
CSSStyleDeclaration.prototype.getCssText = function () {
|
|
91
|
+
var properties = this.getProperties();
|
|
92
|
+
|
|
93
|
+
if (this.parseError) {
|
|
94
|
+
// in case of a parse error, pass through original styles
|
|
95
|
+
return this.styleValue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
var cssText = [];
|
|
99
|
+
properties.forEach(function (property, propertyName) {
|
|
100
|
+
var strImportant = property.priority === 'important' ? '!important' : '';
|
|
101
|
+
cssText.push(
|
|
102
|
+
propertyName.trim() + ':' + property.value.trim() + strImportant
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
return cssText.join(';');
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
CSSStyleDeclaration.prototype._handleParseError = function () {
|
|
109
|
+
if (this.parseError) {
|
|
110
|
+
console.warn(
|
|
111
|
+
"Warning: Parse error when parsing inline styles, style properties of this element cannot be used. The raw styles can still be get/set using .attr('style').value. Error details: " +
|
|
112
|
+
this.parseError
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
CSSStyleDeclaration.prototype._getProperty = function (propertyName) {
|
|
118
|
+
if (typeof propertyName === 'undefined') {
|
|
119
|
+
throw Error('1 argument required, but only 0 present.');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
var properties = this.getProperties();
|
|
123
|
+
this._handleParseError();
|
|
124
|
+
|
|
125
|
+
var property = properties.get(propertyName.trim());
|
|
126
|
+
return property;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Return the optional priority, "important".
|
|
131
|
+
*
|
|
132
|
+
* @param {string} propertyName representing the property name to be checked.
|
|
133
|
+
* @return {string} priority that represents the priority (e.g. "important") if one exists. If none exists, returns the empty string.
|
|
134
|
+
*/
|
|
135
|
+
CSSStyleDeclaration.prototype.getPropertyPriority = function (propertyName) {
|
|
136
|
+
var property = this._getProperty(propertyName);
|
|
137
|
+
return property ? property.priority : '';
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Return the property value given a property name.
|
|
142
|
+
*
|
|
143
|
+
* @param {string} propertyName representing the property name to be checked.
|
|
144
|
+
* @return {string} value containing the value of the property. If not set, returns the empty string.
|
|
145
|
+
*/
|
|
146
|
+
CSSStyleDeclaration.prototype.getPropertyValue = function (propertyName) {
|
|
147
|
+
var property = this._getProperty(propertyName);
|
|
148
|
+
return property ? property.value : null;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Return a property name.
|
|
153
|
+
*
|
|
154
|
+
* @param {number} index of the node to be fetched. The index is zero-based.
|
|
155
|
+
* @return {string} propertyName that is the name of the CSS property at the specified index.
|
|
156
|
+
*/
|
|
157
|
+
CSSStyleDeclaration.prototype.item = function (index) {
|
|
158
|
+
if (typeof index === 'undefined') {
|
|
159
|
+
throw Error('1 argument required, but only 0 present.');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
var properties = this.getProperties();
|
|
163
|
+
this._handleParseError();
|
|
164
|
+
|
|
165
|
+
return Array.from(properties.keys())[index];
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Return all properties of the node.
|
|
170
|
+
*
|
|
171
|
+
* @return {Map} properties that is a Map with propertyName as key and property (propertyValue + propertyPriority) as value.
|
|
172
|
+
*/
|
|
173
|
+
CSSStyleDeclaration.prototype.getProperties = function () {
|
|
174
|
+
this._loadCssText();
|
|
175
|
+
return this.properties;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// writes to properties
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Remove a property from the CSS declaration block.
|
|
182
|
+
*
|
|
183
|
+
* @param {string} propertyName representing the property name to be removed.
|
|
184
|
+
* @return {string} oldValue equal to the value of the CSS property before it was removed.
|
|
185
|
+
*/
|
|
186
|
+
CSSStyleDeclaration.prototype.removeProperty = function (propertyName) {
|
|
187
|
+
if (typeof propertyName === 'undefined') {
|
|
188
|
+
throw Error('1 argument required, but only 0 present.');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
this.addStyleValueHandler();
|
|
192
|
+
|
|
193
|
+
var properties = this.getProperties();
|
|
194
|
+
this._handleParseError();
|
|
195
|
+
|
|
196
|
+
var oldValue = this.getPropertyValue(propertyName);
|
|
197
|
+
properties.delete(propertyName.trim());
|
|
198
|
+
return oldValue;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Modify an existing CSS property or creates a new CSS property in the declaration block.
|
|
203
|
+
*
|
|
204
|
+
* @param {string} propertyName representing the CSS property name to be modified.
|
|
205
|
+
* @param {string} value containing the new property value. If not specified, treated as the empty string. value must not contain "!important" -- that should be set using the priority parameter.
|
|
206
|
+
* @param {string} priority allowing the "important" CSS priority to be set. If not specified, treated as the empty string.
|
|
207
|
+
* @return {{value: string, priority: string}}
|
|
208
|
+
*/
|
|
209
|
+
CSSStyleDeclaration.prototype.setProperty = function (
|
|
210
|
+
propertyName,
|
|
211
|
+
value,
|
|
212
|
+
priority
|
|
213
|
+
) {
|
|
214
|
+
if (typeof propertyName === 'undefined') {
|
|
215
|
+
throw Error('propertyName argument required, but only not present.');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
this.addStyleValueHandler();
|
|
219
|
+
|
|
220
|
+
var properties = this.getProperties();
|
|
221
|
+
this._handleParseError();
|
|
222
|
+
|
|
223
|
+
var property = {
|
|
224
|
+
value: value.trim(),
|
|
225
|
+
priority: priority.trim(),
|
|
226
|
+
};
|
|
227
|
+
properties.set(propertyName.trim(), property);
|
|
228
|
+
|
|
229
|
+
return property;
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
module.exports = CSSStyleDeclaration;
|