@tbela99/css-parser 1.0.0 → 1.1.1-alpha4

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 (87) hide show
  1. package/CHANGELOG.md +269 -0
  2. package/README.md +16 -11
  3. package/dist/index-umd-web.js +3805 -1894
  4. package/dist/index.cjs +3806 -1895
  5. package/dist/index.d.ts +184 -57
  6. package/dist/lib/ast/expand.js +2 -1
  7. package/dist/lib/ast/features/calc.js +12 -1
  8. package/dist/lib/ast/features/inlinecssvariables.js +47 -24
  9. package/dist/lib/ast/features/prefix.js +117 -86
  10. package/dist/lib/ast/features/shorthand.js +29 -6
  11. package/dist/lib/ast/features/transform.js +10 -3
  12. package/dist/lib/ast/features/type.js +7 -0
  13. package/dist/lib/ast/math/expression.js +7 -1
  14. package/dist/lib/ast/math/math.js +6 -0
  15. package/dist/lib/ast/minify.js +165 -77
  16. package/dist/lib/ast/transform/compute.js +1 -0
  17. package/dist/lib/ast/transform/matrix.js +1 -0
  18. package/dist/lib/ast/types.js +26 -15
  19. package/dist/lib/ast/utils/utils.js +104 -0
  20. package/dist/lib/ast/walk.js +33 -7
  21. package/dist/lib/fs/resolve.js +10 -0
  22. package/dist/lib/parser/declaration/list.js +48 -45
  23. package/dist/lib/parser/declaration/map.js +1 -0
  24. package/dist/lib/parser/declaration/set.js +2 -1
  25. package/dist/lib/parser/parse.js +350 -279
  26. package/dist/lib/parser/tokenize.js +147 -72
  27. package/dist/lib/parser/utils/declaration.js +4 -3
  28. package/dist/lib/parser/utils/type.js +2 -1
  29. package/dist/lib/renderer/color/a98rgb.js +2 -1
  30. package/dist/lib/renderer/color/color-mix.js +10 -7
  31. package/dist/lib/renderer/color/color.js +171 -153
  32. package/dist/lib/renderer/color/hex.js +2 -1
  33. package/dist/lib/renderer/color/hsl.js +2 -1
  34. package/dist/lib/renderer/color/hwb.js +2 -1
  35. package/dist/lib/renderer/color/lab.js +2 -1
  36. package/dist/lib/renderer/color/lch.js +2 -1
  37. package/dist/lib/renderer/color/oklab.js +2 -1
  38. package/dist/lib/renderer/color/oklch.js +2 -1
  39. package/dist/lib/renderer/color/p3.js +2 -1
  40. package/dist/lib/renderer/color/rec2020.js +2 -1
  41. package/dist/lib/renderer/color/relativecolor.js +17 -11
  42. package/dist/lib/renderer/color/rgb.js +4 -3
  43. package/dist/lib/renderer/color/srgb.js +18 -17
  44. package/dist/lib/renderer/color/utils/components.js +6 -5
  45. package/dist/lib/renderer/color/utils/constants.js +47 -3
  46. package/dist/lib/renderer/color/xyz.js +2 -1
  47. package/dist/lib/renderer/color/xyzd50.js +2 -1
  48. package/dist/lib/renderer/render.js +48 -20
  49. package/dist/lib/syntax/syntax.js +257 -140
  50. package/dist/lib/validation/at-rules/container.js +75 -97
  51. package/dist/lib/validation/at-rules/counter-style.js +9 -8
  52. package/dist/lib/validation/at-rules/custom-media.js +13 -15
  53. package/dist/lib/validation/at-rules/document.js +22 -27
  54. package/dist/lib/validation/at-rules/font-feature-values.js +8 -8
  55. package/dist/lib/validation/at-rules/import.js +30 -81
  56. package/dist/lib/validation/at-rules/keyframes.js +18 -22
  57. package/dist/lib/validation/at-rules/layer.js +5 -5
  58. package/dist/lib/validation/at-rules/media.js +42 -52
  59. package/dist/lib/validation/at-rules/namespace.js +19 -23
  60. package/dist/lib/validation/at-rules/page-margin-box.js +15 -18
  61. package/dist/lib/validation/at-rules/page.js +8 -7
  62. package/dist/lib/validation/at-rules/supports.js +73 -82
  63. package/dist/lib/validation/at-rules/when.js +32 -36
  64. package/dist/lib/validation/atrule.js +15 -14
  65. package/dist/lib/validation/config.js +24 -1
  66. package/dist/lib/validation/config.json.js +611 -111
  67. package/dist/lib/validation/parser/parse.js +206 -212
  68. package/dist/lib/validation/parser/types.js +1 -1
  69. package/dist/lib/validation/selector.js +3 -3
  70. package/dist/lib/validation/syntax.js +984 -0
  71. package/dist/lib/validation/syntaxes/complex-selector-list.js +10 -11
  72. package/dist/lib/validation/syntaxes/complex-selector.js +10 -11
  73. package/dist/lib/validation/syntaxes/compound-selector.js +40 -50
  74. package/dist/lib/validation/syntaxes/family-name.js +9 -8
  75. package/dist/lib/validation/syntaxes/keyframe-block-list.js +4 -3
  76. package/dist/lib/validation/syntaxes/keyframe-selector.js +15 -18
  77. package/dist/lib/validation/syntaxes/layer-name.js +6 -5
  78. package/dist/lib/validation/syntaxes/relative-selector-list.js +7 -6
  79. package/dist/lib/validation/syntaxes/relative-selector.js +2 -1
  80. package/dist/lib/validation/syntaxes/url.js +18 -22
  81. package/dist/lib/validation/utils/list.js +2 -1
  82. package/dist/lib/validation/utils/whitespace.js +2 -1
  83. package/dist/node/index.js +4 -2
  84. package/dist/node/load.js +5 -0
  85. package/dist/web/index.js +4 -2
  86. package/dist/web/load.js +5 -0
  87. package/package.json +14 -13
@@ -0,0 +1,984 @@
1
+ import { ValidationTokenEnum } from './parser/types.js';
2
+ import { renderSyntax } from './parser/parse.js';
3
+ import { EnumToken, SyntaxValidationResult } from '../ast/types.js';
4
+ import '../ast/minify.js';
5
+ import '../ast/walk.js';
6
+ import '../parser/parse.js';
7
+ import '../parser/tokenize.js';
8
+ import '../parser/utils/config.js';
9
+ import { wildCardFuncs, isIdentColor, mathFuncs } from '../syntax/syntax.js';
10
+ import { renderToken } from '../renderer/render.js';
11
+ import { funcLike, ColorKind, colorsFunc } from '../renderer/color/utils/constants.js';
12
+ import { getSyntaxConfig, getParsedSyntax, getSyntax } from './config.js';
13
+ import './syntaxes/complex-selector.js';
14
+
15
+ const config = getSyntaxConfig();
16
+ // @ts-ignore
17
+ const allValues = getSyntaxConfig()["declarations" /* ValidationSyntaxGroupEnum.Declarations */].all.syntax.trim().split(/[\s|]+/g);
18
+ function createContext(input) {
19
+ const values = input.slice();
20
+ const result = values.slice();
21
+ if (result.at(-1)?.typ == EnumToken.WhitespaceTokenType) {
22
+ result.pop();
23
+ }
24
+ return {
25
+ index: -1,
26
+ peek() {
27
+ let index = this.index + 1;
28
+ if (index >= result.length) {
29
+ return null;
30
+ }
31
+ if (result[index]?.typ == EnumToken.WhitespaceTokenType) {
32
+ index++;
33
+ }
34
+ return result[index] ?? null;
35
+ },
36
+ update(context) {
37
+ // @ts-ignore
38
+ const newIndex = result.indexOf(context.current());
39
+ if (newIndex > this.index) {
40
+ this.index = newIndex;
41
+ }
42
+ },
43
+ consume(token, howMany) {
44
+ let newIndex = result.indexOf(token, this.index + 1);
45
+ if (newIndex == -1 || newIndex < this.index) {
46
+ return false;
47
+ }
48
+ howMany ??= 0;
49
+ let splice = 1;
50
+ if (result[newIndex - 1]?.typ == EnumToken.WhitespaceTokenType) {
51
+ splice++;
52
+ newIndex--;
53
+ }
54
+ result.splice(this.index + 1, 0, ...result.splice(newIndex, splice + howMany));
55
+ this.index += howMany + splice;
56
+ return true;
57
+ },
58
+ done() {
59
+ return this.index + 1 >= result.length;
60
+ },
61
+ current() {
62
+ return result[this.index] ?? null;
63
+ },
64
+ next() {
65
+ let index = this.index + 1;
66
+ if (index >= result.length) {
67
+ return null;
68
+ }
69
+ if (result[index]?.typ == EnumToken.WhitespaceTokenType) {
70
+ index++;
71
+ }
72
+ this.index = index;
73
+ return result[this.index] ?? null;
74
+ },
75
+ tokens() {
76
+ return result;
77
+ },
78
+ slice() {
79
+ return result.slice(this.index + 1);
80
+ },
81
+ clone() {
82
+ const context = createContext(result.slice());
83
+ context.index = this.index;
84
+ return context;
85
+ },
86
+ // @ts-ignore
87
+ toJSON() {
88
+ return {
89
+ index: this.index,
90
+ slice: this.slice(),
91
+ tokens: this.tokens()
92
+ };
93
+ }
94
+ };
95
+ }
96
+ function evaluateSyntax(node, options) {
97
+ let ast;
98
+ let result;
99
+ switch (node.typ) {
100
+ case EnumToken.DeclarationNodeType:
101
+ if (node.nam.startsWith('--')) {
102
+ break;
103
+ }
104
+ ast = getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, node.nam);
105
+ // console.error({ast: ast.reduce((acc, curr) => acc + renderSyntax(curr), '')});
106
+ if (ast != null) {
107
+ let token = null;
108
+ const values = node.val.slice();
109
+ while (values.length > 0) {
110
+ token = values.at(-1);
111
+ if (token.typ == EnumToken.WhitespaceTokenType || token.typ == EnumToken.CommentTokenType) {
112
+ values.pop();
113
+ }
114
+ else {
115
+ if (token.typ == EnumToken.ImportantTokenType) {
116
+ values.pop();
117
+ if (values.at(-1)?.typ == EnumToken.WhitespaceTokenType) {
118
+ values.pop();
119
+ }
120
+ }
121
+ break;
122
+ }
123
+ }
124
+ result = doEvaluateSyntax(ast, createContext(values), { ...options, visited: new WeakMap() });
125
+ // console.error(JSON.stringify({ast, values, result}, null, 1));
126
+ if (result.valid == SyntaxValidationResult.Valid && !result.context.done()) {
127
+ let token = null;
128
+ while ((token = result.context.next()) != null) {
129
+ if (token.typ == EnumToken.WhitespaceTokenType || token.typ == EnumToken.CommentTokenType) {
130
+ continue;
131
+ }
132
+ return {
133
+ ...result,
134
+ valid: SyntaxValidationResult.Drop,
135
+ node: token,
136
+ syntax: getSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, node.nam),
137
+ error: `unexpected token: '${renderToken(token)}'`,
138
+ };
139
+ }
140
+ }
141
+ return {
142
+ ...result,
143
+ syntax: getSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, node.nam)
144
+ };
145
+ }
146
+ break;
147
+ case EnumToken.RuleNodeType:
148
+ case EnumToken.AtRuleNodeType:
149
+ case EnumToken.KeyframeAtRuleNodeType:
150
+ case EnumToken.KeyFrameRuleNodeType:
151
+ // default:
152
+ //
153
+ // throw new Error(`Not implemented: ${node.typ}`);
154
+ }
155
+ return {
156
+ valid: SyntaxValidationResult.Valid,
157
+ node,
158
+ syntax: null,
159
+ error: ''
160
+ };
161
+ }
162
+ function clearVisited(token, syntax, key, options) {
163
+ options.visited.get(token)?.get?.(key)?.delete(syntax);
164
+ }
165
+ function isVisited(token, syntax, key, options) {
166
+ if (options.visited.get(token)?.get?.(key)?.has(syntax)) {
167
+ return true;
168
+ }
169
+ if (!options.visited.has(token)) {
170
+ options.visited.set(token, new Map());
171
+ }
172
+ if (!options.visited.get(token).has(key)) {
173
+ options.visited.get(token).set(key, new Set());
174
+ }
175
+ options.visited.get(token).get(key).add(syntax);
176
+ return false;
177
+ }
178
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Values_and_Units/Value_definition_syntax
179
+ function doEvaluateSyntax(syntaxes, context, options) {
180
+ let syntax;
181
+ let i = 0;
182
+ let result;
183
+ let token = null;
184
+ // console.error(`>> doEvaluateSyntax: ${syntaxes.reduce((acc, curr) => acc + renderSyntax(curr), '')}\n>> ${JSON.stringify({syntaxes}, null, 1)}>> context: ${context.slice<Token>().reduce((acc, curr) => acc + renderToken(curr), '')}`);
185
+ for (; i < syntaxes.length; i++) {
186
+ syntax = syntaxes[i];
187
+ if (context.done()) {
188
+ if (syntax.typ == ValidationTokenEnum.Whitespace || syntax.isOptional || syntax.isRepeatable) {
189
+ continue;
190
+ }
191
+ break;
192
+ }
193
+ token = context.peek();
194
+ if (syntax.typ == ValidationTokenEnum.Whitespace) {
195
+ if (context.peek()?.typ == EnumToken.WhitespaceTokenType) {
196
+ context.next();
197
+ }
198
+ continue;
199
+ }
200
+ else if (options.isList !== false && syntax.isList) {
201
+ result = matchList(syntax, context, options);
202
+ }
203
+ else if (options.isRepeatable !== false && syntax.isRepeatable) {
204
+ result = matchRepeatable(syntax, context, options);
205
+ }
206
+ else if (options.occurence !== false && syntax.occurence != null) {
207
+ result = matchOccurence(syntax, context, options);
208
+ }
209
+ else if (options.atLeastOnce !== false && syntax.atLeastOnce) {
210
+ result = matchAtLeastOnce(syntax, context, options);
211
+ }
212
+ else {
213
+ if (isVisited(token, syntax, 'doEvaluateSyntax', options)) {
214
+ // console.error(`cyclic dependency: ${renderSyntax(syntax)}`);
215
+ return {
216
+ valid: SyntaxValidationResult.Drop,
217
+ node: token,
218
+ syntax,
219
+ error: `cyclic dependency: ${renderSyntax(syntax)}`,
220
+ context
221
+ };
222
+ }
223
+ result = match(syntax, context, options);
224
+ if (result.valid == SyntaxValidationResult.Valid) {
225
+ clearVisited(token, syntax, 'doEvaluateSyntax', options);
226
+ }
227
+ }
228
+ if (result.valid == SyntaxValidationResult.Drop) {
229
+ if (syntax.isOptional) {
230
+ continue;
231
+ }
232
+ return result;
233
+ }
234
+ context.update(result.context);
235
+ }
236
+ // @ts-ignore
237
+ return result ?? {
238
+ valid: SyntaxValidationResult.Valid,
239
+ node: null,
240
+ syntax: syntaxes[i - 1],
241
+ error: '',
242
+ context
243
+ };
244
+ }
245
+ function matchAtLeastOnce(syntax, context, options) {
246
+ let success = false;
247
+ let result;
248
+ while (!context.done()) {
249
+ result = match(syntax, context.clone(), { ...options, atLeastOnce: false });
250
+ if (result.valid == SyntaxValidationResult.Valid) {
251
+ success = true;
252
+ context.update(result.context);
253
+ continue;
254
+ }
255
+ break;
256
+ }
257
+ return {
258
+ valid: success ? SyntaxValidationResult.Valid : SyntaxValidationResult.Drop,
259
+ node: context.current(),
260
+ syntax,
261
+ error: success ? '' : `could not match atLeastOnce: ${renderSyntax(syntax)}`,
262
+ context
263
+ };
264
+ }
265
+ function matchRepeatable(syntax, context, options) {
266
+ let result;
267
+ while (!context.done()) {
268
+ result = match(syntax, context.clone(), { ...options, isRepeatable: false });
269
+ if (result.valid == SyntaxValidationResult.Valid) {
270
+ context.update(result.context);
271
+ continue;
272
+ }
273
+ break;
274
+ }
275
+ return {
276
+ valid: SyntaxValidationResult.Valid,
277
+ node: null,
278
+ syntax,
279
+ error: '',
280
+ context
281
+ };
282
+ }
283
+ function matchList(syntax, context, options) {
284
+ let success = false;
285
+ let result;
286
+ let count = 0;
287
+ let con = context.clone();
288
+ let tokens = [];
289
+ while (!con.done()) {
290
+ while (!con.done() && con.peek()?.typ != EnumToken.CommaTokenType) {
291
+ tokens.push(con.next());
292
+ }
293
+ if (tokens.length == 0) {
294
+ return {
295
+ valid: SyntaxValidationResult.Drop,
296
+ node: context.peek(),
297
+ syntax,
298
+ error: `could not match list: ${renderSyntax(syntax)}`,
299
+ context
300
+ };
301
+ }
302
+ result = doEvaluateSyntax([syntax], createContext(tokens), {
303
+ ...options,
304
+ isList: false,
305
+ occurence: false
306
+ });
307
+ if (result.valid == SyntaxValidationResult.Valid) {
308
+ context = con.clone();
309
+ count++;
310
+ // pop comma
311
+ if (con.done() || con.peek()?.typ != EnumToken.CommaTokenType) {
312
+ break;
313
+ }
314
+ con.next();
315
+ tokens.length = 0;
316
+ }
317
+ else {
318
+ break;
319
+ }
320
+ }
321
+ success = count > 0;
322
+ if (count && syntax.occurence != null) {
323
+ success = count >= syntax.occurence.min;
324
+ if (success && syntax.occurence.max != null) {
325
+ success = count <= syntax.occurence.max;
326
+ }
327
+ }
328
+ return {
329
+ valid: success ? SyntaxValidationResult.Valid : SyntaxValidationResult.Drop,
330
+ node: context.current(),
331
+ syntax,
332
+ error: '',
333
+ context
334
+ };
335
+ }
336
+ function matchOccurence(syntax, context, options) {
337
+ let counter = 0;
338
+ let result;
339
+ do {
340
+ result = match(syntax, context.clone(), { ...options, occurence: false });
341
+ if (result.valid == SyntaxValidationResult.Drop) {
342
+ break;
343
+ }
344
+ counter++;
345
+ context.update(result.context);
346
+ } while (result.valid == SyntaxValidationResult.Valid && !context.done());
347
+ let sucesss = counter >= syntax.occurence.min;
348
+ if (sucesss && syntax.occurence.max != null) {
349
+ if (Number.isFinite(syntax.occurence.max)) {
350
+ sucesss = sucesss && counter <= syntax.occurence.max;
351
+ }
352
+ }
353
+ return {
354
+ valid: sucesss ? SyntaxValidationResult.Valid : SyntaxValidationResult.Drop,
355
+ node: context.current(),
356
+ syntax,
357
+ error: sucesss ? '' : `expected ${renderSyntax(syntax)} ${syntax.occurence.min} to ${syntax.occurence.max} occurences, got ${counter}`,
358
+ context
359
+ };
360
+ }
361
+ function match(syntax, context, options) {
362
+ // console.error(`>> match(): ${renderSyntax(syntax)}\n>> ${JSON.stringify({syntax}, null, 1)}>> context: ${context.slice<Token>().reduce((acc, curr) => acc + renderToken(curr), '')}`);
363
+ let success = false;
364
+ let result;
365
+ let token = context.peek();
366
+ switch (syntax.typ) {
367
+ case ValidationTokenEnum.PipeToken:
368
+ return someOf(syntax.chi, context, options);
369
+ case ValidationTokenEnum.Bracket:
370
+ return doEvaluateSyntax(syntax.chi, context, options);
371
+ case ValidationTokenEnum.AmpersandToken:
372
+ return allOf(flatten(syntax), context, options);
373
+ case ValidationTokenEnum.ColumnToken: {
374
+ let result = anyOf(flatten(syntax), context, options);
375
+ if (result.valid == SyntaxValidationResult.Valid) {
376
+ return result;
377
+ }
378
+ return {
379
+ valid: SyntaxValidationResult.Drop,
380
+ node: context.current(),
381
+ syntax,
382
+ error: `expected '${ValidationTokenEnum[syntax.typ].toLowerCase()}', got '${context.done() ? null : renderToken(context.peek())}'`,
383
+ context
384
+ };
385
+ }
386
+ }
387
+ if (token.typ == EnumToken.WhitespaceTokenType) {
388
+ context.next();
389
+ // @ts-ignore
390
+ if (syntax?.typ == ValidationTokenEnum.Whitespace) {
391
+ return {
392
+ valid: SyntaxValidationResult.Valid,
393
+ node: null,
394
+ syntax,
395
+ error: '',
396
+ context
397
+ };
398
+ }
399
+ }
400
+ if (syntax.typ != ValidationTokenEnum.PropertyType && (token?.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(token.val))) {
401
+ const result = doEvaluateSyntax(getParsedSyntax("functions" /* ValidationSyntaxGroupEnum.Functions */, token.val)?.[0]?.chi ?? [], createContext(token.chi), {
402
+ ...options,
403
+ isRepeatable: null,
404
+ isList: null,
405
+ occurence: null,
406
+ atLeastOnce: null
407
+ });
408
+ if (result.valid == SyntaxValidationResult.Valid) {
409
+ context.next();
410
+ }
411
+ return { ...result, context };
412
+ }
413
+ switch (syntax.typ) {
414
+ case ValidationTokenEnum.Keyword:
415
+ success = (token.typ == EnumToken.IdenTokenType || token.typ == EnumToken.DashedIdenTokenType || isIdentColor(token)) &&
416
+ (token.val == syntax.val ||
417
+ syntax.val.localeCompare(token.val, undefined, { sensitivity: 'base' }) == 0 ||
418
+ // config.declarations.all
419
+ allValues.includes(token.val.toLowerCase()));
420
+ if (success) {
421
+ context.next();
422
+ return {
423
+ valid: success ? SyntaxValidationResult.Valid : SyntaxValidationResult.Drop,
424
+ node: token,
425
+ syntax,
426
+ error: success ? '' : `expected keyword: '${syntax.val}', got ${renderToken(token)}`,
427
+ context
428
+ };
429
+ }
430
+ break;
431
+ case ValidationTokenEnum.PropertyType:
432
+ return matchPropertyType(syntax, context, options);
433
+ case ValidationTokenEnum.ValidationFunctionDefinition:
434
+ token = context.peek();
435
+ if (token.typ == EnumToken.ParensTokenType || !funcLike.concat(EnumToken.ColorTokenType) || (!('chi' in token))) {
436
+ return {
437
+ valid: SyntaxValidationResult.Drop,
438
+ node: context.next(),
439
+ syntax,
440
+ error: `expected function or color token, got ${renderToken(token)}`,
441
+ context
442
+ };
443
+ }
444
+ // {
445
+ // console.error(JSON.stringify({funcDef: (getParsedSyntax(ValidationSyntaxGroupEnum.Syntaxes, (syntax as ValidationFunctionDefinitionToken).val + '()')?.[0] as ValidationFunctionToken).chi}, null, 1))
446
+ //
447
+ // const child = getParsedSyntax(ValidationSyntaxGroupEnum.Syntaxes, (syntax as ValidationFunctionDefinitionToken).val + '()')?.[0] as ValidationFunctionToken;
448
+ result = match(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, syntax.val + '()')?.[0], context, options);
449
+ if (result.valid == SyntaxValidationResult.Valid) {
450
+ context.next();
451
+ result.context = context;
452
+ return result;
453
+ }
454
+ // }
455
+ break;
456
+ case ValidationTokenEnum.DeclarationType:
457
+ return doEvaluateSyntax(getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, syntax.val), context, {
458
+ ...options,
459
+ isRepeatable: null,
460
+ isList: null,
461
+ occurence: null,
462
+ atLeastOnce: null
463
+ });
464
+ case ValidationTokenEnum.Parens:
465
+ token = context.peek();
466
+ if (token.typ != EnumToken.ParensTokenType) {
467
+ break;
468
+ }
469
+ success = doEvaluateSyntax(syntax.chi, createContext(token.chi), {
470
+ ...options,
471
+ isRepeatable: null,
472
+ isList: null,
473
+ occurence: null,
474
+ atLeastOnce: null
475
+ }).valid == SyntaxValidationResult.Valid;
476
+ break;
477
+ case ValidationTokenEnum.Comma:
478
+ success = context.peek()?.typ == EnumToken.CommaTokenType;
479
+ if (success) {
480
+ context.next();
481
+ }
482
+ break;
483
+ case ValidationTokenEnum.Number:
484
+ success = context.peek()?.typ == EnumToken.NumberTokenType;
485
+ if (success) {
486
+ context.next();
487
+ }
488
+ break;
489
+ case ValidationTokenEnum.Whitespace:
490
+ success = context.peek()?.typ == EnumToken.WhitespaceTokenType;
491
+ if (success) {
492
+ context.next();
493
+ }
494
+ break;
495
+ case ValidationTokenEnum.Separator:
496
+ {
497
+ const token = context.peek();
498
+ success = token?.typ == EnumToken.LiteralTokenType && token.val == '/';
499
+ if (success) {
500
+ context.next();
501
+ }
502
+ }
503
+ break;
504
+ default:
505
+ token = context.peek();
506
+ if (!wildCardFuncs.includes(syntax.val) && syntax.val != token.val) {
507
+ break;
508
+ }
509
+ if (token.typ != EnumToken.ParensTokenType && funcLike.includes(token.typ)) {
510
+ success = doEvaluateSyntax(syntax.chi, createContext(token.chi), {
511
+ ...options,
512
+ isRepeatable: null,
513
+ isList: null,
514
+ occurence: null,
515
+ atLeastOnce: null
516
+ }).valid == SyntaxValidationResult.Valid;
517
+ if (success) {
518
+ context.next();
519
+ }
520
+ break;
521
+ }
522
+ if (syntax.typ == ValidationTokenEnum.Function) {
523
+ success = funcLike.includes(token.typ) && doEvaluateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, syntax.val + '()')?.[0]?.chi, createContext(token.chi), {
524
+ ...options,
525
+ isRepeatable: null,
526
+ isList: null,
527
+ occurence: null,
528
+ atLeastOnce: null
529
+ }).valid == SyntaxValidationResult.Valid;
530
+ if (success) {
531
+ context.next();
532
+ }
533
+ break;
534
+ }
535
+ // throw new Error(`Not implemented: ${ValidationTokenEnum[syntax.typ] ?? syntax.typ} : ${renderSyntax(syntax)} : ${renderToken(context.peek() as Token)} : ${JSON.stringify(syntax, null, 1)} | ${JSON.stringify(context.peek(), null, 1)}`);
536
+ }
537
+ if (!success && token.typ == EnumToken.IdenTokenType && allValues.includes(token.val.toLowerCase())) {
538
+ success = true;
539
+ context.next();
540
+ }
541
+ return {
542
+ valid: success ? SyntaxValidationResult.Valid : SyntaxValidationResult.Drop,
543
+ node: context.peek(),
544
+ syntax,
545
+ error: success ? '' : `expected '${ValidationTokenEnum[syntax.typ].toLowerCase()}', got '${renderToken(context.peek())}'`,
546
+ context
547
+ };
548
+ }
549
+ function matchPropertyType(syntax, context, options) {
550
+ if (![
551
+ 'bg-position',
552
+ 'length-percentage', 'flex', 'calc-sum', 'color', 'color-base', 'system-color', 'deprecated-system-color',
553
+ 'pseudo-class-selector', 'pseudo-element-selector'
554
+ ].includes(syntax.val)) {
555
+ if (syntax.val in config["syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */]) {
556
+ return doEvaluateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, syntax.val), context, {
557
+ ...options,
558
+ isRepeatable: null,
559
+ isList: null,
560
+ occurence: null,
561
+ atLeastOnce: null
562
+ });
563
+ }
564
+ }
565
+ let success = true;
566
+ let token = context.peek();
567
+ if ((token?.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(token.val))) {
568
+ const result = doEvaluateSyntax(getParsedSyntax("functions" /* ValidationSyntaxGroupEnum.Functions */, token.val)?.[0]?.chi ?? [], createContext(token.chi), {
569
+ ...options,
570
+ isRepeatable: null,
571
+ isList: null,
572
+ occurence: null,
573
+ atLeastOnce: null
574
+ });
575
+ if (result.valid == SyntaxValidationResult.Valid) {
576
+ context.next();
577
+ }
578
+ return { ...result, context };
579
+ }
580
+ switch (syntax.val) {
581
+ case 'bg-position': {
582
+ let val;
583
+ let keyworkMatchCount = 0;
584
+ let lengthMatchCount = 0;
585
+ let functionMatchCount = 0;
586
+ let isBGX = false;
587
+ let isBGY = false;
588
+ while (token != null && keyworkMatchCount + lengthMatchCount + functionMatchCount < 3) {
589
+ // match one value: keyword or length
590
+ success = (token.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(token.val));
591
+ if (success) {
592
+ functionMatchCount++;
593
+ context.next();
594
+ token = context.peek();
595
+ continue;
596
+ }
597
+ if (token.typ == EnumToken.WhitespaceTokenType) {
598
+ context.next();
599
+ token = context.peek();
600
+ continue;
601
+ }
602
+ if (token.typ == EnumToken.IdenTokenType) {
603
+ val = token.val.toLowerCase();
604
+ success = ['left', 'center', 'right', 'top', 'center', 'bottom'].includes(val);
605
+ if (!success) {
606
+ break;
607
+ }
608
+ keyworkMatchCount++;
609
+ if (keyworkMatchCount > 2) {
610
+ return {
611
+ valid: SyntaxValidationResult.Drop,
612
+ node: token,
613
+ syntax,
614
+ error: `expected <length>`,
615
+ context
616
+ };
617
+ }
618
+ if (val == 'left' || val == 'right') {
619
+ if (isBGX) {
620
+ return {
621
+ valid: SyntaxValidationResult.Drop,
622
+ node: token,
623
+ syntax,
624
+ error: `top | bottom | <length-percentage>`,
625
+ context
626
+ };
627
+ }
628
+ isBGX = true;
629
+ }
630
+ if (val == 'top' || val == 'bottom') {
631
+ if (isBGY) {
632
+ return {
633
+ valid: SyntaxValidationResult.Drop,
634
+ node: token,
635
+ syntax,
636
+ error: `expected left | right | <length-percentage>`,
637
+ context
638
+ };
639
+ }
640
+ isBGY = true;
641
+ }
642
+ context.next();
643
+ token = context.peek();
644
+ continue;
645
+ }
646
+ success = token.typ == EnumToken.LengthTokenType || token.typ == EnumToken.PercentageTokenType || (token.typ == EnumToken.NumberTokenType && token.val == '0');
647
+ if (!success) {
648
+ break;
649
+ }
650
+ lengthMatchCount++;
651
+ context.next();
652
+ token = context.peek();
653
+ }
654
+ if (keyworkMatchCount + lengthMatchCount + functionMatchCount == 0) {
655
+ return {
656
+ valid: SyntaxValidationResult.Drop,
657
+ node: token,
658
+ syntax,
659
+ error: `expected <bg-position>`,
660
+ context
661
+ };
662
+ }
663
+ return {
664
+ valid: SyntaxValidationResult.Valid,
665
+ node: token,
666
+ syntax,
667
+ error: '',
668
+ context
669
+ };
670
+ }
671
+ case 'calc-sum':
672
+ success = (token.typ == EnumToken.FunctionTokenType && mathFuncs.includes(token.val)) ||
673
+ // @ts-ignore
674
+ (token.typ == EnumToken.IdenTokenType && typeof Math[token.val.toUpperCase()] == 'number') ||
675
+ [EnumToken.BinaryExpressionTokenType, EnumToken.NumberTokenType, EnumToken.PercentageTokenType, EnumToken.DimensionTokenType, EnumToken.LengthTokenType, EnumToken.AngleTokenType, EnumToken.TimeTokenType, EnumToken.ResolutionTokenType, EnumToken.FrequencyTokenType].includes(token.typ);
676
+ break;
677
+ case 'declaration-value':
678
+ while (!context.done()) {
679
+ context.next();
680
+ }
681
+ success = true;
682
+ break;
683
+ case 'url-token':
684
+ success = token.typ == EnumToken.UrlTokenTokenType || token.typ == EnumToken.StringTokenType || (token.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(token.val));
685
+ break;
686
+ case 'ident':
687
+ case 'ident-token':
688
+ case 'custom-ident':
689
+ success = token.typ == EnumToken.IdenTokenType || token.typ == EnumToken.DashedIdenTokenType || isIdentColor(token);
690
+ break;
691
+ case 'dashed-ident':
692
+ case 'custom-property-name':
693
+ success = token.typ == EnumToken.DashedIdenTokenType;
694
+ break;
695
+ case 'system-color':
696
+ success = (token.typ == EnumToken.ColorTokenType && token.kin == ColorKind.SYS) || (token.typ == EnumToken.IdenTokenType && token.val.localeCompare('currentcolor', 'en', { sensitivity: 'base' }) == 0) || (token.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(token.val));
697
+ break;
698
+ case 'deprecated-system-color':
699
+ success = (token.typ == EnumToken.ColorTokenType && token.kin == ColorKind.DPSYS) || (token.typ == EnumToken.IdenTokenType && token.val.localeCompare('currentcolor', 'en', { sensitivity: 'base' }) == 0) || (token.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(token.val));
700
+ break;
701
+ case 'color':
702
+ case 'color-base':
703
+ success = token.typ == EnumToken.ColorTokenType || (token.typ == EnumToken.IdenTokenType && token.val.localeCompare('currentcolor', 'en', { sensitivity: 'base' }) == 0) || (token.typ == EnumToken.IdenTokenType && token.val.localeCompare('transparent', 'en', { sensitivity: 'base' }) == 0) || (token.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(token.val));
704
+ if (!success && token.typ == EnumToken.FunctionTokenType && colorsFunc.includes(token.val)) {
705
+ success = doEvaluateSyntax(getParsedSyntax("functions" /* ValidationSyntaxGroupEnum.Functions */, token.val)?.[0]?.chi, createContext(token.chi), {
706
+ ...options,
707
+ isRepeatable: null,
708
+ isList: null,
709
+ occurence: null,
710
+ atLeastOnce: null
711
+ }).valid == SyntaxValidationResult.Valid;
712
+ }
713
+ break;
714
+ case 'hex-color':
715
+ success = (token.typ == EnumToken.ColorTokenType && token.kin == ColorKind.HEX) || (token.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(token.val));
716
+ break;
717
+ case 'integer':
718
+ success = (token.typ == EnumToken.NumberTokenType && Number.isInteger(+(token.val))) || (token.typ == EnumToken.FunctionTokenType && token.val == 'calc');
719
+ if ('range' in syntax) {
720
+ success = success && +token.val >= +syntax.range[0] && +token.val <= +syntax.range[1];
721
+ }
722
+ break;
723
+ case 'dimension':
724
+ success = [
725
+ EnumToken.DimensionTokenType,
726
+ EnumToken.LengthTokenType,
727
+ EnumToken.AngleTokenType,
728
+ EnumToken.TimeTokenType,
729
+ EnumToken.ResolutionTokenType,
730
+ EnumToken.FrequencyTokenType
731
+ ].includes(token.typ) || (token.typ == EnumToken.FunctionTokenType && token.val == 'calc');
732
+ break;
733
+ case 'flex':
734
+ success = token.typ == EnumToken.FlexTokenType || (token.typ == EnumToken.FunctionTokenType && token.val == 'calc');
735
+ break;
736
+ case 'number':
737
+ case 'number-token':
738
+ success = token.typ == EnumToken.NumberTokenType;
739
+ if (success && 'range' in syntax) {
740
+ success = +token.val >= +syntax.range[0] && (syntax.range[1] == null || +token.val <= +syntax.range[1]);
741
+ }
742
+ break;
743
+ case 'angle':
744
+ success = token.typ == EnumToken.AngleTokenType || (token.typ == EnumToken.NumberTokenType && token.val == '0') || (token.typ == EnumToken.FunctionTokenType && token.val == 'calc');
745
+ break;
746
+ case 'length':
747
+ success = token.typ == EnumToken.LengthTokenType || (token.typ == EnumToken.NumberTokenType && token.val == '0') || (token.typ == EnumToken.FunctionTokenType && token.val == 'calc');
748
+ break;
749
+ case 'percentage':
750
+ success = token.typ == EnumToken.PercentageTokenType || (token.typ == EnumToken.NumberTokenType && token.val == '0') || (token.typ == EnumToken.FunctionTokenType && token.val == 'calc');
751
+ break;
752
+ case 'length-percentage':
753
+ success = token.typ == EnumToken.LengthTokenType || token.typ == EnumToken.PercentageTokenType || (token.typ == EnumToken.NumberTokenType && token.val == '0') || (token.typ == EnumToken.FunctionTokenType && token.val == 'calc');
754
+ break;
755
+ case 'resolution':
756
+ success = token.typ == EnumToken.ResolutionTokenType || token.typ == EnumToken.PercentageTokenType || (token.typ == EnumToken.NumberTokenType && token.val == '0') || (token.typ == EnumToken.FunctionTokenType && token.val == 'calc');
757
+ break;
758
+ case 'hash-token':
759
+ success = token.typ == EnumToken.HashTokenType;
760
+ break;
761
+ case 'string':
762
+ success = token.typ == EnumToken.StringTokenType || token.typ == EnumToken.IdenTokenType || (token.typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(token.val));
763
+ break;
764
+ case 'time':
765
+ success = token.typ == EnumToken.TimeTokenType || (token.typ == EnumToken.FunctionTokenType && token.val == 'calc');
766
+ break;
767
+ case 'zero':
768
+ success = token.val == '0' || (token.typ == EnumToken.FunctionTokenType && token.val == 'calc');
769
+ break;
770
+ case 'pseudo-element-selector':
771
+ success = token.typ == EnumToken.PseudoElementTokenType;
772
+ break;
773
+ case 'pseudo-class-selector':
774
+ success = token.typ == EnumToken.PseudoClassTokenType || token.typ == EnumToken.PseudoClassFuncTokenType;
775
+ if (success) {
776
+ success = token.val + (token.typ == EnumToken.PseudoClassTokenType ? '' : '()') in config["selectors" /* ValidationSyntaxGroupEnum.Selectors */];
777
+ if (success && token.typ == EnumToken.PseudoClassFuncTokenType) {
778
+ success = doEvaluateSyntax(getParsedSyntax("selectors" /* ValidationSyntaxGroupEnum.Selectors */, token.val + '()')?.[0]?.chi ?? [], createContext(token.chi), {
779
+ ...options,
780
+ isRepeatable: null,
781
+ isList: null,
782
+ occurence: null,
783
+ atLeastOnce: null
784
+ }).valid == SyntaxValidationResult.Valid;
785
+ }
786
+ }
787
+ break;
788
+ // default:
789
+ //
790
+ // throw new Error(`Not implemented: ${ValidationTokenEnum[syntax.typ] ?? syntax.typ} : ${renderSyntax(syntax)}\n${JSON.stringify(syntax, null, 1)}`);
791
+ }
792
+ if (!success &&
793
+ token.typ == EnumToken.FunctionTokenType &&
794
+ ['length-percentage', 'length', 'number', 'number-token', 'angle', 'percentage', 'dimension'].includes(syntax.val)) {
795
+ if (!success) {
796
+ success = mathFuncs.includes(token.val.toLowerCase()) &&
797
+ // (token as FunctionToken).val + '()' in config[ValidationSyntaxGroupEnum.Syntaxes] &&
798
+ doEvaluateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, token.val + '()')?.[0]?.chi ?? [], createContext(token.chi), {
799
+ ...options,
800
+ isRepeatable: null,
801
+ isList: null,
802
+ occurence: null,
803
+ atLeastOnce: null
804
+ }).valid == SyntaxValidationResult.Valid;
805
+ }
806
+ }
807
+ if (!success && token.typ == EnumToken.IdenTokenType) {
808
+ success = allValues.includes(token.val.toLowerCase());
809
+ }
810
+ if (success) {
811
+ context.next();
812
+ }
813
+ return {
814
+ valid: success ? SyntaxValidationResult.Valid : SyntaxValidationResult.Drop,
815
+ node: token,
816
+ syntax,
817
+ error: success ? '' : `expected '${syntax.val}', got ${renderToken(token)}`,
818
+ context
819
+ };
820
+ }
821
+ function someOf(syntaxes, context, options) {
822
+ let result;
823
+ let i;
824
+ let success = false;
825
+ const matched = [];
826
+ for (i = 0; i < syntaxes.length; i++) {
827
+ if (context.peek()?.typ == EnumToken.WhitespaceTokenType) {
828
+ context.next();
829
+ }
830
+ result = doEvaluateSyntax(syntaxes[i], context.clone(), options);
831
+ if (result.valid == SyntaxValidationResult.Valid) {
832
+ success = true;
833
+ if (result.context.done()) {
834
+ return result;
835
+ }
836
+ matched.push(result);
837
+ }
838
+ }
839
+ if (matched.length > 0) {
840
+ // pick the best match
841
+ matched.sort((a, b) => a.context.done() ? -1 : b.context.done() ? 1 : b.context.index - a.context.index);
842
+ }
843
+ return matched[0] ?? {
844
+ valid: SyntaxValidationResult.Drop,
845
+ node: context.current(),
846
+ syntax: null,
847
+ error: success ? '' : `could not match someOf: ${syntaxes.reduce((acc, curr) => acc + (acc.length > 0 ? ' | ' : '') + curr.reduce((acc, curr) => acc + renderSyntax(curr), ''), '')}`,
848
+ context
849
+ };
850
+ }
851
+ function anyOf(syntaxes, context, options) {
852
+ let result;
853
+ let i;
854
+ let success = false;
855
+ for (i = 0; i < syntaxes.length; i++) {
856
+ result = doEvaluateSyntax(syntaxes[i], context.clone(), options);
857
+ if (result.valid == SyntaxValidationResult.Valid) {
858
+ success = true;
859
+ context.update(result.context);
860
+ if (result.context.done()) {
861
+ return result;
862
+ }
863
+ syntaxes.splice(i, 1);
864
+ i = -1;
865
+ }
866
+ }
867
+ return {
868
+ valid: success ? SyntaxValidationResult.Valid : SyntaxValidationResult.Drop,
869
+ node: context.current(),
870
+ syntax: null,
871
+ error: success ? '' : `could not match anyOf: ${syntaxes.reduce((acc, curr) => acc + '[' + curr.reduce((acc, curr) => acc + renderSyntax(curr), '') + ']', '')}`,
872
+ context
873
+ };
874
+ }
875
+ function allOf(syntax, context, options) {
876
+ let result;
877
+ let i;
878
+ let slice = context.slice();
879
+ const vars = [];
880
+ const tokens = [];
881
+ const repeatable = [];
882
+ // match optional syntax first
883
+ // <length>{2,3}&&<color>? => <color>?&&<length>{2,3}
884
+ for (i = 0; i < syntax.length; i++) {
885
+ if (syntax[i].length == 1 && syntax[i][0].occurence != null) {
886
+ repeatable.push(syntax[i]);
887
+ syntax.splice(i--, 1);
888
+ }
889
+ }
890
+ if (repeatable.length > 0) {
891
+ syntax.push(...repeatable);
892
+ }
893
+ // sort tokens -> wildCard -> last
894
+ // 1px var(...) 2px => 1px 2px var(...)
895
+ for (i = 0; i < slice.length; i++) {
896
+ if (slice[i].typ == EnumToken.FunctionTokenType && wildCardFuncs.includes(slice[i].val.toLowerCase())) {
897
+ vars.push(slice[i]);
898
+ if (slice[i + 1]?.typ == EnumToken.WhitespaceTokenType) {
899
+ vars.push(slice[++i]);
900
+ }
901
+ continue;
902
+ }
903
+ if (slice[i].typ == EnumToken.CommaTokenType || (slice[i].typ == EnumToken.LiteralTokenType && slice[i].val == '/')) {
904
+ tokens.push(...vars);
905
+ vars.length = 0;
906
+ }
907
+ tokens.push(slice[i]);
908
+ }
909
+ if (vars.length > 0) {
910
+ tokens.push(...vars);
911
+ }
912
+ const con = createContext(tokens);
913
+ let cp;
914
+ let j;
915
+ for (i = 0; i < syntax.length; i++) {
916
+ if (syntax[i].length == 1 && syntax[i][0].isOptional) {
917
+ syntax[i][0].isOptional = false;
918
+ j = 0;
919
+ cp = con.clone();
920
+ slice = cp.slice();
921
+ if (cp.done()) {
922
+ syntax[i][0].isOptional = true;
923
+ syntax.splice(i, 1);
924
+ i = -1;
925
+ continue;
926
+ }
927
+ while (!cp.done()) {
928
+ result = doEvaluateSyntax(syntax[i], cp.clone(), options);
929
+ if (result.valid == SyntaxValidationResult.Valid) {
930
+ let end = slice.indexOf(cp.current());
931
+ if (end == -1) {
932
+ end = 0;
933
+ }
934
+ else {
935
+ end -= j - 1;
936
+ }
937
+ con.consume(slice[j], end < 0 ? 0 : end);
938
+ break;
939
+ }
940
+ cp.next();
941
+ j++;
942
+ }
943
+ syntax[i][0].isOptional = true;
944
+ // @ts-ignore
945
+ if (result?.valid == SyntaxValidationResult.Valid) {
946
+ syntax.splice(i, 1);
947
+ i = -1;
948
+ }
949
+ continue;
950
+ }
951
+ result = doEvaluateSyntax(syntax[i], con.clone(), options);
952
+ if (result.valid == SyntaxValidationResult.Valid) {
953
+ con.update(result.context);
954
+ syntax.splice(i, 1);
955
+ i = -1;
956
+ }
957
+ }
958
+ const success = syntax.length == 0;
959
+ return {
960
+ valid: success ? SyntaxValidationResult.Valid : SyntaxValidationResult.Drop,
961
+ node: context.current(),
962
+ syntax: syntax?.[0]?.[0] ?? null,
963
+ error: `could not match allOf: ${syntax.reduce((acc, curr) => acc + '[' + curr.reduce((acc, curr) => acc + renderSyntax(curr), '') + ']', '')}`,
964
+ context: success ? con : context
965
+ };
966
+ }
967
+ function flatten(syntax) {
968
+ const stack = [syntax.l, syntax.r];
969
+ const data = [];
970
+ let s;
971
+ let i = 0;
972
+ for (; i < stack.length; i++) {
973
+ if (stack[i].length == 1 && stack[i][0].typ == syntax.typ) {
974
+ s = stack[i][0];
975
+ stack.splice(i--, 1, s.l, s.r);
976
+ }
977
+ else {
978
+ data.push(stack[i]);
979
+ }
980
+ }
981
+ return data;
982
+ }
983
+
984
+ export { createContext, doEvaluateSyntax, evaluateSyntax };