@tbela99/css-parser 0.7.0 → 0.8.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/README.md +142 -81
- package/dist/index-umd-web.js +7027 -51519
- package/dist/index.cjs +7022 -51515
- package/dist/index.d.ts +189 -60
- package/dist/lib/ast/expand.js +87 -2
- package/dist/lib/ast/features/calc.js +76 -12
- package/dist/lib/ast/features/inlinecssvariables.js +6 -1
- package/dist/lib/ast/features/prefix.js +17 -9
- package/dist/lib/ast/features/shorthand.js +1 -0
- package/dist/lib/ast/math/expression.js +299 -11
- package/dist/lib/ast/math/math.js +7 -1
- package/dist/lib/ast/minify.js +1 -1
- package/dist/lib/ast/types.js +58 -49
- package/dist/lib/ast/walk.js +80 -18
- package/dist/lib/parser/declaration/list.js +1 -0
- package/dist/lib/parser/declaration/map.js +1 -0
- package/dist/lib/parser/declaration/set.js +1 -0
- package/dist/lib/parser/parse.js +285 -72
- package/dist/lib/parser/tokenize.js +23 -3
- package/dist/lib/parser/utils/declaration.js +2 -2
- package/dist/lib/parser/utils/type.js +6 -6
- package/dist/lib/renderer/color/a98rgb.js +1 -0
- package/dist/lib/renderer/color/color.js +1 -0
- package/dist/lib/renderer/color/colormix.js +1 -0
- package/dist/lib/renderer/color/hex.js +1 -0
- package/dist/lib/renderer/color/hsl.js +1 -0
- package/dist/lib/renderer/color/hwb.js +1 -0
- package/dist/lib/renderer/color/lab.js +1 -0
- package/dist/lib/renderer/color/lch.js +1 -0
- package/dist/lib/renderer/color/oklab.js +1 -0
- package/dist/lib/renderer/color/oklch.js +1 -0
- package/dist/lib/renderer/color/p3.js +1 -0
- package/dist/lib/renderer/color/prophotoRgb.js +56 -0
- package/dist/lib/renderer/color/rec2020.js +1 -0
- package/dist/lib/renderer/color/relativecolor.js +52 -28
- package/dist/lib/renderer/color/rgb.js +1 -0
- package/dist/lib/renderer/color/srgb.js +1 -0
- package/dist/lib/renderer/color/utils/components.js +1 -0
- package/dist/lib/renderer/color/utils/constants.js +1 -0
- package/dist/lib/renderer/color/xyz.js +1 -0
- package/dist/lib/renderer/color/xyzd50.js +1 -0
- package/dist/lib/renderer/render.js +28 -6
- package/dist/lib/syntax/syntax.js +27 -4
- package/dist/lib/validation/at-rules/counter-style.js +78 -0
- package/dist/lib/validation/at-rules/document.js +114 -0
- package/dist/lib/validation/at-rules/font-feature-values.js +49 -0
- package/dist/lib/validation/at-rules/import.js +196 -0
- package/dist/lib/validation/at-rules/keyframes.js +70 -0
- package/dist/lib/validation/at-rules/layer.js +27 -0
- package/dist/lib/validation/at-rules/media.js +166 -0
- package/dist/lib/validation/at-rules/namespace.js +85 -0
- package/dist/lib/validation/at-rules/page-margin-box.js +56 -0
- package/dist/lib/validation/at-rules/page.js +88 -0
- package/dist/lib/validation/at-rules/supports.js +262 -0
- package/dist/lib/validation/atrule.js +172 -0
- package/dist/lib/validation/config.js +30 -2
- package/dist/lib/validation/config.json.js +1560 -50902
- package/dist/lib/validation/declaration.js +72 -0
- package/dist/lib/validation/parser/parse.js +1059 -7
- package/dist/lib/validation/parser/types.js +27 -12
- package/dist/lib/validation/selector.js +23 -444
- package/dist/lib/validation/syntax.js +1429 -0
- package/dist/lib/validation/syntaxes/complex-selector-list.js +41 -0
- package/dist/lib/validation/syntaxes/complex-selector.js +283 -0
- package/dist/lib/validation/syntaxes/family-name.js +91 -0
- package/dist/lib/validation/syntaxes/keyframe-block-list.js +27 -0
- package/dist/lib/validation/syntaxes/keyframe-selector.js +137 -0
- package/dist/lib/validation/syntaxes/layer-name.js +67 -0
- package/dist/lib/validation/syntaxes/relative-selector-list.js +27 -0
- package/dist/lib/validation/syntaxes/relative-selector.js +36 -0
- package/dist/lib/validation/syntaxes/selector-list.js +5 -0
- package/dist/lib/validation/syntaxes/selector.js +5 -0
- package/dist/lib/validation/syntaxes/url.js +75 -0
- package/dist/lib/validation/utils/list.js +24 -0
- package/dist/lib/validation/utils/whitespace.js +22 -0
- package/dist/node/index.js +13 -0
- package/dist/web/index.js +13 -0
- package/dist/web/load.js +1 -0
- package/package.json +17 -15
- package/dist/lib/ast/utils/minifyfeature.js +0 -9
- package/dist/lib/iterable/weakset.js +0 -58
- package/dist/lib/parser/utils/syntax.js +0 -450
package/dist/lib/parser/parse.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
import { isPseudo, isAtKeyword, isFunction, isNumber, isPercentage, isFlex, isDimension, parseDimension, isIdent, isHexColor, isHash, isIdentStart, isColor } from '../syntax/syntax.js';
|
|
1
|
+
import { isPseudo, isAtKeyword, isFunction, isNumber, isPercentage, isFlex, isDimension, parseDimension, isIdent, isHexColor, isHash, isIdentStart, mathFuncs, isColor, mediaTypes } from '../syntax/syntax.js';
|
|
2
2
|
import './utils/config.js';
|
|
3
3
|
import { EnumToken, funcLike, ValidationLevel } from '../ast/types.js';
|
|
4
4
|
import { minify, definedPropertySettings, combinators } from '../ast/minify.js';
|
|
5
5
|
import { walkValues, walk } from '../ast/walk.js';
|
|
6
6
|
import { expand } from '../ast/expand.js';
|
|
7
|
-
import {
|
|
7
|
+
import { parseDeclarationNode } from './utils/declaration.js';
|
|
8
8
|
import { renderToken } from '../renderer/render.js';
|
|
9
9
|
import { COLORS_NAMES, systemColors, deprecatedSystemColors } from '../renderer/color/utils/constants.js';
|
|
10
10
|
import { tokenize } from './tokenize.js';
|
|
11
|
+
import '../validation/config.js';
|
|
12
|
+
import '../validation/parser/types.js';
|
|
13
|
+
import '../validation/parser/parse.js';
|
|
11
14
|
import { validateSelector } from '../validation/selector.js';
|
|
15
|
+
import { validateAtRule } from '../validation/atrule.js';
|
|
12
16
|
|
|
13
17
|
const urlTokenMatcher = /^(["']?)[a-zA-Z0-9_/.-][a-zA-Z0-9_/:.#?-]+(\1)$/;
|
|
14
18
|
const trimWhiteSpace = [EnumToken.CommentTokenType, EnumToken.GtTokenType, EnumToken.GteTokenType, EnumToken.LtTokenType, EnumToken.LteTokenType, EnumToken.ColumnCombinatorTokenType];
|
|
@@ -90,7 +94,7 @@ async function doParse(iterator, options = {}) {
|
|
|
90
94
|
inlineCssVariables: false,
|
|
91
95
|
setParent: true,
|
|
92
96
|
removePrefix: false,
|
|
93
|
-
validation:
|
|
97
|
+
validation: true,
|
|
94
98
|
...options
|
|
95
99
|
};
|
|
96
100
|
if (options.expandNestingRules) {
|
|
@@ -143,13 +147,12 @@ async function doParse(iterator, options = {}) {
|
|
|
143
147
|
if (item.token == ';' || item.token == '{') {
|
|
144
148
|
let node = await parseNode(tokens, context, stats, options, errors, src, map);
|
|
145
149
|
if (node != null) {
|
|
150
|
+
// @ts-ignore
|
|
146
151
|
stack.push(node);
|
|
147
152
|
// @ts-ignore
|
|
148
153
|
context = node;
|
|
149
154
|
}
|
|
150
155
|
else if (item.token == '{') {
|
|
151
|
-
// node == null
|
|
152
|
-
// consume and throw away until the closing '}' or EOF
|
|
153
156
|
let inBlock = 1;
|
|
154
157
|
do {
|
|
155
158
|
item = iter.next().value;
|
|
@@ -172,14 +175,18 @@ async function doParse(iterator, options = {}) {
|
|
|
172
175
|
const previousNode = stack.pop();
|
|
173
176
|
// @ts-ignore
|
|
174
177
|
context = stack[stack.length - 1] ?? ast;
|
|
178
|
+
// @ts-ignore
|
|
175
179
|
if (previousNode != null && previousNode.typ == EnumToken.InvalidRuleTokenType) {
|
|
180
|
+
// @ts-ignore
|
|
176
181
|
const index = context.chi.findIndex(node => node == previousNode);
|
|
177
182
|
if (index > -1) {
|
|
183
|
+
// @ts-ignore
|
|
178
184
|
context.chi.splice(index, 1);
|
|
179
185
|
}
|
|
180
186
|
}
|
|
181
187
|
// @ts-ignore
|
|
182
188
|
if (options.removeEmpty && previousNode != null && previousNode.chi.length == 0 && context.chi[context.chi.length - 1] == previousNode) {
|
|
189
|
+
// @ts-ignore
|
|
183
190
|
context.chi.pop();
|
|
184
191
|
}
|
|
185
192
|
tokens = [];
|
|
@@ -201,6 +208,7 @@ async function doParse(iterator, options = {}) {
|
|
|
201
208
|
context = stack[stack.length - 1] ?? ast;
|
|
202
209
|
// @ts-ignore
|
|
203
210
|
if (options.removeEmpty && previousNode != null && previousNode.chi.length == 0 && context.chi[context.chi.length - 1] == previousNode) {
|
|
211
|
+
// @ts-ignore
|
|
204
212
|
context.chi.pop();
|
|
205
213
|
continue;
|
|
206
214
|
}
|
|
@@ -250,25 +258,33 @@ async function doParse(iterator, options = {}) {
|
|
|
250
258
|
minify(ast, options, true, errors, false);
|
|
251
259
|
}
|
|
252
260
|
}
|
|
253
|
-
if (options.setParent) {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
261
|
+
// if (options.setParent) {
|
|
262
|
+
//
|
|
263
|
+
// const nodes: Array<AstRule | AstAtRule | AstRuleStyleSheet> = [ast];
|
|
264
|
+
// let node: AstNode;
|
|
265
|
+
//
|
|
266
|
+
// while ((node = nodes.shift()!)) {
|
|
267
|
+
//
|
|
268
|
+
// // @ts-ignore
|
|
269
|
+
// if (node.chi.length > 0) {
|
|
270
|
+
//
|
|
271
|
+
// // @ts-ignore
|
|
272
|
+
// for (const child of node.chi) {
|
|
273
|
+
//
|
|
274
|
+
// if (child.parent != node) {
|
|
275
|
+
//
|
|
276
|
+
// Object.defineProperty(child, 'parent', {...definedPropertySettings, value: node});
|
|
277
|
+
// }
|
|
278
|
+
//
|
|
279
|
+
// if ('chi' in child && child.chi.length > 0) {
|
|
280
|
+
//
|
|
281
|
+
// // @ts-ignore
|
|
282
|
+
// nodes.push(<AstRule | AstAtRule>child);
|
|
283
|
+
// }
|
|
284
|
+
// }
|
|
285
|
+
// }
|
|
286
|
+
// }
|
|
287
|
+
// }
|
|
272
288
|
const endTime = performance.now();
|
|
273
289
|
if (options.signal != null) {
|
|
274
290
|
options.signal.removeEventListener('abort', reject);
|
|
@@ -284,7 +300,6 @@ async function doParse(iterator, options = {}) {
|
|
|
284
300
|
total: `${(endTime - startTime).toFixed(2)}ms`
|
|
285
301
|
}
|
|
286
302
|
};
|
|
287
|
-
// });
|
|
288
303
|
}
|
|
289
304
|
async function parseNode(results, context, stats, options, errors, src, map) {
|
|
290
305
|
let tokens = [];
|
|
@@ -341,28 +356,36 @@ async function parseNode(results, context, stats, options, errors, src, map) {
|
|
|
341
356
|
if (tokens[0]?.typ == EnumToken.AtRuleTokenType) {
|
|
342
357
|
const atRule = tokens.shift();
|
|
343
358
|
const position = map.get(atRule);
|
|
344
|
-
if (atRule.val == 'charset') {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
359
|
+
// if (atRule.val == 'charset') {
|
|
360
|
+
//
|
|
361
|
+
// if (context.typ != EnumToken.StyleSheetNodeType || context.chi.some(t => t.typ != EnumToken.CDOCOMMTokenType && t.typ != EnumToken.CommentNodeType)) {
|
|
362
|
+
//
|
|
363
|
+
// errors.push({
|
|
364
|
+
// action: 'drop',
|
|
365
|
+
// message: 'doParse: invalid @charset',
|
|
366
|
+
// location: {src, ...position}
|
|
367
|
+
// });
|
|
368
|
+
//
|
|
369
|
+
// return null;
|
|
370
|
+
// }
|
|
371
|
+
//
|
|
372
|
+
// if (options.removeCharset) {
|
|
373
|
+
//
|
|
374
|
+
// return null;
|
|
375
|
+
// }
|
|
376
|
+
// }
|
|
357
377
|
// @ts-ignore
|
|
358
378
|
while ([EnumToken.WhitespaceTokenType].includes(tokens[0]?.typ)) {
|
|
359
379
|
tokens.shift();
|
|
360
380
|
}
|
|
361
381
|
if (atRule.val == 'import') {
|
|
362
382
|
// only @charset and @layer are accepted before @import
|
|
383
|
+
// @ts-ignore
|
|
363
384
|
if (context.chi.length > 0) {
|
|
385
|
+
// @ts-ignore
|
|
364
386
|
let i = context.chi.length;
|
|
365
387
|
while (i--) {
|
|
388
|
+
// @ts-ignore
|
|
366
389
|
const type = context.chi[i].typ;
|
|
367
390
|
if (type == EnumToken.CommentNodeType) {
|
|
368
391
|
continue;
|
|
@@ -371,6 +394,7 @@ async function parseNode(results, context, stats, options, errors, src, map) {
|
|
|
371
394
|
errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
|
|
372
395
|
return null;
|
|
373
396
|
}
|
|
397
|
+
// @ts-ignore
|
|
374
398
|
const name = context.chi[i].nam;
|
|
375
399
|
if (name != 'charset' && name != 'import' && name != 'layer') {
|
|
376
400
|
errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
|
|
@@ -428,6 +452,7 @@ async function parseNode(results, context, stats, options, errors, src, map) {
|
|
|
428
452
|
stats.importedBytesIn += root.stats.bytesIn;
|
|
429
453
|
if (root.ast.chi.length > 0) {
|
|
430
454
|
// @todo - filter charset, layer and scope
|
|
455
|
+
// @ts-ignore
|
|
431
456
|
context.chi.push(...root.ast.chi);
|
|
432
457
|
}
|
|
433
458
|
if (root.errors.length > 0) {
|
|
@@ -445,16 +470,24 @@ async function parseNode(results, context, stats, options, errors, src, map) {
|
|
|
445
470
|
// https://www.w3.org/TR/css-nesting-1/#conditionals
|
|
446
471
|
// allowed nesting at-rules
|
|
447
472
|
// there must be a top level rule in the stack
|
|
448
|
-
|
|
473
|
+
if (atRule.val == 'charset' && options.removeCharset) {
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
const t = parseAtRulePrelude(parseTokens(tokens, { minify: options.minify }), atRule);
|
|
477
|
+
const raw = t.reduce((acc, curr) => {
|
|
449
478
|
acc.push(renderToken(curr, { removeComments: true }));
|
|
450
479
|
return acc;
|
|
451
480
|
}, []);
|
|
452
481
|
const node = {
|
|
453
482
|
typ: EnumToken.AtRuleNodeType,
|
|
454
483
|
nam: renderToken(atRule, { removeComments: true }),
|
|
484
|
+
tokens: t,
|
|
455
485
|
val: raw.join('')
|
|
456
486
|
};
|
|
457
|
-
Object.
|
|
487
|
+
Object.defineProperties(node, {
|
|
488
|
+
tokens: { ...definedPropertySettings, enumerable: true, value: tokens.slice() },
|
|
489
|
+
raw: { ...definedPropertySettings, value: raw }
|
|
490
|
+
});
|
|
458
491
|
if (delim.typ == EnumToken.BlockStartTokenType) {
|
|
459
492
|
node.chi = [];
|
|
460
493
|
}
|
|
@@ -465,8 +498,16 @@ async function parseNode(results, context, stats, options, errors, src, map) {
|
|
|
465
498
|
if (options.sourcemap) {
|
|
466
499
|
node.loc = loc;
|
|
467
500
|
}
|
|
501
|
+
if (options.validation) {
|
|
502
|
+
const valid = validateAtRule(node, options, context);
|
|
503
|
+
if (valid.valid == ValidationLevel.Drop) {
|
|
504
|
+
// @ts-ignore
|
|
505
|
+
node.typ = EnumToken.InvalidAtRuleTokenType;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
468
508
|
// @ts-ignore
|
|
469
509
|
context.chi.push(node);
|
|
510
|
+
Object.defineProperty(node, 'parent', { ...definedPropertySettings, value: context });
|
|
470
511
|
return delim.typ == EnumToken.BlockStartTokenType ? node : null;
|
|
471
512
|
}
|
|
472
513
|
else {
|
|
@@ -474,7 +515,6 @@ async function parseNode(results, context, stats, options, errors, src, map) {
|
|
|
474
515
|
if (delim.typ == EnumToken.BlockStartTokenType) {
|
|
475
516
|
const position = map.get(tokens[0]);
|
|
476
517
|
const uniq = new Map;
|
|
477
|
-
// const uniqTokens: Token[][] = [[]];
|
|
478
518
|
parseTokens(tokens, { minify: true }).reduce((acc, curr, index, array) => {
|
|
479
519
|
if (curr.typ == EnumToken.CommentTokenType) {
|
|
480
520
|
return acc;
|
|
@@ -514,21 +554,28 @@ async function parseNode(results, context, stats, options, errors, src, map) {
|
|
|
514
554
|
}, uniq);
|
|
515
555
|
const ruleType = context.typ == EnumToken.AtRuleNodeType && context.nam == 'keyframes' ? EnumToken.KeyFrameRuleNodeType : EnumToken.RuleNodeType;
|
|
516
556
|
if (ruleType == EnumToken.RuleNodeType) {
|
|
517
|
-
|
|
518
|
-
if (
|
|
519
|
-
|
|
520
|
-
|
|
557
|
+
parseSelector(tokens);
|
|
558
|
+
if (options.validation) {
|
|
559
|
+
// @ts-ignore
|
|
560
|
+
const valid = validateSelector(tokens, options, context);
|
|
561
|
+
if (valid.valid != ValidationLevel.Valid) {
|
|
562
|
+
const node = {
|
|
563
|
+
typ: EnumToken.InvalidRuleTokenType,
|
|
564
|
+
// @ts-ignore
|
|
565
|
+
sel: tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), ''),
|
|
566
|
+
chi: []
|
|
567
|
+
};
|
|
568
|
+
errors.push({
|
|
569
|
+
action: 'drop',
|
|
570
|
+
message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"',
|
|
571
|
+
// @ts-ignore
|
|
572
|
+
location: { src, ...(map.get(valid.node) ?? position) }
|
|
573
|
+
});
|
|
521
574
|
// @ts-ignore
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
action: 'drop',
|
|
527
|
-
message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"',
|
|
528
|
-
location: { src, ...(map.get(valid.node) ?? position) }
|
|
529
|
-
});
|
|
530
|
-
context.chi.push(node);
|
|
531
|
-
return node;
|
|
575
|
+
context.chi.push(node);
|
|
576
|
+
Object.defineProperty(node, 'parent', { ...definedPropertySettings, value: context });
|
|
577
|
+
return node;
|
|
578
|
+
}
|
|
532
579
|
}
|
|
533
580
|
}
|
|
534
581
|
const node = {
|
|
@@ -536,6 +583,11 @@ async function parseNode(results, context, stats, options, errors, src, map) {
|
|
|
536
583
|
sel: [...uniq.keys()].join(','),
|
|
537
584
|
chi: []
|
|
538
585
|
};
|
|
586
|
+
Object.defineProperty(node, 'tokens', {
|
|
587
|
+
...definedPropertySettings,
|
|
588
|
+
enumerable: true,
|
|
589
|
+
value: tokens.slice()
|
|
590
|
+
});
|
|
539
591
|
let raw = [...uniq.values()];
|
|
540
592
|
Object.defineProperty(node, 'raw', {
|
|
541
593
|
enumerable: false,
|
|
@@ -552,18 +604,39 @@ async function parseNode(results, context, stats, options, errors, src, map) {
|
|
|
552
604
|
}
|
|
553
605
|
// @ts-ignore
|
|
554
606
|
context.chi.push(node);
|
|
607
|
+
Object.defineProperty(node, 'parent', { ...definedPropertySettings, value: context });
|
|
555
608
|
return node;
|
|
556
609
|
}
|
|
557
610
|
else {
|
|
558
|
-
// declaration
|
|
559
|
-
// @ts-ignore
|
|
560
611
|
let name = null;
|
|
561
|
-
// @ts-ignore
|
|
562
612
|
let value = null;
|
|
563
613
|
for (let i = 0; i < tokens.length; i++) {
|
|
564
614
|
if (tokens[i].typ == EnumToken.CommentTokenType) {
|
|
565
615
|
continue;
|
|
566
616
|
}
|
|
617
|
+
if (name == null && [EnumToken.IdenTokenType, EnumToken.DashedIdenTokenType].includes(tokens[i].typ)) {
|
|
618
|
+
name = tokens.slice(0, i + 1);
|
|
619
|
+
}
|
|
620
|
+
else if (name != null && funcLike.concat([
|
|
621
|
+
EnumToken.LiteralTokenType,
|
|
622
|
+
EnumToken.IdenTokenType, EnumToken.DashedIdenTokenType,
|
|
623
|
+
EnumToken.PseudoClassTokenType, EnumToken.PseudoClassFuncTokenType
|
|
624
|
+
]).includes(tokens[i].typ)) {
|
|
625
|
+
if (tokens[i].val.charAt(0) == ':') {
|
|
626
|
+
Object.assign(tokens[i], getTokenType(tokens[i].val.slice(1)));
|
|
627
|
+
}
|
|
628
|
+
if ('chi' in tokens[i]) {
|
|
629
|
+
tokens[i].typ = EnumToken.FunctionTokenType;
|
|
630
|
+
}
|
|
631
|
+
value = parseTokens(tokens.slice(i), {
|
|
632
|
+
parseColor: options.parseColor,
|
|
633
|
+
src: options.src,
|
|
634
|
+
resolveUrls: options.resolveUrls,
|
|
635
|
+
resolve: options.resolve,
|
|
636
|
+
cwd: options.cwd
|
|
637
|
+
});
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
567
640
|
if (tokens[i].typ == EnumToken.ColonTokenType) {
|
|
568
641
|
name = tokens.slice(0, i);
|
|
569
642
|
value = parseTokens(tokens.slice(i + 1), {
|
|
@@ -573,6 +646,7 @@ async function parseNode(results, context, stats, options, errors, src, map) {
|
|
|
573
646
|
resolve: options.resolve,
|
|
574
647
|
cwd: options.cwd
|
|
575
648
|
});
|
|
649
|
+
break;
|
|
576
650
|
}
|
|
577
651
|
}
|
|
578
652
|
if (name == null) {
|
|
@@ -606,15 +680,141 @@ async function parseNode(results, context, stats, options, errors, src, map) {
|
|
|
606
680
|
// @ts-ignore
|
|
607
681
|
val: value
|
|
608
682
|
};
|
|
609
|
-
const result =
|
|
683
|
+
const result = parseDeclarationNode(node, errors, src, position);
|
|
610
684
|
if (result != null) {
|
|
685
|
+
if (options.validation) ;
|
|
611
686
|
// @ts-ignore
|
|
612
|
-
context.chi.push(
|
|
687
|
+
context.chi.push(result);
|
|
688
|
+
Object.defineProperty(result, 'parent', { ...definedPropertySettings, value: context });
|
|
613
689
|
}
|
|
614
690
|
return null;
|
|
615
691
|
}
|
|
616
692
|
}
|
|
617
693
|
}
|
|
694
|
+
function parseAtRulePrelude(tokens, atRule) {
|
|
695
|
+
// @ts-ignore
|
|
696
|
+
for (const { value, parent } of walkValues(tokens, null, null, true)) {
|
|
697
|
+
if (value.typ == EnumToken.CommentTokenType ||
|
|
698
|
+
value.typ == EnumToken.WhitespaceTokenType ||
|
|
699
|
+
value.typ == EnumToken.CommaTokenType) {
|
|
700
|
+
continue;
|
|
701
|
+
}
|
|
702
|
+
if (atRule.val == 'page' && value.typ == EnumToken.PseudoClassTokenType) {
|
|
703
|
+
if ([':left', ':right', ':first', ':blank'].includes(value.val)) {
|
|
704
|
+
// @ts-ignore
|
|
705
|
+
value.typ = EnumToken.PseudoPageTokenType;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if (atRule.val == 'layer') {
|
|
709
|
+
if (parent == null && value.typ == EnumToken.LiteralTokenType) {
|
|
710
|
+
if (value.val.charAt(0) == '.') {
|
|
711
|
+
if (isIdent(value.val.slice(1))) {
|
|
712
|
+
// @ts-ignore
|
|
713
|
+
value.typ = EnumToken.ClassSelectorTokenType;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
if (value.typ == EnumToken.IdenTokenType) {
|
|
719
|
+
if (parent == null && mediaTypes.some((t) => {
|
|
720
|
+
if (value.val.localeCompare(t, 'en', { sensitivity: 'base' }) == 0) {
|
|
721
|
+
// @ts-ignore
|
|
722
|
+
value.typ = EnumToken.MediaFeatureTokenType;
|
|
723
|
+
return true;
|
|
724
|
+
}
|
|
725
|
+
return false;
|
|
726
|
+
})) {
|
|
727
|
+
continue;
|
|
728
|
+
}
|
|
729
|
+
if (value.typ == EnumToken.IdenTokenType && 'and'.localeCompare(value.val, 'en', { sensitivity: 'base' }) == 0) {
|
|
730
|
+
// @ts-ignore
|
|
731
|
+
value.typ = EnumToken.MediaFeatureAndTokenType;
|
|
732
|
+
continue;
|
|
733
|
+
}
|
|
734
|
+
if (value.typ == EnumToken.IdenTokenType && 'or'.localeCompare(value.val, 'en', { sensitivity: 'base' }) == 0) {
|
|
735
|
+
// @ts-ignore
|
|
736
|
+
value.typ = EnumToken.MediaFeatureOrTokenType;
|
|
737
|
+
continue;
|
|
738
|
+
}
|
|
739
|
+
if (value.typ == EnumToken.IdenTokenType &&
|
|
740
|
+
['not', 'only'].some((t) => t.localeCompare(value.val, 'en', { sensitivity: 'base' }) == 0)) {
|
|
741
|
+
// @ts-ignore
|
|
742
|
+
const array = parent?.chi ?? tokens;
|
|
743
|
+
const startIndex = array.indexOf(value);
|
|
744
|
+
let index = startIndex + 1;
|
|
745
|
+
if (index == 0) {
|
|
746
|
+
continue;
|
|
747
|
+
}
|
|
748
|
+
while (index < array.length && [EnumToken.CommentTokenType, EnumToken.WhitespaceTokenType].includes(array[index].typ)) {
|
|
749
|
+
index++;
|
|
750
|
+
}
|
|
751
|
+
if (array[index] == null || array[index].typ == EnumToken.CommaTokenType) {
|
|
752
|
+
continue;
|
|
753
|
+
}
|
|
754
|
+
Object.assign(array[startIndex], {
|
|
755
|
+
typ: value.val.toLowerCase() == 'not' ? EnumToken.MediaFeatureNotTokenType : EnumToken.MediaFeatureOnlyTokenType,
|
|
756
|
+
val: array[index]
|
|
757
|
+
});
|
|
758
|
+
array.splice(startIndex + 1, index - startIndex);
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
if (value.typ == EnumToken.ParensTokenType) {
|
|
763
|
+
// @todo parse range and declarations
|
|
764
|
+
// parseDeclaration(parent.chi);
|
|
765
|
+
let i;
|
|
766
|
+
let nameIndex = -1;
|
|
767
|
+
let valueIndex = -1;
|
|
768
|
+
for (let i = 0; i < value.chi.length; i++) {
|
|
769
|
+
if (value.chi[i].typ == EnumToken.CommentTokenType || value.chi[i].typ == EnumToken.WhitespaceTokenType) {
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
if (value.chi[i].typ == EnumToken.IdenTokenType) {
|
|
773
|
+
nameIndex = i;
|
|
774
|
+
}
|
|
775
|
+
break;
|
|
776
|
+
}
|
|
777
|
+
if (nameIndex == -1) {
|
|
778
|
+
continue;
|
|
779
|
+
}
|
|
780
|
+
for (let i = nameIndex + 1; i < value.chi.length; i++) {
|
|
781
|
+
if (value.chi[i].typ == EnumToken.CommentTokenType || value.chi[i].typ == EnumToken.WhitespaceTokenType) {
|
|
782
|
+
continue;
|
|
783
|
+
}
|
|
784
|
+
valueIndex = i;
|
|
785
|
+
break;
|
|
786
|
+
}
|
|
787
|
+
if (valueIndex == -1) {
|
|
788
|
+
// @ts-ignore
|
|
789
|
+
// value.chi[nameIndex].typ = EnumToken.MediaFeatureTokenType;
|
|
790
|
+
continue;
|
|
791
|
+
// return tokens;
|
|
792
|
+
}
|
|
793
|
+
for (i = nameIndex + 1; i < value.chi.length; i++) {
|
|
794
|
+
if ([
|
|
795
|
+
EnumToken.GtTokenType, EnumToken.LtTokenType,
|
|
796
|
+
EnumToken.GteTokenType, EnumToken.LteTokenType,
|
|
797
|
+
EnumToken.ColonTokenType
|
|
798
|
+
].includes(value.chi[valueIndex].typ)) {
|
|
799
|
+
const val = value.chi.splice(valueIndex, 1)[0];
|
|
800
|
+
const node = value.chi.splice(nameIndex, 1)[0];
|
|
801
|
+
while (value.chi[0]?.typ == EnumToken.WhitespaceTokenType) {
|
|
802
|
+
value.chi.shift();
|
|
803
|
+
}
|
|
804
|
+
const t = [{
|
|
805
|
+
typ: EnumToken.MediaQueryConditionTokenType,
|
|
806
|
+
l: node,
|
|
807
|
+
op: { typ: val.typ },
|
|
808
|
+
r: value.chi.slice()
|
|
809
|
+
}];
|
|
810
|
+
value.chi.length = 0;
|
|
811
|
+
value.chi.push(...t);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
return tokens;
|
|
817
|
+
}
|
|
618
818
|
function parseSelector(tokens) {
|
|
619
819
|
for (const { value, previousValue, nextValue, parent } of walkValues(tokens)) {
|
|
620
820
|
if (value.typ == EnumToken.CommentTokenType ||
|
|
@@ -754,6 +954,10 @@ function parseSelector(tokens) {
|
|
|
754
954
|
}
|
|
755
955
|
return tokens;
|
|
756
956
|
}
|
|
957
|
+
// export async function parseDeclarations(src: string, options: ParserOptions = {}): Promise<AstDeclaration[]> {
|
|
958
|
+
//
|
|
959
|
+
// return doParse(`.x{${src}`, options).then((result: ParseResult) => <AstDeclaration[]>(<AstRule>result.ast.chi[0]).chi.filter(t => t.typ == EnumToken.DeclarationNodeType));
|
|
960
|
+
// }
|
|
757
961
|
function parseString(src, options = { location: false }) {
|
|
758
962
|
return parseTokens([...tokenize(src)].map(t => {
|
|
759
963
|
const token = getTokenType(t.token, t.hint);
|
|
@@ -764,9 +968,6 @@ function parseString(src, options = { location: false }) {
|
|
|
764
968
|
}));
|
|
765
969
|
}
|
|
766
970
|
function getTokenType(val, hint) {
|
|
767
|
-
// if (val === '' && hint == null) {
|
|
768
|
-
// throw new Error('empty string?');
|
|
769
|
-
// }
|
|
770
971
|
if (hint != null) {
|
|
771
972
|
return enumTokenHints.has(hint) ? { typ: hint } : { typ: hint, val };
|
|
772
973
|
}
|
|
@@ -941,14 +1142,20 @@ function getTokenType(val, hint) {
|
|
|
941
1142
|
function parseTokens(tokens, options = {}) {
|
|
942
1143
|
for (let i = 0; i < tokens.length; i++) {
|
|
943
1144
|
const t = tokens[i];
|
|
1145
|
+
if (t.typ == EnumToken.PseudoClassFuncTokenType) {
|
|
1146
|
+
if (t.val.slice(1) in webkitPseudoAliasMap) {
|
|
1147
|
+
t.val = ':' + webkitPseudoAliasMap[t.val.slice(1)];
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
else if (t.typ == EnumToken.PseudoClassTokenType) {
|
|
1151
|
+
if (t.val.slice(1) in webkitPseudoAliasMap) {
|
|
1152
|
+
t.val = ':' + webkitPseudoAliasMap[t.val.slice(1)];
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
944
1155
|
if (t.typ == EnumToken.WhitespaceTokenType && ((i == 0 ||
|
|
945
1156
|
i + 1 == tokens.length ||
|
|
946
1157
|
[EnumToken.CommaTokenType, EnumToken.GteTokenType, EnumToken.LteTokenType, EnumToken.ColumnCombinatorTokenType].includes(tokens[i + 1].typ)) ||
|
|
947
|
-
(i > 0 &&
|
|
948
|
-
// tokens[i + 1]?.typ != Literal ||
|
|
949
|
-
// funcLike.includes(tokens[i - 1].typ) &&
|
|
950
|
-
// !['var', 'calc'].includes((<FunctionToken>tokens[i - 1]).val)))) &&
|
|
951
|
-
trimWhiteSpace.includes(tokens[i - 1].typ)))) {
|
|
1158
|
+
(i > 0 && trimWhiteSpace.includes(tokens[i - 1].typ)))) {
|
|
952
1159
|
tokens.splice(i--, 1);
|
|
953
1160
|
continue;
|
|
954
1161
|
}
|
|
@@ -1040,7 +1247,7 @@ function parseTokens(tokens, options = {}) {
|
|
|
1040
1247
|
}
|
|
1041
1248
|
}
|
|
1042
1249
|
else if ([
|
|
1043
|
-
EnumToken.DashMatchTokenType, EnumToken.StartMatchTokenType, EnumToken.ContainMatchTokenType, EnumToken.EndMatchTokenType, EnumToken.IncludeMatchTokenType
|
|
1250
|
+
EnumToken.DashMatchTokenType, EnumToken.StartMatchTokenType, EnumToken.ContainMatchTokenType, EnumToken.EndMatchTokenType, EnumToken.IncludeMatchTokenType, EnumToken.DelimTokenType
|
|
1044
1251
|
].includes(t.chi[m].typ)) {
|
|
1045
1252
|
let upper = m;
|
|
1046
1253
|
let lower = m;
|
|
@@ -1070,9 +1277,15 @@ function parseTokens(tokens, options = {}) {
|
|
|
1070
1277
|
Object.assign(val, { typ: EnumToken.IdenTokenType, val: slice });
|
|
1071
1278
|
}
|
|
1072
1279
|
}
|
|
1280
|
+
// @ts-ignore
|
|
1281
|
+
const typ = t.chi[m].typ;
|
|
1282
|
+
// @ts-ignore
|
|
1073
1283
|
t.chi[m] = {
|
|
1074
1284
|
typ: EnumToken.MatchExpressionTokenType,
|
|
1075
|
-
op:
|
|
1285
|
+
op: {
|
|
1286
|
+
// @ts-ignore
|
|
1287
|
+
typ: typ == EnumToken.DelimTokenType ? EnumToken.EqualMatchTokenType : typ
|
|
1288
|
+
},
|
|
1076
1289
|
l: t.chi[lower],
|
|
1077
1290
|
r: t.chi[upper]
|
|
1078
1291
|
};
|
|
@@ -1141,7 +1354,7 @@ function parseTokens(tokens, options = {}) {
|
|
|
1141
1354
|
// @ts-ignore
|
|
1142
1355
|
parseTokens(t.chi, options);
|
|
1143
1356
|
}
|
|
1144
|
-
if (t.typ == EnumToken.FunctionTokenType && t.val
|
|
1357
|
+
if (t.typ == EnumToken.FunctionTokenType && mathFuncs.includes(t.val)) {
|
|
1145
1358
|
for (const { value, parent } of walkValues(t.chi)) {
|
|
1146
1359
|
if (value.typ == EnumToken.WhitespaceTokenType) {
|
|
1147
1360
|
const p = (parent ?? t);
|
|
@@ -1261,4 +1474,4 @@ function parseTokens(tokens, options = {}) {
|
|
|
1261
1474
|
return tokens;
|
|
1262
1475
|
}
|
|
1263
1476
|
|
|
1264
|
-
export { doParse, parseSelector, parseString, parseTokens, urlTokenMatcher };
|
|
1477
|
+
export { doParse, parseAtRulePrelude, parseSelector, parseString, parseTokens, urlTokenMatcher };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EnumToken } from '../ast/types.js';
|
|
2
2
|
import '../ast/minify.js';
|
|
3
|
+
import '../ast/walk.js';
|
|
3
4
|
import './parse.js';
|
|
4
5
|
import { isWhiteSpace, isNewLine, isDigit, isNonPrintable } from '../syntax/syntax.js';
|
|
5
6
|
import './utils/config.js';
|
|
@@ -187,6 +188,13 @@ function* tokenize(stream) {
|
|
|
187
188
|
buffer = '';
|
|
188
189
|
}
|
|
189
190
|
break;
|
|
191
|
+
case '&':
|
|
192
|
+
if (buffer.length > 0) {
|
|
193
|
+
yield pushToken(buffer, parseInfo);
|
|
194
|
+
buffer = '';
|
|
195
|
+
}
|
|
196
|
+
yield pushToken(value, parseInfo);
|
|
197
|
+
break;
|
|
190
198
|
case '<':
|
|
191
199
|
if (buffer.length > 0) {
|
|
192
200
|
yield pushToken(buffer, parseInfo);
|
|
@@ -215,6 +223,13 @@ function* tokenize(stream) {
|
|
|
215
223
|
buffer = '';
|
|
216
224
|
}
|
|
217
225
|
break;
|
|
226
|
+
case '#':
|
|
227
|
+
if (buffer.length > 0) {
|
|
228
|
+
yield pushToken(buffer, parseInfo);
|
|
229
|
+
buffer = '';
|
|
230
|
+
}
|
|
231
|
+
buffer += value;
|
|
232
|
+
break;
|
|
218
233
|
case '\\':
|
|
219
234
|
// EOF
|
|
220
235
|
if (!(value = next(parseInfo))) {
|
|
@@ -319,7 +334,7 @@ function* tokenize(stream) {
|
|
|
319
334
|
case ':':
|
|
320
335
|
case ',':
|
|
321
336
|
case '=':
|
|
322
|
-
if (buffer.length > 0) {
|
|
337
|
+
if (buffer.length > 0 && buffer != ':') {
|
|
323
338
|
yield pushToken(buffer, parseInfo);
|
|
324
339
|
buffer = '';
|
|
325
340
|
}
|
|
@@ -329,8 +344,13 @@ function* tokenize(stream) {
|
|
|
329
344
|
yield pushToken(value + val, parseInfo, EnumToken.ContainMatchTokenType);
|
|
330
345
|
break;
|
|
331
346
|
}
|
|
332
|
-
if (value == ':'
|
|
333
|
-
|
|
347
|
+
if (value == ':') {
|
|
348
|
+
if (isWhiteSpace(val.codePointAt(0))) {
|
|
349
|
+
yield pushToken(value, parseInfo, EnumToken.ColonTokenType);
|
|
350
|
+
buffer = '';
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
buffer += value;
|
|
334
354
|
break;
|
|
335
355
|
}
|
|
336
356
|
yield pushToken(value, parseInfo);
|
|
@@ -7,7 +7,7 @@ import './config.js';
|
|
|
7
7
|
import '../../renderer/color/utils/constants.js';
|
|
8
8
|
import '../../renderer/sourcemap/lib/encode.js';
|
|
9
9
|
|
|
10
|
-
function
|
|
10
|
+
function parseDeclarationNode(node, errors, src, position) {
|
|
11
11
|
while (node.val[0]?.typ == EnumToken.WhitespaceTokenType) {
|
|
12
12
|
node.val.shift();
|
|
13
13
|
}
|
|
@@ -65,4 +65,4 @@ function parseGridTemplate(template) {
|
|
|
65
65
|
return buffer.length > 0 ? result + buffer : result;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
export {
|
|
68
|
+
export { parseDeclarationNode };
|