@eslint/css-tree 3.2.0
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/LICENSE +20 -0
- package/README.md +194 -0
- package/cjs/convertor/create.cjs +32 -0
- package/cjs/convertor/index.cjs +8 -0
- package/cjs/data-patch.cjs +7 -0
- package/cjs/data.cjs +120 -0
- package/cjs/definition-syntax/SyntaxError.cjs +16 -0
- package/cjs/definition-syntax/generate.cjs +139 -0
- package/cjs/definition-syntax/index.cjs +13 -0
- package/cjs/definition-syntax/parse.cjs +556 -0
- package/cjs/definition-syntax/scanner.cjs +113 -0
- package/cjs/definition-syntax/walk.cjs +57 -0
- package/cjs/generator/create.cjs +102 -0
- package/cjs/generator/index.cjs +8 -0
- package/cjs/generator/sourceMap.cjs +96 -0
- package/cjs/generator/token-before.cjs +170 -0
- package/cjs/index.cjs +65 -0
- package/cjs/lexer/Lexer.cjs +517 -0
- package/cjs/lexer/error.cjs +128 -0
- package/cjs/lexer/generic-an-plus-b.cjs +235 -0
- package/cjs/lexer/generic-const.cjs +12 -0
- package/cjs/lexer/generic-urange.cjs +149 -0
- package/cjs/lexer/generic.cjs +589 -0
- package/cjs/lexer/index.cjs +7 -0
- package/cjs/lexer/match-graph.cjs +530 -0
- package/cjs/lexer/match.cjs +632 -0
- package/cjs/lexer/prepare-tokens.cjs +54 -0
- package/cjs/lexer/search.cjs +65 -0
- package/cjs/lexer/structure.cjs +173 -0
- package/cjs/lexer/trace.cjs +73 -0
- package/cjs/lexer/units.cjs +38 -0
- package/cjs/parser/SyntaxError.cjs +74 -0
- package/cjs/parser/create.cjs +378 -0
- package/cjs/parser/index.cjs +8 -0
- package/cjs/parser/parse-selector.cjs +8 -0
- package/cjs/parser/sequence.cjs +47 -0
- package/cjs/syntax/atrule/container.cjs +32 -0
- package/cjs/syntax/atrule/font-face.cjs +12 -0
- package/cjs/syntax/atrule/import.cjs +101 -0
- package/cjs/syntax/atrule/index.cjs +27 -0
- package/cjs/syntax/atrule/layer.cjs +16 -0
- package/cjs/syntax/atrule/media.cjs +16 -0
- package/cjs/syntax/atrule/nest.cjs +16 -0
- package/cjs/syntax/atrule/page.cjs +16 -0
- package/cjs/syntax/atrule/scope.cjs +16 -0
- package/cjs/syntax/atrule/starting-style.cjs +12 -0
- package/cjs/syntax/atrule/supports.cjs +16 -0
- package/cjs/syntax/config/generator.cjs +9 -0
- package/cjs/syntax/config/lexer.cjs +14 -0
- package/cjs/syntax/config/mix.cjs +126 -0
- package/cjs/syntax/config/parser-selector.cjs +19 -0
- package/cjs/syntax/config/parser.cjs +49 -0
- package/cjs/syntax/config/walker.cjs +9 -0
- package/cjs/syntax/create.cjs +58 -0
- package/cjs/syntax/function/expression.cjs +11 -0
- package/cjs/syntax/function/var.cjs +43 -0
- package/cjs/syntax/index.cjs +14 -0
- package/cjs/syntax/node/AnPlusB.cjs +293 -0
- package/cjs/syntax/node/Atrule.cjs +103 -0
- package/cjs/syntax/node/AtrulePrelude.cjs +52 -0
- package/cjs/syntax/node/AttributeSelector.cjs +148 -0
- package/cjs/syntax/node/Block.cjs +96 -0
- package/cjs/syntax/node/Brackets.cjs +38 -0
- package/cjs/syntax/node/CDC.cjs +26 -0
- package/cjs/syntax/node/CDO.cjs +26 -0
- package/cjs/syntax/node/ClassSelector.cjs +31 -0
- package/cjs/syntax/node/Combinator.cjs +61 -0
- package/cjs/syntax/node/Comment.cjs +40 -0
- package/cjs/syntax/node/Condition.cjs +120 -0
- package/cjs/syntax/node/Declaration.cjs +166 -0
- package/cjs/syntax/node/DeclarationList.cjs +62 -0
- package/cjs/syntax/node/Dimension.cjs +30 -0
- package/cjs/syntax/node/Feature.cjs +101 -0
- package/cjs/syntax/node/FeatureFunction.cjs +67 -0
- package/cjs/syntax/node/FeatureRange.cjs +133 -0
- package/cjs/syntax/node/Function.cjs +45 -0
- package/cjs/syntax/node/GeneralEnclosed.cjs +68 -0
- package/cjs/syntax/node/Hash.cjs +30 -0
- package/cjs/syntax/node/IdSelector.cjs +33 -0
- package/cjs/syntax/node/Identifier.cjs +25 -0
- package/cjs/syntax/node/Layer.cjs +35 -0
- package/cjs/syntax/node/LayerList.cjs +43 -0
- package/cjs/syntax/node/MediaQuery.cjs +100 -0
- package/cjs/syntax/node/MediaQueryList.cjs +41 -0
- package/cjs/syntax/node/NestingSelector.cjs +29 -0
- package/cjs/syntax/node/Nth.cjs +54 -0
- package/cjs/syntax/node/Number.cjs +25 -0
- package/cjs/syntax/node/Operator.cjs +28 -0
- package/cjs/syntax/node/Parentheses.cjs +38 -0
- package/cjs/syntax/node/Percentage.cjs +25 -0
- package/cjs/syntax/node/PseudoClassSelector.cjs +67 -0
- package/cjs/syntax/node/PseudoElementSelector.cjs +69 -0
- package/cjs/syntax/node/Ratio.cjs +71 -0
- package/cjs/syntax/node/Raw.cjs +48 -0
- package/cjs/syntax/node/Rule.cjs +58 -0
- package/cjs/syntax/node/Scope.cjs +69 -0
- package/cjs/syntax/node/Selector.cjs +38 -0
- package/cjs/syntax/node/SelectorList.cjs +43 -0
- package/cjs/syntax/node/String.cjs +26 -0
- package/cjs/syntax/node/StyleSheet.cjs +83 -0
- package/cjs/syntax/node/SupportsDeclaration.cjs +38 -0
- package/cjs/syntax/node/TypeSelector.cjs +59 -0
- package/cjs/syntax/node/UnicodeRange.cjs +158 -0
- package/cjs/syntax/node/Url.cjs +54 -0
- package/cjs/syntax/node/Value.cjs +26 -0
- package/cjs/syntax/node/WhiteSpace.cjs +34 -0
- package/cjs/syntax/node/index-generate.cjs +103 -0
- package/cjs/syntax/node/index-parse-selector.cjs +39 -0
- package/cjs/syntax/node/index-parse.cjs +103 -0
- package/cjs/syntax/node/index.cjs +103 -0
- package/cjs/syntax/pseudo/index.cjs +60 -0
- package/cjs/syntax/pseudo/lang.cjs +37 -0
- package/cjs/syntax/scope/atrulePrelude.cjs +9 -0
- package/cjs/syntax/scope/default.cjs +76 -0
- package/cjs/syntax/scope/index.cjs +11 -0
- package/cjs/syntax/scope/selector.cjs +88 -0
- package/cjs/syntax/scope/value.cjs +29 -0
- package/cjs/tokenizer/OffsetToLocation.cjs +91 -0
- package/cjs/tokenizer/TokenStream.cjs +358 -0
- package/cjs/tokenizer/adopt-buffer.cjs +13 -0
- package/cjs/tokenizer/char-code-definitions.cjs +236 -0
- package/cjs/tokenizer/index.cjs +554 -0
- package/cjs/tokenizer/names.cjs +32 -0
- package/cjs/tokenizer/types.cjs +57 -0
- package/cjs/tokenizer/utils.cjs +261 -0
- package/cjs/utils/List.cjs +473 -0
- package/cjs/utils/clone.cjs +25 -0
- package/cjs/utils/create-custom-error.cjs +18 -0
- package/cjs/utils/ident.cjs +102 -0
- package/cjs/utils/index.cjs +20 -0
- package/cjs/utils/names.cjs +113 -0
- package/cjs/utils/string.cjs +99 -0
- package/cjs/utils/url.cjs +108 -0
- package/cjs/version.cjs +5 -0
- package/cjs/walker/create.cjs +291 -0
- package/cjs/walker/index.cjs +8 -0
- package/data/patch.json +874 -0
- package/dist/csstree.esm.js +12 -0
- package/dist/csstree.js +12 -0
- package/dist/data.cjs +1341 -0
- package/dist/data.js +1341 -0
- package/dist/version.cjs +1 -0
- package/dist/version.js +1 -0
- package/lib/convertor/create.js +28 -0
- package/lib/convertor/index.js +4 -0
- package/lib/data-patch.js +6 -0
- package/lib/data.js +118 -0
- package/lib/definition-syntax/SyntaxError.js +12 -0
- package/lib/definition-syntax/generate.js +135 -0
- package/lib/definition-syntax/index.js +4 -0
- package/lib/definition-syntax/parse.js +552 -0
- package/lib/definition-syntax/scanner.js +109 -0
- package/lib/definition-syntax/walk.js +53 -0
- package/lib/generator/create.js +97 -0
- package/lib/generator/index.js +4 -0
- package/lib/generator/sourceMap.js +92 -0
- package/lib/generator/token-before.js +182 -0
- package/lib/index.d.ts +3016 -0
- package/lib/index.js +30 -0
- package/lib/lexer/Lexer.js +511 -0
- package/lib/lexer/error.js +123 -0
- package/lib/lexer/generic-an-plus-b.js +238 -0
- package/lib/lexer/generic-const.js +8 -0
- package/lib/lexer/generic-urange.js +151 -0
- package/lib/lexer/generic.js +622 -0
- package/lib/lexer/index.js +1 -0
- package/lib/lexer/match-graph.js +527 -0
- package/lib/lexer/match.js +630 -0
- package/lib/lexer/prepare-tokens.js +50 -0
- package/lib/lexer/search.js +61 -0
- package/lib/lexer/structure.js +169 -0
- package/lib/lexer/trace.js +66 -0
- package/lib/lexer/units.js +27 -0
- package/lib/parser/SyntaxError.js +70 -0
- package/lib/parser/create.js +388 -0
- package/lib/parser/index.js +4 -0
- package/lib/parser/parse-selector.js +4 -0
- package/lib/parser/sequence.js +43 -0
- package/lib/syntax/atrule/container.js +28 -0
- package/lib/syntax/atrule/font-face.js +8 -0
- package/lib/syntax/atrule/import.js +104 -0
- package/lib/syntax/atrule/index.js +23 -0
- package/lib/syntax/atrule/layer.js +12 -0
- package/lib/syntax/atrule/media.js +12 -0
- package/lib/syntax/atrule/nest.js +12 -0
- package/lib/syntax/atrule/page.js +12 -0
- package/lib/syntax/atrule/scope.js +12 -0
- package/lib/syntax/atrule/starting-style.js +8 -0
- package/lib/syntax/atrule/supports.js +12 -0
- package/lib/syntax/config/generator.js +5 -0
- package/lib/syntax/config/lexer.js +10 -0
- package/lib/syntax/config/mix.js +122 -0
- package/lib/syntax/config/parser-selector.js +15 -0
- package/lib/syntax/config/parser.js +45 -0
- package/lib/syntax/config/walker.js +5 -0
- package/lib/syntax/create.js +55 -0
- package/lib/syntax/function/expression.js +7 -0
- package/lib/syntax/function/var.js +39 -0
- package/lib/syntax/index.js +10 -0
- package/lib/syntax/node/AnPlusB.js +292 -0
- package/lib/syntax/node/Atrule.js +100 -0
- package/lib/syntax/node/AtrulePrelude.js +47 -0
- package/lib/syntax/node/AttributeSelector.js +147 -0
- package/lib/syntax/node/Block.js +95 -0
- package/lib/syntax/node/Brackets.js +35 -0
- package/lib/syntax/node/CDC.js +19 -0
- package/lib/syntax/node/CDO.js +19 -0
- package/lib/syntax/node/ClassSelector.js +24 -0
- package/lib/syntax/node/Combinator.js +54 -0
- package/lib/syntax/node/Comment.js +33 -0
- package/lib/syntax/node/Condition.js +123 -0
- package/lib/syntax/node/Declaration.js +165 -0
- package/lib/syntax/node/DeclarationList.js +62 -0
- package/lib/syntax/node/Dimension.js +23 -0
- package/lib/syntax/node/Feature.js +103 -0
- package/lib/syntax/node/FeatureFunction.js +63 -0
- package/lib/syntax/node/FeatureRange.js +133 -0
- package/lib/syntax/node/Function.js +41 -0
- package/lib/syntax/node/GeneralEnclosed.js +66 -0
- package/lib/syntax/node/Hash.js +23 -0
- package/lib/syntax/node/IdSelector.js +26 -0
- package/lib/syntax/node/Identifier.js +18 -0
- package/lib/syntax/node/Layer.js +28 -0
- package/lib/syntax/node/LayerList.js +36 -0
- package/lib/syntax/node/MediaQuery.js +102 -0
- package/lib/syntax/node/MediaQueryList.js +34 -0
- package/lib/syntax/node/NestingSelector.js +22 -0
- package/lib/syntax/node/Nth.js +47 -0
- package/lib/syntax/node/Number.js +18 -0
- package/lib/syntax/node/Operator.js +21 -0
- package/lib/syntax/node/Parentheses.js +34 -0
- package/lib/syntax/node/Percentage.js +18 -0
- package/lib/syntax/node/PseudoClassSelector.js +65 -0
- package/lib/syntax/node/PseudoElementSelector.js +66 -0
- package/lib/syntax/node/Ratio.js +68 -0
- package/lib/syntax/node/Raw.js +41 -0
- package/lib/syntax/node/Rule.js +51 -0
- package/lib/syntax/node/Scope.js +66 -0
- package/lib/syntax/node/Selector.js +31 -0
- package/lib/syntax/node/SelectorList.js +35 -0
- package/lib/syntax/node/String.js +19 -0
- package/lib/syntax/node/StyleSheet.js +82 -0
- package/lib/syntax/node/SupportsDeclaration.js +34 -0
- package/lib/syntax/node/TypeSelector.js +52 -0
- package/lib/syntax/node/UnicodeRange.js +156 -0
- package/lib/syntax/node/Url.js +52 -0
- package/lib/syntax/node/Value.js +19 -0
- package/lib/syntax/node/WhiteSpace.js +27 -0
- package/lib/syntax/node/index-generate.js +49 -0
- package/lib/syntax/node/index-parse-selector.js +17 -0
- package/lib/syntax/node/index-parse.js +49 -0
- package/lib/syntax/node/index.js +49 -0
- package/lib/syntax/pseudo/index.js +56 -0
- package/lib/syntax/pseudo/lang.js +33 -0
- package/lib/syntax/scope/atrulePrelude.js +5 -0
- package/lib/syntax/scope/default.js +85 -0
- package/lib/syntax/scope/index.js +3 -0
- package/lib/syntax/scope/selector.js +94 -0
- package/lib/syntax/scope/value.js +25 -0
- package/lib/tokenizer/OffsetToLocation.js +87 -0
- package/lib/tokenizer/TokenStream.js +366 -0
- package/lib/tokenizer/adopt-buffer.js +9 -0
- package/lib/tokenizer/char-code-definitions.js +212 -0
- package/lib/tokenizer/index.js +513 -0
- package/lib/tokenizer/names.js +28 -0
- package/lib/tokenizer/types.js +28 -0
- package/lib/tokenizer/utils.js +254 -0
- package/lib/utils/List.js +469 -0
- package/lib/utils/clone.js +21 -0
- package/lib/utils/create-custom-error.js +14 -0
- package/lib/utils/ident.js +101 -0
- package/lib/utils/index.js +6 -0
- package/lib/utils/names.js +106 -0
- package/lib/utils/string.js +99 -0
- package/lib/utils/url.js +108 -0
- package/lib/version.js +5 -0
- package/lib/walker/create.js +287 -0
- package/lib/walker/index.js +4 -0
- package/package.json +133 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { List } from './List.js';
|
|
2
|
+
|
|
3
|
+
export function clone(node) {
|
|
4
|
+
const result = {};
|
|
5
|
+
|
|
6
|
+
for (const key of Object.keys(node)) {
|
|
7
|
+
let value = node[key];
|
|
8
|
+
|
|
9
|
+
if (value) {
|
|
10
|
+
if (Array.isArray(value) || value instanceof List) {
|
|
11
|
+
value = value.map(clone);
|
|
12
|
+
} else if (value.constructor === Object) {
|
|
13
|
+
value = clone(value);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
result[key] = value;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function createCustomError(name, message) {
|
|
2
|
+
// use Object.create(), because some VMs prevent setting line/column otherwise
|
|
3
|
+
// (iOS Safari 10 even throws an exception)
|
|
4
|
+
const error = Object.create(SyntaxError.prototype);
|
|
5
|
+
const errorStack = new Error();
|
|
6
|
+
|
|
7
|
+
return Object.assign(error, {
|
|
8
|
+
name,
|
|
9
|
+
message,
|
|
10
|
+
get stack() {
|
|
11
|
+
return (errorStack.stack || '').replace(/^(.+\n){1,3}/, `${name}: ${message}\n`);
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isName,
|
|
3
|
+
isValidEscape,
|
|
4
|
+
consumeEscaped,
|
|
5
|
+
decodeEscaped
|
|
6
|
+
} from '../tokenizer/index.js';
|
|
7
|
+
|
|
8
|
+
const REVERSE_SOLIDUS = 0x005c; // U+005C REVERSE SOLIDUS (\)
|
|
9
|
+
|
|
10
|
+
export function decode(str) {
|
|
11
|
+
const end = str.length - 1;
|
|
12
|
+
let decoded = '';
|
|
13
|
+
|
|
14
|
+
for (let i = 0; i < str.length; i++) {
|
|
15
|
+
let code = str.charCodeAt(i);
|
|
16
|
+
|
|
17
|
+
if (code === REVERSE_SOLIDUS) {
|
|
18
|
+
// special case at the ending
|
|
19
|
+
if (i === end) {
|
|
20
|
+
// if the next input code point is EOF, do nothing
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
code = str.charCodeAt(++i);
|
|
25
|
+
|
|
26
|
+
// consume escaped
|
|
27
|
+
if (isValidEscape(REVERSE_SOLIDUS, code)) {
|
|
28
|
+
const escapeStart = i - 1;
|
|
29
|
+
const escapeEnd = consumeEscaped(str, escapeStart);
|
|
30
|
+
|
|
31
|
+
i = escapeEnd - 1;
|
|
32
|
+
decoded += decodeEscaped(str.substring(escapeStart + 1, escapeEnd));
|
|
33
|
+
} else {
|
|
34
|
+
// \r\n
|
|
35
|
+
if (code === 0x000d && str.charCodeAt(i + 1) === 0x000a) {
|
|
36
|
+
i++;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
decoded += str[i];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return decoded;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// https://drafts.csswg.org/cssom/#serialize-an-identifier
|
|
48
|
+
// § 2.1. Common Serializing Idioms
|
|
49
|
+
export function encode(str) {
|
|
50
|
+
let encoded = '';
|
|
51
|
+
|
|
52
|
+
// If the character is the first character and is a "-" (U+002D),
|
|
53
|
+
// and there is no second character, then the escaped character.
|
|
54
|
+
// Note: That's means a single dash string "-" return as escaped dash,
|
|
55
|
+
// so move the condition out of the main loop
|
|
56
|
+
if (str.length === 1 && str.charCodeAt(0) === 0x002D) {
|
|
57
|
+
return '\\-';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// To serialize an identifier means to create a string represented
|
|
61
|
+
// by the concatenation of, for each character of the identifier:
|
|
62
|
+
for (let i = 0; i < str.length; i++) {
|
|
63
|
+
const code = str.charCodeAt(i);
|
|
64
|
+
|
|
65
|
+
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER (U+FFFD).
|
|
66
|
+
if (code === 0x0000) {
|
|
67
|
+
encoded += '\uFFFD';
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (
|
|
72
|
+
// If the character is in the range [\1-\1f] (U+0001 to U+001F) or is U+007F ...
|
|
73
|
+
// Note: Do not compare with 0x0001 since 0x0000 is precessed before
|
|
74
|
+
code <= 0x001F || code === 0x007F ||
|
|
75
|
+
// [or] ... is in the range [0-9] (U+0030 to U+0039),
|
|
76
|
+
(code >= 0x0030 && code <= 0x0039 && (
|
|
77
|
+
// If the character is the first character ...
|
|
78
|
+
i === 0 ||
|
|
79
|
+
// If the character is the second character ... and the first character is a "-" (U+002D)
|
|
80
|
+
i === 1 && str.charCodeAt(0) === 0x002D
|
|
81
|
+
))
|
|
82
|
+
) {
|
|
83
|
+
// ... then the character escaped as code point.
|
|
84
|
+
encoded += '\\' + code.toString(16) + ' ';
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// If the character is not handled by one of the above rules and is greater
|
|
89
|
+
// than or equal to U+0080, is "-" (U+002D) or "_" (U+005F), or is in one
|
|
90
|
+
// of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to U+005A),
|
|
91
|
+
// or \[a-z] (U+0061 to U+007A), then the character itself.
|
|
92
|
+
if (isName(code)) {
|
|
93
|
+
encoded += str.charAt(i);
|
|
94
|
+
} else {
|
|
95
|
+
// Otherwise, the escaped character.
|
|
96
|
+
encoded += '\\' + str.charAt(i);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return encoded;
|
|
101
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
const keywords = new Map();
|
|
2
|
+
const properties = new Map();
|
|
3
|
+
const HYPHENMINUS = 45; // '-'.charCodeAt()
|
|
4
|
+
|
|
5
|
+
export const keyword = getKeywordDescriptor;
|
|
6
|
+
export const property = getPropertyDescriptor;
|
|
7
|
+
export const vendorPrefix = getVendorPrefix;
|
|
8
|
+
export function isCustomProperty(str, offset) {
|
|
9
|
+
offset = offset || 0;
|
|
10
|
+
|
|
11
|
+
return str.length - offset >= 2 &&
|
|
12
|
+
str.charCodeAt(offset) === HYPHENMINUS &&
|
|
13
|
+
str.charCodeAt(offset + 1) === HYPHENMINUS;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getVendorPrefix(str, offset) {
|
|
17
|
+
offset = offset || 0;
|
|
18
|
+
|
|
19
|
+
// verdor prefix should be at least 3 chars length
|
|
20
|
+
if (str.length - offset >= 3) {
|
|
21
|
+
// vendor prefix starts with hyper minus following non-hyper minus
|
|
22
|
+
if (str.charCodeAt(offset) === HYPHENMINUS &&
|
|
23
|
+
str.charCodeAt(offset + 1) !== HYPHENMINUS) {
|
|
24
|
+
// vendor prefix should contain a hyper minus at the ending
|
|
25
|
+
const secondDashIndex = str.indexOf('-', offset + 2);
|
|
26
|
+
|
|
27
|
+
if (secondDashIndex !== -1) {
|
|
28
|
+
return str.substring(offset, secondDashIndex + 1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return '';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getKeywordDescriptor(keyword) {
|
|
37
|
+
if (keywords.has(keyword)) {
|
|
38
|
+
return keywords.get(keyword);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const name = keyword.toLowerCase();
|
|
42
|
+
let descriptor = keywords.get(name);
|
|
43
|
+
|
|
44
|
+
if (descriptor === undefined) {
|
|
45
|
+
const custom = isCustomProperty(name, 0);
|
|
46
|
+
const vendor = !custom ? getVendorPrefix(name, 0) : '';
|
|
47
|
+
descriptor = Object.freeze({
|
|
48
|
+
basename: name.substr(vendor.length),
|
|
49
|
+
name,
|
|
50
|
+
prefix: vendor,
|
|
51
|
+
vendor,
|
|
52
|
+
custom
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
keywords.set(keyword, descriptor);
|
|
57
|
+
|
|
58
|
+
return descriptor;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getPropertyDescriptor(property) {
|
|
62
|
+
if (properties.has(property)) {
|
|
63
|
+
return properties.get(property);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let name = property;
|
|
67
|
+
let hack = property[0];
|
|
68
|
+
|
|
69
|
+
if (hack === '/') {
|
|
70
|
+
hack = property[1] === '/' ? '//' : '/';
|
|
71
|
+
} else if (hack !== '_' &&
|
|
72
|
+
hack !== '*' &&
|
|
73
|
+
hack !== '$' &&
|
|
74
|
+
hack !== '#' &&
|
|
75
|
+
hack !== '+' &&
|
|
76
|
+
hack !== '&') {
|
|
77
|
+
hack = '';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const custom = isCustomProperty(name, hack.length);
|
|
81
|
+
|
|
82
|
+
// re-use result when possible (the same as for lower case)
|
|
83
|
+
if (!custom) {
|
|
84
|
+
name = name.toLowerCase();
|
|
85
|
+
if (properties.has(name)) {
|
|
86
|
+
const descriptor = properties.get(name);
|
|
87
|
+
properties.set(property, descriptor);
|
|
88
|
+
return descriptor;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const vendor = !custom ? getVendorPrefix(name, hack.length) : '';
|
|
93
|
+
const prefix = name.substr(0, hack.length + vendor.length);
|
|
94
|
+
const descriptor = Object.freeze({
|
|
95
|
+
basename: name.substr(prefix.length),
|
|
96
|
+
name: name.substr(hack.length),
|
|
97
|
+
hack,
|
|
98
|
+
vendor,
|
|
99
|
+
prefix,
|
|
100
|
+
custom
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
properties.set(property, descriptor);
|
|
104
|
+
|
|
105
|
+
return descriptor;
|
|
106
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isHexDigit,
|
|
3
|
+
isWhiteSpace,
|
|
4
|
+
isValidEscape,
|
|
5
|
+
consumeEscaped,
|
|
6
|
+
decodeEscaped
|
|
7
|
+
} from '../tokenizer/index.js';
|
|
8
|
+
|
|
9
|
+
const REVERSE_SOLIDUS = 0x005c; // U+005C REVERSE SOLIDUS (\)
|
|
10
|
+
const QUOTATION_MARK = 0x0022; // "
|
|
11
|
+
const APOSTROPHE = 0x0027; // '
|
|
12
|
+
|
|
13
|
+
export function decode(str) {
|
|
14
|
+
const len = str.length;
|
|
15
|
+
const firstChar = str.charCodeAt(0);
|
|
16
|
+
const start = firstChar === QUOTATION_MARK || firstChar === APOSTROPHE ? 1 : 0;
|
|
17
|
+
const end = start === 1 && len > 1 && str.charCodeAt(len - 1) === firstChar ? len - 2 : len - 1;
|
|
18
|
+
let decoded = '';
|
|
19
|
+
|
|
20
|
+
for (let i = start; i <= end; i++) {
|
|
21
|
+
let code = str.charCodeAt(i);
|
|
22
|
+
|
|
23
|
+
if (code === REVERSE_SOLIDUS) {
|
|
24
|
+
// special case at the ending
|
|
25
|
+
if (i === end) {
|
|
26
|
+
// if the next input code point is EOF, do nothing
|
|
27
|
+
// otherwise include last quote as escaped
|
|
28
|
+
if (i !== len - 1) {
|
|
29
|
+
decoded = str.substr(i + 1);
|
|
30
|
+
}
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
code = str.charCodeAt(++i);
|
|
35
|
+
|
|
36
|
+
// consume escaped
|
|
37
|
+
if (isValidEscape(REVERSE_SOLIDUS, code)) {
|
|
38
|
+
const escapeStart = i - 1;
|
|
39
|
+
const escapeEnd = consumeEscaped(str, escapeStart);
|
|
40
|
+
|
|
41
|
+
i = escapeEnd - 1;
|
|
42
|
+
decoded += decodeEscaped(str.substring(escapeStart + 1, escapeEnd));
|
|
43
|
+
} else {
|
|
44
|
+
// \r\n
|
|
45
|
+
if (code === 0x000d && str.charCodeAt(i + 1) === 0x000a) {
|
|
46
|
+
i++;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
decoded += str[i];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return decoded;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// https://drafts.csswg.org/cssom/#serialize-a-string
|
|
58
|
+
// § 2.1. Common Serializing Idioms
|
|
59
|
+
export function encode(str, apostrophe) {
|
|
60
|
+
const quote = apostrophe ? '\'' : '"';
|
|
61
|
+
const quoteCode = apostrophe ? APOSTROPHE : QUOTATION_MARK;
|
|
62
|
+
let encoded = '';
|
|
63
|
+
let wsBeforeHexIsNeeded = false;
|
|
64
|
+
|
|
65
|
+
for (let i = 0; i < str.length; i++) {
|
|
66
|
+
const code = str.charCodeAt(i);
|
|
67
|
+
|
|
68
|
+
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER (U+FFFD).
|
|
69
|
+
if (code === 0x0000) {
|
|
70
|
+
encoded += '\uFFFD';
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// If the character is in the range [\1-\1f] (U+0001 to U+001F) or is U+007F,
|
|
75
|
+
// the character escaped as code point.
|
|
76
|
+
// Note: Do not compare with 0x0001 since 0x0000 is precessed before
|
|
77
|
+
if (code <= 0x001f || code === 0x007F) {
|
|
78
|
+
encoded += '\\' + code.toString(16);
|
|
79
|
+
wsBeforeHexIsNeeded = true;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// If the character is '"' (U+0022) or "\" (U+005C), the escaped character.
|
|
84
|
+
if (code === quoteCode || code === REVERSE_SOLIDUS) {
|
|
85
|
+
encoded += '\\' + str.charAt(i);
|
|
86
|
+
wsBeforeHexIsNeeded = false;
|
|
87
|
+
} else {
|
|
88
|
+
if (wsBeforeHexIsNeeded && (isHexDigit(code) || isWhiteSpace(code))) {
|
|
89
|
+
encoded += ' ';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Otherwise, the character itself.
|
|
93
|
+
encoded += str.charAt(i);
|
|
94
|
+
wsBeforeHexIsNeeded = false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return quote + encoded + quote;
|
|
99
|
+
}
|
package/lib/utils/url.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isHexDigit,
|
|
3
|
+
isWhiteSpace,
|
|
4
|
+
isValidEscape,
|
|
5
|
+
consumeEscaped,
|
|
6
|
+
decodeEscaped
|
|
7
|
+
} from '../tokenizer/index.js';
|
|
8
|
+
|
|
9
|
+
const SPACE = 0x0020; // U+0020 SPACE
|
|
10
|
+
const REVERSE_SOLIDUS = 0x005c; // U+005C REVERSE SOLIDUS (\)
|
|
11
|
+
const QUOTATION_MARK = 0x0022; // "
|
|
12
|
+
const APOSTROPHE = 0x0027; // '
|
|
13
|
+
const LEFTPARENTHESIS = 0x0028; // U+0028 LEFT PARENTHESIS (()
|
|
14
|
+
const RIGHTPARENTHESIS = 0x0029; // U+0029 RIGHT PARENTHESIS ())
|
|
15
|
+
|
|
16
|
+
export function decode(str) {
|
|
17
|
+
const len = str.length;
|
|
18
|
+
let start = 4; // length of "url("
|
|
19
|
+
let end = str.charCodeAt(len - 1) === RIGHTPARENTHESIS ? len - 2 : len - 1;
|
|
20
|
+
let decoded = '';
|
|
21
|
+
|
|
22
|
+
while (start < end && isWhiteSpace(str.charCodeAt(start))) {
|
|
23
|
+
start++;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
while (start < end && isWhiteSpace(str.charCodeAt(end))) {
|
|
27
|
+
end--;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (let i = start; i <= end; i++) {
|
|
31
|
+
let code = str.charCodeAt(i);
|
|
32
|
+
|
|
33
|
+
if (code === REVERSE_SOLIDUS) {
|
|
34
|
+
// special case at the ending
|
|
35
|
+
if (i === end) {
|
|
36
|
+
// if the next input code point is EOF, do nothing
|
|
37
|
+
// otherwise include last left parenthesis as escaped
|
|
38
|
+
if (i !== len - 1) {
|
|
39
|
+
decoded = str.substr(i + 1);
|
|
40
|
+
}
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
code = str.charCodeAt(++i);
|
|
45
|
+
|
|
46
|
+
// consume escaped
|
|
47
|
+
if (isValidEscape(REVERSE_SOLIDUS, code)) {
|
|
48
|
+
const escapeStart = i - 1;
|
|
49
|
+
const escapeEnd = consumeEscaped(str, escapeStart);
|
|
50
|
+
|
|
51
|
+
i = escapeEnd - 1;
|
|
52
|
+
decoded += decodeEscaped(str.substring(escapeStart + 1, escapeEnd));
|
|
53
|
+
} else {
|
|
54
|
+
// \r\n
|
|
55
|
+
if (code === 0x000d && str.charCodeAt(i + 1) === 0x000a) {
|
|
56
|
+
i++;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
decoded += str[i];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return decoded;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function encode(str) {
|
|
68
|
+
let encoded = '';
|
|
69
|
+
let wsBeforeHexIsNeeded = false;
|
|
70
|
+
|
|
71
|
+
for (let i = 0; i < str.length; i++) {
|
|
72
|
+
const code = str.charCodeAt(i);
|
|
73
|
+
|
|
74
|
+
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER (U+FFFD).
|
|
75
|
+
if (code === 0x0000) {
|
|
76
|
+
encoded += '\uFFFD';
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// If the character is in the range [\1-\1f] (U+0001 to U+001F) or is U+007F,
|
|
81
|
+
// the character escaped as code point.
|
|
82
|
+
// Note: Do not compare with 0x0001 since 0x0000 is precessed before
|
|
83
|
+
if (code <= 0x001f || code === 0x007F) {
|
|
84
|
+
encoded += '\\' + code.toString(16);
|
|
85
|
+
wsBeforeHexIsNeeded = true;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (code === SPACE ||
|
|
90
|
+
code === REVERSE_SOLIDUS ||
|
|
91
|
+
code === QUOTATION_MARK ||
|
|
92
|
+
code === APOSTROPHE ||
|
|
93
|
+
code === LEFTPARENTHESIS ||
|
|
94
|
+
code === RIGHTPARENTHESIS) {
|
|
95
|
+
encoded += '\\' + str.charAt(i);
|
|
96
|
+
wsBeforeHexIsNeeded = false;
|
|
97
|
+
} else {
|
|
98
|
+
if (wsBeforeHexIsNeeded && isHexDigit(code)) {
|
|
99
|
+
encoded += ' ';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
encoded += str.charAt(i);
|
|
103
|
+
wsBeforeHexIsNeeded = false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return 'url(' + encoded + ')';
|
|
108
|
+
}
|