@tbela99/css-parser 1.3.3 → 1.4.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/CHANGELOG.md +44 -0
- package/README.md +64 -48
- package/dist/config.json.js +3 -0
- package/dist/index-umd-web.js +2266 -631
- package/dist/index.cjs +2271 -620
- package/dist/index.d.ts +522 -181
- package/dist/lib/ast/expand.js +5 -10
- package/dist/lib/ast/features/calc.js +3 -2
- package/dist/lib/ast/features/inlinecssvariables.js +5 -3
- package/dist/lib/ast/features/prefix.js +1 -1
- package/dist/lib/ast/features/shorthand.js +1 -0
- package/dist/lib/ast/features/transform.js +13 -19
- package/dist/lib/ast/features/type.js +1 -1
- package/dist/lib/ast/minify.js +6 -3
- package/dist/lib/ast/transform/compute.js +2 -4
- package/dist/lib/ast/transform/matrix.js +20 -20
- package/dist/lib/ast/transform/minify.js +105 -12
- package/dist/lib/ast/transform/rotate.js +11 -11
- package/dist/lib/ast/transform/scale.js +6 -6
- package/dist/lib/ast/transform/skew.js +4 -4
- package/dist/lib/ast/transform/translate.js +3 -3
- package/dist/lib/ast/transform/utils.js +30 -37
- package/dist/lib/ast/types.js +76 -5
- package/dist/lib/ast/walk.js +77 -58
- package/dist/lib/fs/resolve.js +69 -10
- package/dist/lib/parser/declaration/list.js +6 -1
- package/dist/lib/parser/parse.js +1169 -312
- package/dist/lib/parser/tokenize.js +33 -20
- package/dist/lib/parser/utils/declaration.js +54 -0
- package/dist/lib/parser/utils/hash.js +86 -0
- package/dist/lib/parser/utils/text.js +8 -0
- package/dist/lib/renderer/render.js +26 -7
- package/dist/lib/syntax/color/relativecolor.js +0 -3
- package/dist/lib/syntax/syntax.js +36 -18
- package/dist/lib/validation/at-rules/container.js +11 -0
- package/dist/lib/validation/at-rules/counter-style.js +11 -0
- package/dist/lib/validation/at-rules/font-feature-values.js +11 -0
- package/dist/lib/validation/at-rules/keyframes.js +11 -0
- package/dist/lib/validation/at-rules/layer.js +11 -0
- package/dist/lib/validation/at-rules/media.js +11 -0
- package/dist/lib/validation/at-rules/page-margin-box.js +11 -0
- package/dist/lib/validation/at-rules/page.js +11 -0
- package/dist/lib/validation/at-rules/supports.js +11 -0
- package/dist/lib/validation/at-rules/when.js +11 -0
- package/dist/lib/validation/config.js +0 -2
- package/dist/lib/validation/config.json.js +36 -4
- package/dist/lib/validation/parser/parse.js +53 -2
- package/dist/lib/validation/syntax.js +204 -36
- package/dist/lib/validation/syntaxes/compound-selector.js +1 -2
- package/dist/lib/validation/syntaxes/relative-selector-list.js +2 -5
- package/dist/node.js +60 -18
- package/dist/types.d.ts +17 -0
- package/dist/types.js +20 -0
- package/dist/web.js +43 -17
- package/package.json +20 -17
- package/dist/lib/validation/parser/types.js +0 -54
|
@@ -138,23 +138,27 @@ function* consumeString(quoteStr, buffer, parseInfo) {
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
function match(parseInfo, input) {
|
|
141
|
-
|
|
141
|
+
const position = parseInfo.currentPosition.ind - parseInfo.offset;
|
|
142
|
+
return parseInfo.stream.slice(position + 1, position + input.length + 1) == input;
|
|
142
143
|
}
|
|
143
144
|
function peek(parseInfo, count = 1) {
|
|
144
145
|
if (count == 1) {
|
|
145
|
-
return parseInfo.stream.charAt(parseInfo.currentPosition.ind + 1);
|
|
146
|
+
return parseInfo.stream.charAt(parseInfo.currentPosition.ind - parseInfo.offset + 1);
|
|
146
147
|
}
|
|
147
|
-
|
|
148
|
+
const position = parseInfo.currentPosition.ind - parseInfo.offset;
|
|
149
|
+
return parseInfo.stream.slice(position + 1, position + count + 1);
|
|
148
150
|
}
|
|
149
151
|
function prev(parseInfo) {
|
|
150
|
-
return parseInfo.stream.charAt(parseInfo.currentPosition.ind - 1);
|
|
152
|
+
return parseInfo.offset == parseInfo.currentPosition.ind ? parseInfo.buffer.slice(-1) : parseInfo.stream.charAt(parseInfo.currentPosition.ind - parseInfo.offset - 1);
|
|
151
153
|
}
|
|
152
154
|
function next(parseInfo, count = 1) {
|
|
153
155
|
let char = '';
|
|
154
156
|
let chr = '';
|
|
155
|
-
|
|
157
|
+
let position = parseInfo.currentPosition.ind - parseInfo.offset;
|
|
158
|
+
while (count-- && (chr = parseInfo.stream.charAt(position + 1))) {
|
|
156
159
|
char += chr;
|
|
157
|
-
const codepoint = parseInfo.stream.charCodeAt(++
|
|
160
|
+
const codepoint = parseInfo.stream.charCodeAt(++position);
|
|
161
|
+
++parseInfo.currentPosition.ind;
|
|
158
162
|
if (isNewLine(codepoint)) {
|
|
159
163
|
parseInfo.currentPosition.lin++;
|
|
160
164
|
parseInfo.currentPosition.col = 0;
|
|
@@ -182,13 +186,15 @@ function* tokenize(parseInfo, yieldEOFToken = true) {
|
|
|
182
186
|
yield pushToken(buffer, parseInfo);
|
|
183
187
|
buffer = '';
|
|
184
188
|
}
|
|
189
|
+
buffer += value;
|
|
185
190
|
while (value = next(parseInfo)) {
|
|
186
191
|
charCode = value.charCodeAt(0);
|
|
187
192
|
if (!isWhiteSpace(charCode)) {
|
|
188
193
|
break;
|
|
189
194
|
}
|
|
195
|
+
buffer += value;
|
|
190
196
|
}
|
|
191
|
-
yield pushToken(
|
|
197
|
+
yield pushToken(buffer, parseInfo, EnumToken.WhitespaceTokenType);
|
|
192
198
|
buffer = '';
|
|
193
199
|
}
|
|
194
200
|
switch (charCode) {
|
|
@@ -236,8 +242,7 @@ function* tokenize(parseInfo, yieldEOFToken = true) {
|
|
|
236
242
|
buffer = '';
|
|
237
243
|
}
|
|
238
244
|
if (match(parseInfo, '=')) {
|
|
239
|
-
yield pushToken(
|
|
240
|
-
next(parseInfo);
|
|
245
|
+
yield pushToken(value + next(parseInfo), parseInfo, EnumToken.LteTokenType);
|
|
241
246
|
break;
|
|
242
247
|
}
|
|
243
248
|
buffer += value;
|
|
@@ -292,8 +297,7 @@ function* tokenize(parseInfo, yieldEOFToken = true) {
|
|
|
292
297
|
}
|
|
293
298
|
if (charCode == 124 /* TokenMap.PIPE */) {
|
|
294
299
|
if (match(parseInfo, '|')) {
|
|
295
|
-
next(parseInfo);
|
|
296
|
-
yield pushToken('', parseInfo, EnumToken.ColumnCombinatorTokenType);
|
|
300
|
+
yield pushToken(value + next(parseInfo), parseInfo, EnumToken.ColumnCombinatorTokenType);
|
|
297
301
|
}
|
|
298
302
|
else if (match(parseInfo, '=')) {
|
|
299
303
|
buffer += next(parseInfo);
|
|
@@ -347,11 +351,10 @@ function* tokenize(parseInfo, yieldEOFToken = true) {
|
|
|
347
351
|
buffer = '';
|
|
348
352
|
}
|
|
349
353
|
if (match(parseInfo, '=')) {
|
|
350
|
-
yield pushToken(
|
|
351
|
-
next(parseInfo);
|
|
354
|
+
yield pushToken(value + next(parseInfo), parseInfo, EnumToken.GteTokenType);
|
|
352
355
|
}
|
|
353
356
|
else {
|
|
354
|
-
yield pushToken(
|
|
357
|
+
yield pushToken(value, parseInfo, EnumToken.GtTokenType);
|
|
355
358
|
}
|
|
356
359
|
consumeWhiteSpace(parseInfo);
|
|
357
360
|
break;
|
|
@@ -402,7 +405,7 @@ function* tokenize(parseInfo, yieldEOFToken = true) {
|
|
|
402
405
|
yield pushToken(buffer, parseInfo);
|
|
403
406
|
buffer = '';
|
|
404
407
|
}
|
|
405
|
-
yield pushToken(
|
|
408
|
+
yield pushToken(value, parseInfo, EnumToken.EndParensTokenType);
|
|
406
409
|
break;
|
|
407
410
|
case 40 /* TokenMap.OPEN_PAREN */:
|
|
408
411
|
if (buffer.length == 0) {
|
|
@@ -468,7 +471,7 @@ function* tokenize(parseInfo, yieldEOFToken = true) {
|
|
|
468
471
|
// ')'
|
|
469
472
|
if (charCode == 0x29) {
|
|
470
473
|
yield pushToken(buffer, parseInfo, hasNewLine ? EnumToken.BadStringTokenType : EnumToken.StringTokenType);
|
|
471
|
-
yield pushToken(
|
|
474
|
+
yield pushToken(value, parseInfo, EnumToken.EndParensTokenType);
|
|
472
475
|
buffer = '';
|
|
473
476
|
break;
|
|
474
477
|
}
|
|
@@ -492,7 +495,7 @@ function* tokenize(parseInfo, yieldEOFToken = true) {
|
|
|
492
495
|
charCode = value.charCodeAt(0);
|
|
493
496
|
if (charCode == 0x29) { // ')'
|
|
494
497
|
yield pushToken(buffer, parseInfo, EnumToken.UrlTokenTokenType);
|
|
495
|
-
yield pushToken(
|
|
498
|
+
yield pushToken(value, parseInfo, EnumToken.EndParensTokenType);
|
|
496
499
|
buffer = '';
|
|
497
500
|
break;
|
|
498
501
|
}
|
|
@@ -526,8 +529,7 @@ function* tokenize(parseInfo, yieldEOFToken = true) {
|
|
|
526
529
|
buffer = '';
|
|
527
530
|
}
|
|
528
531
|
if (match(parseInfo, 'important')) {
|
|
529
|
-
yield pushToken(
|
|
530
|
-
next(parseInfo, 9);
|
|
532
|
+
yield pushToken(value + next(parseInfo, 9), parseInfo, EnumToken.ImportantTokenType);
|
|
531
533
|
buffer = '';
|
|
532
534
|
break;
|
|
533
535
|
}
|
|
@@ -572,6 +574,7 @@ async function* tokenizeStream(input) {
|
|
|
572
574
|
const parseInfo = {
|
|
573
575
|
stream: '',
|
|
574
576
|
buffer: '',
|
|
577
|
+
offset: 0,
|
|
575
578
|
position: { ind: 0, lin: 1, col: 1 },
|
|
576
579
|
currentPosition: { ind: -1, lin: 1, col: 0 }
|
|
577
580
|
};
|
|
@@ -579,7 +582,17 @@ async function* tokenizeStream(input) {
|
|
|
579
582
|
const reader = input.getReader();
|
|
580
583
|
while (true) {
|
|
581
584
|
const { done, value } = await reader.read();
|
|
582
|
-
|
|
585
|
+
const stream = ArrayBuffer.isView(value) ? decoder.decode(value, { stream: true }) : value;
|
|
586
|
+
if (!done) {
|
|
587
|
+
if (parseInfo.stream.length > 2) {
|
|
588
|
+
parseInfo.stream = parseInfo.stream.slice(-2) + stream;
|
|
589
|
+
parseInfo.offset = parseInfo.currentPosition.ind - 1;
|
|
590
|
+
}
|
|
591
|
+
else {
|
|
592
|
+
parseInfo.stream = stream;
|
|
593
|
+
parseInfo.offset = Math.max(0, parseInfo.currentPosition.ind);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
583
596
|
yield* tokenize(parseInfo, done);
|
|
584
597
|
if (done) {
|
|
585
598
|
break;
|
|
@@ -20,6 +20,60 @@ function parseDeclarationNode(node, errors, location) {
|
|
|
20
20
|
});
|
|
21
21
|
return null;
|
|
22
22
|
}
|
|
23
|
+
if ('composes' == node.nam.toLowerCase()) {
|
|
24
|
+
let left = [];
|
|
25
|
+
let right = [];
|
|
26
|
+
let current = 0;
|
|
27
|
+
let hasFrom = 0;
|
|
28
|
+
for (; current < node.val.length; current++) {
|
|
29
|
+
if (EnumToken.WhitespaceTokenType == node.val[current].typ || EnumToken.CommentTokenType == node.val[current].typ) {
|
|
30
|
+
if (!hasFrom) {
|
|
31
|
+
left.push(node.val[current]);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
right.push(node.val[current]);
|
|
35
|
+
}
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (EnumToken.IdenTokenType == node.val[current].typ || EnumToken.DashedIdenTokenType == node.val[current].typ || EnumToken.StringTokenType == node.val[current].typ) {
|
|
39
|
+
if (EnumToken.IdenTokenType == node.val[current].typ) {
|
|
40
|
+
if ('from' == node.val[current].val) {
|
|
41
|
+
if (hasFrom) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
hasFrom++;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (hasFrom) {
|
|
49
|
+
right.push(node.val[current]);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
left.push(node.val[current]);
|
|
53
|
+
}
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
if (hasFrom <= 1 && current > 0) {
|
|
59
|
+
if (hasFrom == 0) {
|
|
60
|
+
node.val.splice(0, left.length, {
|
|
61
|
+
typ: EnumToken.ComposesSelectorNodeType,
|
|
62
|
+
l: left,
|
|
63
|
+
r: null
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
node.val.splice(0, current, {
|
|
68
|
+
typ: EnumToken.ComposesSelectorNodeType,
|
|
69
|
+
l: left,
|
|
70
|
+
r: right.reduce((a, b) => {
|
|
71
|
+
return a == null ? b : b.typ == EnumToken.WhitespaceTokenType || b.typ == EnumToken.CommentTokenType ? a : b;
|
|
72
|
+
}, null)
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
23
77
|
for (const { value: val, parent } of walkValues(node.val, node)) {
|
|
24
78
|
if (val.typ == EnumToken.AttrTokenType && val.chi.every((t) => [EnumToken.IdenTokenType, EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ))) {
|
|
25
79
|
// @ts-ignore
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Alphabet: a-z, A-Z, 0-9, _, -
|
|
2
|
+
const LOWER = "abcdefghijklmnopqrstuvwxyz";
|
|
3
|
+
const DIGITS = "0123456789";
|
|
4
|
+
const FULL_ALPHABET = (LOWER + DIGITS).split(""); // 64 chars
|
|
5
|
+
const FIRST_ALPHABET = (LOWER).split(""); // 54 chars (no digits)
|
|
6
|
+
/**
|
|
7
|
+
* supported hash algorithms
|
|
8
|
+
*/
|
|
9
|
+
const hashAlgorithms = ['hex', 'base64', 'base64url', 'sha1', 'sha256', 'sha384', 'sha512'];
|
|
10
|
+
// simple deterministic hash → number
|
|
11
|
+
function hashCode(str) {
|
|
12
|
+
let hash = 0;
|
|
13
|
+
let l = str.length;
|
|
14
|
+
let i = 0;
|
|
15
|
+
while (i < l) {
|
|
16
|
+
hash = (hash * 31 + str.charCodeAt(i++)) >>> 0;
|
|
17
|
+
}
|
|
18
|
+
return hash;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* generate a hash id
|
|
22
|
+
* @param input
|
|
23
|
+
* @param length
|
|
24
|
+
*/
|
|
25
|
+
function hashId(input, length = 6) {
|
|
26
|
+
let n = hashCode(input);
|
|
27
|
+
const chars = [];
|
|
28
|
+
// First character: must not be a digit
|
|
29
|
+
chars.push(FIRST_ALPHABET[n % FIRST_ALPHABET.length]);
|
|
30
|
+
// Remaining characters
|
|
31
|
+
for (let i = 1; i < length; i++) {
|
|
32
|
+
n = (n + chars.length + i) % FULL_ALPHABET.length;
|
|
33
|
+
chars.push(FULL_ALPHABET[n]);
|
|
34
|
+
}
|
|
35
|
+
return chars.join("");
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* convert input to hex
|
|
39
|
+
* @param input
|
|
40
|
+
*/
|
|
41
|
+
function toHex(input) {
|
|
42
|
+
let result = '';
|
|
43
|
+
if (input instanceof ArrayBuffer || ArrayBuffer.isView(input)) {
|
|
44
|
+
for (const byte of Array.from(new Uint8Array(input))) {
|
|
45
|
+
result += byte.toString(16).padStart(2, '0');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
for (const char of String(input)) {
|
|
50
|
+
result += char.charCodeAt(0).toString(16).padStart(2, '0');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* generate a hash
|
|
57
|
+
* @param input
|
|
58
|
+
* @param length
|
|
59
|
+
* @param algo
|
|
60
|
+
*/
|
|
61
|
+
async function hash(input, length = 6, algo) {
|
|
62
|
+
let result;
|
|
63
|
+
if (algo != null) {
|
|
64
|
+
switch (algo) {
|
|
65
|
+
case 'hex':
|
|
66
|
+
return toHex(input).slice(0, length);
|
|
67
|
+
case 'base64':
|
|
68
|
+
case 'base64url':
|
|
69
|
+
result = btoa(input);
|
|
70
|
+
if (algo == 'base64url') {
|
|
71
|
+
result = result.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
72
|
+
}
|
|
73
|
+
return result.slice(0, length);
|
|
74
|
+
case 'sha1':
|
|
75
|
+
case 'sha256':
|
|
76
|
+
case 'sha384':
|
|
77
|
+
case 'sha512':
|
|
78
|
+
return toHex(await crypto.subtle.digest(algo.replace('sha', 'SHA-'), new TextEncoder().encode(input))).slice(0, length);
|
|
79
|
+
default:
|
|
80
|
+
throw new Error(`Unsupported hash algorithm: ${algo}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return hashId(input, length);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { hash, hashAlgorithms, hashId };
|
|
@@ -29,9 +29,10 @@ function update(position, str) {
|
|
|
29
29
|
* render ast
|
|
30
30
|
* @param data
|
|
31
31
|
* @param options
|
|
32
|
+
* @param mapping
|
|
32
33
|
* @private
|
|
33
34
|
*/
|
|
34
|
-
function doRender(data, options = {}) {
|
|
35
|
+
function doRender(data, options = {}, mapping) {
|
|
35
36
|
const minify = options.minify ?? true;
|
|
36
37
|
const beautify = options.beautify ?? !minify;
|
|
37
38
|
options = {
|
|
@@ -68,12 +69,23 @@ function doRender(data, options = {}) {
|
|
|
68
69
|
const errors = [];
|
|
69
70
|
const sourcemap = options.sourcemap ? new SourceMap : null;
|
|
70
71
|
const cache = Object.create(null);
|
|
72
|
+
const position = {
|
|
73
|
+
ind: 0,
|
|
74
|
+
lin: 1,
|
|
75
|
+
col: 1
|
|
76
|
+
};
|
|
77
|
+
let code = '';
|
|
78
|
+
if (mapping != null) {
|
|
79
|
+
if (mapping.importMapping != null) {
|
|
80
|
+
for (const [key, value] of Object.entries(mapping.importMapping)) {
|
|
81
|
+
code += `:import("${key}")${options.indent}{${options.newLine}${Object.entries(value).reduce((acc, [k, v]) => acc + (acc.length > 0 ? options.newLine : '') + `${options.indent}${v}:${options.indent}${k};`, '')}${options.newLine}}${options.newLine}`;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
code += `:export${options.indent}{${options.newLine}${Object.entries(mapping.mapping).reduce((acc, [k, v]) => acc + (acc.length > 0 ? options.newLine : '') + `${options.indent}${k}:${options.indent}${v};`, '')}${options.newLine}}${options.newLine}`;
|
|
85
|
+
update(position, code);
|
|
86
|
+
}
|
|
71
87
|
const result = {
|
|
72
|
-
code: renderAstNode(options.expandNestingRules ? expand(data) : data, options, sourcemap, {
|
|
73
|
-
ind: 0,
|
|
74
|
-
lin: 1,
|
|
75
|
-
col: 1
|
|
76
|
-
}, errors, function reducer(acc, curr) {
|
|
88
|
+
code: code + renderAstNode(options.expandNestingRules && [EnumToken.StyleSheetNodeType, EnumToken.AtRuleNodeType, EnumToken.RuleNodeType].includes(data.typ) && 'chi' in data ? expand(data) : data, options, sourcemap, position, errors, function reducer(acc, curr) {
|
|
77
89
|
if (curr.typ == EnumToken.CommentTokenType && options.removeComments) {
|
|
78
90
|
if (!options.preserveLicense || !curr.val.startsWith('/*!')) {
|
|
79
91
|
return acc;
|
|
@@ -209,7 +221,7 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
|
|
|
209
221
|
str = `${node.nam}:${options.indent}${(options.minify ? filterValues(node.val) : node.val).reduce(reducer, '').trimEnd()};`;
|
|
210
222
|
}
|
|
211
223
|
else if (node.typ == EnumToken.AtRuleNodeType && !('chi' in node)) {
|
|
212
|
-
str = `${
|
|
224
|
+
str = `${node.val === '' ? '' : options.indent || ' '}${node.val};`;
|
|
213
225
|
}
|
|
214
226
|
else {
|
|
215
227
|
str = renderAstNode(node, options, sourcemap, { ...position }, errors, reducer, cache, level + 1, indents);
|
|
@@ -232,6 +244,11 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
|
|
|
232
244
|
return `@${data.nam}${data.val === '' ? '' : options.indent || ' '}${data.val}${options.indent}{${options.newLine}` + (children === '' ? '' : indentSub + children + options.newLine) + indent + `}`;
|
|
233
245
|
}
|
|
234
246
|
return data.sel + `${options.indent}{${options.newLine}` + (children === '' ? '' : indentSub + children + options.newLine) + indent + `}`;
|
|
247
|
+
case EnumToken.CssVariableTokenType:
|
|
248
|
+
case EnumToken.CssVariableImportTokenType:
|
|
249
|
+
return `@value ${data.nam}:${options.indent}${filterValues((options.minify ? data.val : data.val)).reduce(reducer, '').trim()};`;
|
|
250
|
+
case EnumToken.CssVariableDeclarationMapTokenType:
|
|
251
|
+
return `@value ${filterValues(data.vars).reduce((acc, curr) => acc + renderToken(curr), '').trim()} from ${filterValues(data.from).reduce((acc, curr) => acc + renderToken(curr), '').trim()};`;
|
|
235
252
|
case EnumToken.InvalidDeclarationNodeType:
|
|
236
253
|
case EnumToken.InvalidRuleTokenType:
|
|
237
254
|
case EnumToken.InvalidAtRuleTokenType:
|
|
@@ -386,6 +403,8 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
|
|
|
386
403
|
case EnumToken.NameSpaceAttributeTokenType:
|
|
387
404
|
return (token.l == null ? '' : renderToken(token.l, options, cache, reducer, errors)) + '|' +
|
|
388
405
|
renderToken(token.r, options, cache, reducer, errors);
|
|
406
|
+
case EnumToken.ComposesSelectorNodeType:
|
|
407
|
+
return token.l.reduce((acc, curr) => acc + renderToken(curr, options, cache), '') + (token.r == null ? '' : ' from ' + renderToken(token.r, options, cache, reducer, errors));
|
|
389
408
|
case EnumToken.BlockStartTokenType:
|
|
390
409
|
return '{';
|
|
391
410
|
case EnumToken.BlockEndTokenType:
|
|
@@ -77,10 +77,7 @@ function computeComponentValue(expr, converted, values) {
|
|
|
77
77
|
// normalize hue
|
|
78
78
|
for (const k of walkValues([object.h])) {
|
|
79
79
|
if (k.value.typ == EnumToken.AngleTokenType && k.value.unit == 'deg') {
|
|
80
|
-
// @ts-ignore
|
|
81
80
|
k.value.typ = EnumToken.NumberTokenType;
|
|
82
|
-
// @ts-ignore
|
|
83
|
-
delete k.value.unit;
|
|
84
81
|
}
|
|
85
82
|
}
|
|
86
83
|
}
|
|
@@ -528,7 +528,7 @@ function isColor(token) {
|
|
|
528
528
|
}
|
|
529
529
|
if (token.typ == EnumToken.IdenTokenType) {
|
|
530
530
|
// named color
|
|
531
|
-
return token.val.toLowerCase() in COLORS_NAMES;
|
|
531
|
+
return token.val.toLowerCase() in COLORS_NAMES || 'currentcolor' === token.val.toLowerCase() || 'transparent' === token.val.toLowerCase();
|
|
532
532
|
}
|
|
533
533
|
let isLegacySyntax = false;
|
|
534
534
|
if (token.typ == EnumToken.FunctionTokenType) {
|
|
@@ -581,8 +581,13 @@ function isColor(token) {
|
|
|
581
581
|
return false;
|
|
582
582
|
}
|
|
583
583
|
}
|
|
584
|
-
if (children[i].typ == EnumToken.FunctionTokenType
|
|
585
|
-
|
|
584
|
+
if (children[i].typ == EnumToken.FunctionTokenType) {
|
|
585
|
+
if ('var' == children[i].val.toLowerCase()) {
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
if (!mathFuncs.includes(children[i].val)) {
|
|
589
|
+
return false;
|
|
590
|
+
}
|
|
586
591
|
}
|
|
587
592
|
}
|
|
588
593
|
if (children.length == 4 || (isRelative && children.length == 6)) {
|
|
@@ -869,23 +874,29 @@ function isNumber(name) {
|
|
|
869
874
|
}
|
|
870
875
|
return true;
|
|
871
876
|
}
|
|
872
|
-
function isDimension(name) {
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
877
|
+
// export function isDimension(name: string) {
|
|
878
|
+
//
|
|
879
|
+
// let index: number = name.length;
|
|
880
|
+
//
|
|
881
|
+
// while (index--) {
|
|
882
|
+
//
|
|
883
|
+
// if (isLetter(<number>name.charCodeAt(index))) {
|
|
884
|
+
//
|
|
885
|
+
// continue
|
|
886
|
+
// }
|
|
887
|
+
//
|
|
888
|
+
// index++;
|
|
889
|
+
// break;
|
|
890
|
+
// }
|
|
891
|
+
//
|
|
892
|
+
// const number: string = name.slice(0, index);
|
|
893
|
+
// return number.length > 0 && isIdentStart(name.charCodeAt(index)) && isNumber(number);
|
|
894
|
+
// }
|
|
884
895
|
function isPercentage(name) {
|
|
885
896
|
return name.endsWith('%') && isNumber(name.slice(0, -1));
|
|
886
897
|
}
|
|
887
|
-
function isFlex(
|
|
888
|
-
return
|
|
898
|
+
function isFlex(dimension) {
|
|
899
|
+
return 'unit' in dimension && 'fr' == dimension.unit.toLowerCase();
|
|
889
900
|
}
|
|
890
901
|
function parseDimension(name) {
|
|
891
902
|
let index = name.length;
|
|
@@ -901,6 +912,9 @@ function parseDimension(name) {
|
|
|
901
912
|
val: +name.slice(0, index),
|
|
902
913
|
unit: name.slice(index)
|
|
903
914
|
};
|
|
915
|
+
if (index < 0 || Number.isNaN(dimension.val)) {
|
|
916
|
+
return null;
|
|
917
|
+
}
|
|
904
918
|
if (isAngle(dimension)) {
|
|
905
919
|
// @ts-ignore
|
|
906
920
|
dimension.typ = EnumToken.AngleTokenType;
|
|
@@ -924,6 +938,10 @@ function parseDimension(name) {
|
|
|
924
938
|
// @ts-ignore
|
|
925
939
|
dimension.typ = EnumToken.FrequencyTokenType;
|
|
926
940
|
}
|
|
941
|
+
else if (isFlex(dimension)) {
|
|
942
|
+
// @ts-ignore
|
|
943
|
+
dimension.typ = EnumToken.FlexTokenType;
|
|
944
|
+
}
|
|
927
945
|
return dimension;
|
|
928
946
|
}
|
|
929
947
|
function isHexColor(name) {
|
|
@@ -958,4 +976,4 @@ function isWhiteSpace(codepoint) {
|
|
|
958
976
|
codepoint == 0xa || codepoint == 0xc || codepoint == 0xd;
|
|
959
977
|
}
|
|
960
978
|
|
|
961
|
-
export { colorFontTech, fontFeaturesTech, fontFormat, isAngle, isAtKeyword, isColor, isColorspace, isDigit,
|
|
979
|
+
export { colorFontTech, fontFeaturesTech, fontFormat, isAngle, isAtKeyword, isColor, isColorspace, isDigit, isFlex, isFrequency, isFunction, isHash, isHexColor, isHueInterpolationMethod, isIdent, isIdentCodepoint, isIdentColor, isIdentStart, isLength, isNewLine, isNumber, isPercentage, isPercentageToken, isPolarColorspace, isPseudo, isRectangularOrthogonalColorspace, isResolution, isTime, isWhiteSpace, mathFuncs, mediaTypes, mozExtensions, parseColor, parseDimension, pseudoAliasMap, pseudoElements, transformFunctions, webkitExtensions, wildCardFuncs };
|
|
@@ -11,6 +11,17 @@ import { splitTokenList } from '../utils/list.js';
|
|
|
11
11
|
|
|
12
12
|
const validateContainerScrollStateFeature = validateContainerSizeFeature;
|
|
13
13
|
function validateAtRuleContainer(atRule, options, root) {
|
|
14
|
+
if (!Array.isArray(atRule.chi)) {
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
return {
|
|
17
|
+
valid: SyntaxValidationResult.Drop,
|
|
18
|
+
matches: [],
|
|
19
|
+
node: atRule,
|
|
20
|
+
syntax: '@' + atRule.nam,
|
|
21
|
+
error: 'expected supports body',
|
|
22
|
+
tokens: []
|
|
23
|
+
};
|
|
24
|
+
}
|
|
14
25
|
// media-query-list
|
|
15
26
|
if (!Array.isArray(atRule.tokens) || atRule.tokens.length == 0) {
|
|
16
27
|
// @ts-ignore
|
|
@@ -8,6 +8,17 @@ import '../../syntax/color/utils/constants.js';
|
|
|
8
8
|
import '../../renderer/sourcemap/lib/encode.js';
|
|
9
9
|
|
|
10
10
|
function validateAtRuleCounterStyle(atRule, options, root) {
|
|
11
|
+
if (!Array.isArray(atRule.chi)) {
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
return {
|
|
14
|
+
valid: SyntaxValidationResult.Drop,
|
|
15
|
+
matches: [],
|
|
16
|
+
node: atRule,
|
|
17
|
+
syntax: '@' + atRule.nam,
|
|
18
|
+
error: 'expected supports body',
|
|
19
|
+
tokens: []
|
|
20
|
+
};
|
|
21
|
+
}
|
|
11
22
|
// media-query-list
|
|
12
23
|
if (!Array.isArray(atRule.tokens) || atRule.tokens.length == 0) {
|
|
13
24
|
// @ts-ignore
|
|
@@ -12,6 +12,17 @@ import '../syntax.js';
|
|
|
12
12
|
import '../config.js';
|
|
13
13
|
|
|
14
14
|
function validateAtRuleFontFeatureValues(atRule, options, root) {
|
|
15
|
+
if (!Array.isArray(atRule.chi)) {
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
return {
|
|
18
|
+
valid: SyntaxValidationResult.Drop,
|
|
19
|
+
matches: [],
|
|
20
|
+
node: atRule,
|
|
21
|
+
syntax: '@' + atRule.nam,
|
|
22
|
+
error: 'expected supports body',
|
|
23
|
+
tokens: []
|
|
24
|
+
};
|
|
25
|
+
}
|
|
15
26
|
if (!Array.isArray(atRule.tokens) || atRule.tokens.length == 0) {
|
|
16
27
|
// @ts-ignore
|
|
17
28
|
return {
|
|
@@ -9,6 +9,17 @@ import '../../renderer/sourcemap/lib/encode.js';
|
|
|
9
9
|
import { consumeWhitespace } from '../utils/whitespace.js';
|
|
10
10
|
|
|
11
11
|
function validateAtRuleKeyframes(atRule, options, root) {
|
|
12
|
+
if (!Array.isArray(atRule.chi)) {
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
return {
|
|
15
|
+
valid: SyntaxValidationResult.Drop,
|
|
16
|
+
matches: [],
|
|
17
|
+
node: atRule,
|
|
18
|
+
syntax: '@' + atRule.nam,
|
|
19
|
+
error: 'expected supports body',
|
|
20
|
+
tokens: []
|
|
21
|
+
};
|
|
22
|
+
}
|
|
12
23
|
if (!Array.isArray(atRule.tokens) || atRule.tokens.length == 0) {
|
|
13
24
|
// @ts-ignore
|
|
14
25
|
return {
|
|
@@ -12,6 +12,17 @@ import '../syntax.js';
|
|
|
12
12
|
import '../config.js';
|
|
13
13
|
|
|
14
14
|
function validateAtRuleLayer(atRule, options, root) {
|
|
15
|
+
if (!Array.isArray(atRule.chi)) {
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
return {
|
|
18
|
+
valid: SyntaxValidationResult.Drop,
|
|
19
|
+
matches: [],
|
|
20
|
+
node: atRule,
|
|
21
|
+
syntax: '@' + atRule.nam,
|
|
22
|
+
error: 'expected supports body',
|
|
23
|
+
tokens: []
|
|
24
|
+
};
|
|
25
|
+
}
|
|
15
26
|
// media-query-list
|
|
16
27
|
if (!Array.isArray(atRule.tokens) || atRule.tokens.length == 0) {
|
|
17
28
|
// @ts-ignore
|
|
@@ -10,6 +10,17 @@ import { consumeWhitespace } from '../utils/whitespace.js';
|
|
|
10
10
|
import { splitTokenList } from '../utils/list.js';
|
|
11
11
|
|
|
12
12
|
function validateAtRuleMedia(atRule, options, root) {
|
|
13
|
+
if (!Array.isArray(atRule.chi)) {
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
return {
|
|
16
|
+
valid: SyntaxValidationResult.Drop,
|
|
17
|
+
matches: [],
|
|
18
|
+
node: atRule,
|
|
19
|
+
syntax: '@' + atRule.nam,
|
|
20
|
+
error: 'expected supports body',
|
|
21
|
+
tokens: []
|
|
22
|
+
};
|
|
23
|
+
}
|
|
13
24
|
// media-query-list
|
|
14
25
|
if (!Array.isArray(atRule.tokens) || atRule.tokens.length == 0) {
|
|
15
26
|
// @ts-ignore
|
|
@@ -8,6 +8,17 @@ import '../../syntax/color/utils/constants.js';
|
|
|
8
8
|
import '../../renderer/sourcemap/lib/encode.js';
|
|
9
9
|
|
|
10
10
|
function validateAtRulePageMarginBox(atRule, options, root) {
|
|
11
|
+
if (!Array.isArray(atRule.chi)) {
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
return {
|
|
14
|
+
valid: SyntaxValidationResult.Drop,
|
|
15
|
+
matches: [],
|
|
16
|
+
node: atRule,
|
|
17
|
+
syntax: '@' + atRule.nam,
|
|
18
|
+
error: 'expected supports body',
|
|
19
|
+
tokens: []
|
|
20
|
+
};
|
|
21
|
+
}
|
|
11
22
|
if (Array.isArray(atRule.tokens) && atRule.tokens.length > 0) {
|
|
12
23
|
// @ts-ignore
|
|
13
24
|
return {
|
|
@@ -9,6 +9,17 @@ import '../../renderer/sourcemap/lib/encode.js';
|
|
|
9
9
|
import { splitTokenList } from '../utils/list.js';
|
|
10
10
|
|
|
11
11
|
function validateAtRulePage(atRule, options, root) {
|
|
12
|
+
if (!Array.isArray(atRule.chi)) {
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
return {
|
|
15
|
+
valid: SyntaxValidationResult.Drop,
|
|
16
|
+
matches: [],
|
|
17
|
+
node: atRule,
|
|
18
|
+
syntax: '@' + atRule.nam,
|
|
19
|
+
error: 'expected supports body',
|
|
20
|
+
tokens: []
|
|
21
|
+
};
|
|
22
|
+
}
|
|
12
23
|
// media-query-list
|
|
13
24
|
if (!Array.isArray(atRule.tokens) || atRule.tokens.length == 0) {
|
|
14
25
|
// @ts-ignore
|
|
@@ -23,6 +23,17 @@ function validateAtRuleSupports(atRule, options, root) {
|
|
|
23
23
|
tokens: []
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
+
if (!Array.isArray(atRule.chi)) {
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
return {
|
|
29
|
+
valid: SyntaxValidationResult.Drop,
|
|
30
|
+
matches: [],
|
|
31
|
+
node: atRule,
|
|
32
|
+
syntax: '@' + atRule.nam,
|
|
33
|
+
error: 'expected supports body',
|
|
34
|
+
tokens: []
|
|
35
|
+
};
|
|
36
|
+
}
|
|
26
37
|
const result = validateAtRuleSupportsConditions(atRule, atRule.tokens);
|
|
27
38
|
if (result) {
|
|
28
39
|
if (result.node == null) {
|