@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 CHANGED
@@ -88,6 +88,7 @@ require('extract-zip');
88
88
  require('tar');
89
89
  require('./download/gitlab/types.cjs');
90
90
  require('./colors/attribs.cjs');
91
+ require('./optimise/unwrap.cjs');
91
92
  require('./export/helpers/custom-files.cjs');
92
93
  require('child_process');
93
94
 
package/lib/index.mjs CHANGED
@@ -86,5 +86,6 @@ import 'extract-zip';
86
86
  import 'tar';
87
87
  import './download/gitlab/types.mjs';
88
88
  import './colors/attribs.mjs';
89
+ import './optimise/unwrap.mjs';
89
90
  import './export/helpers/custom-files.mjs';
90
91
  import 'child_process';
@@ -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 | unknown>;
21
- type ScanDirectorySyncCallback = Callback<ScanDirectoryCallbackStringResult | unknown>;
20
+ type ScanDirectoryCallback = AsyncCallback<ScanDirectoryCallbackStringResult | undefined>;
21
+ type ScanDirectorySyncCallback = Callback<ScanDirectoryCallbackStringResult | undefined>;
22
22
  /**
23
23
  * Find all files in directory
24
24
  */
@@ -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 | unknown>;
21
- type ScanDirectorySyncCallback = Callback<ScanDirectoryCallbackStringResult | unknown>;
20
+ type ScanDirectoryCallback = AsyncCallback<ScanDirectoryCallbackStringResult | undefined>;
21
+ type ScanDirectorySyncCallback = Callback<ScanDirectoryCallbackStringResult | undefined>;
22
22
  /**
23
23
  * Find all files in directory
24
24
  */
@@ -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 | unknown>;
21
- type ScanDirectorySyncCallback = Callback<ScanDirectoryCallbackStringResult | unknown>;
20
+ type ScanDirectoryCallback = AsyncCallback<ScanDirectoryCallbackStringResult | undefined>;
21
+ type ScanDirectorySyncCallback = Callback<ScanDirectoryCallbackStringResult | undefined>;
22
22
  /**
23
23
  * Find all files in directory
24
24
  */
@@ -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 = (childNode.attribs["fill"] ?? "").toLowerCase();
28
- if (fill !== "white" && fill !== "#fff" && fill !== "#ffffff") {
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 removeFigmaClipPathFromSVG(svg) {
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 tagName = node.tagName;
123
- if (svg_data_tags.defsTag.has(tagName)) {
124
- const defsChildren = node.children;
125
- for (let j = 0; j < defsChildren.length; j++) {
126
- const childNode = defsChildren[j];
127
- if (childNode.type === "tag" && childNode.tagName === "clipPath") {
128
- const result = checkClipPath(childNode);
129
- if (result !== void 0) {
130
- const validChildren = node.children.filter(
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;
@@ -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 adds to icons that might have overflowing elements
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
 
@@ -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 adds to icons that might have overflowing elements
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
 
@@ -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 adds to icons that might have overflowing elements
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
 
@@ -1,4 +1,14 @@
1
- import { defsTag, maskTags, symbolTag } from '../svg/data/tags.mjs';
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 = (childNode.attribs["fill"] ?? "").toLowerCase();
26
- if (fill !== "white" && fill !== "#fff" && fill !== "#ffffff") {
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 removeFigmaClipPathFromSVG(svg) {
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 tagName = node.tagName;
121
- if (defsTag.has(tagName)) {
122
- const defsChildren = node.children;
123
- for (let j = 0; j < defsChildren.length; j++) {
124
- const childNode = defsChildren[j];
125
- if (childNode.type === "tag" && childNode.tagName === "clipPath") {
126
- const result = checkClipPath(childNode);
127
- if (result !== void 0) {
128
- const validChildren = node.children.filter(
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.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.14",
20
- "@types/tar": "^6.1.10",
21
- "axios": "^1.6.3",
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.1",
26
- "svgo": "^3.1.0",
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.11",
31
- "@types/node": "^20.10.5",
32
- "@typescript-eslint/eslint-plugin": "^6.16.0",
33
- "@typescript-eslint/parser": "^6.16.0",
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.2",
37
+ "eslint-plugin-prettier": "^5.1.3",
38
38
  "jest": "^29.7.0",
39
- "prettier": "^3.1.1",
39
+ "prettier": "^3.2.5",
40
40
  "rimraf": "^5.0.5",
41
- "ts-jest": "^29.1.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",