@projectwallace/css-parser 0.6.7 → 0.7.1

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.
@@ -0,0 +1,455 @@
1
+ import { DIMENSION, NUMBER, DECLARATION, FLAG_IMPORTANT, FLAG_VENDOR_PREFIXED, FLAG_HAS_ERROR, FLAG_HAS_BLOCK, FLAG_HAS_DECLARATIONS, STYLE_RULE, BLOCK, AT_RULE, COMMENT, PSEUDO_CLASS_SELECTOR, PSEUDO_ELEMENT_SELECTOR, FLAG_HAS_PARENS, NTH_SELECTOR, NTH_OF_SELECTOR, SELECTOR_LIST, SELECTOR, COMBINATOR, ATTRIBUTE_SELECTOR, PRELUDE_OPERATOR, LAYER_NAME, SUPPORTS_QUERY, CONTAINER_QUERY, MEDIA_TYPE, MEDIA_FEATURE, MEDIA_QUERY, LANG_SELECTOR, NESTING_SELECTOR, UNIVERSAL_SELECTOR, ID_SELECTOR, CLASS_SELECTOR, TYPE_SELECTOR, URL, PARENTHESIS, OPERATOR, FUNCTION, HASH, STRING, IDENTIFIER, STYLESHEET } from './arena.js';
2
+ import { is_whitespace, CHAR_MINUS_HYPHEN, CHAR_PLUS } from './string-utils.js';
3
+ import { parse_dimension } from './parse-utils.js';
4
+
5
+ const TYPE_NAMES = {
6
+ [STYLESHEET]: "StyleSheet",
7
+ [STYLE_RULE]: "Rule",
8
+ [AT_RULE]: "Atrule",
9
+ [DECLARATION]: "Declaration",
10
+ [SELECTOR]: "Selector",
11
+ [COMMENT]: "Comment",
12
+ [BLOCK]: "Block",
13
+ [IDENTIFIER]: "Identifier",
14
+ [NUMBER]: "Number",
15
+ [DIMENSION]: "Dimension",
16
+ [STRING]: "String",
17
+ [HASH]: "Hash",
18
+ [FUNCTION]: "Function",
19
+ [OPERATOR]: "Operator",
20
+ [PARENTHESIS]: "Parentheses",
21
+ [URL]: "Url",
22
+ [SELECTOR_LIST]: "SelectorList",
23
+ [TYPE_SELECTOR]: "TypeSelector",
24
+ [CLASS_SELECTOR]: "ClassSelector",
25
+ [ID_SELECTOR]: "IdSelector",
26
+ [ATTRIBUTE_SELECTOR]: "AttributeSelector",
27
+ [PSEUDO_CLASS_SELECTOR]: "PseudoClassSelector",
28
+ [PSEUDO_ELEMENT_SELECTOR]: "PseudoElementSelector",
29
+ [COMBINATOR]: "Combinator",
30
+ [UNIVERSAL_SELECTOR]: "UniversalSelector",
31
+ [NESTING_SELECTOR]: "NestingSelector",
32
+ [NTH_SELECTOR]: "Nth",
33
+ [NTH_OF_SELECTOR]: "NthOf",
34
+ [LANG_SELECTOR]: "Lang",
35
+ [MEDIA_QUERY]: "MediaQuery",
36
+ [MEDIA_FEATURE]: "Feature",
37
+ [MEDIA_TYPE]: "MediaType",
38
+ [CONTAINER_QUERY]: "ContainerQuery",
39
+ [SUPPORTS_QUERY]: "SupportsQuery",
40
+ [LAYER_NAME]: "Layer",
41
+ [PRELUDE_OPERATOR]: "Operator"
42
+ };
43
+ class CSSNode {
44
+ arena;
45
+ source;
46
+ index;
47
+ constructor(arena, source, index) {
48
+ this.arena = arena;
49
+ this.source = source;
50
+ this.index = index;
51
+ }
52
+ // Get the node index (for internal use)
53
+ get_index() {
54
+ return this.index;
55
+ }
56
+ // Get node type as number (for performance)
57
+ get type() {
58
+ return this.arena.get_type(this.index);
59
+ }
60
+ // Get node type as human-readable string
61
+ get type_name() {
62
+ return TYPE_NAMES[this.type] || "unknown";
63
+ }
64
+ // Get the full text of this node from source
65
+ get text() {
66
+ let start = this.arena.get_start_offset(this.index);
67
+ let length = this.arena.get_length(this.index);
68
+ return this.source.substring(start, start + length);
69
+ }
70
+ // Get the "content" text (property name for declarations, at-rule name for at-rules, layer name for import layers)
71
+ get name() {
72
+ let start = this.arena.get_content_start(this.index);
73
+ let length = this.arena.get_content_length(this.index);
74
+ if (length === 0) return "";
75
+ return this.source.substring(start, start + length);
76
+ }
77
+ // Alias for name (for declarations: "color" in "color: blue")
78
+ // More semantic than `name` for declaration nodes
79
+ get property() {
80
+ return this.name;
81
+ }
82
+ // Get the value text (for declarations: "blue" in "color: blue")
83
+ // For dimension/number nodes: returns the numeric value as a number
84
+ // For string nodes: returns the string content without quotes
85
+ get value() {
86
+ if (this.type === DIMENSION || this.type === NUMBER) {
87
+ return parse_dimension(this.text).value;
88
+ }
89
+ let start = this.arena.get_value_start(this.index);
90
+ let length = this.arena.get_value_length(this.index);
91
+ if (length === 0) return null;
92
+ return this.source.substring(start, start + length);
93
+ }
94
+ // Get the prelude text (for at-rules: "(min-width: 768px)" in "@media (min-width: 768px)")
95
+ // This is an alias for `value` to make at-rule usage more semantic
96
+ get prelude() {
97
+ let val = this.value;
98
+ return typeof val === "string" ? val : null;
99
+ }
100
+ // Get the attribute operator (for attribute selectors: =, ~=, |=, ^=, $=, *=)
101
+ // Returns one of the ATTR_OPERATOR_* constants
102
+ get attr_operator() {
103
+ return this.arena.get_attr_operator(this.index);
104
+ }
105
+ // Get the attribute flags (for attribute selectors: i, s)
106
+ // Returns one of the ATTR_FLAG_* constants
107
+ get attr_flags() {
108
+ return this.arena.get_attr_flags(this.index);
109
+ }
110
+ // Get the unit for dimension nodes (e.g., "px" from "100px", "%" from "50%")
111
+ get unit() {
112
+ if (this.type !== DIMENSION) return null;
113
+ return parse_dimension(this.text).unit;
114
+ }
115
+ // Check if this declaration has !important
116
+ get is_important() {
117
+ if (this.type !== DECLARATION) return null;
118
+ return this.arena.has_flag(this.index, FLAG_IMPORTANT);
119
+ }
120
+ // Check if this has a vendor prefix (flag-based for performance)
121
+ get is_vendor_prefixed() {
122
+ return this.arena.has_flag(this.index, FLAG_VENDOR_PREFIXED);
123
+ }
124
+ // Check if this node has an error
125
+ get has_error() {
126
+ return this.arena.has_flag(this.index, FLAG_HAS_ERROR);
127
+ }
128
+ // Check if this at-rule has a prelude
129
+ get has_prelude() {
130
+ return this.arena.get_value_length(this.index) > 0;
131
+ }
132
+ // Check if this rule has a block { }
133
+ get has_block() {
134
+ return this.arena.has_flag(this.index, FLAG_HAS_BLOCK);
135
+ }
136
+ // Check if this style rule has declarations
137
+ get has_declarations() {
138
+ return this.arena.has_flag(this.index, FLAG_HAS_DECLARATIONS);
139
+ }
140
+ // Get the block node (for style rules and at-rules with blocks)
141
+ get block() {
142
+ if (this.type === STYLE_RULE) {
143
+ let first = this.first_child;
144
+ if (!first) return null;
145
+ let blockNode = first.next_sibling;
146
+ if (blockNode && blockNode.type === BLOCK) {
147
+ return blockNode;
148
+ }
149
+ return null;
150
+ }
151
+ if (this.type === AT_RULE) {
152
+ let child = this.first_child;
153
+ while (child) {
154
+ if (child.type === BLOCK && !child.next_sibling) {
155
+ return child;
156
+ }
157
+ child = child.next_sibling;
158
+ }
159
+ return null;
160
+ }
161
+ return null;
162
+ }
163
+ // Check if this block is empty (no declarations or rules, only comments allowed)
164
+ get is_empty() {
165
+ if (this.type !== BLOCK) return false;
166
+ let child = this.first_child;
167
+ while (child) {
168
+ if (child.type !== COMMENT) {
169
+ return false;
170
+ }
171
+ child = child.next_sibling;
172
+ }
173
+ return true;
174
+ }
175
+ // --- Value Node Access (for declarations) ---
176
+ // Get array of parsed value nodes (for declarations only)
177
+ get values() {
178
+ let result = [];
179
+ let child = this.first_child;
180
+ while (child) {
181
+ result.push(child);
182
+ child = child.next_sibling;
183
+ }
184
+ return result;
185
+ }
186
+ // Get count of value nodes
187
+ get value_count() {
188
+ let count = 0;
189
+ let child = this.first_child;
190
+ while (child) {
191
+ count++;
192
+ child = child.next_sibling;
193
+ }
194
+ return count;
195
+ }
196
+ // Get start line number
197
+ get line() {
198
+ return this.arena.get_start_line(this.index);
199
+ }
200
+ // Get start column number
201
+ get column() {
202
+ return this.arena.get_start_column(this.index);
203
+ }
204
+ // Get start offset in source
205
+ get offset() {
206
+ return this.arena.get_start_offset(this.index);
207
+ }
208
+ // Get length in source
209
+ get length() {
210
+ return this.arena.get_length(this.index);
211
+ }
212
+ // --- Tree Traversal ---
213
+ // Get first child node
214
+ get first_child() {
215
+ let child_index = this.arena.get_first_child(this.index);
216
+ if (child_index === 0) return null;
217
+ return new CSSNode(this.arena, this.source, child_index);
218
+ }
219
+ // Get next sibling node
220
+ get next_sibling() {
221
+ let sibling_index = this.arena.get_next_sibling(this.index);
222
+ if (sibling_index === 0) return null;
223
+ return new CSSNode(this.arena, this.source, sibling_index);
224
+ }
225
+ get has_next() {
226
+ let sibling_index = this.arena.get_next_sibling(this.index);
227
+ return sibling_index !== 0;
228
+ }
229
+ // Check if this node has children
230
+ // For pseudo-class/pseudo-element functions, returns true if FLAG_HAS_PARENS is set
231
+ // This allows formatters to distinguish :lang() from :hover
232
+ get has_children() {
233
+ if (this.type === PSEUDO_CLASS_SELECTOR || this.type === PSEUDO_ELEMENT_SELECTOR) {
234
+ if (this.arena.has_flag(this.index, FLAG_HAS_PARENS)) {
235
+ return true;
236
+ }
237
+ }
238
+ return this.arena.has_children(this.index);
239
+ }
240
+ // Get all children as an array
241
+ get children() {
242
+ let result = [];
243
+ let child = this.first_child;
244
+ while (child) {
245
+ result.push(child);
246
+ child = child.next_sibling;
247
+ }
248
+ return result;
249
+ }
250
+ // Make CSSNode iterable over its children
251
+ *[Symbol.iterator]() {
252
+ let child = this.first_child;
253
+ while (child) {
254
+ yield child;
255
+ child = child.next_sibling;
256
+ }
257
+ }
258
+ // --- An+B Expression Helpers (for NODE_SELECTOR_NTH) ---
259
+ // Get the 'a' coefficient from An+B expression (e.g., "2n" from "2n+1", "odd" from "odd")
260
+ get nth_a() {
261
+ if (this.type !== NTH_SELECTOR) return null;
262
+ let len = this.arena.get_content_length(this.index);
263
+ if (len === 0) return null;
264
+ let start = this.arena.get_content_start(this.index);
265
+ return this.source.substring(start, start + len);
266
+ }
267
+ // Get the 'b' coefficient from An+B expression (e.g., "+1" from "2n+1")
268
+ get nth_b() {
269
+ if (this.type !== NTH_SELECTOR) return null;
270
+ let len = this.arena.get_value_length(this.index);
271
+ if (len === 0) return null;
272
+ let start = this.arena.get_value_start(this.index);
273
+ let value = this.source.substring(start, start + len);
274
+ let check_pos = start - 1;
275
+ while (check_pos >= 0) {
276
+ let ch = this.source.charCodeAt(check_pos);
277
+ if (is_whitespace(ch)) {
278
+ check_pos--;
279
+ continue;
280
+ }
281
+ if (ch === CHAR_MINUS_HYPHEN) {
282
+ value = "-" + value;
283
+ } else if (ch === CHAR_PLUS) {
284
+ value = "+" + value;
285
+ }
286
+ break;
287
+ }
288
+ return value;
289
+ }
290
+ // --- Pseudo-Class Nth-Of Helpers (for NODE_SELECTOR_NTH_OF) ---
291
+ // Get the An+B formula node from :nth-child(2n+1 of .foo)
292
+ get nth() {
293
+ if (this.type !== NTH_OF_SELECTOR) return null;
294
+ return this.first_child;
295
+ }
296
+ // Get the selector list from :nth-child(2n+1 of .foo)
297
+ get selector() {
298
+ if (this.type !== NTH_OF_SELECTOR) return null;
299
+ let first = this.first_child;
300
+ return first ? first.next_sibling : null;
301
+ }
302
+ // --- Pseudo-Class Selector List Helper ---
303
+ // Get selector list from pseudo-class functions
304
+ // Works for :is(.a), :not(.b), :has(.c), :where(.d), :nth-child(2n of .e)
305
+ get selector_list() {
306
+ if (this.type !== PSEUDO_CLASS_SELECTOR) return null;
307
+ let child = this.first_child;
308
+ if (!child) return null;
309
+ if (child.type === SELECTOR_LIST) {
310
+ return child;
311
+ }
312
+ if (child.type === NTH_OF_SELECTOR) {
313
+ return child.selector;
314
+ }
315
+ return null;
316
+ }
317
+ // --- Compound Selector Helpers (for NODE_SELECTOR) ---
318
+ // Iterator over first compound selector parts (zero allocation)
319
+ // Yields parts before the first combinator
320
+ *compound_parts() {
321
+ if (this.type !== SELECTOR) return;
322
+ let child = this.first_child;
323
+ while (child) {
324
+ if (child.type === COMBINATOR) break;
325
+ yield child;
326
+ child = child.next_sibling;
327
+ }
328
+ }
329
+ // Get first compound selector as array
330
+ // Returns array of parts before first combinator
331
+ get first_compound() {
332
+ if (this.type !== SELECTOR) return [];
333
+ let result = [];
334
+ let child = this.first_child;
335
+ while (child) {
336
+ if (child.type === COMBINATOR) break;
337
+ result.push(child);
338
+ child = child.next_sibling;
339
+ }
340
+ return result;
341
+ }
342
+ // Split selector into compound selectors
343
+ // Returns array of compound arrays split by combinators
344
+ get all_compounds() {
345
+ if (this.type !== SELECTOR) return [];
346
+ let compounds = [];
347
+ let current_compound = [];
348
+ let child = this.first_child;
349
+ while (child) {
350
+ if (child.type === COMBINATOR) {
351
+ if (current_compound.length > 0) {
352
+ compounds.push(current_compound);
353
+ current_compound = [];
354
+ }
355
+ } else {
356
+ current_compound.push(child);
357
+ }
358
+ child = child.next_sibling;
359
+ }
360
+ if (current_compound.length > 0) {
361
+ compounds.push(current_compound);
362
+ }
363
+ return compounds;
364
+ }
365
+ // Check if selector is compound (no combinators)
366
+ get is_compound() {
367
+ if (this.type !== SELECTOR) return false;
368
+ let child = this.first_child;
369
+ while (child) {
370
+ if (child.type === COMBINATOR) return false;
371
+ child = child.next_sibling;
372
+ }
373
+ return true;
374
+ }
375
+ // Get text of first compound selector (no node allocation)
376
+ get first_compound_text() {
377
+ if (this.type !== SELECTOR) return "";
378
+ let start = -1;
379
+ let end = -1;
380
+ let child = this.first_child;
381
+ while (child) {
382
+ if (child.type === COMBINATOR) break;
383
+ if (start === -1) start = child.offset;
384
+ end = child.offset + child.length;
385
+ child = child.next_sibling;
386
+ }
387
+ if (start === -1) return "";
388
+ return this.source.substring(start, end);
389
+ }
390
+ // --- Node Cloning ---
391
+ /**
392
+ * Clone this node as a mutable plain JavaScript object
393
+ *
394
+ * Extracts all properties from the arena into a plain object with children as an array.
395
+ * The resulting object can be freely modified.
396
+ *
397
+ * @param options - Cloning configuration
398
+ * @param options.deep - Recursively clone children (default: true)
399
+ * @param options.locations - Include line/column/offset/length (default: false)
400
+ * @returns Plain object with children as array
401
+ *
402
+ * @example
403
+ * const ast = parse('div { color: red; }')
404
+ * const decl = ast.first_child.block.first_child
405
+ * const plain = decl.clone()
406
+ *
407
+ * // Access children as array
408
+ * plain.children.length
409
+ * plain.children[0]
410
+ * plain.children.push(newChild)
411
+ */
412
+ clone(options = {}) {
413
+ const { deep = true, locations = false } = options;
414
+ let plain = {
415
+ type: this.type,
416
+ type_name: this.type_name,
417
+ text: this.text,
418
+ children: []
419
+ };
420
+ if (this.name) plain.name = this.name;
421
+ if (this.type === DECLARATION) plain.property = this.name;
422
+ if (this.value !== void 0 && this.value !== null) {
423
+ plain.value = this.value;
424
+ if (this.unit) plain.unit = this.unit;
425
+ }
426
+ if (this.type === AT_RULE && this.prelude) {
427
+ plain.prelude = this.prelude;
428
+ }
429
+ if (this.type === DECLARATION) plain.is_important = this.is_important;
430
+ plain.is_vendor_prefixed = this.is_vendor_prefixed;
431
+ plain.has_error = this.has_error;
432
+ if (this.type === ATTRIBUTE_SELECTOR) {
433
+ plain.attr_operator = this.attr_operator;
434
+ plain.attr_flags = this.attr_flags;
435
+ }
436
+ if (this.type === NTH_SELECTOR || this.type === NTH_OF_SELECTOR) {
437
+ plain.nth_a = this.nth_a;
438
+ plain.nth_b = this.nth_b;
439
+ }
440
+ if (locations) {
441
+ plain.line = this.line;
442
+ plain.column = this.column;
443
+ plain.offset = this.offset;
444
+ plain.length = this.length;
445
+ }
446
+ if (deep) {
447
+ for (let child of this.children) {
448
+ plain.children.push(child.clone({ deep: true, locations }));
449
+ }
450
+ }
451
+ return plain;
452
+ }
453
+ }
454
+
455
+ export { CSSNode, TYPE_NAMES };
package/dist/index.d.ts CHANGED
@@ -8,5 +8,5 @@ export { type ParserOptions } from './parse';
8
8
  export { CSSNode, type CSSNodeType, TYPE_NAMES, type CloneOptions, type PlainCSSNode } from './css-node';
9
9
  export type { LexerPosition } from './lexer';
10
10
  export { ATTR_OPERATOR_NONE, ATTR_OPERATOR_EQUAL, ATTR_OPERATOR_TILDE_EQUAL, ATTR_OPERATOR_PIPE_EQUAL, ATTR_OPERATOR_CARET_EQUAL, ATTR_OPERATOR_DOLLAR_EQUAL, ATTR_OPERATOR_STAR_EQUAL, ATTR_FLAG_NONE, ATTR_FLAG_CASE_INSENSITIVE, ATTR_FLAG_CASE_SENSITIVE, } from './arena';
11
- export { NODE_STYLE_RULE, NODE_AT_RULE, NODE_COMMENT, NODE_DECLARATION, NODE_SELECTOR, NODE_STYLESHEET, NODE_VALUE_KEYWORD, NODE_VALUE_NUMBER, NODE_VALUE_DIMENSION, NODE_VALUE_STRING, NODE_VALUE_COLOR, NODE_VALUE_FUNCTION, NODE_VALUE_OPERATOR, NODE_VALUE_PARENTHESIS, NODE_SELECTOR_LIST, NODE_SELECTOR_TYPE, NODE_SELECTOR_CLASS, NODE_SELECTOR_ID, NODE_SELECTOR_ATTRIBUTE, NODE_SELECTOR_PSEUDO_CLASS, NODE_SELECTOR_PSEUDO_ELEMENT, NODE_SELECTOR_COMBINATOR, NODE_SELECTOR_UNIVERSAL, NODE_SELECTOR_NESTING, NODE_SELECTOR_NTH, NODE_SELECTOR_NTH_OF, NODE_SELECTOR_LANG, NODE_PRELUDE_MEDIA_QUERY, NODE_PRELUDE_MEDIA_FEATURE, NODE_PRELUDE_MEDIA_TYPE, NODE_PRELUDE_CONTAINER_QUERY, NODE_PRELUDE_SUPPORTS_QUERY, NODE_PRELUDE_LAYER_NAME, NODE_PRELUDE_IDENTIFIER, NODE_PRELUDE_OPERATOR, NODE_PRELUDE_IMPORT_URL, NODE_PRELUDE_IMPORT_LAYER, NODE_PRELUDE_IMPORT_SUPPORTS, FLAG_IMPORTANT, } from './parse';
12
- export { TOKEN_IDENT, TOKEN_FUNCTION, TOKEN_AT_KEYWORD, TOKEN_HASH, TOKEN_STRING, TOKEN_BAD_STRING, TOKEN_URL, TOKEN_BAD_URL, TOKEN_DELIM, TOKEN_NUMBER, TOKEN_PERCENTAGE, TOKEN_DIMENSION, TOKEN_WHITESPACE, TOKEN_CDO, TOKEN_CDC, TOKEN_COLON, TOKEN_SEMICOLON, TOKEN_COMMA, TOKEN_LEFT_BRACKET, TOKEN_RIGHT_BRACKET, TOKEN_LEFT_PAREN, TOKEN_RIGHT_PAREN, TOKEN_LEFT_BRACE, TOKEN_RIGHT_BRACE, TOKEN_COMMENT, TOKEN_EOF, type Token, type TokenType, } from './token-types';
11
+ export * from './constants';
12
+ export * from './token-types';
package/dist/index.js CHANGED
@@ -3,27 +3,7 @@ export { parse_selector } from './parse-selector.js';
3
3
  export { parse_atrule_prelude } from './parse-atrule-prelude.js';
4
4
  export { parse_value } from './parse-value.js';
5
5
  export { tokenize } from './tokenize.js';
6
- export { h as ATTR_FLAG_CASE_INSENSITIVE, i as ATTR_FLAG_CASE_SENSITIVE, g as ATTR_FLAG_NONE, d as ATTR_OPERATOR_CARET_EQUAL, e as ATTR_OPERATOR_DOLLAR_EQUAL, a as ATTR_OPERATOR_EQUAL, A as ATTR_OPERATOR_NONE, c as ATTR_OPERATOR_PIPE_EQUAL, f as ATTR_OPERATOR_STAR_EQUAL, b as ATTR_OPERATOR_TILDE_EQUAL, C as CSSNode, Y as FLAG_IMPORTANT, j as NODE_AT_RULE, k as NODE_COMMENT, l as NODE_DECLARATION, P as NODE_PRELUDE_CONTAINER_QUERY, S as NODE_PRELUDE_IDENTIFIER, W as NODE_PRELUDE_IMPORT_LAYER, X as NODE_PRELUDE_IMPORT_SUPPORTS, V as NODE_PRELUDE_IMPORT_URL, R as NODE_PRELUDE_LAYER_NAME, M as NODE_PRELUDE_MEDIA_FEATURE, L as NODE_PRELUDE_MEDIA_QUERY, O as NODE_PRELUDE_MEDIA_TYPE, U as NODE_PRELUDE_OPERATOR, Q as NODE_PRELUDE_SUPPORTS_QUERY, m as NODE_SELECTOR, B as NODE_SELECTOR_ATTRIBUTE, y as NODE_SELECTOR_CLASS, F as NODE_SELECTOR_COMBINATOR, z as NODE_SELECTOR_ID, K as NODE_SELECTOR_LANG, w as NODE_SELECTOR_LIST, H as NODE_SELECTOR_NESTING, I as NODE_SELECTOR_NTH, J as NODE_SELECTOR_NTH_OF, D as NODE_SELECTOR_PSEUDO_CLASS, E as NODE_SELECTOR_PSEUDO_ELEMENT, x as NODE_SELECTOR_TYPE, G as NODE_SELECTOR_UNIVERSAL, n as NODE_STYLESHEET, N as NODE_STYLE_RULE, s as NODE_VALUE_COLOR, q as NODE_VALUE_DIMENSION, t as NODE_VALUE_FUNCTION, o as NODE_VALUE_KEYWORD, p as NODE_VALUE_NUMBER, u as NODE_VALUE_OPERATOR, v as NODE_VALUE_PARENTHESIS, r as NODE_VALUE_STRING, T as TYPE_NAMES } from './css-node-GOEvp2OO.js';
7
- export { b as TOKEN_AT_KEYWORD, e as TOKEN_BAD_STRING, g as TOKEN_BAD_URL, n as TOKEN_CDC, m as TOKEN_CDO, o as TOKEN_COLON, q as TOKEN_COMMA, x as TOKEN_COMMENT, h as TOKEN_DELIM, k as TOKEN_DIMENSION, y as TOKEN_EOF, a as TOKEN_FUNCTION, c as TOKEN_HASH, T as TOKEN_IDENT, v as TOKEN_LEFT_BRACE, r as TOKEN_LEFT_BRACKET, t as TOKEN_LEFT_PAREN, i as TOKEN_NUMBER, j as TOKEN_PERCENTAGE, w as TOKEN_RIGHT_BRACE, s as TOKEN_RIGHT_BRACKET, u as TOKEN_RIGHT_PAREN, p as TOKEN_SEMICOLON, d as TOKEN_STRING, f as TOKEN_URL, l as TOKEN_WHITESPACE } from './lexer-CtBKgfVv.js';
8
-
9
- function walk(node, callback, depth = 0) {
10
- callback(node, depth);
11
- let child = node.first_child;
12
- while (child) {
13
- walk(child, callback, depth + 1);
14
- child = child.next_sibling;
15
- }
16
- }
17
- const NOOP = function() {
18
- };
19
- function traverse(node, { enter = NOOP, leave = NOOP } = {}) {
20
- enter(node);
21
- let child = node.first_child;
22
- while (child) {
23
- traverse(child, { enter, leave });
24
- child = child.next_sibling;
25
- }
26
- leave(node);
27
- }
28
-
29
- export { traverse, walk };
6
+ export { traverse, walk } from './walk.js';
7
+ export { CSSNode, TYPE_NAMES } from './css-node.js';
8
+ export { ATTRIBUTE_SELECTOR, ATTR_FLAG_CASE_INSENSITIVE, ATTR_FLAG_CASE_SENSITIVE, ATTR_FLAG_NONE, ATTR_OPERATOR_CARET_EQUAL, ATTR_OPERATOR_DOLLAR_EQUAL, ATTR_OPERATOR_EQUAL, ATTR_OPERATOR_NONE, ATTR_OPERATOR_PIPE_EQUAL, ATTR_OPERATOR_STAR_EQUAL, ATTR_OPERATOR_TILDE_EQUAL, AT_RULE, BLOCK, CLASS_SELECTOR, COMBINATOR, COMMENT, CONTAINER_QUERY, DECLARATION, DIMENSION, FLAG_IMPORTANT, FUNCTION, HASH, IDENTIFIER, ID_SELECTOR, LANG_SELECTOR, LAYER_NAME, MEDIA_FEATURE, MEDIA_QUERY, MEDIA_TYPE, NESTING_SELECTOR, NTH_OF_SELECTOR, NTH_SELECTOR, NUMBER, OPERATOR, PARENTHESIS, PRELUDE_OPERATOR, PSEUDO_CLASS_SELECTOR, PSEUDO_ELEMENT_SELECTOR, SELECTOR, SELECTOR_LIST, STRING, STYLESHEET, STYLE_RULE, SUPPORTS_QUERY, TYPE_SELECTOR, UNIVERSAL_SELECTOR, URL } from './arena.js';
9
+ export { TOKEN_AT_KEYWORD, TOKEN_BAD_STRING, TOKEN_BAD_URL, TOKEN_CDC, TOKEN_CDO, TOKEN_COLON, TOKEN_COMMA, TOKEN_COMMENT, TOKEN_DELIM, TOKEN_DIMENSION, TOKEN_EOF, TOKEN_FUNCTION, TOKEN_HASH, TOKEN_IDENT, TOKEN_LEFT_BRACE, TOKEN_LEFT_BRACKET, TOKEN_LEFT_PAREN, TOKEN_NUMBER, TOKEN_PERCENTAGE, TOKEN_RIGHT_BRACE, TOKEN_RIGHT_BRACKET, TOKEN_RIGHT_PAREN, TOKEN_SEMICOLON, TOKEN_STRING, TOKEN_URL, TOKEN_WHITESPACE } from './token-types.js';
package/dist/lexer.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type Token, type TokenType } from './token-types';
1
+ import { type TokenType } from './token-types';
2
2
  export interface LexerPosition {
3
3
  pos: number;
4
4
  line: number;
@@ -9,39 +9,3 @@ export interface LexerPosition {
9
9
  token_line: number;
10
10
  token_column: number;
11
11
  }
12
- export declare class Lexer {
13
- source: string;
14
- pos: number;
15
- line: number;
16
- column: number;
17
- skip_comments: boolean;
18
- token_type: TokenType;
19
- token_start: number;
20
- token_end: number;
21
- token_line: number;
22
- token_column: number;
23
- constructor(source: string, skip_comments?: boolean);
24
- next_token_fast(skip_whitespace?: boolean): TokenType;
25
- consume_whitespace(start_line: number, start_column: number): TokenType;
26
- consume_comment(start_line: number, start_column: number): TokenType;
27
- consume_string(quote: number, start_line: number, start_column: number): TokenType;
28
- consume_hex_escape(): void;
29
- consume_number(start_line: number, start_column: number): TokenType;
30
- consume_ident_or_function(start_line: number, start_column: number): TokenType;
31
- consume_at_keyword(start_line: number, start_column: number): TokenType;
32
- consume_hash(start_line: number, start_column: number): TokenType;
33
- advance(count?: number): void;
34
- peek(offset?: number): number;
35
- make_token(type: TokenType, start: number, end: number, line?: number, column?: number): TokenType;
36
- next_token(skip_whitespace?: boolean): Token | null;
37
- /**
38
- * Save complete lexer state for backtracking
39
- * @returns Object containing all lexer state
40
- */
41
- save_position(): LexerPosition;
42
- /**
43
- * Restore lexer state from saved position
44
- * @param saved The saved position to restore
45
- */
46
- restore_position(saved: LexerPosition): void;
47
- }
@@ -1,83 +1,5 @@
1
- let CHAR_ALPHA = 1 << 0;
2
- let CHAR_DIGIT = 1 << 1;
3
- let CHAR_HEX = 1 << 2;
4
- let CHAR_WHITESPACE = 1 << 3;
5
- let CHAR_NEWLINE = 1 << 4;
6
- let char_types = new Uint8Array(128);
7
- for (let i = 48; i <= 57; i++) {
8
- char_types[i] = CHAR_DIGIT;
9
- }
10
- for (let i = 48; i <= 57; i++) {
11
- char_types[i] |= CHAR_HEX;
12
- }
13
- for (let i = 65; i <= 70; i++) {
14
- char_types[i] = CHAR_HEX;
15
- }
16
- for (let i = 97; i <= 102; i++) {
17
- char_types[i] = CHAR_HEX;
18
- }
19
- for (let i = 65; i <= 90; i++) {
20
- char_types[i] |= CHAR_ALPHA;
21
- }
22
- for (let i = 97; i <= 122; i++) {
23
- char_types[i] |= CHAR_ALPHA;
24
- }
25
- char_types[32] = CHAR_WHITESPACE;
26
- char_types[9] = CHAR_WHITESPACE;
27
- char_types[10] = CHAR_NEWLINE;
28
- char_types[13] = CHAR_NEWLINE;
29
- char_types[12] = CHAR_NEWLINE;
30
- function is_digit(ch) {
31
- return ch < 128 && (char_types[ch] & CHAR_DIGIT) !== 0;
32
- }
33
- function is_hex_digit(ch) {
34
- return ch < 128 && (char_types[ch] & CHAR_HEX) !== 0;
35
- }
36
- function is_alpha(ch) {
37
- return ch < 128 && (char_types[ch] & CHAR_ALPHA) !== 0;
38
- }
39
- function is_whitespace(ch) {
40
- return ch < 128 && (char_types[ch] & CHAR_WHITESPACE) !== 0;
41
- }
42
- function is_newline(ch) {
43
- return ch < 128 && (char_types[ch] & CHAR_NEWLINE) !== 0;
44
- }
45
- function is_ident_start(ch) {
46
- if (ch >= 128) return true;
47
- if (ch === 95) return true;
48
- return is_alpha(ch);
49
- }
50
- function is_ident_char(ch) {
51
- if (ch === 45) return true;
52
- return is_ident_start(ch) || is_digit(ch);
53
- }
54
-
55
- const TOKEN_IDENT = 1;
56
- const TOKEN_FUNCTION = 2;
57
- const TOKEN_AT_KEYWORD = 3;
58
- const TOKEN_HASH = 4;
59
- const TOKEN_STRING = 5;
60
- const TOKEN_BAD_STRING = 6;
61
- const TOKEN_URL = 7;
62
- const TOKEN_BAD_URL = 8;
63
- const TOKEN_DELIM = 9;
64
- const TOKEN_NUMBER = 10;
65
- const TOKEN_PERCENTAGE = 11;
66
- const TOKEN_DIMENSION = 12;
67
- const TOKEN_WHITESPACE = 13;
68
- const TOKEN_CDO = 14;
69
- const TOKEN_CDC = 15;
70
- const TOKEN_COLON = 16;
71
- const TOKEN_SEMICOLON = 17;
72
- const TOKEN_COMMA = 18;
73
- const TOKEN_LEFT_BRACKET = 19;
74
- const TOKEN_RIGHT_BRACKET = 20;
75
- const TOKEN_LEFT_PAREN = 21;
76
- const TOKEN_RIGHT_PAREN = 22;
77
- const TOKEN_LEFT_BRACE = 23;
78
- const TOKEN_RIGHT_BRACE = 24;
79
- const TOKEN_COMMENT = 25;
80
- const TOKEN_EOF = 26;
1
+ import { is_whitespace, is_newline, is_digit, is_ident_start, is_hex_digit, is_ident_char } from './char-types.js';
2
+ import { TOKEN_EOF, TOKEN_LEFT_BRACE, TOKEN_RIGHT_BRACE, TOKEN_COLON, TOKEN_SEMICOLON, TOKEN_COMMA, TOKEN_LEFT_BRACKET, TOKEN_RIGHT_BRACKET, TOKEN_LEFT_PAREN, TOKEN_RIGHT_PAREN, TOKEN_CDO, TOKEN_CDC, TOKEN_DELIM, TOKEN_WHITESPACE, TOKEN_COMMENT, TOKEN_STRING, TOKEN_BAD_STRING, TOKEN_PERCENTAGE, TOKEN_DIMENSION, TOKEN_NUMBER, TOKEN_FUNCTION, TOKEN_IDENT, TOKEN_AT_KEYWORD, TOKEN_HASH } from './token-types.js';
81
3
 
82
4
  const CHAR_LEFT_BRACE = 123;
83
5
  const CHAR_RIGHT_BRACE = 125;
@@ -506,4 +428,4 @@ class Lexer {
506
428
  }
507
429
  }
508
430
 
509
- export { Lexer as L, TOKEN_IDENT as T, TOKEN_FUNCTION as a, TOKEN_AT_KEYWORD as b, TOKEN_HASH as c, TOKEN_STRING as d, TOKEN_BAD_STRING as e, TOKEN_URL as f, TOKEN_BAD_URL as g, TOKEN_DELIM as h, TOKEN_NUMBER as i, TOKEN_PERCENTAGE as j, TOKEN_DIMENSION as k, TOKEN_WHITESPACE as l, TOKEN_CDO as m, TOKEN_CDC as n, TOKEN_COLON as o, TOKEN_SEMICOLON as p, TOKEN_COMMA as q, TOKEN_LEFT_BRACKET as r, TOKEN_RIGHT_BRACKET as s, TOKEN_LEFT_PAREN as t, TOKEN_RIGHT_PAREN as u, TOKEN_LEFT_BRACE as v, TOKEN_RIGHT_BRACE as w, TOKEN_COMMENT as x, TOKEN_EOF as y };
431
+ export { Lexer };
@@ -1,22 +1,2 @@
1
- import { CSSDataArena } from './arena';
2
1
  import { CSSNode } from './css-node';
3
- export declare class ANplusBParser {
4
- private lexer;
5
- private arena;
6
- private source;
7
- private expr_end;
8
- constructor(arena: CSSDataArena, source: string);
9
- /**
10
- * Parse An+B expression
11
- * Examples: odd, even, 3, n, -n, 2n, 2n+1, -3n-5
12
- */
13
- parse_anplusb(start: number, end: number, line?: number): number | null;
14
- /**
15
- * Parse the b part after 'n'
16
- * Handles: +5, -3, whitespace variations
17
- */
18
- private parse_b_part;
19
- private skip_whitespace;
20
- private create_anplusb_node;
21
- }
22
2
  export declare function parse_anplusb(expr: string): CSSNode | null;