@tbela99/css-parser 0.8.0 → 0.9.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 (59) hide show
  1. package/.editorconfig +484 -0
  2. package/README.md +5 -3
  3. package/dist/index-umd-web.js +3272 -1898
  4. package/dist/index.cjs +3272 -1898
  5. package/dist/index.d.ts +48 -11
  6. package/dist/lib/ast/expand.js +14 -2
  7. package/dist/lib/ast/math/expression.js +1 -1
  8. package/dist/lib/ast/minify.js +30 -16
  9. package/dist/lib/ast/types.js +1 -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 +140 -101
  14. package/dist/lib/parser/tokenize.js +15 -3
  15. package/dist/lib/renderer/color/hex.js +1 -1
  16. package/dist/lib/renderer/color/hsl.js +1 -1
  17. package/dist/lib/renderer/color/hwb.js +2 -2
  18. package/dist/lib/renderer/color/lab.js +1 -1
  19. package/dist/lib/renderer/color/lch.js +1 -1
  20. package/dist/lib/renderer/color/oklab.js +2 -2
  21. package/dist/lib/renderer/color/oklch.js +1 -1
  22. package/dist/lib/renderer/color/p3.js +1 -1
  23. package/dist/lib/renderer/color/prophotoRgb.js +1 -1
  24. package/dist/lib/renderer/color/prophotorgb.js +1 -1
  25. package/dist/lib/renderer/color/rgb.js +1 -1
  26. package/dist/lib/renderer/color/srgb.js +2 -2
  27. package/dist/lib/renderer/color/utils/constants.js +1 -1
  28. package/dist/lib/renderer/color/xyz.js +1 -1
  29. package/dist/lib/renderer/render.js +34 -6
  30. package/dist/lib/syntax/syntax.js +336 -1
  31. package/dist/lib/validation/at-rules/container.js +353 -0
  32. package/dist/lib/validation/at-rules/counter-style.js +2 -2
  33. package/dist/lib/validation/at-rules/custom-media.js +52 -0
  34. package/dist/lib/validation/at-rules/else.js +5 -0
  35. package/dist/lib/validation/at-rules/font-feature-values.js +3 -0
  36. package/dist/lib/validation/at-rules/import.js +3 -0
  37. package/dist/lib/validation/at-rules/layer.js +3 -0
  38. package/dist/lib/validation/at-rules/media.js +117 -29
  39. package/dist/lib/validation/at-rules/supports.js +11 -11
  40. package/dist/lib/validation/at-rules/when.js +178 -0
  41. package/dist/lib/validation/atrule.js +25 -10
  42. package/dist/lib/validation/config.js +20 -15
  43. package/dist/lib/validation/config.json.js +162 -42
  44. package/dist/lib/validation/declaration.js +39 -9
  45. package/dist/lib/validation/parser/parse.js +91 -13
  46. package/dist/lib/validation/parser/types.js +1 -0
  47. package/dist/lib/validation/selector.js +6 -3
  48. package/dist/lib/validation/syntax.js +50 -4
  49. package/dist/lib/validation/syntaxes/complex-selector-list.js +16 -12
  50. package/dist/lib/validation/syntaxes/complex-selector.js +17 -247
  51. package/dist/lib/validation/syntaxes/compound-selector.js +226 -0
  52. package/dist/lib/validation/syntaxes/image.js +29 -0
  53. package/dist/lib/validation/syntaxes/keyframe-block-list.js +1 -1
  54. package/dist/lib/validation/syntaxes/keyframe-selector.js +1 -1
  55. package/dist/lib/validation/syntaxes/relative-selector-list.js +43 -13
  56. package/dist/lib/validation/utils/list.js +2 -2
  57. package/dist/node/index.js +1 -1
  58. package/dist/web/index.js +1 -1
  59. package/package.json +7 -7
@@ -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;
@@ -941,6 +1008,10 @@ function renderSyntax(token, parent) {
941
1008
  (token.chi == null ? '' : ' {\n' + token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '')).slice(1, -1) + '\n}';
942
1009
  case ValidationTokenEnum.Block:
943
1010
  return '{' + token.chi.reduce((acc, t) => acc + renderSyntax(t), '') + '}';
1011
+ case ValidationTokenEnum.DeclarationDefinitionToken:
1012
+ return token.nam + ': ' + renderSyntax(token.val);
1013
+ case ValidationTokenEnum.ColumnArrayToken:
1014
+ return token.chi.reduce((acc, curr) => acc + (acc.trim().length > 0 ? '||' : '') + renderSyntax(curr), '');
944
1015
  default:
945
1016
  throw new Error('Unhandled token: ' + JSON.stringify({ token }));
946
1017
  }
@@ -1032,37 +1103,44 @@ function minify(ast) {
1032
1103
  }
1033
1104
  return ast;
1034
1105
  }
1035
- function* walkValidationToken(token, parent, callback) {
1106
+ function* walkValidationToken(token, parent, callback, key) {
1036
1107
  if (Array.isArray(token)) {
1037
1108
  for (const child of token) {
1038
- yield* walkValidationToken(child, parent);
1109
+ yield* walkValidationToken(child, parent, callback, WalkValidationTokenKeyTypeEnum.Array);
1039
1110
  }
1040
1111
  return;
1041
1112
  }
1042
- yield { token, parent };
1043
- if ('prelude' in token) {
1113
+ let action = null;
1114
+ if (callback != null) {
1115
+ // @ts-ignore
1116
+ action = callback(token, parent, key);
1117
+ }
1118
+ if (action != WalkValidationTokenEnum.IgnoreNode && action != WalkValidationTokenEnum.IgnoreAll) {
1119
+ yield { token, parent };
1120
+ }
1121
+ if (action != WalkValidationTokenEnum.IgnoreChildren && action != WalkValidationTokenEnum.IgnoreAll && 'prelude' in token) {
1044
1122
  for (const child of token.prelude) {
1045
- yield* walkValidationToken(child, token);
1123
+ yield* walkValidationToken(child, token, callback, WalkValidationTokenKeyTypeEnum.Prelude);
1046
1124
  }
1047
1125
  }
1048
- if ('chi' in token) {
1126
+ if (action != WalkValidationTokenEnum.IgnoreChildren && 'chi' in token) {
1049
1127
  // @ts-ignore
1050
1128
  for (const child of token.chi) {
1051
- yield* walkValidationToken(child, token);
1129
+ yield* walkValidationToken(child, token, callback, WalkValidationTokenKeyTypeEnum.Children);
1052
1130
  }
1053
1131
  }
1054
- if ('l' in token) {
1132
+ if (action != WalkValidationTokenEnum.IgnoreChildren && action != WalkValidationTokenEnum.IgnoreAll && 'l' in token) {
1055
1133
  // @ts-ignore
1056
1134
  for (const child of token.l) {
1057
- yield* walkValidationToken(child, token);
1135
+ yield* walkValidationToken(child, token, callback, WalkValidationTokenKeyTypeEnum.Left);
1058
1136
  }
1059
1137
  }
1060
- if ('r' in token) {
1138
+ if (action != WalkValidationTokenEnum.IgnoreChildren && action != WalkValidationTokenEnum.IgnoreAll && 'r' in token) {
1061
1139
  // @ts-ignore
1062
1140
  for (const child of token.r) {
1063
- yield* walkValidationToken(child, token);
1141
+ yield* walkValidationToken(child, token, callback, WalkValidationTokenKeyTypeEnum.Right);
1064
1142
  }
1065
1143
  }
1066
1144
  }
1067
1145
 
1068
- export { parseSyntax, renderSyntax, walkValidationToken };
1146
+ export { WalkValidationTokenEnum, WalkValidationTokenKeyTypeEnum, parseSyntax, renderSyntax, walkValidationToken };
@@ -41,6 +41,7 @@ var ValidationTokenEnum;
41
41
  ValidationTokenEnum[ValidationTokenEnum["DeclarationDefinitionToken"] = 37] = "DeclarationDefinitionToken";
42
42
  ValidationTokenEnum[ValidationTokenEnum["SemiColon"] = 38] = "SemiColon";
43
43
  ValidationTokenEnum[ValidationTokenEnum["Character"] = 39] = "Character";
44
+ ValidationTokenEnum[ValidationTokenEnum["ColumnArrayToken"] = 40] = "ColumnArrayToken";
44
45
  })(ValidationTokenEnum || (ValidationTokenEnum = {}));
45
46
  var ValidationSyntaxGroupEnum;
46
47
  (function (ValidationSyntaxGroupEnum) {
@@ -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,5 +1,5 @@
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';
@@ -8,8 +8,10 @@ import { isLength } from '../syntax/syntax.js';
8
8
  import '../parser/utils/config.js';
9
9
  import '../renderer/color/utils/constants.js';
10
10
  import '../renderer/sourcemap/lib/encode.js';
11
- import { getParsedSyntax, getSyntaxConfig } from './config.js';
11
+ import { getSyntaxConfig, getParsedSyntax } from './config.js';
12
12
  import { validateSelector } from './selector.js';
13
+ import './syntaxes/complex-selector.js';
14
+ import { validateImage } from './syntaxes/image.js';
13
15
 
14
16
  const config = getSyntaxConfig();
15
17
  function consumeToken(tokens) {
@@ -30,6 +32,12 @@ function splice(tokens, matches) {
30
32
  return tokens;
31
33
  }
32
34
  function validateSyntax(syntaxes, tokens, root, options, context = { level: 0 }) {
35
+ console.error(JSON.stringify({
36
+ syntax: syntaxes.reduce((acc, curr) => acc + renderSyntax(curr), ''),
37
+ syntaxes,
38
+ tokens,
39
+ s: new Error('bar').stack
40
+ }, null, 1));
33
41
  if (syntaxes == null) {
34
42
  // @ts-ignore
35
43
  return {
@@ -485,7 +493,7 @@ function validateSyntax(syntaxes, tokens, root, options, context = { level: 0 })
485
493
  return result;
486
494
  }
487
495
  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))));
496
+ 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
497
  }
490
498
  function doValidateSyntax(syntax, token, tokens, root, options, context) {
491
499
  let valid = false;
@@ -706,7 +714,21 @@ function doValidateSyntax(syntax, token, tokens, root, options, context) {
706
714
  break;
707
715
  case ValidationTokenEnum.PropertyType:
708
716
  //
709
- if (['media-feature', 'mf-plain'].includes(syntax.val)) {
717
+ if ('image' == syntax.val) {
718
+ valid = token.typ == EnumToken.UrlFunctionTokenType || token.typ == EnumToken.ImageFunctionTokenType;
719
+ if (!valid) {
720
+ return {
721
+ valid: ValidationLevel.Drop,
722
+ matches: [],
723
+ node: token,
724
+ syntax,
725
+ error: 'unexpected <image>',
726
+ tokens
727
+ };
728
+ }
729
+ result = validateImage(token);
730
+ }
731
+ else if (['media-feature', 'mf-plain'].includes(syntax.val)) {
710
732
  valid = token.typ == EnumToken.DeclarationNodeType;
711
733
  result = {
712
734
  valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop,
@@ -751,6 +773,18 @@ function doValidateSyntax(syntax, token, tokens, root, options, context) {
751
773
  }
752
774
  else if (syntax.val == 'group-rule-body') {
753
775
  valid = [EnumToken.AtRuleNodeType, EnumToken.RuleNodeType].includes(token.typ);
776
+ if (!valid && token.typ == EnumToken.DeclarationNodeType && root?.typ == EnumToken.AtRuleNodeType && root.nam == 'media') {
777
+ // allowed only if nested rule
778
+ let parent = root;
779
+ while (parent != null) {
780
+ if (parent.typ == EnumToken.RuleNodeType) {
781
+ valid = true;
782
+ break;
783
+ }
784
+ // @ts-ignore
785
+ parent = parent.parent;
786
+ }
787
+ }
754
788
  // @ts-ignore
755
789
  result = {
756
790
  valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop,
@@ -1419,6 +1453,18 @@ function doValidateSyntax(syntax, token, tokens, root, options, context) {
1419
1453
  tokens
1420
1454
  };
1421
1455
  break;
1456
+ case ValidationTokenEnum.DeclarationDefinitionToken:
1457
+ if (token.typ != EnumToken.DeclarationNodeType || token.nam != syntax.nam) {
1458
+ return {
1459
+ valid: ValidationLevel.Drop,
1460
+ matches: [],
1461
+ node: token,
1462
+ syntax,
1463
+ error: '',
1464
+ tokens
1465
+ };
1466
+ }
1467
+ return validateSyntax([syntax.val], token.val, root, options, context);
1422
1468
  default:
1423
1469
  throw new Error('not implemented: ' + JSON.stringify({ syntax, token, tokens }, null, 1));
1424
1470
  }
@@ -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 };
@@ -1,4 +1,5 @@
1
1
  import { consumeWhitespace } from '../utils/whitespace.js';
2
+ import { splitTokenList } from '../utils/list.js';
2
3
  import { EnumToken, ValidationLevel } from '../../ast/types.js';
3
4
  import '../../ast/minify.js';
4
5
  import '../../ast/walk.js';
@@ -6,9 +7,11 @@ import '../../parser/parse.js';
6
7
  import '../../renderer/color/utils/constants.js';
7
8
  import '../../renderer/sourcemap/lib/encode.js';
8
9
  import '../../parser/utils/config.js';
10
+ import { validateCompoundSelector } from './compound-selector.js';
9
11
 
10
12
  const combinatorsTokens = [EnumToken.ChildCombinatorTokenType, EnumToken.ColumnCombinatorTokenType,
11
- EnumToken.DescendantCombinatorTokenType, EnumToken.NextSiblingCombinatorTokenType, EnumToken.SubsequentSiblingCombinatorTokenType];
13
+ // EnumToken.DescendantCombinatorTokenType,
14
+ EnumToken.NextSiblingCombinatorTokenType, EnumToken.SubsequentSiblingCombinatorTokenType];
12
15
  // <compound-selector> [ <combinator>? <compound-selector> ]*
13
16
  function validateComplexSelector(tokens, root, options) {
14
17
  // [ <type-selector>? <subclass-selector>* [ <pseudo-element-selector> <pseudo-class-selector>* ]* ]!
@@ -25,257 +28,24 @@ function validateComplexSelector(tokens, root, options) {
25
28
  tokens
26
29
  };
27
30
  }
28
- while (tokens.length > 0) {
29
- if (combinatorsTokens.includes(tokens[0].typ)) {
30
- // @ts-ignore
31
- return {
32
- valid: ValidationLevel.Drop,
33
- matches: [],
34
- // @ts-ignore
35
- node: tokens[0],
36
- syntax: null,
37
- error: 'unexpected combinator',
38
- tokens
39
- };
40
- }
41
- if (tokens[0].typ == EnumToken.NestingSelectorTokenType) {
42
- if (!options?.nestedSelector) {
43
- // @ts-ignore
44
- return {
45
- valid: ValidationLevel.Drop,
46
- matches: [],
47
- // @ts-ignore
48
- node: tokens[0],
49
- syntax: null,
50
- error: 'nested selector not allowed',
51
- tokens
52
- };
53
- }
54
- while (tokens.length > 0 && tokens[0].typ == EnumToken.NestingSelectorTokenType) {
55
- tokens.shift();
56
- consumeWhitespace(tokens);
57
- }
58
- if (tokens.length == 0) {
59
- break;
60
- }
61
- }
62
- if (EnumToken.IdenTokenType == tokens[0].typ) {
63
- tokens.shift();
64
- consumeWhitespace(tokens);
65
- if (tokens.length == 0) {
66
- break;
67
- }
68
- }
69
- if (EnumToken.UniversalSelectorTokenType == tokens[0].typ) {
70
- tokens.shift();
71
- consumeWhitespace(tokens);
72
- }
73
- while (tokens.length > 0) {
74
- if (tokens[0].typ == EnumToken.PseudoClassFuncTokenType) {
75
- if (tokens[0].val.startsWith(':-webkit-')) {
76
- // @ts-ignore
77
- return {
78
- valid: ValidationLevel.Drop,
79
- matches: [],
80
- // @ts-ignore
81
- node: tokens[0],
82
- syntax: null,
83
- error: 'invalid pseudo-class',
84
- tokens
85
- };
86
- }
87
- }
88
- if ([
89
- EnumToken.ClassSelectorTokenType,
90
- EnumToken.HashTokenType,
91
- EnumToken.PseudoClassTokenType,
92
- EnumToken.PseudoClassFuncTokenType
93
- ].includes(tokens[0].typ)) {
94
- tokens.shift();
95
- consumeWhitespace(tokens);
96
- continue;
97
- }
98
- if (tokens[0].typ == EnumToken.NestingSelectorTokenType) {
99
- if (!options?.nestedSelector) {
100
- // @ts-ignore
101
- return {
102
- valid: ValidationLevel.Drop,
103
- matches: [],
104
- // @ts-ignore
105
- node: tokens[0],
106
- syntax: null,
107
- error: 'nested selector not allowed',
108
- tokens
109
- };
110
- }
111
- tokens.shift();
112
- consumeWhitespace(tokens);
113
- continue;
114
- }
115
- // validate namespace
116
- if (tokens[0].typ == EnumToken.NameSpaceAttributeTokenType) {
117
- if (!((tokens[0].l == null || tokens[0].l.typ == EnumToken.IdenTokenType || (tokens[0].l.typ == EnumToken.LiteralTokenType && tokens[0].l.val == '*')) &&
118
- tokens[0].r.typ == EnumToken.IdenTokenType)) {
119
- // @ts-ignore
120
- return {
121
- valid: ValidationLevel.Drop,
122
- matches: [],
123
- node: tokens[0],
124
- syntax: null,
125
- error: 'expecting wq-name',
126
- tokens
127
- };
128
- }
129
- tokens.shift();
130
- consumeWhitespace(tokens);
131
- continue;
132
- }
133
- // validate attribute
134
- else if (tokens[0].typ == EnumToken.AttrTokenType) {
135
- const children = tokens[0].chi.slice();
136
- consumeWhitespace(children);
137
- if (children.length == 0) {
138
- // @ts-ignore
139
- return {
140
- valid: ValidationLevel.Drop,
141
- matches: [],
142
- node: tokens[0],
143
- syntax: null,
144
- error: 'invalid attribute selector',
145
- tokens
146
- };
147
- }
148
- if (![
149
- EnumToken.IdenTokenType,
150
- EnumToken.NameSpaceAttributeTokenType,
151
- EnumToken.MatchExpressionTokenType
152
- ].includes(children[0].typ)) {
153
- // @ts-ignore
154
- return {
155
- valid: ValidationLevel.Drop,
156
- matches: [],
157
- node: tokens[0],
158
- syntax: null,
159
- error: 'invalid attribute selector',
160
- tokens
161
- };
162
- }
163
- if (children[0].typ == EnumToken.MatchExpressionTokenType) {
164
- if (![EnumToken.IdenTokenType,
165
- EnumToken.NameSpaceAttributeTokenType].includes(children[0].l.typ) ||
166
- ![
167
- EnumToken.EqualMatchTokenType, EnumToken.DashMatchTokenType,
168
- EnumToken.StartMatchTokenType, EnumToken.ContainMatchTokenType,
169
- EnumToken.EndMatchTokenType, EnumToken.IncludeMatchTokenType
170
- ].includes(children[0].op.typ) ||
171
- ![EnumToken.StringTokenType,
172
- EnumToken.IdenTokenType].includes(children[0].r.typ)) {
173
- // @ts-ignore
174
- return {
175
- valid: ValidationLevel.Drop,
176
- matches: [],
177
- node: tokens[0],
178
- syntax: null,
179
- error: 'invalid attribute selector',
180
- tokens
181
- };
182
- }
183
- if (children[0].attr != null && !['i', 's'].includes(children[0].attr)) {
184
- // @ts-ignore
185
- return {
186
- valid: ValidationLevel.Drop,
187
- matches: [],
188
- node: tokens[0],
189
- syntax: null,
190
- error: 'invalid attribute selector',
191
- tokens
192
- };
193
- }
194
- }
195
- children.shift();
196
- consumeWhitespace(children);
197
- if (children.length > 0) {
198
- // @ts-ignore
199
- return {
200
- valid: ValidationLevel.Drop,
201
- matches: [],
202
- node: children[0],
203
- syntax: null,
204
- error: 'unexpected token',
205
- tokens
206
- };
207
- }
208
- tokens.shift();
209
- consumeWhitespace(tokens);
210
- continue;
211
- }
212
- break;
213
- }
214
- if (tokens.length == 0) {
215
- break;
216
- }
217
- // combinator
218
- if (!combinatorsTokens.includes(tokens[0].typ)) {
219
- if (tokens[0].typ == EnumToken.NestingSelectorTokenType) {
220
- if (!options?.nestedSelector) {
221
- // @ts-ignore
222
- return {
223
- valid: ValidationLevel.Drop,
224
- matches: [],
225
- // @ts-ignore
226
- node: tokens[0],
227
- syntax: null,
228
- error: 'nested selector not allowed',
229
- tokens
230
- };
231
- }
232
- tokens.shift();
233
- consumeWhitespace(tokens);
234
- continue;
235
- }
236
- if (tokens.length > 0 &&
237
- [
238
- EnumToken.IdenTokenType,
239
- EnumToken.AttrTokenType,
240
- EnumToken.NameSpaceAttributeTokenType,
241
- EnumToken.ClassSelectorTokenType,
242
- EnumToken.HashTokenType,
243
- EnumToken.PseudoClassTokenType,
244
- EnumToken.PseudoClassFuncTokenType
245
- ].includes(tokens[0].typ)) {
246
- continue;
247
- }
248
- // @ts-ignore
249
- return {
250
- valid: ValidationLevel.Drop,
251
- matches: [],
252
- node: tokens[0],
253
- syntax: null,
254
- error: 'expecting combinator or subclass-selector',
255
- tokens
256
- };
257
- }
258
- const token = tokens.shift();
259
- consumeWhitespace(tokens);
260
- if (tokens.length == 0) {
261
- // @ts-ignore
262
- return {
263
- valid: ValidationLevel.Drop,
264
- matches: [],
265
- node: token,
266
- syntax: null,
267
- error: 'expected compound-selector',
268
- tokens
269
- };
31
+ // const config = getSyntaxConfig();
32
+ //
33
+ // let match: number = 0;
34
+ let result = null;
35
+ // const combinators: EnumToken[] = combinatorsTokens.filter((t: EnumToken) => t != EnumToken.DescendantCombinatorTokenType);
36
+ for (const t of splitTokenList(tokens, combinatorsTokens)) {
37
+ result = validateCompoundSelector(t, root, options);
38
+ if (result.valid == ValidationLevel.Drop) {
39
+ return result;
270
40
  }
271
41
  }
272
42
  // @ts-ignore
273
- return {
274
- valid: ValidationLevel.Valid,
43
+ return result ?? {
44
+ valid: ValidationLevel.Drop,
275
45
  matches: [],
276
- node: null,
46
+ node: root,
277
47
  syntax: null,
278
- error: '',
48
+ error: 'expecting compound-selector',
279
49
  tokens
280
50
  };
281
51
  }