@projectwallace/css-parser 0.1.0 → 0.2.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/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # CSS Parser
2
2
 
3
+ > [!WARNING]
4
+ > This is a very experimental CSS parser. Expect several bugs and inconveniences!
5
+
3
6
  **High-performance CSS parser optimized for static analysis and formatting**
4
7
 
5
8
  Built for speed and efficiency, this parser handles large CSS files with minimal memory overhead and blazing-fast parse times. Designed with a data-oriented architecture using a single contiguous memory arena for zero allocations during parsing.
package/dist/arena.d.ts CHANGED
@@ -59,6 +59,7 @@ export declare class CSSDataArena {
59
59
  get_last_child(node_index: number): number;
60
60
  get_next_sibling(node_index: number): number;
61
61
  get_start_line(node_index: number): number;
62
+ get_start_column(node_index: number): number;
62
63
  get_value_start(node_index: number): number;
63
64
  get_value_length(node_index: number): number;
64
65
  set_type(node_index: number, type: number): void;
@@ -71,6 +72,7 @@ export declare class CSSDataArena {
71
72
  set_last_child(node_index: number, childIndex: number): void;
72
73
  set_next_sibling(node_index: number, siblingIndex: number): void;
73
74
  set_start_line(node_index: number, line: number): void;
75
+ set_start_column(node_index: number, column: number): void;
74
76
  set_value_start(node_index: number, offset: number): void;
75
77
  set_value_length(node_index: number, length: number): void;
76
78
  private grow;
@@ -1,5 +1,5 @@
1
1
  import { L as Lexer, q as TOKEN_COMMA, T as TOKEN_IDENT, t as TOKEN_LEFT_PAREN, u as TOKEN_RIGHT_PAREN, l as TOKEN_WHITESPACE, f as TOKEN_URL, a as TOKEN_FUNCTION, d as TOKEN_STRING, y as TOKEN_EOF } from './lexer-DXablYMZ.js';
2
- import { O as str_equals, E as NODE_PRELUDE_OPERATOR, y as NODE_PRELUDE_MEDIA_TYPE, w as NODE_PRELUDE_MEDIA_QUERY, x as NODE_PRELUDE_MEDIA_FEATURE, M as trim_boundaries, D as NODE_PRELUDE_IDENTIFIER, z as NODE_PRELUDE_CONTAINER_QUERY, A as NODE_PRELUDE_SUPPORTS_QUERY, B as NODE_PRELUDE_LAYER_NAME, F as NODE_PRELUDE_IMPORT_URL, G as NODE_PRELUDE_IMPORT_LAYER, H as NODE_PRELUDE_IMPORT_SUPPORTS, P as CHAR_SPACE, Q as CHAR_TAB, R as CHAR_NEWLINE, S as CHAR_CARRIAGE_RETURN, T as CHAR_FORM_FEED } from './string-utils-B-rJII-E.js';
2
+ import { O as str_equals, E as NODE_PRELUDE_OPERATOR, y as NODE_PRELUDE_MEDIA_TYPE, w as NODE_PRELUDE_MEDIA_QUERY, x as NODE_PRELUDE_MEDIA_FEATURE, M as trim_boundaries, D as NODE_PRELUDE_IDENTIFIER, z as NODE_PRELUDE_CONTAINER_QUERY, A as NODE_PRELUDE_SUPPORTS_QUERY, B as NODE_PRELUDE_LAYER_NAME, F as NODE_PRELUDE_IMPORT_URL, G as NODE_PRELUDE_IMPORT_LAYER, H as NODE_PRELUDE_IMPORT_SUPPORTS, P as CHAR_SPACE, Q as CHAR_TAB, R as CHAR_NEWLINE, S as CHAR_CARRIAGE_RETURN, T as CHAR_FORM_FEED } from './string-utils-Bm2l6p1L.js';
3
3
 
4
4
  class AtRulePreludeParser {
5
5
  lexer;
@@ -13,10 +13,11 @@ class AtRulePreludeParser {
13
13
  this.prelude_end = 0;
14
14
  }
15
15
  // Parse an at-rule prelude into nodes based on the at-rule type
16
- parse_prelude(at_rule_name, start, end, line = 1) {
16
+ parse_prelude(at_rule_name, start, end, line = 1, column = 1) {
17
17
  this.prelude_end = end;
18
18
  this.lexer.pos = start;
19
19
  this.lexer.line = line;
20
+ this.lexer.column = column;
20
21
  if (str_equals("media", at_rule_name)) {
21
22
  return this.parse_media_query_list();
22
23
  } else if (str_equals("container", at_rule_name)) {
@@ -59,6 +60,7 @@ class AtRulePreludeParser {
59
60
  parse_single_media_query() {
60
61
  let query_start = this.lexer.pos;
61
62
  let query_line = this.lexer.line;
63
+ this.lexer.column;
62
64
  this.skip_whitespace();
63
65
  if (this.lexer.pos >= this.prelude_end) return null;
64
66
  let token_start = this.lexer.pos;
@@ -98,6 +100,7 @@ class AtRulePreludeParser {
98
100
  this.arena.set_start_offset(media_type, this.lexer.token_start);
99
101
  this.arena.set_length(media_type, this.lexer.token_end - this.lexer.token_start);
100
102
  this.arena.set_start_line(media_type, this.lexer.token_line);
103
+ this.arena.set_start_column(media_type, this.lexer.token_column);
101
104
  components.push(media_type);
102
105
  }
103
106
  } else {
@@ -5,7 +5,7 @@ export declare class AtRulePreludeParser {
5
5
  private source;
6
6
  private prelude_end;
7
7
  constructor(arena: CSSDataArena, source: string);
8
- parse_prelude(at_rule_name: string, start: number, end: number, line?: number): number[];
8
+ parse_prelude(at_rule_name: string, start: number, end: number, line?: number, column?: number): number[];
9
9
  private parse_media_query_list;
10
10
  private is_and_or_not;
11
11
  private parse_single_media_query;
@@ -21,6 +21,7 @@ export declare class CSSNode {
21
21
  get values(): CSSNode[];
22
22
  get value_count(): number;
23
23
  get line(): number;
24
+ get column(): number;
24
25
  get offset(): number;
25
26
  get length(): number;
26
27
  get first_child(): CSSNode | null;
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ export { parse } from './parse.js';
2
2
  export { parse_selector } from './parse-selector.js';
3
3
  export { parse_atrule_prelude } from './parse-atrule-prelude.js';
4
4
  export { tokenize } from './tokenize.js';
5
- export { C as CSSNode, I as FLAG_IMPORTANT, a as NODE_AT_RULE, b as NODE_COMMENT, c as NODE_DECLARATION, z as NODE_PRELUDE_CONTAINER_QUERY, D as NODE_PRELUDE_IDENTIFIER, G as NODE_PRELUDE_IMPORT_LAYER, H as NODE_PRELUDE_IMPORT_SUPPORTS, F as NODE_PRELUDE_IMPORT_URL, B as NODE_PRELUDE_LAYER_NAME, x as NODE_PRELUDE_MEDIA_FEATURE, w as NODE_PRELUDE_MEDIA_QUERY, y as NODE_PRELUDE_MEDIA_TYPE, E as NODE_PRELUDE_OPERATOR, A as NODE_PRELUDE_SUPPORTS_QUERY, d as NODE_SELECTOR, q as NODE_SELECTOR_ATTRIBUTE, o as NODE_SELECTOR_CLASS, t as NODE_SELECTOR_COMBINATOR, p as NODE_SELECTOR_ID, m as NODE_SELECTOR_LIST, v as NODE_SELECTOR_NESTING, r as NODE_SELECTOR_PSEUDO_CLASS, s as NODE_SELECTOR_PSEUDO_ELEMENT, n as NODE_SELECTOR_TYPE, u as NODE_SELECTOR_UNIVERSAL, e as NODE_STYLESHEET, N as NODE_STYLE_RULE, j as NODE_VALUE_COLOR, h as NODE_VALUE_DIMENSION, k as NODE_VALUE_FUNCTION, f as NODE_VALUE_KEYWORD, g as NODE_VALUE_NUMBER, l as NODE_VALUE_OPERATOR, i as NODE_VALUE_STRING } from './string-utils-B-rJII-E.js';
5
+ export { C as CSSNode, I as FLAG_IMPORTANT, a as NODE_AT_RULE, b as NODE_COMMENT, c as NODE_DECLARATION, z as NODE_PRELUDE_CONTAINER_QUERY, D as NODE_PRELUDE_IDENTIFIER, G as NODE_PRELUDE_IMPORT_LAYER, H as NODE_PRELUDE_IMPORT_SUPPORTS, F as NODE_PRELUDE_IMPORT_URL, B as NODE_PRELUDE_LAYER_NAME, x as NODE_PRELUDE_MEDIA_FEATURE, w as NODE_PRELUDE_MEDIA_QUERY, y as NODE_PRELUDE_MEDIA_TYPE, E as NODE_PRELUDE_OPERATOR, A as NODE_PRELUDE_SUPPORTS_QUERY, d as NODE_SELECTOR, q as NODE_SELECTOR_ATTRIBUTE, o as NODE_SELECTOR_CLASS, t as NODE_SELECTOR_COMBINATOR, p as NODE_SELECTOR_ID, m as NODE_SELECTOR_LIST, v as NODE_SELECTOR_NESTING, r as NODE_SELECTOR_PSEUDO_CLASS, s as NODE_SELECTOR_PSEUDO_ELEMENT, n as NODE_SELECTOR_TYPE, u as NODE_SELECTOR_UNIVERSAL, e as NODE_STYLESHEET, N as NODE_STYLE_RULE, j as NODE_VALUE_COLOR, h as NODE_VALUE_DIMENSION, k as NODE_VALUE_FUNCTION, f as NODE_VALUE_KEYWORD, g as NODE_VALUE_NUMBER, l as NODE_VALUE_OPERATOR, i as NODE_VALUE_STRING } from './string-utils-Bm2l6p1L.js';
6
6
  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-DXablYMZ.js';
7
7
 
8
8
  function walk(node, callback, depth = 0) {
@@ -1,5 +1,5 @@
1
- import { K as CSSDataArena, C as CSSNode } from './string-utils-B-rJII-E.js';
2
- import { A as AtRulePreludeParser } from './at-rule-prelude-parser-DlqYQAYH.js';
1
+ import { K as CSSDataArena, C as CSSNode } from './string-utils-Bm2l6p1L.js';
2
+ import { A as AtRulePreludeParser } from './at-rule-prelude-parser-7_qZ1z7t.js';
3
3
 
4
4
  function parse_atrule_prelude(at_rule_name, prelude) {
5
5
  const arena = new CSSDataArena(CSSDataArena.capacity_for_source(prelude.length));
@@ -1,5 +1,5 @@
1
- import { K as CSSDataArena, d as NODE_SELECTOR, C as CSSNode } from './string-utils-B-rJII-E.js';
2
- import { S as SelectorParser } from './selector-parser-2b3tGyri.js';
1
+ import { K as CSSDataArena, d as NODE_SELECTOR, C as CSSNode } from './string-utils-Bm2l6p1L.js';
2
+ import { S as SelectorParser } from './selector-parser-BjdQlGvW.js';
3
3
 
4
4
  function parse_selector(source) {
5
5
  const arena = new CSSDataArena(CSSDataArena.capacity_for_source(source.length));
package/dist/parse.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { L as Lexer, y as TOKEN_EOF, q as TOKEN_COMMA, h as TOKEN_DELIM, a as TOKEN_FUNCTION, c as TOKEN_HASH, d as TOKEN_STRING, k as TOKEN_DIMENSION, j as TOKEN_PERCENTAGE, i as TOKEN_NUMBER, T as TOKEN_IDENT, t as TOKEN_LEFT_PAREN, u as TOKEN_RIGHT_PAREN, b as TOKEN_AT_KEYWORD, v as TOKEN_LEFT_BRACE, w as TOKEN_RIGHT_BRACE, o as TOKEN_COLON, p as TOKEN_SEMICOLON } from './lexer-DXablYMZ.js';
2
- import { J as is_whitespace, f as NODE_VALUE_KEYWORD, g as NODE_VALUE_NUMBER, h as NODE_VALUE_DIMENSION, i as NODE_VALUE_STRING, j as NODE_VALUE_COLOR, l as NODE_VALUE_OPERATOR, k as NODE_VALUE_FUNCTION, K as CSSDataArena, e as NODE_STYLESHEET, C as CSSNode, N as NODE_STYLE_RULE, L as FLAG_HAS_BLOCK, d as NODE_SELECTOR, c as NODE_DECLARATION, M as trim_boundaries, I as FLAG_IMPORTANT, a as NODE_AT_RULE } from './string-utils-B-rJII-E.js';
3
- import { S as SelectorParser } from './selector-parser-2b3tGyri.js';
4
- import { A as AtRulePreludeParser } from './at-rule-prelude-parser-DlqYQAYH.js';
2
+ import { J as is_whitespace, f as NODE_VALUE_KEYWORD, g as NODE_VALUE_NUMBER, h as NODE_VALUE_DIMENSION, i as NODE_VALUE_STRING, j as NODE_VALUE_COLOR, l as NODE_VALUE_OPERATOR, k as NODE_VALUE_FUNCTION, K as CSSDataArena, e as NODE_STYLESHEET, C as CSSNode, N as NODE_STYLE_RULE, L as FLAG_HAS_BLOCK, d as NODE_SELECTOR, c as NODE_DECLARATION, M as trim_boundaries, I as FLAG_IMPORTANT, a as NODE_AT_RULE } from './string-utils-Bm2l6p1L.js';
3
+ import { S as SelectorParser } from './selector-parser-BjdQlGvW.js';
4
+ import { A as AtRulePreludeParser } from './at-rule-prelude-parser-7_qZ1z7t.js';
5
5
 
6
6
  const CH_PLUS = 43;
7
7
  const CH_MINUS = 45;
@@ -240,6 +240,7 @@ class Parser {
240
240
  this.arena.set_start_offset(stylesheet, 0);
241
241
  this.arena.set_length(stylesheet, this.source.length);
242
242
  this.arena.set_start_line(stylesheet, 1);
243
+ this.arena.set_start_column(stylesheet, 1);
243
244
  while (!this.is_eof()) {
244
245
  let rule = this.parse_rule();
245
246
  if (rule !== null) {
@@ -265,9 +266,11 @@ class Parser {
265
266
  if (this.is_eof()) return null;
266
267
  let rule_start = this.lexer.token_start;
267
268
  let rule_line = this.lexer.token_line;
269
+ let rule_column = this.lexer.token_column;
268
270
  let style_rule = this.arena.create_node();
269
271
  this.arena.set_type(style_rule, NODE_STYLE_RULE);
270
272
  this.arena.set_start_line(style_rule, rule_line);
273
+ this.arena.set_start_column(style_rule, rule_column);
271
274
  let selector = this.parse_selector();
272
275
  if (selector !== null) {
273
276
  this.arena.append_child(style_rule, selector);
@@ -313,13 +316,14 @@ class Parser {
313
316
  if (this.is_eof()) return null;
314
317
  let selector_start = this.lexer.token_start;
315
318
  let selector_line = this.lexer.token_line;
319
+ let selector_column = this.lexer.token_column;
316
320
  let last_end = this.lexer.token_end;
317
321
  while (!this.is_eof() && this.peek_type() !== TOKEN_LEFT_BRACE) {
318
322
  last_end = this.lexer.token_end;
319
323
  this.next_token();
320
324
  }
321
325
  if (this.parse_selectors_enabled && this.selector_parser) {
322
- let selectorNode = this.selector_parser.parse_selector(selector_start, last_end, selector_line);
326
+ let selectorNode = this.selector_parser.parse_selector(selector_start, last_end, selector_line, selector_column);
323
327
  if (selectorNode !== null) {
324
328
  return selectorNode;
325
329
  }
@@ -327,6 +331,7 @@ class Parser {
327
331
  let selector = this.arena.create_node();
328
332
  this.arena.set_type(selector, NODE_SELECTOR);
329
333
  this.arena.set_start_line(selector, selector_line);
334
+ this.arena.set_start_column(selector, selector_column);
330
335
  this.arena.set_start_offset(selector, selector_start);
331
336
  this.arena.set_length(selector, last_end - selector_start);
332
337
  return selector;
@@ -339,6 +344,7 @@ class Parser {
339
344
  let prop_start = this.lexer.token_start;
340
345
  let prop_end = this.lexer.token_end;
341
346
  let decl_line = this.lexer.token_line;
347
+ let decl_column = this.lexer.token_column;
342
348
  this.next_token();
343
349
  if (this.peek_type() !== TOKEN_COLON) {
344
350
  return null;
@@ -347,6 +353,7 @@ class Parser {
347
353
  let declaration = this.arena.create_node();
348
354
  this.arena.set_type(declaration, NODE_DECLARATION);
349
355
  this.arena.set_start_line(declaration, decl_line);
356
+ this.arena.set_start_column(declaration, decl_column);
350
357
  this.arena.set_start_offset(declaration, prop_start);
351
358
  this.arena.set_content_start(declaration, prop_start);
352
359
  this.arena.set_content_length(declaration, prop_end - prop_start);
@@ -402,6 +409,7 @@ class Parser {
402
409
  }
403
410
  let at_rule_start = this.lexer.token_start;
404
411
  let at_rule_line = this.lexer.token_line;
412
+ let at_rule_column = this.lexer.token_column;
405
413
  let at_rule_name = this.source.substring(this.lexer.token_start + 1, this.lexer.token_end);
406
414
  let name_start = this.lexer.token_start + 1;
407
415
  let name_length = at_rule_name.length;
@@ -409,6 +417,7 @@ class Parser {
409
417
  let at_rule = this.arena.create_node();
410
418
  this.arena.set_type(at_rule, NODE_AT_RULE);
411
419
  this.arena.set_start_line(at_rule, at_rule_line);
420
+ this.arena.set_start_column(at_rule, at_rule_column);
412
421
  this.arena.set_start_offset(at_rule, at_rule_start);
413
422
  this.arena.set_content_start(at_rule, name_start);
414
423
  this.arena.set_content_length(at_rule, name_length);
@@ -423,7 +432,7 @@ class Parser {
423
432
  this.arena.set_value_start(at_rule, trimmed[0]);
424
433
  this.arena.set_value_length(at_rule, trimmed[1] - trimmed[0]);
425
434
  if (this.prelude_parser) {
426
- let prelude_nodes = this.prelude_parser.parse_prelude(at_rule_name, trimmed[0], trimmed[1], at_rule_line);
435
+ let prelude_nodes = this.prelude_parser.parse_prelude(at_rule_name, trimmed[0], trimmed[1], at_rule_line, at_rule_column);
427
436
  for (let prelude_node of prelude_nodes) {
428
437
  this.arena.append_child(at_rule, prelude_node);
429
438
  }
@@ -1,5 +1,5 @@
1
1
  import { L as Lexer, q as TOKEN_COMMA, y as TOKEN_EOF, l as TOKEN_WHITESPACE, a as TOKEN_FUNCTION, o as TOKEN_COLON, r as TOKEN_LEFT_BRACKET, h as TOKEN_DELIM, c as TOKEN_HASH, T as TOKEN_IDENT, s as TOKEN_RIGHT_BRACKET, t as TOKEN_LEFT_PAREN, u as TOKEN_RIGHT_PAREN } from './lexer-DXablYMZ.js';
2
- import { d as NODE_SELECTOR, m as NODE_SELECTOR_LIST, J as is_whitespace, o as NODE_SELECTOR_CLASS, q as NODE_SELECTOR_ATTRIBUTE, M as trim_boundaries, s as NODE_SELECTOR_PSEUDO_ELEMENT, r as NODE_SELECTOR_PSEUDO_CLASS, n as NODE_SELECTOR_TYPE, p as NODE_SELECTOR_ID, u as NODE_SELECTOR_UNIVERSAL, v as NODE_SELECTOR_NESTING, t as NODE_SELECTOR_COMBINATOR } from './string-utils-B-rJII-E.js';
2
+ import { d as NODE_SELECTOR, m as NODE_SELECTOR_LIST, J as is_whitespace, o as NODE_SELECTOR_CLASS, q as NODE_SELECTOR_ATTRIBUTE, M as trim_boundaries, s as NODE_SELECTOR_PSEUDO_ELEMENT, r as NODE_SELECTOR_PSEUDO_CLASS, n as NODE_SELECTOR_TYPE, p as NODE_SELECTOR_ID, u as NODE_SELECTOR_UNIVERSAL, v as NODE_SELECTOR_NESTING, t as NODE_SELECTOR_COMBINATOR } from './string-utils-Bm2l6p1L.js';
3
3
 
4
4
  class SelectorParser {
5
5
  lexer;
@@ -14,10 +14,11 @@ class SelectorParser {
14
14
  }
15
15
  // Parse a selector range into selector nodes
16
16
  // Always returns a NODE_SELECTOR wrapper with detailed selector nodes as children
17
- parse_selector(start, end, line = 1) {
17
+ parse_selector(start, end, line = 1, column = 1) {
18
18
  this.selector_end = end;
19
19
  this.lexer.pos = start;
20
20
  this.lexer.line = line;
21
+ this.lexer.column = column;
21
22
  let innerSelector = this.parse_selector_list();
22
23
  if (innerSelector === null) {
23
24
  return null;
@@ -27,6 +28,7 @@ class SelectorParser {
27
28
  this.arena.set_start_offset(selectorWrapper, start);
28
29
  this.arena.set_length(selectorWrapper, end - start);
29
30
  this.arena.set_start_line(selectorWrapper, line);
31
+ this.arena.set_start_column(selectorWrapper, column);
30
32
  this.arena.set_first_child(selectorWrapper, innerSelector);
31
33
  this.arena.set_last_child(selectorWrapper, innerSelector);
32
34
  return selectorWrapper;
@@ -60,6 +62,7 @@ class SelectorParser {
60
62
  this.arena.set_start_offset(list_node, list_start);
61
63
  this.arena.set_length(list_node, this.lexer.pos - list_start);
62
64
  this.arena.set_start_line(list_node, this.lexer.line);
65
+ this.arena.set_start_column(list_node, this.lexer.column);
63
66
  this.arena.set_first_child(list_node, selectors[0]);
64
67
  this.arena.set_last_child(list_node, selectors[selectors.length - 1]);
65
68
  for (let i = 0; i < selectors.length - 1; i++) {
@@ -210,6 +213,7 @@ class SelectorParser {
210
213
  this.arena.set_start_offset(node, dot_pos);
211
214
  this.arena.set_length(node, this.lexer.token_end - dot_pos);
212
215
  this.arena.set_start_line(node, this.lexer.line);
216
+ this.arena.set_start_column(node, this.lexer.column);
213
217
  this.arena.set_content_start(node, this.lexer.token_start);
214
218
  this.arena.set_content_length(node, this.lexer.token_end - this.lexer.token_start);
215
219
  return node;
@@ -236,6 +240,7 @@ class SelectorParser {
236
240
  this.arena.set_start_offset(node, start);
237
241
  this.arena.set_length(node, end - start);
238
242
  this.arena.set_start_line(node, this.lexer.line);
243
+ this.arena.set_start_column(node, this.lexer.column);
239
244
  let trimmed = trim_boundaries(this.source, start + 1, end - 1);
240
245
  if (trimmed) {
241
246
  this.arena.set_content_start(node, trimmed[0]);
@@ -258,6 +263,7 @@ class SelectorParser {
258
263
  this.arena.set_start_offset(node, start);
259
264
  this.arena.set_length(node, this.lexer.token_end - start);
260
265
  this.arena.set_start_line(node, this.lexer.line);
266
+ this.arena.set_start_column(node, this.lexer.column);
261
267
  this.arena.set_content_start(node, this.lexer.token_start);
262
268
  this.arena.set_content_length(node, this.lexer.token_end - this.lexer.token_start);
263
269
  return node;
@@ -294,6 +300,7 @@ class SelectorParser {
294
300
  this.arena.set_start_offset(node, start);
295
301
  this.arena.set_length(node, end - start);
296
302
  this.arena.set_start_line(node, this.lexer.line);
303
+ this.arena.set_start_column(node, this.lexer.column);
297
304
  this.arena.set_content_start(node, func_name_start);
298
305
  this.arena.set_content_length(node, func_name_end - func_name_start);
299
306
  return node;
@@ -305,6 +312,7 @@ class SelectorParser {
305
312
  this.arena.set_start_offset(node, start);
306
313
  this.arena.set_length(node, end - start);
307
314
  this.arena.set_start_line(node, this.lexer.line);
315
+ this.arena.set_start_column(node, this.lexer.column);
308
316
  this.arena.set_content_start(node, start);
309
317
  this.arena.set_content_length(node, end - start);
310
318
  return node;
@@ -315,6 +323,7 @@ class SelectorParser {
315
323
  this.arena.set_start_offset(node, start);
316
324
  this.arena.set_length(node, end - start);
317
325
  this.arena.set_start_line(node, this.lexer.line);
326
+ this.arena.set_start_column(node, this.lexer.column);
318
327
  this.arena.set_content_start(node, start + 1);
319
328
  this.arena.set_content_length(node, end - start - 1);
320
329
  return node;
@@ -325,6 +334,7 @@ class SelectorParser {
325
334
  this.arena.set_start_offset(node, start);
326
335
  this.arena.set_length(node, end - start);
327
336
  this.arena.set_start_line(node, this.lexer.line);
337
+ this.arena.set_start_column(node, this.lexer.column);
328
338
  this.arena.set_content_start(node, start);
329
339
  this.arena.set_content_length(node, end - start);
330
340
  return node;
@@ -335,6 +345,7 @@ class SelectorParser {
335
345
  this.arena.set_start_offset(node, start);
336
346
  this.arena.set_length(node, end - start);
337
347
  this.arena.set_start_line(node, this.lexer.line);
348
+ this.arena.set_start_column(node, this.lexer.column);
338
349
  this.arena.set_content_start(node, start);
339
350
  this.arena.set_content_length(node, end - start);
340
351
  return node;
@@ -345,6 +356,7 @@ class SelectorParser {
345
356
  this.arena.set_start_offset(node, start);
346
357
  this.arena.set_length(node, end - start);
347
358
  this.arena.set_start_line(node, this.lexer.line);
359
+ this.arena.set_start_column(node, this.lexer.column);
348
360
  this.arena.set_content_start(node, start);
349
361
  this.arena.set_content_length(node, end - start);
350
362
  return node;
@@ -5,7 +5,7 @@ export declare class SelectorParser {
5
5
  private source;
6
6
  private selector_end;
7
7
  constructor(arena: CSSDataArena, source: string);
8
- parse_selector(start: number, end: number, line?: number): number | null;
8
+ parse_selector(start: number, end: number, line?: number, column?: number): number | null;
9
9
  private parse_selector_list;
10
10
  private parse_complex_selector;
11
11
  private parse_compound_selector;
@@ -114,6 +114,10 @@ class CSSDataArena {
114
114
  get_start_line(node_index) {
115
115
  return this.view.getUint32(this.node_offset(node_index) + 32, true);
116
116
  }
117
+ // Read start column
118
+ get_start_column(node_index) {
119
+ return this.view.getUint16(this.node_offset(node_index) + 42, true);
120
+ }
117
121
  // Read value start offset (declaration value / at-rule prelude)
118
122
  get_value_start(node_index) {
119
123
  return this.view.getUint32(this.node_offset(node_index) + 36, true);
@@ -163,6 +167,10 @@ class CSSDataArena {
163
167
  set_start_line(node_index, line) {
164
168
  this.view.setUint32(this.node_offset(node_index) + 32, line, true);
165
169
  }
170
+ // Write start column
171
+ set_start_column(node_index, column) {
172
+ this.view.setUint16(this.node_offset(node_index) + 42, column, true);
173
+ }
166
174
  // Write value start offset (declaration value / at-rule prelude)
167
175
  set_value_start(node_index, offset) {
168
176
  this.view.setUint32(this.node_offset(node_index) + 36, offset, true);
@@ -325,6 +333,10 @@ class CSSNode {
325
333
  get line() {
326
334
  return this.arena.get_start_line(this.index);
327
335
  }
336
+ // Get start column number
337
+ get column() {
338
+ return this.arena.get_start_column(this.index);
339
+ }
328
340
  // Get start offset in source
329
341
  get offset() {
330
342
  return this.arena.get_start_offset(this.index);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@projectwallace/css-parser",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "High-performance CSS lexer and parser, optimized for CSS inspection and analysis",
5
5
  "author": "Bart Veneman <bat@projectwallace.com>",
6
6
  "license": "MIT",