@projectwallace/css-parser 0.16.1 → 0.17.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,7 +1,7 @@
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, o as str_equals } from "./parse-dimension-B0AZRxxt.js";
4
- import { t as CSSNode } from "./css-node-CuLhABl8.js";
2
+ import { l as CSSDataArena } from "./arena-CFwM4uQs.js";
3
+ import { a as is_whitespace, o as str_equals } from "./parse-dimension-ouWXNHdx.js";
4
+ import { t as CSSNode } from "./css-node-B3EzCweR.js";
5
5
  //#region src/parse-value.ts
6
6
  /** @internal */
7
7
  var ValueParser = class {
@@ -18,26 +18,26 @@ var ValueParser = class {
18
18
  parse_value(start, end, start_line, start_column) {
19
19
  this.value_end = end;
20
20
  this.lexer.seek(start, start_line, start_column);
21
- let value_nodes = this.parse_value_tokens();
22
- if (value_nodes.length === 0) return this.arena.create_node(50, start, 0, start_line, start_column);
23
- let first_node_start = this.arena.get_start_offset(value_nodes[0]);
24
- let last_node_index = value_nodes.at(-1);
25
- let last_node_end = this.arena.get_start_offset(last_node_index) + this.arena.get_length(last_node_index);
26
- let value_node = this.arena.create_node(50, first_node_start, last_node_end - first_node_start, start_line, start_column);
27
- this.arena.append_children(value_node, value_nodes);
28
- return value_node;
29
- }
30
- parse_value_tokens() {
31
- let nodes = [];
21
+ let first_node = 0;
22
+ let last_node = 0;
32
23
  while (this.lexer.pos < this.value_end) {
33
24
  this.lexer.next_token_fast(false);
34
25
  if (this.lexer.token_start >= this.value_end) break;
35
26
  if (this.lexer.token_type === 26) break;
36
27
  if (this.is_whitespace_inline()) continue;
37
28
  let node = this.parse_value_node();
38
- if (node !== null) nodes.push(node);
29
+ if (node !== null) {
30
+ if (first_node === 0) first_node = node;
31
+ else this.arena.set_next_sibling(last_node, node);
32
+ last_node = node;
33
+ }
39
34
  }
40
- return nodes;
35
+ if (first_node === 0) return this.arena.create_node(50, start, 0, start_line, start_column);
36
+ let first_node_start = this.arena.get_start_offset(first_node);
37
+ let last_node_end = this.arena.get_start_offset(last_node) + this.arena.get_length(last_node);
38
+ let value_node = this.arena.create_node(50, first_node_start, last_node_end - first_node_start, start_line, start_column);
39
+ this.arena.set_first_child(value_node, first_node);
40
+ return value_node;
41
41
  }
42
42
  is_whitespace_inline() {
43
43
  if (this.lexer.token_start >= this.lexer.token_end) return false;
@@ -113,7 +113,8 @@ var ValueParser = class {
113
113
  return node;
114
114
  }
115
115
  }
116
- let args = [];
116
+ let first_arg = 0;
117
+ let last_arg = 0;
117
118
  let paren_depth = 1;
118
119
  let func_end = end;
119
120
  let content_start = end;
@@ -133,17 +134,22 @@ var ValueParser = class {
133
134
  }
134
135
  if (this.is_whitespace_inline()) continue;
135
136
  let arg_node = this.parse_value_node();
136
- if (arg_node !== null) args.push(arg_node);
137
+ if (arg_node !== null) {
138
+ if (first_arg === 0) first_arg = arg_node;
139
+ else this.arena.set_next_sibling(last_arg, arg_node);
140
+ last_arg = arg_node;
141
+ }
137
142
  }
138
143
  this.arena.set_length(node, func_end - start);
139
144
  this.arena.set_value_start_delta(node, content_start - start);
140
145
  this.arena.set_value_length(node, content_end - content_start);
141
- this.arena.append_children(node, args);
146
+ if (first_arg !== 0) this.arena.set_first_child(node, first_arg);
142
147
  return node;
143
148
  }
144
149
  parse_parenthesis_node(start, end) {
145
150
  let node = this.arena.create_node(17, start, 0, this.lexer.token_line, this.lexer.token_column);
146
- let children = [];
151
+ let first_child = 0;
152
+ let last_child = 0;
147
153
  let paren_depth = 1;
148
154
  let paren_end = end;
149
155
  while (this.lexer.pos < this.value_end && paren_depth > 0) {
@@ -160,10 +166,14 @@ var ValueParser = class {
160
166
  }
161
167
  if (this.is_whitespace_inline()) continue;
162
168
  let child_node = this.parse_value_node();
163
- if (child_node !== null) children.push(child_node);
169
+ if (child_node !== null) {
170
+ if (first_child === 0) first_child = child_node;
171
+ else this.arena.set_next_sibling(last_child, child_node);
172
+ last_child = child_node;
173
+ }
164
174
  }
165
175
  this.arena.set_length(node, paren_end - start);
166
- this.arena.append_children(node, children);
176
+ if (first_child !== 0) this.arena.set_first_child(node, first_child);
167
177
  return node;
168
178
  }
169
179
  };
package/dist/parse.d.ts CHANGED
@@ -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 { t as CommentInfo } from "./tokenize-DeZYFa9R.js";
3
- import { z as StyleSheet } from "./node-types-BrZu8T2C.js";
4
-
3
+ import { z as StyleSheet } from "./node-types-BRnQyc9B.js";
5
4
  //#region src/parse.d.ts
6
5
  interface ParserOptions {
7
6
  parse_values?: boolean;
package/dist/parse.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { t as Lexer } from "./tokenize-BiRLfVbm.js";
2
- import { l as CSSDataArena } from "./arena-CCye9VYE.js";
3
- import { t as CSSNode } from "./css-node-CuLhABl8.js";
4
- import { i as trim_boundaries } from "./parse-utils-BmXnziOy.js";
2
+ import { l as CSSDataArena } from "./arena-CFwM4uQs.js";
3
+ import { t as CSSNode } from "./css-node-B3EzCweR.js";
4
+ import { i as trim_boundaries } from "./parse-utils-D7srNG13.js";
5
5
  import { SelectorParser } from "./parse-selector.js";
6
6
  import { AtRulePreludeParser } from "./parse-atrule-prelude.js";
7
7
  import { DeclarationParser } from "./parse-declaration.js";
@@ -59,13 +59,18 @@ var Parser = class {
59
59
  parse() {
60
60
  this.next_token();
61
61
  let stylesheet = this.arena.create_node(1, 0, this.source.length, 1, 1);
62
- let rules = [];
62
+ let first_rule = 0;
63
+ let last_rule = 0;
63
64
  while (!this.is_eof()) {
64
65
  let rule = this.parse_rule();
65
66
  if (rule === null) this.next_token();
66
- else rules.push(rule);
67
+ else {
68
+ if (first_rule === 0) first_rule = rule;
69
+ else this.arena.set_next_sibling(last_rule, rule);
70
+ last_rule = rule;
71
+ }
67
72
  }
68
- this.arena.append_children(stylesheet, rules);
73
+ if (first_rule !== 0) this.arena.set_first_child(stylesheet, first_rule);
69
74
  this.arena.trim();
70
75
  return new CSSNode(this.arena, this.source, stylesheet);
71
76
  }
@@ -88,25 +93,27 @@ var Parser = class {
88
93
  let block_line = this.lexer.token_line;
89
94
  let block_column = this.lexer.token_column;
90
95
  let block_node = this.arena.create_node(7, block_start, 0, block_line, block_column);
91
- let block_children = [];
96
+ let first_child = 0;
97
+ let last_child = 0;
92
98
  while (!this.is_eof()) {
93
99
  let token_type = this.peek_type();
94
100
  if (token_type === 24) break;
101
+ let child = null;
95
102
  if (token_type === 3) {
96
- let nested_at_rule = this.parse_atrule();
97
- if (nested_at_rule === null) this.next_token();
98
- else block_children.push(nested_at_rule);
99
- continue;
103
+ child = this.parse_atrule();
104
+ if (child === null) this.next_token();
105
+ } else {
106
+ child = this.parse_declaration();
107
+ if (child === null) {
108
+ child = this.parse_style_rule();
109
+ if (child === null) this.next_token();
110
+ } else this.arena.set_flag(style_rule, 32);
100
111
  }
101
- let declaration = this.parse_declaration();
102
- if (declaration !== null) {
103
- this.arena.set_flag(style_rule, 32);
104
- block_children.push(declaration);
105
- continue;
112
+ if (child !== null) {
113
+ if (first_child === 0) first_child = child;
114
+ else this.arena.set_next_sibling(last_child, child);
115
+ last_child = child;
106
116
  }
107
- let nested_rule = this.parse_style_rule();
108
- if (nested_rule === null) this.next_token();
109
- else block_children.push(nested_rule);
110
117
  }
111
118
  let block_end = this.lexer.token_start;
112
119
  let rule_end = this.lexer.token_end;
@@ -116,12 +123,13 @@ var Parser = class {
116
123
  this.next_token();
117
124
  }
118
125
  this.arena.set_length(block_node, block_end - block_start);
119
- this.arena.append_children(block_node, block_children);
126
+ if (first_child !== 0) this.arena.set_first_child(block_node, first_child);
120
127
  this.arena.set_length(style_rule, rule_end - rule_start);
121
- let style_rule_children = [];
122
- if (selector !== null) style_rule_children.push(selector);
123
- style_rule_children.push(block_node);
124
- this.arena.append_children(style_rule, style_rule_children);
128
+ if (selector === null) this.arena.set_first_child(style_rule, block_node);
129
+ else {
130
+ this.arena.set_first_child(style_rule, selector);
131
+ this.arena.set_next_sibling(selector, block_node);
132
+ }
125
133
  return style_rule;
126
134
  }
127
135
  parse_selector() {
@@ -193,30 +201,37 @@ var Parser = class {
193
201
  let block_column = this.lexer.token_column;
194
202
  let block_node = this.arena.create_node(7, block_start, 0, block_line, block_column);
195
203
  let has_declarations = this.atrule_has_declarations(at_rule_name);
196
- let block_children = [];
204
+ let first_child = 0;
205
+ let last_child = 0;
197
206
  if (has_declarations) while (!this.is_eof()) {
198
207
  if (this.peek_type() === 24) break;
199
208
  let declaration = this.parse_declaration();
200
209
  if (declaration === null) this.next_token();
201
- else block_children.push(declaration);
210
+ else {
211
+ if (first_child === 0) first_child = declaration;
212
+ else this.arena.set_next_sibling(last_child, declaration);
213
+ last_child = declaration;
214
+ }
202
215
  }
203
216
  else while (!this.is_eof()) {
204
217
  let token_type = this.peek_type();
205
218
  if (token_type === 24) break;
219
+ let child = null;
206
220
  if (token_type === 3) {
207
- let nested_at_rule = this.parse_atrule();
208
- if (nested_at_rule === null) this.next_token();
209
- else block_children.push(nested_at_rule);
210
- continue;
221
+ child = this.parse_atrule();
222
+ if (child === null) this.next_token();
223
+ } else {
224
+ child = this.parse_declaration();
225
+ if (child === null) {
226
+ child = this.parse_style_rule();
227
+ if (child === null) this.next_token();
228
+ }
211
229
  }
212
- let declaration = this.parse_declaration();
213
- if (declaration !== null) {
214
- block_children.push(declaration);
215
- continue;
230
+ if (child !== null) {
231
+ if (first_child === 0) first_child = child;
232
+ else this.arena.set_next_sibling(last_child, child);
233
+ last_child = child;
216
234
  }
217
- let nested_rule = this.parse_style_rule();
218
- if (nested_rule === null) this.next_token();
219
- else block_children.push(nested_rule);
220
235
  }
221
236
  if (this.peek_type() === 24) {
222
237
  let block_end = this.lexer.token_start;
@@ -224,19 +239,20 @@ var Parser = class {
224
239
  this.next_token();
225
240
  this.arena.set_length(block_node, block_end - block_start);
226
241
  } else this.arena.set_length(block_node, last_end - block_start);
227
- this.arena.append_children(block_node, block_children);
228
- let at_rule_children = [];
229
- if (prelude_wrapper !== null) at_rule_children.push(prelude_wrapper);
230
- at_rule_children.push(block_node);
242
+ if (first_child !== 0) this.arena.set_first_child(block_node, first_child);
231
243
  this.arena.set_length(at_rule, last_end - at_rule_start);
232
- this.arena.append_children(at_rule, at_rule_children);
244
+ if (prelude_wrapper === null) this.arena.set_first_child(at_rule, block_node);
245
+ else {
246
+ this.arena.set_first_child(at_rule, prelude_wrapper);
247
+ this.arena.set_next_sibling(prelude_wrapper, block_node);
248
+ }
233
249
  } else {
234
250
  if (this.peek_type() === 17) {
235
251
  last_end = this.lexer.token_end;
236
252
  this.next_token();
237
253
  }
238
254
  this.arena.set_length(at_rule, last_end - at_rule_start);
239
- if (prelude_wrapper !== null) this.arena.append_children(at_rule, [prelude_wrapper]);
255
+ if (prelude_wrapper !== null) this.arena.set_first_child(at_rule, prelude_wrapper);
240
256
  }
241
257
  return at_rule;
242
258
  }
package/dist/walk.d.ts CHANGED
@@ -1,17 +1,12 @@
1
- import { o as CSSNode, t as AnyNode } from "./node-types-BrZu8T2C.js";
2
-
1
+ import { o as CSSNode, t as AnyNode } from "./node-types-BRnQyc9B.js";
3
2
  //#region src/walk.d.ts
4
3
  declare const SKIP: unique symbol;
5
4
  declare const BREAK: unique symbol;
6
5
  type WalkCallback = (node: AnyNode, depth: number) => void | typeof SKIP | typeof BREAK;
7
6
  /**
8
- * Walk the AST in depth-first order, calling the callback for each node.
9
- * Return SKIP to skip children, BREAK to stop traversal. See API.md for examples.
10
- *
11
- * @param node - The root node to start walking from
12
- * @param callback - Function called for each node. Receives the node and its nesting depth.
13
- * Depth increments only for STYLE_RULE and AT_RULE nodes (tracks rule nesting, not tree depth).
14
- * @param depth - Starting depth (default: 0)
7
+ * Walk the AST depth-first, calling `callback` for each node. Return SKIP to skip
8
+ * children, BREAK to stop. `depth` tracks rule nesting (STYLE_RULE/AT_RULE only),
9
+ * not tree depth.
15
10
  */
16
11
  declare function walk(node: CSSNode, callback: WalkCallback, depth?: number): boolean;
17
12
  type WalkEnterLeaveCallback = (node: AnyNode) => void | typeof SKIP | typeof BREAK;
@@ -20,15 +15,9 @@ interface WalkEnterLeaveOptions {
20
15
  leave?: WalkEnterLeaveCallback;
21
16
  }
22
17
  /**
23
- * Walk the AST in depth-first order, calling enter before visiting children and leave after.
24
- * Return SKIP in enter to skip children (leave still called), BREAK to stop (leave NOT called). See API.md for examples.
25
- *
26
- * @param node - The root node to start walking from
27
- * @param options - Object with optional enter and leave callback functions
18
+ * Walk the AST depth-first, calling `enter` before children and `leave` after.
19
+ * SKIP in enter skips children (leave still runs); BREAK stops (leave doesn't run).
28
20
  */
29
- declare function traverse(node: CSSNode, {
30
- enter,
31
- leave
32
- }?: WalkEnterLeaveOptions): boolean;
21
+ declare function traverse(node: CSSNode, { enter, leave }?: WalkEnterLeaveOptions): boolean;
33
22
  //#endregion
34
23
  export { BREAK, SKIP, traverse, walk };
package/dist/walk.js CHANGED
@@ -1,17 +1,13 @@
1
- import "./arena-CCye9VYE.js";
2
- import { t as CSSNode } from "./css-node-CuLhABl8.js";
1
+ import "./arena-CFwM4uQs.js";
2
+ import { t as CSSNode } from "./css-node-B3EzCweR.js";
3
3
  import "./constants.js";
4
4
  //#region src/walk.ts
5
5
  const SKIP = Symbol("SKIP");
6
6
  const BREAK = Symbol("BREAK");
7
7
  /**
8
- * Walk the AST in depth-first order, calling the callback for each node.
9
- * Return SKIP to skip children, BREAK to stop traversal. See API.md for examples.
10
- *
11
- * @param node - The root node to start walking from
12
- * @param callback - Function called for each node. Receives the node and its nesting depth.
13
- * Depth increments only for STYLE_RULE and AT_RULE nodes (tracks rule nesting, not tree depth).
14
- * @param depth - Starting depth (default: 0)
8
+ * Walk the AST depth-first, calling `callback` for each node. Return SKIP to skip
9
+ * children, BREAK to stop. `depth` tracks rule nesting (STYLE_RULE/AT_RULE only),
10
+ * not tree depth.
15
11
  */
16
12
  function walk(node, callback, depth = 0) {
17
13
  const result = callback(node, depth);
@@ -45,11 +41,8 @@ function _walk(arena, source, index, callback, depth) {
45
41
  }
46
42
  const NOOP = function() {};
47
43
  /**
48
- * Walk the AST in depth-first order, calling enter before visiting children and leave after.
49
- * Return SKIP in enter to skip children (leave still called), BREAK to stop (leave NOT called). See API.md for examples.
50
- *
51
- * @param node - The root node to start walking from
52
- * @param options - Object with optional enter and leave callback functions
44
+ * Walk the AST depth-first, calling `enter` before children and `leave` after.
45
+ * SKIP in enter skips children (leave still runs); BREAK stops (leave doesn't run).
53
46
  */
54
47
  function traverse(node, { enter = NOOP, leave = NOOP } = {}) {
55
48
  const enter_result = enter(node);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@projectwallace/css-parser",
3
- "version": "0.16.1",
3
+ "version": "0.17.0",
4
4
  "description": "High-performance CSS lexer and parser, optimized for CSS inspection and analysis",
5
5
  "keywords": [
6
6
  "ast",
@@ -20,6 +20,7 @@
20
20
  "dist"
21
21
  ],
22
22
  "type": "module",
23
+ "sideEffects": false,
23
24
  "main": "./dist/index.js",
24
25
  "module": "./dist/index.js",
25
26
  "types": "./dist/index.d.ts",
@@ -75,20 +76,20 @@
75
76
  "provenance": true
76
77
  },
77
78
  "devDependencies": {
78
- "@projectwallace/preset-oxlint": "^0.0.10",
79
- "@types/node": "^24.10.1",
79
+ "@projectwallace/preset-oxlint": "^0.0.11",
80
+ "@types/node": "^26.1.1",
80
81
  "@vitest/coverage-v8": "^4.1.9",
81
82
  "bootstrap": "^5.3.8",
82
83
  "css-tree": "^3.1.0",
83
84
  "knip": "^6.18.0",
84
- "oxfmt": "^0.56.0",
85
+ "oxfmt": "^0.59.0",
85
86
  "oxlint": "^1.71.0",
86
87
  "postcss": "^8.5.15",
87
88
  "publint": "^0.3.21",
88
89
  "tailwindcss": "^2.2.8",
89
90
  "tinybench": "^6.0.2",
90
91
  "tsdown": "^0.22.3",
91
- "typescript": "^6.0.3",
92
+ "typescript": "^7.0.2",
92
93
  "vite": "^8.0.16",
93
94
  "vitest": "^4.1.9"
94
95
  },
@@ -105,6 +106,6 @@
105
106
  "lint": "oxlint --config .oxlintrc.json && oxfmt --check",
106
107
  "check": "tsc --noEmit",
107
108
  "knip": "knip",
108
- "precommit": "pnpm run test -- --run; pnpm run lint; pnpm run check"
109
+ "precommit": "pnpm run test --run; pnpm run lint; pnpm run check"
109
110
  }
110
111
  }