@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,23 @@
|
|
|
1
|
+
// src/css/parser/error.ts
|
|
2
|
+
function styleParseError(message, code, index) {
|
|
3
|
+
let fullMessage = message;
|
|
4
|
+
if (typeof index === "number" && index !== -1) {
|
|
5
|
+
const start = index;
|
|
6
|
+
const remaining = code.slice(index) + "!";
|
|
7
|
+
const trimmed = remaining.trim();
|
|
8
|
+
const end = start + remaining.length - trimmed.length;
|
|
9
|
+
const code2 = code.slice(0, end);
|
|
10
|
+
const line = code2.length - code2.replace(/\n/g, "").length + 1;
|
|
11
|
+
fullMessage = message + " on line " + line;
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
type: "style-parse-error",
|
|
15
|
+
message,
|
|
16
|
+
code,
|
|
17
|
+
index,
|
|
18
|
+
fullMessage
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
styleParseError
|
|
23
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tokensToString = void 0;
|
|
4
|
+
const tab = '\t';
|
|
5
|
+
const nl = '\n';
|
|
6
|
+
/**
|
|
7
|
+
* Convert tokens tree to string
|
|
8
|
+
*/
|
|
9
|
+
function tokensToString(tree) {
|
|
10
|
+
let compact = true;
|
|
11
|
+
for (let i = 0; i < tree.length; i++) {
|
|
12
|
+
if (tree[i].type !== 'rule') {
|
|
13
|
+
compact = false;
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return tree
|
|
18
|
+
.map((token) => {
|
|
19
|
+
return parseToken(token, compact, 0);
|
|
20
|
+
})
|
|
21
|
+
.join('');
|
|
22
|
+
}
|
|
23
|
+
exports.tokensToString = tokensToString;
|
|
24
|
+
/**
|
|
25
|
+
* Old code
|
|
26
|
+
*/
|
|
27
|
+
function parseToken(token, compact, depth) {
|
|
28
|
+
let content;
|
|
29
|
+
switch (token.type) {
|
|
30
|
+
case 'rule': {
|
|
31
|
+
return ((compact ? '' : tab.repeat(depth)) +
|
|
32
|
+
token.prop +
|
|
33
|
+
(compact ? ':' : ': ') +
|
|
34
|
+
token.value +
|
|
35
|
+
';' +
|
|
36
|
+
(compact ? '' : nl));
|
|
37
|
+
}
|
|
38
|
+
case 'at-rule': {
|
|
39
|
+
content =
|
|
40
|
+
'@' + token.atRule + joinAtValues(token.atValues, compact);
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
case 'selector': {
|
|
44
|
+
content = token.selectors.join(compact ? ',' : ', ');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const children = token.children.map((item) => {
|
|
48
|
+
return parseToken(item, compact, depth + 1);
|
|
49
|
+
});
|
|
50
|
+
return ((compact ? '' : tab.repeat(depth)) +
|
|
51
|
+
content +
|
|
52
|
+
(compact ? '{' : ' {' + nl) +
|
|
53
|
+
children.join('') +
|
|
54
|
+
(compact ? '}' : tab.repeat(depth) + '}' + nl));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Join at-rule values
|
|
58
|
+
*/
|
|
59
|
+
function joinAtValues(values, compact) {
|
|
60
|
+
return values
|
|
61
|
+
.map((item) => {
|
|
62
|
+
const value = typeof item === 'string' ? item : joinAtValues(item, compact);
|
|
63
|
+
if (value.slice(0, 1) === '(' || value.slice(-1) === ')') {
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
return '(' + value + ')';
|
|
67
|
+
})
|
|
68
|
+
.join(compact ? ',' : ', ');
|
|
69
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// src/css/parser/export.ts
|
|
2
|
+
var tab = " ";
|
|
3
|
+
var nl = "\n";
|
|
4
|
+
function tokensToString(tree) {
|
|
5
|
+
let compact = true;
|
|
6
|
+
for (let i = 0; i < tree.length; i++) {
|
|
7
|
+
if (tree[i].type !== "rule") {
|
|
8
|
+
compact = false;
|
|
9
|
+
break;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return tree.map((token) => {
|
|
13
|
+
return parseToken(token, compact, 0);
|
|
14
|
+
}).join("");
|
|
15
|
+
}
|
|
16
|
+
function parseToken(token, compact, depth) {
|
|
17
|
+
let content;
|
|
18
|
+
switch (token.type) {
|
|
19
|
+
case "rule": {
|
|
20
|
+
return (compact ? "" : tab.repeat(depth)) + token.prop + (compact ? ":" : ": ") + token.value + ";" + (compact ? "" : nl);
|
|
21
|
+
}
|
|
22
|
+
case "at-rule": {
|
|
23
|
+
content = "@" + token.atRule + joinAtValues(token.atValues, compact);
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
case "selector": {
|
|
27
|
+
content = token.selectors.join(compact ? "," : ", ");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const children = token.children.map((item) => {
|
|
31
|
+
return parseToken(item, compact, depth + 1);
|
|
32
|
+
});
|
|
33
|
+
return (compact ? "" : tab.repeat(depth)) + content + (compact ? "{" : " {" + nl) + children.join("") + (compact ? "}" : tab.repeat(depth) + "}" + nl);
|
|
34
|
+
}
|
|
35
|
+
function joinAtValues(values, compact) {
|
|
36
|
+
return values.map((item) => {
|
|
37
|
+
const value = typeof item === "string" ? item : joinAtValues(item, compact);
|
|
38
|
+
if (value.slice(0, 1) === "(" || value.slice(-1) === ")") {
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
return "(" + value + ")";
|
|
42
|
+
}).join(compact ? "," : ", ");
|
|
43
|
+
}
|
|
44
|
+
export {
|
|
45
|
+
tokensToString
|
|
46
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StyleParseError } from './error';
|
|
2
|
+
/**
|
|
3
|
+
* Find end of quoted string
|
|
4
|
+
*
|
|
5
|
+
* Returns index of character after quote
|
|
6
|
+
*/
|
|
7
|
+
export declare function findEndOfQuotedString(code: string, quote: string, start: number): number | null;
|
|
8
|
+
/**
|
|
9
|
+
* Find end of url
|
|
10
|
+
*
|
|
11
|
+
* Returns index of character after end of URL
|
|
12
|
+
*/
|
|
13
|
+
export declare function findEndOfURL(code: string, start: number): number | StyleParseError;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findEndOfURL = exports.findEndOfQuotedString = void 0;
|
|
4
|
+
const error_1 = require("./error");
|
|
5
|
+
/**
|
|
6
|
+
* Find end of quoted string
|
|
7
|
+
*
|
|
8
|
+
* Returns index of character after quote
|
|
9
|
+
*/
|
|
10
|
+
function findEndOfQuotedString(code, quote, start) {
|
|
11
|
+
let nextEscape = code.indexOf('\\', start + 1);
|
|
12
|
+
let end = code.indexOf(quote, start + 1);
|
|
13
|
+
if (end === -1) {
|
|
14
|
+
// Invalid string
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
while (nextEscape !== -1 && nextEscape < end) {
|
|
18
|
+
if (end === nextEscape + 1) {
|
|
19
|
+
end = code.indexOf(quote, end + 1);
|
|
20
|
+
if (end === -1) {
|
|
21
|
+
// Invalid string
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
nextEscape = code.indexOf('\\', nextEscape + 2);
|
|
26
|
+
}
|
|
27
|
+
return end + 1;
|
|
28
|
+
}
|
|
29
|
+
exports.findEndOfQuotedString = findEndOfQuotedString;
|
|
30
|
+
/**
|
|
31
|
+
* Find end of url
|
|
32
|
+
*
|
|
33
|
+
* Returns index of character after end of URL
|
|
34
|
+
*/
|
|
35
|
+
function findEndOfURL(code, start) {
|
|
36
|
+
let index = (start || 0) + 4;
|
|
37
|
+
const length = code.length;
|
|
38
|
+
// eslint-disable-next-line no-constant-condition
|
|
39
|
+
while (true) {
|
|
40
|
+
if (index >= length) {
|
|
41
|
+
return (0, error_1.styleParseError)('Cannot find end of URL', code, start);
|
|
42
|
+
}
|
|
43
|
+
let next = code.charAt(index);
|
|
44
|
+
switch (next) {
|
|
45
|
+
case '"':
|
|
46
|
+
case "'": {
|
|
47
|
+
// quoted url
|
|
48
|
+
let end = findEndOfQuotedString(code, next, index);
|
|
49
|
+
if (end === null) {
|
|
50
|
+
return (0, error_1.styleParseError)('Incomplete string', code, index);
|
|
51
|
+
}
|
|
52
|
+
end = code.indexOf(')', end);
|
|
53
|
+
return end === -1
|
|
54
|
+
? (0, error_1.styleParseError)('Cannot find end of URL', code, start)
|
|
55
|
+
: end + 1;
|
|
56
|
+
}
|
|
57
|
+
case ' ':
|
|
58
|
+
case '\t':
|
|
59
|
+
case '\r':
|
|
60
|
+
case '\n':
|
|
61
|
+
// skip whitespace
|
|
62
|
+
index++;
|
|
63
|
+
break;
|
|
64
|
+
default:
|
|
65
|
+
// unquoted url
|
|
66
|
+
// eslint-disable-next-line no-constant-condition
|
|
67
|
+
while (true) {
|
|
68
|
+
switch (next) {
|
|
69
|
+
case ')':
|
|
70
|
+
return index + 1;
|
|
71
|
+
case '"':
|
|
72
|
+
case "'":
|
|
73
|
+
case '(':
|
|
74
|
+
case ' ':
|
|
75
|
+
case '\t':
|
|
76
|
+
case '\r':
|
|
77
|
+
case '\n':
|
|
78
|
+
return (0, error_1.styleParseError)('Invalid URL', code, start);
|
|
79
|
+
default:
|
|
80
|
+
if (code.charCodeAt(index) < 32) {
|
|
81
|
+
return (0, error_1.styleParseError)('Invalid URL', code, start);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
index++;
|
|
85
|
+
if (index >= length) {
|
|
86
|
+
return (0, error_1.styleParseError)('Cannot find end of URL', code, start);
|
|
87
|
+
}
|
|
88
|
+
next = code.charAt(index);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.findEndOfURL = findEndOfURL;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// src/css/parser/strings.ts
|
|
2
|
+
import { styleParseError } from "./error.mjs";
|
|
3
|
+
function findEndOfQuotedString(code, quote, start) {
|
|
4
|
+
let nextEscape = code.indexOf("\\", start + 1);
|
|
5
|
+
let end = code.indexOf(quote, start + 1);
|
|
6
|
+
if (end === -1) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
while (nextEscape !== -1 && nextEscape < end) {
|
|
10
|
+
if (end === nextEscape + 1) {
|
|
11
|
+
end = code.indexOf(quote, end + 1);
|
|
12
|
+
if (end === -1) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
nextEscape = code.indexOf("\\", nextEscape + 2);
|
|
17
|
+
}
|
|
18
|
+
return end + 1;
|
|
19
|
+
}
|
|
20
|
+
function findEndOfURL(code, start) {
|
|
21
|
+
let index = (start || 0) + 4;
|
|
22
|
+
const length = code.length;
|
|
23
|
+
while (true) {
|
|
24
|
+
if (index >= length) {
|
|
25
|
+
return styleParseError("Cannot find end of URL", code, start);
|
|
26
|
+
}
|
|
27
|
+
let next = code.charAt(index);
|
|
28
|
+
switch (next) {
|
|
29
|
+
case '"':
|
|
30
|
+
case "'": {
|
|
31
|
+
let end = findEndOfQuotedString(code, next, index);
|
|
32
|
+
if (end === null) {
|
|
33
|
+
return styleParseError("Incomplete string", code, index);
|
|
34
|
+
}
|
|
35
|
+
end = code.indexOf(")", end);
|
|
36
|
+
return end === -1 ? styleParseError("Cannot find end of URL", code, start) : end + 1;
|
|
37
|
+
}
|
|
38
|
+
case " ":
|
|
39
|
+
case " ":
|
|
40
|
+
case "\r":
|
|
41
|
+
case "\n":
|
|
42
|
+
index++;
|
|
43
|
+
break;
|
|
44
|
+
default:
|
|
45
|
+
while (true) {
|
|
46
|
+
switch (next) {
|
|
47
|
+
case ")":
|
|
48
|
+
return index + 1;
|
|
49
|
+
case '"':
|
|
50
|
+
case "'":
|
|
51
|
+
case "(":
|
|
52
|
+
case " ":
|
|
53
|
+
case " ":
|
|
54
|
+
case "\r":
|
|
55
|
+
case "\n":
|
|
56
|
+
return styleParseError("Invalid URL", code, start);
|
|
57
|
+
default:
|
|
58
|
+
if (code.charCodeAt(index) < 32) {
|
|
59
|
+
return styleParseError("Invalid URL", code, start);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
index++;
|
|
63
|
+
if (index >= length) {
|
|
64
|
+
return styleParseError("Cannot find end of URL", code, start);
|
|
65
|
+
}
|
|
66
|
+
next = code.charAt(index);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
findEndOfQuotedString,
|
|
73
|
+
findEndOfURL
|
|
74
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CSSRuleToken, CSSTokenWithSelector, TextToken } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Merge text tokens to string
|
|
4
|
+
*/
|
|
5
|
+
export declare function mergeTextTokens(tokens: TextToken[]): string;
|
|
6
|
+
/**
|
|
7
|
+
* Get list of selectors from list of words
|
|
8
|
+
*/
|
|
9
|
+
export declare function getSelectors(tokens: TextToken[]): string[];
|
|
10
|
+
/**
|
|
11
|
+
* Convert text token to rule
|
|
12
|
+
*/
|
|
13
|
+
export declare function textTokensToRule(tokens: TextToken[]): CSSRuleToken | null;
|
|
14
|
+
/**
|
|
15
|
+
* Create at-rule or selector token from text tokens
|
|
16
|
+
*/
|
|
17
|
+
export declare function textTokensToSelector(tokens: TextToken[]): CSSTokenWithSelector | null;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.textTokensToSelector = exports.textTokensToRule = exports.getSelectors = exports.mergeTextTokens = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Merge text tokens to string
|
|
6
|
+
*/
|
|
7
|
+
function mergeTextTokens(tokens) {
|
|
8
|
+
return tokens
|
|
9
|
+
.map((token) => token.text)
|
|
10
|
+
.join('')
|
|
11
|
+
.trim();
|
|
12
|
+
}
|
|
13
|
+
exports.mergeTextTokens = mergeTextTokens;
|
|
14
|
+
/**
|
|
15
|
+
* Get list of selectors from list of words
|
|
16
|
+
*/
|
|
17
|
+
function getSelectors(tokens) {
|
|
18
|
+
const selectors = [];
|
|
19
|
+
let selector = '';
|
|
20
|
+
tokens.forEach((token) => {
|
|
21
|
+
if (token.type !== 'chunk') {
|
|
22
|
+
// Add entire URL or quoted string
|
|
23
|
+
selector += token.text;
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
// Split by comma
|
|
27
|
+
const list = token.text.split(',');
|
|
28
|
+
selector += list.shift();
|
|
29
|
+
while (list.length > 0) {
|
|
30
|
+
selectors.push(selector.trim());
|
|
31
|
+
selector = list.shift();
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
selectors.push(selector.trim());
|
|
35
|
+
// Filter empty entries
|
|
36
|
+
return selectors.filter((item) => item.length > 0);
|
|
37
|
+
}
|
|
38
|
+
exports.getSelectors = getSelectors;
|
|
39
|
+
/**
|
|
40
|
+
* Convert text token to rule
|
|
41
|
+
*/
|
|
42
|
+
function textTokensToRule(tokens) {
|
|
43
|
+
let prop = '';
|
|
44
|
+
let value = '';
|
|
45
|
+
let isProp = true;
|
|
46
|
+
let error = false;
|
|
47
|
+
// Merge all tokens into property and value
|
|
48
|
+
tokens.forEach((token) => {
|
|
49
|
+
if (error) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (token.type !== 'chunk') {
|
|
53
|
+
// URL or quoted string
|
|
54
|
+
if (isProp) {
|
|
55
|
+
// Cannot have URL or quoted string in property
|
|
56
|
+
error = true;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
value += token.text;
|
|
60
|
+
}
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Code token
|
|
64
|
+
const pairs = token.text.split(':');
|
|
65
|
+
if (pairs.length > 2) {
|
|
66
|
+
// Too many ':' in code
|
|
67
|
+
error = true;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (pairs.length === 2) {
|
|
71
|
+
if (!isProp) {
|
|
72
|
+
// Double ':' in code
|
|
73
|
+
error = true;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
prop += pairs[0];
|
|
77
|
+
value = pairs[1];
|
|
78
|
+
isProp = false;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// Add content to property or value
|
|
82
|
+
if (isProp) {
|
|
83
|
+
prop += token.text;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
value += token.text;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
if (error || isProp) {
|
|
90
|
+
// Error or still assembling a property
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
prop = prop.trim();
|
|
94
|
+
value = value.trim();
|
|
95
|
+
if (!prop.length || !value.length) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const result = {
|
|
99
|
+
type: 'rule',
|
|
100
|
+
prop: prop.toLowerCase(),
|
|
101
|
+
value: value,
|
|
102
|
+
index: tokens[0].index,
|
|
103
|
+
};
|
|
104
|
+
// Check for !important (with possibility to support other stuff like !default in future)
|
|
105
|
+
['important'].forEach((word) => {
|
|
106
|
+
if (result.value.slice(0 - word.length - 1).toLowerCase() ===
|
|
107
|
+
'!' + word) {
|
|
108
|
+
result[word] = true;
|
|
109
|
+
result.value = result.value
|
|
110
|
+
.slice(0, result.value.length - word.length - 1)
|
|
111
|
+
.trim();
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
// Value cannot be empty
|
|
115
|
+
return result.value.length ? result : null;
|
|
116
|
+
}
|
|
117
|
+
exports.textTokensToRule = textTokensToRule;
|
|
118
|
+
// Rules that needs extra parsing
|
|
119
|
+
const nestableAtRules = ['media', 'supports'];
|
|
120
|
+
/**
|
|
121
|
+
* Create at-rule or selector token from text tokens
|
|
122
|
+
*/
|
|
123
|
+
function textTokensToSelector(tokens) {
|
|
124
|
+
const selectors = getSelectors(tokens);
|
|
125
|
+
const code = mergeTextTokens(tokens);
|
|
126
|
+
const index = tokens[0].index;
|
|
127
|
+
if (!selectors.length) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
if (selectors[0].charAt(0) === '@') {
|
|
131
|
+
const atRule = selectors[0].split(/\s+/, 1)[0].slice(1).toLowerCase();
|
|
132
|
+
selectors[0] = selectors[0].slice(1 + atRule.length).trim();
|
|
133
|
+
const atValues = selectors;
|
|
134
|
+
// Remove parenthesis for at-rules that can be nested, such as @media
|
|
135
|
+
if (nestableAtRules.indexOf(atRule) !== -1) {
|
|
136
|
+
atValues.forEach((item, index) => {
|
|
137
|
+
if (typeof item !== 'string' ||
|
|
138
|
+
item.charAt(0) !== '(' ||
|
|
139
|
+
item.charAt(item.length - 1) !== ')') {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const list = item
|
|
143
|
+
.slice(1, item.length - 1)
|
|
144
|
+
.split(/\)\s?and\s?\(/i)
|
|
145
|
+
.map((item) => item.trim());
|
|
146
|
+
let match = true;
|
|
147
|
+
list.forEach((item) => {
|
|
148
|
+
if (item.indexOf('(') !== -1 || item.indexOf(')') !== -1) {
|
|
149
|
+
match = false;
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
if (match) {
|
|
153
|
+
atValues[index] = list;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
type: 'at-rule',
|
|
159
|
+
code,
|
|
160
|
+
index,
|
|
161
|
+
atRule,
|
|
162
|
+
atValues,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
return {
|
|
167
|
+
type: 'selector',
|
|
168
|
+
code,
|
|
169
|
+
index,
|
|
170
|
+
selectors,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
exports.textTokensToSelector = textTokensToSelector;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// src/css/parser/text.ts
|
|
2
|
+
function mergeTextTokens(tokens) {
|
|
3
|
+
return tokens.map((token) => token.text).join("").trim();
|
|
4
|
+
}
|
|
5
|
+
function getSelectors(tokens) {
|
|
6
|
+
const selectors = [];
|
|
7
|
+
let selector = "";
|
|
8
|
+
tokens.forEach((token) => {
|
|
9
|
+
if (token.type !== "chunk") {
|
|
10
|
+
selector += token.text;
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const list = token.text.split(",");
|
|
14
|
+
selector += list.shift();
|
|
15
|
+
while (list.length > 0) {
|
|
16
|
+
selectors.push(selector.trim());
|
|
17
|
+
selector = list.shift();
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
selectors.push(selector.trim());
|
|
21
|
+
return selectors.filter((item) => item.length > 0);
|
|
22
|
+
}
|
|
23
|
+
function textTokensToRule(tokens) {
|
|
24
|
+
let prop = "";
|
|
25
|
+
let value = "";
|
|
26
|
+
let isProp = true;
|
|
27
|
+
let error = false;
|
|
28
|
+
tokens.forEach((token) => {
|
|
29
|
+
if (error) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (token.type !== "chunk") {
|
|
33
|
+
if (isProp) {
|
|
34
|
+
error = true;
|
|
35
|
+
} else {
|
|
36
|
+
value += token.text;
|
|
37
|
+
}
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const pairs = token.text.split(":");
|
|
41
|
+
if (pairs.length > 2) {
|
|
42
|
+
error = true;
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (pairs.length === 2) {
|
|
46
|
+
if (!isProp) {
|
|
47
|
+
error = true;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
prop += pairs[0];
|
|
51
|
+
value = pairs[1];
|
|
52
|
+
isProp = false;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (isProp) {
|
|
56
|
+
prop += token.text;
|
|
57
|
+
} else {
|
|
58
|
+
value += token.text;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
if (error || isProp) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
prop = prop.trim();
|
|
65
|
+
value = value.trim();
|
|
66
|
+
if (!prop.length || !value.length) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
const result = {
|
|
70
|
+
type: "rule",
|
|
71
|
+
prop: prop.toLowerCase(),
|
|
72
|
+
value,
|
|
73
|
+
index: tokens[0].index
|
|
74
|
+
};
|
|
75
|
+
["important"].forEach((word) => {
|
|
76
|
+
if (result.value.slice(0 - word.length - 1).toLowerCase() === "!" + word) {
|
|
77
|
+
result[word] = true;
|
|
78
|
+
result.value = result.value.slice(0, result.value.length - word.length - 1).trim();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return result.value.length ? result : null;
|
|
82
|
+
}
|
|
83
|
+
var nestableAtRules = ["media", "supports"];
|
|
84
|
+
function textTokensToSelector(tokens) {
|
|
85
|
+
const selectors = getSelectors(tokens);
|
|
86
|
+
const code = mergeTextTokens(tokens);
|
|
87
|
+
const index = tokens[0].index;
|
|
88
|
+
if (!selectors.length) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
if (selectors[0].charAt(0) === "@") {
|
|
92
|
+
const atRule = selectors[0].split(/\s+/, 1)[0].slice(1).toLowerCase();
|
|
93
|
+
selectors[0] = selectors[0].slice(1 + atRule.length).trim();
|
|
94
|
+
const atValues = selectors;
|
|
95
|
+
if (nestableAtRules.indexOf(atRule) !== -1) {
|
|
96
|
+
atValues.forEach((item, index2) => {
|
|
97
|
+
if (typeof item !== "string" || item.charAt(0) !== "(" || item.charAt(item.length - 1) !== ")") {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const list = item.slice(1, item.length - 1).split(/\)\s?and\s?\(/i).map((item2) => item2.trim());
|
|
101
|
+
let match = true;
|
|
102
|
+
list.forEach((item2) => {
|
|
103
|
+
if (item2.indexOf("(") !== -1 || item2.indexOf(")") !== -1) {
|
|
104
|
+
match = false;
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
if (match) {
|
|
108
|
+
atValues[index2] = list;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
type: "at-rule",
|
|
114
|
+
code,
|
|
115
|
+
index,
|
|
116
|
+
atRule,
|
|
117
|
+
atValues
|
|
118
|
+
};
|
|
119
|
+
} else {
|
|
120
|
+
return {
|
|
121
|
+
type: "selector",
|
|
122
|
+
code,
|
|
123
|
+
index,
|
|
124
|
+
selectors
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
export {
|
|
129
|
+
getSelectors,
|
|
130
|
+
mergeTextTokens,
|
|
131
|
+
textTokensToRule,
|
|
132
|
+
textTokensToSelector
|
|
133
|
+
};
|