@projectwallace/css-parser 0.16.2 → 0.18.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.
@@ -1,8 +1,9 @@
1
1
  import { t as Lexer } from "./tokenize-BiRLfVbm.js";
2
- import { l as CSSDataArena } from "./arena-CCye9VYE.js";
3
- import { a as is_whitespace, l as strip_vendor_prefix, o as str_equals } from "./parse-dimension-B0AZRxxt.js";
4
- import { t as CSSNode } from "./css-node-TR2T5Q7D.js";
5
- import { i as trim_boundaries, n as skip_whitespace_and_comments_forward } from "./parse-utils-BmXnziOy.js";
2
+ import { l as CSSDataArena } from "./arena-CFwM4uQs.js";
3
+ import { l as strip_vendor_prefix, o as str_equals } from "./parse-dimension-ouWXNHdx.js";
4
+ import { t as CSSNode } from "./css-node-B3EzCweR.js";
5
+ import { i as trim_boundaries, n as skip_whitespace_and_comments_forward } from "./parse-utils-D7srNG13.js";
6
+ import { t as ValueNodeParser } from "./value-node-parser-CZ47v3hp.js";
6
7
  //#region src/parse-atrule-prelude.ts
7
8
  /** @internal */
8
9
  var AtRulePreludeParser = class {
@@ -10,11 +11,13 @@ var AtRulePreludeParser = class {
10
11
  arena;
11
12
  source;
12
13
  prelude_end;
14
+ value_node_parser;
13
15
  constructor(arena, source) {
14
16
  this.arena = arena;
15
17
  this.source = source;
16
18
  this.lexer = new Lexer(source);
17
19
  this.prelude_end = 0;
20
+ this.value_node_parser = new ValueNodeParser(arena, source);
18
21
  }
19
22
  parse_prelude(at_rule_name, start, end, line = 1, column = 1) {
20
23
  this.prelude_end = end;
@@ -74,30 +77,30 @@ var AtRulePreludeParser = class {
74
77
  let text = this.source.substring(this.lexer.token_start, this.lexer.token_end);
75
78
  if (!str_equals("only", text) && !str_equals("not", text)) this.lexer.restore_position(saved_token_start);
76
79
  } else this.lexer.restore_position(saved_token_start);
77
- let components = [];
80
+ let first_component = 0;
81
+ let last_component = 0;
78
82
  while (this.lexer.pos < this.prelude_end) {
79
83
  this.skip_whitespace();
80
84
  if (this.lexer.pos >= this.prelude_end) break;
81
85
  if (this.peek_token_type() === 18) break;
82
86
  this.next_token();
83
87
  let token_type = this.lexer.token_type;
84
- if (token_type === 21) {
85
- let feature = this.parse_media_feature();
86
- if (feature !== null) components.push(feature);
87
- } else if (token_type === 1) {
88
+ let component = null;
89
+ if (token_type === 21) component = this.parse_media_feature();
90
+ else if (token_type === 1) {
88
91
  let text = this.source.substring(this.lexer.token_start, this.lexer.token_end);
89
- if (this.is_and_or_not(text)) {
90
- let op = this.create_node(38, this.lexer.token_start, this.lexer.token_end);
91
- components.push(op);
92
- } else {
93
- let media_type = this.create_node(34, this.lexer.token_start, this.lexer.token_end);
94
- components.push(media_type);
95
- }
92
+ if (this.is_and_or_not(text)) component = this.create_node(38, this.lexer.token_start, this.lexer.token_end);
93
+ else component = this.create_node(34, this.lexer.token_start, this.lexer.token_end);
96
94
  } else break;
95
+ if (component !== null) {
96
+ if (first_component === 0) first_component = component;
97
+ else this.arena.set_next_sibling(last_component, component);
98
+ last_component = component;
99
+ }
97
100
  }
98
- if (components.length === 0) return null;
101
+ if (first_component === 0) return null;
99
102
  let query_node = this.create_node(32, query_start, this.lexer.pos);
100
- this.arena.append_children(query_node, components);
103
+ this.arena.set_first_child(query_node, first_component);
101
104
  return query_node;
102
105
  }
103
106
  parse_media_feature() {
@@ -107,7 +110,7 @@ var AtRulePreludeParser = class {
107
110
  while (this.lexer.pos < this.prelude_end && depth > 0) {
108
111
  this.next_token();
109
112
  let token_type = this.lexer.token_type;
110
- if (token_type === 21) depth++;
113
+ if (token_type === 21 || token_type === 2) depth++;
111
114
  else if (token_type === 22) depth--;
112
115
  }
113
116
  if (depth !== 0) return null;
@@ -152,25 +155,24 @@ var AtRulePreludeParser = class {
152
155
  }
153
156
  let value_trimmed = trim_boundaries(this.source, colon_pos + 1, content_end);
154
157
  if (value_trimmed) {
155
- let value_nodes = this.parse_feature_value(value_trimmed[0], value_trimmed[1]);
156
- if (value_nodes.length > 0) this.arena.append_children(feature, value_nodes);
158
+ let value_first = this.parse_feature_value(value_trimmed[0], value_trimmed[1]);
159
+ if (value_first !== 0) this.arena.set_first_child(feature, value_first);
157
160
  }
158
161
  }
159
162
  return feature;
160
163
  }
161
164
  parse_container_query() {
162
- let nodes = [];
163
165
  let query_start = this.lexer.pos;
164
- let components = [];
166
+ let first_component = 0;
167
+ let last_component = 0;
165
168
  while (this.lexer.pos < this.prelude_end) {
166
169
  this.skip_whitespace();
167
170
  if (this.lexer.pos >= this.prelude_end) break;
168
171
  this.next_token();
169
172
  let token_type = this.lexer.token_type;
170
- if (token_type === 21) {
171
- let feature = this.parse_media_feature();
172
- if (feature !== null) components.push(feature);
173
- } else if (token_type === 2) {
173
+ let component = null;
174
+ if (token_type === 21) component = this.parse_media_feature();
175
+ else if (token_type === 2) {
174
176
  let func_name = this.source.substring(this.lexer.token_start, this.lexer.token_end - 1);
175
177
  let func_start = this.lexer.token_start;
176
178
  let content_start = this.lexer.token_end;
@@ -194,23 +196,22 @@ var AtRulePreludeParser = class {
194
196
  this.arena.set_content_length(func_node, func_name.length);
195
197
  this.arena.set_value_start_delta(func_node, content_start - func_start);
196
198
  this.arena.set_value_length(func_node, content_end - content_start);
197
- components.push(func_node);
199
+ component = func_node;
198
200
  } else if (token_type === 1) {
199
201
  let text = this.source.substring(this.lexer.token_start, this.lexer.token_end);
200
- if (this.is_and_or_not(text)) {
201
- let op = this.create_node(38, this.lexer.token_start, this.lexer.token_end);
202
- components.push(op);
203
- } else {
204
- let name = this.create_node(10, this.lexer.token_start, this.lexer.token_end);
205
- components.push(name);
206
- }
202
+ if (this.is_and_or_not(text)) component = this.create_node(38, this.lexer.token_start, this.lexer.token_end);
203
+ else component = this.create_node(10, this.lexer.token_start, this.lexer.token_end);
204
+ }
205
+ if (component !== null) {
206
+ if (first_component === 0) first_component = component;
207
+ else this.arena.set_next_sibling(last_component, component);
208
+ last_component = component;
207
209
  }
208
210
  }
209
- if (components.length === 0) return [];
211
+ if (first_component === 0) return [];
210
212
  let query_node = this.create_node(35, query_start, this.lexer.pos);
211
- this.arena.append_children(query_node, components);
212
- nodes.push(query_node);
213
- return nodes;
213
+ this.arena.set_first_child(query_node, first_component);
214
+ return [query_node];
214
215
  }
215
216
  parse_supports_query() {
216
217
  let nodes = [];
@@ -226,7 +227,7 @@ var AtRulePreludeParser = class {
226
227
  while (this.lexer.pos < this.prelude_end && depth > 0) {
227
228
  this.next_token();
228
229
  let inner_token_type = this.lexer.token_type;
229
- if (inner_token_type === 21) depth++;
230
+ if (inner_token_type === 21 || inner_token_type === 2) depth++;
230
231
  else if (inner_token_type === 22) depth--;
231
232
  }
232
233
  if (depth === 0) {
@@ -240,7 +241,7 @@ var AtRulePreludeParser = class {
240
241
  let colon_pos = this.find_colon_at_depth_zero(trimmed[0], trimmed[1]);
241
242
  if (colon_pos !== -1) {
242
243
  let decl_child = this.create_supports_declaration(trimmed[0], trimmed[1], colon_pos);
243
- this.arena.append_children(query, [decl_child]);
244
+ this.arena.set_first_child(query, decl_child);
244
245
  }
245
246
  }
246
247
  nodes.push(query);
@@ -275,17 +276,17 @@ var AtRulePreludeParser = class {
275
276
  this.arena.set_content_start_delta(decl, 0);
276
277
  this.arena.set_content_length(decl, prop_trimmed[1] - prop_trimmed[0]);
277
278
  if (val_trimmed) {
278
- let value_nodes = this.parse_feature_value(val_trimmed[0], val_trimmed[1]);
279
+ let value_first = this.parse_feature_value(val_trimmed[0], val_trimmed[1]);
279
280
  let value_node;
280
- if (value_nodes.length === 0) value_node = this.arena.create_node(50, val_trimmed[0], 0, this.lexer.token_line, this.lexer.token_column);
281
+ if (value_first === 0) value_node = this.arena.create_node(50, val_trimmed[0], 0, this.lexer.token_line, this.lexer.token_column);
281
282
  else {
282
283
  value_node = this.arena.create_node(50, val_trimmed[0], val_trimmed[1] - val_trimmed[0], this.lexer.token_line, this.lexer.token_column);
283
- this.arena.append_children(value_node, value_nodes);
284
+ this.arena.set_first_child(value_node, value_first);
284
285
  }
285
- this.arena.append_children(decl, [value_node]);
286
+ this.arena.set_first_child(decl, value_node);
286
287
  }
287
288
  let supports_decl = this.create_node(57, content_start, content_end);
288
- this.arena.append_children(supports_decl, [decl]);
289
+ this.arena.set_first_child(supports_decl, decl);
289
290
  return supports_decl;
290
291
  }
291
292
  parse_layer_names() {
@@ -296,9 +297,24 @@ var AtRulePreludeParser = class {
296
297
  this.next_token();
297
298
  let token_type = this.lexer.token_type;
298
299
  if (token_type === 1) {
299
- let layer = this.create_node(37, this.lexer.token_start, this.lexer.token_end);
300
+ let name_start = this.lexer.token_start;
301
+ let name_end = this.lexer.token_end;
302
+ while (this.lexer.pos < this.prelude_end) {
303
+ let saved = this.lexer.save_position();
304
+ if (this.next_token() !== 9 || this.source.charCodeAt(this.lexer.token_start) !== 46 || this.lexer.token_start !== name_end) {
305
+ this.lexer.restore_position(saved);
306
+ break;
307
+ }
308
+ let dot_end = this.lexer.token_end;
309
+ if (this.next_token() !== 1 || this.lexer.token_start !== dot_end) {
310
+ this.lexer.restore_position(saved);
311
+ break;
312
+ }
313
+ name_end = this.lexer.token_end;
314
+ }
315
+ let layer = this.create_node(37, name_start, name_end);
300
316
  this.arena.set_content_start_delta(layer, 0);
301
- this.arena.set_content_length(layer, this.lexer.token_end - this.lexer.token_start);
317
+ this.arena.set_content_length(layer, name_end - name_start);
302
318
  nodes.push(layer);
303
319
  } else if (token_type === 18) continue;
304
320
  else if (token_type === 13) continue;
@@ -457,34 +473,8 @@ var AtRulePreludeParser = class {
457
473
  }
458
474
  return this.lexer.next_token_fast(false);
459
475
  }
460
- parse_value_token() {
461
- switch (this.lexer.token_type) {
462
- case 1: return this.create_node(10, this.lexer.token_start, this.lexer.token_end);
463
- case 10: return this.create_node(11, this.lexer.token_start, this.lexer.token_end);
464
- case 11:
465
- case 12: return this.create_node(12, this.lexer.token_start, this.lexer.token_end);
466
- case 5: return this.create_node(13, this.lexer.token_start, this.lexer.token_end);
467
- default: return null;
468
- }
469
- }
470
476
  parse_feature_value(start, end) {
471
- const saved_position = this.lexer.save_position();
472
- this.lexer.seek(start, this.lexer.line, this.lexer.column);
473
- let nodes = [];
474
- while (this.lexer.pos < end) {
475
- this.lexer.next_token_fast(false);
476
- if (this.lexer.token_start >= end) break;
477
- let all_whitespace = true;
478
- for (let i = this.lexer.token_start; i < this.lexer.token_end && i < end; i++) if (!is_whitespace(this.source.charCodeAt(i))) {
479
- all_whitespace = false;
480
- break;
481
- }
482
- if (all_whitespace) continue;
483
- let node = this.parse_value_token();
484
- if (node !== null) nodes.push(node);
485
- }
486
- this.lexer.restore_position(saved_position);
487
- return nodes;
477
+ return this.value_node_parser.parse_chain(start, end, this.lexer.line, this.lexer.column);
488
478
  }
489
479
  parse_namespace_prelude() {
490
480
  let nodes = [];
@@ -513,7 +503,7 @@ var AtRulePreludeParser = class {
513
503
  let depth = 1;
514
504
  while (this.lexer.pos < this.prelude_end && depth > 0) {
515
505
  this.next_token();
516
- if (this.lexer.token_type === 21) depth++;
506
+ if (this.lexer.token_type === 21 || this.lexer.token_type === 2) depth++;
517
507
  else if (this.lexer.token_type === 22) depth--;
518
508
  }
519
509
  let content_end = this.lexer.token_start;
@@ -543,7 +533,8 @@ var AtRulePreludeParser = class {
543
533
  }
544
534
  parse_feature_range(feature_start, feature_end, content_start, content_end) {
545
535
  let range_node = this.create_node(39, feature_start, feature_end);
546
- let children = [];
536
+ let first_child = 0;
537
+ let last_child = 0;
547
538
  let feature_name_start = -1;
548
539
  let feature_name_end = -1;
549
540
  let pos = content_start;
@@ -555,7 +546,9 @@ var AtRulePreludeParser = class {
555
546
  let op_start = pos++;
556
547
  if (pos < content_end && this.source.charCodeAt(pos) === 61) pos++;
557
548
  let op = this.create_node(38, op_start, pos);
558
- children.push(op);
549
+ if (first_child === 0) first_child = op;
550
+ else this.arena.set_next_sibling(last_child, op);
551
+ last_child = op;
559
552
  } else {
560
553
  let saved = this.lexer.save_position();
561
554
  this.lexer.pos = pos;
@@ -564,8 +557,12 @@ var AtRulePreludeParser = class {
564
557
  feature_name_start = this.lexer.token_start;
565
558
  feature_name_end = this.lexer.token_end;
566
559
  } else {
567
- let value_nodes = this.parse_feature_value(this.lexer.token_start, this.lexer.token_end);
568
- children.push(...value_nodes);
560
+ let value_first = this.parse_feature_value(this.lexer.token_start, this.lexer.token_end);
561
+ if (value_first !== 0) {
562
+ if (first_child === 0) first_child = value_first;
563
+ else this.arena.set_next_sibling(last_child, value_first);
564
+ last_child = this.arena.get_last_sibling(value_first);
565
+ }
569
566
  }
570
567
  pos = this.lexer.pos;
571
568
  this.lexer.restore_position(saved);
@@ -575,7 +572,7 @@ var AtRulePreludeParser = class {
575
572
  this.arena.set_content_start_delta(range_node, feature_name_start - feature_start);
576
573
  this.arena.set_content_length(range_node, feature_name_end - feature_name_start);
577
574
  }
578
- this.arena.append_children(range_node, children);
575
+ if (first_child !== 0) this.arena.set_first_child(range_node, first_child);
579
576
  return range_node;
580
577
  }
581
578
  };
@@ -1,7 +1,6 @@
1
- import { l as CSSDataArena } from "./arena-DfpuGV9Y.js";
1
+ import { l as CSSDataArena } from "./arena-Bx5vp6Sl.js";
2
2
  import { n as Lexer } from "./tokenize-DeZYFa9R.js";
3
- import { d as Declaration } from "./node-types-BrZu8T2C.js";
4
-
3
+ import { d as Declaration } from "./node-types-BRnQyc9B.js";
5
4
  //#region src/parse-declaration.d.ts
6
5
  /** @internal */
7
6
  declare class DeclarationParser {
@@ -1,8 +1,8 @@
1
1
  import { t as Lexer } from "./tokenize-BiRLfVbm.js";
2
- import { l as CSSDataArena } from "./arena-CCye9VYE.js";
3
- import { i as is_vendor_prefixed } from "./parse-dimension-B0AZRxxt.js";
4
- import { t as CSSNode } from "./css-node-TR2T5Q7D.js";
5
- import { i as trim_boundaries } from "./parse-utils-BmXnziOy.js";
2
+ import { l as CSSDataArena } from "./arena-CFwM4uQs.js";
3
+ import { i as is_vendor_prefixed } from "./parse-dimension-ouWXNHdx.js";
4
+ import { t as CSSNode } from "./css-node-B3EzCweR.js";
5
+ import { i as trim_boundaries } from "./parse-utils-D7srNG13.js";
6
6
  import { ValueParser } from "./parse-value.js";
7
7
  //#region src/parse-declaration.ts
8
8
  /** @internal */
@@ -110,17 +110,17 @@ var DeclarationParser = class {
110
110
  this.arena.set_value_length(declaration, trimmed[1] - trimmed[0]);
111
111
  if (this.value_parser) {
112
112
  let valueNode = this.value_parser.parse_value(value_start, trimmed[1], value_start_line, value_start_column);
113
- this.arena.append_children(declaration, [valueNode]);
113
+ this.arena.set_first_child(declaration, valueNode);
114
114
  } else {
115
115
  let rawNode = this.arena.create_node(8, trimmed[0], trimmed[1] - trimmed[0], value_start_line, value_start_column);
116
- this.arena.append_children(declaration, [rawNode]);
116
+ this.arena.set_first_child(declaration, rawNode);
117
117
  }
118
118
  } else {
119
119
  this.arena.set_value_start_delta(declaration, value_start - prop_start);
120
120
  this.arena.set_value_length(declaration, 0);
121
121
  if (this.value_parser) {
122
122
  let valueNode = this.value_parser.parse_value(value_start, value_start, value_start_line, value_start_column);
123
- this.arena.append_children(declaration, [valueNode]);
123
+ this.arena.set_first_child(declaration, valueNode);
124
124
  }
125
125
  }
126
126
  if (has_important) this.arena.set_flag(declaration, 1);
@@ -27,15 +27,7 @@ function str_equals(a, b) {
27
27
  }
28
28
  return true;
29
29
  }
30
- /**
31
- * Case-insensitive ASCII prefix check without allocations
32
- * Returns true if string `str` starts with prefix (case-insensitive)
33
- *
34
- * IMPORTANT: prefix MUST be lowercase for correct comparison
35
- *
36
- * @param str - The string to check
37
- * @param prefix - The lowercase prefix to match against
38
- */
30
+ /** Case-insensitive ASCII prefix check without allocations. `prefix` MUST be lowercase. */
39
31
  function str_starts_with(str, prefix) {
40
32
  if (str.length < prefix.length) return false;
41
33
  for (let i = 0; i < prefix.length; i++) {
@@ -46,16 +38,7 @@ function str_starts_with(str, prefix) {
46
38
  }
47
39
  return true;
48
40
  }
49
- /**
50
- * Case-insensitive character/substring search without allocations
51
- * Returns the index of the first occurrence of searchChar (case-insensitive)
52
- *
53
- * IMPORTANT: searchChar MUST be lowercase for correct comparison
54
- *
55
- * @param str - The string to search in
56
- * @param searchChar - The lowercase character/substring to find
57
- * @returns The index of the first match, or -1 if not found
58
- */
41
+ /** Case-insensitive substring search without allocations, or -1 if not found. `searchChar` MUST be lowercase. */
59
42
  function str_index_of(str, searchChar) {
60
43
  if (searchChar.length === 0) return -1;
61
44
  if (searchChar.length === 1) {
@@ -93,37 +76,12 @@ function is_vendor_prefixed(source, start, end) {
93
76
  for (let i = start + 2; i < end; i++) if (source.charCodeAt(i) === 45) return true;
94
77
  return false;
95
78
  }
96
- /**
97
- * Check if a string is a CSS custom property (starts with --)
98
- *
99
- * @param str - The string to check
100
- * @returns true if the string starts with -- (custom property)
101
- *
102
- * Examples:
103
- * - `--primary-color` → true
104
- * - `--my-var` → true
105
- * - `-webkit-transform` → false (vendor prefix, not custom)
106
- * - `border-radius` → false (standard property)
107
- * - `color` → false
108
- */
79
+ /** True if the string is a CSS custom property (starts with `--`). */
109
80
  function is_custom(str) {
110
81
  if (str.length < 3) return false;
111
82
  return str.charCodeAt(0) === 45 && str.charCodeAt(1) === 45;
112
83
  }
113
- /**
114
- * Strip vendor prefix from a string
115
- *
116
- * @param str - The string to strip vendor prefix from
117
- * @returns The string without vendor prefix, or original string if no prefix found
118
- *
119
- * Examples:
120
- * - `-webkit-keyframes` → `keyframes`
121
- * - `-moz-appearance` → `appearance`
122
- * - `-ms-filter` → `filter`
123
- * - `-o-border-image` → `border-image`
124
- * - `keyframes` → `keyframes` (no change)
125
- * - `--custom-property` → `--custom-property` (custom property, not vendor prefix)
126
- */
84
+ /** Strip a vendor prefix, e.g. `-webkit-keyframes` → `keyframes`. Returns the input unchanged if it has no prefix. */
127
85
  function strip_vendor_prefix(str) {
128
86
  if (!is_vendor_prefixed(str)) return str;
129
87
  for (let i = 2; i < str.length; i++) if (str.charCodeAt(i) === 45) return str.substring(i + 1);
@@ -131,18 +89,7 @@ function strip_vendor_prefix(str) {
131
89
  }
132
90
  //#endregion
133
91
  //#region src/parse-dimension.ts
134
- /**
135
- * Parse a dimension string into numeric value and unit
136
- *
137
- * @param text - Dimension text like "100px", "50%", "1.5em"
138
- * @returns Object with value (number) and unit (string)
139
- *
140
- * Examples:
141
- * - "100px" → { value: 100, unit: "px" }
142
- * - "50%" → { value: 50, unit: "%" }
143
- * - "1.5em" → { value: 1.5, unit: "em" }
144
- * - "-10rem" → { value: -10, unit: "rem" }
145
- */
92
+ /** Parse a dimension string into value and unit, e.g. "100px" → { value: 100, unit: "px" } or "2%" → { value: 2, unit: "%" } */
146
93
  function parse_dimension(text) {
147
94
  let num_end = 0;
148
95
  for (let i = 0; i < text.length; i++) {
@@ -1,16 +1,5 @@
1
1
  //#region src/parse-dimension.d.ts
2
- /**
3
- * Parse a dimension string into numeric value and unit
4
- *
5
- * @param text - Dimension text like "100px", "50%", "1.5em"
6
- * @returns Object with value (number) and unit (string)
7
- *
8
- * Examples:
9
- * - "100px" → { value: 100, unit: "px" }
10
- * - "50%" → { value: 50, unit: "%" }
11
- * - "1.5em" → { value: 1.5, unit: "em" }
12
- * - "-10rem" → { value: -10, unit: "rem" }
13
- */
2
+ /** Parse a dimension string into value and unit, e.g. "100px" → { value: 100, unit: "px" } or "2%" → { value: 2, unit: "%" } */
14
3
  declare function parse_dimension(text: string): {
15
4
  value: number;
16
5
  unit: string;
@@ -1,2 +1,2 @@
1
- import { t as parse_dimension } from "./parse-dimension-B0AZRxxt.js";
1
+ import { t as parse_dimension } from "./parse-dimension-ouWXNHdx.js";
2
2
  export { parse_dimension };
@@ -1,6 +1,5 @@
1
- import { l as CSSDataArena } from "./arena-DfpuGV9Y.js";
2
- import { F as Selector, I as SelectorList } from "./node-types-BrZu8T2C.js";
3
-
1
+ import { l as CSSDataArena } from "./arena-Bx5vp6Sl.js";
2
+ import { F as Selector, I as SelectorList } from "./node-types-BRnQyc9B.js";
4
3
  //#region src/parse-selector.d.ts
5
4
  /** @internal */
6
5
  declare class SelectorParser {
@@ -1,8 +1,8 @@
1
1
  import { t as Lexer } from "./tokenize-BiRLfVbm.js";
2
- import { l as CSSDataArena } from "./arena-CCye9VYE.js";
3
- import { a as is_whitespace, n as is_combinator, o as str_equals } from "./parse-dimension-B0AZRxxt.js";
4
- import { t as CSSNode } from "./css-node-TR2T5Q7D.js";
5
- import { n as skip_whitespace_and_comments_forward, r as skip_whitespace_forward, t as skip_whitespace_and_comments_backward } from "./parse-utils-BmXnziOy.js";
2
+ import { l as CSSDataArena } from "./arena-CFwM4uQs.js";
3
+ import { a as is_whitespace, n as is_combinator, o as str_equals } from "./parse-dimension-ouWXNHdx.js";
4
+ import { t as CSSNode } from "./css-node-B3EzCweR.js";
5
+ import { n as skip_whitespace_and_comments_forward, r as skip_whitespace_forward, t as skip_whitespace_and_comments_backward } from "./parse-utils-D7srNG13.js";
6
6
  import { ANplusBParser } from "./parse-anplusb.js";
7
7
  //#region src/parse-selector.ts
8
8
  /** @internal */
@@ -25,7 +25,8 @@ var SelectorParser = class {
25
25
  return this.parse_selector_list(allow_relative);
26
26
  }
27
27
  parse_selector_list(allow_relative = true) {
28
- let selectors = [];
28
+ let first_selector = 0;
29
+ let last_selector = 0;
29
30
  let list_start = this.lexer.pos;
30
31
  let list_line = this.lexer.line;
31
32
  let list_column = this.lexer.column;
@@ -38,14 +39,10 @@ var SelectorParser = class {
38
39
  let selector_wrapper = this.arena.create_node(5, selector_start, this.lexer.pos - selector_start, selector_line, selector_column);
39
40
  this.arena.set_content_start_delta(selector_wrapper, 0);
40
41
  this.arena.set_content_length(selector_wrapper, this.lexer.pos - selector_start);
41
- let last_component = complex_selector;
42
- let next_sibling = this.arena.get_next_sibling(last_component);
43
- while (next_sibling !== 0) {
44
- last_component = next_sibling;
45
- next_sibling = this.arena.get_next_sibling(last_component);
46
- }
47
42
  this.arena.set_first_child(selector_wrapper, complex_selector);
48
- selectors.push(selector_wrapper);
43
+ if (first_selector === 0) first_selector = selector_wrapper;
44
+ else this.arena.set_next_sibling(last_selector, selector_wrapper);
45
+ last_selector = selector_wrapper;
49
46
  }
50
47
  this.skip_whitespace();
51
48
  if (this.lexer.pos >= this.selector_end) break;
@@ -55,15 +52,16 @@ var SelectorParser = class {
55
52
  continue;
56
53
  } else break;
57
54
  }
58
- if (selectors.length > 0) {
55
+ if (first_selector !== 0) {
59
56
  let list_node = this.arena.create_node(20, list_start, this.lexer.pos - list_start, list_line, list_column);
60
- this.arena.append_children(list_node, selectors);
57
+ this.arena.set_first_child(list_node, first_selector);
61
58
  return list_node;
62
59
  }
63
60
  return null;
64
61
  }
65
62
  parse_complex_selector(allow_relative = true) {
66
- let components = [];
63
+ let first_component = 0;
64
+ let chain_tail = 0;
67
65
  this.skip_whitespace();
68
66
  if (allow_relative && this.lexer.pos < this.selector_end) {
69
67
  const saved = this.lexer.save_position();
@@ -72,7 +70,8 @@ var SelectorParser = class {
72
70
  let ch = this.source.charCodeAt(this.lexer.token_start);
73
71
  if (ch === 62 || ch === 43 || ch === 126) {
74
72
  let combinator = this.create_node_at(27, this.lexer.token_start, this.lexer.token_end, this.lexer.token_line, this.lexer.token_column);
75
- components.push(combinator);
73
+ first_component = combinator;
74
+ chain_tail = combinator;
76
75
  this.skip_whitespace();
77
76
  } else this.lexer.restore_position(saved);
78
77
  } else this.lexer.restore_position(saved);
@@ -80,10 +79,13 @@ var SelectorParser = class {
80
79
  while (this.lexer.pos < this.selector_end) {
81
80
  let compound = this.parse_compound_selector();
82
81
  if (compound === null) break;
83
- components.push(compound);
82
+ if (chain_tail === 0) first_component = compound;
83
+ else this.arena.set_next_sibling(chain_tail, compound);
84
+ chain_tail = this.arena.get_last_sibling(compound);
84
85
  let combinator = this.try_parse_combinator();
85
86
  if (combinator !== null) {
86
- components.push(combinator);
87
+ this.arena.set_next_sibling(chain_tail, combinator);
88
+ chain_tail = combinator;
87
89
  this.skip_whitespace();
88
90
  continue;
89
91
  }
@@ -101,16 +103,11 @@ var SelectorParser = class {
101
103
  this.lexer.restore_position(saved);
102
104
  break;
103
105
  }
104
- if (components.length === 0) return null;
105
- for (let i = 0; i < components.length - 1; i++) {
106
- let last_node = components[i];
107
- while (this.arena.get_next_sibling(last_node) !== 0) last_node = this.arena.get_next_sibling(last_node);
108
- this.arena.set_next_sibling(last_node, components[i + 1]);
109
- }
110
- return components[0];
106
+ return first_component === 0 ? null : first_component;
111
107
  }
112
108
  parse_compound_selector() {
113
- let parts = [];
109
+ let first_part = 0;
110
+ let last_part = 0;
114
111
  while (this.lexer.pos < this.selector_end) {
115
112
  const saved = this.lexer.save_position();
116
113
  this.lexer.next_token_fast(false);
@@ -121,11 +118,11 @@ var SelectorParser = class {
121
118
  this.lexer.restore_position(saved);
122
119
  break;
123
120
  }
124
- parts.push(part);
121
+ if (first_part === 0) first_part = part;
122
+ else this.arena.set_next_sibling(last_part, part);
123
+ last_part = part;
125
124
  }
126
- if (parts.length === 0) return null;
127
- for (let i = 0; i < parts.length - 1; i++) this.arena.set_next_sibling(parts[i], parts[i + 1]);
128
- return parts[0];
125
+ return first_part === 0 ? null : first_part;
129
126
  }
130
127
  parse_simple_selector() {
131
128
  let token_type = this.lexer.token_type;
@@ -1,27 +1,11 @@
1
- import { a as is_whitespace } from "./parse-dimension-B0AZRxxt.js";
1
+ import { a as is_whitespace } from "./parse-dimension-ouWXNHdx.js";
2
2
  //#region src/parse-utils.ts
3
- /**
4
- * Skip whitespace forward from a position
5
- *
6
- * @param source - The source string
7
- * @param pos - Starting position
8
- * @param end - End boundary (exclusive)
9
- * @returns New position after skipping whitespace
10
- * @internal
11
- */
3
+ /** @internal */
12
4
  function skip_whitespace_forward(source, pos, end) {
13
5
  while (pos < end && is_whitespace(source.charCodeAt(pos))) pos++;
14
6
  return pos;
15
7
  }
16
- /**
17
- * Skip whitespace and comments forward from a position
18
- *
19
- * @param source - The source string
20
- * @param pos - Starting position
21
- * @param end - End boundary (exclusive)
22
- * @returns New position after skipping whitespace/comments
23
- * @internal
24
- */
8
+ /** @internal */
25
9
  function skip_whitespace_and_comments_forward(source, pos, end) {
26
10
  while (pos < end) {
27
11
  let ch = source.charCodeAt(pos);
@@ -44,15 +28,7 @@ function skip_whitespace_and_comments_forward(source, pos, end) {
44
28
  }
45
29
  return pos;
46
30
  }
47
- /**
48
- * Skip whitespace and comments backward from a position
49
- *
50
- * @param source - The source string
51
- * @param pos - Starting position (exclusive, scanning backward from pos-1)
52
- * @param start - Start boundary (inclusive, won't go before this)
53
- * @returns New position after skipping whitespace/comments backward
54
- * @internal
55
- */
31
+ /** @internal */
56
32
  function skip_whitespace_and_comments_backward(source, pos, start) {
57
33
  while (pos > start) {
58
34
  let ch = source.charCodeAt(pos - 1);
@@ -76,17 +52,8 @@ function skip_whitespace_and_comments_backward(source, pos, start) {
76
52
  return pos;
77
53
  }
78
54
  /**
79
- * Trim whitespace and comments from both ends of a string range
80
- *
81
- * @param source - The source string
82
- * @param start - Start offset in source
83
- * @param end - End offset in source
84
- * @returns [trimmed_start, trimmed_end] or null if all whitespace/comments
55
+ * Trims whitespace and CSS comments from both ends; returns null if the range is only whitespace/comments.
85
56
  * @internal
86
- *
87
- * Skips whitespace (space, tab, newline, CR, FF) and CSS comments from both ends
88
- * of the specified range. Returns the trimmed boundaries or null if the range
89
- * contains only whitespace and comments.
90
57
  */
91
58
  function trim_boundaries(source, start, end) {
92
59
  start = skip_whitespace_and_comments_forward(source, start, end);