@tbela99/css-parser 1.3.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +64 -48
  3. package/dist/config.json.js +3 -0
  4. package/dist/index-umd-web.js +2266 -631
  5. package/dist/index.cjs +2271 -620
  6. package/dist/index.d.ts +522 -181
  7. package/dist/lib/ast/expand.js +5 -10
  8. package/dist/lib/ast/features/calc.js +3 -2
  9. package/dist/lib/ast/features/inlinecssvariables.js +5 -3
  10. package/dist/lib/ast/features/prefix.js +1 -1
  11. package/dist/lib/ast/features/shorthand.js +1 -0
  12. package/dist/lib/ast/features/transform.js +13 -19
  13. package/dist/lib/ast/features/type.js +1 -1
  14. package/dist/lib/ast/minify.js +6 -3
  15. package/dist/lib/ast/transform/compute.js +2 -4
  16. package/dist/lib/ast/transform/matrix.js +20 -20
  17. package/dist/lib/ast/transform/minify.js +105 -12
  18. package/dist/lib/ast/transform/rotate.js +11 -11
  19. package/dist/lib/ast/transform/scale.js +6 -6
  20. package/dist/lib/ast/transform/skew.js +4 -4
  21. package/dist/lib/ast/transform/translate.js +3 -3
  22. package/dist/lib/ast/transform/utils.js +30 -37
  23. package/dist/lib/ast/types.js +76 -5
  24. package/dist/lib/ast/walk.js +77 -58
  25. package/dist/lib/fs/resolve.js +69 -10
  26. package/dist/lib/parser/declaration/list.js +6 -1
  27. package/dist/lib/parser/parse.js +1169 -312
  28. package/dist/lib/parser/tokenize.js +33 -20
  29. package/dist/lib/parser/utils/declaration.js +54 -0
  30. package/dist/lib/parser/utils/hash.js +86 -0
  31. package/dist/lib/parser/utils/text.js +8 -0
  32. package/dist/lib/renderer/render.js +26 -7
  33. package/dist/lib/syntax/color/relativecolor.js +0 -3
  34. package/dist/lib/syntax/syntax.js +36 -18
  35. package/dist/lib/validation/at-rules/container.js +11 -0
  36. package/dist/lib/validation/at-rules/counter-style.js +11 -0
  37. package/dist/lib/validation/at-rules/font-feature-values.js +11 -0
  38. package/dist/lib/validation/at-rules/keyframes.js +11 -0
  39. package/dist/lib/validation/at-rules/layer.js +11 -0
  40. package/dist/lib/validation/at-rules/media.js +11 -0
  41. package/dist/lib/validation/at-rules/page-margin-box.js +11 -0
  42. package/dist/lib/validation/at-rules/page.js +11 -0
  43. package/dist/lib/validation/at-rules/supports.js +11 -0
  44. package/dist/lib/validation/at-rules/when.js +11 -0
  45. package/dist/lib/validation/config.js +0 -2
  46. package/dist/lib/validation/config.json.js +36 -4
  47. package/dist/lib/validation/parser/parse.js +53 -2
  48. package/dist/lib/validation/syntax.js +204 -36
  49. package/dist/lib/validation/syntaxes/compound-selector.js +1 -2
  50. package/dist/lib/validation/syntaxes/relative-selector-list.js +2 -5
  51. package/dist/node.js +60 -18
  52. package/dist/types.d.ts +17 -0
  53. package/dist/types.js +20 -0
  54. package/dist/web.js +43 -17
  55. package/package.json +20 -17
  56. package/dist/lib/validation/parser/types.js +0 -54
@@ -12,6 +12,17 @@ import { validateMediaFeature, validateMediaCondition } from './media.js';
12
12
  import { validateSupportCondition } from './supports.js';
13
13
 
14
14
  function validateAtRuleWhen(atRule, options, root) {
15
+ if (!Array.isArray(atRule.chi)) {
16
+ // @ts-ignore
17
+ return {
18
+ valid: SyntaxValidationResult.Drop,
19
+ matches: [],
20
+ node: atRule,
21
+ syntax: '@' + atRule.nam,
22
+ error: 'expected supports body',
23
+ tokens: []
24
+ };
25
+ }
15
26
  const slice = Array.isArray(atRule.tokens) ? atRule.tokens.slice() : [];
16
27
  consumeWhitespace(slice);
17
28
  if (slice.length == 0) {
@@ -1,5 +1,4 @@
1
1
  import config from './config.json.js';
2
- import './parser/types.js';
3
2
  import { parseSyntax } from './parser/parse.js';
4
3
 
5
4
  const parsedSyntaxes = new Map();
@@ -51,7 +50,6 @@ function getParsedSyntax(group, key) {
51
50
  const index = group + '.' + keys.join('.');
52
51
  // @ts-ignore
53
52
  if (!parsedSyntaxes.has(index)) {
54
- // @ts-ignore
55
53
  const syntax = parseSyntax(obj.syntax);
56
54
  // @ts-ignore
57
55
  parsedSyntaxes.set(index, syntax.chi);
@@ -753,7 +753,7 @@ var declarations = {
753
753
  syntax: "[ <counter-name> <integer>? ]+ | none"
754
754
  },
755
755
  cursor: {
756
- syntax: "[ [ <url> [ <x> <y> ]? , ]* [ auto | default | none | context-menu | help | pointer | progress | wait | cell | crosshair | text | vertical-text | alias | copy | move | no-drop | not-allowed | e-resize | n-resize | ne-resize | nw-resize | s-resize | se-resize | sw-resize | w-resize | ew-resize | ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | all-scroll | zoom-in | zoom-out | grab | grabbing ] ] [ [ <url> [ <x> <y> ]? , ]* [ auto | default | none | context-menu | help | pointer | progress | wait | cell | crosshair | text | vertical-text | alias | copy | move | no-drop | not-allowed | e-resize | n-resize | ne-resize | nw-resize | s-resize | se-resize | sw-resize | w-resize | ew-resize | ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | all-scroll | zoom-in | zoom-out | grab | grabbing | hand | -webkit-grab | -webkit-grabbing | -webkit-zoom-in | -webkit-zoom-out | -moz-grab | -moz-grabbing | -moz-zoom-in | -moz-zoom-out ] ]"
756
+ syntax: "[ [ <url> [ <x> <y> ]? , ]* <cursor-predefined> ] [ [ <url> [ <x> <y> ]? , ]* [ auto | default | none | context-menu | help | pointer | progress | wait | cell | crosshair | text | vertical-text | alias | copy | move | no-drop | not-allowed | e-resize | n-resize | ne-resize | nw-resize | s-resize | se-resize | sw-resize | w-resize | ew-resize | ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | all-scroll | zoom-in | zoom-out | grab | grabbing | hand | -webkit-grab | -webkit-grabbing | -webkit-zoom-in | -webkit-zoom-out | -moz-grab | -moz-grabbing | -moz-zoom-in | -moz-zoom-out ] ]"
757
757
  },
758
758
  cx: {
759
759
  syntax: "<length> | <percentage>"
@@ -1981,6 +1981,12 @@ var declarations = {
1981
1981
  },
1982
1982
  "white-space-trim": {
1983
1983
  syntax: "none | discard-before || discard-after || discard-inner"
1984
+ },
1985
+ composes: {
1986
+ syntax: "<composes-selector>#"
1987
+ },
1988
+ "composes-selector": {
1989
+ syntax: "<ident>+ [from [global&&<string>]]?"
1984
1990
  }
1985
1991
  };
1986
1992
  var functions = {
@@ -2006,7 +2012,7 @@ var functions = {
2006
2012
  syntax: "atan2( <calc-sum>, <calc-sum> )"
2007
2013
  },
2008
2014
  attr: {
2009
- syntax: "attr( <attr-name> <type-or-unit>? [, <attr-fallback> ]? )"
2015
+ syntax: "attr( <attr-name> <attr-type>? , <declaration-value>? )"
2010
2016
  },
2011
2017
  blur: {
2012
2018
  syntax: "blur( <length>? )"
@@ -2359,7 +2365,7 @@ var syntaxes = {
2359
2365
  syntax: "scroll | fixed | local"
2360
2366
  },
2361
2367
  "attr()": {
2362
- syntax: "attr( <attr-name> <type-or-unit>? [, <attr-fallback> ]? )"
2368
+ syntax: "attr( <attr-name> <attr-type>? , <declaration-value>? )"
2363
2369
  },
2364
2370
  "attr-matcher": {
2365
2371
  syntax: "[ '~' | '|' | '^' | '$' | '*' ]? '='"
@@ -2367,6 +2373,9 @@ var syntaxes = {
2367
2373
  "attr-modifier": {
2368
2374
  syntax: "i | s"
2369
2375
  },
2376
+ "attr-type": {
2377
+ syntax: "type( <syntax> ) | raw-string | number | <attr-unit>"
2378
+ },
2370
2379
  "attribute-selector": {
2371
2380
  syntax: "'[' <wq-name> ']' | '[' <wq-name> <attr-matcher> [ <string-token> | <ident-token> ] <attr-modifier>? ']'"
2372
2381
  },
@@ -2580,6 +2589,9 @@ var syntaxes = {
2580
2589
  "cubic-bezier-easing-function": {
2581
2590
  syntax: "ease | ease-in | ease-out | ease-in-out | cubic-bezier( <number [0,1]> , <number> , <number [0,1]> , <number> )"
2582
2591
  },
2592
+ "cursor-predefined": {
2593
+ syntax: "auto | default | none | context-menu | help | pointer | progress | wait | cell | crosshair | text | vertical-text | alias | copy | move | no-drop | not-allowed | e-resize | n-resize | ne-resize | nw-resize | s-resize | se-resize | sw-resize | w-resize | ew-resize | ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | all-scroll | zoom-in | zoom-out | grab | grabbing"
2594
+ },
2583
2595
  "custom-color-space": {
2584
2596
  syntax: "<dashed-ident>"
2585
2597
  },
@@ -4190,7 +4202,27 @@ var atRules = {
4190
4202
  }
4191
4203
  },
4192
4204
  "@nest": {
4193
- syntax: "<complex-selector-list>"
4205
+ },
4206
+ "@stylistic": {
4207
+ syntax: " @stylistic { <feature-value-declaration-list> } "
4208
+ },
4209
+ "@historical-forms": {
4210
+ syntax: " @historical-forms { <feature-value-declaration-list> } "
4211
+ },
4212
+ "@styleset": {
4213
+ syntax: " @styleset { <feature-value-declaration-list> } "
4214
+ },
4215
+ "@character-variant": {
4216
+ syntax: " @character-variant { <feature-value-declaration-list> } "
4217
+ },
4218
+ "@swash": {
4219
+ syntax: " @swash { <feature-value-declaration-list> } "
4220
+ },
4221
+ "@ornaments": {
4222
+ syntax: " @ornaments { <feature-value-declaration-list> } "
4223
+ },
4224
+ "@annotation": {
4225
+ syntax: " @annotation { <feature-value-declaration-list> } "
4194
4226
  }
4195
4227
  };
4196
4228
  var config = {
@@ -1,4 +1,3 @@
1
- import { ValidationTokenEnum } from './types.js';
2
1
  import { isIdent, isPseudo } from '../../syntax/syntax.js';
3
2
  import { EnumToken } from '../../ast/types.js';
4
3
  import '../../ast/minify.js';
@@ -9,6 +8,58 @@ import '../../parser/utils/config.js';
9
8
  import '../../syntax/color/utils/constants.js';
10
9
  import '../../renderer/sourcemap/lib/encode.js';
11
10
 
11
+ var ValidationTokenEnum;
12
+ (function (ValidationTokenEnum) {
13
+ ValidationTokenEnum[ValidationTokenEnum["Root"] = 0] = "Root";
14
+ ValidationTokenEnum[ValidationTokenEnum["Keyword"] = 1] = "Keyword";
15
+ ValidationTokenEnum[ValidationTokenEnum["PropertyType"] = 2] = "PropertyType";
16
+ ValidationTokenEnum[ValidationTokenEnum["DeclarationType"] = 3] = "DeclarationType";
17
+ ValidationTokenEnum[ValidationTokenEnum["AtRule"] = 4] = "AtRule";
18
+ ValidationTokenEnum[ValidationTokenEnum["ValidationFunctionDefinition"] = 5] = "ValidationFunctionDefinition";
19
+ ValidationTokenEnum[ValidationTokenEnum["OpenBracket"] = 6] = "OpenBracket";
20
+ ValidationTokenEnum[ValidationTokenEnum["CloseBracket"] = 7] = "CloseBracket";
21
+ ValidationTokenEnum[ValidationTokenEnum["OpenParenthesis"] = 8] = "OpenParenthesis";
22
+ ValidationTokenEnum[ValidationTokenEnum["CloseParenthesis"] = 9] = "CloseParenthesis";
23
+ ValidationTokenEnum[ValidationTokenEnum["Comma"] = 10] = "Comma";
24
+ ValidationTokenEnum[ValidationTokenEnum["Pipe"] = 11] = "Pipe";
25
+ ValidationTokenEnum[ValidationTokenEnum["Column"] = 12] = "Column";
26
+ ValidationTokenEnum[ValidationTokenEnum["Star"] = 13] = "Star";
27
+ ValidationTokenEnum[ValidationTokenEnum["OpenCurlyBrace"] = 14] = "OpenCurlyBrace";
28
+ ValidationTokenEnum[ValidationTokenEnum["CloseCurlyBrace"] = 15] = "CloseCurlyBrace";
29
+ ValidationTokenEnum[ValidationTokenEnum["HashMark"] = 16] = "HashMark";
30
+ ValidationTokenEnum[ValidationTokenEnum["QuestionMark"] = 17] = "QuestionMark";
31
+ ValidationTokenEnum[ValidationTokenEnum["Function"] = 18] = "Function";
32
+ ValidationTokenEnum[ValidationTokenEnum["Number"] = 19] = "Number";
33
+ ValidationTokenEnum[ValidationTokenEnum["Whitespace"] = 20] = "Whitespace";
34
+ ValidationTokenEnum[ValidationTokenEnum["Parenthesis"] = 21] = "Parenthesis";
35
+ ValidationTokenEnum[ValidationTokenEnum["Bracket"] = 22] = "Bracket";
36
+ ValidationTokenEnum[ValidationTokenEnum["Block"] = 23] = "Block";
37
+ ValidationTokenEnum[ValidationTokenEnum["AtLeastOnce"] = 24] = "AtLeastOnce";
38
+ ValidationTokenEnum[ValidationTokenEnum["Separator"] = 25] = "Separator";
39
+ ValidationTokenEnum[ValidationTokenEnum["Exclamation"] = 26] = "Exclamation";
40
+ ValidationTokenEnum[ValidationTokenEnum["Ampersand"] = 27] = "Ampersand";
41
+ ValidationTokenEnum[ValidationTokenEnum["PipeToken"] = 28] = "PipeToken";
42
+ ValidationTokenEnum[ValidationTokenEnum["ColumnToken"] = 29] = "ColumnToken";
43
+ ValidationTokenEnum[ValidationTokenEnum["AmpersandToken"] = 30] = "AmpersandToken";
44
+ ValidationTokenEnum[ValidationTokenEnum["Parens"] = 31] = "Parens";
45
+ ValidationTokenEnum[ValidationTokenEnum["PseudoClassToken"] = 32] = "PseudoClassToken";
46
+ ValidationTokenEnum[ValidationTokenEnum["PseudoClassFunctionToken"] = 33] = "PseudoClassFunctionToken";
47
+ ValidationTokenEnum[ValidationTokenEnum["StringToken"] = 34] = "StringToken";
48
+ ValidationTokenEnum[ValidationTokenEnum["AtRuleDefinition"] = 35] = "AtRuleDefinition";
49
+ ValidationTokenEnum[ValidationTokenEnum["DeclarationNameToken"] = 36] = "DeclarationNameToken";
50
+ ValidationTokenEnum[ValidationTokenEnum["DeclarationDefinitionToken"] = 37] = "DeclarationDefinitionToken";
51
+ ValidationTokenEnum[ValidationTokenEnum["SemiColon"] = 38] = "SemiColon";
52
+ ValidationTokenEnum[ValidationTokenEnum["Character"] = 39] = "Character";
53
+ ValidationTokenEnum[ValidationTokenEnum["InfinityToken"] = 40] = "InfinityToken";
54
+ })(ValidationTokenEnum || (ValidationTokenEnum = {}));
55
+ var ValidationSyntaxGroupEnum;
56
+ (function (ValidationSyntaxGroupEnum) {
57
+ ValidationSyntaxGroupEnum["Declarations"] = "declarations";
58
+ ValidationSyntaxGroupEnum["Functions"] = "functions";
59
+ ValidationSyntaxGroupEnum["Syntaxes"] = "syntaxes";
60
+ ValidationSyntaxGroupEnum["Selectors"] = "selectors";
61
+ ValidationSyntaxGroupEnum["AtRules"] = "atRules";
62
+ })(ValidationSyntaxGroupEnum || (ValidationSyntaxGroupEnum = {}));
12
63
  const skipped = [
13
64
  ValidationTokenEnum.Star,
14
65
  ValidationTokenEnum.HashMark,
@@ -1040,4 +1091,4 @@ function minify(ast) {
1040
1091
  return ast;
1041
1092
  }
1042
1093
 
1043
- export { parseSyntax, renderSyntax };
1094
+ export { ValidationSyntaxGroupEnum, ValidationTokenEnum, parseSyntax, renderSyntax };
@@ -1,22 +1,132 @@
1
- import { ValidationTokenEnum } from './parser/types.js';
2
- import { renderSyntax } from './parser/parse.js';
3
- import { EnumToken, SyntaxValidationResult, ColorType } from '../ast/types.js';
1
+ import { ValidationTokenEnum, renderSyntax } from './parser/parse.js';
2
+ import { SyntaxValidationResult, EnumToken, ColorType } from '../ast/types.js';
4
3
  import '../ast/minify.js';
5
4
  import '../ast/walk.js';
6
5
  import '../parser/parse.js';
7
6
  import '../parser/tokenize.js';
8
7
  import '../parser/utils/config.js';
9
- import { wildCardFuncs, isIdentColor, mathFuncs } from '../syntax/syntax.js';
8
+ import { wildCardFuncs, isIdentColor, mathFuncs, isColor } from '../syntax/syntax.js';
10
9
  import { renderToken } from '../renderer/render.js';
11
10
  import '../renderer/sourcemap/lib/encode.js';
12
11
  import { getSyntaxConfig, getParsedSyntax, getSyntax } from './config.js';
13
12
  import './syntaxes/complex-selector.js';
14
13
  import { funcLike, colorsFunc } from '../syntax/color/utils/constants.js';
14
+ import '../../types.js';
15
15
  import '../ast/features/type.js';
16
16
 
17
17
  const config = getSyntaxConfig();
18
18
  // @ts-ignore
19
19
  const allValues = getSyntaxConfig()["declarations" /* ValidationSyntaxGroupEnum.Declarations */].all.syntax.trim().split(/[\s|]+/g);
20
+ /**
21
+ * Check if a node is allowed as child in a given context
22
+ * @param node
23
+ * @param context
24
+ */
25
+ function isNodeAllowedInContext(node, context) {
26
+ if (node.typ == EnumToken.CommentNodeType || context == null) {
27
+ return true;
28
+ }
29
+ switch (context?.typ) {
30
+ case EnumToken.StyleSheetNodeType:
31
+ case EnumToken.RuleNodeType:
32
+ return node.typ == EnumToken.RuleNodeType ||
33
+ node.typ == EnumToken.AtRuleNodeType ||
34
+ node.typ == EnumToken.KeyframesAtRuleNodeType ||
35
+ (node.typ == EnumToken.DeclarationNodeType && context.typ == EnumToken.RuleNodeType) ||
36
+ (node.typ == EnumToken.CDOCOMMNodeType && context.typ == EnumToken.StyleSheetNodeType);
37
+ case EnumToken.KeyframesAtRuleNodeType:
38
+ return node.typ == EnumToken.KeyFramesRuleNodeType;
39
+ case EnumToken.KeyFramesRuleNodeType:
40
+ return node.typ == EnumToken.DeclarationNodeType;
41
+ case EnumToken.AtRuleNodeType:
42
+ // @ts-ignore
43
+ const syntax = getParsedSyntax("atRules" /* ValidationSyntaxGroupEnum.AtRules */, '@' + context.nam)?.[0].chi ?? null;
44
+ //
45
+ if (syntax == null) {
46
+ // console.error(`syntax: Not found ${ValidationSyntaxGroupEnum.AtRules}@${(context as AstAtRule).nam}`);
47
+ return true;
48
+ }
49
+ const stack = syntax.slice();
50
+ for (const child of stack) {
51
+ if (Array.isArray(child)) {
52
+ stack.push(...child);
53
+ continue;
54
+ }
55
+ if ('chi' in child && Array.isArray(child.chi)) {
56
+ stack.push(...child.chi);
57
+ continue;
58
+ }
59
+ // @ts-ignore
60
+ if (child.l != null) {
61
+ // @ts-ignore
62
+ stack.push(child.l);
63
+ // @ts-ignore
64
+ if (child.r != null) {
65
+ // @ts-ignore
66
+ stack.push(...(Array.isArray(child.r) ? child.r : [child.r]));
67
+ }
68
+ continue;
69
+ }
70
+ if (node.typ == EnumToken.DeclarationNodeType) {
71
+ if (child.typ == ValidationTokenEnum.DeclarationDefinitionToken) {
72
+ if (node.nam == child.nam) {
73
+ return true;
74
+ }
75
+ }
76
+ }
77
+ if (child.typ == ValidationTokenEnum.PropertyType) {
78
+ if (['group-rule-body', 'block-contents', 'rule-list', 'stylesheet'].includes(child.val)) {
79
+ if ((node.typ == EnumToken.RuleNodeType ||
80
+ node.typ == EnumToken.AtRuleNodeType ||
81
+ node.typ == EnumToken.KeyframesAtRuleNodeType)) {
82
+ return true;
83
+ }
84
+ if (node.typ == EnumToken.DeclarationNodeType) {
85
+ let parent = node.parent;
86
+ while (parent != null) {
87
+ if (parent.parent?.typ == EnumToken.RuleNodeType) {
88
+ return true;
89
+ }
90
+ parent = parent.parent;
91
+ }
92
+ }
93
+ }
94
+ if (['declaration-list', 'feature-value-declaration'].includes(child.val) && node.typ == EnumToken.DeclarationNodeType) {
95
+ return true;
96
+ }
97
+ if (child.val == 'page-body' && (node.typ == EnumToken.DeclarationNodeType || (node.typ == EnumToken.AtRuleNodeType && [
98
+ 'top-left-corner', 'top-left', 'top-center', 'top-right', 'top-right-corner',
99
+ 'bottom-left-corner', 'bottom-left', 'bottom-center', 'bottom-right', 'bottom-right-corner',
100
+ 'left-top', 'left-middle', 'left-bottom', 'right-top', 'right-middle', 'right-bottom'
101
+ ].includes(node.nam)))) {
102
+ return true;
103
+ }
104
+ if (child.val == 'feature-value-block-list' &&
105
+ (node.typ == EnumToken.AtRuleNodeType && ['stylistic', 'historical-forms', 'styleset', 'character-variant', 'swash', 'ornaments', 'annotation'].includes(node.nam))) {
106
+ return true;
107
+ }
108
+ if (['feature-value-declaration-list', 'feature-value-declaration'].includes(child.val) && node.typ == EnumToken.DeclarationNodeType) {
109
+ return true;
110
+ }
111
+ if (child.val == 'page-body') {
112
+ if (node.typ == EnumToken.DeclarationNodeType) {
113
+ return true;
114
+ }
115
+ }
116
+ // console.error(`isNodeAllowedInContext: Not found ${(child as ValidationPropertyToken).val}`, {
117
+ // child,
118
+ // node
119
+ // });
120
+ }
121
+ }
122
+ break;
123
+ }
124
+ return false;
125
+ }
126
+ /**
127
+ * Create a syntax validation context from a list of tokens
128
+ * @param input
129
+ */
20
130
  function createContext(input) {
21
131
  const values = input.slice();
22
132
  const result = values.filter(token => token.typ != EnumToken.CommentTokenType).slice();
@@ -77,7 +187,22 @@ function createContext(input) {
77
187
  }
78
188
  };
79
189
  }
80
- function evaluateSyntax(node, options) {
190
+ /**
191
+ * Evaluate the validity of the syntax of a node
192
+ * @param node
193
+ * @param parent
194
+ * @param options
195
+ */
196
+ function evaluateSyntax(node, parent, options) {
197
+ if (node.validSyntax) {
198
+ return {
199
+ valid: SyntaxValidationResult.Valid,
200
+ node,
201
+ syntax: null,
202
+ error: '',
203
+ context: []
204
+ };
205
+ }
81
206
  let ast;
82
207
  let result;
83
208
  switch (node.typ) {
@@ -85,25 +210,34 @@ function evaluateSyntax(node, options) {
85
210
  if (node.nam.startsWith('--')) {
86
211
  break;
87
212
  }
213
+ let token = null;
214
+ let values = node.val.slice();
88
215
  ast = getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, node.nam);
89
- if (ast != null) {
90
- let token = null;
91
- const values = node.val.slice();
92
- while (values.length > 0) {
93
- token = values.at(-1);
94
- if (token.typ == EnumToken.WhitespaceTokenType || token.typ == EnumToken.CommentTokenType) {
216
+ while (values.length > 0) {
217
+ token = values.at(-1);
218
+ if (token.typ == EnumToken.WhitespaceTokenType || token.typ == EnumToken.CommentTokenType) {
219
+ values.pop();
220
+ }
221
+ else {
222
+ if (token.typ == EnumToken.ImportantTokenType) {
95
223
  values.pop();
96
- }
97
- else {
98
- if (token.typ == EnumToken.ImportantTokenType) {
224
+ if (values.at(-1)?.typ == EnumToken.WhitespaceTokenType) {
99
225
  values.pop();
100
- if (values.at(-1)?.typ == EnumToken.WhitespaceTokenType) {
101
- values.pop();
102
- }
103
226
  }
104
- break;
227
+ }
228
+ break;
229
+ }
230
+ }
231
+ if (ast == null) {
232
+ if (parent?.typ == EnumToken.AtRuleNodeType) {
233
+ ast = (getParsedSyntax("atRules" /* ValidationSyntaxGroupEnum.AtRules */, ['@' + parent.nam, 'descriptors', node.nam]));
234
+ if (ast == null) {
235
+ ast = (getParsedSyntax("atRules" /* ValidationSyntaxGroupEnum.AtRules */, ['@' + parent.nam, 'descriptors', node.nam]) ?? getParsedSyntax("atRules" /* ValidationSyntaxGroupEnum.AtRules */, '@' + parent.nam))?.[0]?.chi;
236
+ values = [{ ...node, val: values }];
105
237
  }
106
238
  }
239
+ }
240
+ if (ast != null) {
107
241
  result = doEvaluateSyntax(ast, createContext(values), { ...options, visited: new WeakMap() });
108
242
  if (result.valid == SyntaxValidationResult.Valid && !result.context.done()) {
109
243
  let token = null;
@@ -195,7 +329,7 @@ function doEvaluateSyntax(syntaxes, context, options) {
195
329
  continue;
196
330
  }
197
331
  }
198
- else if (options.occurence !== false && syntax.occurence != null) {
332
+ else if (options.occurrence !== false && syntax.occurence != null) {
199
333
  result = matchOccurence(syntax, context, options);
200
334
  }
201
335
  else if (options.atLeastOnce !== false && syntax.atLeastOnce) {
@@ -284,7 +418,7 @@ function matchList(syntax, context, options) {
284
418
  result = doEvaluateSyntax([syntax], createContext(tokens), {
285
419
  ...options,
286
420
  isList: false,
287
- occurence: false
421
+ occurrence: false
288
422
  });
289
423
  if (result.valid == SyntaxValidationResult.Valid) {
290
424
  context = con.clone();
@@ -319,7 +453,7 @@ function matchOccurence(syntax, context, options) {
319
453
  let counter = 0;
320
454
  let result;
321
455
  do {
322
- result = match(syntax, context.clone(), { ...options, occurence: false });
456
+ result = match(syntax, context.clone(), { ...options, occurrence: false });
323
457
  if (result.valid == SyntaxValidationResult.Drop) {
324
458
  break;
325
459
  }
@@ -370,7 +504,7 @@ function match(syntax, context, options) {
370
504
  ...options,
371
505
  isRepeatable: null,
372
506
  isList: null,
373
- occurence: null,
507
+ occurrence: null,
374
508
  atLeastOnce: null
375
509
  });
376
510
  if (result.valid == SyntaxValidationResult.Valid) {
@@ -382,7 +516,7 @@ function match(syntax, context, options) {
382
516
  case ValidationTokenEnum.Keyword:
383
517
  success = (token.typ == EnumToken.IdenTokenType || token.typ == EnumToken.DashedIdenTokenType || isIdentColor(token)) &&
384
518
  (token.val == syntax.val ||
385
- syntax.val === token.val?.toLowerCase?.() ||
519
+ syntax.val.toLowerCase() === token.val?.toLowerCase?.() ||
386
520
  // config.declarations.all
387
521
  allValues.includes(token.val.toLowerCase()));
388
522
  if (success) {
@@ -421,7 +555,7 @@ function match(syntax, context, options) {
421
555
  ...options,
422
556
  isRepeatable: null,
423
557
  isList: null,
424
- occurence: null,
558
+ occurrence: null,
425
559
  atLeastOnce: null
426
560
  });
427
561
  case ValidationTokenEnum.Comma:
@@ -456,7 +590,7 @@ function match(syntax, context, options) {
456
590
  ...options,
457
591
  isRepeatable: null,
458
592
  isList: null,
459
- occurence: null,
593
+ occurrence: null,
460
594
  atLeastOnce: null
461
595
  }).valid == SyntaxValidationResult.Valid;
462
596
  if (success) {
@@ -479,18 +613,20 @@ function match(syntax, context, options) {
479
613
  }
480
614
  function matchPropertyType(syntax, context, options) {
481
615
  if (![
482
- 'bg-position',
616
+ 'color',
483
617
  'integer',
618
+ 'bg-position',
619
+ 'composes-selector',
484
620
  'length-percentage', 'flex', 'calc-sum', 'color',
485
621
  'color-base', 'system-color', 'deprecated-system-color',
486
- 'pseudo-class-selector', 'pseudo-element-selector'
622
+ 'pseudo-class-selector', 'pseudo-element-selector', 'feature-value-declaration'
487
623
  ].includes(syntax.val)) {
488
624
  if (syntax.val in config["syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */]) {
489
625
  return doEvaluateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, syntax.val), context, {
490
626
  ...options,
491
627
  isRepeatable: null,
492
628
  isList: null,
493
- occurence: null,
629
+ occurrence: null,
494
630
  atLeastOnce: null
495
631
  });
496
632
  }
@@ -502,7 +638,7 @@ function matchPropertyType(syntax, context, options) {
502
638
  ...options,
503
639
  isRepeatable: null,
504
640
  isList: null,
505
- occurence: null,
641
+ occurrence: null,
506
642
  atLeastOnce: null
507
643
  });
508
644
  if (result.valid == SyntaxValidationResult.Valid) {
@@ -511,6 +647,9 @@ function matchPropertyType(syntax, context, options) {
511
647
  return { ...result, context };
512
648
  }
513
649
  switch (syntax.val) {
650
+ case 'composes-selector':
651
+ success = token.typ == EnumToken.ComposesSelectorNodeType;
652
+ break;
514
653
  case 'bg-position': {
515
654
  let val;
516
655
  let keyworkMatchCount = 0;
@@ -607,6 +746,14 @@ function matchPropertyType(syntax, context, options) {
607
746
  (token.typ == EnumToken.IdenTokenType && typeof Math[token.val.toUpperCase()] == 'number') ||
608
747
  [EnumToken.BinaryExpressionTokenType, EnumToken.NumberTokenType, EnumToken.PercentageTokenType, EnumToken.DimensionTokenType, EnumToken.LengthTokenType, EnumToken.AngleTokenType, EnumToken.TimeTokenType, EnumToken.ResolutionTokenType, EnumToken.FrequencyTokenType].includes(token.typ);
609
748
  break;
749
+ case 'declaration':
750
+ {
751
+ success = token.typ == EnumToken.DeclarationNodeType;
752
+ if (success) {
753
+ success = evaluateSyntax(token, null, options).valid == SyntaxValidationResult.Valid;
754
+ }
755
+ }
756
+ break;
610
757
  case 'declaration-value':
611
758
  while (!context.done()) {
612
759
  context.next();
@@ -633,13 +780,17 @@ function matchPropertyType(syntax, context, options) {
633
780
  break;
634
781
  case 'color':
635
782
  case 'color-base':
636
- success = token.typ == EnumToken.ColorTokenType || (token.typ == EnumToken.IdenTokenType && 'currentcolor' === token.val.toLowerCase()) || (token.typ == EnumToken.IdenTokenType && 'transparent' === token.val.toLowerCase()) || (token.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(token.val));
783
+ success = token.typ == EnumToken.ColorTokenType ||
784
+ (token.typ == EnumToken.IdenTokenType && 'currentcolor' === token.val.toLowerCase()) ||
785
+ (token.typ == EnumToken.IdenTokenType && 'transparent' === token.val.toLowerCase()) ||
786
+ (token.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(token.val) ||
787
+ isColor(token));
637
788
  if (!success && token.typ == EnumToken.FunctionTokenType && colorsFunc.includes(token.val)) {
638
789
  success = doEvaluateSyntax(getParsedSyntax("functions" /* ValidationSyntaxGroupEnum.Functions */, token.val)?.[0]?.chi, createContext(token.chi), {
639
790
  ...options,
640
791
  isRepeatable: null,
641
792
  isList: null,
642
- occurence: null,
793
+ occurrence: null,
643
794
  atLeastOnce: null
644
795
  }).valid == SyntaxValidationResult.Valid;
645
796
  }
@@ -647,8 +798,26 @@ function matchPropertyType(syntax, context, options) {
647
798
  case 'hex-color':
648
799
  success = (token.typ == EnumToken.ColorTokenType && token.kin == ColorType.HEX) || (token.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(token.val));
649
800
  break;
801
+ case 'feature-value-declaration':
802
+ {
803
+ let hasNumber = false;
804
+ success = token.typ == EnumToken.DeclarationNodeType && token.val.length > 0 && token.val.every((val) => {
805
+ if (val.typ == EnumToken.WhitespaceTokenType || val.typ == EnumToken.CommentTokenType) {
806
+ return true;
807
+ }
808
+ const success = (val.typ == EnumToken.NumberTokenType && Number.isInteger(+val.val) && val.val > 0) || (val.typ == EnumToken.FunctionTokenType && mathFuncs.includes(val.val.toLowerCase()) || (val.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(val.val)));
809
+ if (success) {
810
+ hasNumber = true;
811
+ }
812
+ if ('range' in syntax) {
813
+ return success && +val.val >= +syntax.range[0] && +val.val <= +syntax.range[1];
814
+ }
815
+ return success;
816
+ }) && hasNumber;
817
+ }
818
+ break;
650
819
  case 'integer':
651
- success = (token.typ == EnumToken.NumberTokenType && Number.isInteger(+(token.val))) || (token.typ == EnumToken.FunctionTokenType && mathFuncs.includes(token.val.toLowerCase()) || (token.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(token.val)));
820
+ success = (token.typ == EnumToken.NumberTokenType && /^[+-]?\d+$/.test(token.val.toString())) || (token.typ == EnumToken.FunctionTokenType && mathFuncs.includes(token.val.toLowerCase()) || (token.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(token.val)));
652
821
  if ('range' in syntax) {
653
822
  success = success && +token.val >= +syntax.range[0] && +token.val <= +syntax.range[1];
654
823
  }
@@ -712,7 +881,7 @@ function matchPropertyType(syntax, context, options) {
712
881
  ...options,
713
882
  isRepeatable: null,
714
883
  isList: null,
715
- occurence: null,
884
+ occurrence: null,
716
885
  atLeastOnce: null
717
886
  }).valid == SyntaxValidationResult.Valid;
718
887
  }
@@ -728,7 +897,7 @@ function matchPropertyType(syntax, context, options) {
728
897
  ...options,
729
898
  isRepeatable: null,
730
899
  isList: null,
731
- occurence: null,
900
+ occurrence: null,
732
901
  atLeastOnce: null
733
902
  }).valid == SyntaxValidationResult.Valid;
734
903
  }
@@ -875,7 +1044,6 @@ function allOf(syntax, context, options) {
875
1044
  i = -1;
876
1045
  }
877
1046
  }
878
- // console.error()
879
1047
  const success = syntax.length == 0;
880
1048
  return {
881
1049
  valid: success ? SyntaxValidationResult.Valid : SyntaxValidationResult.Drop,
@@ -902,4 +1070,4 @@ function flatten(syntax) {
902
1070
  return data;
903
1071
  }
904
1072
 
905
- export { createContext, doEvaluateSyntax, evaluateSyntax };
1073
+ export { createContext, doEvaluateSyntax, evaluateSyntax, isNodeAllowedInContext };
@@ -20,8 +20,7 @@ function validateCompoundSelector(tokens, root, options) {
20
20
  node: root,
21
21
  // @ts-ignore
22
22
  syntax: null,
23
- error: 'expected selector',
24
- tokens
23
+ error: 'expected selector'
25
24
  };
26
25
  }
27
26
  tokens = tokens.slice();
@@ -19,15 +19,12 @@ function validateRelativeSelectorList(tokens, root, options) {
19
19
  return result;
20
20
  }
21
21
  }
22
+ // @ts-ignore
22
23
  return {
23
24
  valid: SyntaxValidationResult.Valid,
24
- matches: [],
25
- // @ts-ignore
26
25
  node: root,
27
- // @ts-ignore
28
26
  syntax: null,
29
- error: '',
30
- tokens
27
+ error: ''
31
28
  };
32
29
  }
33
30