@iconify/tools 2.0.11 → 2.0.12

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 (38) hide show
  1. package/lib/colors/parse.d.ts +14 -7
  2. package/lib/colors/parse.js +101 -39
  3. package/lib/colors/parse.mjs +81 -38
  4. package/lib/index.d.ts +2 -0
  5. package/lib/index.js +5 -1
  6. package/lib/index.mjs +4 -0
  7. package/lib/optimise/global-style.d.ts +5 -0
  8. package/lib/optimise/global-style.js +158 -0
  9. package/lib/optimise/global-style.mjs +129 -0
  10. package/lib/svg/analyse/error.d.ts +5 -0
  11. package/lib/svg/analyse/error.js +22 -0
  12. package/lib/svg/analyse/error.mjs +16 -0
  13. package/lib/svg/analyse/types.d.ts +89 -0
  14. package/lib/svg/analyse/types.js +2 -0
  15. package/lib/svg/analyse/types.mjs +0 -0
  16. package/lib/svg/analyse.d.ts +8 -0
  17. package/lib/svg/analyse.js +352 -0
  18. package/lib/svg/analyse.mjs +302 -0
  19. package/lib/svg/cleanup/attribs.d.ts +1 -1
  20. package/lib/svg/cleanup/attribs.js +8 -0
  21. package/lib/svg/cleanup/attribs.mjs +8 -1
  22. package/lib/svg/cleanup/bad-tags.d.ts +1 -1
  23. package/lib/svg/cleanup/bad-tags.js +0 -2
  24. package/lib/svg/cleanup/bad-tags.mjs +0 -3
  25. package/lib/svg/cleanup/inline-style.d.ts +1 -1
  26. package/lib/svg/cleanup/root-svg.d.ts +1 -1
  27. package/lib/svg/cleanup/root-svg.js +3 -1
  28. package/lib/svg/cleanup/root-svg.mjs +2 -2
  29. package/lib/svg/cleanup/svgo-style.d.ts +1 -1
  30. package/lib/svg/data/attributes.js +1 -1
  31. package/lib/svg/data/attributes.mjs +1 -1
  32. package/lib/svg/data/tags.d.ts +15 -7
  33. package/lib/svg/data/tags.js +20 -9
  34. package/lib/svg/data/tags.mjs +11 -6
  35. package/lib/svg/parse-style.d.ts +7 -7
  36. package/lib/svg/parse-style.js +27 -7
  37. package/lib/svg/parse-style.mjs +26 -7
  38. package/package.json +17 -1
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cleanupGlobalStyle = void 0;
4
+ require("../svg/data/attributes");
5
+ const tags_1 = require("../svg/data/tags");
6
+ const parse_1 = require("../svg/parse");
7
+ const parse_style_1 = require("../svg/parse-style");
8
+ function getClassList(value) {
9
+ return value === null || value === void 0 ? void 0 : value.split(/\s+/);
10
+ }
11
+ const tempDataAttrbiute = 'data-gstyle-temp';
12
+ /**
13
+ * Expand global style
14
+ */
15
+ async function cleanupGlobalStyle(svg) {
16
+ const backup = svg.toString();
17
+ let containsTempAttr = false;
18
+ // Find all animated classes
19
+ const animatedClasses = new Set();
20
+ await (0, parse_1.parseSVG)(svg, (item) => {
21
+ if (!tags_1.animateTags.has(item.tagName)) {
22
+ return;
23
+ }
24
+ const $element = item.$element;
25
+ if ($element.attr('attributeName') !== 'class') {
26
+ return;
27
+ }
28
+ ['from', 'to', 'values'].forEach((attr) => {
29
+ const value = $element.attr(attr);
30
+ if (typeof value !== 'string') {
31
+ return;
32
+ }
33
+ value.split(';').forEach((item) => {
34
+ getClassList(item).forEach((className) => {
35
+ animatedClasses.add(className);
36
+ });
37
+ });
38
+ });
39
+ });
40
+ // Parse style
41
+ try {
42
+ await (0, parse_style_1.parseSVGStyle)(svg, async (styleItem) => {
43
+ var _a;
44
+ const returnValue = styleItem.value;
45
+ if (styleItem.type !== 'global') {
46
+ return returnValue;
47
+ }
48
+ // Handle only simple selectors
49
+ if (styleItem.selectors.length !== 1 ||
50
+ styleItem.selectorTokens.length !== 1) {
51
+ return returnValue;
52
+ }
53
+ // Do not handle media queries
54
+ const selectorToken = styleItem.selectorTokens[0];
55
+ if (selectorToken.type !== 'selector') {
56
+ return returnValue;
57
+ }
58
+ // Simple selector and simple rule
59
+ const selector = styleItem.selectors[0];
60
+ const firstChar = selector.charAt(0);
61
+ let matchType;
62
+ if (firstChar === '.') {
63
+ matchType = 'class';
64
+ }
65
+ else if (firstChar === '#') {
66
+ matchType = 'id';
67
+ }
68
+ else if (tags_1.allValidTags.has(selector)) {
69
+ matchType = 'tag';
70
+ }
71
+ else {
72
+ return returnValue;
73
+ }
74
+ const valueMatch = matchType === 'tag' ? selector : selector.slice(1);
75
+ if (matchType === 'class' && animatedClasses.has(valueMatch)) {
76
+ // Class name is used in animations
77
+ return returnValue;
78
+ }
79
+ // Check if element is a match
80
+ const isMatch = (tagName, $element) => {
81
+ switch (matchType) {
82
+ case 'id':
83
+ return $element.attr('id') === valueMatch;
84
+ case 'tag':
85
+ return tagName === valueMatch;
86
+ case 'class': {
87
+ const className = $element.attr('class');
88
+ if (!className ||
89
+ getClassList(className).indexOf(valueMatch) === -1) {
90
+ return false;
91
+ }
92
+ }
93
+ }
94
+ return true;
95
+ };
96
+ // Parse all elements
97
+ await (0, parse_1.parseSVG)(svg, (svgItem) => {
98
+ var _a;
99
+ const tagName = svgItem.tagName;
100
+ const $element = svgItem.$element;
101
+ if (!isMatch(tagName, $element)) {
102
+ return;
103
+ }
104
+ // Transfer attribute
105
+ const addedAttributes = new Set((_a = $element.attr(tempDataAttrbiute)) === null || _a === void 0 ? void 0 : _a.split(/\s+/));
106
+ const prop = styleItem.prop;
107
+ if ($element.attr(prop) !== void 0) {
108
+ // Previously added attribute?
109
+ if (addedAttributes.has(prop)) {
110
+ // Two CSS rules are applied to same element: abort parsing and restore content from backup.
111
+ // This parse is very basic, it does not account for specificity.
112
+ throw new Error('Duplicate attribute');
113
+ }
114
+ }
115
+ $element.attr(prop, styleItem.value);
116
+ addedAttributes.add(prop);
117
+ $element.attr(tempDataAttrbiute, Array.from(addedAttributes).join(' '));
118
+ containsTempAttr = true;
119
+ });
120
+ // Remove class attribute
121
+ if (matchType === 'class' &&
122
+ ((_a = styleItem.nextTokens[0]) === null || _a === void 0 ? void 0 : _a.type) === 'close') {
123
+ // Can remove class
124
+ await (0, parse_1.parseSVG)(svg, (svgItem) => {
125
+ const $element = svgItem.$element;
126
+ if (!isMatch('', $element)) {
127
+ return;
128
+ }
129
+ // Remove class
130
+ const classList = getClassList($element.attr('class'));
131
+ if (!classList) {
132
+ return;
133
+ }
134
+ const filtered = classList.filter((item) => item !== valueMatch);
135
+ if (!filtered.length) {
136
+ $element.removeAttr('class');
137
+ }
138
+ else {
139
+ $element.attr('class', filtered.join(' '));
140
+ }
141
+ });
142
+ }
143
+ // Remove rule
144
+ return;
145
+ });
146
+ // Remove temporary attributes
147
+ if (containsTempAttr) {
148
+ await (0, parse_1.parseSVG)(svg, (item) => {
149
+ item.$element.removeAttr(tempDataAttrbiute);
150
+ });
151
+ }
152
+ }
153
+ catch (err) {
154
+ // Failed: restore from backup
155
+ svg.load(backup);
156
+ }
157
+ }
158
+ exports.cleanupGlobalStyle = cleanupGlobalStyle;
@@ -0,0 +1,129 @@
1
+ // src/optimise/global-style.ts
2
+ import "../svg/data/attributes.mjs";
3
+ import { allValidTags, animateTags } from "../svg/data/tags.mjs";
4
+ import { parseSVG } from "../svg/parse.mjs";
5
+ import { parseSVGStyle } from "../svg/parse-style.mjs";
6
+ function getClassList(value) {
7
+ return value == null ? void 0 : value.split(/\s+/);
8
+ }
9
+ var tempDataAttrbiute = "data-gstyle-temp";
10
+ async function cleanupGlobalStyle(svg) {
11
+ const backup = svg.toString();
12
+ let containsTempAttr = false;
13
+ const animatedClasses = new Set();
14
+ await parseSVG(svg, (item) => {
15
+ if (!animateTags.has(item.tagName)) {
16
+ return;
17
+ }
18
+ const $element = item.$element;
19
+ if ($element.attr("attributeName") !== "class") {
20
+ return;
21
+ }
22
+ ["from", "to", "values"].forEach((attr) => {
23
+ const value = $element.attr(attr);
24
+ if (typeof value !== "string") {
25
+ return;
26
+ }
27
+ value.split(";").forEach((item2) => {
28
+ getClassList(item2).forEach((className) => {
29
+ animatedClasses.add(className);
30
+ });
31
+ });
32
+ });
33
+ });
34
+ try {
35
+ await parseSVGStyle(svg, async (styleItem) => {
36
+ var _a;
37
+ const returnValue = styleItem.value;
38
+ if (styleItem.type !== "global") {
39
+ return returnValue;
40
+ }
41
+ if (styleItem.selectors.length !== 1 || styleItem.selectorTokens.length !== 1) {
42
+ return returnValue;
43
+ }
44
+ const selectorToken = styleItem.selectorTokens[0];
45
+ if (selectorToken.type !== "selector") {
46
+ return returnValue;
47
+ }
48
+ const selector = styleItem.selectors[0];
49
+ const firstChar = selector.charAt(0);
50
+ let matchType;
51
+ if (firstChar === ".") {
52
+ matchType = "class";
53
+ } else if (firstChar === "#") {
54
+ matchType = "id";
55
+ } else if (allValidTags.has(selector)) {
56
+ matchType = "tag";
57
+ } else {
58
+ return returnValue;
59
+ }
60
+ const valueMatch = matchType === "tag" ? selector : selector.slice(1);
61
+ if (matchType === "class" && animatedClasses.has(valueMatch)) {
62
+ return returnValue;
63
+ }
64
+ const isMatch = (tagName, $element) => {
65
+ switch (matchType) {
66
+ case "id":
67
+ return $element.attr("id") === valueMatch;
68
+ case "tag":
69
+ return tagName === valueMatch;
70
+ case "class": {
71
+ const className = $element.attr("class");
72
+ if (!className || getClassList(className).indexOf(valueMatch) === -1) {
73
+ return false;
74
+ }
75
+ }
76
+ }
77
+ return true;
78
+ };
79
+ await parseSVG(svg, (svgItem) => {
80
+ var _a2;
81
+ const tagName = svgItem.tagName;
82
+ const $element = svgItem.$element;
83
+ if (!isMatch(tagName, $element)) {
84
+ return;
85
+ }
86
+ const addedAttributes = new Set((_a2 = $element.attr(tempDataAttrbiute)) == null ? void 0 : _a2.split(/\s+/));
87
+ const prop = styleItem.prop;
88
+ if ($element.attr(prop) !== void 0) {
89
+ if (addedAttributes.has(prop)) {
90
+ throw new Error("Duplicate attribute");
91
+ }
92
+ }
93
+ $element.attr(prop, styleItem.value);
94
+ addedAttributes.add(prop);
95
+ $element.attr(tempDataAttrbiute, Array.from(addedAttributes).join(" "));
96
+ containsTempAttr = true;
97
+ });
98
+ if (matchType === "class" && ((_a = styleItem.nextTokens[0]) == null ? void 0 : _a.type) === "close") {
99
+ await parseSVG(svg, (svgItem) => {
100
+ const $element = svgItem.$element;
101
+ if (!isMatch("", $element)) {
102
+ return;
103
+ }
104
+ const classList = getClassList($element.attr("class"));
105
+ if (!classList) {
106
+ return;
107
+ }
108
+ const filtered = classList.filter((item) => item !== valueMatch);
109
+ if (!filtered.length) {
110
+ $element.removeAttr("class");
111
+ } else {
112
+ $element.attr("class", filtered.join(" "));
113
+ }
114
+ });
115
+ }
116
+ return;
117
+ });
118
+ if (containsTempAttr) {
119
+ await parseSVG(svg, (item) => {
120
+ item.$element.removeAttr(tempDataAttrbiute);
121
+ });
122
+ }
123
+ } catch (err) {
124
+ svg.load(backup);
125
+ }
126
+ }
127
+ export {
128
+ cleanupGlobalStyle
129
+ };
@@ -0,0 +1,5 @@
1
+ import type { ExtendedTagElement } from './types';
2
+ /**
3
+ * Get tag for error message
4
+ */
5
+ export declare function analyseTagError(element: ExtendedTagElement): string;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.analyseTagError = void 0;
4
+ /**
5
+ * Get tag for error message
6
+ */
7
+ function analyseTagError(element) {
8
+ let result = '<' + element.tagName;
9
+ if (element._id) {
10
+ result += ' id="' + element._id + '"';
11
+ }
12
+ const attribs = element.attribs;
13
+ if (attribs['d']) {
14
+ const value = attribs['d'];
15
+ result +=
16
+ ' d="' +
17
+ (value.length > 16 ? value.slice(0, 12) + '...' : value) +
18
+ '"';
19
+ }
20
+ return result + '>';
21
+ }
22
+ exports.analyseTagError = analyseTagError;
@@ -0,0 +1,16 @@
1
+ // src/svg/analyse/error.ts
2
+ function analyseTagError(element) {
3
+ let result = "<" + element.tagName;
4
+ if (element._id) {
5
+ result += ' id="' + element._id + '"';
6
+ }
7
+ const attribs = element.attribs;
8
+ if (attribs["d"]) {
9
+ const value = attribs["d"];
10
+ result += ' d="' + (value.length > 16 ? value.slice(0, 12) + "..." : value) + '"';
11
+ }
12
+ return result + ">";
13
+ }
14
+ export {
15
+ analyseTagError
16
+ };
@@ -0,0 +1,89 @@
1
+ /// <reference types="cheerio" />
2
+ /**
3
+ * Options
4
+ */
5
+ export interface AnalyseSVGStructureOptions {
6
+ fixErrors?: boolean;
7
+ }
8
+ /**
9
+ * Extended properties for element
10
+ */
11
+ /**
12
+ * Link to element
13
+ */
14
+ export interface LinkToElementWithID {
15
+ id: string;
16
+ usedAsMask: boolean;
17
+ usedByIndex: number;
18
+ }
19
+ /**
20
+ * How element is used by parent elements
21
+ */
22
+ export interface ExtendedTagElementUses {
23
+ _usedAsMask: boolean;
24
+ _usedAsPaint: boolean;
25
+ }
26
+ /**
27
+ * Definition: mask, clip path, symbol, etc...
28
+ */
29
+ interface ReusableElement {
30
+ id: string;
31
+ isMask: boolean;
32
+ index: number;
33
+ }
34
+ /**
35
+ * Element with id
36
+ *
37
+ * Similar to ReusableElement, but not necessary a definition - any element with id. Also contains list of child elements
38
+ */
39
+ export interface ElementWithID {
40
+ id: string;
41
+ isMask: boolean;
42
+ indexes: Set<number>;
43
+ }
44
+ /**
45
+ * Parent and child elements. Unlike standard tree, this tree is for elements that inherit attributes from parent element
46
+ */
47
+ interface ExtendedTagElementRelations {
48
+ _parentElement?: number;
49
+ _childElements?: number[];
50
+ }
51
+ /**
52
+ * Extended tag
53
+ */
54
+ export interface ExtendedTagElement extends cheerio.TagElement, ExtendedTagElementUses, ExtendedTagElementRelations {
55
+ _index: number;
56
+ _id?: string;
57
+ _belongsTo?: ElementWithID[];
58
+ _reusableElement?: ReusableElement;
59
+ _linksTo?: LinkToElementWithID[];
60
+ }
61
+ /**
62
+ * Additional stuff for <svg>
63
+ */
64
+ export interface ExtendedRootTagElement extends ExtendedTagElement {
65
+ _parsed?: boolean;
66
+ }
67
+ /**
68
+ * Tree
69
+ */
70
+ export interface ElementsTreeItem {
71
+ index: number;
72
+ usedAsMask: boolean;
73
+ parent?: ElementsTreeItem;
74
+ children: ElementsTreeItem[];
75
+ }
76
+ /**
77
+ * Elements map
78
+ */
79
+ export declare type ElementsMap = Map<number, ExtendedTagElement>;
80
+ /**
81
+ * Result
82
+ */
83
+ export interface AnalyseSVGStructureResult {
84
+ elements: ElementsMap;
85
+ ids: Record<string, number>;
86
+ links: LinkToElementWithID[];
87
+ tree: ElementsTreeItem;
88
+ }
89
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
File without changes
@@ -0,0 +1,8 @@
1
+ import type { SVG } from './index';
2
+ import type { AnalyseSVGStructureResult, AnalyseSVGStructureOptions } from './analyse/types';
3
+ /**
4
+ * Find all IDs, links, which elements use palette, which items aren't used
5
+ *
6
+ * Before running this function run cleanup functions to change inline style to attributes and fix attributes
7
+ */
8
+ export declare function analyseSVGStructure(svg: SVG, options?: AnalyseSVGStructureOptions): Promise<AnalyseSVGStructureResult>;