@iconify/tools 4.0.0 → 4.0.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/lib/index.cjs +1 -0
- package/lib/index.mjs +1 -0
- package/lib/misc/scan.d.cts +2 -2
- package/lib/misc/scan.d.mts +2 -2
- package/lib/misc/scan.d.ts +2 -2
- package/lib/optimise/figma.cjs +106 -49
- package/lib/optimise/figma.d.cts +4 -1
- package/lib/optimise/figma.d.mts +4 -1
- package/lib/optimise/figma.d.ts +4 -1
- package/lib/optimise/figma.mjs +107 -50
- package/lib/optimise/unwrap.cjs +31 -0
- package/lib/optimise/unwrap.d.cts +11 -0
- package/lib/optimise/unwrap.d.mts +11 -0
- package/lib/optimise/unwrap.d.ts +11 -0
- package/lib/optimise/unwrap.mjs +29 -0
- package/package.json +18 -13
package/lib/index.cjs
CHANGED
package/lib/index.mjs
CHANGED
package/lib/misc/scan.d.cts
CHANGED
|
@@ -17,8 +17,8 @@ type ScanDirectoryCallbackFalseResult = boolean | null | undefined;
|
|
|
17
17
|
type ScanDirectoryCallbackStringResult = ScanDirectoryCallbackFalseResult | string;
|
|
18
18
|
type Callback<T> = (ext: string, file: string, subdir: string, path: string, stat: Stats) => T;
|
|
19
19
|
type AsyncCallback<T> = Callback<T | Promise<T>>;
|
|
20
|
-
type ScanDirectoryCallback = AsyncCallback<ScanDirectoryCallbackStringResult |
|
|
21
|
-
type ScanDirectorySyncCallback = Callback<ScanDirectoryCallbackStringResult |
|
|
20
|
+
type ScanDirectoryCallback = AsyncCallback<ScanDirectoryCallbackStringResult | undefined>;
|
|
21
|
+
type ScanDirectorySyncCallback = Callback<ScanDirectoryCallbackStringResult | undefined>;
|
|
22
22
|
/**
|
|
23
23
|
* Find all files in directory
|
|
24
24
|
*/
|
package/lib/misc/scan.d.mts
CHANGED
|
@@ -17,8 +17,8 @@ type ScanDirectoryCallbackFalseResult = boolean | null | undefined;
|
|
|
17
17
|
type ScanDirectoryCallbackStringResult = ScanDirectoryCallbackFalseResult | string;
|
|
18
18
|
type Callback<T> = (ext: string, file: string, subdir: string, path: string, stat: Stats) => T;
|
|
19
19
|
type AsyncCallback<T> = Callback<T | Promise<T>>;
|
|
20
|
-
type ScanDirectoryCallback = AsyncCallback<ScanDirectoryCallbackStringResult |
|
|
21
|
-
type ScanDirectorySyncCallback = Callback<ScanDirectoryCallbackStringResult |
|
|
20
|
+
type ScanDirectoryCallback = AsyncCallback<ScanDirectoryCallbackStringResult | undefined>;
|
|
21
|
+
type ScanDirectorySyncCallback = Callback<ScanDirectoryCallbackStringResult | undefined>;
|
|
22
22
|
/**
|
|
23
23
|
* Find all files in directory
|
|
24
24
|
*/
|
package/lib/misc/scan.d.ts
CHANGED
|
@@ -17,8 +17,8 @@ type ScanDirectoryCallbackFalseResult = boolean | null | undefined;
|
|
|
17
17
|
type ScanDirectoryCallbackStringResult = ScanDirectoryCallbackFalseResult | string;
|
|
18
18
|
type Callback<T> = (ext: string, file: string, subdir: string, path: string, stat: Stats) => T;
|
|
19
19
|
type AsyncCallback<T> = Callback<T | Promise<T>>;
|
|
20
|
-
type ScanDirectoryCallback = AsyncCallback<ScanDirectoryCallbackStringResult |
|
|
21
|
-
type ScanDirectorySyncCallback = Callback<ScanDirectoryCallbackStringResult |
|
|
20
|
+
type ScanDirectoryCallback = AsyncCallback<ScanDirectoryCallbackStringResult | undefined>;
|
|
21
|
+
type ScanDirectorySyncCallback = Callback<ScanDirectoryCallbackStringResult | undefined>;
|
|
22
22
|
/**
|
|
23
23
|
* Find all files in directory
|
|
24
24
|
*/
|
package/lib/optimise/figma.cjs
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const utils = require('@iconify/utils');
|
|
4
|
+
const svg_cleanup_inlineStyle = require('../svg/cleanup/inline-style.cjs');
|
|
3
5
|
const svg_data_tags = require('../svg/data/tags.cjs');
|
|
6
|
+
const svg_parse = require('../svg/parse.cjs');
|
|
7
|
+
const optimise_unwrap = require('./unwrap.cjs');
|
|
8
|
+
require('../css/parse.cjs');
|
|
9
|
+
require('../css/parser/tokens.cjs');
|
|
10
|
+
require('../css/parser/error.cjs');
|
|
11
|
+
require('../css/parser/strings.cjs');
|
|
12
|
+
require('../css/parser/text.cjs');
|
|
13
|
+
require('../svg/data/attributes.cjs');
|
|
4
14
|
|
|
5
15
|
function isTinyNumber(value, limit) {
|
|
6
16
|
const num = parseInt(value);
|
|
@@ -24,8 +34,10 @@ function checkClipPathNode(clipNode, expectedWidth, expectedHeight) {
|
|
|
24
34
|
...childNode.attribs
|
|
25
35
|
};
|
|
26
36
|
delete attribs["fill"];
|
|
27
|
-
const fill =
|
|
28
|
-
|
|
37
|
+
const fill = childNode.attribs["fill"];
|
|
38
|
+
const colorValue = fill ? utils.stringToColor(fill) : null;
|
|
39
|
+
const colorString = colorValue ? utils.colorToString(colorValue) : null;
|
|
40
|
+
if (fill && colorString !== "#fff") {
|
|
29
41
|
console.warn(
|
|
30
42
|
"Unxepected fill on clip path:",
|
|
31
43
|
childNode.attribs["fill"]
|
|
@@ -74,11 +86,79 @@ function checkClipPathNode(clipNode, expectedWidth, expectedHeight) {
|
|
|
74
86
|
}
|
|
75
87
|
const urlStart = "url(#";
|
|
76
88
|
const urlEnd = ")";
|
|
77
|
-
function
|
|
89
|
+
function remove(svg) {
|
|
90
|
+
optimise_unwrap.unwrapEmptyGroup(svg);
|
|
91
|
+
let content = svg.toString();
|
|
92
|
+
const backup = content;
|
|
93
|
+
const isPenpot = content.includes("frame-clip-def");
|
|
94
|
+
if (isPenpot) {
|
|
95
|
+
svg_cleanup_inlineStyle.cleanupInlineStyle(svg);
|
|
96
|
+
svg_parse.parseSVG(svg, (item) => {
|
|
97
|
+
const tagName = item.tagName;
|
|
98
|
+
for (const attr in item.element.attribs) {
|
|
99
|
+
const value = item.element.attribs[attr];
|
|
100
|
+
switch (attr) {
|
|
101
|
+
case "id":
|
|
102
|
+
if (!svg_data_tags.maskTags.has(tagName) && !svg_data_tags.symbolTag.has(tagName)) {
|
|
103
|
+
item.$element.removeAttr(attr);
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
case "class":
|
|
107
|
+
case "xmlns:xlink":
|
|
108
|
+
case "version":
|
|
109
|
+
item.$element.removeAttr(attr);
|
|
110
|
+
break;
|
|
111
|
+
case "transform": {
|
|
112
|
+
const trimmed = value.replace(/\s+/g, "").replace(/\.0+/g, "");
|
|
113
|
+
if (!trimmed || trimmed === "matrix(1,0,0,1,0,0)") {
|
|
114
|
+
item.$element.removeAttr(attr);
|
|
115
|
+
}
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
case "rx":
|
|
119
|
+
case "ry":
|
|
120
|
+
case "x":
|
|
121
|
+
case "y":
|
|
122
|
+
if (value === "0") {
|
|
123
|
+
item.$element.removeAttr(attr);
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
case "fill-opacity":
|
|
127
|
+
case "stroke-opacity":
|
|
128
|
+
case "opacity":
|
|
129
|
+
if (value === "1") {
|
|
130
|
+
item.$element.removeAttr(attr);
|
|
131
|
+
}
|
|
132
|
+
break;
|
|
133
|
+
case "fill":
|
|
134
|
+
case "stroke": {
|
|
135
|
+
const colorValue = utils.stringToColor(value);
|
|
136
|
+
if (colorValue?.type === "rgb") {
|
|
137
|
+
item.$element.attr(attr, utils.colorToString(colorValue));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
content = svg.toString();
|
|
144
|
+
}
|
|
145
|
+
const clipPathBlocks = content.match(
|
|
146
|
+
/<clipPath[^>]*>[\s\S]+?<\/clipPath>/g
|
|
147
|
+
);
|
|
148
|
+
if (clipPathBlocks?.length === 2 && clipPathBlocks[0] === clipPathBlocks[1]) {
|
|
149
|
+
const split = clipPathBlocks[0];
|
|
150
|
+
const lines = content.split(split);
|
|
151
|
+
content = lines.shift() + split + lines.join("");
|
|
152
|
+
}
|
|
153
|
+
if (content.includes("<defs>")) {
|
|
154
|
+
content = content.replace(/<\/?defs>/g, "");
|
|
155
|
+
}
|
|
156
|
+
if (content !== backup) {
|
|
157
|
+
svg.load(content);
|
|
158
|
+
}
|
|
78
159
|
const cheerio = svg.$svg;
|
|
79
160
|
const $root = svg.$svg(":root");
|
|
80
161
|
const children = $root.children();
|
|
81
|
-
const backup = svg.toString();
|
|
82
162
|
const shapesToClip = [];
|
|
83
163
|
let clipID;
|
|
84
164
|
for (let i = 0; i < children.length; i++) {
|
|
@@ -102,59 +182,26 @@ function removeFigmaClipPathFromSVG(svg) {
|
|
|
102
182
|
if (typeof clipID !== "string") {
|
|
103
183
|
return false;
|
|
104
184
|
}
|
|
105
|
-
const checkClipPath = (node) => {
|
|
106
|
-
const id = node.attribs["id"];
|
|
107
|
-
if (id !== clipID) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
const result = checkClipPathNode(
|
|
111
|
-
node,
|
|
112
|
-
svg.viewBox.width,
|
|
113
|
-
svg.viewBox.height
|
|
114
|
-
);
|
|
115
|
-
cheerio(node).remove();
|
|
116
|
-
return result;
|
|
117
|
-
};
|
|
118
185
|
const findClipPath = () => {
|
|
119
186
|
for (let i = 0; i < children.length; i++) {
|
|
120
187
|
const node = children[i];
|
|
121
|
-
if (node.type === "tag") {
|
|
122
|
-
const
|
|
123
|
-
if (
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
(test) => {
|
|
132
|
-
if (test.type === "text") {
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
return true;
|
|
136
|
-
}
|
|
137
|
-
);
|
|
138
|
-
if (!validChildren.length) {
|
|
139
|
-
cheerio(node).remove();
|
|
140
|
-
}
|
|
141
|
-
return result;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
if (tagName === "clipPath") {
|
|
147
|
-
const result = checkClipPath(node);
|
|
148
|
-
if (result !== void 0) {
|
|
149
|
-
return result;
|
|
150
|
-
}
|
|
188
|
+
if (node.type === "tag" && node.tagName === "clipPath") {
|
|
189
|
+
const id = node.attribs["id"];
|
|
190
|
+
if (id === clipID) {
|
|
191
|
+
const result = checkClipPathNode(
|
|
192
|
+
node,
|
|
193
|
+
svg.viewBox.width,
|
|
194
|
+
svg.viewBox.height
|
|
195
|
+
);
|
|
196
|
+
cheerio(node).remove();
|
|
197
|
+
return result;
|
|
151
198
|
}
|
|
199
|
+
return;
|
|
152
200
|
}
|
|
153
201
|
}
|
|
154
202
|
};
|
|
155
203
|
const clipPath = findClipPath();
|
|
156
204
|
if (!clipPath) {
|
|
157
|
-
svg.load(backup);
|
|
158
205
|
return false;
|
|
159
206
|
}
|
|
160
207
|
const attribs = clipPath.attribs;
|
|
@@ -163,7 +210,6 @@ function removeFigmaClipPathFromSVG(svg) {
|
|
|
163
210
|
cheerio(node).removeAttr("clip-path");
|
|
164
211
|
for (const attr in attribs) {
|
|
165
212
|
if (node.attribs[attr] !== void 0) {
|
|
166
|
-
svg.load(backup);
|
|
167
213
|
return false;
|
|
168
214
|
}
|
|
169
215
|
cheerio(node).attr(attr, attribs[attr]);
|
|
@@ -171,5 +217,16 @@ function removeFigmaClipPathFromSVG(svg) {
|
|
|
171
217
|
}
|
|
172
218
|
return true;
|
|
173
219
|
}
|
|
220
|
+
function removeFigmaClipPathFromSVG(svg) {
|
|
221
|
+
const backup = svg.toString();
|
|
222
|
+
try {
|
|
223
|
+
if (remove(svg)) {
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
} catch {
|
|
227
|
+
}
|
|
228
|
+
svg.load(backup);
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
174
231
|
|
|
175
232
|
exports.removeFigmaClipPathFromSVG = removeFigmaClipPathFromSVG;
|
package/lib/optimise/figma.d.cts
CHANGED
|
@@ -4,7 +4,10 @@ import '@iconify/types';
|
|
|
4
4
|
import '@iconify/utils/lib/customisations/defaults';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Removes clip path from SVG, which Figma
|
|
7
|
+
* Removes clip path from SVG, which Figma and Penpot add to icons that might have overflowing elements.
|
|
8
|
+
* Also removes mess generated by Penpot
|
|
9
|
+
*
|
|
10
|
+
* Function was originally designed for Figma only, but later added support for Penpot
|
|
8
11
|
*/
|
|
9
12
|
declare function removeFigmaClipPathFromSVG(svg: SVG): boolean;
|
|
10
13
|
|
package/lib/optimise/figma.d.mts
CHANGED
|
@@ -4,7 +4,10 @@ import '@iconify/types';
|
|
|
4
4
|
import '@iconify/utils/lib/customisations/defaults';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Removes clip path from SVG, which Figma
|
|
7
|
+
* Removes clip path from SVG, which Figma and Penpot add to icons that might have overflowing elements.
|
|
8
|
+
* Also removes mess generated by Penpot
|
|
9
|
+
*
|
|
10
|
+
* Function was originally designed for Figma only, but later added support for Penpot
|
|
8
11
|
*/
|
|
9
12
|
declare function removeFigmaClipPathFromSVG(svg: SVG): boolean;
|
|
10
13
|
|
package/lib/optimise/figma.d.ts
CHANGED
|
@@ -4,7 +4,10 @@ import '@iconify/types';
|
|
|
4
4
|
import '@iconify/utils/lib/customisations/defaults';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Removes clip path from SVG, which Figma
|
|
7
|
+
* Removes clip path from SVG, which Figma and Penpot add to icons that might have overflowing elements.
|
|
8
|
+
* Also removes mess generated by Penpot
|
|
9
|
+
*
|
|
10
|
+
* Function was originally designed for Figma only, but later added support for Penpot
|
|
8
11
|
*/
|
|
9
12
|
declare function removeFigmaClipPathFromSVG(svg: SVG): boolean;
|
|
10
13
|
|
package/lib/optimise/figma.mjs
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { stringToColor, colorToString } from '@iconify/utils';
|
|
2
|
+
import { cleanupInlineStyle } from '../svg/cleanup/inline-style.mjs';
|
|
3
|
+
import { maskTags, symbolTag, defsTag } from '../svg/data/tags.mjs';
|
|
4
|
+
import { parseSVG } from '../svg/parse.mjs';
|
|
5
|
+
import { unwrapEmptyGroup } from './unwrap.mjs';
|
|
6
|
+
import '../css/parse.mjs';
|
|
7
|
+
import '../css/parser/tokens.mjs';
|
|
8
|
+
import '../css/parser/error.mjs';
|
|
9
|
+
import '../css/parser/strings.mjs';
|
|
10
|
+
import '../css/parser/text.mjs';
|
|
11
|
+
import '../svg/data/attributes.mjs';
|
|
2
12
|
|
|
3
13
|
function isTinyNumber(value, limit) {
|
|
4
14
|
const num = parseInt(value);
|
|
@@ -22,8 +32,10 @@ function checkClipPathNode(clipNode, expectedWidth, expectedHeight) {
|
|
|
22
32
|
...childNode.attribs
|
|
23
33
|
};
|
|
24
34
|
delete attribs["fill"];
|
|
25
|
-
const fill =
|
|
26
|
-
|
|
35
|
+
const fill = childNode.attribs["fill"];
|
|
36
|
+
const colorValue = fill ? stringToColor(fill) : null;
|
|
37
|
+
const colorString = colorValue ? colorToString(colorValue) : null;
|
|
38
|
+
if (fill && colorString !== "#fff") {
|
|
27
39
|
console.warn(
|
|
28
40
|
"Unxepected fill on clip path:",
|
|
29
41
|
childNode.attribs["fill"]
|
|
@@ -72,11 +84,79 @@ function checkClipPathNode(clipNode, expectedWidth, expectedHeight) {
|
|
|
72
84
|
}
|
|
73
85
|
const urlStart = "url(#";
|
|
74
86
|
const urlEnd = ")";
|
|
75
|
-
function
|
|
87
|
+
function remove(svg) {
|
|
88
|
+
unwrapEmptyGroup(svg);
|
|
89
|
+
let content = svg.toString();
|
|
90
|
+
const backup = content;
|
|
91
|
+
const isPenpot = content.includes("frame-clip-def");
|
|
92
|
+
if (isPenpot) {
|
|
93
|
+
cleanupInlineStyle(svg);
|
|
94
|
+
parseSVG(svg, (item) => {
|
|
95
|
+
const tagName = item.tagName;
|
|
96
|
+
for (const attr in item.element.attribs) {
|
|
97
|
+
const value = item.element.attribs[attr];
|
|
98
|
+
switch (attr) {
|
|
99
|
+
case "id":
|
|
100
|
+
if (!maskTags.has(tagName) && !symbolTag.has(tagName)) {
|
|
101
|
+
item.$element.removeAttr(attr);
|
|
102
|
+
}
|
|
103
|
+
break;
|
|
104
|
+
case "class":
|
|
105
|
+
case "xmlns:xlink":
|
|
106
|
+
case "version":
|
|
107
|
+
item.$element.removeAttr(attr);
|
|
108
|
+
break;
|
|
109
|
+
case "transform": {
|
|
110
|
+
const trimmed = value.replace(/\s+/g, "").replace(/\.0+/g, "");
|
|
111
|
+
if (!trimmed || trimmed === "matrix(1,0,0,1,0,0)") {
|
|
112
|
+
item.$element.removeAttr(attr);
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case "rx":
|
|
117
|
+
case "ry":
|
|
118
|
+
case "x":
|
|
119
|
+
case "y":
|
|
120
|
+
if (value === "0") {
|
|
121
|
+
item.$element.removeAttr(attr);
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
case "fill-opacity":
|
|
125
|
+
case "stroke-opacity":
|
|
126
|
+
case "opacity":
|
|
127
|
+
if (value === "1") {
|
|
128
|
+
item.$element.removeAttr(attr);
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
case "fill":
|
|
132
|
+
case "stroke": {
|
|
133
|
+
const colorValue = stringToColor(value);
|
|
134
|
+
if (colorValue?.type === "rgb") {
|
|
135
|
+
item.$element.attr(attr, colorToString(colorValue));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
content = svg.toString();
|
|
142
|
+
}
|
|
143
|
+
const clipPathBlocks = content.match(
|
|
144
|
+
/<clipPath[^>]*>[\s\S]+?<\/clipPath>/g
|
|
145
|
+
);
|
|
146
|
+
if (clipPathBlocks?.length === 2 && clipPathBlocks[0] === clipPathBlocks[1]) {
|
|
147
|
+
const split = clipPathBlocks[0];
|
|
148
|
+
const lines = content.split(split);
|
|
149
|
+
content = lines.shift() + split + lines.join("");
|
|
150
|
+
}
|
|
151
|
+
if (content.includes("<defs>")) {
|
|
152
|
+
content = content.replace(/<\/?defs>/g, "");
|
|
153
|
+
}
|
|
154
|
+
if (content !== backup) {
|
|
155
|
+
svg.load(content);
|
|
156
|
+
}
|
|
76
157
|
const cheerio = svg.$svg;
|
|
77
158
|
const $root = svg.$svg(":root");
|
|
78
159
|
const children = $root.children();
|
|
79
|
-
const backup = svg.toString();
|
|
80
160
|
const shapesToClip = [];
|
|
81
161
|
let clipID;
|
|
82
162
|
for (let i = 0; i < children.length; i++) {
|
|
@@ -100,59 +180,26 @@ function removeFigmaClipPathFromSVG(svg) {
|
|
|
100
180
|
if (typeof clipID !== "string") {
|
|
101
181
|
return false;
|
|
102
182
|
}
|
|
103
|
-
const checkClipPath = (node) => {
|
|
104
|
-
const id = node.attribs["id"];
|
|
105
|
-
if (id !== clipID) {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
const result = checkClipPathNode(
|
|
109
|
-
node,
|
|
110
|
-
svg.viewBox.width,
|
|
111
|
-
svg.viewBox.height
|
|
112
|
-
);
|
|
113
|
-
cheerio(node).remove();
|
|
114
|
-
return result;
|
|
115
|
-
};
|
|
116
183
|
const findClipPath = () => {
|
|
117
184
|
for (let i = 0; i < children.length; i++) {
|
|
118
185
|
const node = children[i];
|
|
119
|
-
if (node.type === "tag") {
|
|
120
|
-
const
|
|
121
|
-
if (
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
(test) => {
|
|
130
|
-
if (test.type === "text") {
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
return true;
|
|
134
|
-
}
|
|
135
|
-
);
|
|
136
|
-
if (!validChildren.length) {
|
|
137
|
-
cheerio(node).remove();
|
|
138
|
-
}
|
|
139
|
-
return result;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (tagName === "clipPath") {
|
|
145
|
-
const result = checkClipPath(node);
|
|
146
|
-
if (result !== void 0) {
|
|
147
|
-
return result;
|
|
148
|
-
}
|
|
186
|
+
if (node.type === "tag" && node.tagName === "clipPath") {
|
|
187
|
+
const id = node.attribs["id"];
|
|
188
|
+
if (id === clipID) {
|
|
189
|
+
const result = checkClipPathNode(
|
|
190
|
+
node,
|
|
191
|
+
svg.viewBox.width,
|
|
192
|
+
svg.viewBox.height
|
|
193
|
+
);
|
|
194
|
+
cheerio(node).remove();
|
|
195
|
+
return result;
|
|
149
196
|
}
|
|
197
|
+
return;
|
|
150
198
|
}
|
|
151
199
|
}
|
|
152
200
|
};
|
|
153
201
|
const clipPath = findClipPath();
|
|
154
202
|
if (!clipPath) {
|
|
155
|
-
svg.load(backup);
|
|
156
203
|
return false;
|
|
157
204
|
}
|
|
158
205
|
const attribs = clipPath.attribs;
|
|
@@ -161,7 +208,6 @@ function removeFigmaClipPathFromSVG(svg) {
|
|
|
161
208
|
cheerio(node).removeAttr("clip-path");
|
|
162
209
|
for (const attr in attribs) {
|
|
163
210
|
if (node.attribs[attr] !== void 0) {
|
|
164
|
-
svg.load(backup);
|
|
165
211
|
return false;
|
|
166
212
|
}
|
|
167
213
|
cheerio(node).attr(attr, attribs[attr]);
|
|
@@ -169,5 +215,16 @@ function removeFigmaClipPathFromSVG(svg) {
|
|
|
169
215
|
}
|
|
170
216
|
return true;
|
|
171
217
|
}
|
|
218
|
+
function removeFigmaClipPathFromSVG(svg) {
|
|
219
|
+
const backup = svg.toString();
|
|
220
|
+
try {
|
|
221
|
+
if (remove(svg)) {
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
} catch {
|
|
225
|
+
}
|
|
226
|
+
svg.load(backup);
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
172
229
|
|
|
173
230
|
export { removeFigmaClipPathFromSVG };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function unwrapEmptyGroup(svg) {
|
|
4
|
+
const cheerio = svg.$svg;
|
|
5
|
+
const $root = svg.$svg(":root");
|
|
6
|
+
const children = $root.children();
|
|
7
|
+
if (children.length !== 1 || children[0].tagName !== "g") {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const groupNode = children[0];
|
|
11
|
+
const html = cheerio(groupNode).html();
|
|
12
|
+
if (!html) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
for (const attr in groupNode.attribs) {
|
|
16
|
+
const value = groupNode.attribs[attr];
|
|
17
|
+
switch (attr) {
|
|
18
|
+
case "id": {
|
|
19
|
+
if (html?.includes(value)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
default:
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
$root.html(html);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
exports.unwrapEmptyGroup = unwrapEmptyGroup;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SVG } from '../svg/index.cjs';
|
|
2
|
+
import 'cheerio';
|
|
3
|
+
import '@iconify/types';
|
|
4
|
+
import '@iconify/utils/lib/customisations/defaults';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Removes empty group from SVG root element
|
|
8
|
+
*/
|
|
9
|
+
declare function unwrapEmptyGroup(svg: SVG): void;
|
|
10
|
+
|
|
11
|
+
export { unwrapEmptyGroup };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SVG } from '../svg/index.mjs';
|
|
2
|
+
import 'cheerio';
|
|
3
|
+
import '@iconify/types';
|
|
4
|
+
import '@iconify/utils/lib/customisations/defaults';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Removes empty group from SVG root element
|
|
8
|
+
*/
|
|
9
|
+
declare function unwrapEmptyGroup(svg: SVG): void;
|
|
10
|
+
|
|
11
|
+
export { unwrapEmptyGroup };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SVG } from '../svg/index.js';
|
|
2
|
+
import 'cheerio';
|
|
3
|
+
import '@iconify/types';
|
|
4
|
+
import '@iconify/utils/lib/customisations/defaults';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Removes empty group from SVG root element
|
|
8
|
+
*/
|
|
9
|
+
declare function unwrapEmptyGroup(svg: SVG): void;
|
|
10
|
+
|
|
11
|
+
export { unwrapEmptyGroup };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
function unwrapEmptyGroup(svg) {
|
|
2
|
+
const cheerio = svg.$svg;
|
|
3
|
+
const $root = svg.$svg(":root");
|
|
4
|
+
const children = $root.children();
|
|
5
|
+
if (children.length !== 1 || children[0].tagName !== "g") {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const groupNode = children[0];
|
|
9
|
+
const html = cheerio(groupNode).html();
|
|
10
|
+
if (!html) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
for (const attr in groupNode.attribs) {
|
|
14
|
+
const value = groupNode.attribs[attr];
|
|
15
|
+
switch (attr) {
|
|
16
|
+
case "id": {
|
|
17
|
+
if (html?.includes(value)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
default:
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
$root.html(html);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { unwrapEmptyGroup };
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"type": "module",
|
|
4
4
|
"description": "Collection of functions for cleaning up and parsing SVG for Iconify project",
|
|
5
5
|
"author": "Vjacheslav Trushkin",
|
|
6
|
-
"version": "4.0.
|
|
6
|
+
"version": "4.0.2",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"bugs": "https://github.com/iconify/tools/issues",
|
|
9
9
|
"homepage": "https://github.com/iconify/tools",
|
|
@@ -16,29 +16,29 @@
|
|
|
16
16
|
"types": "./lib/index.d.ts",
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@iconify/types": "^2.0.0",
|
|
19
|
-
"@iconify/utils": "^2.1.
|
|
20
|
-
"@types/tar": "^6.1.
|
|
21
|
-
"axios": "^1.6.
|
|
19
|
+
"@iconify/utils": "^2.1.22",
|
|
20
|
+
"@types/tar": "^6.1.11",
|
|
21
|
+
"axios": "^1.6.7",
|
|
22
22
|
"cheerio": "1.0.0-rc.12",
|
|
23
23
|
"extract-zip": "^2.0.1",
|
|
24
24
|
"local-pkg": "^0.5.0",
|
|
25
|
-
"pathe": "^1.1.
|
|
26
|
-
"svgo": "^3.
|
|
25
|
+
"pathe": "^1.1.2",
|
|
26
|
+
"svgo": "^3.2.0",
|
|
27
27
|
"tar": "^6.2.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@types/jest": "^29.5.
|
|
31
|
-
"@types/node": "^20.
|
|
32
|
-
"@typescript-eslint/eslint-plugin": "^6.
|
|
33
|
-
"@typescript-eslint/parser": "^6.
|
|
30
|
+
"@types/jest": "^29.5.12",
|
|
31
|
+
"@types/node": "^20.11.17",
|
|
32
|
+
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
|
33
|
+
"@typescript-eslint/parser": "^6.21.0",
|
|
34
34
|
"cross-env": "^7.0.3",
|
|
35
35
|
"eslint": "^8.56.0",
|
|
36
36
|
"eslint-config-prettier": "^9.1.0",
|
|
37
|
-
"eslint-plugin-prettier": "^5.1.
|
|
37
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
38
38
|
"jest": "^29.7.0",
|
|
39
|
-
"prettier": "^3.
|
|
39
|
+
"prettier": "^3.2.5",
|
|
40
40
|
"rimraf": "^5.0.5",
|
|
41
|
-
"ts-jest": "^29.1.
|
|
41
|
+
"ts-jest": "^29.1.2",
|
|
42
42
|
"typescript": "^5.3.3",
|
|
43
43
|
"unbuild": "^2.0.0"
|
|
44
44
|
},
|
|
@@ -454,6 +454,11 @@
|
|
|
454
454
|
"require": "./lib/optimise/svgo.cjs",
|
|
455
455
|
"import": "./lib/optimise/svgo.mjs"
|
|
456
456
|
},
|
|
457
|
+
"./lib/optimise/unwrap": {
|
|
458
|
+
"types": "./lib/optimise/unwrap.d.ts",
|
|
459
|
+
"require": "./lib/optimise/unwrap.cjs",
|
|
460
|
+
"import": "./lib/optimise/unwrap.mjs"
|
|
461
|
+
},
|
|
457
462
|
"./lib/svg/analyse": {
|
|
458
463
|
"types": "./lib/svg/analyse.d.ts",
|
|
459
464
|
"require": "./lib/svg/analyse.cjs",
|