@jesscss/css-parser 1.0.8-alpha.6 → 2.0.0-alpha.2

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 (52) hide show
  1. package/lib/advancedActionsParser.d.ts +60 -0
  2. package/lib/advancedActionsParser.js +203 -0
  3. package/lib/advancedActionsParser.js.map +1 -0
  4. package/lib/cssActionsParser.d.ts +155 -0
  5. package/lib/cssActionsParser.js +376 -0
  6. package/lib/cssActionsParser.js.map +1 -0
  7. package/lib/cssErrorMessageProvider.d.ts +14 -0
  8. package/lib/cssErrorMessageProvider.js +40 -0
  9. package/lib/cssErrorMessageProvider.js.map +1 -0
  10. package/lib/cssParser.d.ts +36 -103
  11. package/lib/cssParser.js +75 -58
  12. package/lib/cssParser.js.map +1 -0
  13. package/lib/cssTokens.d.ts +539 -5
  14. package/lib/cssTokens.js +488 -232
  15. package/lib/cssTokens.js.map +1 -0
  16. package/lib/index.d.ts +8 -16
  17. package/lib/index.js +9 -41
  18. package/lib/index.js.map +1 -0
  19. package/lib/productions.d.ts +273 -0
  20. package/lib/productions.js +3499 -0
  21. package/lib/productions.js.map +1 -0
  22. package/lib/test/ast-serialize.test.d.ts +1 -0
  23. package/lib/test/ast-serialize.test.js +157 -0
  24. package/lib/test/ast-serialize.test.js.map +1 -0
  25. package/lib/test/container.test.d.ts +1 -0
  26. package/lib/test/container.test.js +369 -0
  27. package/lib/test/container.test.js.map +1 -0
  28. package/lib/test/css-files.test.d.ts +1 -0
  29. package/lib/test/css-files.test.js +21 -0
  30. package/lib/test/css-files.test.js.map +1 -0
  31. package/lib/test/less-output.test.d.ts +1 -0
  32. package/lib/test/less-output.test.js +52 -0
  33. package/lib/test/less-output.test.js.map +1 -0
  34. package/lib/util/cst.d.ts +7 -2
  35. package/lib/util/cst.js +5 -9
  36. package/lib/util/cst.js.map +1 -0
  37. package/lib/util/index.d.ts +19 -13
  38. package/lib/util/index.js +98 -87
  39. package/lib/util/index.js.map +1 -0
  40. package/package.json +43 -20
  41. package/lib/productions/atRules.d.ts +0 -2
  42. package/lib/productions/atRules.js +0 -196
  43. package/lib/productions/blocks.d.ts +0 -2
  44. package/lib/productions/blocks.js +0 -181
  45. package/lib/productions/declarations.d.ts +0 -14
  46. package/lib/productions/declarations.js +0 -59
  47. package/lib/productions/root.d.ts +0 -2
  48. package/lib/productions/root.js +0 -49
  49. package/lib/productions/selectors.d.ts +0 -2
  50. package/lib/productions/selectors.js +0 -231
  51. package/lib/productions/values.d.ts +0 -2
  52. package/lib/productions/values.js +0 -114
@@ -0,0 +1,3499 @@
1
+ import { EMPTY_ALT, tokenMatcher } from 'chevrotain';
2
+ import { Node, Any, Keyword, Block, Ruleset, Declaration, SelectorList, CompoundSelector, ComplexSelector, Combinator, BasicSelector, Ampersand, List, Sequence, Call, Url, Paren, Operation, Quoted, PseudoSelector, AttributeSelector, AtRule, QueryCondition, CustomDeclaration, RawRules } from '@jesscss/core';
3
+ export function stylesheet(T) {
4
+ const $ = this;
5
+ // stylesheet
6
+ // : CHARSET? main EOF
7
+ // ;
8
+ return (options = {}) => {
9
+ let RECORDING_PHASE = $.RECORDING_PHASE;
10
+ let context;
11
+ if (!RECORDING_PHASE) {
12
+ /** Auto-creates tree context */
13
+ context = this.context;
14
+ }
15
+ let charset;
16
+ $.OPTION(() => {
17
+ charset = $.CONSUME(T.Charset);
18
+ });
19
+ const ctx = { isRoot: true };
20
+ let root = $.SUBRULE($.main);
21
+ if (!RECORDING_PHASE) {
22
+ let rules = root.value;
23
+ if (charset) {
24
+ let loc = $.getLocationInfo(charset);
25
+ let rootLoc = root.location;
26
+ rules.unshift(new Any(charset.image, { role: 'charset' }, loc, context));
27
+ rootLoc[0] = loc[0];
28
+ rootLoc[1] = loc[1];
29
+ rootLoc[2] = loc[2];
30
+ }
31
+ return root;
32
+ }
33
+ };
34
+ }
35
+ export function main(T, alt) {
36
+ let $ = this;
37
+ alt ??= (ctx = {}) => [
38
+ { ALT: () => $.SUBRULE($.qualifiedRule) },
39
+ { ALT: () => $.SUBRULE($.atRule) }
40
+ ];
41
+ return (ctx = {}) => {
42
+ let RECORDING_PHASE = $.RECORDING_PHASE;
43
+ const isRoot = !!ctx.isRoot;
44
+ let context;
45
+ if (!RECORDING_PHASE) {
46
+ context = this.context;
47
+ }
48
+ let rules;
49
+ if (!RECORDING_PHASE) {
50
+ rules = [];
51
+ }
52
+ let requiredSemi = false;
53
+ let lastRule;
54
+ /**
55
+ * In this production rule, semi-colons are not required
56
+ * but this is repurposed by declarationList and by Less / Sass,
57
+ * so that's why this gate is here.
58
+ */
59
+ $.MANY({
60
+ GATE: () => !requiredSemi || (requiredSemi && ($.LA(1).tokenType === T.Semi
61
+ || $.LA(0).tokenType === T.Semi)),
62
+ DEF: () => {
63
+ const localAlt = typeof alt === 'function' ? alt(ctx) : alt;
64
+ let value = $.OR(localAlt);
65
+ if (!RECORDING_PHASE) {
66
+ if (!(value instanceof Node)) {
67
+ /** This is a semi-colon token */
68
+ if (lastRule) {
69
+ lastRule.options.semi = true;
70
+ }
71
+ else {
72
+ rules.push(new Any(';', { role: 'semi' }, $.getLocationInfo($.LA(1)), context));
73
+ }
74
+ }
75
+ else {
76
+ requiredSemi = !!value.requiredSemi;
77
+ rules.push(value);
78
+ lastRule = value;
79
+ }
80
+ }
81
+ }
82
+ });
83
+ if (!RECORDING_PHASE) {
84
+ let returnNode = $.getRulesWithComments(rules, $.getLocationInfo($.LA(1)));
85
+ // Attaches remaining whitespace at the end of rules
86
+ const wrapped = $.wrap(returnNode, true);
87
+ return wrapped;
88
+ }
89
+ };
90
+ }
91
+ export function qualifiedRule(T, selectorAlt) {
92
+ const $ = this;
93
+ selectorAlt ??= (ctx = {}) => [
94
+ {
95
+ GATE: () => !ctx.inner,
96
+ ALT: () => $.SUBRULE($.selectorList, { ARGS: [ctx] })
97
+ },
98
+ {
99
+ GATE: () => !!ctx.inner,
100
+ ALT: () => $.SUBRULE($.forgivingSelectorList, { ARGS: [ctx] })
101
+ }
102
+ ];
103
+ // qualifiedRule
104
+ // : selectorList WS* LCURLY declarationList RCURLY
105
+ // ;
106
+ return (ctx = {}) => {
107
+ $.startRule();
108
+ let selector = $.OR(selectorAlt(ctx));
109
+ $.CONSUME(T.LCurly);
110
+ let rules = $.SUBRULE($.declarationList);
111
+ $.CONSUME(T.RCurly);
112
+ if (!$.RECORDING_PHASE) {
113
+ let location = $.endRule();
114
+ const ruleset = new Ruleset({
115
+ selector,
116
+ rules
117
+ }, undefined, location, this.context);
118
+ return ruleset;
119
+ }
120
+ };
121
+ }
122
+ /** * SELECTORS ***/
123
+ /** @see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors */
124
+ /**
125
+ A selector with a single component, such as a single id selector
126
+ or type selector, that's not used in combination with or contains
127
+ any other selector component or combinator
128
+ .e.g `a` | `#selected` | `.foo`
129
+
130
+ @todo Define known pseudos
131
+
132
+ NOTE: A COLOR_IDENT_START token is a valid ID
133
+ */
134
+ // simpleSelector
135
+ // : classSelector
136
+ // | ID
137
+ // | COLOR_IDENT_START
138
+ // | identifier
139
+ // | AMPERSAND
140
+ // | STAR
141
+ // | pseudoSelector
142
+ // | attributeSelector
143
+ // ;
144
+ export function simpleSelector(T, selectorAlt) {
145
+ const $ = this;
146
+ selectorAlt ??= (ctx = {}) => [
147
+ {
148
+ /**
149
+ * It used to be the case that, in CSS Nesting, the first selector
150
+ * could not be an identifier. However, it looks like that's no
151
+ * longer the case.
152
+ *
153
+ * @see: https://github.com/w3c/csswg-drafts/issues/9317
154
+ */
155
+ ALT: () => $.CONSUME(T.Ident)
156
+ },
157
+ {
158
+ /** In CSS Nesting, outer selector can't contain an ampersand */
159
+ GATE: () => !!ctx.inner,
160
+ ALT: () => $.CONSUME(T.Ampersand)
161
+ },
162
+ { ALT: () => $.SUBRULE($.classSelector, { ARGS: [ctx] }) },
163
+ { ALT: () => $.SUBRULE($.idSelector, { ARGS: [ctx] }) },
164
+ { ALT: () => $.CONSUME(T.Star) },
165
+ { ALT: () => $.SUBRULE($.pseudoSelector, { ARGS: [ctx] }) },
166
+ { ALT: () => $.SUBRULE($.attributeSelector, { ARGS: [ctx] }) },
167
+ /** Supports keyframes selectors */
168
+ { ALT: () => $.CONSUME(T.DimensionInt) },
169
+ { ALT: () => $.CONSUME(T.DimensionNum) }
170
+ ];
171
+ return (ctx = {}) => {
172
+ let selector = $.OR(selectorAlt(ctx));
173
+ if (!$.RECORDING_PHASE) {
174
+ if ($.isToken(selector)) {
175
+ if (selector.tokenType.name === 'Ampersand') {
176
+ return new Ampersand(undefined, undefined, $.getLocationInfo(selector), this.context);
177
+ }
178
+ return new BasicSelector(selector.image, undefined, $.getLocationInfo(selector), this.context);
179
+ }
180
+ return selector;
181
+ }
182
+ };
183
+ }
184
+ // classSelector
185
+ // : DOT identifier
186
+ // ;
187
+ export function classSelector(T) {
188
+ const $ = this;
189
+ return () => {
190
+ let selector = $.CONSUME(T.DotName);
191
+ if (!$.RECORDING_PHASE) {
192
+ return new BasicSelector(selector.image, undefined, $.getLocationInfo(selector), this.context);
193
+ }
194
+ };
195
+ }
196
+ export function idSelector(T, selectorAlt) {
197
+ const $ = this;
198
+ selectorAlt ??= (ctx = {}) => [
199
+ { ALT: () => $.CONSUME(T.HashName) },
200
+ { ALT: () => $.CONSUME(T.ColorIdentStart) }
201
+ ];
202
+ /** #id, #FF0000 are both valid ids */
203
+ return (ctx = {}) => {
204
+ let selector = $.OR(selectorAlt(ctx));
205
+ if (!$.RECORDING_PHASE) {
206
+ return new BasicSelector(selector.image, undefined, $.getLocationInfo(selector), this.context);
207
+ }
208
+ };
209
+ }
210
+ export function pseudoSelector(T, selectorAlt) {
211
+ const $ = this;
212
+ const createPseudo = (name, arg) => {
213
+ if (!$.RECORDING_PHASE) {
214
+ let location = $.endRule();
215
+ return new PseudoSelector({
216
+ name,
217
+ arg
218
+ }, undefined, location, this.context);
219
+ }
220
+ };
221
+ selectorAlt ??= (ctx = {}) => [
222
+ {
223
+ ALT: () => {
224
+ let name = $.CONSUME(T.NthPseudoClass);
225
+ let val = $.SUBRULE($.nthValue, { ARGS: [ctx] });
226
+ $.CONSUME(T.RParen);
227
+ return createPseudo(name.image.slice(0, -1), val);
228
+ }
229
+ },
230
+ {
231
+ ALT: () => {
232
+ let name = $.CONSUME(T.SelectorPseudoClass);
233
+ let val = $.SUBRULE($.forgivingSelectorList, { ARGS: [ctx] });
234
+ $.CONSUME2(T.RParen);
235
+ return createPseudo(name.image.slice(0, -1), val);
236
+ }
237
+ },
238
+ {
239
+ ALT: () => {
240
+ let name = $.CONSUME(T.Colon).image;
241
+ $.OPTION({
242
+ GATE: $.noSep,
243
+ DEF: () => {
244
+ name += $.CONSUME2(T.Colon).image;
245
+ }
246
+ });
247
+ /**
248
+ * We use OR often to assert that no whitespace is allowed.
249
+ * There's no other way currently to do a positive-assertion Gate
250
+ * in Chevrotain.
251
+ */
252
+ let values = $.OR4([
253
+ {
254
+ /** ::unknown(values) */
255
+ GATE: $.noSep,
256
+ ALT: () => {
257
+ name += $.CONSUME(T.GenericFunctionStart).image;
258
+ let RECORDING_PHASE = $.RECORDING_PHASE;
259
+ let values;
260
+ if (!RECORDING_PHASE) {
261
+ values = [];
262
+ name = name.slice(0, -1);
263
+ }
264
+ let valuesLocation;
265
+ $.startRule();
266
+ $.MANY(() => {
267
+ let val = $.SUBRULE($.anyInnerValue);
268
+ if (!RECORDING_PHASE) {
269
+ values.push(val);
270
+ }
271
+ });
272
+ if (!RECORDING_PHASE) {
273
+ valuesLocation = $.endRule();
274
+ }
275
+ $.CONSUME3(T.RParen);
276
+ if (!RECORDING_PHASE && values.length) {
277
+ return new Sequence(values, undefined, valuesLocation, this.context);
278
+ }
279
+ }
280
+ },
281
+ {
282
+ /** ::unknown */
283
+ GATE: $.noSep,
284
+ ALT: () => {
285
+ name += $.CONSUME(T.Ident).image;
286
+ }
287
+ }
288
+ ]);
289
+ return createPseudo(name, values);
290
+ }
291
+ }
292
+ ];
293
+ // pseudoSelector
294
+ // : NTH_PSEUDO_CLASS '(' WS* nthValue WS* ')'
295
+ // | FUNCTIONAL_PSEUDO_CLASS '(' WS* forgivingSelectorList WS* ')'
296
+ // | COLON COLON? identifier ('(' anyInnerValue* ')')?
297
+ // ;
298
+ return (ctx = {}) => {
299
+ $.startRule();
300
+ return $.OR(selectorAlt(ctx));
301
+ };
302
+ }
303
+ export function nthValue(T, valueAlt) {
304
+ const $ = this;
305
+ valueAlt ??= (ctx = {}) => {
306
+ return [
307
+ { ALT: () => $.CONSUME(T.NthOdd) },
308
+ { ALT: () => $.CONSUME(T.NthEven) },
309
+ { ALT: () => $.CONSUME(T.Integer) },
310
+ {
311
+ ALT: () => {
312
+ $.OR2([
313
+ { ALT: () => $.CONSUME(T.NthSignedDimension) },
314
+ { ALT: () => $.CONSUME(T.NthUnsignedDimension) },
315
+ { ALT: () => $.CONSUME(T.NthSignedPlus) },
316
+ { ALT: () => $.CONSUME(T.NthIdent) }
317
+ ]);
318
+ $.OPTION(() => {
319
+ $.OR3([
320
+ { ALT: () => $.CONSUME(T.SignedInt) },
321
+ {
322
+ ALT: () => {
323
+ $.CONSUME(T.Minus);
324
+ $.CONSUME(T.UnsignedInt);
325
+ }
326
+ }
327
+ ]);
328
+ });
329
+ $.OPTION2(() => {
330
+ $.CONSUME(T.Of);
331
+ $.SUBRULE($.complexSelector, { ARGS: [ctx] });
332
+ });
333
+ }
334
+ }
335
+ ];
336
+ };
337
+ /**
338
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child
339
+ */
340
+ return (ctx = {}) => {
341
+ let RECORDING_PHASE = $.RECORDING_PHASE;
342
+ $.startRule();
343
+ let startTokenOffset;
344
+ if (!RECORDING_PHASE) {
345
+ startTokenOffset = this.LA(1).startOffset;
346
+ }
347
+ $.OR(valueAlt(ctx));
348
+ if (!RECORDING_PHASE) {
349
+ /** Coelesce all token values into one value */
350
+ let endTokenOffset = $.LA(-1).startOffset;
351
+ let location = $.endRule();
352
+ let origTokens = this.originalInput;
353
+ let origLength = origTokens.length;
354
+ let tokenValues = '';
355
+ for (let i = 0; i < origLength; i++) {
356
+ let token = origTokens[i];
357
+ if (token.startOffset >= startTokenOffset) {
358
+ tokenValues += token.image;
359
+ }
360
+ if (token.startOffset > endTokenOffset) {
361
+ break;
362
+ }
363
+ }
364
+ return $.wrap(new Any(tokenValues, { role: 'any' }, location, this.context), 'both');
365
+ }
366
+ };
367
+ }
368
+ // attributeSelector
369
+ // : LSQUARE WS* identifier (STAR | TILDE | CARET | DOLLAR | PIPE)? EQ WS* (identifier | STRING) WS* (ATTRIBUTE_FLAG WS*)? RSQUARE
370
+ // ;
371
+ export function attributeSelector(T, valueAlt) {
372
+ const $ = this;
373
+ valueAlt ??= (ctx = {}) => [
374
+ {
375
+ ALT: () => {
376
+ let token = $.CONSUME2(T.Ident);
377
+ if (!$.RECORDING_PHASE) {
378
+ return new Any(token.image, { role: 'ident' }, $.getLocationInfo(token), this.context);
379
+ }
380
+ }
381
+ },
382
+ { ALT: () => $.SUBRULE($.string) }
383
+ ];
384
+ return (ctx = {}) => {
385
+ let RECORDING_PHASE = $.RECORDING_PHASE;
386
+ $.startRule();
387
+ $.CONSUME(T.LSquare);
388
+ let key = $.CONSUME(T.Ident);
389
+ let op;
390
+ let value;
391
+ let mod;
392
+ $.OPTION(() => {
393
+ op = $.OR([
394
+ { ALT: () => $.CONSUME(T.Eq) },
395
+ { ALT: () => $.CONSUME(T.AttrMatch) }
396
+ ]);
397
+ value = $.OR2(valueAlt(ctx));
398
+ });
399
+ $.OPTION2(() => mod = $.CONSUME(T.AttrFlag));
400
+ $.CONSUME(T.RSquare);
401
+ if (!RECORDING_PHASE) {
402
+ let location = $.endRule();
403
+ return new AttributeSelector({
404
+ name: key.image,
405
+ op: op?.image,
406
+ value,
407
+ mod: mod?.image
408
+ }, undefined, location, this.context);
409
+ }
410
+ };
411
+ }
412
+ export function compoundSelector(T) {
413
+ const $ = this;
414
+ /**
415
+ A sequence of simple selectors that are not separated by
416
+ a combinator.
417
+ .e.g. `a#selected`
418
+ */
419
+ // compoundSelector
420
+ // : simpleSelector+
421
+ // ;
422
+ return (ctx = {}) => {
423
+ let RECORDING_PHASE = $.RECORDING_PHASE;
424
+ let selectors;
425
+ if (!RECORDING_PHASE) {
426
+ selectors = [];
427
+ }
428
+ let sel = $.SUBRULE($.simpleSelector, { ARGS: [ctx] });
429
+ if (!RECORDING_PHASE) {
430
+ selectors.push(sel);
431
+ }
432
+ $.MANY({
433
+ /** Make sure we don't ignore space combinators */
434
+ GATE: () => !$.hasWS(),
435
+ DEF: () => {
436
+ sel = $.SUBRULE2($.simpleSelector, { ARGS: [ctx] });
437
+ if (!RECORDING_PHASE) {
438
+ /** Make sure we don't add implicit whitespace */
439
+ sel.pre = 0;
440
+ selectors.push(sel);
441
+ }
442
+ }
443
+ });
444
+ if (!RECORDING_PHASE) {
445
+ if (selectors.length === 1) {
446
+ return selectors[0];
447
+ }
448
+ return new CompoundSelector(selectors, undefined, $.getLocationFromNodes(selectors), this.context);
449
+ }
450
+ };
451
+ }
452
+ /**
453
+ * @param manyGate - Exposed for Less to exclude the keyword 'all' from the selector list
454
+ */
455
+ export function complexSelector(T, manyGate) {
456
+ const $ = this;
457
+ manyGate ??= (ctx) => () => $.hasWS() || tokenMatcher($.LA(1), T.Combinator);
458
+ /**
459
+ A sequence of one or more simple and/or compound selectors
460
+ that are separated by combinators.
461
+ .e.g. a#selected > .icon
462
+ */
463
+ // complexSelector
464
+ // : compoundSelector (WS* (combinator WS*)? compoundSelector)*
465
+ // ;
466
+ return (ctx = {}) => {
467
+ let RECORDING_PHASE = $.RECORDING_PHASE;
468
+ let GATE = manyGate(ctx);
469
+ $.startRule();
470
+ let selectors = [$.SUBRULE($.compoundSelector, { ARGS: [ctx] })];
471
+ /**
472
+ * Only space combinators and specified combinators will enter the MANY
473
+ */
474
+ $.MANY({
475
+ GATE,
476
+ DEF: () => {
477
+ let co;
478
+ let combinator;
479
+ $.OPTION(() => {
480
+ co = $.CONSUME(T.Combinator);
481
+ });
482
+ if (!RECORDING_PHASE) {
483
+ if (co) {
484
+ combinator = $.wrap(new Combinator(co.image, undefined, $.getLocationInfo(co), this.context), 'both');
485
+ }
486
+ else {
487
+ /** Whitespace combinators are special */
488
+ let startOffset = this.LA(1).startOffset;
489
+ /**
490
+ * Technically, a whitespace combinator may not actually _include_
491
+ * a literal space (it can be a newline, for example), but we'll just use a
492
+ * space for now.
493
+ */
494
+ combinator = new Combinator(' ', undefined, undefined, this.context);
495
+ let pre = $.getPrePost(startOffset);
496
+ if (pre === 1) {
497
+ pre = 0;
498
+ }
499
+ else if (pre) {
500
+ let last = pre[pre.length - 1];
501
+ if (typeof last === 'string' && last.endsWith(' ')) {
502
+ /** remove the last character if a space */
503
+ pre[pre.length - 1] = last.slice(0, -1);
504
+ }
505
+ }
506
+ combinator.pre = pre;
507
+ }
508
+ }
509
+ let compound = $.SUBRULE2($.compoundSelector, { ARGS: [ctx] });
510
+ if (!RECORDING_PHASE) {
511
+ selectors.push(combinator, compound);
512
+ }
513
+ }
514
+ });
515
+ if (!RECORDING_PHASE) {
516
+ let location = $.endRule();
517
+ if (selectors.length === 1) {
518
+ return selectors[0];
519
+ }
520
+ return new ComplexSelector(selectors, undefined, location, this.context);
521
+ }
522
+ };
523
+ }
524
+ /**
525
+ A selector representing an element relative to one or more
526
+ anchor elements preceded by a combinator.
527
+ e.g. + div#topic > #reference
528
+ */
529
+ // relativeSelector
530
+ // : (combinator WS*)? complexSelector
531
+ // ;
532
+ export function relativeSelector(T) {
533
+ const $ = this;
534
+ return (ctx = {}) => {
535
+ return $.OR([
536
+ {
537
+ ALT: () => {
538
+ let co = $.CONSUME(T.Combinator);
539
+ let complex = $.SUBRULE($.complexSelector, { ARGS: [ctx] });
540
+ if (!$.RECORDING_PHASE) {
541
+ let combinator = new Combinator(co.image, undefined, $.getLocationInfo(co), this.context);
542
+ if (complex instanceof ComplexSelector) {
543
+ complex.value.unshift(combinator);
544
+ let location = complex.location;
545
+ location[0] = co.startOffset;
546
+ location[1] = co.startLine;
547
+ location[2] = co.startColumn;
548
+ }
549
+ else {
550
+ complex = new ComplexSelector([combinator, complex], undefined, $.getLocationFromNodes([combinator, complex]), this.context);
551
+ }
552
+ }
553
+ return complex;
554
+ }
555
+ },
556
+ {
557
+ ALT: () => $.SUBRULE2($.complexSelector, { ARGS: [ctx] })
558
+ }
559
+ ]);
560
+ };
561
+ }
562
+ export function forgivingSelectorList(T) {
563
+ const $ = this;
564
+ /**
565
+ https://www.w3.org/TR/css-nesting-1/
566
+
567
+ NOTE: implementers should throw a parsing
568
+ error if the selectorlist starts with an identifier
569
+ */
570
+ // forgivingSelectorList
571
+ // : relativeSelector (WS* COMMA WS* relativeSelector)*
572
+ // ;
573
+ return (ctx = {}) => {
574
+ let RECORDING_PHASE = $.RECORDING_PHASE;
575
+ $.startRule();
576
+ let sequences;
577
+ let i = 0;
578
+ if (!RECORDING_PHASE) {
579
+ sequences = [];
580
+ }
581
+ $.AT_LEAST_ONE_SEP({
582
+ SEP: T.Comma,
583
+ DEF: () => {
584
+ let selector = $.SUBRULE($.relativeSelector, { ARGS: [ctx] });
585
+ if (!RECORDING_PHASE) {
586
+ i++;
587
+ if (i === 1 && ctx.qualifiedRule) {
588
+ // Only attach post; leave pre for the parent Rules to lift comments
589
+ sequences.push($.wrap(selector, true));
590
+ }
591
+ else {
592
+ sequences.push($.wrap(selector, i === 1 ? true : 'both'));
593
+ }
594
+ }
595
+ }
596
+ });
597
+ if (!RECORDING_PHASE) {
598
+ let location = $.endRule();
599
+ if (sequences.length === 1) {
600
+ return sequences[0];
601
+ }
602
+ return new SelectorList(sequences, undefined, location, this.context);
603
+ }
604
+ };
605
+ }
606
+ export function selectorList(T) {
607
+ const $ = this;
608
+ // selectorList
609
+ // : complexSelector (WS* COMMA WS* complexSelector)*
610
+ // ;
611
+ return (ctx = {}) => {
612
+ let RECORDING_PHASE = $.RECORDING_PHASE;
613
+ $.startRule();
614
+ let i = 0;
615
+ let sequences;
616
+ if (!RECORDING_PHASE) {
617
+ sequences = [];
618
+ }
619
+ $.AT_LEAST_ONE_SEP({
620
+ SEP: T.Comma,
621
+ DEF: () => {
622
+ let sel = $.SUBRULE2($.complexSelector, { ARGS: [ctx] });
623
+ if (!RECORDING_PHASE) {
624
+ i++;
625
+ // Do not consume leading pre for the first selector of a qualified rule,
626
+ // so that pre-rule comments remain available to be lifted to Rules.
627
+ if (i === 1 && ctx.qualifiedRule) {
628
+ // Only attach post; leave pre for the parent Rules to lift comments
629
+ sequences.push($.wrap(sel, true));
630
+ }
631
+ else {
632
+ sequences.push($.wrap(sel, i === 1 ? true : 'both'));
633
+ }
634
+ }
635
+ }
636
+ });
637
+ if (!RECORDING_PHASE) {
638
+ let location = $.endRule();
639
+ if (sequences.length === 1) {
640
+ return sequences[0];
641
+ }
642
+ return new SelectorList(sequences, undefined, location, this.context);
643
+ }
644
+ };
645
+ }
646
+ export function declarationList(T, alt) {
647
+ const $ = this;
648
+ /** * Declarations ***/
649
+ // https://www.w3.org/TR/css-syntax-3/#declaration-list-diagram
650
+ // declarationList
651
+ // : WS* (
652
+ // declaration? (WS* SEMI declarationList)*
653
+ // | innerAtRule declarationList
654
+ // | innerQualifiedRule declarationList
655
+ // )
656
+ // ;
657
+ /**
658
+ * Originally this was structured much like the CSS spec,
659
+ * like this:
660
+ * $.OPTION(() => $.SUBRULE($.declaration))
661
+ * $.OPTION2(() => {
662
+ * $.CONSUME(T.Semi)
663
+ * $.SUBRULE3($.declarationList)
664
+ * })
665
+ * ...but chevrotain-allstar doesn't deal well with
666
+ * recursivity, as it predicts the ENTIRE path for
667
+ * each alt
668
+ */
669
+ alt ??= (ctx = {}) => [
670
+ { ALT: () => $.SUBRULE($.declaration, { ARGS: [ctx] }) },
671
+ { ALT: () => $.SUBRULE($.innerAtRule, { ARGS: [{ ...ctx, inner: true }] }) },
672
+ { ALT: () => $.SUBRULE2($.qualifiedRule, { ARGS: [{ ...ctx, inner: true }] }) },
673
+ { ALT: () => $.CONSUME2(T.Semi) }
674
+ ];
675
+ return main.call(this, T, alt);
676
+ }
677
+ export function declaration(T, alt) {
678
+ const $ = this;
679
+ alt ??= (ctx = {}) => [
680
+ {
681
+ ALT: () => {
682
+ let name;
683
+ $.OR2([
684
+ {
685
+ ALT: () => name = $.CONSUME(T.Ident)
686
+ },
687
+ {
688
+ GATE: () => $.legacyMode,
689
+ ALT: () => name = $.CONSUME(T.LegacyPropIdent)
690
+ }
691
+ ]);
692
+ let assign = $.CONSUME(T.Assign);
693
+ let value = $.SUBRULE($.valueList, { ARGS: [ctx] });
694
+ let important;
695
+ $.OPTION(() => {
696
+ important = $.CONSUME(T.Important);
697
+ });
698
+ if (!$.RECORDING_PHASE) {
699
+ let nameNode = $.wrap(new Any(name.image, { role: 'property' }, $.getLocationInfo(name), this.context), true);
700
+ return [nameNode, assign, value, important];
701
+ }
702
+ }
703
+ },
704
+ {
705
+ ALT: () => {
706
+ let RECORDING_PHASE = $.RECORDING_PHASE;
707
+ let name = $.CONSUME(T.CustomProperty);
708
+ let assign = $.CONSUME2(T.Assign);
709
+ let nodes;
710
+ if (!RECORDING_PHASE) {
711
+ nodes = [];
712
+ }
713
+ $.startRule();
714
+ $.MANY(() => {
715
+ let val = $.SUBRULE($.customValue, { ARGS: [{ ...ctx, inCustomPropertyValue: true }] });
716
+ if (!RECORDING_PHASE) {
717
+ nodes.push(val);
718
+ }
719
+ });
720
+ if (!RECORDING_PHASE) {
721
+ let location = $.endRule();
722
+ let nameNode = $.wrap(new Any(name.image, { role: 'property' }, $.getLocationInfo(name), this.context), true);
723
+ let value = new Sequence(nodes, undefined, location, this.context);
724
+ return [nameNode, assign, value];
725
+ }
726
+ }
727
+ }
728
+ ];
729
+ // declaration
730
+ // : identifier WS* COLON WS* valueList (WS* IMPORTANT)?
731
+ // | CUSTOM_IDENT WS* COLON CUSTOM_VALUE*
732
+ // ;
733
+ return (ctx = {}) => {
734
+ let RECORDING_PHASE = $.RECORDING_PHASE;
735
+ $.startRule();
736
+ let name;
737
+ let assign;
738
+ let value;
739
+ let important;
740
+ let val = $.OR(alt(ctx));
741
+ if (!RECORDING_PHASE) {
742
+ ([name, assign, value, important] = val);
743
+ }
744
+ if (!RECORDING_PHASE) {
745
+ let location = $.endRule();
746
+ const isCustom = name.valueOf().startsWith('--');
747
+ const wrapCtx = isCustom ? { ...ctx, inCustomPropertyValue: true } : ctx;
748
+ return new (isCustom ? CustomDeclaration : Declaration)({
749
+ name: name,
750
+ value: $.wrap(value, 'both', wrapCtx),
751
+ important: important ? $.wrap(new Any(important.image, { role: 'flag' }, $.getLocationInfo(important), this.context), 'both') : undefined
752
+ }, { assign: assign.image }, location, this.context);
753
+ }
754
+ };
755
+ }
756
+ /**
757
+ * @todo - This could be implemented with a multi-mode lexer?
758
+ * Multi-modes was the right way to do it with Antlr, but
759
+ * Chevrotain does not support recursive tokens very well.
760
+ */
761
+ export function customValue(T, alt) {
762
+ const $ = this;
763
+ /** Should be almost anything, but custom blocks need matching closers */
764
+ // Order matters: prefer nested blocks first, then strings, then raw tokens.
765
+ // Avoid knownFunctions here to remove ambiguity with custom blocks.
766
+ alt ??= (ctx = {}) => [
767
+ {
768
+ ALT: () => {
769
+ return $.SUBRULE($.customBlock, { ARGS: [ctx] });
770
+ }
771
+ },
772
+ {
773
+ ALT: () => {
774
+ return $.SUBRULE($.string, { ARGS: [ctx] });
775
+ }
776
+ },
777
+ {
778
+ ALT: () => {
779
+ const token = $.OR3([
780
+ { ALT: () => $.CONSUME(T.Value) },
781
+ { ALT: () => $.CONSUME(T.CustomProperty) },
782
+ { ALT: () => $.CONSUME(T.Colon) },
783
+ { ALT: () => $.CONSUME(T.AtName) },
784
+ { ALT: () => $.CONSUME(T.Comma) },
785
+ { ALT: () => $.CONSUME(T.Important) },
786
+ { ALT: () => $.CONSUME(T.Unknown) }
787
+ ]);
788
+ if (!$.RECORDING_PHASE) {
789
+ return $.wrap($.processValueToken(token, ctx), undefined, ctx);
790
+ }
791
+ }
792
+ }
793
+ ];
794
+ return (ctx = {}) => {
795
+ return $.OR(alt(ctx));
796
+ };
797
+ }
798
+ export function innerCustomValue(T, alt) {
799
+ const $ = this;
800
+ alt ??= (ctx = {}) => [
801
+ {
802
+ ALT: () => {
803
+ /** Can also have semi-colons */
804
+ let semi = $.CONSUME(T.Semi);
805
+ if (!$.RECORDING_PHASE) {
806
+ return $.wrap(new Any(semi.image, { role: 'semi' }, $.getLocationInfo(semi), this.context));
807
+ }
808
+ }
809
+ },
810
+ { ALT: () => $.SUBRULE($.customValue, { ARGS: [ctx] }) }
811
+ ];
812
+ return (ctx = {}) => $.OR(alt(ctx));
813
+ }
814
+ /**
815
+ * Extra tokens in a custom property or general enclosed. Should include any
816
+ * and every token possible (except semis), including unknown tokens.
817
+ *
818
+ * @todo - In tests, is there a way to test that every token is captured?
819
+ */
820
+ export function extraTokens(T, alt) {
821
+ const $ = this;
822
+ alt ??= (ctx = {}) => [
823
+ { ALT: () => $.SUBRULE($.functionCallLike, { ARGS: [ctx] }) },
824
+ { ALT: () => $.CONSUME(T.Value) },
825
+ { ALT: () => $.CONSUME(T.CustomProperty) },
826
+ { ALT: () => $.CONSUME(T.Colon) },
827
+ { ALT: () => $.CONSUME(T.AtName) },
828
+ { ALT: () => $.CONSUME(T.Comma) },
829
+ { ALT: () => $.CONSUME(T.Important) },
830
+ { ALT: () => $.CONSUME(T.Unknown) }
831
+ ];
832
+ return (ctx = {}) => {
833
+ let node = $.OR(alt(ctx));
834
+ if (!$.RECORDING_PHASE) {
835
+ if (!(node instanceof Node)) {
836
+ node = $.wrap($.processValueToken(node));
837
+ }
838
+ return node;
839
+ }
840
+ };
841
+ }
842
+ export function customBlock(T, alt) {
843
+ const $ = this;
844
+ alt ??= (ctx = {}) => [
845
+ {
846
+ ALT: () => {
847
+ let RECORDING_PHASE = $.RECORDING_PHASE;
848
+ let start;
849
+ let end;
850
+ let nodes;
851
+ if (!RECORDING_PHASE) {
852
+ nodes = [];
853
+ }
854
+ $.OR2([
855
+ /**
856
+ * All tokens that have a left parentheses.
857
+ * These need to match a right parentheses.
858
+ */
859
+ { ALT: () => start = $.CONSUME(T.LParen) },
860
+ { ALT: () => start = $.CONSUME(T.FunctionStart) },
861
+ { ALT: () => start = $.CONSUME(T.FunctionalPseudoClass) }
862
+ ]);
863
+ $.MANY(() => {
864
+ let val = $.SUBRULE($.innerCustomValue, { ARGS: [ctx] });
865
+ if (!$.RECORDING_PHASE) {
866
+ nodes.push(val);
867
+ }
868
+ });
869
+ end = $.CONSUME(T.RParen);
870
+ return [start, nodes, end];
871
+ }
872
+ },
873
+ {
874
+ ALT: () => {
875
+ let RECORDING_PHASE = $.RECORDING_PHASE;
876
+ let nodes;
877
+ if (!RECORDING_PHASE) {
878
+ nodes = [];
879
+ }
880
+ let start = $.CONSUME(T.LSquare);
881
+ $.MANY2(() => {
882
+ let val = $.SUBRULE2($.innerCustomValue, { ARGS: [ctx] });
883
+ if (!RECORDING_PHASE) {
884
+ nodes.push(val);
885
+ }
886
+ });
887
+ let end = $.CONSUME(T.RSquare);
888
+ return [start, nodes, end];
889
+ }
890
+ },
891
+ {
892
+ ALT: () => {
893
+ let RECORDING_PHASE = $.RECORDING_PHASE;
894
+ let nodes;
895
+ if (!RECORDING_PHASE) {
896
+ nodes = [];
897
+ }
898
+ let start = $.CONSUME(T.LCurly);
899
+ $.MANY3(() => {
900
+ let val = $.SUBRULE3($.innerCustomValue, { ARGS: [ctx] });
901
+ if (!RECORDING_PHASE) {
902
+ nodes.push(val);
903
+ }
904
+ });
905
+ let end = $.CONSUME(T.RCurly);
906
+ return [start, nodes, end];
907
+ }
908
+ }
909
+ ];
910
+ return (ctx = {}) => {
911
+ let RECORDING_PHASE = $.RECORDING_PHASE;
912
+ $.startRule();
913
+ let start;
914
+ let end;
915
+ let nodes;
916
+ let val = $.OR(alt(ctx));
917
+ if (!RECORDING_PHASE) {
918
+ ([start, nodes, end] = val);
919
+ }
920
+ if (!RECORDING_PHASE) {
921
+ let location = $.endRule();
922
+ let type;
923
+ switch (start.image) {
924
+ case '[':
925
+ type = 'square';
926
+ break;
927
+ case '{':
928
+ type = 'curly';
929
+ break;
930
+ }
931
+ if (type) {
932
+ // Preserve inner sequence post so trailing semicolons become part of block content
933
+ const seqLoc = nodes.length ? $.getLocationFromNodes(nodes) : undefined;
934
+ let seq = new Sequence(nodes, undefined, seqLoc, this.context);
935
+ return $.wrap(new Block($.wrap(seq, true, ctx), { type }, location, this.context), undefined, ctx);
936
+ }
937
+ else {
938
+ let startNode = $.wrap(new Any(start.image, { role: 'any' }, $.getLocationInfo(start), this.context), undefined, ctx);
939
+ let endNode = $.wrap(new Any(end.image, { role: 'any' }, $.getLocationInfo(end), this.context), undefined, ctx);
940
+ nodes = [startNode, ...nodes, endNode];
941
+ return new Sequence(nodes, undefined, location, this.context);
942
+ }
943
+ }
944
+ };
945
+ }
946
+ export function valueList(T) {
947
+ const $ = this;
948
+ /** Values separated by commas */
949
+ // valueList
950
+ // : value+ (, value+)*
951
+ // ;
952
+ return (ctx = {}) => {
953
+ let RECORDING_PHASE = $.RECORDING_PHASE;
954
+ $.startRule();
955
+ let nodes;
956
+ if (!RECORDING_PHASE) {
957
+ nodes = [];
958
+ }
959
+ $.AT_LEAST_ONE_SEP({
960
+ SEP: T.Comma,
961
+ DEF: () => {
962
+ let seq = $.SUBRULE($.valueSequence, { ARGS: [ctx] });
963
+ if (!RECORDING_PHASE) {
964
+ nodes.push(seq);
965
+ }
966
+ }
967
+ });
968
+ if (!RECORDING_PHASE) {
969
+ let location = $.endRule();
970
+ if (nodes.length === 1) {
971
+ return nodes[0];
972
+ }
973
+ return new List(nodes, undefined, location, this.context);
974
+ }
975
+ };
976
+ }
977
+ export function valueSequence(T) {
978
+ const $ = this;
979
+ /** Often space-separated */
980
+ return (ctx = {}) => {
981
+ let RECORDING_PHASE = $.RECORDING_PHASE;
982
+ $.startRule();
983
+ let nodes;
984
+ if (!RECORDING_PHASE) {
985
+ nodes = [];
986
+ }
987
+ $.AT_LEAST_ONE(() => {
988
+ let value = $.SUBRULE($.value, { ARGS: [ctx] });
989
+ if (!RECORDING_PHASE) {
990
+ nodes.push($.wrap(value));
991
+ }
992
+ });
993
+ if (!RECORDING_PHASE) {
994
+ let location = $.endRule();
995
+ if (nodes.length === 1) {
996
+ return $.wrap(nodes[0], true);
997
+ }
998
+ return $.wrap(new Sequence(nodes, undefined, location, this.context), true);
999
+ }
1000
+ };
1001
+ }
1002
+ export function squareValue(T) {
1003
+ const $ = this;
1004
+ return (ctx = {}) => {
1005
+ $.startRule();
1006
+ $.CONSUME(T.LSquare);
1007
+ let ident = $.CONSUME(T.Ident);
1008
+ $.CONSUME(T.RSquare);
1009
+ if (!$.RECORDING_PHASE) {
1010
+ let location = $.endRule();
1011
+ let identNode = new Any(ident.image, { role: 'ident' }, $.getLocationInfo(ident), this.context);
1012
+ return new Block(identNode, { type: 'square' }, location, this.context);
1013
+ }
1014
+ };
1015
+ }
1016
+ // value
1017
+ // : WS
1018
+ // | identifier
1019
+ // | integer
1020
+ // | number
1021
+ // | dimension
1022
+ // | COLOR_IDENT_START
1023
+ // | COLOR_INT_START
1024
+ // | STRING
1025
+ // | function
1026
+ // | '[' identifier ']'
1027
+ // | unknownValue
1028
+ // ;
1029
+ export function value(T, valueAlt) {
1030
+ const $ = this;
1031
+ valueAlt ??= (ctx = {}) => [
1032
+ /** Function should appear before Ident */
1033
+ { ALT: () => $.SUBRULE($.functionCall, { ARGS: [ctx] }) },
1034
+ { ALT: () => $.CONSUME(T.Ident) },
1035
+ { ALT: () => $.CONSUME(T.Dimension) },
1036
+ { ALT: () => $.CONSUME(T.Number) },
1037
+ { ALT: () => $.CONSUME(T.Color) },
1038
+ { ALT: () => $.CONSUME(T.UnicodeRange) },
1039
+ { ALT: () => $.SUBRULE($.string, { ARGS: [ctx] }) },
1040
+ { ALT: () => $.SUBRULE($.squareValue, { ARGS: [ctx] }) },
1041
+ {
1042
+ /** e.g. progid:DXImageTransform.Microsoft.Blur(pixelradius=2) */
1043
+ GATE: () => $.legacyMode,
1044
+ ALT: () => $.CONSUME(T.LegacyMSFilter)
1045
+ }
1046
+ ];
1047
+ return (ctx = {}) => {
1048
+ $.startRule();
1049
+ let node = $.OR(valueAlt(ctx));
1050
+ /**
1051
+ * Allows slash separators. Note that, structurally, the meaning
1052
+ * of slash separators in CSS is inconsistent and ambiguous. It
1053
+ * could separate a sequence of tokens from another sequence,
1054
+ * or it could separate ONE token from another, with other tokens
1055
+ * not included in the "slash list", OR it can represent division
1056
+ * in a math expression. CSS is just, unfortunately, not a very
1057
+ * syntactically-consistent language, and each property's value
1058
+ * essentially has a defined "micro-syntax".
1059
+ */
1060
+ let additionalValue;
1061
+ $.OPTION(() => {
1062
+ $.CONSUME(T.Slash);
1063
+ additionalValue = $.SUBRULE($.value, { ARGS: [ctx] });
1064
+ });
1065
+ if (!$.RECORDING_PHASE) {
1066
+ let location = $.endRule();
1067
+ if (!(node instanceof Node)) {
1068
+ node = $.processValueToken(node);
1069
+ }
1070
+ if (additionalValue) {
1071
+ return $.wrap(new List([$.wrap(node, true), additionalValue], { sep: '/' }, location, this.context));
1072
+ }
1073
+ return $.wrap(node);
1074
+ }
1075
+ };
1076
+ }
1077
+ export function string(T, stringAlt) {
1078
+ const $ = this;
1079
+ stringAlt ??= (ctx = {}) => [
1080
+ {
1081
+ ALT: () => {
1082
+ $.startRule();
1083
+ let quote = $.CONSUME(T.SingleQuoteStart);
1084
+ let contents;
1085
+ $.OPTION(() => contents = $.CONSUME(T.SingleQuoteStringContents));
1086
+ $.CONSUME(T.SingleQuoteEnd);
1087
+ if (!$.RECORDING_PHASE) {
1088
+ let location = $.endRule();
1089
+ const escaped = quote.image.startsWith('~');
1090
+ const quoteChar = quote.image.replace(/^~/, '');
1091
+ let value = contents?.image ?? '';
1092
+ if (escaped) {
1093
+ value = value.replace(/\\(?:\r\n?|\n|\f)/g, '\n');
1094
+ }
1095
+ return new Quoted(new Any(value, { role: 'any' }), { quote: quoteChar, escaped }, location, this.context);
1096
+ }
1097
+ }
1098
+ },
1099
+ {
1100
+ ALT: () => {
1101
+ $.startRule();
1102
+ let quote = $.CONSUME(T.DoubleQuoteStart);
1103
+ let contents;
1104
+ $.OPTION2(() => contents = $.CONSUME(T.DoubleQuoteStringContents));
1105
+ $.CONSUME(T.DoubleQuoteEnd);
1106
+ if (!$.RECORDING_PHASE) {
1107
+ let location = $.endRule();
1108
+ const escaped = quote.image.startsWith('~');
1109
+ const quoteChar = quote.image.replace(/^~/, '');
1110
+ let value = contents?.image ?? '';
1111
+ if (escaped) {
1112
+ value = value.replace(/\\(?:\r\n?|\n|\f)/g, '\n');
1113
+ }
1114
+ return new Quoted(new Any(value, { role: 'any' }), { quote: quoteChar, escaped }, location, this.context);
1115
+ }
1116
+ }
1117
+ }
1118
+ ];
1119
+ return (ctx = {}) => $.OR(stringAlt(ctx));
1120
+ }
1121
+ /** Implementers can decide to throw errors or warnings or not */
1122
+ // unknownValue
1123
+ // : COLON
1124
+ // | EQ
1125
+ // | DOT
1126
+ // | ID
1127
+ // | UNKNOWN
1128
+ // | AT_RULE
1129
+ // ;
1130
+ // $.RULE('unknownValue', () => {
1131
+ // $.OR([
1132
+ // { ALT: () => $.CONSUME(T.Colon) },
1133
+ // { ALT: () => $.CONSUME(T.Eq) },
1134
+ // { ALT: () => $.CONSUME(T.DotName) },
1135
+ // { ALT: () => $.CONSUME(T.HashName) },
1136
+ // { ALT: () => $.CONSUME(T.Unknown) },
1137
+ // { ALT: () => $.CONSUME(T.AtName) }
1138
+ // ])
1139
+ // })
1140
+ /** Abstracted for easy over-ride */
1141
+ // $.RULE('expression', () => {
1142
+ // $.SUBRULE($.mathSum)
1143
+ // })
1144
+ export function mathSum(T) {
1145
+ const $ = this;
1146
+ let opAlt = [
1147
+ { ALT: () => $.CONSUME(T.Plus) },
1148
+ { ALT: () => $.CONSUME(T.Minus) }
1149
+ ];
1150
+ // mathSum
1151
+ // : mathProduct (WS* ('+' | '-') WS* mathProduct)*
1152
+ // ;
1153
+ return (ctx = {}) => {
1154
+ let RECORDING_PHASE = $.RECORDING_PHASE;
1155
+ $.startRule();
1156
+ let left = $.SUBRULE($.mathProduct, { ARGS: [ctx] });
1157
+ $.MANY(() => {
1158
+ let op = $.OR(opAlt);
1159
+ let right = $.SUBRULE2($.mathProduct, { ARGS: [ctx] });
1160
+ if (!RECORDING_PHASE) {
1161
+ left = new Operation([left, op.image, right], { inCalc: true }, undefined, this.context);
1162
+ }
1163
+ });
1164
+ if (!RECORDING_PHASE) {
1165
+ left._location = $.endRule();
1166
+ return left;
1167
+ }
1168
+ };
1169
+ }
1170
+ // mathProduct
1171
+ // : mathValue (WS* ('*' | '/') WS* mathValue)*
1172
+ // ;
1173
+ export function mathProduct(T) {
1174
+ const $ = this;
1175
+ let opAlt = [
1176
+ { ALT: () => $.CONSUME(T.Star) },
1177
+ { ALT: () => $.CONSUME(T.Divide) }
1178
+ ];
1179
+ return (ctx = {}) => {
1180
+ let RECORDING_PHASE = $.RECORDING_PHASE;
1181
+ $.startRule();
1182
+ let left = $.SUBRULE($.mathValue, { ARGS: [ctx] });
1183
+ $.MANY(() => {
1184
+ let op = $.OR(opAlt);
1185
+ let right = $.SUBRULE2($.mathValue, { ARGS: [ctx] });
1186
+ if (!RECORDING_PHASE) {
1187
+ left = new Operation([left, op.image, right], { inCalc: true }, undefined, this.context);
1188
+ }
1189
+ });
1190
+ if (!RECORDING_PHASE) {
1191
+ left._location = $.endRule();
1192
+ return left;
1193
+ }
1194
+ };
1195
+ }
1196
+ // mathValue
1197
+ // : number
1198
+ // | dimension
1199
+ // | percentage
1200
+ // | mathConstant
1201
+ // | '(' WS* mathSum WS* ')'
1202
+ // ;
1203
+ export function mathValue(T, alt) {
1204
+ const $ = this;
1205
+ alt ??= (ctx = {}) => [
1206
+ { ALT: () => $.CONSUME(T.Number) },
1207
+ { ALT: () => $.CONSUME(T.Dimension) },
1208
+ // Allow identifiers like channel names in color space calcs (e.g., calc(l - 0.1))
1209
+ { ALT: () => $.CONSUME(T.Ident) },
1210
+ { ALT: () => $.CONSUME(T.MathConstant) },
1211
+ { ALT: () => $.SUBRULE($.knownFunctions, { ARGS: [ctx] }) },
1212
+ { ALT: () => $.SUBRULE($.mathParen, { ARGS: [ctx] }) }
1213
+ ];
1214
+ return (ctx = {}) => {
1215
+ let RECORDING_PHASE = $.RECORDING_PHASE;
1216
+ let node = $.OR(alt(ctx));
1217
+ if (!RECORDING_PHASE) {
1218
+ if (!(node instanceof Node)) {
1219
+ node = $.processValueToken(node);
1220
+ }
1221
+ return $.wrap(node, 'both');
1222
+ }
1223
+ };
1224
+ }
1225
+ export function mathParen(T) {
1226
+ const $ = this;
1227
+ return (ctx = {}) => {
1228
+ $.startRule();
1229
+ $.CONSUME(T.LParen);
1230
+ let node = $.SUBRULE($.mathSum, { ARGS: [ctx] });
1231
+ $.CONSUME(T.RParen);
1232
+ if (!$.RECORDING_PHASE) {
1233
+ let location = $.endRule();
1234
+ return new Paren(node, undefined, location, this.context);
1235
+ }
1236
+ };
1237
+ }
1238
+ // function
1239
+ // : URL_FUNCTION
1240
+ // | VAR_FUNCTION '(' WS* CUSTOM_IDENT (WS* COMMA WS* valueList)? ')'
1241
+ // | CALC_FUNCTION '(' WS* mathSum WS* ')'
1242
+ // | identifier '(' valueList ')'
1243
+ // ;
1244
+ // These have special parsing rules
1245
+ export function knownFunctions(T, alt) {
1246
+ const $ = this;
1247
+ alt ??= (ctx = {}) => [
1248
+ { ALT: () => $.SUBRULE($.urlFunction, { ARGS: [ctx] }) },
1249
+ { ALT: () => $.SUBRULE($.varFunction, { ARGS: [ctx] }) },
1250
+ { ALT: () => $.SUBRULE($.calcFunction, { ARGS: [ctx] }) }
1251
+ ];
1252
+ return (ctx = {}) => $.OR(alt(ctx));
1253
+ }
1254
+ export function ifFunctionArgs(T) {
1255
+ const $ = this;
1256
+ return (ctx = {}) => {
1257
+ const RECORDING_PHASE = $.RECORDING_PHASE;
1258
+ $.startRule();
1259
+ let branches;
1260
+ if (!RECORDING_PHASE) {
1261
+ branches = [];
1262
+ }
1263
+ $.AT_LEAST_ONE_SEP({
1264
+ SEP: T.Semi,
1265
+ DEF: () => {
1266
+ const condition = $.SUBRULE($.valueSequence, { ARGS: [{ ...ctx, inner: true }] });
1267
+ $.CONSUME(T.Assign);
1268
+ const value = $.SUBRULE($.valueList, { ARGS: [{ ...ctx, inner: true }] });
1269
+ if (!RECORDING_PHASE) {
1270
+ const sep = $.wrap(new Any(':', { role: 'operator' }, undefined, this.context), true);
1271
+ const loc = $.getLocationFromNodes([condition, value]);
1272
+ branches.push(new Sequence([$.wrap(condition, true), sep, $.wrap(value, true)], undefined, loc, this.context));
1273
+ }
1274
+ }
1275
+ });
1276
+ $.OPTION(() => $.CONSUME2(T.Semi));
1277
+ if (!RECORDING_PHASE) {
1278
+ const location = $.endRule();
1279
+ if (branches.length === 1) {
1280
+ return branches[0];
1281
+ }
1282
+ return new List(branches, { sep: ';' }, location, this.context);
1283
+ }
1284
+ };
1285
+ }
1286
+ export function ifFunction(T) {
1287
+ const $ = this;
1288
+ return (ctx = {}) => {
1289
+ $.startRule();
1290
+ const start = $.CONSUME(T.FunctionStart);
1291
+ const args = $.SUBRULE($.ifFunctionArgs, { ARGS: [{ ...ctx, inner: true }] });
1292
+ $.CONSUME(T.RParen);
1293
+ if (!$.RECORDING_PHASE) {
1294
+ const location = $.endRule();
1295
+ return new Call({
1296
+ name: start.image.slice(0, -1),
1297
+ args: new List([args])
1298
+ }, undefined, location, this.context);
1299
+ }
1300
+ };
1301
+ }
1302
+ export function varFunction(T) {
1303
+ const $ = this;
1304
+ return (ctx = {}) => {
1305
+ $.startRule();
1306
+ $.CONSUME(T.Var);
1307
+ let prop = $.CONSUME(T.CustomProperty);
1308
+ let args;
1309
+ $.OPTION(() => {
1310
+ $.CONSUME(T.Comma);
1311
+ args = $.SUBRULE($.valueList, { ARGS: [ctx] });
1312
+ });
1313
+ $.CONSUME(T.RParen);
1314
+ if (!$.RECORDING_PHASE) {
1315
+ let location = $.endRule();
1316
+ let propNode = $.wrap(new Any(prop.image, { role: 'customprop' }, $.getLocationInfo(prop), this.context), 'both');
1317
+ if (!args) {
1318
+ args = new List([propNode], undefined, $.getLocationInfo(prop), this.context);
1319
+ }
1320
+ else {
1321
+ let { startOffset, startLine, startColumn } = prop;
1322
+ args.value.unshift(propNode);
1323
+ args.location[0] = startOffset;
1324
+ args.location[1] = startLine;
1325
+ args.location[2] = startColumn;
1326
+ }
1327
+ return new Call({
1328
+ name: 'var',
1329
+ args
1330
+ }, undefined, location, this.context);
1331
+ }
1332
+ };
1333
+ }
1334
+ export function calcFunction(T) {
1335
+ const $ = this;
1336
+ return (ctx = {}) => {
1337
+ $.startRule();
1338
+ $.CONSUME(T.Calc);
1339
+ let args = $.SUBRULE($.mathSum, { ARGS: [ctx] });
1340
+ $.CONSUME2(T.RParen);
1341
+ if (!$.RECORDING_PHASE) {
1342
+ let location = $.endRule();
1343
+ return new Call({
1344
+ name: 'calc',
1345
+ args: new List([args])
1346
+ }, undefined, location, this.context);
1347
+ }
1348
+ };
1349
+ }
1350
+ export function urlFunction(T, alt) {
1351
+ const $ = this;
1352
+ alt ??= (ctx = {}) => [
1353
+ { ALT: () => $.SUBRULE($.string, { ARGS: [ctx] }) },
1354
+ { ALT: () => $.CONSUME(T.NonQuotedUrl) }
1355
+ ];
1356
+ return (ctx = {}) => {
1357
+ $.startRule();
1358
+ $.CONSUME(T.UrlStart);
1359
+ let node = $.OR(alt(ctx));
1360
+ $.CONSUME(T.UrlEnd);
1361
+ if (!$.RECORDING_PHASE) {
1362
+ let location = $.endRule();
1363
+ if (!(node instanceof Node)) {
1364
+ /** Whitespace should be included in the NonQuotedUrl */
1365
+ node = new Any(node.image, { role: 'urlvalue' }, $.getLocationInfo(node), this.context);
1366
+ }
1367
+ return new Url(node, undefined, location, this.context);
1368
+ }
1369
+ };
1370
+ }
1371
+ /**
1372
+ All At-rules according to spec are supposed to end with either
1373
+ a semi-colon or a curly-braced block. Some pre-processors
1374
+ (like PostCSS) allow the semi-colon to be optional, so we also
1375
+ allow it and insert it if it's missing.
1376
+ */
1377
+ // atRule
1378
+ // : importAtRule
1379
+ // | mediaAtRule
1380
+ // | unknownAtRule
1381
+ // | pageAtRule
1382
+ // | fontFaceAtRule
1383
+ // | supportsAtRule
1384
+ // ;
1385
+ export function atRule(T, alt) {
1386
+ const $ = this;
1387
+ let ruleAlt = alt ?? ((ctx) => ([
1388
+ { ALT: () => $.SUBRULE($.containerAtRule, { ARGS: [ctx] }) },
1389
+ { ALT: () => $.SUBRULE($.scopeAtRule, { ARGS: [ctx] }) },
1390
+ { ALT: () => $.SUBRULE($.documentAtRule, { ARGS: [ctx] }) },
1391
+ { ALT: () => $.SUBRULE($.layerAtRule, { ARGS: [ctx] }) },
1392
+ { ALT: () => $.SUBRULE($.keyframesAtRule, { ARGS: [ctx] }) },
1393
+ { ALT: () => $.SUBRULE($.importAtRule, { ARGS: [ctx] }) },
1394
+ { ALT: () => $.SUBRULE($.mediaAtRule, { ARGS: [ctx] }) },
1395
+ { ALT: () => $.SUBRULE($.pageAtRule, { ARGS: [ctx] }) },
1396
+ { ALT: () => $.SUBRULE($.fontFaceAtRule, { ARGS: [ctx] }) },
1397
+ { ALT: () => $.SUBRULE($.supportsAtRule, { ARGS: [ctx] }) },
1398
+ { ALT: () => $.SUBRULE($.nestedAtRule, { ARGS: [ctx] }) },
1399
+ { ALT: () => $.SUBRULE($.nonNestedAtRule, { ARGS: [ctx] }) },
1400
+ { ALT: () => $.SUBRULE($.unknownAtRule, { ARGS: [ctx] }) }
1401
+ ]));
1402
+ return (ctx) => $.OR(ruleAlt(ctx));
1403
+ }
1404
+ /**
1405
+ Inner rules are mostly the same except they have a declarationList
1406
+ instead of a main block within {}
1407
+ */
1408
+ // innerAtRule
1409
+ // : innerMediaAtRule
1410
+ // | unknownAtRule
1411
+ // ;
1412
+ export function innerAtRule(T, alt) {
1413
+ const $ = this;
1414
+ alt ??= (ctx = {}) => [
1415
+ { ALT: () => $.SUBRULE($.containerAtRule, { ARGS: [ctx] }) },
1416
+ { ALT: () => $.SUBRULE($.scopeAtRule, { ARGS: [ctx] }) },
1417
+ { ALT: () => $.SUBRULE($.documentAtRule, { ARGS: [ctx] }) },
1418
+ { ALT: () => $.SUBRULE($.layerAtRule, { ARGS: [ctx] }) },
1419
+ { ALT: () => $.SUBRULE($.keyframesAtRule, { ARGS: [ctx] }) },
1420
+ { ALT: () => $.SUBRULE($.mediaAtRule, { ARGS: [ctx] }) },
1421
+ { ALT: () => $.SUBRULE($.supportsAtRule, { ARGS: [ctx] }) },
1422
+ { ALT: () => $.SUBRULE($.nestedAtRule, { ARGS: [ctx] }) },
1423
+ { ALT: () => $.SUBRULE($.unknownAtRule, { ARGS: [ctx] }) }
1424
+ ];
1425
+ return (ctx = {}) => $.OR(alt({ ...ctx, inner: true }));
1426
+ }
1427
+ /**
1428
+ * @see https://www.w3.org/TR/css-nesting-1/#conditionals
1429
+ */
1430
+ export function atRuleBody(T) {
1431
+ const $ = this;
1432
+ return (ctx = {}) => $.OR([
1433
+ {
1434
+ GATE: () => !ctx.inner,
1435
+ ALT: () => $.SUBRULE($.main, { ARGS: [ctx] })
1436
+ },
1437
+ {
1438
+ GATE: () => !!ctx.inner,
1439
+ ALT: () => $.SUBRULE($.declarationList, { ARGS: [ctx] })
1440
+ }
1441
+ ]);
1442
+ }
1443
+ function resolvePreludeRule($, preludeRule) {
1444
+ if (typeof preludeRule === 'string') {
1445
+ const rec = $;
1446
+ return rec[preludeRule];
1447
+ }
1448
+ return preludeRule;
1449
+ }
1450
+ export function mediaAtRule(T, preludeRule) {
1451
+ const $ = this;
1452
+ return (ctx = {}) => {
1453
+ let RECORDING_PHASE = $.RECORDING_PHASE;
1454
+ $.startRule();
1455
+ let name = $.CONSUME(T.AtMedia);
1456
+ let rules;
1457
+ const resolvedPreludeRule = resolvePreludeRule($, preludeRule);
1458
+ const prelude = typeof resolvedPreludeRule === 'function'
1459
+ ? $.SUBRULE(resolvedPreludeRule, { ARGS: [ctx] })
1460
+ : $.SUBRULE($.mediaQueryList, { ARGS: [ctx] });
1461
+ $.CONSUME(T.LCurly);
1462
+ rules = $.SUBRULE($.atRuleBody, { ARGS: [ctx] });
1463
+ $.CONSUME(T.RCurly);
1464
+ if (!RECORDING_PHASE) {
1465
+ let location = $.endRule();
1466
+ return new AtRule({
1467
+ name: $.wrap(new Any(name.image, { role: 'atkeyword' }, $.getLocationInfo(name), this.context), true),
1468
+ prelude: $.wrap(prelude, true),
1469
+ rules
1470
+ }, { nestable: true }, location, this.context);
1471
+ }
1472
+ };
1473
+ }
1474
+ export function mediaQueryList(T) {
1475
+ const $ = this;
1476
+ return (ctx = {}) => {
1477
+ let RECORDING_PHASE = $.RECORDING_PHASE;
1478
+ $.startRule();
1479
+ let queries = RECORDING_PHASE ? undefined : [];
1480
+ $.AT_LEAST_ONE_SEP({
1481
+ SEP: T.Comma,
1482
+ DEF: () => {
1483
+ let query = $.SUBRULE($.mediaQuery, { ARGS: [ctx] });
1484
+ if (!RECORDING_PHASE) {
1485
+ queries.push(query);
1486
+ }
1487
+ }
1488
+ });
1489
+ if (!RECORDING_PHASE) {
1490
+ if (queries.length === 1) {
1491
+ $.endRule();
1492
+ return queries[0];
1493
+ }
1494
+ return new List(queries, undefined, $.endRule(), this.context);
1495
+ }
1496
+ };
1497
+ }
1498
+ /**
1499
+ * @see https://w3c.github.io/csswg-drafts/mediaqueries/#mq-syntax
1500
+ * Note, some of the spec had to be re-written for less ambiguity.
1501
+ * However, this is a spec-compliant implementation.
1502
+ */
1503
+ // mediaQuery
1504
+ // : mediaCondition
1505
+ // | ((NOT | ONLY) WS*)? mediaType (WS* AND WS* mediaConditionWithoutOr)?
1506
+ // ;
1507
+ export function mediaQuery(T, alt) {
1508
+ const $ = this;
1509
+ alt ??= (ctx = {}) => [
1510
+ { ALT: () => $.SUBRULE($.mediaCondition, { ARGS: [ctx] }) },
1511
+ {
1512
+ ALT: () => {
1513
+ let RECORDING_PHASE = $.RECORDING_PHASE;
1514
+ $.startRule();
1515
+ let token;
1516
+ let node;
1517
+ let nodes;
1518
+ if (!RECORDING_PHASE) {
1519
+ nodes = [];
1520
+ }
1521
+ $.OPTION(() => {
1522
+ $.OR2([
1523
+ { ALT: () => token = $.CONSUME(T.Not) },
1524
+ { ALT: () => token = $.CONSUME(T.Only) }
1525
+ ]);
1526
+ });
1527
+ if (token && !RECORDING_PHASE) {
1528
+ nodes.push($.wrap(new Keyword(token.image, undefined, $.getLocationInfo(token), this.context), 'both'));
1529
+ token = undefined;
1530
+ }
1531
+ let type = $.SUBRULE($.mediaType, { ARGS: [ctx] });
1532
+ if (!RECORDING_PHASE) {
1533
+ nodes.push(type);
1534
+ }
1535
+ $.OPTION2(() => {
1536
+ token = $.CONSUME(T.And);
1537
+ node = $.SUBRULE($.mediaConditionWithoutOr, { ARGS: [ctx] });
1538
+ });
1539
+ if (!RECORDING_PHASE) {
1540
+ if (token) {
1541
+ nodes.push($.wrap(new Keyword(token.image, undefined, $.getLocationInfo(token), this.context), 'both'));
1542
+ }
1543
+ if (node) {
1544
+ nodes.push(node);
1545
+ }
1546
+ }
1547
+ if (!RECORDING_PHASE) {
1548
+ let location = $.endRule();
1549
+ return new QueryCondition(nodes, undefined, location, this.context);
1550
+ }
1551
+ }
1552
+ }
1553
+ ];
1554
+ return (ctx = {}) => $.OR(alt(ctx));
1555
+ }
1556
+ /** Doesn't include only, not, and, or, layer */
1557
+ // mediaType
1558
+ // : IDENT
1559
+ // | SCREEN
1560
+ // | PRINT
1561
+ // | ALL
1562
+ // ;
1563
+ export function mediaType(T, alt) {
1564
+ const $ = this;
1565
+ alt ??= (ctx = {}) => [
1566
+ { ALT: () => $.CONSUME(T.PlainIdent) },
1567
+ { ALT: () => $.CONSUME(T.Screen) },
1568
+ { ALT: () => $.CONSUME(T.Print) },
1569
+ { ALT: () => $.CONSUME(T.All) }
1570
+ ];
1571
+ return (ctx = {}) => {
1572
+ let token = $.OR(alt(ctx));
1573
+ if (!$.RECORDING_PHASE) {
1574
+ return $.wrap(new Keyword(token.image, undefined, $.getLocationInfo(token), this.context), 'both');
1575
+ }
1576
+ };
1577
+ }
1578
+ // mediaCondition
1579
+ // : mediaNot | mediaInParens ( WS* (mediaAnd* | mediaOr* ))
1580
+ // ;
1581
+ export function mediaCondition(T, alt) {
1582
+ const $ = this;
1583
+ alt ??= (ctx = {}) => [
1584
+ { ALT: () => $.SUBRULE($.mediaNot, { ARGS: [ctx] }) },
1585
+ {
1586
+ ALT: () => {
1587
+ let RECORDING_PHASE = $.RECORDING_PHASE;
1588
+ $.startRule();
1589
+ let nodes;
1590
+ if (!RECORDING_PHASE) {
1591
+ nodes = [];
1592
+ }
1593
+ let node = $.SUBRULE($.mediaInParens, { ARGS: [ctx] });
1594
+ if (!RECORDING_PHASE) {
1595
+ nodes.push(node);
1596
+ }
1597
+ $.MANY(() => {
1598
+ let rule = $.OR2([
1599
+ { ALT: () => $.SUBRULE($.mediaAnd, { ARGS: [ctx] }) },
1600
+ { ALT: () => $.SUBRULE($.mediaOr, { ARGS: [ctx] }) }
1601
+ ]);
1602
+ if (!RECORDING_PHASE) {
1603
+ nodes.push(...rule);
1604
+ }
1605
+ });
1606
+ if (!RECORDING_PHASE) {
1607
+ // Only wrap in QueryCondition if there are multiple nodes (AND/OR operators)
1608
+ // Otherwise, return the single node directly (like Sequence does)
1609
+ if (nodes.length === 1) {
1610
+ $.endRule();
1611
+ return nodes[0];
1612
+ }
1613
+ return new QueryCondition(nodes, undefined, $.endRule(), this.context);
1614
+ }
1615
+ }
1616
+ }
1617
+ ];
1618
+ return (ctx = {}) => $.OR(alt(ctx));
1619
+ }
1620
+ // mediaConditionWithoutOr
1621
+ // : mediaNot | mediaInParens (WS* mediaAnd)*
1622
+ // ;
1623
+ export function mediaConditionWithoutOr(T, alt) {
1624
+ const $ = this;
1625
+ alt ??= (ctx = {}) => [
1626
+ { ALT: () => $.SUBRULE($.mediaNot, { ARGS: [ctx] }) },
1627
+ {
1628
+ ALT: () => {
1629
+ let RECORDING_PHASE = $.RECORDING_PHASE;
1630
+ $.startRule();
1631
+ let nodes;
1632
+ if (!RECORDING_PHASE) {
1633
+ nodes = [];
1634
+ }
1635
+ let node = $.SUBRULE($.mediaInParens, { ARGS: [ctx] });
1636
+ if (!RECORDING_PHASE) {
1637
+ nodes.push(node);
1638
+ }
1639
+ $.MANY(() => {
1640
+ let rule = $.SUBRULE($.mediaAnd, { ARGS: [ctx] });
1641
+ if (!RECORDING_PHASE) {
1642
+ nodes.push(...rule);
1643
+ }
1644
+ });
1645
+ if (!RECORDING_PHASE) {
1646
+ // Only wrap in QueryCondition if there are multiple nodes (AND operators)
1647
+ // Otherwise, return the single node directly (like Sequence does)
1648
+ if (nodes.length === 1) {
1649
+ $.endRule();
1650
+ return nodes[0];
1651
+ }
1652
+ return new QueryCondition(nodes, undefined, $.endRule(), this.context);
1653
+ }
1654
+ }
1655
+ }
1656
+ ];
1657
+ return (ctx = {}) => $.OR(alt(ctx));
1658
+ }
1659
+ // mediaNot
1660
+ // : NOT WS* mediaInParens
1661
+ // ;
1662
+ export function mediaNot(T) {
1663
+ const $ = this;
1664
+ return (ctx = {}) => {
1665
+ $.startRule();
1666
+ let token = $.CONSUME(T.Not);
1667
+ let node = $.SUBRULE($.mediaInParens, { ARGS: [ctx] });
1668
+ if (!$.RECORDING_PHASE) {
1669
+ return new QueryCondition([
1670
+ $.wrap(new Keyword(token.image, undefined, $.getLocationInfo(token), this.context), 'both'),
1671
+ node
1672
+ ], undefined, $.endRule(), this.context);
1673
+ }
1674
+ };
1675
+ }
1676
+ // mediaAnd
1677
+ // : AND WS* mediaInParens
1678
+ // ;
1679
+ export function mediaAnd(T) {
1680
+ const $ = this;
1681
+ /** Returns an array */
1682
+ return (ctx = {}) => {
1683
+ let token = $.CONSUME(T.And);
1684
+ let node = $.SUBRULE($.mediaInParens, { ARGS: [ctx] });
1685
+ if (!$.RECORDING_PHASE) {
1686
+ return [
1687
+ $.wrap(new Keyword(token.image, undefined, $.getLocationInfo(token), this.context), 'both'),
1688
+ node
1689
+ ];
1690
+ }
1691
+ };
1692
+ }
1693
+ // mediaOr
1694
+ // : OR WS* mediaInParens
1695
+ // ;
1696
+ export function mediaOr(T) {
1697
+ const $ = this;
1698
+ /** Returns an array */
1699
+ return (ctx = {}) => {
1700
+ let token = $.CONSUME(T.Or);
1701
+ let node = $.SUBRULE($.mediaInParens, { ARGS: [ctx] });
1702
+ if (!$.RECORDING_PHASE) {
1703
+ return [
1704
+ $.wrap(new Keyword(token.image, undefined, $.getLocationInfo(token), this.context), 'both'),
1705
+ node
1706
+ ];
1707
+ }
1708
+ };
1709
+ }
1710
+ // mediaInParens
1711
+ // : '(' WS* (mediaCondition | mediaFeature) WS* ')'
1712
+ // | generalEnclosed
1713
+ // ;
1714
+ export function mediaInParens(T, alt) {
1715
+ const $ = this;
1716
+ alt ??= (ctx = {}) => [
1717
+ { ALT: () => $.SUBRULE($.mediaCondition, { ARGS: [ctx] }) },
1718
+ { ALT: () => $.SUBRULE($.mediaFeature, { ARGS: [ctx] }) }
1719
+ ];
1720
+ return (ctx = {}) => {
1721
+ let RECORDING_PHASE = $.RECORDING_PHASE;
1722
+ $.startRule();
1723
+ $.CONSUME(T.LParen);
1724
+ /*
1725
+ * CSS also allows for parentheses to contain
1726
+ * almost anything, including a wild sequence
1727
+ * of tokens (e.g. `@media (!!&) {}`), as it would
1728
+ * be up to the user agent to decide what the content
1729
+ * of the parentheses means. (CSS defines this as
1730
+ * "generalEnclosed" in the spec.)
1731
+ *
1732
+ * But that would mean that detecting errors in
1733
+ * parsing would not be possible. So we only parse
1734
+ * "known" media queries.
1735
+ */
1736
+ let node = $.OR2(alt(ctx));
1737
+ $.CONSUME(T.RParen);
1738
+ if (!RECORDING_PHASE) {
1739
+ let location = $.endRule();
1740
+ return $.wrap(new Paren($.wrap(node, 'both'), undefined, location, this.context));
1741
+ }
1742
+ };
1743
+ }
1744
+ /**
1745
+ An identifier is a legal value, so it can be
1746
+ ambiguous which side of the expression we're on
1747
+ while parsing. The browser figures this out
1748
+ post-parsing.
1749
+ */
1750
+ // mediaFeature
1751
+ // : identifier (WS* (
1752
+ // COLON WS* mfValue
1753
+ // | mediaRange
1754
+ // | mfComparison WS* mfNonIdentifierValue
1755
+ // ))?
1756
+ // | mfNonIdentifierValue WS* (
1757
+ // mfComparison WS* identifier
1758
+ // | mediaRange
1759
+ // )
1760
+ // ;
1761
+ export function mediaFeature(T, alt) {
1762
+ const $ = this;
1763
+ alt ??= (ctx = {}) => [
1764
+ {
1765
+ ALT: () => {
1766
+ let RECORDING_PHASE = $.RECORDING_PHASE;
1767
+ $.startRule();
1768
+ let rule;
1769
+ let ident = $.CONSUME(T.Ident);
1770
+ $.OPTION(() => {
1771
+ rule = $.OR2([
1772
+ {
1773
+ ALT: () => {
1774
+ $.CONSUME(T.Colon);
1775
+ let value = $.SUBRULE($.mfValue, { ARGS: [ctx] });
1776
+ if (!RECORDING_PHASE) {
1777
+ let location = $.endRule();
1778
+ return $.wrap(new Declaration({
1779
+ name: $.wrap(new Any(ident.image, { role: 'property' }), true),
1780
+ value: $.wrap(value)
1781
+ }, undefined, location, this.context), 'both');
1782
+ }
1783
+ }
1784
+ },
1785
+ {
1786
+ ALT: () => {
1787
+ let seq = $.SUBRULE($.mediaRange, { ARGS: [ctx] });
1788
+ if (!RECORDING_PHASE) {
1789
+ let [startOffset, startLine, startColumn] = $.endRule();
1790
+ seq.value.unshift($.wrap(new Any(ident.image, { role: 'ident' }, $.getLocationInfo(ident), this.context)));
1791
+ seq.location[0] = startOffset;
1792
+ seq.location[1] = startLine;
1793
+ seq.location[2] = startColumn;
1794
+ return new QueryCondition(seq.value, undefined, seq.location, this.context);
1795
+ }
1796
+ return seq;
1797
+ }
1798
+ },
1799
+ {
1800
+ ALT: () => {
1801
+ let op = $.SUBRULE($.mfComparison, { ARGS: [ctx] });
1802
+ let value = $.SUBRULE($.mfNonIdentifierValue, { ARGS: [ctx] });
1803
+ if (!RECORDING_PHASE) {
1804
+ let location = $.endRule();
1805
+ return new QueryCondition([
1806
+ $.wrap(new Any(ident.image, { role: 'ident' }, $.getLocationInfo(ident), this.context)),
1807
+ $.wrap(new Any(op.image, { role: 'operator' }, $.getLocationInfo(op), this.context), 'both'),
1808
+ value
1809
+ ], undefined, location, this.context);
1810
+ }
1811
+ }
1812
+ }
1813
+ ]);
1814
+ });
1815
+ if (!RECORDING_PHASE && !rule) {
1816
+ let location = $.endRule();
1817
+ let anyNode = new Keyword(ident.image, undefined, location, this.context);
1818
+ return $.wrap(new QueryCondition([anyNode], undefined, location, this.context), 'both');
1819
+ }
1820
+ return rule;
1821
+ }
1822
+ },
1823
+ {
1824
+ ALT: () => {
1825
+ let RECORDING_PHASE = $.RECORDING_PHASE;
1826
+ $.startRule();
1827
+ let rule1 = $.SUBRULE2($.mfNonIdentifierValue, { ARGS: [{ ...ctx }] });
1828
+ return $.OR3([
1829
+ {
1830
+ ALT: () => {
1831
+ let op = $.SUBRULE2($.mfComparison, { ARGS: [{ ...ctx }] });
1832
+ let value = $.CONSUME2(T.Ident);
1833
+ if (!RECORDING_PHASE) {
1834
+ let location = $.endRule();
1835
+ return new QueryCondition([
1836
+ rule1,
1837
+ $.wrap(new Any(op.image, { role: 'operator' }, $.getLocationInfo(op), this.context)),
1838
+ $.wrap(new Any(value.image, { role: 'ident' }, $.getLocationInfo(value), this.context), 'both')
1839
+ ], undefined, location, this.context);
1840
+ }
1841
+ }
1842
+ },
1843
+ {
1844
+ ALT: () => {
1845
+ let seq = $.SUBRULE2($.mediaRange, { ARGS: [{ ...ctx }] });
1846
+ if (!RECORDING_PHASE) {
1847
+ let [startOffset, startLine, startColumn] = $.endRule();
1848
+ seq.value.unshift(rule1);
1849
+ seq.location[0] = startOffset;
1850
+ seq.location[1] = startLine;
1851
+ seq.location[2] = startColumn;
1852
+ return new QueryCondition(seq.value, undefined, seq.location, this.context);
1853
+ }
1854
+ return seq;
1855
+ }
1856
+ }
1857
+ ]);
1858
+ }
1859
+ }
1860
+ ];
1861
+ return (ctx = {}) => $.OR(alt(ctx));
1862
+ }
1863
+ /**
1864
+ * @note Both comparison operators have to match.
1865
+ */
1866
+ // mediaRange
1867
+ // : mfLt WS* identifier (WS* mfLt WS* mfValue)?
1868
+ // | mfGt WS* identifier (WS* mfGt WS* mfValue)?
1869
+ // ;
1870
+ export function mediaRange(T, alt) {
1871
+ const $ = this;
1872
+ alt ??= (ctx = {}) => [
1873
+ {
1874
+ ALT: () => {
1875
+ let op1 = $.CONSUME(T.MfLt);
1876
+ let val1 = $.CONSUME(T.Ident);
1877
+ let op2;
1878
+ let val2;
1879
+ $.OPTION(() => {
1880
+ op2 = $.CONSUME2(T.MfLt);
1881
+ val2 = $.SUBRULE($.mfValue, { ARGS: [ctx] });
1882
+ });
1883
+ return [op1, val1, op2, val2];
1884
+ }
1885
+ },
1886
+ {
1887
+ ALT: () => {
1888
+ let op1 = $.CONSUME(T.MfGt);
1889
+ let val1 = $.CONSUME2(T.Ident);
1890
+ let op2;
1891
+ let val2;
1892
+ $.OPTION2(() => {
1893
+ op2 = $.CONSUME2(T.MfGt);
1894
+ val2 = $.SUBRULE2($.mfValue, { ARGS: [ctx] });
1895
+ });
1896
+ return [op1, val1, op2, val2];
1897
+ }
1898
+ }
1899
+ ];
1900
+ return (ctx = {}) => {
1901
+ let RECORDING_PHASE = $.RECORDING_PHASE;
1902
+ $.startRule();
1903
+ let op1;
1904
+ let val1;
1905
+ let op2;
1906
+ let val2;
1907
+ let val = $.OR(alt(ctx));
1908
+ if (!RECORDING_PHASE) {
1909
+ ([op1, val1, op2, val2] = val);
1910
+ }
1911
+ if (!$.RECORDING_PHASE) {
1912
+ let location = $.endRule();
1913
+ let nodes = [
1914
+ $.wrap(new Any(op1.image, { role: 'operator' }, $.getLocationInfo(op1), this.context)),
1915
+ $.wrap(new Any(val1.image, { role: 'ident' }, $.getLocationInfo(val1), this.context), 'both')
1916
+ ];
1917
+ if (op2) {
1918
+ nodes.push($.wrap(new Any(op2.image, { role: 'operator' }, $.getLocationInfo(op2), this.context)));
1919
+ nodes.push($.wrap(val2, 'both'));
1920
+ }
1921
+ return new Sequence(nodes, undefined, location, this.context);
1922
+ }
1923
+ };
1924
+ }
1925
+ // mfNonIdentifierValue
1926
+ // : number (WS* '/' WS* number)?
1927
+ // | dimension
1928
+ // ;
1929
+ export function mfNonIdentifierValue(T, alt) {
1930
+ const $ = this;
1931
+ alt ??= (ctx = {}) => [
1932
+ {
1933
+ ALT: () => {
1934
+ $.startRule();
1935
+ let num1 = $.CONSUME(T.Number);
1936
+ let num2;
1937
+ $.OPTION(() => {
1938
+ $.CONSUME(T.Slash);
1939
+ num2 = $.CONSUME2(T.Number);
1940
+ });
1941
+ if (!$.RECORDING_PHASE) {
1942
+ let location = $.endRule();
1943
+ let num1Node = $.wrap($.processValueToken(num1), 'both');
1944
+ if (!num2) {
1945
+ return num1Node;
1946
+ }
1947
+ let num2Node = $.wrap($.processValueToken(num2), 'both');
1948
+ return new List([num1Node, num2Node], { sep: '/' }, location, this.context);
1949
+ }
1950
+ }
1951
+ },
1952
+ {
1953
+ ALT: () => {
1954
+ let dim = $.CONSUME(T.Dimension);
1955
+ if (!$.RECORDING_PHASE) {
1956
+ return $.wrap($.processValueToken(dim), 'both');
1957
+ }
1958
+ }
1959
+ }
1960
+ ];
1961
+ return (ctx = {}) => $.OR(alt(ctx));
1962
+ }
1963
+ // mfValue
1964
+ // : mfNonIdentifierValue | identifier
1965
+ // ;
1966
+ export function mfValue(T, alt) {
1967
+ const $ = this;
1968
+ alt ??= (ctx = {}) => [
1969
+ { ALT: () => $.SUBRULE($.mfNonIdentifierValue, { ARGS: [ctx] }) },
1970
+ {
1971
+ ALT: () => {
1972
+ let token = $.CONSUME(T.Ident);
1973
+ if (!$.RECORDING_PHASE) {
1974
+ return $.wrap(new Any(token.image, { role: 'ident' }, $.getLocationInfo(token), this.context), 'both');
1975
+ }
1976
+ }
1977
+ }
1978
+ ];
1979
+ return (ctx = {}) => $.OR(alt(ctx));
1980
+ }
1981
+ // mfComparison
1982
+ // : mfLt | mfGt | mfEq
1983
+ // ;
1984
+ export function mfComparison(T) {
1985
+ const $ = this;
1986
+ let comparisonAlt = [
1987
+ { ALT: () => $.CONSUME(T.MfLt) },
1988
+ { ALT: () => $.CONSUME(T.MfGt) },
1989
+ { ALT: () => $.CONSUME(T.Eq) }
1990
+ ];
1991
+ return () => $.OR(comparisonAlt);
1992
+ }
1993
+ /**
1994
+ * @see https://www.w3.org/TR/css-page-3/
1995
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@page
1996
+ */
1997
+ export function pageAtRule(T) {
1998
+ const $ = this;
1999
+ return (ctx = {}) => {
2000
+ $.startRule();
2001
+ let name = $.CONSUME(T.AtPage);
2002
+ let selector = [];
2003
+ $.MANY_SEP({
2004
+ SEP: T.Comma,
2005
+ DEF: () => selector.push($.SUBRULE($.pageSelector, { ARGS: [ctx] }))
2006
+ });
2007
+ $.CONSUME(T.LCurly);
2008
+ let rules = $.SUBRULE($.declarationList, { ARGS: [ctx] });
2009
+ $.CONSUME(T.RCurly);
2010
+ if (!$.RECORDING_PHASE) {
2011
+ let location = $.endRule();
2012
+ return new AtRule({
2013
+ name: $.wrap(new Any(name.image, { role: 'atkeyword' }, $.getLocationInfo(name), this.context), true),
2014
+ prelude: selector.length ? $.wrap(new List(selector, undefined, $.getLocationFromNodes(selector), this.context), true) : undefined,
2015
+ rules
2016
+ }, undefined, location, this.context);
2017
+ }
2018
+ };
2019
+ }
2020
+ export function pageSelector(T) {
2021
+ const $ = this;
2022
+ return (ctx = {}) => {
2023
+ $.startRule();
2024
+ let token = '';
2025
+ $.OPTION(() => token += $.CONSUME(T.Ident).image);
2026
+ $.MANY({
2027
+ GATE: () => $.LA(1).tokenType === T.Colon && $.noSep(1),
2028
+ DEF: () => {
2029
+ token += $.CONSUME(T.Colon).image;
2030
+ token += $.CONSUME(T.PagePseudoClassKeywords).image;
2031
+ }
2032
+ });
2033
+ if (!$.RECORDING_PHASE) {
2034
+ let location = $.endRule();
2035
+ return $.wrap(new BasicSelector(token, undefined, location, this.context));
2036
+ }
2037
+ };
2038
+ }
2039
+ // fontFaceAtRule
2040
+ // : FONT_FACE_RULE WS* LCURLY declarationList RCURLY
2041
+ // ;
2042
+ export function fontFaceAtRule(T) {
2043
+ const $ = this;
2044
+ return (ctx = {}) => {
2045
+ $.startRule();
2046
+ let name = $.CONSUME(T.AtFontFace);
2047
+ $.CONSUME(T.LCurly);
2048
+ let rules = $.SUBRULE($.declarationList, { ARGS: [ctx] });
2049
+ $.CONSUME(T.RCurly);
2050
+ if (!$.RECORDING_PHASE) {
2051
+ let location = $.endRule();
2052
+ return new AtRule({
2053
+ name: $.wrap(new Any(name.image, { role: 'atkeyword' }, $.getLocationInfo(name), this.context), true),
2054
+ rules
2055
+ }, undefined, location, this.context);
2056
+ }
2057
+ };
2058
+ }
2059
+ // keyframesAtRule
2060
+ // : (AT_KEYFRAMES | vendorKeyframes) WS* IDENT WS* '{' keyframeBlock* '}'
2061
+ // ;
2062
+ export function keyframesAtRule(T) {
2063
+ const $ = this;
2064
+ return (ctx = {}) => {
2065
+ const RECORDING_PHASE = $.RECORDING_PHASE;
2066
+ $.startRule();
2067
+ let atTok = $.CONSUME(T.AtKeyframes);
2068
+ // prelude: a single animation name
2069
+ let preludeNode = $.SUBRULE($.keyframesName, { ARGS: [ctx] });
2070
+ $.CONSUME(T.LCurly);
2071
+ const rules = $.SUBRULE($.declarationList, { ARGS: [ctx] });
2072
+ $.CONSUME(T.RCurly);
2073
+ if (!$.RECORDING_PHASE) {
2074
+ return new AtRule({
2075
+ name: $.wrap(new Any(atTok.image, { role: 'atkeyword' }, $.getLocationInfo(atTok), this.context), true),
2076
+ prelude: preludeNode ? $.wrap(preludeNode, 'both') : undefined,
2077
+ // Include isolated comments inside the keyframes body
2078
+ rules
2079
+ }, undefined, $.endRule(), this.context);
2080
+ }
2081
+ };
2082
+ }
2083
+ /**
2084
+ * Keyframes name prelude
2085
+ * CSS: Ident | String
2086
+ */
2087
+ export function keyframesName(T) {
2088
+ const $ = this;
2089
+ return (ctx = {}) => {
2090
+ const RECORDING_PHASE = $.RECORDING_PHASE;
2091
+ let node;
2092
+ $.OR({
2093
+ DEF: [
2094
+ { ALT: () => {
2095
+ const tok = $.CONSUME(T.Ident);
2096
+ if (!RECORDING_PHASE) {
2097
+ node = $.wrap($.processValueToken(tok));
2098
+ }
2099
+ } },
2100
+ { ALT: () => node = $.SUBRULE($.string, { ARGS: [ctx] }) }
2101
+ ]
2102
+ });
2103
+ return node;
2104
+ };
2105
+ }
2106
+ // containerAtRule: @container <container-name>? <container-query-list> { main }
2107
+ /**
2108
+ * Parses @container at-rule with optional container name and container query list.
2109
+ *
2110
+ * WHAT I'M TRYING TO DO:
2111
+ * Disambiguate between:
2112
+ * 1. `@container sidebar (width > 400px)` - `sidebar` is a container name
2113
+ * 2. `@container size(min-width: 60ch)` - `size` is NOT a container name, it's a function call (FunctionStart token)
2114
+ * 3. `@container (width > 400px)` - no container name, query starts directly
2115
+ *
2116
+ * Strategy:
2117
+ * - If next token is FunctionStart (like `size(` or `style(`), it's a query function, NOT a container name
2118
+ * - If next token is Ident (not a query keyword), it COULD be a container name
2119
+ * - The containerQueryList production will handle parsing the actual query (whether it's a function or condition)
2120
+ *
2121
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@container
2122
+ */
2123
+ export function containerAtRule(T, preludeRule) {
2124
+ const $ = this;
2125
+ return (ctx = {}) => {
2126
+ $.startRule();
2127
+ const name = $.CONSUME(T.AtContainer);
2128
+ let prelude;
2129
+ let containerName;
2130
+ let queryList;
2131
+ if (preludeRule) {
2132
+ const resolvedPreludeRule = resolvePreludeRule($, preludeRule);
2133
+ if (typeof resolvedPreludeRule === 'function') {
2134
+ prelude = $.SUBRULE(resolvedPreludeRule, { ARGS: [ctx] });
2135
+ }
2136
+ }
2137
+ else {
2138
+ $.OR([
2139
+ {
2140
+ GATE: () => {
2141
+ const next = $.LA(1);
2142
+ // If it's a FunctionStart (like `size(` or `style(`), it's a query function, not a container name
2143
+ if (tokenMatcher(next, T.FunctionStart)) {
2144
+ return false;
2145
+ }
2146
+ // If it's an Ident (not a query keyword), it could be a container name
2147
+ return (next.tokenType === T.Ident || next.tokenType === T.PlainIdent)
2148
+ && next.image.toLowerCase() !== 'not'
2149
+ && next.image.toLowerCase() !== 'only'
2150
+ && next.image.toLowerCase() !== 'and'
2151
+ && next.image.toLowerCase() !== 'or';
2152
+ },
2153
+ ALT: () => {
2154
+ containerName = $.SUBRULE($.containerName, { ARGS: [ctx] });
2155
+ queryList = $.SUBRULE($.containerQueryList, { ARGS: [ctx] });
2156
+ }
2157
+ },
2158
+ {
2159
+ ALT: () => {
2160
+ queryList = $.SUBRULE2($.containerQueryList, { ARGS: [ctx] });
2161
+ }
2162
+ }
2163
+ ]);
2164
+ queryList = queryList;
2165
+ }
2166
+ $.CONSUME(T.LCurly);
2167
+ const rules = $.SUBRULE($.atRuleBody, { ARGS: [ctx] });
2168
+ $.CONSUME(T.RCurly);
2169
+ if (!$.RECORDING_PHASE) {
2170
+ let preludeNodes = [];
2171
+ if (!prelude && containerName) {
2172
+ preludeNodes.push($.wrap(containerName, true));
2173
+ }
2174
+ if (!prelude) {
2175
+ preludeNodes.push($.wrap(queryList, containerName ? true : 'both'));
2176
+ prelude = preludeNodes.length
2177
+ ? $.wrap(new Sequence(preludeNodes, undefined, $.getLocationFromNodes(preludeNodes), this.context), 'both')
2178
+ : undefined;
2179
+ }
2180
+ return new AtRule({
2181
+ name: $.wrap(new Any(name.image, { role: 'atkeyword' }, $.getLocationInfo(name), this.context), true),
2182
+ prelude,
2183
+ rules
2184
+ }, { nestable: true }, $.endRule(), this.context);
2185
+ }
2186
+ };
2187
+ }
2188
+ /**
2189
+ * Container name: an optional identifier
2190
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@container#container-name
2191
+ */
2192
+ export function containerName(T) {
2193
+ const $ = this;
2194
+ return (ctx = {}) => {
2195
+ let token = $.CONSUME(T.Ident);
2196
+ if (!$.RECORDING_PHASE) {
2197
+ return $.wrap(new Any(token.image, { role: 'ident' }, $.getLocationInfo(token), this.context), 'both');
2198
+ }
2199
+ };
2200
+ }
2201
+ /**
2202
+ * Container query list: comma-separated list of container queries
2203
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@container#container-query
2204
+ */
2205
+ export function containerQueryList(T) {
2206
+ const $ = this;
2207
+ return (ctx = {}) => {
2208
+ let RECORDING_PHASE = $.RECORDING_PHASE;
2209
+ $.startRule();
2210
+ let queries = RECORDING_PHASE ? undefined : [];
2211
+ $.AT_LEAST_ONE_SEP({
2212
+ SEP: T.Comma,
2213
+ DEF: () => {
2214
+ let query = $.SUBRULE($.containerQuery, { ARGS: [ctx] });
2215
+ if (!RECORDING_PHASE) {
2216
+ queries.push(query);
2217
+ }
2218
+ }
2219
+ });
2220
+ if (!RECORDING_PHASE) {
2221
+ if (queries.length === 1) {
2222
+ $.endRule();
2223
+ return queries[0];
2224
+ }
2225
+ return new List(queries, undefined, $.endRule(), this.context);
2226
+ }
2227
+ };
2228
+ }
2229
+ /**
2230
+ * Container query: a container condition or container query type function
2231
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@container#container-query
2232
+ *
2233
+ * Container queries can be:
2234
+ * - Regular conditions: (width > 400px)
2235
+ * - Container query type functions: size(min-width: 60ch), style(--responsive: true), scroll-state(stuck: top)
2236
+ */
2237
+ export function containerQuery(T) {
2238
+ const $ = this;
2239
+ return (ctx = {}) => {
2240
+ return $.OR([
2241
+ {
2242
+ // Container query type function: any FunctionStart token
2243
+ // This allows for size(...), style(...), scroll-state(...), and any Less-evaluated functions
2244
+ GATE: () => tokenMatcher($.LA(1), T.FunctionStart),
2245
+ ALT: () => {
2246
+ $.startRule();
2247
+ let nodes;
2248
+ if (!$.RECORDING_PHASE) {
2249
+ nodes = [];
2250
+ }
2251
+ // Parse first function call
2252
+ const funcStart = $.CONSUME(T.FunctionStart);
2253
+ const funcName = funcStart.image.slice(0, -1);
2254
+ let args = !$.RECORDING_PHASE ? [] : undefined;
2255
+ $.AT_LEAST_ONE_SEP({
2256
+ SEP: T.Comma,
2257
+ DEF: () => {
2258
+ // Arguments can be QueryConditions, declarations, or just a name (Any)
2259
+ $.OR2([
2260
+ {
2261
+ // QueryCondition: starts with LParen or Not
2262
+ GATE: () => {
2263
+ const next = $.LA(1);
2264
+ return next.tokenType === T.LParen || next.tokenType === T.Not;
2265
+ },
2266
+ ALT: () => {
2267
+ const arg = $.SUBRULE2($.containerCondition, { ARGS: [ctx] });
2268
+ if (!$.RECORDING_PHASE) {
2269
+ args.push($.wrap(arg));
2270
+ }
2271
+ }
2272
+ },
2273
+ {
2274
+ // Declaration: starts with Ident or CustomProperty followed by Assign (colon)
2275
+ GATE: () => {
2276
+ const next = $.LA(1);
2277
+ const after = $.LA(2);
2278
+ const isIdent = next.tokenType === T.Ident || next.tokenType === T.PlainIdent || next.tokenType === T.CustomProperty;
2279
+ return isIdent && after && tokenMatcher(after, T.Assign);
2280
+ },
2281
+ ALT: () => {
2282
+ const arg = $.SUBRULE($.declaration, { ARGS: [ctx] });
2283
+ if (!$.RECORDING_PHASE) {
2284
+ args.push($.wrap(arg));
2285
+ }
2286
+ }
2287
+ },
2288
+ {
2289
+ // Just a name (Any): Ident, PlainIdent, or CustomProperty without Assign
2290
+ GATE: () => {
2291
+ const next = $.LA(1);
2292
+ const after = $.LA(2);
2293
+ const isIdent = next.tokenType === T.Ident || next.tokenType === T.PlainIdent || next.tokenType === T.CustomProperty;
2294
+ return isIdent && (!after || !tokenMatcher(after, T.Assign));
2295
+ },
2296
+ ALT: () => {
2297
+ let nameToken;
2298
+ $.OR3([
2299
+ { ALT: () => nameToken = $.CONSUME(T.Ident) },
2300
+ { ALT: () => nameToken = $.CONSUME(T.PlainIdent) },
2301
+ { ALT: () => nameToken = $.CONSUME(T.CustomProperty) }
2302
+ ]);
2303
+ if (!$.RECORDING_PHASE && nameToken) {
2304
+ const nameNode = $.wrap(new Any(nameToken.image, { role: 'name' }, $.getLocationInfo(nameToken), this.context), true);
2305
+ args.push(nameNode);
2306
+ }
2307
+ }
2308
+ }
2309
+ ]);
2310
+ }
2311
+ });
2312
+ $.CONSUME(T.RParen);
2313
+ if (!$.RECORDING_PHASE) {
2314
+ const call = new Call({
2315
+ name: funcName,
2316
+ args: args.length > 0 ? new List(args) : undefined
2317
+ }, undefined, $.getLocationFromNodes([funcStart]), this.context);
2318
+ nodes.push(call);
2319
+ }
2320
+ // Check for and/or after the function call (similar to mediaCondition)
2321
+ $.MANY(() => {
2322
+ let rule = $.OR4([
2323
+ { ALT: () => $.SUBRULE($.containerAnd, { ARGS: [ctx] }) },
2324
+ { ALT: () => $.SUBRULE($.containerOr, { ARGS: [ctx] }) }
2325
+ ]);
2326
+ if (!$.RECORDING_PHASE) {
2327
+ nodes.push(...rule);
2328
+ }
2329
+ });
2330
+ if (!$.RECORDING_PHASE) {
2331
+ const location = $.endRule();
2332
+ // Always wrap function calls in QueryCondition (even if alone)
2333
+ return new QueryCondition(nodes, undefined, location, this.context);
2334
+ }
2335
+ }
2336
+ },
2337
+ {
2338
+ // Regular container condition
2339
+ ALT: () => $.SUBRULE($.containerCondition, { ARGS: [ctx] })
2340
+ }
2341
+ ]);
2342
+ };
2343
+ }
2344
+ /**
2345
+ * Container condition: similar to media condition but without mediaType variant
2346
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@container#container-query
2347
+ *
2348
+ * Container conditions can also have `not` followed by a container query type function,
2349
+ * and `and`/`or` can be followed by `not`, which media queries don't support.
2350
+ */
2351
+ export function containerCondition(T, alt) {
2352
+ const $ = this;
2353
+ return (ctx = {}) => {
2354
+ return $.OR([
2355
+ {
2356
+ // Handle `not` followed by a container query type function (e.g., `not scroll-state(...)`)
2357
+ GATE: () => {
2358
+ const next = $.LA(1);
2359
+ if (next.tokenType === T.Not) {
2360
+ const afterNot = $.LA(2);
2361
+ return afterNot && tokenMatcher(afterNot, T.FunctionStart);
2362
+ }
2363
+ return false;
2364
+ },
2365
+ ALT: () => {
2366
+ $.startRule();
2367
+ const notToken = $.CONSUME(T.Not);
2368
+ // Parse the function call as a container query
2369
+ const funcQuery = $.SUBRULE($.containerQuery, { ARGS: [ctx] });
2370
+ if (!$.RECORDING_PHASE) {
2371
+ return new QueryCondition([
2372
+ $.wrap(new Keyword(notToken.image, undefined, $.getLocationInfo(notToken), this.context), 'both'),
2373
+ funcQuery
2374
+ ], undefined, $.endRule(), this.context);
2375
+ }
2376
+ }
2377
+ },
2378
+ {
2379
+ // Custom container condition that handles `and not` and `or not`
2380
+ // Always use container path for LParen (containerInParens handles the same as mediaInParens,
2381
+ // but containerAnd/containerOr can handle container-specific cases)
2382
+ GATE: () => {
2383
+ const next = $.LA(1);
2384
+ return next.tokenType === T.LParen;
2385
+ },
2386
+ ALT: () => {
2387
+ let RECORDING_PHASE = $.RECORDING_PHASE;
2388
+ $.startRule();
2389
+ let nodes;
2390
+ if (!RECORDING_PHASE) {
2391
+ nodes = [];
2392
+ }
2393
+ let node = $.SUBRULE($.containerInParens, { ARGS: [ctx] });
2394
+ if (!RECORDING_PHASE) {
2395
+ nodes.push(node);
2396
+ }
2397
+ $.MANY(() => {
2398
+ let rule = $.OR2([
2399
+ { ALT: () => $.SUBRULE($.containerAnd, { ARGS: [ctx] }) },
2400
+ { ALT: () => $.SUBRULE($.containerOr, { ARGS: [ctx] }) }
2401
+ ]);
2402
+ if (!RECORDING_PHASE) {
2403
+ nodes.push(...rule);
2404
+ }
2405
+ });
2406
+ if (!RECORDING_PHASE) {
2407
+ if (nodes.length === 1) {
2408
+ $.endRule();
2409
+ return nodes[0];
2410
+ }
2411
+ return new QueryCondition(nodes, undefined, $.endRule(), this.context);
2412
+ }
2413
+ }
2414
+ },
2415
+ {
2416
+ // For cases not starting with LParen (like `not` at start), reuse media condition logic
2417
+ GATE: () => {
2418
+ const next = $.LA(1);
2419
+ // Only use mediaCondition if it doesn't start with LParen (LParen case handled above)
2420
+ return next.tokenType !== T.LParen;
2421
+ },
2422
+ ALT: () => $.SUBRULE3($.mediaCondition, { ARGS: [ctx] })
2423
+ }
2424
+ ]);
2425
+ };
2426
+ }
2427
+ /**
2428
+ * Container and: similar to mediaAnd but can handle `and not` and function calls
2429
+ */
2430
+ export function containerAnd(T) {
2431
+ const $ = this;
2432
+ return (ctx = {}) => {
2433
+ let token = $.CONSUME(T.And);
2434
+ // Handle `and not` or `and` followed by containerInParens or function call
2435
+ let node;
2436
+ $.OR3([
2437
+ {
2438
+ GATE: () => $.LA(1).tokenType === T.Not,
2439
+ ALT: () => {
2440
+ const notToken = $.CONSUME(T.Not);
2441
+ node = $.SUBRULE($.containerInParens, { ARGS: [ctx] });
2442
+ if (!$.RECORDING_PHASE) {
2443
+ const notNode = $.wrap(new Keyword(notToken.image, undefined, $.getLocationInfo(notToken), this.context), 'both');
2444
+ node = new QueryCondition([notNode, node], undefined, $.getLocationFromNodes([notNode, node]), this.context);
2445
+ }
2446
+ }
2447
+ },
2448
+ {
2449
+ GATE: () => tokenMatcher($.LA(1), T.FunctionStart),
2450
+ ALT: () => {
2451
+ // Parse function call (reuse containerQuery logic)
2452
+ const funcStart = $.CONSUME(T.FunctionStart);
2453
+ const funcName = funcStart.image.slice(0, -1);
2454
+ let args = !$.RECORDING_PHASE ? [] : undefined;
2455
+ $.AT_LEAST_ONE_SEP({
2456
+ SEP: T.Comma,
2457
+ DEF: () => {
2458
+ $.OR2([
2459
+ {
2460
+ GATE: () => {
2461
+ const next = $.LA(1);
2462
+ return next.tokenType === T.LParen || next.tokenType === T.Not;
2463
+ },
2464
+ ALT: () => {
2465
+ const arg = $.SUBRULE2($.containerCondition, { ARGS: [ctx] });
2466
+ if (!$.RECORDING_PHASE) {
2467
+ args.push($.wrap(arg));
2468
+ }
2469
+ }
2470
+ },
2471
+ {
2472
+ GATE: () => {
2473
+ const next = $.LA(1);
2474
+ const after = $.LA(2);
2475
+ const isIdent = next.tokenType === T.Ident || next.tokenType === T.PlainIdent || next.tokenType === T.CustomProperty;
2476
+ return isIdent && after && tokenMatcher(after, T.Assign);
2477
+ },
2478
+ ALT: () => {
2479
+ const arg = $.SUBRULE($.declaration, { ARGS: [ctx] });
2480
+ if (!$.RECORDING_PHASE) {
2481
+ args.push($.wrap(arg));
2482
+ }
2483
+ }
2484
+ },
2485
+ {
2486
+ GATE: () => {
2487
+ const next = $.LA(1);
2488
+ const after = $.LA(2);
2489
+ const isIdent = next.tokenType === T.Ident || next.tokenType === T.PlainIdent || next.tokenType === T.CustomProperty;
2490
+ return isIdent && (!after || !tokenMatcher(after, T.Assign));
2491
+ },
2492
+ ALT: () => {
2493
+ let nameToken;
2494
+ $.OR7([
2495
+ { ALT: () => nameToken = $.CONSUME(T.Ident) },
2496
+ { ALT: () => nameToken = $.CONSUME(T.PlainIdent) },
2497
+ { ALT: () => nameToken = $.CONSUME(T.CustomProperty) }
2498
+ ]);
2499
+ if (!$.RECORDING_PHASE && nameToken) {
2500
+ const nameNode = $.wrap(new Any(nameToken.image, { role: 'name' }, $.getLocationInfo(nameToken), this.context), true);
2501
+ args.push(nameNode);
2502
+ }
2503
+ }
2504
+ }
2505
+ ]);
2506
+ }
2507
+ });
2508
+ $.CONSUME(T.RParen);
2509
+ if (!$.RECORDING_PHASE) {
2510
+ node = new Call({
2511
+ name: funcName,
2512
+ args: args.length > 0 ? new List(args) : undefined
2513
+ }, undefined, $.getLocationFromNodes([funcStart]), this.context);
2514
+ }
2515
+ }
2516
+ },
2517
+ {
2518
+ ALT: () => {
2519
+ node = $.SUBRULE2($.containerInParens, { ARGS: [ctx] });
2520
+ }
2521
+ }
2522
+ ]);
2523
+ if (!$.RECORDING_PHASE && node) {
2524
+ return [
2525
+ $.wrap(new Keyword(token.image, undefined, $.getLocationInfo(token), this.context), 'both'),
2526
+ node
2527
+ ];
2528
+ }
2529
+ };
2530
+ }
2531
+ /**
2532
+ * Container or: similar to mediaOr but can handle `or not` and function calls
2533
+ */
2534
+ export function containerOr(T) {
2535
+ const $ = this;
2536
+ return (ctx = {}) => {
2537
+ let token = $.CONSUME(T.Or);
2538
+ // Handle `or not` or `or` followed by containerInParens or function call
2539
+ let node;
2540
+ $.OR3([
2541
+ {
2542
+ GATE: () => $.LA(1).tokenType === T.Not,
2543
+ ALT: () => {
2544
+ const notToken = $.CONSUME(T.Not);
2545
+ node = $.SUBRULE($.containerInParens, { ARGS: [ctx] });
2546
+ if (!$.RECORDING_PHASE) {
2547
+ const notNode = $.wrap(new Keyword(notToken.image, undefined, $.getLocationInfo(notToken), this.context), 'both');
2548
+ node = new QueryCondition([notNode, node], undefined, $.getLocationFromNodes([notNode, node]), this.context);
2549
+ }
2550
+ }
2551
+ },
2552
+ {
2553
+ GATE: () => tokenMatcher($.LA(1), T.FunctionStart),
2554
+ ALT: () => {
2555
+ // Parse function call (reuse containerQuery logic)
2556
+ const funcStart = $.CONSUME(T.FunctionStart);
2557
+ const funcName = funcStart.image.slice(0, -1);
2558
+ let args = !$.RECORDING_PHASE ? [] : undefined;
2559
+ $.AT_LEAST_ONE_SEP({
2560
+ SEP: T.Comma,
2561
+ DEF: () => {
2562
+ $.OR2([
2563
+ {
2564
+ GATE: () => {
2565
+ const next = $.LA(1);
2566
+ return next.tokenType === T.LParen || next.tokenType === T.Not;
2567
+ },
2568
+ ALT: () => {
2569
+ const arg = $.SUBRULE2($.containerCondition, { ARGS: [ctx] });
2570
+ if (!$.RECORDING_PHASE) {
2571
+ args.push($.wrap(arg));
2572
+ }
2573
+ }
2574
+ },
2575
+ {
2576
+ GATE: () => {
2577
+ const next = $.LA(1);
2578
+ const after = $.LA(2);
2579
+ const isIdent = next.tokenType === T.Ident || next.tokenType === T.PlainIdent || next.tokenType === T.CustomProperty;
2580
+ return isIdent && after && tokenMatcher(after, T.Assign);
2581
+ },
2582
+ ALT: () => {
2583
+ const arg = $.SUBRULE($.declaration, { ARGS: [ctx] });
2584
+ if (!$.RECORDING_PHASE) {
2585
+ args.push($.wrap(arg));
2586
+ }
2587
+ }
2588
+ },
2589
+ {
2590
+ GATE: () => {
2591
+ const next = $.LA(1);
2592
+ const after = $.LA(2);
2593
+ const isIdent = next.tokenType === T.Ident || next.tokenType === T.PlainIdent || next.tokenType === T.CustomProperty;
2594
+ return isIdent && (!after || !tokenMatcher(after, T.Assign));
2595
+ },
2596
+ ALT: () => {
2597
+ let nameToken;
2598
+ $.OR9([
2599
+ { ALT: () => nameToken = $.CONSUME(T.Ident) },
2600
+ { ALT: () => nameToken = $.CONSUME(T.PlainIdent) },
2601
+ { ALT: () => nameToken = $.CONSUME(T.CustomProperty) }
2602
+ ]);
2603
+ if (!$.RECORDING_PHASE && nameToken) {
2604
+ const nameNode = $.wrap(new Any(nameToken.image, { role: 'name' }, $.getLocationInfo(nameToken), this.context), true);
2605
+ args.push(nameNode);
2606
+ }
2607
+ }
2608
+ }
2609
+ ]);
2610
+ }
2611
+ });
2612
+ $.CONSUME(T.RParen);
2613
+ if (!$.RECORDING_PHASE) {
2614
+ node = new Call({
2615
+ name: funcName,
2616
+ args: args.length > 0 ? new List(args) : undefined
2617
+ }, undefined, $.getLocationFromNodes([funcStart]), this.context);
2618
+ }
2619
+ }
2620
+ },
2621
+ {
2622
+ ALT: () => {
2623
+ node = $.SUBRULE2($.containerInParens, { ARGS: [ctx] });
2624
+ }
2625
+ }
2626
+ ]);
2627
+ if (!$.RECORDING_PHASE && node) {
2628
+ return [
2629
+ $.wrap(new Keyword(token.image, undefined, $.getLocationInfo(token), this.context), 'both'),
2630
+ node
2631
+ ];
2632
+ }
2633
+ };
2634
+ }
2635
+ /**
2636
+ * Container in parens: similar to media in parens
2637
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@container#container-query
2638
+ */
2639
+ export function containerInParens(T, alt) {
2640
+ const $ = this;
2641
+ // Reuse media in parens logic since container queries use the same syntax
2642
+ return (ctx = {}) => {
2643
+ return $.SUBRULE($.mediaInParens, { ARGS: [ctx] });
2644
+ };
2645
+ }
2646
+ /**
2647
+ * Container feature: similar to media feature
2648
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@container#container-query
2649
+ */
2650
+ export function containerFeature(T, alt) {
2651
+ const $ = this;
2652
+ // Reuse media feature logic since container queries use the same syntax
2653
+ return (ctx = {}) => {
2654
+ return $.SUBRULE($.mediaFeature, { ARGS: [ctx] });
2655
+ };
2656
+ }
2657
+ // scopeAtRule: @scope <prelude>? { main }
2658
+ export function scopeAtRule(T, preludeRule) {
2659
+ const $ = this;
2660
+ return (ctx = {}) => {
2661
+ $.startRule();
2662
+ const name = $.CONSUME(T.AtScope);
2663
+ let prelude;
2664
+ if (preludeRule) {
2665
+ const resolvedPreludeRule = resolvePreludeRule($, preludeRule);
2666
+ if (typeof resolvedPreludeRule === 'function') {
2667
+ prelude = $.SUBRULE(resolvedPreludeRule, { ARGS: [ctx] });
2668
+ }
2669
+ }
2670
+ else {
2671
+ const preludeNodes = [];
2672
+ $.MANY(() => preludeNodes.push($.wrap($.SUBRULE($.anyOuterValue, { ARGS: [ctx] }))));
2673
+ if (!$.RECORDING_PHASE) {
2674
+ prelude = preludeNodes.length
2675
+ ? $.wrap(new Sequence(preludeNodes, undefined, $.getLocationFromNodes(preludeNodes), this.context), 'both')
2676
+ : undefined;
2677
+ }
2678
+ }
2679
+ $.CONSUME(T.LCurly);
2680
+ const rules = $.SUBRULE($.atRuleBody, { ARGS: [ctx] });
2681
+ $.CONSUME(T.RCurly);
2682
+ if (!$.RECORDING_PHASE) {
2683
+ return new AtRule({
2684
+ name: $.wrap(new Any(name.image, { role: 'atkeyword' }, $.getLocationInfo(name), this.context), true),
2685
+ prelude,
2686
+ rules
2687
+ }, { nestable: true }, $.endRule(), this.context);
2688
+ }
2689
+ };
2690
+ }
2691
+ // documentAtRule (non-standard): @document <prelude>? { main }
2692
+ export function documentAtRule(T) {
2693
+ const $ = this;
2694
+ return (ctx = {}) => {
2695
+ $.startRule();
2696
+ const name = $.CONSUME(T.AtDocument);
2697
+ const preludeNodes = [];
2698
+ $.MANY(() => preludeNodes.push($.wrap($.SUBRULE($.anyOuterValue, { ARGS: [ctx] }))));
2699
+ $.CONSUME(T.LCurly);
2700
+ const rules = $.SUBRULE($.atRuleBody, { ARGS: [ctx] });
2701
+ $.CONSUME(T.RCurly);
2702
+ if (!$.RECORDING_PHASE) {
2703
+ return new AtRule({
2704
+ name: $.wrap(new Any(name.image, { role: 'atkeyword' }, $.getLocationInfo(name), this.context), true),
2705
+ prelude: preludeNodes.length ? $.wrap(new Sequence(preludeNodes, undefined, $.getLocationFromNodes(preludeNodes), this.context), 'both') : undefined,
2706
+ rules
2707
+ }, undefined, $.endRule(), this.context);
2708
+ }
2709
+ };
2710
+ }
2711
+ /**
2712
+ * `@layer` at rule
2713
+ *
2714
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@layer
2715
+ *
2716
+ * `@layer` =
2717
+ * `@layer` <layer-name>? { <rule-list> } |
2718
+ * `@layer` <layer-name># ;
2719
+ *
2720
+ * `<layer-name>` =
2721
+ * <ident> [ '.' <ident> ]*
2722
+ */
2723
+ export function layerAtRule(T) {
2724
+ const $ = this;
2725
+ return (ctx = {}) => {
2726
+ const RECORDING_PHASE = $.RECORDING_PHASE;
2727
+ $.startRule();
2728
+ const atTok = $.CONSUME(T.AtLayer);
2729
+ // Optional single layer-name before a block, or first of a comma list in statement form
2730
+ const preludeNodes = RECORDING_PHASE ? [] : [];
2731
+ return $.OR([
2732
+ {
2733
+ ALT: () => {
2734
+ $.OPTION(() => {
2735
+ const nameNode = $.SUBRULE($.layerName, { ARGS: [ctx] });
2736
+ if (!RECORDING_PHASE) {
2737
+ preludeNodes.push($.wrap(nameNode));
2738
+ }
2739
+ });
2740
+ $.CONSUME(T.LCurly);
2741
+ const rules = $.SUBRULE($.atRuleBody, { ARGS: [ctx] });
2742
+ $.CONSUME(T.RCurly);
2743
+ if (!RECORDING_PHASE) {
2744
+ return new AtRule({
2745
+ name: $.wrap(new Any(atTok.image, { role: 'atkeyword' }, $.getLocationInfo(atTok), this.context), true),
2746
+ prelude: preludeNodes.length ? $.wrap(new Sequence(preludeNodes, undefined, $.getLocationFromNodes(preludeNodes), this.context), 'both') : undefined,
2747
+ rules
2748
+ }, { nestable: true }, $.endRule(), this.context);
2749
+ }
2750
+ }
2751
+ },
2752
+ {
2753
+ ALT: () => {
2754
+ $.MANY_SEP({
2755
+ SEP: T.Comma,
2756
+ DEF: () => {
2757
+ let nameNode = $.SUBRULE2($.layerName, { ARGS: [ctx] });
2758
+ if (!RECORDING_PHASE) {
2759
+ preludeNodes.push($.wrap(nameNode));
2760
+ }
2761
+ }
2762
+ });
2763
+ $.CONSUME(T.Semi);
2764
+ if (!RECORDING_PHASE) {
2765
+ return new AtRule({
2766
+ name: $.wrap(new Any(atTok.image, { role: 'atkeyword' }, $.getLocationInfo(atTok), this.context), true),
2767
+ prelude: preludeNodes.length ? $.wrap(new List(preludeNodes, undefined, $.getLocationFromNodes(preludeNodes), this.context), 'both') : undefined
2768
+ }, undefined, $.endRule(), this.context);
2769
+ }
2770
+ }
2771
+ }
2772
+ ]);
2773
+ };
2774
+ }
2775
+ /**
2776
+ * <layer-name> = <ident> ('.' <ident>)*
2777
+ */
2778
+ export function layerName(T) {
2779
+ const $ = this;
2780
+ return (ctx = {}) => {
2781
+ const RECORDING_PHASE = $.RECORDING_PHASE;
2782
+ $.startRule();
2783
+ const nodes = RECORDING_PHASE ? [] : [];
2784
+ const first = $.CONSUME(T.Ident);
2785
+ if (!RECORDING_PHASE) {
2786
+ nodes.push($.wrap($.processValueToken(first)));
2787
+ }
2788
+ $.MANY({
2789
+ GATE: $.noSep,
2790
+ DEF: () => {
2791
+ const seg = $.CONSUME(T.DotName);
2792
+ if (!RECORDING_PHASE) {
2793
+ nodes.push($.wrap($.processValueToken(seg)));
2794
+ }
2795
+ }
2796
+ });
2797
+ if (!RECORDING_PHASE) {
2798
+ const loc = $.endRule();
2799
+ return new Sequence(nodes, undefined, loc, this.context);
2800
+ }
2801
+ };
2802
+ }
2803
+ /**
2804
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@supports
2805
+ */
2806
+ // supportsAtRule
2807
+ // : SUPPORTS_RULE WS* supportsCondition WS* LCURLY main RCURLY
2808
+ // ;
2809
+ export function supportsAtRule(T, preludeRule) {
2810
+ const $ = this;
2811
+ return (ctx = {}) => {
2812
+ $.startRule();
2813
+ let name = $.CONSUME(T.AtSupports);
2814
+ const resolvedPreludeRule = resolvePreludeRule($, preludeRule);
2815
+ const prelude = typeof resolvedPreludeRule === 'function'
2816
+ ? $.SUBRULE(resolvedPreludeRule, { ARGS: [ctx] })
2817
+ : $.SUBRULE($.supportsCondition, { ARGS: [ctx] });
2818
+ $.CONSUME(T.LCurly);
2819
+ let rules = $.SUBRULE($.atRuleBody, { ARGS: [ctx] });
2820
+ $.CONSUME(T.RCurly);
2821
+ if (!$.RECORDING_PHASE) {
2822
+ let location = $.endRule();
2823
+ return new AtRule({
2824
+ name: $.wrap(new Any(name.image, { role: 'atkeyword' }, $.getLocationInfo(name), this.context), true),
2825
+ prelude: $.wrap(prelude, 'both'),
2826
+ rules
2827
+ }, { nestable: true }, location, this.context);
2828
+ }
2829
+ };
2830
+ }
2831
+ /** spec-compliant but simplified */
2832
+ // supportsCondition
2833
+ // : NOT supportsInParens
2834
+ // | supportsInParens (WS* AND supportsInParens)*
2835
+ // | supportsInParens (WS* OR supportsInParens)*
2836
+ // ;
2837
+ export function supportsCondition(T) {
2838
+ const $ = this;
2839
+ let conditionAlt = (ctx = {}) => [
2840
+ {
2841
+ GATE: () => $.LA(1).tokenType === T.Not,
2842
+ ALT: () => {
2843
+ $.startRule();
2844
+ let keyword = $.CONSUME(T.Not);
2845
+ let value = $.SUBRULE($.supportsInParens, { ARGS: [ctx] });
2846
+ if (!$.RECORDING_PHASE) {
2847
+ let location = $.endRule();
2848
+ return new QueryCondition([
2849
+ $.wrap(new Keyword(keyword.image, undefined, $.getLocationInfo(keyword), this.context)),
2850
+ value
2851
+ ], undefined, location, this.context);
2852
+ }
2853
+ }
2854
+ },
2855
+ {
2856
+ GATE: () => $.LA(1).tokenType !== T.Not,
2857
+ ALT: () => {
2858
+ let start = $.startRule();
2859
+ let RECORDING_PHASE = $.RECORDING_PHASE;
2860
+ let [startOffset, startLine, startColumn] = start ?? [];
2861
+ let left = $.SUBRULE2($.supportsInParens, { ARGS: [ctx] });
2862
+ /**
2863
+ * Can be followed by many ands or many ors
2864
+ */
2865
+ $.OR2([
2866
+ {
2867
+ ALT: () => {
2868
+ $.AT_LEAST_ONE(() => {
2869
+ let keyword = $.CONSUME(T.And);
2870
+ let right = $.SUBRULE3($.supportsInParens, { ARGS: [ctx] });
2871
+ if (!RECORDING_PHASE) {
2872
+ let [, , , endOffset, endLine, endColumn] = right.location;
2873
+ left = new QueryCondition([
2874
+ left,
2875
+ $.wrap(new Keyword(keyword.image, undefined, $.getLocationInfo(keyword), this.context)),
2876
+ right
2877
+ ], undefined, [startOffset, startLine, startColumn, endOffset, endLine, endColumn], this.context);
2878
+ }
2879
+ });
2880
+ }
2881
+ },
2882
+ {
2883
+ ALT: () => {
2884
+ $.AT_LEAST_ONE2(() => {
2885
+ let keyword = $.CONSUME(T.Or);
2886
+ let right = $.SUBRULE5($.supportsInParens, { ARGS: [ctx] });
2887
+ if (!RECORDING_PHASE) {
2888
+ let [, , , endOffset, endLine, endColumn] = right.location;
2889
+ left = new QueryCondition([
2890
+ left,
2891
+ $.wrap(new Keyword(keyword.image, undefined, $.getLocationInfo(keyword), this.context)),
2892
+ right
2893
+ ], undefined, [startOffset, startLine, startColumn, endOffset, endLine, endColumn], this.context);
2894
+ }
2895
+ });
2896
+ }
2897
+ },
2898
+ {
2899
+ ALT: EMPTY_ALT()
2900
+ }
2901
+ ]);
2902
+ if (!RECORDING_PHASE) {
2903
+ $.endRule();
2904
+ }
2905
+ return left;
2906
+ }
2907
+ }
2908
+ ];
2909
+ return (ctx = {}) => $.OR(conditionAlt(ctx));
2910
+ }
2911
+ // supportsInParens
2912
+ // : '(' WS* supportsCondition WS* ')'
2913
+ // | '(' WS* declaration WS* ')'
2914
+ // | generalEnclosed
2915
+ // ;
2916
+ export function supportsInParens(T) {
2917
+ const $ = this;
2918
+ let conditionAlt = (ctx = {}) => [
2919
+ {
2920
+ ALT: () => {
2921
+ $.startRule();
2922
+ /** Function-like call */
2923
+ let name = $.CONSUME(T.Ident);
2924
+ let args;
2925
+ $.OR2([
2926
+ {
2927
+ GATE: $.noSep,
2928
+ ALT: () => {
2929
+ $.CONSUME(T.LParen);
2930
+ args = $.SUBRULE($.valueList, { ARGS: [ctx] });
2931
+ $.CONSUME(T.RParen);
2932
+ }
2933
+ }
2934
+ ]);
2935
+ if (!$.RECORDING_PHASE) {
2936
+ let location = $.endRule();
2937
+ return new Call({
2938
+ name: name.image,
2939
+ args
2940
+ }, undefined, location, this.context);
2941
+ }
2942
+ }
2943
+ },
2944
+ {
2945
+ ALT: () => {
2946
+ $.startRule();
2947
+ let values = [];
2948
+ $.CONSUME2(T.LParen);
2949
+ /**
2950
+ * Intentionally omits "generalEnclosed" from spec.
2951
+ * See the note on media queries.
2952
+ */
2953
+ let value = $.OR3([
2954
+ { ALT: () => $.SUBRULE($.supportsCondition, { ARGS: [ctx] }) },
2955
+ { ALT: () => $.SUBRULE($.declaration, { ARGS: [ctx] }) }
2956
+ ]);
2957
+ $.CONSUME2(T.RParen);
2958
+ if (!$.RECORDING_PHASE) {
2959
+ let location = $.endRule();
2960
+ if (!(value instanceof Node)) {
2961
+ value = new Sequence(values, undefined, $.getLocationFromNodes(values), this.context);
2962
+ }
2963
+ return $.wrap(new Paren($.wrap(value, 'both'), undefined, location, this.context));
2964
+ }
2965
+ }
2966
+ }
2967
+ ];
2968
+ return (ctx = {}) => $.OR(conditionAlt(ctx));
2969
+ }
2970
+ /** Used within anyOuterValue */
2971
+ export function functionCallLike(T) {
2972
+ const $ = this;
2973
+ return (ctx = {}) => {
2974
+ let RECORDING_PHASE = $.RECORDING_PHASE;
2975
+ $.startRule();
2976
+ const name = $.CONSUME(T.FunctionStart);
2977
+ let args = !RECORDING_PHASE ? [] : undefined;
2978
+ let seq;
2979
+ $.MANY({
2980
+ GATE: () => {
2981
+ let tt = $.LA(1).tokenType;
2982
+ return tt !== T.RParen && tt !== T.UrlEnd;
2983
+ },
2984
+ DEF: () => {
2985
+ const node = $.SUBRULE($.anyOuterValue, { ARGS: [ctx] });
2986
+ if (!RECORDING_PHASE) {
2987
+ args.push($.wrap(node));
2988
+ }
2989
+ }
2990
+ });
2991
+ if (!RECORDING_PHASE) {
2992
+ let location = args.length ? $.getLocationFromNodes(args) : undefined;
2993
+ if (args.length) {
2994
+ seq = new Sequence(args, undefined, location, this.context);
2995
+ }
2996
+ }
2997
+ $.OR([
2998
+ { ALT: () => $.CONSUME(T.RParen) },
2999
+ { ALT: () => $.CONSUME(T.UrlEnd) }
3000
+ ]);
3001
+ if (!RECORDING_PHASE) {
3002
+ const location = $.endRule();
3003
+ return $.wrap(new Call({ name: name.image.slice(0, -1), args: new List(seq ? [seq] : []) }, undefined, location, this.context));
3004
+ }
3005
+ };
3006
+ }
3007
+ export function functionCall(T, alt) {
3008
+ const $ = this;
3009
+ const modernColorFunctions = new Set(['rgb', 'rgba', 'hsl', 'hsla']);
3010
+ const isModernColorCall = (name, args) => {
3011
+ if (!modernColorFunctions.has(name.toLowerCase())) {
3012
+ return false;
3013
+ }
3014
+ if (!args || args.value.length !== 1) {
3015
+ return false;
3016
+ }
3017
+ const firstArg = args.value[0];
3018
+ return Boolean(firstArg instanceof Sequence && firstArg.value.length >= 2);
3019
+ };
3020
+ alt ??= (ctx = {}) => [
3021
+ {
3022
+ GATE: () => tokenMatcher($.LA(1), T.FunctionStart) && $.LA(1).image.slice(0, -1).toLowerCase() === 'if',
3023
+ ALT: () => $.SUBRULE($.ifFunction, { ARGS: [ctx] })
3024
+ },
3025
+ {
3026
+ // Disambiguate known functions by their dedicated tokens
3027
+ GATE: () => {
3028
+ let tokenType = $.LA(1).tokenType;
3029
+ return tokenType === T.UrlStart
3030
+ || tokenType === T.Var
3031
+ || tokenType === T.Calc;
3032
+ },
3033
+ ALT: () => $.SUBRULE($.knownFunctions, { ARGS: [ctx] })
3034
+ },
3035
+ {
3036
+ GATE: () => {
3037
+ let tokenType = $.LA(1).tokenType;
3038
+ return tokenType !== T.UrlStart
3039
+ && tokenType !== T.Var
3040
+ && tokenType !== T.Calc;
3041
+ },
3042
+ ALT: () => {
3043
+ $.startRule();
3044
+ let name = $.CONSUME(T.FunctionStart);
3045
+ let args;
3046
+ $.OPTION(() => args = $.SUBRULE($.functionCallArgs, { ARGS: [ctx] }));
3047
+ $.CONSUME(T.RParen);
3048
+ if (!$.RECORDING_PHASE) {
3049
+ let location = $.endRule();
3050
+ const functionName = name.image.slice(0, -1);
3051
+ const modernSyntax = isModernColorCall(functionName, args);
3052
+ return new Call({
3053
+ name: functionName,
3054
+ args
3055
+ }, modernSyntax ? { modernSyntax: true } : undefined, location, this.context);
3056
+ }
3057
+ }
3058
+ }
3059
+ ];
3060
+ return (ctx = {}) => $.OR(alt(ctx));
3061
+ }
3062
+ /**
3063
+ * Originally, function arguments always had commas,
3064
+ * but it looks like that might be expanded in the
3065
+ * future in CSS to allow for semi-colon separators.
3066
+ * with the same rationale of why this was introduced
3067
+ * by Less (that values can already have commas).
3068
+ *
3069
+ * @see https://drafts.csswg.org/css-values-4/#interpolate
3070
+ *
3071
+ * @todo - if a function is introduced where semi-colons
3072
+ * are separators AND only 1 argument is required, then
3073
+ * that will have to be specially handled.
3074
+ */
3075
+ export function functionCallArgs(T) {
3076
+ const $ = this;
3077
+ return (ctx = {}) => {
3078
+ let RECORDING_PHASE = $.RECORDING_PHASE;
3079
+ $.startRule();
3080
+ let node = $.SUBRULE($.valueSequence, { ARGS: [ctx] });
3081
+ let commaNodes;
3082
+ let semiNodes;
3083
+ if (!RECORDING_PHASE) {
3084
+ commaNodes = [$.wrap(node, true)];
3085
+ semiNodes = [];
3086
+ }
3087
+ let isSemiList = false;
3088
+ $.MANY(() => {
3089
+ $.OR([
3090
+ {
3091
+ GATE: () => !isSemiList,
3092
+ ALT: () => {
3093
+ $.CONSUME(T.Comma);
3094
+ node = $.SUBRULE2($.valueSequence, { ARGS: [ctx] });
3095
+ if (!RECORDING_PHASE) {
3096
+ commaNodes.push($.wrap(node, true));
3097
+ }
3098
+ }
3099
+ },
3100
+ {
3101
+ ALT: () => {
3102
+ isSemiList = true;
3103
+ $.CONSUME(T.Semi);
3104
+ if (!RECORDING_PHASE) {
3105
+ /** Aggregate the previous set of comma-nodes */
3106
+ if (commaNodes.length > 1) {
3107
+ let commaList = new List(commaNodes, undefined, $.getLocationFromNodes(commaNodes), this.context);
3108
+ semiNodes.push(commaList);
3109
+ }
3110
+ else {
3111
+ semiNodes.push(commaNodes[0]);
3112
+ }
3113
+ }
3114
+ node = $.SUBRULE3($.valueList, { ARGS: [ctx] });
3115
+ if (!RECORDING_PHASE) {
3116
+ semiNodes.push($.wrap(node, true));
3117
+ }
3118
+ }
3119
+ }
3120
+ ]);
3121
+ });
3122
+ if (!RECORDING_PHASE) {
3123
+ $.endRule();
3124
+ const nodes = isSemiList ? semiNodes : commaNodes;
3125
+ return new List(nodes, isSemiList ? { sep: ';' } : undefined);
3126
+ }
3127
+ };
3128
+ }
3129
+ // https://www.w3.org/TR/css-cascade-4/#at-import
3130
+ // importAtRule
3131
+ // : IMPORT_RULE WS* (URL_FUNCTION | STRING) (WS* SUPPORTS_FUNCTION WS* (supportsCondition | declaration))? (WS* mediaQuery)? SEMI
3132
+ // ;
3133
+ export function importAtRule(T) {
3134
+ const $ = this;
3135
+ return (ctx = {}) => {
3136
+ let RECORDING_PHASE = $.RECORDING_PHASE;
3137
+ $.startRule();
3138
+ let name = $.CONSUME(T.AtImport);
3139
+ let preludeNodes;
3140
+ if (!RECORDING_PHASE) {
3141
+ preludeNodes = [];
3142
+ }
3143
+ let node = $.SUBRULE($.importPrelude, { ARGS: [ctx] });
3144
+ if (!RECORDING_PHASE) {
3145
+ preludeNodes.push($.wrap(node));
3146
+ }
3147
+ let extraNodes;
3148
+ $.OPTION(() => {
3149
+ extraNodes = $.SUBRULE($.importPostlude, { ARGS: [ctx] });
3150
+ });
3151
+ if (!RECORDING_PHASE && extraNodes && extraNodes.length) {
3152
+ for (const n of extraNodes) {
3153
+ preludeNodes.push(n);
3154
+ }
3155
+ }
3156
+ $.CONSUME(T.Semi);
3157
+ if (!RECORDING_PHASE) {
3158
+ let location = $.endRule();
3159
+ return new AtRule({
3160
+ name: $.wrap(new Any(name.image, { role: 'atkeyword' }, $.getLocationInfo(name), this.context), true),
3161
+ prelude: new Sequence(preludeNodes, undefined, $.getLocationFromNodes(preludeNodes), this.context)
3162
+ }, undefined, location, this.context);
3163
+ }
3164
+ };
3165
+ }
3166
+ /** import prelude: url(...) or "string" */
3167
+ export function importPrelude(T) {
3168
+ const $ = this;
3169
+ return (ctx = {}) => {
3170
+ return $.OR([
3171
+ { ALT: () => $.SUBRULE($.urlFunction, { ARGS: [ctx] }) },
3172
+ { ALT: () => $.SUBRULE($.string, { ARGS: [ctx] }) }
3173
+ ]);
3174
+ };
3175
+ }
3176
+ /** import postlude: optional layer(), supports(), media. Returns Node[] */
3177
+ export function importPostlude(T) {
3178
+ const $ = this;
3179
+ return (ctx = {}) => {
3180
+ let RECORDING_PHASE = $.RECORDING_PHASE;
3181
+ let nodes;
3182
+ if (!RECORDING_PHASE) {
3183
+ nodes = [];
3184
+ }
3185
+ /** layer(responsive) */
3186
+ $.OPTION(() => {
3187
+ let start = $.CONSUME(T.Layer);
3188
+ let value = $.SUBRULE($.layerName);
3189
+ let end = $.CONSUME(T.RParen);
3190
+ if (!RECORDING_PHASE) {
3191
+ let { startOffset, startLine, startColumn } = start;
3192
+ let { endOffset, endLine, endColumn } = end;
3193
+ let location = [startOffset, startLine, startColumn, endOffset, endLine, endColumn];
3194
+ nodes.push($.wrap(new Call({
3195
+ name: 'layer',
3196
+ args: new List([value])
3197
+ }, undefined, location, this.context)));
3198
+ }
3199
+ });
3200
+ /** supports(display: grid) */
3201
+ $.OPTION2(() => {
3202
+ let start = $.CONSUME(T.Supports);
3203
+ let value = $.OR4([
3204
+ { ALT: () => $.SUBRULE($.supportsCondition, { ARGS: [ctx] }) },
3205
+ { ALT: () => $.SUBRULE($.declaration, { ARGS: [ctx] }) }
3206
+ ]);
3207
+ let end = $.CONSUME2(T.RParen);
3208
+ if (!RECORDING_PHASE) {
3209
+ let { startOffset, startLine, startColumn } = start;
3210
+ let { endOffset, endLine, endColumn } = end;
3211
+ let location = [startOffset, startLine, startColumn, endOffset, endLine, endColumn];
3212
+ nodes.push($.wrap(new Call({
3213
+ name: 'supports',
3214
+ args: new List([$.wrap(value, 'both')])
3215
+ }, undefined, location, this.context)));
3216
+ }
3217
+ });
3218
+ /** media query list */
3219
+ $.OPTION3(() => {
3220
+ let mediaNode = $.SUBRULE($.mediaQueryList, { ARGS: [ctx] });
3221
+ if (!RECORDING_PHASE) {
3222
+ nodes.push(mediaNode);
3223
+ }
3224
+ });
3225
+ return nodes;
3226
+ };
3227
+ }
3228
+ /**
3229
+ * @todo - add more structure for known nested at-rules.
3230
+ */
3231
+ export function nestedAtRule(T) {
3232
+ const $ = this;
3233
+ return (ctx = {}) => {
3234
+ let RECORDING_PHASE = $.RECORDING_PHASE;
3235
+ $.startRule();
3236
+ let name = $.CONSUME(T.AtNested);
3237
+ let preludeNodes;
3238
+ let rules;
3239
+ if (!RECORDING_PHASE) {
3240
+ preludeNodes = [];
3241
+ }
3242
+ $.MANY(() => {
3243
+ let value = $.SUBRULE($.anyOuterValue, { ARGS: [ctx] });
3244
+ if (!RECORDING_PHASE) {
3245
+ preludeNodes.push($.wrap(value));
3246
+ }
3247
+ });
3248
+ $.CONSUME(T.LCurly);
3249
+ // All known nested at-rules use declaration lists in their blocks
3250
+ rules = $.SUBRULE($.declarationList, { ARGS: [ctx] });
3251
+ $.CONSUME(T.RCurly);
3252
+ if (!$.RECORDING_PHASE) {
3253
+ return new AtRule({
3254
+ name: $.wrap(new Any(name.image, { role: 'atkeyword' }, $.getLocationInfo(name), this.context), true),
3255
+ prelude: preludeNodes.length ? $.wrap(new Sequence(preludeNodes, undefined, $.getLocationFromNodes(preludeNodes), this.context), 'both') : undefined,
3256
+ rules
3257
+ }, undefined, $.endRule(), this.context);
3258
+ }
3259
+ };
3260
+ }
3261
+ export function nonNestedAtRule(T) {
3262
+ const $ = this;
3263
+ return (ctx = {}) => {
3264
+ $.startRule();
3265
+ let preludeNodes = [];
3266
+ let name = $.CONSUME(T.AtNonNested);
3267
+ $.MANY(() => preludeNodes.push($.wrap($.SUBRULE($.anyOuterValue, { ARGS: [ctx] }))));
3268
+ $.CONSUME(T.Semi);
3269
+ if (!$.RECORDING_PHASE) {
3270
+ return new AtRule({
3271
+ name: $.wrap(new Any(name.image, { role: 'atkeyword' }, $.getLocationInfo(name), this.context), true),
3272
+ prelude: $.wrap(new Sequence(preludeNodes, undefined, $.getLocationFromNodes(preludeNodes), this.context))
3273
+ }, undefined, $.endRule(), this.context);
3274
+ }
3275
+ };
3276
+ }
3277
+ // unknownAtRule
3278
+ // : AT_RULE anyOuterValue* (SEMI | LCURLY anyInnerValue* RCURLY)
3279
+ // ;
3280
+ export function unknownAtRule(T) {
3281
+ const $ = this;
3282
+ const { AtKeyword, Semi, LCurly, RCurly, DotName, HashName, Ampersand, LSquare, SelectorPseudoClass, NthPseudoClass, Star, ColorIdentStart, PlainIdent, CustomProperty, LegacyPropIdent, Colon } = T;
3283
+ return (ctx = {}) => {
3284
+ let RECORDING_PHASE = $.RECORDING_PHASE;
3285
+ $.startRule();
3286
+ let preludeNodes;
3287
+ let valueNodes;
3288
+ let declRules;
3289
+ let endToken;
3290
+ let innerBlockLocation;
3291
+ if (!RECORDING_PHASE) {
3292
+ preludeNodes = [];
3293
+ }
3294
+ let name = $.CONSUME(T.AtKeyword);
3295
+ $.MANY(() => {
3296
+ let val = $.SUBRULE($.anyOuterValue, { ARGS: [ctx] });
3297
+ if (!RECORDING_PHASE) {
3298
+ preludeNodes.push($.wrap(val, 'both'));
3299
+ }
3300
+ });
3301
+ $.OR([
3302
+ { ALT: () => $.CONSUME(Semi) },
3303
+ {
3304
+ ALT: () => {
3305
+ if (!RECORDING_PHASE) {
3306
+ valueNodes = [];
3307
+ }
3308
+ $.CONSUME(LCurly);
3309
+ $.startRule();
3310
+ // 1) Fast selector/nested-at-rule start gate
3311
+ let t1 = $.LA(1).tokenType;
3312
+ let t2 = $.LA(2).tokenType;
3313
+ let assumeDeclList = (t1 === DotName
3314
+ || t1 === HashName
3315
+ || t1 === Ampersand
3316
+ || t1 === LSquare
3317
+ || t1 === SelectorPseudoClass
3318
+ || t1 === NthPseudoClass
3319
+ || t1 === Star
3320
+ || t1 === ColorIdentStart
3321
+ || t1 === AtKeyword
3322
+ // Also treat IDENT followed by '{' as a rule start (e.g., @-moz-document url-prefix() { a { ... } })
3323
+ || ((t1 === PlainIdent
3324
+ || t1 === CustomProperty
3325
+ || t1 === LegacyPropIdent) && t2 === LCurly));
3326
+ if (!assumeDeclList) {
3327
+ assumeDeclList = (t1 === PlainIdent
3328
+ || t1 === CustomProperty
3329
+ || t1 === LegacyPropIdent) && t2 === Colon;
3330
+ }
3331
+ $.OR9([
3332
+ {
3333
+ GATE: () => assumeDeclList,
3334
+ ALT: () => {
3335
+ declRules = $.SUBRULE($.atRuleBody, { ARGS: [{ ...ctx, inner: true }] });
3336
+ }
3337
+ },
3338
+ {
3339
+ GATE: () => !assumeDeclList,
3340
+ ALT: () => {
3341
+ /** Fallback to raw capture */
3342
+ $.MANY9(() => {
3343
+ const value = $.SUBRULE($.anyInnerValue, { ARGS: [ctx] });
3344
+ if (!RECORDING_PHASE) {
3345
+ valueNodes.push($.wrap(value, 'both'));
3346
+ }
3347
+ });
3348
+ }
3349
+ }
3350
+ ]);
3351
+ endToken = $.CONSUME(RCurly);
3352
+ if (!RECORDING_PHASE) {
3353
+ innerBlockLocation = $.endRule();
3354
+ }
3355
+ }
3356
+ }
3357
+ ]);
3358
+ if (!RECORDING_PHASE) {
3359
+ // Build rules result: declaration list, or single-sequence fallback, or undefined
3360
+ let rules;
3361
+ if (declRules) {
3362
+ rules = declRules;
3363
+ }
3364
+ else {
3365
+ if (valueNodes?.length) {
3366
+ // Create a single Sequence from all inner nodes, so serialization treats it as one unit
3367
+ const seqLoc = $.getLocationFromNodes(valueNodes);
3368
+ const seq = new Sequence(valueNodes, undefined, seqLoc, this.context);
3369
+ // Use RawRules to avoid inserting newlines/indentation during serialization
3370
+ rules = new RawRules([seq], undefined, seqLoc, this.context);
3371
+ }
3372
+ }
3373
+ return new AtRule({
3374
+ name: $.wrap(new Any(name.image, { role: 'atkeyword' }, $.getLocationInfo(name), this.context), true),
3375
+ prelude: preludeNodes.length ? new Sequence(preludeNodes, undefined, $.getLocationFromNodes(preludeNodes), this.context) : undefined,
3376
+ rules
3377
+ }, undefined, $.endRule(), this.context);
3378
+ }
3379
+ };
3380
+ }
3381
+ /**
3382
+ @todo - add all tokens
3383
+ @see - https://stackoverflow.com/questions/55594491/antlr-4-parser-match-any-token
3384
+
3385
+ From - https://w3c.github.io/csswg-drafts/css-syntax-3/#typedef-any-value
3386
+ The <any-value> production is identical to <declaration-value>, but also allows
3387
+ top-level <semicolon-token> tokens and <delim-token> tokens with a value of "!".
3388
+ It represents the entirety of what valid CSS can be in any context.
3389
+
3390
+ Parts of the spec that allow any value should not display a warning or error
3391
+ for any unknown token.
3392
+ */
3393
+ // anyOuterValue
3394
+ // : value
3395
+ // | COMMA
3396
+ // | '(' anyInnerValue* ')'
3397
+ // | '[' anyInnerValue* ']'
3398
+ // ;
3399
+ export function anyOuterValue(T) {
3400
+ const $ = this;
3401
+ let valueAlt = (ctx = {}) => [
3402
+ { ALT: () => $.SUBRULE($.extraTokens, { ARGS: [ctx] }) },
3403
+ { ALT: () => $.SUBRULE($.string, { ARGS: [ctx] }) },
3404
+ {
3405
+ ALT: () => {
3406
+ let RECORDING_PHASE = $.RECORDING_PHASE;
3407
+ $.startRule();
3408
+ let nodes;
3409
+ if (!RECORDING_PHASE) {
3410
+ nodes = [];
3411
+ }
3412
+ $.CONSUME(T.LParen);
3413
+ $.MANY(() => {
3414
+ let val = $.SUBRULE($.anyInnerValue, { ARGS: [ctx] });
3415
+ if (!RECORDING_PHASE) {
3416
+ nodes.push($.wrap(val));
3417
+ }
3418
+ });
3419
+ $.CONSUME(T.RParen);
3420
+ if (!RECORDING_PHASE) {
3421
+ let location = $.endRule();
3422
+ return new Paren(nodes.length ? new Sequence(nodes, undefined, $.getLocationFromNodes(nodes), this.context) : undefined, undefined, location, this.context);
3423
+ }
3424
+ }
3425
+ },
3426
+ {
3427
+ ALT: () => {
3428
+ let RECORDING_PHASE = $.RECORDING_PHASE;
3429
+ $.startRule();
3430
+ let nodes;
3431
+ if (!RECORDING_PHASE) {
3432
+ nodes = [];
3433
+ }
3434
+ $.CONSUME(T.LSquare);
3435
+ $.MANY2(() => {
3436
+ let node = $.SUBRULE2($.anyInnerValue, { ARGS: [ctx] });
3437
+ if (!RECORDING_PHASE) {
3438
+ nodes.push($.wrap(node));
3439
+ }
3440
+ });
3441
+ $.CONSUME(T.RSquare);
3442
+ if (!RECORDING_PHASE) {
3443
+ let location = $.endRule();
3444
+ return new Paren($.wrap(new Sequence(nodes, undefined, $.getLocationFromNodes(nodes), this.context), true), undefined, location, this.context);
3445
+ }
3446
+ }
3447
+ }
3448
+ ];
3449
+ return (ctx = {}) => $.OR(valueAlt(ctx));
3450
+ }
3451
+ /**
3452
+ * Same as allowable outer values, but allows
3453
+ * semi-colons and curly blocks.
3454
+ */
3455
+ // anyInnerValue
3456
+ // : anyOuterValue
3457
+ // | '{' anyInnerValue* '}'
3458
+ // | ID
3459
+ // | SEMI
3460
+ // | pseudoSelector
3461
+ // ;
3462
+ export function anyInnerValue(T) {
3463
+ const $ = this;
3464
+ let valueAlt = (ctx = {}) => [
3465
+ { ALT: () => $.SUBRULE($.anyOuterValue, { ARGS: [ctx] }) },
3466
+ {
3467
+ ALT: () => {
3468
+ $.startRule();
3469
+ let RECORDING_PHASE = $.RECORDING_PHASE;
3470
+ let nodes;
3471
+ if (!RECORDING_PHASE) {
3472
+ nodes = [];
3473
+ }
3474
+ $.CONSUME(T.LCurly);
3475
+ $.MANY(() => {
3476
+ let node = $.SUBRULE2($.anyInnerValue, { ARGS: [ctx] });
3477
+ if (!RECORDING_PHASE) {
3478
+ nodes.push(node);
3479
+ }
3480
+ });
3481
+ $.CONSUME(T.RCurly);
3482
+ if (!RECORDING_PHASE) {
3483
+ let location = $.endRule();
3484
+ return new Block($.wrap(new Sequence(nodes, undefined, $.getLocationFromNodes(nodes), this.context), 'both'), { type: 'curly' }, location, this.context);
3485
+ }
3486
+ }
3487
+ },
3488
+ {
3489
+ ALT: () => {
3490
+ let semi = $.CONSUME(T.Semi);
3491
+ if (!$.RECORDING_PHASE) {
3492
+ return $.wrap(new Any(semi.image, { role: 'semi' }, $.getLocationInfo(semi), this.context));
3493
+ }
3494
+ }
3495
+ }
3496
+ ];
3497
+ return (ctx = {}) => $.OR(valueAlt(ctx));
3498
+ }
3499
+ //# sourceMappingURL=productions.js.map