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