@tbela99/css-parser 0.8.0 → 0.9.1

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 (64) hide show
  1. package/.editorconfig +484 -0
  2. package/README.md +13 -8
  3. package/dist/index-umd-web.js +2451 -2554
  4. package/dist/index.cjs +2605 -2708
  5. package/dist/index.d.ts +73 -23
  6. package/dist/lib/ast/expand.js +29 -4
  7. package/dist/lib/ast/math/expression.js +1 -1
  8. package/dist/lib/ast/minify.js +31 -17
  9. package/dist/lib/ast/types.js +2 -0
  10. package/dist/lib/ast/walk.js +12 -0
  11. package/dist/lib/parser/declaration/map.js +59 -52
  12. package/dist/lib/parser/declaration/set.js +0 -12
  13. package/dist/lib/parser/parse.js +204 -139
  14. package/dist/lib/parser/tokenize.js +15 -3
  15. package/dist/lib/renderer/color/color.js +2 -2
  16. package/dist/lib/renderer/color/hex.js +1 -1
  17. package/dist/lib/renderer/color/hsl.js +1 -1
  18. package/dist/lib/renderer/color/hwb.js +2 -2
  19. package/dist/lib/renderer/color/lab.js +3 -2
  20. package/dist/lib/renderer/color/lch.js +1 -1
  21. package/dist/lib/renderer/color/oklab.js +2 -2
  22. package/dist/lib/renderer/color/oklch.js +1 -1
  23. package/dist/lib/renderer/color/p3.js +1 -1
  24. package/dist/lib/renderer/color/prophotoRgb.js +2 -2
  25. package/dist/lib/renderer/color/prophotorgb.js +2 -2
  26. package/dist/lib/renderer/color/rgb.js +1 -1
  27. package/dist/lib/renderer/color/srgb.js +2 -2
  28. package/dist/lib/renderer/color/utils/constants.js +1 -1
  29. package/dist/lib/renderer/color/xyz.js +2 -18
  30. package/dist/lib/renderer/color/xyzd50.js +20 -2
  31. package/dist/lib/renderer/render.js +37 -8
  32. package/dist/lib/renderer/sourcemap/sourcemap.js +1 -1
  33. package/dist/lib/syntax/syntax.js +337 -1
  34. package/dist/lib/validation/at-rules/container.js +353 -0
  35. package/dist/lib/validation/at-rules/counter-style.js +2 -2
  36. package/dist/lib/validation/at-rules/custom-media.js +52 -0
  37. package/dist/lib/validation/at-rules/document.js +40 -60
  38. package/dist/lib/validation/at-rules/else.js +5 -0
  39. package/dist/lib/validation/at-rules/font-feature-values.js +3 -0
  40. package/dist/lib/validation/at-rules/import.js +64 -59
  41. package/dist/lib/validation/at-rules/layer.js +3 -0
  42. package/dist/lib/validation/at-rules/media.js +118 -29
  43. package/dist/lib/validation/at-rules/supports.js +51 -20
  44. package/dist/lib/validation/at-rules/when.js +178 -0
  45. package/dist/lib/validation/atrule.js +25 -10
  46. package/dist/lib/validation/config.js +20 -15
  47. package/dist/lib/validation/config.json.js +242 -74
  48. package/dist/lib/validation/declaration.js +32 -10
  49. package/dist/lib/validation/parser/parse.js +87 -103
  50. package/dist/lib/validation/parser/types.js +2 -2
  51. package/dist/lib/validation/selector.js +6 -3
  52. package/dist/lib/validation/syntax.js +86 -6
  53. package/dist/lib/validation/syntaxes/complex-selector-list.js +16 -12
  54. package/dist/lib/validation/syntaxes/complex-selector.js +17 -247
  55. package/dist/lib/validation/syntaxes/compound-selector.js +226 -0
  56. package/dist/lib/validation/syntaxes/image.js +29 -0
  57. package/dist/lib/validation/syntaxes/keyframe-block-list.js +1 -1
  58. package/dist/lib/validation/syntaxes/keyframe-selector.js +1 -1
  59. package/dist/lib/validation/syntaxes/layer-name.js +5 -16
  60. package/dist/lib/validation/syntaxes/relative-selector-list.js +43 -13
  61. package/dist/lib/validation/utils/list.js +2 -2
  62. package/dist/node/index.js +1 -1
  63. package/dist/web/index.js +1 -1
  64. package/package.json +10 -9
@@ -5,7 +5,7 @@ import '../parser/parse.js';
5
5
  import '../renderer/color/utils/constants.js';
6
6
  import '../renderer/sourcemap/lib/encode.js';
7
7
  import '../parser/utils/config.js';
8
- import { getParsedSyntax, getSyntaxConfig } from './config.js';
8
+ import { getSyntaxConfig, getParsedSyntax } from './config.js';
9
9
  import { validateSyntax } from './syntax.js';
10
10
 
11
11
  function validateDeclaration(declaration, options, root) {
@@ -21,6 +21,7 @@ function validateDeclaration(declaration, options, root) {
21
21
  }
22
22
  // root is at-rule - check if declaration allowed
23
23
  if (root?.typ == EnumToken.AtRuleNodeType) {
24
+ //
24
25
  const syntax = getParsedSyntax("atRules" /* ValidationSyntaxGroupEnum.AtRules */, '@' + root.nam)?.[0];
25
26
  if (syntax != null) {
26
27
  if (!('chi' in syntax)) {
@@ -39,15 +40,36 @@ function validateDeclaration(declaration, options, root) {
39
40
  error: ''
40
41
  };
41
42
  }
42
- if (!(name in config.declarations) && !(name in config.syntaxes)) {
43
- return {
44
- valid: ValidationLevel.Drop,
45
- node: declaration,
46
- syntax: null,
47
- error: `unknown declaration "${declaration.nam}"`
48
- };
43
+ // console.error({syntax});
44
+ const config = getSyntaxConfig();
45
+ // @ts-ignore
46
+ const obj = config["atRules" /* ValidationSyntaxGroupEnum.AtRules */]['@' + root.nam];
47
+ if ('descriptors' in obj) {
48
+ const descriptors = obj.descriptors;
49
+ if (!(name in descriptors)) {
50
+ return {
51
+ valid: ValidationLevel.Drop,
52
+ node: declaration,
53
+ syntax: `<${declaration.nam}>`,
54
+ error: `declaration <${declaration.nam}> is not allowed in <@${root.nam}>`
55
+ };
56
+ }
57
+ const syntax = getParsedSyntax("atRules" /* ValidationSyntaxGroupEnum.AtRules */, ['@' + root.nam, 'descriptors', name]);
58
+ return validateSyntax(syntax, declaration.val, root, options);
49
59
  }
50
- return validateSyntax(syntax.chi, [declaration], root, options);
60
+ // console.error({name});
61
+ // if (!(name in config.declarations) && !(name in config.syntaxes)) {
62
+ //
63
+ // return {
64
+ //
65
+ // valid: ValidationLevel.Drop,
66
+ // node: declaration,
67
+ // syntax: null,
68
+ // error: `unknown declaration "${declaration.nam}"`
69
+ // }
70
+ // }
71
+ //
72
+ // return validateSyntax((syntax as ValidationAtRuleDefinitionToken).chi as ValidationToken[], [declaration], root, options);
51
73
  }
52
74
  }
53
75
  if (name.startsWith('--')) {
@@ -62,7 +84,7 @@ function validateDeclaration(declaration, options, root) {
62
84
  return {
63
85
  valid: ValidationLevel.Drop,
64
86
  node: declaration,
65
- syntax: null,
87
+ syntax: `<${declaration.nam}>`,
66
88
  error: `unknown declaration "${declaration.nam}"`
67
89
  };
68
90
  }
@@ -1,6 +1,20 @@
1
1
  import { ValidationTokenEnum } from './types.js';
2
2
  import { isIdent, isPseudo } from '../../syntax/syntax.js';
3
3
 
4
+ var WalkValidationTokenEnum;
5
+ (function (WalkValidationTokenEnum) {
6
+ WalkValidationTokenEnum[WalkValidationTokenEnum["IgnoreChildren"] = 0] = "IgnoreChildren";
7
+ WalkValidationTokenEnum[WalkValidationTokenEnum["IgnoreNode"] = 1] = "IgnoreNode";
8
+ WalkValidationTokenEnum[WalkValidationTokenEnum["IgnoreAll"] = 2] = "IgnoreAll";
9
+ })(WalkValidationTokenEnum || (WalkValidationTokenEnum = {}));
10
+ var WalkValidationTokenKeyTypeEnum;
11
+ (function (WalkValidationTokenKeyTypeEnum) {
12
+ WalkValidationTokenKeyTypeEnum["Array"] = "array";
13
+ WalkValidationTokenKeyTypeEnum["Children"] = "chi";
14
+ WalkValidationTokenKeyTypeEnum["Left"] = "l";
15
+ WalkValidationTokenKeyTypeEnum["Right"] = "r";
16
+ WalkValidationTokenKeyTypeEnum["Prelude"] = "prelude";
17
+ })(WalkValidationTokenKeyTypeEnum || (WalkValidationTokenKeyTypeEnum = {}));
4
18
  const skipped = [
5
19
  ValidationTokenEnum.Star,
6
20
  ValidationTokenEnum.HashMark,
@@ -167,13 +181,66 @@ function* tokenize(syntax, position = { ind: 0, lin: 1, col: 0 }, currentPositio
167
181
  yield getTokenType(buffer, position, currentPosition);
168
182
  }
169
183
  }
184
+ function columnCallback(token, parent, key) {
185
+ if (key == WalkValidationTokenKeyTypeEnum.Prelude) {
186
+ return WalkValidationTokenEnum.IgnoreAll;
187
+ }
188
+ if (token.typ == ValidationTokenEnum.ColumnToken || token.typ == ValidationTokenEnum.Whitespace) {
189
+ return WalkValidationTokenEnum.IgnoreNode;
190
+ }
191
+ return WalkValidationTokenEnum.IgnoreChildren;
192
+ }
193
+ function toColumnArray(ast, parent) {
194
+ const result = new Map;
195
+ // @ts-ignore
196
+ for (const { token } of walkValidationToken(ast, null, columnCallback)) {
197
+ result.set(JSON.stringify(token), token);
198
+ }
199
+ const node = {
200
+ typ: ValidationTokenEnum.ColumnArrayToken,
201
+ chi: [...result.values()]
202
+ };
203
+ if (parent != null) {
204
+ replaceNode(parent, ast, node);
205
+ }
206
+ return node;
207
+ }
208
+ function replaceNode(parent, target, node) {
209
+ if ('l' in parent && parent.l == target) {
210
+ parent.l = node;
211
+ }
212
+ if ('r' in parent && parent.r == target) {
213
+ parent.r = node;
214
+ }
215
+ if ('chi' in parent) {
216
+ // @ts-ignore
217
+ for (let i = 0; i < parent.chi.length; i++) {
218
+ // @ts-ignore
219
+ if (parent.chi[i] == target) {
220
+ // @ts-ignore
221
+ parent.chi[i] = node;
222
+ break;
223
+ }
224
+ }
225
+ }
226
+ }
227
+ function transform(context) {
228
+ for (const { token, parent } of walkValidationToken(context)) {
229
+ switch (token.typ) {
230
+ case ValidationTokenEnum.ColumnToken:
231
+ toColumnArray(token, parent);
232
+ break;
233
+ }
234
+ }
235
+ return context;
236
+ }
170
237
  function parseSyntax(syntax) {
171
238
  const root = Object.defineProperty({
172
239
  typ: ValidationTokenEnum.Root,
173
240
  chi: []
174
241
  }, 'pos', { ...objectProperties, value: { ind: 0, lin: 1, col: 0 } });
175
242
  // return minify(doParseSyntax(syntaxes, tokenize(syntaxes), root)) as ValidationRootToken;
176
- return minify(doParseSyntax(syntax, tokenize(syntax), root));
243
+ return minify(transform(doParseSyntax(syntax, tokenize(syntax), root)));
177
244
  }
178
245
  function matchParens(syntax, iterator) {
179
246
  let item;
@@ -882,96 +949,6 @@ function move(position, chr) {
882
949
  }
883
950
  return position;
884
951
  }
885
- function renderSyntax(token, parent) {
886
- let glue;
887
- switch (token.typ) {
888
- case ValidationTokenEnum.Root:
889
- return token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '');
890
- case ValidationTokenEnum.Whitespace:
891
- return ' ';
892
- case ValidationTokenEnum.ValidationFunctionDefinition:
893
- return '<' + token.val + '()>';
894
- case ValidationTokenEnum.HashMark:
895
- return '#';
896
- case ValidationTokenEnum.Pipe:
897
- return '|';
898
- case ValidationTokenEnum.Column:
899
- return '||';
900
- case ValidationTokenEnum.PipeToken:
901
- return token.chi.reduce((acc, curr) => acc + (acc.trim().length > 0 ? '|' : '') + curr.reduce((acc, curr) => acc + renderSyntax(curr), ''), '');
902
- case ValidationTokenEnum.ColumnToken:
903
- case ValidationTokenEnum.AmpersandToken:
904
- glue = token.typ == ValidationTokenEnum.ColumnToken ? '||' : '&&';
905
- return token.l.reduce((acc, curr) => acc + renderSyntax(curr), '') +
906
- glue +
907
- token.r.reduce((acc, curr) => acc + renderSyntax(curr), '');
908
- case ValidationTokenEnum.Function:
909
- case ValidationTokenEnum.PseudoClassFunctionToken:
910
- case ValidationTokenEnum.Parens:
911
- return token.val + '(' + token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '') + ')' + renderAttributes(token);
912
- case ValidationTokenEnum.Comma:
913
- return ',';
914
- case ValidationTokenEnum.Keyword:
915
- return token.val + renderAttributes(token);
916
- case ValidationTokenEnum.OpenBracket:
917
- return '[';
918
- case ValidationTokenEnum.Ampersand:
919
- return '&&';
920
- case ValidationTokenEnum.QuestionMark:
921
- return '?';
922
- case ValidationTokenEnum.Separator:
923
- return '/';
924
- case ValidationTokenEnum.Bracket:
925
- return '[' + token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '') + ']' + renderAttributes(token);
926
- case ValidationTokenEnum.PropertyType:
927
- return '<' + token.val + '>' + renderAttributes(token);
928
- case ValidationTokenEnum.DeclarationType:
929
- return "<'" + token.val + "'>" + renderAttributes(token);
930
- case ValidationTokenEnum.Number:
931
- case ValidationTokenEnum.PseudoClassToken:
932
- case ValidationTokenEnum.StringToken:
933
- return token.val + '';
934
- case ValidationTokenEnum.SemiColon:
935
- return ';';
936
- case ValidationTokenEnum.AtRule:
937
- return '@' + token.val;
938
- case ValidationTokenEnum.AtRuleDefinition:
939
- return '@' + token.val +
940
- (token.prelude == null ? '' : ' ' + token.prelude.reduce((acc, curr) => acc + renderSyntax(curr), '')) +
941
- (token.chi == null ? '' : ' {\n' + token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '')).slice(1, -1) + '\n}';
942
- case ValidationTokenEnum.Block:
943
- return '{' + token.chi.reduce((acc, t) => acc + renderSyntax(t), '') + '}';
944
- default:
945
- throw new Error('Unhandled token: ' + JSON.stringify({ token }));
946
- }
947
- }
948
- function renderAttributes(token) {
949
- let result = '';
950
- if (token.isList) {
951
- result += '#';
952
- }
953
- if (token.isOptional) {
954
- result += '?';
955
- }
956
- if (token.isRepeatableGroup) {
957
- result += '!';
958
- }
959
- if (token.isRepeatable) {
960
- result += '*';
961
- }
962
- if (token.atLeastOnce) {
963
- result += '+';
964
- }
965
- if (token.occurence != null) {
966
- if (token.occurence.max == 0 || token.occurence.max == token.occurence.min || Number.isNaN(token.occurence.max)) {
967
- result += '{' + token.occurence.min + '}';
968
- }
969
- else {
970
- result += '{' + token.occurence.min + ',' + token.occurence.max + '}';
971
- }
972
- }
973
- return result;
974
- }
975
952
  function minify(ast) {
976
953
  if (Array.isArray(ast)) {
977
954
  // @ts-ignore
@@ -1032,37 +1009,44 @@ function minify(ast) {
1032
1009
  }
1033
1010
  return ast;
1034
1011
  }
1035
- function* walkValidationToken(token, parent, callback) {
1012
+ function* walkValidationToken(token, parent, callback, key) {
1036
1013
  if (Array.isArray(token)) {
1037
1014
  for (const child of token) {
1038
- yield* walkValidationToken(child, parent);
1015
+ yield* walkValidationToken(child, parent, callback, WalkValidationTokenKeyTypeEnum.Array);
1039
1016
  }
1040
1017
  return;
1041
1018
  }
1042
- yield { token, parent };
1043
- if ('prelude' in token) {
1019
+ let action = null;
1020
+ if (callback != null) {
1021
+ // @ts-ignore
1022
+ action = callback(token, parent, key);
1023
+ }
1024
+ if (action != WalkValidationTokenEnum.IgnoreNode && action != WalkValidationTokenEnum.IgnoreAll) {
1025
+ yield { token, parent };
1026
+ }
1027
+ if (action != WalkValidationTokenEnum.IgnoreChildren && action != WalkValidationTokenEnum.IgnoreAll && 'prelude' in token) {
1044
1028
  for (const child of token.prelude) {
1045
- yield* walkValidationToken(child, token);
1029
+ yield* walkValidationToken(child, token, callback, WalkValidationTokenKeyTypeEnum.Prelude);
1046
1030
  }
1047
1031
  }
1048
- if ('chi' in token) {
1032
+ if (action != WalkValidationTokenEnum.IgnoreChildren && 'chi' in token) {
1049
1033
  // @ts-ignore
1050
1034
  for (const child of token.chi) {
1051
- yield* walkValidationToken(child, token);
1035
+ yield* walkValidationToken(child, token, callback, WalkValidationTokenKeyTypeEnum.Children);
1052
1036
  }
1053
1037
  }
1054
- if ('l' in token) {
1038
+ if (action != WalkValidationTokenEnum.IgnoreChildren && action != WalkValidationTokenEnum.IgnoreAll && 'l' in token) {
1055
1039
  // @ts-ignore
1056
1040
  for (const child of token.l) {
1057
- yield* walkValidationToken(child, token);
1041
+ yield* walkValidationToken(child, token, callback, WalkValidationTokenKeyTypeEnum.Left);
1058
1042
  }
1059
1043
  }
1060
- if ('r' in token) {
1044
+ if (action != WalkValidationTokenEnum.IgnoreChildren && action != WalkValidationTokenEnum.IgnoreAll && 'r' in token) {
1061
1045
  // @ts-ignore
1062
1046
  for (const child of token.r) {
1063
- yield* walkValidationToken(child, token);
1047
+ yield* walkValidationToken(child, token, callback, WalkValidationTokenKeyTypeEnum.Right);
1064
1048
  }
1065
1049
  }
1066
1050
  }
1067
1051
 
1068
- export { parseSyntax, renderSyntax, walkValidationToken };
1052
+ export { WalkValidationTokenEnum, WalkValidationTokenKeyTypeEnum, parseSyntax, walkValidationToken };
@@ -1,4 +1,3 @@
1
- const specialValues = ['inherit', 'initial', 'unset', 'revert', 'revert-layer'];
2
1
  var ValidationTokenEnum;
3
2
  (function (ValidationTokenEnum) {
4
3
  ValidationTokenEnum[ValidationTokenEnum["Root"] = 0] = "Root";
@@ -41,6 +40,7 @@ var ValidationTokenEnum;
41
40
  ValidationTokenEnum[ValidationTokenEnum["DeclarationDefinitionToken"] = 37] = "DeclarationDefinitionToken";
42
41
  ValidationTokenEnum[ValidationTokenEnum["SemiColon"] = 38] = "SemiColon";
43
42
  ValidationTokenEnum[ValidationTokenEnum["Character"] = 39] = "Character";
43
+ ValidationTokenEnum[ValidationTokenEnum["ColumnArrayToken"] = 40] = "ColumnArrayToken";
44
44
  })(ValidationTokenEnum || (ValidationTokenEnum = {}));
45
45
  var ValidationSyntaxGroupEnum;
46
46
  (function (ValidationSyntaxGroupEnum) {
@@ -51,4 +51,4 @@ var ValidationSyntaxGroupEnum;
51
51
  ValidationSyntaxGroupEnum["AtRules"] = "atRules";
52
52
  })(ValidationSyntaxGroupEnum || (ValidationSyntaxGroupEnum = {}));
53
53
 
54
- export { ValidationSyntaxGroupEnum, ValidationTokenEnum, specialValues };
54
+ export { ValidationSyntaxGroupEnum, ValidationTokenEnum };
@@ -8,11 +8,14 @@ import '../parser/utils/config.js';
8
8
  import { validateRelativeSelectorList } from './syntaxes/relative-selector-list.js';
9
9
  import './syntaxes/complex-selector.js';
10
10
  import { validateKeyframeBlockList } from './syntaxes/keyframe-block-list.js';
11
+ import './parser/types.js';
12
+ import './parser/parse.js';
13
+ import './config.js';
11
14
  import { validateSelectorList } from './syntaxes/selector-list.js';
12
15
 
13
16
  function validateSelector(selector, options, root) {
14
17
  if (root == null) {
15
- return validateRelativeSelectorList(selector, root);
18
+ return validateSelectorList(selector, root, options);
16
19
  }
17
20
  // @ts-ignore
18
21
  if (root.typ == EnumToken.AtRuleNodeType && root.nam.match(/^(-[a-z]+-)?keyframes$/)) {
@@ -25,14 +28,14 @@ function validateSelector(selector, options, root) {
25
28
  isNested++;
26
29
  if (isNested > 0) {
27
30
  // @ts-ignore
28
- return validateRelativeSelectorList(selector, root, { nestedSelector: true });
31
+ return validateRelativeSelectorList(selector, root, { ...(options ?? {}), nestedSelector: true });
29
32
  }
30
33
  }
31
34
  currentRoot = currentRoot.parent;
32
35
  }
33
36
  const nestedSelector = isNested > 0;
34
37
  // @ts-ignore
35
- return nestedSelector ? validateRelativeSelectorList(selector, root, { nestedSelector }) : validateSelectorList(selector, root, { nestedSelector });
38
+ return nestedSelector ? validateRelativeSelectorList(selector, root, { ...(options ?? {}), nestedSelector }) : validateSelectorList(selector, root, { ...(options ?? {}), nestedSelector });
36
39
  }
37
40
 
38
41
  export { validateSelector };
@@ -1,15 +1,16 @@
1
1
  import { ValidationTokenEnum, specialValues } from './parser/types.js';
2
- import './parser/parse.js';
2
+ import { renderSyntax } from './parser/parse.js';
3
3
  import { ValidationLevel, EnumToken, funcLike } from '../ast/types.js';
4
4
  import '../ast/minify.js';
5
5
  import '../ast/walk.js';
6
6
  import '../parser/parse.js';
7
7
  import { isLength } from '../syntax/syntax.js';
8
8
  import '../parser/utils/config.js';
9
- import '../renderer/color/utils/constants.js';
10
- import '../renderer/sourcemap/lib/encode.js';
11
- import { getParsedSyntax, getSyntaxConfig } from './config.js';
9
+ import { renderToken } from '../renderer/render.js';
10
+ import { getSyntaxConfig, getParsedSyntax } from './config.js';
12
11
  import { validateSelector } from './selector.js';
12
+ import './syntaxes/complex-selector.js';
13
+ import { validateImage } from './syntaxes/image.js';
13
14
 
14
15
  const config = getSyntaxConfig();
15
16
  function consumeToken(tokens) {
@@ -30,6 +31,12 @@ function splice(tokens, matches) {
30
31
  return tokens;
31
32
  }
32
33
  function validateSyntax(syntaxes, tokens, root, options, context = { level: 0 }) {
34
+ console.error(JSON.stringify({
35
+ syntax: syntaxes?.reduce?.((acc, curr) => acc + renderSyntax(curr), ''),
36
+ // syntaxes,
37
+ tokens: tokens.reduce((acc, curr) => acc + renderToken(curr), ''),
38
+ s: new Error('bar').stack
39
+ }, null, 1));
33
40
  if (syntaxes == null) {
34
41
  // @ts-ignore
35
42
  return {
@@ -485,7 +492,7 @@ function validateSyntax(syntaxes, tokens, root, options, context = { level: 0 })
485
492
  return result;
486
493
  }
487
494
  function isOptionalSyntax(syntaxes) {
488
- return syntaxes.every(t => t.typ == ValidationTokenEnum.Whitespace || t.isOptional || t.isRepeatable || (t.typ == ValidationTokenEnum.PropertyType && isOptionalSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, t.val) ?? getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, t.val))));
495
+ return syntaxes.length > 0 && syntaxes.every(t => t.typ == ValidationTokenEnum.Whitespace || t.isOptional || t.isRepeatable || (t.typ == ValidationTokenEnum.PropertyType && isOptionalSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, t.val) ?? getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, t.val) ?? [])));
489
496
  }
490
497
  function doValidateSyntax(syntax, token, tokens, root, options, context) {
491
498
  let valid = false;
@@ -706,7 +713,21 @@ function doValidateSyntax(syntax, token, tokens, root, options, context) {
706
713
  break;
707
714
  case ValidationTokenEnum.PropertyType:
708
715
  //
709
- if (['media-feature', 'mf-plain'].includes(syntax.val)) {
716
+ if ('image' == syntax.val) {
717
+ valid = token.typ == EnumToken.UrlFunctionTokenType || token.typ == EnumToken.ImageFunctionTokenType;
718
+ if (!valid) {
719
+ return {
720
+ valid: ValidationLevel.Drop,
721
+ matches: [],
722
+ node: token,
723
+ syntax,
724
+ error: 'unexpected <image>',
725
+ tokens
726
+ };
727
+ }
728
+ result = validateImage(token);
729
+ }
730
+ else if (['media-feature', 'mf-plain'].includes(syntax.val)) {
710
731
  valid = token.typ == EnumToken.DeclarationNodeType;
711
732
  result = {
712
733
  valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop,
@@ -751,6 +772,18 @@ function doValidateSyntax(syntax, token, tokens, root, options, context) {
751
772
  }
752
773
  else if (syntax.val == 'group-rule-body') {
753
774
  valid = [EnumToken.AtRuleNodeType, EnumToken.RuleNodeType].includes(token.typ);
775
+ if (!valid && token.typ == EnumToken.DeclarationNodeType && root?.typ == EnumToken.AtRuleNodeType && root.nam == 'media') {
776
+ // allowed only if nested rule
777
+ let parent = root;
778
+ while (parent != null) {
779
+ if (parent.typ == EnumToken.RuleNodeType) {
780
+ valid = true;
781
+ break;
782
+ }
783
+ // @ts-ignore
784
+ parent = parent.parent;
785
+ }
786
+ }
754
787
  // @ts-ignore
755
788
  result = {
756
789
  valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop,
@@ -1357,6 +1390,41 @@ function doValidateSyntax(syntax, token, tokens, root, options, context) {
1357
1390
  tokens
1358
1391
  };
1359
1392
  break;
1393
+ case ValidationTokenEnum.ColumnArrayToken:
1394
+ {
1395
+ matches = [];
1396
+ queue = [];
1397
+ const children = syntax.chi;
1398
+ let child;
1399
+ while (child = children.shift()) {
1400
+ result = validateSyntax([child], tokens, root, options, context);
1401
+ if (result.valid == ValidationLevel.Valid) {
1402
+ matches.push(child);
1403
+ consumeToken(tokens);
1404
+ token = tokens[0];
1405
+ if (queue.length > 0) {
1406
+ children.unshift(...queue);
1407
+ queue = [];
1408
+ }
1409
+ if (token == null) {
1410
+ break;
1411
+ }
1412
+ }
1413
+ else {
1414
+ queue.push(child);
1415
+ }
1416
+ }
1417
+ valid = matches.length > 0;
1418
+ result = {
1419
+ valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop,
1420
+ matches: valid ? [token] : [],
1421
+ node: valid ? null : token,
1422
+ syntax,
1423
+ error: valid ? '' : 'expecting token',
1424
+ tokens
1425
+ };
1426
+ }
1427
+ break;
1360
1428
  case ValidationTokenEnum.ColumnToken:
1361
1429
  children = [...syntax.l.slice(), ...syntax.r.slice()];
1362
1430
  matches = [];
@@ -1419,6 +1487,18 @@ function doValidateSyntax(syntax, token, tokens, root, options, context) {
1419
1487
  tokens
1420
1488
  };
1421
1489
  break;
1490
+ case ValidationTokenEnum.DeclarationDefinitionToken:
1491
+ if (token.typ != EnumToken.DeclarationNodeType || token.nam != syntax.nam) {
1492
+ return {
1493
+ valid: ValidationLevel.Drop,
1494
+ matches: [],
1495
+ node: token,
1496
+ syntax,
1497
+ error: '',
1498
+ tokens
1499
+ };
1500
+ }
1501
+ return validateSyntax([syntax.val], token.val, root, options, context);
1422
1502
  default:
1423
1503
  throw new Error('not implemented: ' + JSON.stringify({ syntax, token, tokens }, null, 1));
1424
1504
  }
@@ -1,4 +1,4 @@
1
- import { ValidationLevel, EnumToken } from '../../ast/types.js';
1
+ import { ValidationLevel } from '../../ast/types.js';
2
2
  import '../../ast/minify.js';
3
3
  import '../../ast/walk.js';
4
4
  import '../../parser/parse.js';
@@ -7,6 +7,7 @@ import '../../renderer/sourcemap/lib/encode.js';
7
7
  import '../../parser/utils/config.js';
8
8
  import { validateSelector } from './selector.js';
9
9
  import { consumeWhitespace } from '../utils/whitespace.js';
10
+ import { splitTokenList } from '../utils/list.js';
10
11
 
11
12
  function validateComplexSelectorList(tokens, root, options) {
12
13
  tokens = tokens.slice();
@@ -22,20 +23,23 @@ function validateComplexSelectorList(tokens, root, options) {
22
23
  tokens
23
24
  };
24
25
  }
25
- let i = -1;
26
- let j = 0;
27
26
  let result = null;
28
- while (i + 1 < tokens.length) {
29
- if (tokens[++i].typ == EnumToken.CommaTokenType) {
30
- result = validateSelector(tokens.slice(j, i), root, options);
31
- if (result.valid == ValidationLevel.Drop) {
32
- return result;
33
- }
34
- j = i + 1;
35
- i = j;
27
+ for (const t of splitTokenList(tokens)) {
28
+ result = validateSelector(t, root, options);
29
+ if (result.valid == ValidationLevel.Drop) {
30
+ return result;
36
31
  }
37
32
  }
38
- return validateSelector(i == j ? tokens.slice(i) : tokens.slice(j, i + 1), root, options);
33
+ // @ts-ignore
34
+ return result ?? {
35
+ valid: ValidationLevel.Drop,
36
+ matches: [],
37
+ // @ts-ignore
38
+ node: root,
39
+ syntax: null,
40
+ error: 'expecting complex selector list',
41
+ tokens
42
+ };
39
43
  }
40
44
 
41
45
  export { validateComplexSelectorList };