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.
Files changed (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +294 -0
  3. package/bin/svgo +10 -0
  4. package/dist/svgo.browser.js +1 -0
  5. package/lib/css-tools.js +239 -0
  6. package/lib/parser.js +259 -0
  7. package/lib/path.js +347 -0
  8. package/lib/stringifier.js +326 -0
  9. package/lib/style.js +283 -0
  10. package/lib/svgo/coa.js +517 -0
  11. package/lib/svgo/config.js +138 -0
  12. package/lib/svgo/css-class-list.js +72 -0
  13. package/lib/svgo/css-select-adapter.d.ts +2 -0
  14. package/lib/svgo/css-select-adapter.js +120 -0
  15. package/lib/svgo/css-style-declaration.js +232 -0
  16. package/lib/svgo/jsAPI.d.ts +2 -0
  17. package/lib/svgo/jsAPI.js +443 -0
  18. package/lib/svgo/plugins.js +109 -0
  19. package/lib/svgo/tools.js +137 -0
  20. package/lib/svgo-node.js +106 -0
  21. package/lib/svgo.js +83 -0
  22. package/lib/types.ts +172 -0
  23. package/lib/xast.js +102 -0
  24. package/package.json +130 -0
  25. package/plugins/_applyTransforms.js +335 -0
  26. package/plugins/_collections.js +2168 -0
  27. package/plugins/_path.js +816 -0
  28. package/plugins/_transforms.js +379 -0
  29. package/plugins/addAttributesToSVGElement.js +87 -0
  30. package/plugins/addClassesToSVGElement.js +87 -0
  31. package/plugins/cleanupAttrs.js +55 -0
  32. package/plugins/cleanupEnableBackground.js +75 -0
  33. package/plugins/cleanupIDs.js +297 -0
  34. package/plugins/cleanupListOfValues.js +154 -0
  35. package/plugins/cleanupNumericValues.js +113 -0
  36. package/plugins/collapseGroups.js +135 -0
  37. package/plugins/convertColors.js +152 -0
  38. package/plugins/convertEllipseToCircle.js +39 -0
  39. package/plugins/convertPathData.js +1023 -0
  40. package/plugins/convertShapeToPath.js +175 -0
  41. package/plugins/convertStyleToAttrs.js +132 -0
  42. package/plugins/convertTransform.js +432 -0
  43. package/plugins/inlineStyles.js +379 -0
  44. package/plugins/mergePaths.js +104 -0
  45. package/plugins/mergeStyles.js +93 -0
  46. package/plugins/minifyStyles.js +148 -0
  47. package/plugins/moveElemsAttrsToGroup.js +130 -0
  48. package/plugins/moveGroupAttrsToElems.js +62 -0
  49. package/plugins/plugins.js +56 -0
  50. package/plugins/prefixIds.js +241 -0
  51. package/plugins/preset-default.js +80 -0
  52. package/plugins/removeAttributesBySelector.js +99 -0
  53. package/plugins/removeAttrs.js +159 -0
  54. package/plugins/removeComments.js +31 -0
  55. package/plugins/removeDesc.js +41 -0
  56. package/plugins/removeDimensions.js +43 -0
  57. package/plugins/removeDoctype.js +42 -0
  58. package/plugins/removeEditorsNSData.js +68 -0
  59. package/plugins/removeElementsByAttr.js +78 -0
  60. package/plugins/removeEmptyAttrs.js +33 -0
  61. package/plugins/removeEmptyContainers.js +58 -0
  62. package/plugins/removeEmptyText.js +57 -0
  63. package/plugins/removeHiddenElems.js +318 -0
  64. package/plugins/removeMetadata.js +29 -0
  65. package/plugins/removeNonInheritableGroupAttrs.js +38 -0
  66. package/plugins/removeOffCanvasPaths.js +138 -0
  67. package/plugins/removeRasterImages.js +33 -0
  68. package/plugins/removeScriptElement.js +29 -0
  69. package/plugins/removeStyleElement.js +29 -0
  70. package/plugins/removeTitle.js +29 -0
  71. package/plugins/removeUnknownsAndDefaults.js +218 -0
  72. package/plugins/removeUnusedNS.js +61 -0
  73. package/plugins/removeUselessDefs.js +65 -0
  74. package/plugins/removeUselessStrokeAndFill.js +144 -0
  75. package/plugins/removeViewBox.js +51 -0
  76. package/plugins/removeXMLNS.js +30 -0
  77. package/plugins/removeXMLProcInst.js +30 -0
  78. package/plugins/reusePaths.js +113 -0
  79. package/plugins/sortAttrs.js +113 -0
  80. package/plugins/sortDefsChildren.js +60 -0
@@ -0,0 +1,335 @@
1
+ 'use strict';
2
+
3
+ // TODO implement as separate plugin
4
+
5
+ const {
6
+ transformsMultiply,
7
+ transform2js,
8
+ transformArc,
9
+ } = require('./_transforms.js');
10
+ const { removeLeadingZero } = require('../lib/svgo/tools.js');
11
+ const { referencesProps, attrsGroupsDefaults } = require('./_collections.js');
12
+
13
+ const regNumericValues = /[-+]?(\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g;
14
+ const defaultStrokeWidth = attrsGroupsDefaults.presentation['stroke-width'];
15
+
16
+ /**
17
+ * Apply transformation(s) to the Path data.
18
+ *
19
+ * @param {Object} elem current element
20
+ * @param {Array} path input path data
21
+ * @param {Object} params whether to apply transforms to stroked lines and transform precision (used for stroke width)
22
+ * @return {Array} output path data
23
+ */
24
+ const applyTransforms = (elem, pathData, params) => {
25
+ // if there are no 'stroke' attr and references to other objects such as
26
+ // gradiends or clip-path which are also subjects to transform.
27
+ if (
28
+ elem.attributes.transform == null ||
29
+ elem.attributes.transform === '' ||
30
+ // styles are not considered when applying transform
31
+ // can be fixed properly with new style engine
32
+ elem.attributes.style != null ||
33
+ Object.entries(elem.attributes).some(
34
+ ([name, value]) =>
35
+ referencesProps.includes(name) && value.includes('url(')
36
+ )
37
+ ) {
38
+ return;
39
+ }
40
+
41
+ const matrix = transformsMultiply(transform2js(elem.attributes.transform));
42
+ const stroke = elem.computedAttr('stroke');
43
+ const id = elem.computedAttr('id');
44
+ const transformPrecision = params.transformPrecision;
45
+
46
+ if (stroke && stroke != 'none') {
47
+ if (
48
+ !params.applyTransformsStroked ||
49
+ ((matrix.data[0] != matrix.data[3] ||
50
+ matrix.data[1] != -matrix.data[2]) &&
51
+ (matrix.data[0] != -matrix.data[3] || matrix.data[1] != matrix.data[2]))
52
+ )
53
+ return;
54
+
55
+ // "stroke-width" should be inside the part with ID, otherwise it can be overrided in <use>
56
+ if (id) {
57
+ let idElem = elem;
58
+ let hasStrokeWidth = false;
59
+
60
+ do {
61
+ if (idElem.attributes['stroke-width']) {
62
+ hasStrokeWidth = true;
63
+ }
64
+ } while (
65
+ idElem.attributes.id !== id &&
66
+ !hasStrokeWidth &&
67
+ (idElem = idElem.parentNode)
68
+ );
69
+
70
+ if (!hasStrokeWidth) return;
71
+ }
72
+
73
+ const scale = +Math.sqrt(
74
+ matrix.data[0] * matrix.data[0] + matrix.data[1] * matrix.data[1]
75
+ ).toFixed(transformPrecision);
76
+
77
+ if (scale !== 1) {
78
+ const strokeWidth =
79
+ elem.computedAttr('stroke-width') || defaultStrokeWidth;
80
+
81
+ if (
82
+ elem.attributes['vector-effect'] == null ||
83
+ elem.attributes['vector-effect'] !== 'non-scaling-stroke'
84
+ ) {
85
+ if (elem.attributes['stroke-width'] != null) {
86
+ elem.attributes['stroke-width'] = elem.attributes['stroke-width']
87
+ .trim()
88
+ .replace(regNumericValues, (num) => removeLeadingZero(num * scale));
89
+ } else {
90
+ elem.attributes['stroke-width'] = strokeWidth.replace(
91
+ regNumericValues,
92
+ (num) => removeLeadingZero(num * scale)
93
+ );
94
+ }
95
+
96
+ if (elem.attributes['stroke-dashoffset'] != null) {
97
+ elem.attributes['stroke-dashoffset'] = elem.attributes[
98
+ 'stroke-dashoffset'
99
+ ]
100
+ .trim()
101
+ .replace(regNumericValues, (num) => removeLeadingZero(num * scale));
102
+ }
103
+
104
+ if (elem.attributes['stroke-dasharray'] != null) {
105
+ elem.attributes['stroke-dasharray'] = elem.attributes[
106
+ 'stroke-dasharray'
107
+ ]
108
+ .trim()
109
+ .replace(regNumericValues, (num) => removeLeadingZero(num * scale));
110
+ }
111
+ }
112
+ }
113
+ } else if (id) {
114
+ // Stroke and stroke-width can be redefined with <use>
115
+ return;
116
+ }
117
+
118
+ applyMatrixToPathData(pathData, matrix.data);
119
+
120
+ // remove transform attr
121
+ delete elem.attributes.transform;
122
+
123
+ return;
124
+ };
125
+ exports.applyTransforms = applyTransforms;
126
+
127
+ const transformAbsolutePoint = (matrix, x, y) => {
128
+ const newX = matrix[0] * x + matrix[2] * y + matrix[4];
129
+ const newY = matrix[1] * x + matrix[3] * y + matrix[5];
130
+ return [newX, newY];
131
+ };
132
+
133
+ const transformRelativePoint = (matrix, x, y) => {
134
+ const newX = matrix[0] * x + matrix[2] * y;
135
+ const newY = matrix[1] * x + matrix[3] * y;
136
+ return [newX, newY];
137
+ };
138
+
139
+ const applyMatrixToPathData = (pathData, matrix) => {
140
+ const start = [0, 0];
141
+ const cursor = [0, 0];
142
+
143
+ for (const pathItem of pathData) {
144
+ let { command, args } = pathItem;
145
+
146
+ // moveto (x y)
147
+ if (command === 'M') {
148
+ cursor[0] = args[0];
149
+ cursor[1] = args[1];
150
+ start[0] = cursor[0];
151
+ start[1] = cursor[1];
152
+ const [x, y] = transformAbsolutePoint(matrix, args[0], args[1]);
153
+ args[0] = x;
154
+ args[1] = y;
155
+ }
156
+ if (command === 'm') {
157
+ cursor[0] += args[0];
158
+ cursor[1] += args[1];
159
+ start[0] = cursor[0];
160
+ start[1] = cursor[1];
161
+ const [x, y] = transformRelativePoint(matrix, args[0], args[1]);
162
+ args[0] = x;
163
+ args[1] = y;
164
+ }
165
+
166
+ // horizontal lineto (x)
167
+ // convert to lineto to handle two-dimentional transforms
168
+ if (command === 'H') {
169
+ command = 'L';
170
+ args = [args[0], cursor[1]];
171
+ }
172
+ if (command === 'h') {
173
+ command = 'l';
174
+ args = [args[0], 0];
175
+ }
176
+
177
+ // vertical lineto (y)
178
+ // convert to lineto to handle two-dimentional transforms
179
+ if (command === 'V') {
180
+ command = 'L';
181
+ args = [cursor[0], args[0]];
182
+ }
183
+ if (command === 'v') {
184
+ command = 'l';
185
+ args = [0, args[0]];
186
+ }
187
+
188
+ // lineto (x y)
189
+ if (command === 'L') {
190
+ cursor[0] = args[0];
191
+ cursor[1] = args[1];
192
+ const [x, y] = transformAbsolutePoint(matrix, args[0], args[1]);
193
+ args[0] = x;
194
+ args[1] = y;
195
+ }
196
+ if (command === 'l') {
197
+ cursor[0] += args[0];
198
+ cursor[1] += args[1];
199
+ const [x, y] = transformRelativePoint(matrix, args[0], args[1]);
200
+ args[0] = x;
201
+ args[1] = y;
202
+ }
203
+
204
+ // curveto (x1 y1 x2 y2 x y)
205
+ if (command === 'C') {
206
+ cursor[0] = args[4];
207
+ cursor[1] = args[5];
208
+ const [x1, y1] = transformAbsolutePoint(matrix, args[0], args[1]);
209
+ const [x2, y2] = transformAbsolutePoint(matrix, args[2], args[3]);
210
+ const [x, y] = transformAbsolutePoint(matrix, args[4], args[5]);
211
+ args[0] = x1;
212
+ args[1] = y1;
213
+ args[2] = x2;
214
+ args[3] = y2;
215
+ args[4] = x;
216
+ args[5] = y;
217
+ }
218
+ if (command === 'c') {
219
+ cursor[0] += args[4];
220
+ cursor[1] += args[5];
221
+ const [x1, y1] = transformRelativePoint(matrix, args[0], args[1]);
222
+ const [x2, y2] = transformRelativePoint(matrix, args[2], args[3]);
223
+ const [x, y] = transformRelativePoint(matrix, args[4], args[5]);
224
+ args[0] = x1;
225
+ args[1] = y1;
226
+ args[2] = x2;
227
+ args[3] = y2;
228
+ args[4] = x;
229
+ args[5] = y;
230
+ }
231
+
232
+ // smooth curveto (x2 y2 x y)
233
+ if (command === 'S') {
234
+ cursor[0] = args[2];
235
+ cursor[1] = args[3];
236
+ const [x2, y2] = transformAbsolutePoint(matrix, args[0], args[1]);
237
+ const [x, y] = transformAbsolutePoint(matrix, args[2], args[3]);
238
+ args[0] = x2;
239
+ args[1] = y2;
240
+ args[2] = x;
241
+ args[3] = y;
242
+ }
243
+ if (command === 's') {
244
+ cursor[0] += args[2];
245
+ cursor[1] += args[3];
246
+ const [x2, y2] = transformRelativePoint(matrix, args[0], args[1]);
247
+ const [x, y] = transformRelativePoint(matrix, args[2], args[3]);
248
+ args[0] = x2;
249
+ args[1] = y2;
250
+ args[2] = x;
251
+ args[3] = y;
252
+ }
253
+
254
+ // quadratic Bézier curveto (x1 y1 x y)
255
+ if (command === 'Q') {
256
+ cursor[0] = args[2];
257
+ cursor[1] = args[3];
258
+ const [x1, y1] = transformAbsolutePoint(matrix, args[0], args[1]);
259
+ const [x, y] = transformAbsolutePoint(matrix, args[2], args[3]);
260
+ args[0] = x1;
261
+ args[1] = y1;
262
+ args[2] = x;
263
+ args[3] = y;
264
+ }
265
+ if (command === 'q') {
266
+ cursor[0] += args[2];
267
+ cursor[1] += args[3];
268
+ const [x1, y1] = transformRelativePoint(matrix, args[0], args[1]);
269
+ const [x, y] = transformRelativePoint(matrix, args[2], args[3]);
270
+ args[0] = x1;
271
+ args[1] = y1;
272
+ args[2] = x;
273
+ args[3] = y;
274
+ }
275
+
276
+ // smooth quadratic Bézier curveto (x y)
277
+ if (command === 'T') {
278
+ cursor[0] = args[0];
279
+ cursor[1] = args[1];
280
+ const [x, y] = transformAbsolutePoint(matrix, args[0], args[1]);
281
+ args[0] = x;
282
+ args[1] = y;
283
+ }
284
+ if (command === 't') {
285
+ cursor[0] += args[0];
286
+ cursor[1] += args[1];
287
+ const [x, y] = transformRelativePoint(matrix, args[0], args[1]);
288
+ args[0] = x;
289
+ args[1] = y;
290
+ }
291
+
292
+ // elliptical arc (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
293
+ if (command === 'A') {
294
+ transformArc(cursor, args, matrix);
295
+ cursor[0] = args[5];
296
+ cursor[1] = args[6];
297
+ // reduce number of digits in rotation angle
298
+ if (Math.abs(args[2]) > 80) {
299
+ const a = args[0];
300
+ const rotation = args[2];
301
+ args[0] = args[1];
302
+ args[1] = a;
303
+ args[2] = rotation + (rotation > 0 ? -90 : 90);
304
+ }
305
+ const [x, y] = transformAbsolutePoint(matrix, args[5], args[6]);
306
+ args[5] = x;
307
+ args[6] = y;
308
+ }
309
+ if (command === 'a') {
310
+ transformArc([0, 0], args, matrix);
311
+ cursor[0] += args[5];
312
+ cursor[1] += args[6];
313
+ // reduce number of digits in rotation angle
314
+ if (Math.abs(args[2]) > 80) {
315
+ const a = args[0];
316
+ const rotation = args[2];
317
+ args[0] = args[1];
318
+ args[1] = a;
319
+ args[2] = rotation + (rotation > 0 ? -90 : 90);
320
+ }
321
+ const [x, y] = transformRelativePoint(matrix, args[5], args[6]);
322
+ args[5] = x;
323
+ args[6] = y;
324
+ }
325
+
326
+ // closepath
327
+ if (command === 'z' || command === 'Z') {
328
+ cursor[0] = start[0];
329
+ cursor[1] = start[1];
330
+ }
331
+
332
+ pathItem.command = command;
333
+ pathItem.args = args;
334
+ }
335
+ };