@iconify/tools 1.3.17 → 2.0.0-dev.2
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/.editorconfig +13 -0
- package/.eslintignore +2 -0
- package/lib/colors/attribs.d.ts +16 -0
- package/lib/colors/attribs.js +26 -0
- package/lib/colors/attribs.mjs +28 -0
- package/lib/colors/parse.d.ts +37 -0
- package/lib/colors/parse.js +261 -0
- package/lib/colors/parse.mjs +212 -0
- package/lib/css/parse.d.ts +4 -0
- package/lib/css/parse.js +23 -0
- package/lib/css/parse.mjs +20 -0
- package/lib/css/parser/error.d.ts +11 -0
- package/lib/css/parser/error.js +27 -0
- package/lib/css/parser/error.mjs +23 -0
- package/lib/css/parser/export.d.ts +5 -0
- package/lib/css/parser/export.js +69 -0
- package/lib/css/parser/export.mjs +46 -0
- package/lib/css/parser/strings.d.ts +13 -0
- package/lib/css/parser/strings.js +93 -0
- package/lib/css/parser/strings.mjs +74 -0
- package/lib/css/parser/text.d.ts +17 -0
- package/lib/css/parser/text.js +174 -0
- package/lib/css/parser/text.mjs +133 -0
- package/lib/css/parser/tokens.d.ts +6 -0
- package/lib/css/parser/tokens.js +200 -0
- package/lib/css/parser/tokens.mjs +186 -0
- package/lib/css/parser/tree.d.ts +5 -0
- package/lib/css/parser/tree.js +44 -0
- package/lib/css/parser/tree.mjs +40 -0
- package/lib/css/parser/types.d.ts +51 -0
- package/lib/css/parser/types.js +2 -0
- package/lib/css/parser/types.mjs +0 -0
- package/lib/icon-set/index.d.ts +134 -0
- package/lib/icon-set/index.js +776 -0
- package/lib/icon-set/index.mjs +617 -0
- package/lib/icon-set/match.d.ts +6 -0
- package/lib/icon-set/match.js +66 -0
- package/lib/icon-set/match.mjs +55 -0
- package/lib/icon-set/merge.d.ts +5 -0
- package/lib/icon-set/merge.js +91 -0
- package/lib/icon-set/merge.mjs +75 -0
- package/lib/icon-set/props.d.ts +10 -0
- package/lib/icon-set/props.js +33 -0
- package/lib/icon-set/props.mjs +25 -0
- package/lib/icon-set/types.d.ts +68 -0
- package/lib/icon-set/types.js +2 -0
- package/lib/icon-set/types.mjs +0 -0
- package/lib/import/directory.d.ts +35 -0
- package/lib/import/directory.js +59 -0
- package/lib/import/directory.mjs +47 -0
- package/lib/misc/keyword.d.ts +4 -0
- package/lib/misc/keyword.js +31 -0
- package/lib/misc/keyword.mjs +17 -0
- package/lib/misc/scan.d.ts +24 -0
- package/lib/misc/scan.js +48 -0
- package/lib/misc/scan.mjs +43 -0
- package/lib/optimise/flags.d.ts +5 -0
- package/lib/optimise/flags.js +303 -0
- package/lib/optimise/flags.mjs +241 -0
- package/lib/optimise/scale.d.ts +5 -0
- package/lib/optimise/scale.js +42 -0
- package/lib/optimise/scale.mjs +22 -0
- package/lib/optimise/svgo.d.ts +27 -0
- package/lib/optimise/svgo.js +88 -0
- package/lib/optimise/svgo.mjs +75 -0
- package/lib/svg/cleanup/attribs.d.ts +5 -0
- package/lib/svg/cleanup/attribs.js +43 -0
- package/lib/svg/cleanup/attribs.mjs +36 -0
- package/lib/svg/cleanup/bad-tags.d.ts +5 -0
- package/lib/svg/cleanup/bad-tags.js +69 -0
- package/lib/svg/cleanup/bad-tags.mjs +68 -0
- package/lib/svg/cleanup/inline-style.d.ts +5 -0
- package/lib/svg/cleanup/inline-style.js +77 -0
- package/lib/svg/cleanup/inline-style.mjs +65 -0
- package/lib/svg/cleanup/root-svg.d.ts +5 -0
- package/lib/svg/cleanup/root-svg.js +106 -0
- package/lib/svg/cleanup/root-svg.mjs +88 -0
- package/lib/svg/cleanup/svgo-style.d.ts +5 -0
- package/lib/svg/cleanup/svgo-style.js +35 -0
- package/lib/svg/cleanup/svgo-style.mjs +29 -0
- package/lib/svg/cleanup.d.ts +5 -0
- package/lib/svg/cleanup.js +24 -0
- package/lib/svg/cleanup.mjs +16 -0
- package/lib/svg/data/attributes.d.ts +71 -0
- package/lib/svg/data/attributes.js +403 -0
- package/lib/svg/data/attributes.mjs +352 -0
- package/lib/svg/data/tags.d.ts +89 -0
- package/lib/svg/data/tags.js +185 -0
- package/lib/svg/data/tags.mjs +136 -0
- package/lib/svg/index.d.ts +33 -0
- package/lib/svg/index.js +122 -0
- package/lib/svg/index.mjs +85 -0
- package/lib/svg/parse-style.d.ts +40 -0
- package/lib/svg/parse-style.js +131 -0
- package/lib/svg/parse-style.mjs +109 -0
- package/lib/svg/parse.d.ts +30 -0
- package/lib/svg/parse.js +49 -0
- package/lib/svg/parse.mjs +40 -0
- package/package.json +167 -13
- package/README.md +0 -576
- package/license.txt +0 -21
- package/sample/parse.js +0 -74
- package/sample/source/icon-close.svg +0 -15
- package/sample/source/icon-confirm.svg +0 -14
- package/sample/source/icon-search.svg +0 -16
- package/src/collection.js +0 -641
- package/src/colors/change_palette.js +0 -227
- package/src/colors/get_palette.js +0 -143
- package/src/colors/opacify.js +0 -195
- package/src/export/component.js +0 -482
- package/src/export/dir.js +0 -109
- package/src/export/json.js +0 -329
- package/src/export/phantomjs.js +0 -76
- package/src/export/phantomjs_script.js +0 -125
- package/src/export/png.js +0 -193
- package/src/export/svg.js +0 -55
- package/src/export/templates/component.md +0 -79
- package/src/export/templates/info.md +0 -3
- package/src/export/templates/sample-react-1.md +0 -21
- package/src/export/templates/sample-react-2.md +0 -15
- package/src/export/templates/sample-react.md +0 -11
- package/src/export/templates/sample-svelte.md +0 -11
- package/src/export/templates/sample-svelte1.md +0 -22
- package/src/export/templates/sample-svelte2.md +0 -13
- package/src/export/templates/sample-vue-0.md +0 -30
- package/src/export/templates/sample-vue-1.md +0 -25
- package/src/export/templates/sample-vue-2.md +0 -27
- package/src/export/templates/sample-vue.md +0 -28
- package/src/helpers.js +0 -43
- package/src/import/dir.js +0 -234
- package/src/import/font.js +0 -402
- package/src/import/json.js +0 -200
- package/src/import/svg.js +0 -60
- package/src/import/web_icons.js +0 -248
- package/src/modules.js +0 -50
- package/src/optimize/crop.js +0 -554
- package/src/optimize/crop_script.js +0 -525
- package/src/optimize/flags.js +0 -430
- package/src/optimize/scale.js +0 -72
- package/src/optimize/svgo.js +0 -161
- package/src/optimize/tags.js +0 -522
- package/src/shapes/convert.js +0 -264
- package/src/shapes/index.js +0 -135
- package/src/shapes/length.js +0 -707
- package/src/shapes/length_script.js +0 -105
- package/src/shapes/options.js +0 -60
- package/src/svg.js +0 -162
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// src/misc/scan.ts
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
async function scanDirectory(path, callback, subdirs = true) {
|
|
4
|
+
const results = [];
|
|
5
|
+
if (path.length && path.slice(-1) !== "/") {
|
|
6
|
+
path += "/";
|
|
7
|
+
}
|
|
8
|
+
async function scan(subdir) {
|
|
9
|
+
const files = await fs.readdir(path + subdir);
|
|
10
|
+
for (let i = 0; i < files.length; i++) {
|
|
11
|
+
const filename = files[i];
|
|
12
|
+
if (filename.slice(0, 1) === ".") {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
const stat = await fs.lstat(path + subdir + filename);
|
|
16
|
+
if (stat.isDirectory()) {
|
|
17
|
+
if (subdirs) {
|
|
18
|
+
await scan(subdir + filename + "/");
|
|
19
|
+
}
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (!stat.isFile()) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const parts = filename.split(".");
|
|
26
|
+
const ext = parts.length > 1 ? "." + parts.pop() : "";
|
|
27
|
+
const file = parts.join(".");
|
|
28
|
+
let callbackResult = callback(ext, file, subdir, path);
|
|
29
|
+
if (callbackResult instanceof Promise) {
|
|
30
|
+
callbackResult = await callbackResult;
|
|
31
|
+
}
|
|
32
|
+
if (callbackResult === void 0 || callbackResult === false || callbackResult === null) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
results.push(callbackResult === true ? subdir + filename : callbackResult);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
await scan("");
|
|
39
|
+
return results;
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
scanDirectory
|
|
43
|
+
};
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deOptimisePaths = void 0;
|
|
4
|
+
const parse_1 = require("../svg/parse");
|
|
5
|
+
/**
|
|
6
|
+
* Command constants
|
|
7
|
+
*/
|
|
8
|
+
const CLOSE_PATH = 1;
|
|
9
|
+
const MOVE_TO = 2;
|
|
10
|
+
const HORIZ_LINE_TO = 4;
|
|
11
|
+
const VERT_LINE_TO = 8;
|
|
12
|
+
const LINE_TO = 16;
|
|
13
|
+
const CURVE_TO = 32;
|
|
14
|
+
const SMOOTH_CURVE_TO = 64;
|
|
15
|
+
const QUAD_TO = 128;
|
|
16
|
+
const SMOOTH_QUAD_TO = 256;
|
|
17
|
+
const ARC = 512;
|
|
18
|
+
/**
|
|
19
|
+
* Number of arguments for each command
|
|
20
|
+
*/
|
|
21
|
+
const argCount = {
|
|
22
|
+
[MOVE_TO]: 2,
|
|
23
|
+
[LINE_TO]: 2,
|
|
24
|
+
[HORIZ_LINE_TO]: 1,
|
|
25
|
+
[VERT_LINE_TO]: 1,
|
|
26
|
+
[CLOSE_PATH]: 0,
|
|
27
|
+
[QUAD_TO]: 4,
|
|
28
|
+
[SMOOTH_QUAD_TO]: 2,
|
|
29
|
+
[CURVE_TO]: 6,
|
|
30
|
+
[SMOOTH_CURVE_TO]: 4,
|
|
31
|
+
[ARC]: 7,
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Check if character is a digit
|
|
35
|
+
*/
|
|
36
|
+
const isDigit = (num) => num >= 48 && num <= 57;
|
|
37
|
+
/**
|
|
38
|
+
* Check if character is white space
|
|
39
|
+
*/
|
|
40
|
+
const isWhiteSpace = (num) => num === 32 || num === 9 || num === 13 || num === 10;
|
|
41
|
+
/**
|
|
42
|
+
* Clean up path
|
|
43
|
+
*
|
|
44
|
+
* @param {string} path
|
|
45
|
+
* @return {string}
|
|
46
|
+
*/
|
|
47
|
+
function cleanPath(path) {
|
|
48
|
+
const commands = [];
|
|
49
|
+
const length = path.length;
|
|
50
|
+
let currentNumber = '';
|
|
51
|
+
let currentNumberHasExp = false;
|
|
52
|
+
let currentNumberHasExpDigits = false;
|
|
53
|
+
let currentNumberHasDecimal = false;
|
|
54
|
+
let canParseCommandOrComma = true;
|
|
55
|
+
let currentCommand = null;
|
|
56
|
+
let currentCommandType = null;
|
|
57
|
+
let currentArgs = [];
|
|
58
|
+
let i = 0;
|
|
59
|
+
const finishCommand = () => {
|
|
60
|
+
if (currentCommand !== null) {
|
|
61
|
+
commands.push({
|
|
62
|
+
command: currentCommand,
|
|
63
|
+
params: currentArgs.slice(0),
|
|
64
|
+
});
|
|
65
|
+
currentArgs = [];
|
|
66
|
+
canParseCommandOrComma = true;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const parseNumber = () => {
|
|
70
|
+
// Number ended - validate it
|
|
71
|
+
if (currentNumber !== '' && currentCommandType) {
|
|
72
|
+
let value = Number(currentNumber);
|
|
73
|
+
if (isNaN(value)) {
|
|
74
|
+
throw new Error('Invalid number "' + currentNumber + '" at ' + i);
|
|
75
|
+
}
|
|
76
|
+
// Validate arc arguments
|
|
77
|
+
if (currentCommandType === ARC) {
|
|
78
|
+
if (currentArgs.length < 2 && value <= 0) {
|
|
79
|
+
throw new Error('Expected positive number, got "' + value + '" at ' + i);
|
|
80
|
+
}
|
|
81
|
+
// eslint-disable-next-line no-constant-condition
|
|
82
|
+
while (true) {
|
|
83
|
+
// Not flag
|
|
84
|
+
if (currentArgs.length < 3 || currentArgs.length > 4) {
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
// Valid flag
|
|
88
|
+
if (currentNumber === '0' || currentNumber === '1') {
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
// Unpack flag
|
|
92
|
+
const slice = currentNumber.slice(0, 1);
|
|
93
|
+
const newNumber = currentNumber.slice(1);
|
|
94
|
+
const newValue = Number(newNumber);
|
|
95
|
+
if (slice === '0' || slice === '1') {
|
|
96
|
+
// Valid flag
|
|
97
|
+
if (isNaN(newValue)) {
|
|
98
|
+
throw new Error('Invalid number "' + currentNumber + '" at ' + i);
|
|
99
|
+
}
|
|
100
|
+
currentArgs.push(slice);
|
|
101
|
+
currentNumber = newNumber;
|
|
102
|
+
value = newValue;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
throw new Error('Expected a flag, got "' + currentNumber + '" at ' + i);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Add current number to arguments list
|
|
109
|
+
currentArgs.push(currentNumber);
|
|
110
|
+
if (currentArgs.length === argCount[currentCommandType]) {
|
|
111
|
+
finishCommand();
|
|
112
|
+
}
|
|
113
|
+
currentNumber = '';
|
|
114
|
+
currentNumberHasExpDigits = false;
|
|
115
|
+
currentNumberHasExp = false;
|
|
116
|
+
currentNumberHasDecimal = false;
|
|
117
|
+
canParseCommandOrComma = true;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
for (i = 0; i < length; i++) {
|
|
121
|
+
const char = path[i];
|
|
122
|
+
const num = char.charCodeAt(0);
|
|
123
|
+
// Test for number
|
|
124
|
+
if (isDigit(num)) {
|
|
125
|
+
currentNumber += char;
|
|
126
|
+
currentNumberHasExpDigits = currentNumberHasExp;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
// Test for exponential number
|
|
130
|
+
if (char === 'e' || char === 'E') {
|
|
131
|
+
currentNumber += char;
|
|
132
|
+
currentNumberHasExp = true;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
// Test for number signs
|
|
136
|
+
if ((char === '-' || char === '+') &&
|
|
137
|
+
currentNumberHasExp &&
|
|
138
|
+
!currentNumberHasExpDigits) {
|
|
139
|
+
currentNumber += char;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
// Decimal point
|
|
143
|
+
if (char === '.' && !currentNumberHasExp && !currentNumberHasDecimal) {
|
|
144
|
+
currentNumber += char;
|
|
145
|
+
currentNumberHasDecimal = true;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
// Number ended - validate it
|
|
149
|
+
parseNumber();
|
|
150
|
+
// White space
|
|
151
|
+
if (isWhiteSpace(num)) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
// Only one comma per command
|
|
155
|
+
if (canParseCommandOrComma && char === ',') {
|
|
156
|
+
canParseCommandOrComma = false;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
// New number
|
|
160
|
+
if (char === '+' || char === '-' || char === '.') {
|
|
161
|
+
currentNumber = char;
|
|
162
|
+
currentNumberHasDecimal = char === '.';
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
// Expecting new command, so argument should be empty
|
|
166
|
+
if (currentArgs.length > 0) {
|
|
167
|
+
throw new Error('Unexpected command at ' + i);
|
|
168
|
+
}
|
|
169
|
+
// Test comma, reset value
|
|
170
|
+
if (!canParseCommandOrComma) {
|
|
171
|
+
throw new Error('Command cannot follow comma at ' + i + '');
|
|
172
|
+
}
|
|
173
|
+
canParseCommandOrComma = false;
|
|
174
|
+
// Detect next command
|
|
175
|
+
currentCommand = char;
|
|
176
|
+
switch (char) {
|
|
177
|
+
case 'z':
|
|
178
|
+
case 'Z':
|
|
179
|
+
// Close path
|
|
180
|
+
commands.push({
|
|
181
|
+
command: char,
|
|
182
|
+
params: [],
|
|
183
|
+
});
|
|
184
|
+
canParseCommandOrComma = true;
|
|
185
|
+
currentCommandType = null;
|
|
186
|
+
currentCommand = null;
|
|
187
|
+
break;
|
|
188
|
+
case 'h':
|
|
189
|
+
case 'H':
|
|
190
|
+
// Horizontal move
|
|
191
|
+
currentCommandType = HORIZ_LINE_TO;
|
|
192
|
+
break;
|
|
193
|
+
case 'v':
|
|
194
|
+
case 'V':
|
|
195
|
+
// Vertical move
|
|
196
|
+
currentCommandType = VERT_LINE_TO;
|
|
197
|
+
break;
|
|
198
|
+
case 'm':
|
|
199
|
+
case 'M':
|
|
200
|
+
// Move to
|
|
201
|
+
currentCommandType = MOVE_TO;
|
|
202
|
+
break;
|
|
203
|
+
case 'l':
|
|
204
|
+
case 'L':
|
|
205
|
+
// Line to
|
|
206
|
+
currentCommandType = LINE_TO;
|
|
207
|
+
break;
|
|
208
|
+
case 'c':
|
|
209
|
+
case 'C':
|
|
210
|
+
// Curve
|
|
211
|
+
currentCommandType = CURVE_TO;
|
|
212
|
+
break;
|
|
213
|
+
case 's':
|
|
214
|
+
case 'S':
|
|
215
|
+
// Smooth curve
|
|
216
|
+
currentCommandType = SMOOTH_CURVE_TO;
|
|
217
|
+
break;
|
|
218
|
+
case 'q':
|
|
219
|
+
case 'Q':
|
|
220
|
+
// Quadratic bezier curve
|
|
221
|
+
currentCommandType = QUAD_TO;
|
|
222
|
+
break;
|
|
223
|
+
case 't':
|
|
224
|
+
case 'T':
|
|
225
|
+
// Smooth quadratic bezier curve
|
|
226
|
+
currentCommandType = SMOOTH_QUAD_TO;
|
|
227
|
+
break;
|
|
228
|
+
case 'a':
|
|
229
|
+
case 'A':
|
|
230
|
+
// Elliptic arc
|
|
231
|
+
currentCommandType = ARC;
|
|
232
|
+
break;
|
|
233
|
+
default:
|
|
234
|
+
throw new Error('Unexpected character "' + char + '" at ' + i);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Parse last number
|
|
238
|
+
parseNumber();
|
|
239
|
+
// Add last command
|
|
240
|
+
if (currentArgs.length) {
|
|
241
|
+
if (!currentCommandType) {
|
|
242
|
+
throw new Error('Empty path');
|
|
243
|
+
}
|
|
244
|
+
if (currentArgs.length !== argCount[currentCommandType]) {
|
|
245
|
+
throw new Error('Unexpected end of path at ' + i);
|
|
246
|
+
}
|
|
247
|
+
finishCommand();
|
|
248
|
+
}
|
|
249
|
+
// Build path
|
|
250
|
+
let output = '';
|
|
251
|
+
commands.forEach((item) => {
|
|
252
|
+
output += item.command;
|
|
253
|
+
item.params.forEach((value, index) => {
|
|
254
|
+
if (index > 0) {
|
|
255
|
+
const char = value[0];
|
|
256
|
+
// noinspection FallThroughInSwitchStatementJS
|
|
257
|
+
switch (char) {
|
|
258
|
+
case '-':
|
|
259
|
+
case '+':
|
|
260
|
+
// Number - no space
|
|
261
|
+
break;
|
|
262
|
+
case '.':
|
|
263
|
+
// Dot - no space if previous entry was command
|
|
264
|
+
if (index < 1) {
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
// No space if previous entry had dot
|
|
268
|
+
if (item.params[index - 1].indexOf('.') !== -1) {
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
// no-fallthrough
|
|
272
|
+
default:
|
|
273
|
+
output += ' ';
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
output += value;
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
return output;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* De-optimise paths. Compressed paths are still not supported by some software.
|
|
283
|
+
*/
|
|
284
|
+
async function deOptimisePaths(svg) {
|
|
285
|
+
await (0, parse_1.parseSVG)(svg, (item) => {
|
|
286
|
+
if (item.tagName !== 'path') {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const d = item.element.attribs.d;
|
|
290
|
+
if (typeof d === 'string') {
|
|
291
|
+
try {
|
|
292
|
+
const optimised = cleanPath(d);
|
|
293
|
+
if (optimised !== d) {
|
|
294
|
+
item.$element.attr('d', optimised);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
//
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
exports.deOptimisePaths = deOptimisePaths;
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// src/optimise/flags.ts
|
|
2
|
+
import { parseSVG } from "../svg/parse.mjs";
|
|
3
|
+
var CLOSE_PATH = 1;
|
|
4
|
+
var MOVE_TO = 2;
|
|
5
|
+
var HORIZ_LINE_TO = 4;
|
|
6
|
+
var VERT_LINE_TO = 8;
|
|
7
|
+
var LINE_TO = 16;
|
|
8
|
+
var CURVE_TO = 32;
|
|
9
|
+
var SMOOTH_CURVE_TO = 64;
|
|
10
|
+
var QUAD_TO = 128;
|
|
11
|
+
var SMOOTH_QUAD_TO = 256;
|
|
12
|
+
var ARC = 512;
|
|
13
|
+
var argCount = {
|
|
14
|
+
[MOVE_TO]: 2,
|
|
15
|
+
[LINE_TO]: 2,
|
|
16
|
+
[HORIZ_LINE_TO]: 1,
|
|
17
|
+
[VERT_LINE_TO]: 1,
|
|
18
|
+
[CLOSE_PATH]: 0,
|
|
19
|
+
[QUAD_TO]: 4,
|
|
20
|
+
[SMOOTH_QUAD_TO]: 2,
|
|
21
|
+
[CURVE_TO]: 6,
|
|
22
|
+
[SMOOTH_CURVE_TO]: 4,
|
|
23
|
+
[ARC]: 7
|
|
24
|
+
};
|
|
25
|
+
var isDigit = (num) => num >= 48 && num <= 57;
|
|
26
|
+
var isWhiteSpace = (num) => num === 32 || num === 9 || num === 13 || num === 10;
|
|
27
|
+
function cleanPath(path) {
|
|
28
|
+
const commands = [];
|
|
29
|
+
const length = path.length;
|
|
30
|
+
let currentNumber = "";
|
|
31
|
+
let currentNumberHasExp = false;
|
|
32
|
+
let currentNumberHasExpDigits = false;
|
|
33
|
+
let currentNumberHasDecimal = false;
|
|
34
|
+
let canParseCommandOrComma = true;
|
|
35
|
+
let currentCommand = null;
|
|
36
|
+
let currentCommandType = null;
|
|
37
|
+
let currentArgs = [];
|
|
38
|
+
let i = 0;
|
|
39
|
+
const finishCommand = () => {
|
|
40
|
+
if (currentCommand !== null) {
|
|
41
|
+
commands.push({
|
|
42
|
+
command: currentCommand,
|
|
43
|
+
params: currentArgs.slice(0)
|
|
44
|
+
});
|
|
45
|
+
currentArgs = [];
|
|
46
|
+
canParseCommandOrComma = true;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const parseNumber = () => {
|
|
50
|
+
if (currentNumber !== "" && currentCommandType) {
|
|
51
|
+
let value = Number(currentNumber);
|
|
52
|
+
if (isNaN(value)) {
|
|
53
|
+
throw new Error('Invalid number "' + currentNumber + '" at ' + i);
|
|
54
|
+
}
|
|
55
|
+
if (currentCommandType === ARC) {
|
|
56
|
+
if (currentArgs.length < 2 && value <= 0) {
|
|
57
|
+
throw new Error('Expected positive number, got "' + value + '" at ' + i);
|
|
58
|
+
}
|
|
59
|
+
while (true) {
|
|
60
|
+
if (currentArgs.length < 3 || currentArgs.length > 4) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
if (currentNumber === "0" || currentNumber === "1") {
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
const slice = currentNumber.slice(0, 1);
|
|
67
|
+
const newNumber = currentNumber.slice(1);
|
|
68
|
+
const newValue = Number(newNumber);
|
|
69
|
+
if (slice === "0" || slice === "1") {
|
|
70
|
+
if (isNaN(newValue)) {
|
|
71
|
+
throw new Error('Invalid number "' + currentNumber + '" at ' + i);
|
|
72
|
+
}
|
|
73
|
+
currentArgs.push(slice);
|
|
74
|
+
currentNumber = newNumber;
|
|
75
|
+
value = newValue;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
throw new Error('Expected a flag, got "' + currentNumber + '" at ' + i);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
currentArgs.push(currentNumber);
|
|
82
|
+
if (currentArgs.length === argCount[currentCommandType]) {
|
|
83
|
+
finishCommand();
|
|
84
|
+
}
|
|
85
|
+
currentNumber = "";
|
|
86
|
+
currentNumberHasExpDigits = false;
|
|
87
|
+
currentNumberHasExp = false;
|
|
88
|
+
currentNumberHasDecimal = false;
|
|
89
|
+
canParseCommandOrComma = true;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
for (i = 0; i < length; i++) {
|
|
93
|
+
const char = path[i];
|
|
94
|
+
const num = char.charCodeAt(0);
|
|
95
|
+
if (isDigit(num)) {
|
|
96
|
+
currentNumber += char;
|
|
97
|
+
currentNumberHasExpDigits = currentNumberHasExp;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (char === "e" || char === "E") {
|
|
101
|
+
currentNumber += char;
|
|
102
|
+
currentNumberHasExp = true;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if ((char === "-" || char === "+") && currentNumberHasExp && !currentNumberHasExpDigits) {
|
|
106
|
+
currentNumber += char;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (char === "." && !currentNumberHasExp && !currentNumberHasDecimal) {
|
|
110
|
+
currentNumber += char;
|
|
111
|
+
currentNumberHasDecimal = true;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
parseNumber();
|
|
115
|
+
if (isWhiteSpace(num)) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (canParseCommandOrComma && char === ",") {
|
|
119
|
+
canParseCommandOrComma = false;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (char === "+" || char === "-" || char === ".") {
|
|
123
|
+
currentNumber = char;
|
|
124
|
+
currentNumberHasDecimal = char === ".";
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (currentArgs.length > 0) {
|
|
128
|
+
throw new Error("Unexpected command at " + i);
|
|
129
|
+
}
|
|
130
|
+
if (!canParseCommandOrComma) {
|
|
131
|
+
throw new Error("Command cannot follow comma at " + i + "");
|
|
132
|
+
}
|
|
133
|
+
canParseCommandOrComma = false;
|
|
134
|
+
currentCommand = char;
|
|
135
|
+
switch (char) {
|
|
136
|
+
case "z":
|
|
137
|
+
case "Z":
|
|
138
|
+
commands.push({
|
|
139
|
+
command: char,
|
|
140
|
+
params: []
|
|
141
|
+
});
|
|
142
|
+
canParseCommandOrComma = true;
|
|
143
|
+
currentCommandType = null;
|
|
144
|
+
currentCommand = null;
|
|
145
|
+
break;
|
|
146
|
+
case "h":
|
|
147
|
+
case "H":
|
|
148
|
+
currentCommandType = HORIZ_LINE_TO;
|
|
149
|
+
break;
|
|
150
|
+
case "v":
|
|
151
|
+
case "V":
|
|
152
|
+
currentCommandType = VERT_LINE_TO;
|
|
153
|
+
break;
|
|
154
|
+
case "m":
|
|
155
|
+
case "M":
|
|
156
|
+
currentCommandType = MOVE_TO;
|
|
157
|
+
break;
|
|
158
|
+
case "l":
|
|
159
|
+
case "L":
|
|
160
|
+
currentCommandType = LINE_TO;
|
|
161
|
+
break;
|
|
162
|
+
case "c":
|
|
163
|
+
case "C":
|
|
164
|
+
currentCommandType = CURVE_TO;
|
|
165
|
+
break;
|
|
166
|
+
case "s":
|
|
167
|
+
case "S":
|
|
168
|
+
currentCommandType = SMOOTH_CURVE_TO;
|
|
169
|
+
break;
|
|
170
|
+
case "q":
|
|
171
|
+
case "Q":
|
|
172
|
+
currentCommandType = QUAD_TO;
|
|
173
|
+
break;
|
|
174
|
+
case "t":
|
|
175
|
+
case "T":
|
|
176
|
+
currentCommandType = SMOOTH_QUAD_TO;
|
|
177
|
+
break;
|
|
178
|
+
case "a":
|
|
179
|
+
case "A":
|
|
180
|
+
currentCommandType = ARC;
|
|
181
|
+
break;
|
|
182
|
+
default:
|
|
183
|
+
throw new Error('Unexpected character "' + char + '" at ' + i);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
parseNumber();
|
|
187
|
+
if (currentArgs.length) {
|
|
188
|
+
if (!currentCommandType) {
|
|
189
|
+
throw new Error("Empty path");
|
|
190
|
+
}
|
|
191
|
+
if (currentArgs.length !== argCount[currentCommandType]) {
|
|
192
|
+
throw new Error("Unexpected end of path at " + i);
|
|
193
|
+
}
|
|
194
|
+
finishCommand();
|
|
195
|
+
}
|
|
196
|
+
let output = "";
|
|
197
|
+
commands.forEach((item) => {
|
|
198
|
+
output += item.command;
|
|
199
|
+
item.params.forEach((value, index) => {
|
|
200
|
+
if (index > 0) {
|
|
201
|
+
const char = value[0];
|
|
202
|
+
switch (char) {
|
|
203
|
+
case "-":
|
|
204
|
+
case "+":
|
|
205
|
+
break;
|
|
206
|
+
case ".":
|
|
207
|
+
if (index < 1) {
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
if (item.params[index - 1].indexOf(".") !== -1) {
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
default:
|
|
214
|
+
output += " ";
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
output += value;
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
return output;
|
|
221
|
+
}
|
|
222
|
+
async function deOptimisePaths(svg) {
|
|
223
|
+
await parseSVG(svg, (item) => {
|
|
224
|
+
if (item.tagName !== "path") {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const d = item.element.attribs.d;
|
|
228
|
+
if (typeof d === "string") {
|
|
229
|
+
try {
|
|
230
|
+
const optimised = cleanPath(d);
|
|
231
|
+
if (optimised !== d) {
|
|
232
|
+
item.$element.attr("d", optimised);
|
|
233
|
+
}
|
|
234
|
+
} catch (err) {
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
export {
|
|
240
|
+
deOptimisePaths
|
|
241
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.scaleSVG = void 0;
|
|
4
|
+
const svgo_1 = require("./svgo");
|
|
5
|
+
/**
|
|
6
|
+
* Scale icon
|
|
7
|
+
*/
|
|
8
|
+
async function scaleSVG(svg, scale) {
|
|
9
|
+
const viewBox = svg.viewBox;
|
|
10
|
+
const width = viewBox.width * scale;
|
|
11
|
+
const height = viewBox.height * scale;
|
|
12
|
+
const left = viewBox.left * scale;
|
|
13
|
+
const top = viewBox.top * scale;
|
|
14
|
+
const content = '<svg width="' +
|
|
15
|
+
width +
|
|
16
|
+
'" height="' +
|
|
17
|
+
height +
|
|
18
|
+
'" viewBox="' +
|
|
19
|
+
left +
|
|
20
|
+
' ' +
|
|
21
|
+
top +
|
|
22
|
+
' ' +
|
|
23
|
+
width +
|
|
24
|
+
' ' +
|
|
25
|
+
height +
|
|
26
|
+
'">' +
|
|
27
|
+
'<g transform="scale(' +
|
|
28
|
+
scale +
|
|
29
|
+
')">' +
|
|
30
|
+
svg.getBody() +
|
|
31
|
+
'</g></svg>';
|
|
32
|
+
svg.load(content);
|
|
33
|
+
await (0, svgo_1.runSVGO)(svg, {
|
|
34
|
+
plugins: [
|
|
35
|
+
'collapseGroups',
|
|
36
|
+
'convertTransform',
|
|
37
|
+
'convertPathData',
|
|
38
|
+
'sortAttrs',
|
|
39
|
+
],
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
exports.scaleSVG = scaleSVG;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// src/optimise/scale.ts
|
|
2
|
+
import { runSVGO } from "./svgo.mjs";
|
|
3
|
+
async function scaleSVG(svg, scale) {
|
|
4
|
+
const viewBox = svg.viewBox;
|
|
5
|
+
const width = viewBox.width * scale;
|
|
6
|
+
const height = viewBox.height * scale;
|
|
7
|
+
const left = viewBox.left * scale;
|
|
8
|
+
const top = viewBox.top * scale;
|
|
9
|
+
const content = '<svg width="' + width + '" height="' + height + '" viewBox="' + left + " " + top + " " + width + " " + height + '"><g transform="scale(' + scale + ')">' + svg.getBody() + "</g></svg>";
|
|
10
|
+
svg.load(content);
|
|
11
|
+
await runSVGO(svg, {
|
|
12
|
+
plugins: [
|
|
13
|
+
"collapseGroups",
|
|
14
|
+
"convertTransform",
|
|
15
|
+
"convertPathData",
|
|
16
|
+
"sortAttrs"
|
|
17
|
+
]
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
scaleSVG
|
|
22
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Plugin } from 'svgo';
|
|
2
|
+
import type { SVG } from '../svg';
|
|
3
|
+
export declare const defaultSVGOPlugins: Plugin[];
|
|
4
|
+
/**
|
|
5
|
+
* Plugins that modify shapes. Added to plugins list, unless 'keepShapes' option is enabled
|
|
6
|
+
*/
|
|
7
|
+
export declare const shapeModifiyingSVGOPlugins: Plugin[];
|
|
8
|
+
/**
|
|
9
|
+
* Options
|
|
10
|
+
*/
|
|
11
|
+
interface SVGOCommonOptions {
|
|
12
|
+
multipass?: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface SVGOOptionsWithPlugin extends SVGOCommonOptions {
|
|
15
|
+
plugins: Plugin[];
|
|
16
|
+
}
|
|
17
|
+
interface SVGOptionsWithoutPlugin extends SVGOCommonOptions {
|
|
18
|
+
plugins?: undefined;
|
|
19
|
+
keepShapes?: boolean;
|
|
20
|
+
cleanupIDs?: string | false;
|
|
21
|
+
}
|
|
22
|
+
declare type SVGOOptions = SVGOOptionsWithPlugin | SVGOptionsWithoutPlugin;
|
|
23
|
+
/**
|
|
24
|
+
* Run SVGO on icon
|
|
25
|
+
*/
|
|
26
|
+
export declare function runSVGO(svg: SVG, options?: SVGOOptions): Promise<void>;
|
|
27
|
+
export {};
|