@tbela99/css-parser 0.7.1 → 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.
Files changed (82) hide show
  1. package/README.md +136 -82
  2. package/dist/index-umd-web.js +6956 -51524
  3. package/dist/index.cjs +6955 -51528
  4. package/dist/index.d.ts +180 -65
  5. package/dist/lib/ast/expand.js +34 -9
  6. package/dist/lib/ast/features/calc.js +76 -12
  7. package/dist/lib/ast/features/inlinecssvariables.js +6 -1
  8. package/dist/lib/ast/features/prefix.js +17 -9
  9. package/dist/lib/ast/features/shorthand.js +1 -0
  10. package/dist/lib/ast/math/expression.js +299 -11
  11. package/dist/lib/ast/math/math.js +7 -1
  12. package/dist/lib/ast/minify.js +1 -1
  13. package/dist/lib/ast/types.js +58 -49
  14. package/dist/lib/ast/walk.js +80 -18
  15. package/dist/lib/parser/declaration/list.js +1 -0
  16. package/dist/lib/parser/declaration/map.js +1 -0
  17. package/dist/lib/parser/declaration/set.js +1 -0
  18. package/dist/lib/parser/parse.js +285 -72
  19. package/dist/lib/parser/tokenize.js +16 -3
  20. package/dist/lib/parser/utils/declaration.js +2 -2
  21. package/dist/lib/parser/utils/type.js +6 -6
  22. package/dist/lib/renderer/color/a98rgb.js +1 -0
  23. package/dist/lib/renderer/color/color.js +1 -0
  24. package/dist/lib/renderer/color/colormix.js +1 -0
  25. package/dist/lib/renderer/color/hex.js +1 -0
  26. package/dist/lib/renderer/color/hsl.js +1 -0
  27. package/dist/lib/renderer/color/hwb.js +1 -0
  28. package/dist/lib/renderer/color/lab.js +1 -0
  29. package/dist/lib/renderer/color/lch.js +1 -0
  30. package/dist/lib/renderer/color/oklab.js +1 -0
  31. package/dist/lib/renderer/color/oklch.js +1 -0
  32. package/dist/lib/renderer/color/p3.js +1 -0
  33. package/dist/lib/renderer/color/prophotoRgb.js +56 -0
  34. package/dist/lib/renderer/color/rec2020.js +1 -0
  35. package/dist/lib/renderer/color/relativecolor.js +52 -28
  36. package/dist/lib/renderer/color/rgb.js +1 -0
  37. package/dist/lib/renderer/color/srgb.js +1 -0
  38. package/dist/lib/renderer/color/utils/components.js +1 -0
  39. package/dist/lib/renderer/color/utils/constants.js +1 -0
  40. package/dist/lib/renderer/color/xyz.js +1 -0
  41. package/dist/lib/renderer/color/xyzd50.js +1 -0
  42. package/dist/lib/renderer/render.js +28 -6
  43. package/dist/lib/syntax/syntax.js +27 -4
  44. package/dist/lib/validation/at-rules/counter-style.js +78 -0
  45. package/dist/lib/validation/at-rules/document.js +114 -0
  46. package/dist/lib/validation/at-rules/font-feature-values.js +49 -0
  47. package/dist/lib/validation/at-rules/import.js +196 -0
  48. package/dist/lib/validation/at-rules/keyframes.js +70 -0
  49. package/dist/lib/validation/at-rules/layer.js +27 -0
  50. package/dist/lib/validation/at-rules/media.js +166 -0
  51. package/dist/lib/validation/at-rules/namespace.js +85 -0
  52. package/dist/lib/validation/at-rules/page-margin-box.js +56 -0
  53. package/dist/lib/validation/at-rules/page.js +88 -0
  54. package/dist/lib/validation/at-rules/supports.js +262 -0
  55. package/dist/lib/validation/atrule.js +172 -0
  56. package/dist/lib/validation/config.js +30 -2
  57. package/dist/lib/validation/config.json.js +1560 -50902
  58. package/dist/lib/validation/declaration.js +72 -0
  59. package/dist/lib/validation/parser/parse.js +1059 -7
  60. package/dist/lib/validation/parser/types.js +27 -12
  61. package/dist/lib/validation/selector.js +23 -444
  62. package/dist/lib/validation/syntax.js +1429 -0
  63. package/dist/lib/validation/syntaxes/complex-selector-list.js +41 -0
  64. package/dist/lib/validation/syntaxes/complex-selector.js +283 -0
  65. package/dist/lib/validation/syntaxes/family-name.js +91 -0
  66. package/dist/lib/validation/syntaxes/keyframe-block-list.js +27 -0
  67. package/dist/lib/validation/syntaxes/keyframe-selector.js +137 -0
  68. package/dist/lib/validation/syntaxes/layer-name.js +67 -0
  69. package/dist/lib/validation/syntaxes/relative-selector-list.js +27 -0
  70. package/dist/lib/validation/syntaxes/relative-selector.js +36 -0
  71. package/dist/lib/validation/syntaxes/selector-list.js +5 -0
  72. package/dist/lib/validation/syntaxes/selector.js +5 -0
  73. package/dist/lib/validation/syntaxes/url.js +75 -0
  74. package/dist/lib/validation/utils/list.js +24 -0
  75. package/dist/lib/validation/utils/whitespace.js +22 -0
  76. package/dist/node/index.js +4 -4
  77. package/dist/web/index.js +4 -0
  78. package/dist/web/load.js +1 -0
  79. package/package.json +15 -13
  80. package/dist/lib/ast/utils/minifyfeature.js +0 -9
  81. package/dist/lib/iterable/weakset.js +0 -58
  82. package/dist/lib/parser/utils/syntax.js +0 -450
@@ -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 { parseDeclaration } from './utils/declaration.js';
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: false,
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
- const nodes = [ast];
255
- let node;
256
- while ((node = nodes.shift())) {
257
- // @ts-ignore
258
- if (node.chi.length > 0) {
259
- // @ts-ignore
260
- for (const child of node.chi) {
261
- if (child.parent != node) {
262
- Object.defineProperty(child, 'parent', { ...definedPropertySettings, value: node });
263
- }
264
- if ('chi' in child && child.chi.length > 0) {
265
- // @ts-ignore
266
- nodes.push(child);
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
- if (position.ind > 0) {
346
- errors.push({
347
- action: 'drop',
348
- message: 'doParse: invalid @charset',
349
- location: { src, ...position }
350
- });
351
- return null;
352
- }
353
- if (options.removeCharset) {
354
- return null;
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
- const raw = parseTokens(tokens, { minify: options.minify }).reduce((acc, curr) => {
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.defineProperty(node, 'raw', { ...definedPropertySettings, value: raw });
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
- const valid = validateSelector(parseSelector(tokens), options, context);
518
- if (valid.valid != ValidationLevel.Valid) {
519
- const node = {
520
- typ: EnumToken.InvalidRuleTokenType,
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
- sel: tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), ''),
523
- chi: []
524
- };
525
- errors.push({
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 = parseDeclaration(node, errors, src, position);
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(node);
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: t.chi[m].typ,
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 == 'calc') {
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';
@@ -222,6 +223,13 @@ function* tokenize(stream) {
222
223
  buffer = '';
223
224
  }
224
225
  break;
226
+ case '#':
227
+ if (buffer.length > 0) {
228
+ yield pushToken(buffer, parseInfo);
229
+ buffer = '';
230
+ }
231
+ buffer += value;
232
+ break;
225
233
  case '\\':
226
234
  // EOF
227
235
  if (!(value = next(parseInfo))) {
@@ -326,7 +334,7 @@ function* tokenize(stream) {
326
334
  case ':':
327
335
  case ',':
328
336
  case '=':
329
- if (buffer.length > 0) {
337
+ if (buffer.length > 0 && buffer != ':') {
330
338
  yield pushToken(buffer, parseInfo);
331
339
  buffer = '';
332
340
  }
@@ -336,8 +344,13 @@ function* tokenize(stream) {
336
344
  yield pushToken(value + val, parseInfo, EnumToken.ContainMatchTokenType);
337
345
  break;
338
346
  }
339
- if (value == ':' && ':' == val) {
340
- buffer += value + next(parseInfo);
347
+ if (value == ':') {
348
+ if (isWhiteSpace(val.codePointAt(0))) {
349
+ yield pushToken(value, parseInfo, EnumToken.ColonTokenType);
350
+ buffer = '';
351
+ break;
352
+ }
353
+ buffer += value;
341
354
  break;
342
355
  }
343
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 parseDeclaration(node, errors, src, position) {
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 { parseDeclaration };
68
+ export { parseDeclarationNode };