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
package/lib/svgo-node.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const { pathToFileURL } = require('url');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const {
|
|
8
|
+
extendDefaultPlugins,
|
|
9
|
+
optimize: optimizeAgnostic,
|
|
10
|
+
createContentItem,
|
|
11
|
+
} = require('./svgo.js');
|
|
12
|
+
|
|
13
|
+
exports.extendDefaultPlugins = extendDefaultPlugins;
|
|
14
|
+
exports.createContentItem = createContentItem;
|
|
15
|
+
|
|
16
|
+
const importConfig = async (configFile) => {
|
|
17
|
+
let config;
|
|
18
|
+
// at the moment dynamic import may randomly fail with segfault
|
|
19
|
+
// to workaround this for some users .cjs extension is loaded
|
|
20
|
+
// exclusively with require
|
|
21
|
+
if (configFile.endsWith('.cjs')) {
|
|
22
|
+
config = require(configFile);
|
|
23
|
+
} else {
|
|
24
|
+
try {
|
|
25
|
+
// dynamic import expects file url instead of path and may fail
|
|
26
|
+
// when windows path is provided
|
|
27
|
+
const { default: imported } = await import(pathToFileURL(configFile));
|
|
28
|
+
config = imported;
|
|
29
|
+
} catch (importError) {
|
|
30
|
+
// TODO remove require in v3
|
|
31
|
+
try {
|
|
32
|
+
config = require(configFile);
|
|
33
|
+
} catch (requireError) {
|
|
34
|
+
// throw original error if es module is detected
|
|
35
|
+
if (requireError.code === 'ERR_REQUIRE_ESM') {
|
|
36
|
+
throw importError;
|
|
37
|
+
} else {
|
|
38
|
+
throw requireError;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (config == null || typeof config !== 'object' || Array.isArray(config)) {
|
|
44
|
+
throw Error(`Invalid config file "${configFile}"`);
|
|
45
|
+
}
|
|
46
|
+
return config;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const isFile = async (file) => {
|
|
50
|
+
try {
|
|
51
|
+
const stats = await fs.promises.stat(file);
|
|
52
|
+
return stats.isFile();
|
|
53
|
+
} catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const loadConfig = async (configFile, cwd = process.cwd()) => {
|
|
59
|
+
if (configFile != null) {
|
|
60
|
+
if (path.isAbsolute(configFile)) {
|
|
61
|
+
return await importConfig(configFile);
|
|
62
|
+
} else {
|
|
63
|
+
return await importConfig(path.join(cwd, configFile));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
let dir = cwd;
|
|
67
|
+
// eslint-disable-next-line no-constant-condition
|
|
68
|
+
while (true) {
|
|
69
|
+
const js = path.join(dir, 'svgo.config.js');
|
|
70
|
+
if (await isFile(js)) {
|
|
71
|
+
return await importConfig(js);
|
|
72
|
+
}
|
|
73
|
+
const mjs = path.join(dir, 'svgo.config.mjs');
|
|
74
|
+
if (await isFile(mjs)) {
|
|
75
|
+
return await importConfig(mjs);
|
|
76
|
+
}
|
|
77
|
+
const cjs = path.join(dir, 'svgo.config.cjs');
|
|
78
|
+
if (await isFile(cjs)) {
|
|
79
|
+
return await importConfig(cjs);
|
|
80
|
+
}
|
|
81
|
+
const parent = path.dirname(dir);
|
|
82
|
+
if (dir === parent) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
dir = parent;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
exports.loadConfig = loadConfig;
|
|
89
|
+
|
|
90
|
+
const optimize = (input, config) => {
|
|
91
|
+
if (config == null) {
|
|
92
|
+
config = {};
|
|
93
|
+
}
|
|
94
|
+
if (typeof config !== 'object') {
|
|
95
|
+
throw Error('Config should be an object');
|
|
96
|
+
}
|
|
97
|
+
return optimizeAgnostic(input, {
|
|
98
|
+
...config,
|
|
99
|
+
js2svg: {
|
|
100
|
+
// platform specific default for end of line
|
|
101
|
+
eol: os.EOL === '\r\n' ? 'crlf' : 'lf',
|
|
102
|
+
...config.js2svg,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
exports.optimize = optimize;
|
package/lib/svgo.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
defaultPlugins,
|
|
5
|
+
resolvePluginConfig,
|
|
6
|
+
extendDefaultPlugins,
|
|
7
|
+
} = require('./svgo/config.js');
|
|
8
|
+
const { parseSvg } = require('./parser.js');
|
|
9
|
+
const { stringifySvg } = require('./stringifier.js');
|
|
10
|
+
const { invokePlugins } = require('./svgo/plugins.js');
|
|
11
|
+
const JSAPI = require('./svgo/jsAPI.js');
|
|
12
|
+
const { encodeSVGDatauri } = require('./svgo/tools.js');
|
|
13
|
+
|
|
14
|
+
exports.extendDefaultPlugins = extendDefaultPlugins;
|
|
15
|
+
|
|
16
|
+
const optimize = (input, config) => {
|
|
17
|
+
if (config == null) {
|
|
18
|
+
config = {};
|
|
19
|
+
}
|
|
20
|
+
if (typeof config !== 'object') {
|
|
21
|
+
throw Error('Config should be an object');
|
|
22
|
+
}
|
|
23
|
+
const maxPassCount = config.multipass ? 10 : 1;
|
|
24
|
+
let prevResultSize = Number.POSITIVE_INFINITY;
|
|
25
|
+
let svgjs = null;
|
|
26
|
+
const info = {};
|
|
27
|
+
if (config.path != null) {
|
|
28
|
+
info.path = config.path;
|
|
29
|
+
}
|
|
30
|
+
for (let i = 0; i < maxPassCount; i += 1) {
|
|
31
|
+
info.multipassCount = i;
|
|
32
|
+
// TODO throw this error in v3
|
|
33
|
+
try {
|
|
34
|
+
svgjs = parseSvg(input, config.path);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
return { error: error.toString(), modernError: error };
|
|
37
|
+
}
|
|
38
|
+
if (svgjs.error != null) {
|
|
39
|
+
if (config.path != null) {
|
|
40
|
+
svgjs.path = config.path;
|
|
41
|
+
}
|
|
42
|
+
return svgjs;
|
|
43
|
+
}
|
|
44
|
+
const plugins = config.plugins || defaultPlugins;
|
|
45
|
+
if (Array.isArray(plugins) === false) {
|
|
46
|
+
throw Error(
|
|
47
|
+
"Invalid plugins list. Provided 'plugins' in config should be an array."
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
const resolvedPlugins = plugins.map(resolvePluginConfig);
|
|
51
|
+
const globalOverrides = {};
|
|
52
|
+
if (config.floatPrecision != null) {
|
|
53
|
+
globalOverrides.floatPrecision = config.floatPrecision;
|
|
54
|
+
}
|
|
55
|
+
svgjs = invokePlugins(svgjs, info, resolvedPlugins, null, globalOverrides);
|
|
56
|
+
svgjs = stringifySvg(svgjs, config.js2svg);
|
|
57
|
+
if (svgjs.data.length < prevResultSize) {
|
|
58
|
+
input = svgjs.data;
|
|
59
|
+
prevResultSize = svgjs.data.length;
|
|
60
|
+
} else {
|
|
61
|
+
if (config.datauri) {
|
|
62
|
+
svgjs.data = encodeSVGDatauri(svgjs.data, config.datauri);
|
|
63
|
+
}
|
|
64
|
+
if (config.path != null) {
|
|
65
|
+
svgjs.path = config.path;
|
|
66
|
+
}
|
|
67
|
+
return svgjs;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return svgjs;
|
|
71
|
+
};
|
|
72
|
+
exports.optimize = optimize;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The factory that creates a content item with the helper methods.
|
|
76
|
+
*
|
|
77
|
+
* @param {Object} data which is passed to jsAPI constructor
|
|
78
|
+
* @returns {JSAPI} content item
|
|
79
|
+
*/
|
|
80
|
+
const createContentItem = (data) => {
|
|
81
|
+
return new JSAPI(data);
|
|
82
|
+
};
|
|
83
|
+
exports.createContentItem = createContentItem;
|
package/lib/types.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
export type XastDoctype = {
|
|
2
|
+
type: 'doctype';
|
|
3
|
+
name: string;
|
|
4
|
+
data: {
|
|
5
|
+
doctype: string;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type XastInstruction = {
|
|
10
|
+
type: 'instruction';
|
|
11
|
+
name: string;
|
|
12
|
+
value: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type XastComment = {
|
|
16
|
+
type: 'comment';
|
|
17
|
+
value: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type XastCdata = {
|
|
21
|
+
type: 'cdata';
|
|
22
|
+
value: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type XastText = {
|
|
26
|
+
type: 'text';
|
|
27
|
+
value: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type XastElement = {
|
|
31
|
+
type: 'element';
|
|
32
|
+
name: string;
|
|
33
|
+
attributes: Record<string, string>;
|
|
34
|
+
children: Array<XastChild>;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type XastChild =
|
|
38
|
+
| XastDoctype
|
|
39
|
+
| XastInstruction
|
|
40
|
+
| XastComment
|
|
41
|
+
| XastCdata
|
|
42
|
+
| XastText
|
|
43
|
+
| XastElement;
|
|
44
|
+
|
|
45
|
+
export type XastRoot = {
|
|
46
|
+
type: 'root';
|
|
47
|
+
children: Array<XastChild>;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type XastParent = XastRoot | XastElement;
|
|
51
|
+
|
|
52
|
+
export type XastNode = XastRoot | XastChild;
|
|
53
|
+
|
|
54
|
+
export type StringifyOptions = {
|
|
55
|
+
doctypeStart?: string;
|
|
56
|
+
doctypeEnd?: string;
|
|
57
|
+
procInstStart?: string;
|
|
58
|
+
procInstEnd?: string;
|
|
59
|
+
tagOpenStart?: string;
|
|
60
|
+
tagOpenEnd?: string;
|
|
61
|
+
tagCloseStart?: string;
|
|
62
|
+
tagCloseEnd?: string;
|
|
63
|
+
tagShortStart?: string;
|
|
64
|
+
tagShortEnd?: string;
|
|
65
|
+
attrStart?: string;
|
|
66
|
+
attrEnd?: string;
|
|
67
|
+
commentStart?: string;
|
|
68
|
+
commentEnd?: string;
|
|
69
|
+
cdataStart?: string;
|
|
70
|
+
cdataEnd?: string;
|
|
71
|
+
textStart?: string;
|
|
72
|
+
textEnd?: string;
|
|
73
|
+
indent?: number | string;
|
|
74
|
+
regEntities?: RegExp;
|
|
75
|
+
regValEntities?: RegExp;
|
|
76
|
+
encodeEntity?: (char: string) => string;
|
|
77
|
+
pretty?: boolean;
|
|
78
|
+
useShortTags?: boolean;
|
|
79
|
+
eol?: 'lf' | 'crlf';
|
|
80
|
+
finalNewline?: boolean;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
type VisitorNode<Node> = {
|
|
84
|
+
enter?: (node: Node, parentNode: XastParent) => void | symbol;
|
|
85
|
+
exit?: (node: Node, parentNode: XastParent) => void;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
type VisitorRoot = {
|
|
89
|
+
enter?: (node: XastRoot, parentNode: null) => void;
|
|
90
|
+
exit?: (node: XastRoot, parentNode: null) => void;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export type Visitor = {
|
|
94
|
+
doctype?: VisitorNode<XastDoctype>;
|
|
95
|
+
instruction?: VisitorNode<XastInstruction>;
|
|
96
|
+
comment?: VisitorNode<XastComment>;
|
|
97
|
+
cdata?: VisitorNode<XastCdata>;
|
|
98
|
+
text?: VisitorNode<XastText>;
|
|
99
|
+
element?: VisitorNode<XastElement>;
|
|
100
|
+
root?: VisitorRoot;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export type PluginInfo = {
|
|
104
|
+
path?: string;
|
|
105
|
+
multipassCount: number;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export type Plugin<Params> = (
|
|
109
|
+
root: XastRoot,
|
|
110
|
+
params: Params,
|
|
111
|
+
info: PluginInfo
|
|
112
|
+
) => null | Visitor;
|
|
113
|
+
|
|
114
|
+
export type Specificity = [number, number, number, number];
|
|
115
|
+
|
|
116
|
+
export type StylesheetDeclaration = {
|
|
117
|
+
name: string;
|
|
118
|
+
value: string;
|
|
119
|
+
important: boolean;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export type StylesheetRule = {
|
|
123
|
+
dynamic: boolean;
|
|
124
|
+
selectors: string;
|
|
125
|
+
specificity: Specificity;
|
|
126
|
+
declarations: Array<StylesheetDeclaration>;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export type Stylesheet = {
|
|
130
|
+
rules: Array<StylesheetRule>;
|
|
131
|
+
parents: Map<XastElement, XastParent>;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
type StaticStyle = {
|
|
135
|
+
type: 'static';
|
|
136
|
+
inherited: boolean;
|
|
137
|
+
value: string;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
type DynamicStyle = {
|
|
141
|
+
type: 'dynamic';
|
|
142
|
+
inherited: boolean;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export type ComputedStyles = Record<string, StaticStyle | DynamicStyle>;
|
|
146
|
+
|
|
147
|
+
export type PathDataCommand =
|
|
148
|
+
| 'M'
|
|
149
|
+
| 'm'
|
|
150
|
+
| 'Z'
|
|
151
|
+
| 'z'
|
|
152
|
+
| 'L'
|
|
153
|
+
| 'l'
|
|
154
|
+
| 'H'
|
|
155
|
+
| 'h'
|
|
156
|
+
| 'V'
|
|
157
|
+
| 'v'
|
|
158
|
+
| 'C'
|
|
159
|
+
| 'c'
|
|
160
|
+
| 'S'
|
|
161
|
+
| 's'
|
|
162
|
+
| 'Q'
|
|
163
|
+
| 'q'
|
|
164
|
+
| 'T'
|
|
165
|
+
| 't'
|
|
166
|
+
| 'A'
|
|
167
|
+
| 'a';
|
|
168
|
+
|
|
169
|
+
export type PathDataItem = {
|
|
170
|
+
command: PathDataCommand;
|
|
171
|
+
args: Array<number>;
|
|
172
|
+
};
|
package/lib/xast.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {import('./types').XastNode} XastNode
|
|
5
|
+
* @typedef {import('./types').XastChild} XastChild
|
|
6
|
+
* @typedef {import('./types').XastParent} XastParent
|
|
7
|
+
* @typedef {import('./types').Visitor} Visitor
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { selectAll, selectOne, is } = require('css-select');
|
|
11
|
+
const xastAdaptor = require('./svgo/css-select-adapter.js');
|
|
12
|
+
|
|
13
|
+
const cssSelectOptions = {
|
|
14
|
+
xmlMode: true,
|
|
15
|
+
adapter: xastAdaptor,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @type {(node: XastNode, selector: string) => Array<XastChild>}
|
|
20
|
+
*/
|
|
21
|
+
const querySelectorAll = (node, selector) => {
|
|
22
|
+
return selectAll(selector, node, cssSelectOptions);
|
|
23
|
+
};
|
|
24
|
+
exports.querySelectorAll = querySelectorAll;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @type {(node: XastNode, selector: string) => null | XastChild}
|
|
28
|
+
*/
|
|
29
|
+
const querySelector = (node, selector) => {
|
|
30
|
+
return selectOne(selector, node, cssSelectOptions);
|
|
31
|
+
};
|
|
32
|
+
exports.querySelector = querySelector;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @type {(node: XastChild, selector: string) => boolean}
|
|
36
|
+
*/
|
|
37
|
+
const matches = (node, selector) => {
|
|
38
|
+
return is(node, selector, cssSelectOptions);
|
|
39
|
+
};
|
|
40
|
+
exports.matches = matches;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @type {(node: XastChild, name: string) => null | XastChild}
|
|
44
|
+
*/
|
|
45
|
+
const closestByName = (node, name) => {
|
|
46
|
+
let currentNode = node;
|
|
47
|
+
while (currentNode) {
|
|
48
|
+
if (currentNode.type === 'element' && currentNode.name === name) {
|
|
49
|
+
return currentNode;
|
|
50
|
+
}
|
|
51
|
+
// @ts-ignore parentNode is hidden from public usage
|
|
52
|
+
currentNode = currentNode.parentNode;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
};
|
|
56
|
+
exports.closestByName = closestByName;
|
|
57
|
+
|
|
58
|
+
const visitSkip = Symbol();
|
|
59
|
+
exports.visitSkip = visitSkip;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @type {(node: XastNode, visitor: Visitor, parentNode?: any) => void}
|
|
63
|
+
*/
|
|
64
|
+
const visit = (node, visitor, parentNode) => {
|
|
65
|
+
const callbacks = visitor[node.type];
|
|
66
|
+
if (callbacks && callbacks.enter) {
|
|
67
|
+
// @ts-ignore hard to infer
|
|
68
|
+
const symbol = callbacks.enter(node, parentNode);
|
|
69
|
+
if (symbol === visitSkip) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// visit root children
|
|
74
|
+
if (node.type === 'root') {
|
|
75
|
+
// copy children array to not loose cursor when children is spliced
|
|
76
|
+
for (const child of node.children) {
|
|
77
|
+
visit(child, visitor, node);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// visit element children if still attached to parent
|
|
81
|
+
if (node.type === 'element') {
|
|
82
|
+
if (parentNode.children.includes(node)) {
|
|
83
|
+
for (const child of node.children) {
|
|
84
|
+
visit(child, visitor, node);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (callbacks && callbacks.exit) {
|
|
89
|
+
// @ts-ignore hard to infer
|
|
90
|
+
callbacks.exit(node, parentNode);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
exports.visit = visit;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @type {(node: XastChild, parentNode: XastParent) => void}
|
|
97
|
+
*/
|
|
98
|
+
const detachNodeFromParent = (node, parentNode) => {
|
|
99
|
+
// avoid splice to not break for loops
|
|
100
|
+
parentNode.children = parentNode.children.filter((child) => child !== node);
|
|
101
|
+
};
|
|
102
|
+
exports.detachNodeFromParent = detachNodeFromParent;
|
package/package.json
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
{
|
|
2
|
+
"packageManager": "yarn@2.4.3",
|
|
3
|
+
"name": "svgo-v2",
|
|
4
|
+
"version": "2.8.0",
|
|
5
|
+
"description": "将css-tree替换为css-tree-v2",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"svgo",
|
|
9
|
+
"svg",
|
|
10
|
+
"optimize",
|
|
11
|
+
"minify"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/svg/svgo",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/svg/svgo/issues"
|
|
16
|
+
},
|
|
17
|
+
"author": {
|
|
18
|
+
"name": "Kir Belevich",
|
|
19
|
+
"email": "kir@belevi.ch",
|
|
20
|
+
"url": "https://github.com/deepsweet"
|
|
21
|
+
},
|
|
22
|
+
"contributors": [
|
|
23
|
+
{
|
|
24
|
+
"name": "Sergey Belov",
|
|
25
|
+
"email": "peimei@ya.ru",
|
|
26
|
+
"url": "https://github.com/arikon"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "Lev Solntsev",
|
|
30
|
+
"email": "lev.sun@ya.ru",
|
|
31
|
+
"url": "https://github.com/GreLI"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "Bogdan Chadkin",
|
|
35
|
+
"email": "trysound@yandex.ru",
|
|
36
|
+
"url": "https://github.com/TrySound"
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git://github.com/svg/svgo.git"
|
|
42
|
+
},
|
|
43
|
+
"main": "./lib/svgo-node.js",
|
|
44
|
+
"bin": "./bin/svgo",
|
|
45
|
+
"files": [
|
|
46
|
+
"bin",
|
|
47
|
+
"lib",
|
|
48
|
+
"plugins",
|
|
49
|
+
"dist",
|
|
50
|
+
"!**/*.test.js"
|
|
51
|
+
],
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=10.13.0"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules jest --maxWorkers=4 --coverage",
|
|
57
|
+
"lint": "eslint --ignore-path .gitignore . && prettier --check \"**/*.js\" --ignore-path .gitignore",
|
|
58
|
+
"fix": "eslint --ignore-path .gitignore --fix . && prettier --write \"**/*.js\" --ignore-path .gitignore",
|
|
59
|
+
"typecheck": "tsc",
|
|
60
|
+
"test-browser": "rollup -c && node ./test/browser.js",
|
|
61
|
+
"test-regression": "node ./test/regression-extract.js && NO_DIFF=1 node ./test/regression.js"
|
|
62
|
+
},
|
|
63
|
+
"prettier": {
|
|
64
|
+
"singleQuote": true
|
|
65
|
+
},
|
|
66
|
+
"eslintConfig": {
|
|
67
|
+
"parserOptions": {
|
|
68
|
+
"ecmaVersion": "2021"
|
|
69
|
+
},
|
|
70
|
+
"env": {
|
|
71
|
+
"node": true,
|
|
72
|
+
"es2021": true
|
|
73
|
+
},
|
|
74
|
+
"extends": [
|
|
75
|
+
"eslint:recommended"
|
|
76
|
+
],
|
|
77
|
+
"overrides": [
|
|
78
|
+
{
|
|
79
|
+
"files": [
|
|
80
|
+
"rollup.config.js"
|
|
81
|
+
],
|
|
82
|
+
"parserOptions": {
|
|
83
|
+
"sourceType": "module"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"files": [
|
|
88
|
+
"**/*.test.js"
|
|
89
|
+
],
|
|
90
|
+
"env": {
|
|
91
|
+
"jest": true
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
"jest": {
|
|
97
|
+
"coveragePathIgnorePatterns": [
|
|
98
|
+
"fixtures"
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
"dependencies": {
|
|
102
|
+
"@trysound/sax": "0.2.0",
|
|
103
|
+
"commander": "^7.2.0",
|
|
104
|
+
"css-select": "^4.1.3",
|
|
105
|
+
"css-tree-v2": "^1.1.3",
|
|
106
|
+
"csso": "^4.2.0",
|
|
107
|
+
"picocolors": "^1.0.0",
|
|
108
|
+
"stable": "^0.1.8"
|
|
109
|
+
},
|
|
110
|
+
"devDependencies": {
|
|
111
|
+
"@rollup/plugin-commonjs": "^20.0.0",
|
|
112
|
+
"@rollup/plugin-json": "^4.1.0",
|
|
113
|
+
"@rollup/plugin-node-resolve": "^13.0.4",
|
|
114
|
+
"@types/css-tree": "^1.0.6",
|
|
115
|
+
"@types/csso": "^4.2.0",
|
|
116
|
+
"@types/jest": "^27.0.1",
|
|
117
|
+
"del": "^6.0.0",
|
|
118
|
+
"eslint": "^7.32.0",
|
|
119
|
+
"jest": "^27.2.5",
|
|
120
|
+
"node-fetch": "^2.6.2",
|
|
121
|
+
"pixelmatch": "^5.2.1",
|
|
122
|
+
"playwright": "^1.14.1",
|
|
123
|
+
"pngjs": "^6.0.0",
|
|
124
|
+
"prettier": "^2.4.0",
|
|
125
|
+
"rollup": "^2.56.3",
|
|
126
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
127
|
+
"tar-stream": "^2.2.0",
|
|
128
|
+
"typescript": "^4.4.3"
|
|
129
|
+
}
|
|
130
|
+
}
|