@tbela99/css-parser 0.9.0 → 1.0.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 (70) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +22 -12
  3. package/dist/index-umd-web.js +2678 -2838
  4. package/dist/index.cjs +2468 -2628
  5. package/dist/index.d.ts +71 -26
  6. package/dist/lib/ast/expand.js +15 -2
  7. package/dist/lib/ast/features/calc.js +7 -10
  8. package/dist/lib/ast/features/index.js +1 -0
  9. package/dist/lib/ast/features/inlinecssvariables.js +0 -5
  10. package/dist/lib/ast/features/prefix.js +2 -7
  11. package/dist/lib/ast/features/shorthand.js +6 -9
  12. package/dist/lib/ast/features/transform.js +60 -0
  13. package/dist/lib/ast/math/expression.js +14 -10
  14. package/dist/lib/ast/math/math.js +14 -2
  15. package/dist/lib/ast/minify.js +47 -6
  16. package/dist/lib/ast/transform/compute.js +336 -0
  17. package/dist/lib/ast/transform/convert.js +33 -0
  18. package/dist/lib/ast/transform/matrix.js +111 -0
  19. package/dist/lib/ast/transform/minify.js +296 -0
  20. package/dist/lib/ast/transform/perspective.js +10 -0
  21. package/dist/lib/ast/transform/rotate.js +40 -0
  22. package/dist/lib/ast/transform/scale.js +32 -0
  23. package/dist/lib/ast/transform/skew.js +23 -0
  24. package/dist/lib/ast/transform/translate.js +32 -0
  25. package/dist/lib/ast/transform/utils.js +198 -0
  26. package/dist/lib/ast/types.js +2 -0
  27. package/dist/lib/ast/walk.js +23 -17
  28. package/dist/lib/parser/parse.js +174 -127
  29. package/dist/lib/parser/utils/declaration.js +1 -1
  30. package/dist/lib/renderer/color/{colormix.js → color-mix.js} +6 -0
  31. package/dist/lib/renderer/color/color.js +96 -20
  32. package/dist/lib/renderer/color/hex.js +17 -7
  33. package/dist/lib/renderer/color/hsl.js +7 -2
  34. package/dist/lib/renderer/color/lab.js +10 -1
  35. package/dist/lib/renderer/color/lch.js +8 -0
  36. package/dist/lib/renderer/color/oklab.js +8 -0
  37. package/dist/lib/renderer/color/oklch.js +8 -0
  38. package/dist/lib/renderer/color/prophotorgb.js +2 -2
  39. package/dist/lib/renderer/color/relativecolor.js +10 -21
  40. package/dist/lib/renderer/color/rgb.js +10 -7
  41. package/dist/lib/renderer/color/srgb.js +30 -6
  42. package/dist/lib/renderer/color/utils/components.js +13 -2
  43. package/dist/lib/renderer/color/xyz.js +2 -18
  44. package/dist/lib/renderer/color/xyzd50.js +20 -2
  45. package/dist/lib/renderer/render.js +70 -32
  46. package/dist/lib/renderer/sourcemap/sourcemap.js +1 -1
  47. package/dist/lib/syntax/syntax.js +75 -56
  48. package/dist/lib/validation/at-rules/container.js +6 -6
  49. package/dist/lib/validation/at-rules/document.js +40 -60
  50. package/dist/lib/validation/at-rules/import.js +61 -59
  51. package/dist/lib/validation/at-rules/keyframes.js +1 -1
  52. package/dist/lib/validation/at-rules/media.js +1 -1
  53. package/dist/lib/validation/at-rules/supports.js +40 -9
  54. package/dist/lib/validation/atrule.js +0 -4
  55. package/dist/lib/validation/config.json.js +83 -35
  56. package/dist/lib/validation/parser/parse.js +1 -95
  57. package/dist/lib/validation/parser/types.js +1 -2
  58. package/dist/lib/validation/selector.js +5 -2
  59. package/dist/lib/validation/syntaxes/compound-selector.js +2 -2
  60. package/dist/lib/validation/syntaxes/keyframe-block-list.js +2 -2
  61. package/dist/lib/validation/syntaxes/keyframe-selector.js +11 -90
  62. package/dist/lib/validation/syntaxes/layer-name.js +5 -16
  63. package/dist/lib/validation/syntaxes/relative-selector.js +15 -14
  64. package/dist/lib/validation/utils/list.js +18 -1
  65. package/dist/node/load.js +1 -1
  66. package/package.json +13 -12
  67. package/dist/lib/renderer/color/prophotoRgb.js +0 -56
  68. package/dist/lib/validation/declaration.js +0 -102
  69. package/dist/lib/validation/syntax.js +0 -1475
  70. package/dist/lib/validation/syntaxes/image.js +0 -29
@@ -2,14 +2,14 @@ import { getAngle, color2srgbvalues, clamp } from './color/color.js';
2
2
  import { colorFuncColorSpace, COLORS_NAMES } from './color/utils/constants.js';
3
3
  import { getComponents } from './color/utils/components.js';
4
4
  import { reduceHexValue, srgb2hexvalues, rgb2hex, hsl2hex, hwb2hex, cmyk2hex, oklab2hex, oklch2hex, lab2hex, lch2hex } from './color/hex.js';
5
- import { EnumToken } from '../ast/types.js';
5
+ import { EnumToken, funcLike } from '../ast/types.js';
6
6
  import '../ast/minify.js';
7
7
  import '../ast/walk.js';
8
8
  import { expand } from '../ast/expand.js';
9
- import { colorMix } from './color/colormix.js';
9
+ import { colorMix } from './color/color-mix.js';
10
10
  import { parseRelativeColor } from './color/relativecolor.js';
11
11
  import { SourceMap } from './sourcemap/sourcemap.js';
12
- import { isColor, mathFuncs, isNewLine } from '../syntax/syntax.js';
12
+ import { isColor, pseudoElements, mathFuncs, isNewLine } from '../syntax/syntax.js';
13
13
 
14
14
  const colorsFunc = ['rgb', 'rgba', 'hsl', 'hsla', 'hwb', 'device-cmyk', 'color-mix', 'color', 'oklab', 'lab', 'oklch', 'lch', 'light-dark'];
15
15
  function reduceNumber(val) {
@@ -109,7 +109,7 @@ function doRender(data, options = {}) {
109
109
  return result;
110
110
  }
111
111
  function updateSourceMap(node, options, cache, sourcemap, position, str) {
112
- if ([EnumToken.RuleNodeType, EnumToken.AtRuleNodeType, EnumToken.KeyFrameRuleNodeType].includes(node.typ)) {
112
+ if ([EnumToken.RuleNodeType, EnumToken.AtRuleNodeType, EnumToken.KeyFrameRuleNodeType, EnumToken.KeyframeAtRuleNodeType].includes(node.typ)) {
113
113
  let src = node.loc?.src ?? '';
114
114
  let output = options.output ?? '';
115
115
  if (!(src in cache)) {
@@ -152,7 +152,7 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
152
152
  const indentSub = indents[level + 1];
153
153
  switch (data.typ) {
154
154
  case EnumToken.DeclarationNodeType:
155
- return `${data.nam}:${options.indent}${data.val.reduce(reducer, '')}`;
155
+ return `${data.nam}:${options.indent}${(options.minify ? filterValues(data.val) : data.val).reduce(reducer, '')}`;
156
156
  case EnumToken.CommentNodeType:
157
157
  case EnumToken.CDOCOMMNodeType:
158
158
  if (data.val.startsWith('/*# sourceMappingURL=')) {
@@ -181,7 +181,8 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
181
181
  case EnumToken.AtRuleNodeType:
182
182
  case EnumToken.RuleNodeType:
183
183
  case EnumToken.KeyFrameRuleNodeType:
184
- if (data.typ == EnumToken.AtRuleNodeType && !('chi' in data)) {
184
+ case EnumToken.KeyframeAtRuleNodeType:
185
+ if ([EnumToken.AtRuleNodeType, EnumToken.KeyframeAtRuleNodeType].includes(data.typ) && !('chi' in data)) {
185
186
  return `${indent}@${data.nam}${data.val === '' ? '' : options.indent || ' '}${data.val};`;
186
187
  }
187
188
  // @ts-ignore
@@ -191,7 +192,7 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
191
192
  str = options.removeComments && (!options.preserveLicense || !node.val.startsWith('/*!')) ? '' : node.val;
192
193
  }
193
194
  else if (node.typ == EnumToken.DeclarationNodeType) {
194
- if (node.val.length == 0) {
195
+ if (!node.nam.startsWith('--') && node.val.length == 0) {
195
196
  // @ts-ignore
196
197
  errors.push({
197
198
  action: 'ignore',
@@ -200,7 +201,7 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
200
201
  });
201
202
  return '';
202
203
  }
203
- str = `${node.nam}:${options.indent}${node.val.reduce(reducer, '').trimEnd()};`;
204
+ str = `${node.nam}:${options.indent}${(options.minify ? filterValues(node.val) : node.val).reduce(reducer, '').trimEnd()};`;
204
205
  }
205
206
  else if (node.typ == EnumToken.AtRuleNodeType && !('chi' in node)) {
206
207
  str = `${data.val === '' ? '' : options.indent || ' '}${data.val};`;
@@ -222,7 +223,7 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
222
223
  if (children.endsWith(';')) {
223
224
  children = children.slice(0, -1);
224
225
  }
225
- if (data.typ == EnumToken.AtRuleNodeType) {
226
+ if ([EnumToken.AtRuleNodeType, EnumToken.KeyframeAtRuleNodeType].includes(data.typ)) {
226
227
  return `@${data.nam}${data.val === '' ? '' : options.indent || ' '}${data.val}${options.indent}{${options.newLine}` + (children === '' ? '' : indentSub + children + options.newLine) + indent + `}`;
227
228
  }
228
229
  return data.sel + `${options.indent}{${options.newLine}` + (children === '' ? '' : indentSub + children + options.newLine) + indent + `}`;
@@ -258,20 +259,25 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
258
259
  if (isColor(token)) {
259
260
  // @ts-ignore
260
261
  token.typ = EnumToken.ColorTokenType;
262
+ // @ts-ignore
261
263
  if (token.chi[0].typ == EnumToken.IdenTokenType && token.chi[0].val == 'from') {
262
264
  // @ts-ignore
263
265
  token.cal = 'rel';
264
266
  }
265
- else if (token.val == 'color-mix' && token.chi[0].typ == EnumToken.IdenTokenType && token.chi[0].val == 'in') {
266
- // @ts-ignore
267
- token.cal = 'mix';
268
- }
269
- else {
270
- if (token.val == 'color') {
267
+ else { // @ts-ignore
268
+ if (token.val == 'color-mix' && token.chi[0].typ == EnumToken.IdenTokenType && token.chi[0].val == 'in') {
271
269
  // @ts-ignore
272
- token.cal = 'col';
270
+ token.cal = 'mix';
271
+ }
272
+ else {
273
+ // @ts-ignore
274
+ if (token.val == 'color') {
275
+ // @ts-ignore
276
+ token.cal = 'col';
277
+ }
278
+ // @ts-ignore
279
+ token.chi = token.chi.filter((t) => ![EnumToken.WhitespaceTokenType, EnumToken.CommaTokenType, EnumToken.CommentTokenType].includes(t.typ));
273
280
  }
274
- token.chi = token.chi.filter((t) => ![EnumToken.WhitespaceTokenType, EnumToken.CommaTokenType, EnumToken.CommentTokenType].includes(t.typ));
275
281
  }
276
282
  }
277
283
  }
@@ -338,22 +344,36 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
338
344
  if (value != null) {
339
345
  token = value;
340
346
  }
347
+ else if (!token.chi.some(t => t.typ == EnumToken.CommaTokenType)) {
348
+ token.chi = children.reduce((acc, curr, index) => {
349
+ if (acc.length > 0) {
350
+ acc.push({ typ: EnumToken.CommaTokenType });
351
+ }
352
+ acc.push(...curr);
353
+ return acc;
354
+ }, []);
355
+ }
341
356
  }
342
357
  if (token.cal == 'rel' && ['rgb', 'hsl', 'hwb', 'lab', 'lch', 'oklab', 'oklch', 'color'].includes(token.val)) {
343
358
  const chi = getComponents(token);
344
359
  const offset = token.val == 'color' ? 2 : 1;
345
- // @ts-ignore
346
- const color = chi[1];
347
- const components = parseRelativeColor(token.val == 'color' ? chi[offset].val : token.val, color, chi[offset + 1], chi[offset + 2], chi[offset + 3], chi[offset + 4]);
348
- if (components != null) {
349
- token.chi = [...(token.val == 'color' ? [chi[offset]] : []), ...Object.values(components)];
350
- delete token.cal;
360
+ if (chi != null) {
361
+ // @ts-ignore
362
+ const color = chi[1];
363
+ const components = parseRelativeColor(token.val == 'color' ? chi[offset].val : token.val, color, chi[offset + 1], chi[offset + 2], chi[offset + 3], chi[offset + 4]);
364
+ if (components != null) {
365
+ token.chi = [...(token.val == 'color' ? [chi[offset]] : []), ...Object.values(components)];
366
+ delete token.cal;
367
+ }
351
368
  }
352
369
  }
353
370
  if (token.val == 'color') {
354
371
  if (token.chi[0].typ == EnumToken.IdenTokenType && colorFuncColorSpace.includes(token.chi[0].val.toLowerCase())) {
355
- // @ts-ignore
356
- return reduceHexValue(srgb2hexvalues(...color2srgbvalues(token)));
372
+ const values = color2srgbvalues(token);
373
+ if (Array.isArray(values) && values.every(t => !Number.isNaN(t))) {
374
+ // @ts-ignore
375
+ return reduceHexValue(srgb2hexvalues(...values));
376
+ }
357
377
  }
358
378
  }
359
379
  if (token.cal != null) {
@@ -410,7 +430,7 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
410
430
  else if (token.val == 'lch') {
411
431
  value = lch2hex(token);
412
432
  }
413
- if (value !== '') {
433
+ if (value !== '' && value != null) {
414
434
  return reduceHexValue(value);
415
435
  }
416
436
  }
@@ -589,8 +609,9 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
589
609
  return '';
590
610
  }
591
611
  case EnumToken.PseudoClassTokenType:
612
+ case EnumToken.PseudoElementTokenType:
592
613
  // https://www.w3.org/TR/selectors-4/#single-colon-pseudos
593
- if (token.typ == EnumToken.PseudoClassTokenType && ['::before', '::after', '::first-line', '::first-letter'].includes(token.val)) {
614
+ if (token.typ == EnumToken.PseudoElementTokenType && pseudoElements.includes(token.val.slice(1))) {
594
615
  return token.val.slice(1);
595
616
  }
596
617
  case EnumToken.UrlTokenTokenType:
@@ -599,7 +620,11 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
599
620
  if (!('original' in token)) {
600
621
  // do not modify original token
601
622
  token = { ...token };
602
- Object.defineProperty(token, 'original', { enumerable: false, writable: false, value: token.val });
623
+ Object.defineProperty(token, 'original', {
624
+ enumerable: false,
625
+ writable: false,
626
+ value: token.val
627
+ });
603
628
  }
604
629
  // @ts-ignore
605
630
  if (!(token.original in cache)) {
@@ -632,7 +657,7 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
632
657
  case EnumToken.InvalidClassSelectorTokenType:
633
658
  return token.val;
634
659
  case EnumToken.DeclarationNodeType:
635
- return token.nam + ':' + token.val.reduce((acc, curr) => acc + renderToken(curr, options, cache), '');
660
+ return token.nam + ':' + (options.minify ? filterValues(token.val) : token.val).reduce((acc, curr) => acc + renderToken(curr, options, cache), '');
636
661
  case EnumToken.MediaQueryConditionTokenType:
637
662
  return renderToken(token.l, options, cache, reducer, errors) + renderToken(token.op, options, cache, reducer, errors) + token.r.reduce((acc, curr) => acc + renderToken(curr, options, cache), '');
638
663
  case EnumToken.MediaFeatureTokenType:
@@ -645,11 +670,24 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
645
670
  return 'and';
646
671
  case EnumToken.MediaFeatureOrTokenType:
647
672
  return 'or';
648
- default:
649
- throw new Error(`render: unexpected token ${JSON.stringify(token, null, 1)}`);
673
+ // default:
674
+ //
675
+ // throw new Error(`render: unexpected token ${JSON.stringify(token, null, 1)}`);
650
676
  }
651
677
  errors?.push({ action: 'ignore', message: `render: unexpected token ${JSON.stringify(token, null, 1)}` });
652
678
  return '';
653
679
  }
680
+ function filterValues(values) {
681
+ let i = 0;
682
+ for (; i < values.length; i++) {
683
+ if (values[i].typ == EnumToken.ImportantTokenType && values[i - 1]?.typ == EnumToken.WhitespaceTokenType) {
684
+ values.splice(i - 1, 1);
685
+ }
686
+ else if (funcLike.includes(values[i].typ) && !['var', 'calc'].includes(values[i].val) && values[i + 1]?.typ == EnumToken.WhitespaceTokenType) {
687
+ values.splice(i + 1, 1);
688
+ }
689
+ }
690
+ return values;
691
+ }
654
692
 
655
- export { colorsFunc, doRender, reduceNumber, renderToken };
693
+ export { colorsFunc, doRender, filterValues, reduceNumber, renderToken };
@@ -1,11 +1,11 @@
1
1
  import { encode } from './lib/encode.js';
2
2
 
3
3
  class SourceMap {
4
+ lastLocation = null;
4
5
  #version = 3;
5
6
  #sources = [];
6
7
  #map = new Map;
7
8
  #line = -1;
8
- lastLocation = null;
9
9
  add(source, original) {
10
10
  if (original.src !== '') {
11
11
  if (!this.#sources.includes(original.src)) {
@@ -19,12 +19,21 @@ const dimensionUnits = new Set([
19
19
  const fontFormat = ['collection', 'embedded-opentype', 'opentype', 'svg', 'truetype', 'woff', 'woff2'];
20
20
  const colorFontTech = ['color-colrv0', 'color-colrv1', 'color-svg', 'color-sbix', 'color-cbdt'];
21
21
  const fontFeaturesTech = ['features-opentype', 'features-aat', 'features-graphite', 'incremental-patch', 'incremental-range', 'incremental-auto', 'variations', 'palettes'];
22
+ const transformFunctions = [
23
+ 'translate', 'scale', 'rotate', 'skew', 'perspective',
24
+ 'translateX', 'translateY', 'translateZ',
25
+ 'scaleX', 'scaleY', 'scaleZ',
26
+ 'rotateX', 'rotateY', 'rotateZ',
27
+ 'skewX', 'skewY',
28
+ 'rotate3d', 'translate3d', 'scale3d', 'matrix', 'matrix3d'
29
+ ];
22
30
  // https://drafts.csswg.org/mediaqueries/#media-types
23
31
  const mediaTypes = ['all', 'print', 'screen',
24
32
  /* deprecated */
25
33
  'aural', 'braille', 'embossed', 'handheld', 'projection', 'tty', 'tv', 'speech'];
26
34
  // https://www.w3.org/TR/css-values-4/#math-function
27
35
  const mathFuncs = ['calc', 'clamp', 'min', 'max', 'round', 'mod', 'rem', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', 'pow', 'sqrt', 'hypot', 'log', 'exp', 'abs', 'sign'];
36
+ const pseudoElements = [':before', ':after', ':first-line', ':first-letter'];
28
37
  const webkitPseudoAliasMap = {
29
38
  '-webkit-autofill': 'autofill',
30
39
  '-webkit-any': 'is',
@@ -409,7 +418,9 @@ function isColor(token) {
409
418
  }
410
419
  let isLegacySyntax = false;
411
420
  if (token.typ == EnumToken.FunctionTokenType && token.chi.length > 0 && colorsFunc.includes(token.val)) {
421
+ // @ts-ignore
412
422
  if (token.val == 'light-dark') {
423
+ // @ts-ignore
413
424
  const children = token.chi.filter((t) => [EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.LiteralTokenType, EnumToken.ColorTokenType, EnumToken.FunctionTokenType, EnumToken.PercentageTokenType].includes(t.typ));
414
425
  if (children.length != 2) {
415
426
  return false;
@@ -418,7 +429,9 @@ function isColor(token) {
418
429
  return true;
419
430
  }
420
431
  }
432
+ // @ts-ignore
421
433
  if (token.val == 'color') {
434
+ // @ts-ignore
422
435
  const children = token.chi.filter((t) => [EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.LiteralTokenType, EnumToken.ColorTokenType, EnumToken.FunctionTokenType, EnumToken.PercentageTokenType].includes(t.typ));
423
436
  const isRelative = children[0].typ == EnumToken.IdenTokenType && children[0].val == 'from';
424
437
  if (children.length < 4 || children.length > 8) {
@@ -467,73 +480,79 @@ function isColor(token) {
467
480
  }
468
481
  return true;
469
482
  }
470
- else if (token.val == 'color-mix') {
471
- const children = token.chi.reduce((acc, t) => {
472
- if (t.typ == EnumToken.CommaTokenType) {
473
- acc.push([]);
474
- }
475
- else {
476
- if (![EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ)) {
477
- acc[acc.length - 1].push(t);
483
+ else { // @ts-ignore
484
+ if (token.val == 'color-mix') {
485
+ // @ts-ignore
486
+ const children = token.chi.reduce((acc, t) => {
487
+ if (t.typ == EnumToken.CommaTokenType) {
488
+ acc.push([]);
478
489
  }
479
- }
480
- return acc;
481
- }, [[]]);
482
- if (children.length == 3) {
483
- if (children[0].length > 3 ||
484
- children[0][0].typ != EnumToken.IdenTokenType ||
485
- children[0][0].val != 'in' ||
486
- !isColorspace(children[0][1]) ||
487
- (children[0].length == 3 && !isHueInterpolationMethod(children[0][2])) ||
488
- children[1].length > 2 ||
489
- children[1][0].typ != EnumToken.ColorTokenType ||
490
- children[2].length > 2 ||
491
- children[2][0].typ != EnumToken.ColorTokenType) {
492
- return false;
493
- }
494
- if (children[1].length == 2) {
495
- if (!(children[1][1].typ == EnumToken.PercentageTokenType || (children[1][1].typ == EnumToken.NumberTokenType && children[1][1].val == '0'))) {
496
- return false;
490
+ else {
491
+ if (![EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ)) {
492
+ acc[acc.length - 1].push(t);
493
+ }
497
494
  }
498
- }
499
- if (children[2].length == 2) {
500
- if (!(children[2][1].typ == EnumToken.PercentageTokenType || (children[2][1].typ == EnumToken.NumberTokenType && children[2][1].val == '0'))) {
495
+ return acc;
496
+ }, [[]]);
497
+ if (children.length == 3) {
498
+ if (children[0].length > 3 ||
499
+ children[0][0].typ != EnumToken.IdenTokenType ||
500
+ children[0][0].val != 'in' ||
501
+ !isColorspace(children[0][1]) ||
502
+ (children[0].length == 3 && !isHueInterpolationMethod(children[0][2])) ||
503
+ children[1].length > 2 ||
504
+ children[1][0].typ != EnumToken.ColorTokenType ||
505
+ children[2].length > 2 ||
506
+ children[2][0].typ != EnumToken.ColorTokenType) {
501
507
  return false;
502
508
  }
509
+ if (children[1].length == 2) {
510
+ if (!(children[1][1].typ == EnumToken.PercentageTokenType || (children[1][1].typ == EnumToken.NumberTokenType && children[1][1].val == '0'))) {
511
+ return false;
512
+ }
513
+ }
514
+ if (children[2].length == 2) {
515
+ if (!(children[2][1].typ == EnumToken.PercentageTokenType || (children[2][1].typ == EnumToken.NumberTokenType && children[2][1].val == '0'))) {
516
+ return false;
517
+ }
518
+ }
519
+ return true;
503
520
  }
504
- return true;
505
- }
506
- return false;
507
- }
508
- else {
509
- const keywords = ['from', 'none'];
510
- if (['rgb', 'hsl', 'hwb', 'lab', 'lch', 'oklab', 'oklch'].includes(token.val)) {
511
- keywords.push('alpha', ...token.val.slice(-3).split(''));
521
+ return false;
512
522
  }
513
- // @ts-ignore
514
- for (const v of token.chi) {
515
- if (v.typ == EnumToken.CommaTokenType) {
516
- isLegacySyntax = true;
523
+ else {
524
+ const keywords = ['from', 'none'];
525
+ // @ts-ignore
526
+ if (['rgb', 'hsl', 'hwb', 'lab', 'lch', 'oklab', 'oklch'].includes(token.val)) {
527
+ // @ts-ignore
528
+ keywords.push('alpha', ...token.val.slice(-3).split(''));
517
529
  }
518
- if (v.typ == EnumToken.IdenTokenType) {
519
- if (!(keywords.includes(v.val) || v.val.toLowerCase() in COLORS_NAMES)) {
520
- return false;
530
+ // @ts-ignore
531
+ for (const v of token.chi) {
532
+ if (v.typ == EnumToken.CommaTokenType) {
533
+ isLegacySyntax = true;
521
534
  }
522
- if (keywords.includes(v.val)) {
523
- if (isLegacySyntax) {
535
+ if (v.typ == EnumToken.IdenTokenType) {
536
+ if (!(keywords.includes(v.val) || v.val.toLowerCase() in COLORS_NAMES)) {
524
537
  return false;
525
538
  }
526
- if (v.val == 'from' && ['rgba', 'hsla'].includes(token.val)) {
527
- return false;
539
+ if (keywords.includes(v.val)) {
540
+ if (isLegacySyntax) {
541
+ return false;
542
+ }
543
+ // @ts-ignore
544
+ if (v.val == 'from' && ['rgba', 'hsla'].includes(token.val)) {
545
+ return false;
546
+ }
528
547
  }
548
+ continue;
549
+ }
550
+ if (v.typ == EnumToken.FunctionTokenType && (mathFuncs.includes(v.val) || v.val == 'var' || colorsFunc.includes(v.val))) {
551
+ continue;
552
+ }
553
+ if (![EnumToken.ColorTokenType, EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.AngleTokenType, EnumToken.PercentageTokenType, EnumToken.CommaTokenType, EnumToken.WhitespaceTokenType, EnumToken.LiteralTokenType].includes(v.typ)) {
554
+ return false;
529
555
  }
530
- continue;
531
- }
532
- if (v.typ == EnumToken.FunctionTokenType && (mathFuncs.includes(v.val) || v.val == 'var' || colorsFunc.includes(v.val))) {
533
- continue;
534
- }
535
- if (![EnumToken.ColorTokenType, EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.AngleTokenType, EnumToken.PercentageTokenType, EnumToken.CommaTokenType, EnumToken.WhitespaceTokenType, EnumToken.LiteralTokenType].includes(v.typ)) {
536
- return false;
537
556
  }
538
557
  }
539
558
  }
@@ -811,4 +830,4 @@ function isWhiteSpace(codepoint) {
811
830
  codepoint == 0xa || codepoint == 0xc || codepoint == 0xd;
812
831
  }
813
832
 
814
- export { colorFontTech, fontFeaturesTech, fontFormat, isAngle, isAtKeyword, isColor, isColorspace, isDigit, isDimension, isFlex, isFrequency, isFunction, isHash, isHexColor, isHueInterpolationMethod, isIdent, isIdentCodepoint, isIdentStart, isLength, isNewLine, isNonPrintable, isNumber, isPercentage, isPolarColorspace, isPseudo, isRectangularOrthogonalColorspace, isResolution, isTime, isWhiteSpace, mathFuncs, mediaTypes, mozExtensions, parseDimension, webkitExtensions, webkitPseudoAliasMap };
833
+ export { colorFontTech, fontFeaturesTech, fontFormat, isAngle, isAtKeyword, isColor, isColorspace, isDigit, isDimension, isFlex, isFrequency, isFunction, isHash, isHexColor, isHueInterpolationMethod, isIdent, isIdentCodepoint, isIdentStart, isLength, isNewLine, isNonPrintable, isNumber, isPercentage, isPolarColorspace, isPseudo, isRectangularOrthogonalColorspace, isResolution, isTime, isWhiteSpace, mathFuncs, mediaTypes, mozExtensions, parseDimension, pseudoElements, transformFunctions, webkitExtensions, webkitPseudoAliasMap };
@@ -95,10 +95,10 @@ function validateAtRuleContainerQueryList(tokens, atRule) {
95
95
  break;
96
96
  }
97
97
  token = queries[0];
98
- if (token.typ == EnumToken.MediaFeatureNotTokenType) {
98
+ if (token?.typ == EnumToken.MediaFeatureNotTokenType) {
99
99
  token = token.val;
100
100
  }
101
- if (token.typ != EnumToken.ParensTokenType && (token.typ != EnumToken.FunctionTokenType || !['scroll-state', 'style'].includes(token.val))) {
101
+ if (token?.typ != EnumToken.ParensTokenType && (token?.typ != EnumToken.FunctionTokenType || !['scroll-state', 'style'].includes(token.val))) {
102
102
  return {
103
103
  valid: ValidationLevel.Drop,
104
104
  matches: [],
@@ -108,7 +108,7 @@ function validateAtRuleContainerQueryList(tokens, atRule) {
108
108
  tokens
109
109
  };
110
110
  }
111
- if (token.typ == EnumToken.ParensTokenType) {
111
+ if (token?.typ == EnumToken.ParensTokenType) {
112
112
  result = validateContainerSizeFeature(token.chi, atRule);
113
113
  }
114
114
  else if (token.val == 'scroll-state') {
@@ -126,7 +126,7 @@ function validateAtRuleContainerQueryList(tokens, atRule) {
126
126
  break;
127
127
  }
128
128
  token = queries[0];
129
- if (token.typ != EnumToken.MediaFeatureAndTokenType && token.typ != EnumToken.MediaFeatureOrTokenType) {
129
+ if (token?.typ != EnumToken.MediaFeatureAndTokenType && token?.typ != EnumToken.MediaFeatureOrTokenType) {
130
130
  return {
131
131
  valid: ValidationLevel.Drop,
132
132
  matches: [],
@@ -137,9 +137,9 @@ function validateAtRuleContainerQueryList(tokens, atRule) {
137
137
  };
138
138
  }
139
139
  if (tokenType == null) {
140
- tokenType = token.typ;
140
+ tokenType = token?.typ;
141
141
  }
142
- if (tokenType != token.typ) {
142
+ if (tokenType == null || tokenType != token?.typ) {
143
143
  return {
144
144
  valid: ValidationLevel.Drop,
145
145
  matches: [],
@@ -6,6 +6,7 @@ import '../../renderer/color/utils/constants.js';
6
6
  import '../../renderer/sourcemap/lib/encode.js';
7
7
  import '../../parser/utils/config.js';
8
8
  import { consumeWhitespace } from '../utils/whitespace.js';
9
+ import { splitTokenList } from '../utils/list.js';
9
10
  import { validateURL } from '../syntaxes/url.js';
10
11
 
11
12
  function validateAtRuleDocument(atRule, options, root) {
@@ -34,71 +35,50 @@ function validateAtRuleDocument(atRule, options, root) {
34
35
  tokens
35
36
  };
36
37
  }
37
- if (tokens[0].typ == EnumToken.CommaTokenType) {
38
+ for (const t of splitTokenList(tokens)) {
39
+ if (t.length != 1) {
40
+ return {
41
+ valid: ValidationLevel.Drop,
42
+ matches: [],
43
+ node: t[0] ?? atRule,
44
+ syntax: '@document',
45
+ error: 'unexpected token',
46
+ tokens
47
+ };
48
+ }
38
49
  // @ts-ignore
39
- return {
40
- valid: ValidationLevel.Drop,
41
- matches: [],
42
- node: tokens[0],
43
- syntax: '@document',
44
- error: 'unexpected token',
45
- tokens
46
- };
47
- }
48
- while (tokens.length > 0) {
49
- if (tokens[0].typ == EnumToken.CommentTokenType) {
50
- tokens.shift();
51
- consumeWhitespace(tokens);
50
+ if ((t[0].typ != EnumToken.FunctionTokenType && t[0].typ != EnumToken.UrlFunctionTokenType) || !['url', 'url-prefix', 'domain', 'media-document', 'regexp'].some((f) => f.localeCompare(t[0].val, undefined, { sensitivity: 'base' }) == 0)) {
51
+ return {
52
+ valid: ValidationLevel.Drop,
53
+ matches: [],
54
+ node: t[0] ?? atRule,
55
+ syntax: '@document',
56
+ error: 'expecting any of url-prefix(), domain(), media-document(), regexp() but found ' + t[0].val,
57
+ tokens
58
+ };
52
59
  }
53
- result = validateURL(tokens[0]);
54
- if (result.valid == ValidationLevel.Valid) {
55
- tokens.shift();
56
- consumeWhitespace(tokens);
60
+ if (t[0].typ == EnumToken.UrlFunctionTokenType) {
61
+ result = validateURL(t[0]);
62
+ if (result?.valid == ValidationLevel.Drop) {
63
+ return result;
64
+ }
57
65
  continue;
58
66
  }
59
- if (tokens[0].typ == EnumToken.FunctionTokenType) {
60
- if (!['url-prefix', 'domain', 'media-document', 'regexp'].some((t) => t.localeCompare(tokens[0].val, undefined, { sensitivity: 'base' }) == 0)) {
61
- // @ts-ignore
62
- return {
63
- valid: ValidationLevel.Drop,
64
- matches: [],
65
- node: tokens[0],
66
- syntax: '@document',
67
- error: 'unexpected token',
68
- tokens
69
- };
70
- }
71
- const children = tokens[0].chi.slice();
72
- consumeWhitespace(children);
73
- if (children.length == 0) {
74
- // @ts-ignore
75
- return {
76
- valid: ValidationLevel.Drop,
77
- matches: [],
78
- node: tokens[0],
79
- syntax: '@document',
80
- error: 'expecting string argument',
81
- tokens
82
- };
83
- }
84
- if (children[0].typ == EnumToken.StringTokenType) {
85
- children.shift();
86
- consumeWhitespace(children);
87
- }
88
- if (children.length > 0) {
89
- // @ts-ignore
90
- return {
91
- valid: ValidationLevel.Drop,
92
- matches: [],
93
- node: children[0],
94
- syntax: '@document',
95
- error: 'unexpected token',
96
- tokens
97
- };
98
- }
99
- tokens.shift();
100
- consumeWhitespace(tokens);
67
+ const children = t[0].chi.slice();
68
+ consumeWhitespace(children);
69
+ if (children.length != 1 || (children[0].typ != EnumToken.StringTokenType && children[0].typ != EnumToken.UrlTokenTokenType)) {
70
+ // @ts-ignore
71
+ return {
72
+ valid: ValidationLevel.Drop,
73
+ matches: [],
74
+ node: tokens[0],
75
+ syntax: '@document',
76
+ error: 'expecting string argument',
77
+ tokens
78
+ };
101
79
  }
80
+ tokens.shift();
81
+ consumeWhitespace(tokens);
102
82
  }
103
83
  // @ts-ignore
104
84
  return {