@excom/quark-parser 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.rush/temp/chunked-rush-logs/quark-parser.apply-exports.chunks.jsonl +1 -0
- package/.rush/temp/chunked-rush-logs/quark-parser.build_package-metas.chunks.jsonl +1 -0
- package/.rush/temp/operation/apply-exports/all.log +1 -0
- package/.rush/temp/operation/apply-exports/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/apply-exports/state.json +3 -0
- package/.rush/temp/operation/build_package-metas/all.log +1 -0
- package/.rush/temp/operation/build_package-metas/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/build_package-metas/state.json +3 -0
- package/.rush/temp/shrinkwrap-deps.json +3 -0
- package/config/rig.json +5 -0
- package/index.ts +12 -0
- package/package.json +39 -0
- package/rush-logs/quark-parser.apply-exports.cache.log +1 -0
- package/rush-logs/quark-parser.apply-exports.log +1 -0
- package/rush-logs/quark-parser.build_package-metas.cache.log +1 -0
- package/rush-logs/quark-parser.build_package-metas.log +1 -0
- package/src/error.ts +24 -0
- package/src/parser.ts +1482 -0
- package/src/tables.ts +77 -0
- package/src/tokenizer.ts +443 -0
- package/src/types.ts +497 -0
- package/support/docs/README.md +443 -0
- package/support/package-meta.json +33 -0
- package/support/tests/grammar-docs.test.ts +109 -0
- package/support/tests/parser-at-rules.test.ts +430 -0
- package/support/tests/parser-declarations.test.ts +152 -0
- package/support/tests/parser-edge-cases.test.ts +296 -0
- package/support/tests/parser-expressions.test.ts +413 -0
- package/support/tests/parser-real-world.test.ts +429 -0
- package/support/tests/parser-selectors.test.ts +169 -0
- package/support/tests/tokenizer.test.ts +268 -0
- package/tsconfig.json +5 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token and AST node types for the Quark language.
|
|
3
|
+
*
|
|
4
|
+
* Quark is a derivative of CSS: its own at-rules plus the CSS constructs
|
|
5
|
+
* the engine runs, with two accessors CSS does not have:
|
|
6
|
+
* - dot accessor: `$obj.field`, `prop("provision").body`, `item.name`
|
|
7
|
+
* - bracket accessor: `$obj["field"]`, `$tags[$index]`
|
|
8
|
+
*
|
|
9
|
+
* This is a real AST: expressions are structured nodes, not token soup, and
|
|
10
|
+
* whitespace and punctuation are not represented.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Numeric offsets into the original source string. */
|
|
14
|
+
export interface Span {
|
|
15
|
+
start: number;
|
|
16
|
+
end: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/*
|
|
20
|
+
* ---------------------------------------------------------------------------
|
|
21
|
+
* Tokens
|
|
22
|
+
* ---------------------------------------------------------------------------
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
export type TokenType =
|
|
26
|
+
| "ident"
|
|
27
|
+
| "variable"
|
|
28
|
+
| "at"
|
|
29
|
+
| "string"
|
|
30
|
+
| "number"
|
|
31
|
+
| "hash"
|
|
32
|
+
| "punct"
|
|
33
|
+
| "url"
|
|
34
|
+
| "comment";
|
|
35
|
+
|
|
36
|
+
export interface Token extends Span {
|
|
37
|
+
type: TokenType;
|
|
38
|
+
/**
|
|
39
|
+
* ident name / variable name (no `$`) / at-keyword name (no `@`) / raw
|
|
40
|
+
* string contents (no quotes, escapes preserved) / number text (no unit) /
|
|
41
|
+
* hash text (no `#`) / punctuation characters / raw url contents / comment
|
|
42
|
+
* text (no delimiters).
|
|
43
|
+
*/
|
|
44
|
+
value: string;
|
|
45
|
+
/** Unit for number tokens (`px`, `%`, `em`, ...). */
|
|
46
|
+
unit?: string;
|
|
47
|
+
/** Quote character for string tokens. */
|
|
48
|
+
quote?: '"' | "'";
|
|
49
|
+
/** Whether whitespace or a comment directly precedes this token. */
|
|
50
|
+
ws: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface TokenizeResult {
|
|
54
|
+
tokens: Token[];
|
|
55
|
+
comments: Token[];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
* ---------------------------------------------------------------------------
|
|
60
|
+
* Statements
|
|
61
|
+
* ---------------------------------------------------------------------------
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
export interface BaseNode extends Span {
|
|
65
|
+
type: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type Statement = Rule | AtRule | Declaration | CommentNode;
|
|
69
|
+
|
|
70
|
+
export interface Stylesheet extends BaseNode {
|
|
71
|
+
type: "stylesheet";
|
|
72
|
+
body: Statement[];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface Block extends BaseNode {
|
|
76
|
+
type: "block";
|
|
77
|
+
body: Statement[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface CommentNode extends BaseNode {
|
|
81
|
+
type: "comment";
|
|
82
|
+
text: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface Rule extends BaseNode {
|
|
86
|
+
type: "rule";
|
|
87
|
+
selector: SelectorList;
|
|
88
|
+
block: Block;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface Declaration extends BaseNode {
|
|
92
|
+
type: "declaration";
|
|
93
|
+
property: Property | Variable;
|
|
94
|
+
value: Expression;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface Property extends BaseNode {
|
|
98
|
+
type: "property";
|
|
99
|
+
name: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/*
|
|
103
|
+
* ---------------------------------------------------------------------------
|
|
104
|
+
* Selectors
|
|
105
|
+
* ---------------------------------------------------------------------------
|
|
106
|
+
*/
|
|
107
|
+
|
|
108
|
+
export interface SelectorList extends BaseNode {
|
|
109
|
+
type: "selector_list";
|
|
110
|
+
selectors: Selector[];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface Selector extends BaseNode {
|
|
114
|
+
type: "selector";
|
|
115
|
+
parts: SelectorPart[];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type SelectorPart =
|
|
119
|
+
| TypeSelector
|
|
120
|
+
| ClassSelector
|
|
121
|
+
| IdSelector
|
|
122
|
+
| AttributeSelector
|
|
123
|
+
| PseudoClassSelector
|
|
124
|
+
| PseudoElementSelector
|
|
125
|
+
| ParentSelector
|
|
126
|
+
| Combinator;
|
|
127
|
+
|
|
128
|
+
export interface TypeSelector extends BaseNode {
|
|
129
|
+
type: "type_selector";
|
|
130
|
+
/** Tag name or `*`. */
|
|
131
|
+
name: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface ClassSelector extends BaseNode {
|
|
135
|
+
type: "class_selector";
|
|
136
|
+
name: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface IdSelector extends BaseNode {
|
|
140
|
+
type: "id_selector";
|
|
141
|
+
name: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface AttributeSelector extends BaseNode {
|
|
145
|
+
type: "attribute_selector";
|
|
146
|
+
name: string;
|
|
147
|
+
/** `=` `*=` `^=` `$=` `|=` `~=` or `null` for bare `[attr]`. */
|
|
148
|
+
operator: string | null;
|
|
149
|
+
value: Expression | null;
|
|
150
|
+
/** `i` or `s` case-sensitivity modifier. */
|
|
151
|
+
modifier: string | null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface PseudoClassSelector extends BaseNode {
|
|
155
|
+
type: "pseudo_class_selector";
|
|
156
|
+
name: string;
|
|
157
|
+
/**
|
|
158
|
+
* Selector list for selector-taking pseudos (`:not`, `:is`, `:where`,
|
|
159
|
+
* `:has`), raw source for the rest (`:nth-child(2n+1)`), `null` when the
|
|
160
|
+
* pseudo has no arguments.
|
|
161
|
+
*/
|
|
162
|
+
argument: SelectorList | RawArgument | null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface PseudoElementSelector extends BaseNode {
|
|
166
|
+
type: "pseudo_element_selector";
|
|
167
|
+
name: string;
|
|
168
|
+
argument: RawArgument | null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface RawArgument extends BaseNode {
|
|
172
|
+
type: "raw";
|
|
173
|
+
value: string;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export interface ParentSelector extends BaseNode {
|
|
177
|
+
type: "parent_selector";
|
|
178
|
+
/** Suffix for `&-modifier` style selectors. */
|
|
179
|
+
suffix: string | null;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export interface Combinator extends BaseNode {
|
|
183
|
+
type: "combinator";
|
|
184
|
+
value: " " | ">" | "+" | "~";
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/*
|
|
188
|
+
* ---------------------------------------------------------------------------
|
|
189
|
+
* Expressions
|
|
190
|
+
* ---------------------------------------------------------------------------
|
|
191
|
+
*/
|
|
192
|
+
|
|
193
|
+
export type Expression =
|
|
194
|
+
| StringLiteral
|
|
195
|
+
| NumberLiteral
|
|
196
|
+
| ColorLiteral
|
|
197
|
+
| BooleanLiteral
|
|
198
|
+
| NullLiteral
|
|
199
|
+
| Identifier
|
|
200
|
+
| Variable
|
|
201
|
+
| ParentReference
|
|
202
|
+
| Interpolation
|
|
203
|
+
| Url
|
|
204
|
+
| FunctionCall
|
|
205
|
+
| IfFunction
|
|
206
|
+
| Member
|
|
207
|
+
| IndexAccess
|
|
208
|
+
| Unary
|
|
209
|
+
| Binary
|
|
210
|
+
| ListLiteral
|
|
211
|
+
| MapLiteral;
|
|
212
|
+
|
|
213
|
+
export interface StringLiteral extends BaseNode {
|
|
214
|
+
type: "string";
|
|
215
|
+
quote: '"' | "'";
|
|
216
|
+
/** Literal text parts (escapes preserved) interleaved with interpolations. */
|
|
217
|
+
parts: Array<string | Interpolation>;
|
|
218
|
+
/** Full contents when the string has no interpolation, else `null`. */
|
|
219
|
+
value: string | null;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export interface NumberLiteral extends BaseNode {
|
|
223
|
+
type: "number";
|
|
224
|
+
value: number;
|
|
225
|
+
unit: string | null;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** Hex color, including the `#`. */
|
|
229
|
+
export interface ColorLiteral extends BaseNode {
|
|
230
|
+
type: "color";
|
|
231
|
+
value: string;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export interface BooleanLiteral extends BaseNode {
|
|
235
|
+
type: "boolean";
|
|
236
|
+
value: boolean;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export interface NullLiteral extends BaseNode {
|
|
240
|
+
type: "null";
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** Unquoted word: `none`, `solid`, `item`, `index`, ... */
|
|
244
|
+
export interface Identifier extends BaseNode {
|
|
245
|
+
type: "identifier";
|
|
246
|
+
name: string;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** `$name` (name stored without the `$`). */
|
|
250
|
+
export interface Variable extends BaseNode {
|
|
251
|
+
type: "variable";
|
|
252
|
+
name: string;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** `&` used inside an expression, e.g. `closest(&)`. */
|
|
256
|
+
export interface ParentReference extends BaseNode {
|
|
257
|
+
type: "parent_reference";
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** `#{expression}` */
|
|
261
|
+
export interface Interpolation extends BaseNode {
|
|
262
|
+
type: "interpolation";
|
|
263
|
+
expression: Expression;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** Unquoted `url(...)`. Quoted urls parse as a regular `function` call. */
|
|
267
|
+
export interface Url extends BaseNode {
|
|
268
|
+
type: "url";
|
|
269
|
+
parts: Array<string | Interpolation>;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export interface FunctionCall extends BaseNode {
|
|
273
|
+
type: "function";
|
|
274
|
+
/** `Member` callees cover namespaced/method calls: `math.div()`, `item.join()`. */
|
|
275
|
+
callee: Identifier | Member | Interpolation;
|
|
276
|
+
args: Argument[];
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export interface Argument extends BaseNode {
|
|
280
|
+
type: "argument";
|
|
281
|
+
/** Variable name (without `$`) for named arguments: `f($name: v)`. */
|
|
282
|
+
name: string | null;
|
|
283
|
+
value: Expression;
|
|
284
|
+
/** `f($args...)` */
|
|
285
|
+
spread: boolean;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* CSS-style conditional function:
|
|
290
|
+
* `if($cond: a; $other == 1: b; else: c)`.
|
|
291
|
+
*
|
|
292
|
+
* Arms are `condition: value` pairs separated by `;`, evaluated in order;
|
|
293
|
+
* the optional `else` arm (condition `null`) must be last. A colon-less
|
|
294
|
+
* `if(...)` parses as a regular `function` call instead.
|
|
295
|
+
*/
|
|
296
|
+
export interface IfFunction extends BaseNode {
|
|
297
|
+
type: "if";
|
|
298
|
+
arms: IfArm[];
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export interface IfArm {
|
|
302
|
+
/** `null` for the `else` arm. */
|
|
303
|
+
condition: Expression | null;
|
|
304
|
+
value: Expression;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** Dot accessor: `$obj.field`, `math.$pi`, `prop("provision").body`. */
|
|
308
|
+
export interface Member extends BaseNode {
|
|
309
|
+
type: "member";
|
|
310
|
+
object: Expression;
|
|
311
|
+
property: string;
|
|
312
|
+
/** True for namespaced variables: `math.$pi`. */
|
|
313
|
+
variable: boolean;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** Bracket accessor: `$obj["field"]`, `$list[$i]`. */
|
|
317
|
+
export interface IndexAccess extends BaseNode {
|
|
318
|
+
type: "index";
|
|
319
|
+
object: Expression;
|
|
320
|
+
index: Expression;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export interface Unary extends BaseNode {
|
|
324
|
+
type: "unary";
|
|
325
|
+
operator: "-" | "+" | "not";
|
|
326
|
+
argument: Expression;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export type BinaryOperator =
|
|
330
|
+
| "or"
|
|
331
|
+
| "and"
|
|
332
|
+
| "=="
|
|
333
|
+
| "!="
|
|
334
|
+
| "<"
|
|
335
|
+
| ">"
|
|
336
|
+
| "<="
|
|
337
|
+
| ">="
|
|
338
|
+
| "+"
|
|
339
|
+
| "-"
|
|
340
|
+
| "*"
|
|
341
|
+
| "/"
|
|
342
|
+
| "%";
|
|
343
|
+
|
|
344
|
+
export interface Binary extends BaseNode {
|
|
345
|
+
type: "binary";
|
|
346
|
+
operator: BinaryOperator;
|
|
347
|
+
left: Expression;
|
|
348
|
+
right: Expression;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export interface ListLiteral extends BaseNode {
|
|
352
|
+
type: "list";
|
|
353
|
+
separator: "," | " ";
|
|
354
|
+
items: Expression[];
|
|
355
|
+
/** True for square-bracket lists: `[1, 2, 3]`. */
|
|
356
|
+
brackets: boolean;
|
|
357
|
+
/** True when the list was written wrapped in parentheses. */
|
|
358
|
+
parens: boolean;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export interface MapLiteral extends BaseNode {
|
|
362
|
+
type: "map";
|
|
363
|
+
entries: MapEntry[];
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export interface MapEntry {
|
|
367
|
+
key: Expression;
|
|
368
|
+
value: Expression;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/*
|
|
372
|
+
* ---------------------------------------------------------------------------
|
|
373
|
+
* At-rules
|
|
374
|
+
* ---------------------------------------------------------------------------
|
|
375
|
+
*/
|
|
376
|
+
|
|
377
|
+
export type AtRule =
|
|
378
|
+
| UseRule
|
|
379
|
+
| ScopeRule
|
|
380
|
+
| ListenerRule
|
|
381
|
+
| ActionRule
|
|
382
|
+
| TransitionRule
|
|
383
|
+
| DelayRule
|
|
384
|
+
| ValueAtRule;
|
|
385
|
+
|
|
386
|
+
export interface AtRuleBase extends BaseNode {
|
|
387
|
+
type: "atrule";
|
|
388
|
+
name: string;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/** `@use "url" [as name | as *];`: a `with (…)` clause is a parse error. */
|
|
392
|
+
export interface UseRule extends AtRuleBase {
|
|
393
|
+
name: "use";
|
|
394
|
+
url: string;
|
|
395
|
+
/** `null` = derived from url, `"*"` = global. */
|
|
396
|
+
namespace: string | null;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/** `@scope { … }`: anchors its rules to the sheet host. No prelude. */
|
|
400
|
+
export interface ScopeRule extends AtRuleBase {
|
|
401
|
+
name: "scope";
|
|
402
|
+
block: Block;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* One entry of an at-rule options group: `once`, `target: "li"`,
|
|
407
|
+
* `debounce: 300`. A bare name is a flag (`true`). Shared by `@on`,
|
|
408
|
+
* `@dispatch`, `@command` and `@view-transition`.
|
|
409
|
+
*/
|
|
410
|
+
export interface ListenerOption extends BaseNode {
|
|
411
|
+
type: "listener_option";
|
|
412
|
+
name: string;
|
|
413
|
+
/** `null` for a bare flag (`once`, `self`, `prevent-default`, …). */
|
|
414
|
+
value: Expression | null;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* One event or command name in an at-rule's name list (`@on click,
|
|
419
|
+
* submit`, `@dispatch cart-add`, `@command --refresh`): a bare identifier
|
|
420
|
+
* or a quoted string.
|
|
421
|
+
*/
|
|
422
|
+
export interface EventName extends BaseNode {
|
|
423
|
+
type: "event_name";
|
|
424
|
+
/** The name, without quotes when written as a string. */
|
|
425
|
+
name: string;
|
|
426
|
+
/** True when the name was written as a quoted string. */
|
|
427
|
+
quoted: boolean;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* `@on <event>[, <event>] [(options)] { … }` / `@on <event> (options);`:
|
|
432
|
+
* Quark's listener at-rule. Events are bare identifiers (`click`,
|
|
433
|
+
* `super-form-success`) or strings, comma-separated. An optional
|
|
434
|
+
* parenthesised options group follows (`(target: "li", once, handle:
|
|
435
|
+
* save($draft))`; names are idents, values single expressions; a bare
|
|
436
|
+
* name is a flag). Then either a block — an ordinary rule body the
|
|
437
|
+
* runtime applies once per event — or `;`. A statement without options
|
|
438
|
+
* has nothing to do and is a parse error; a handler list after the
|
|
439
|
+
* events (the pre-2026-09-13 form) is a parse error pointing at
|
|
440
|
+
* `handle:`. `@off` was removed (parse error).
|
|
441
|
+
*/
|
|
442
|
+
export interface ListenerRule extends AtRuleBase {
|
|
443
|
+
name: "on";
|
|
444
|
+
/** Event types in source order; at least one. */
|
|
445
|
+
events: EventName[];
|
|
446
|
+
/** Options group in source order; empty when absent. */
|
|
447
|
+
options: ListenerOption[];
|
|
448
|
+
/** The `@on` block body, or `null` for the statement form. */
|
|
449
|
+
block: Block | null;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* `@dispatch <event>[, <event>] [(options)];` and `@command <name>[,
|
|
454
|
+
* <name>] [(options)];`: Quark's outgoing-event at-rules, statements only
|
|
455
|
+
* (a block is a parse error). Names follow the `@on` event grammar; the
|
|
456
|
+
* options group is the same node as `@on`'s. The runtime accepts them
|
|
457
|
+
* inside `@on` blocks only.
|
|
458
|
+
*/
|
|
459
|
+
export interface ActionRule extends AtRuleBase {
|
|
460
|
+
name: "dispatch" | "command";
|
|
461
|
+
/** Event / command names in source order; at least one. */
|
|
462
|
+
names: EventName[];
|
|
463
|
+
/** Options group in source order; empty when absent. */
|
|
464
|
+
options: ListenerOption[];
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* `@view-transition [(options)] { … }`: Quark's paint-policy block. The
|
|
469
|
+
* optional options group (`(types: "todo", timeout: 500)`) has the same
|
|
470
|
+
* shape as `@on`'s; the block is an ordinary rule body whose writes the
|
|
471
|
+
* runtime applies inside `document.startViewTransition()`. A block is
|
|
472
|
+
* required.
|
|
473
|
+
*/
|
|
474
|
+
export interface TransitionRule extends AtRuleBase {
|
|
475
|
+
name: "view-transition";
|
|
476
|
+
/** Options group in source order; empty when absent. */
|
|
477
|
+
options: ListenerOption[];
|
|
478
|
+
block: Block;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* `@delay <ms> { … }`: Quark's deferred-writes at-rule. The duration is
|
|
483
|
+
* one expression (evaluated at runtime, milliseconds); the block is an
|
|
484
|
+
* ordinary rule body the runtime applies once when the timer fires. No
|
|
485
|
+
* statement form: a missing duration or block is a parse error.
|
|
486
|
+
*/
|
|
487
|
+
export interface DelayRule extends AtRuleBase {
|
|
488
|
+
name: "delay";
|
|
489
|
+
duration: Expression;
|
|
490
|
+
block: Block;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/** `@debug`, `@warn`, `@error`. */
|
|
494
|
+
export interface ValueAtRule extends AtRuleBase {
|
|
495
|
+
name: "debug" | "warn" | "error";
|
|
496
|
+
value: Expression;
|
|
497
|
+
}
|