@projectwallace/css-parser 0.13.4 → 0.13.6

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.
Files changed (41) hide show
  1. package/dist/css-node-2ejJUrIw.js +645 -0
  2. package/dist/css-node-DqyvMXBN.d.ts +313 -0
  3. package/dist/index.d.ts +150 -16
  4. package/dist/index.js +103 -13
  5. package/dist/parse-anplusb.d.ts +26 -2
  6. package/dist/parse-anplusb.js +191 -207
  7. package/dist/parse-atrule-prelude.d.ts +40 -2
  8. package/dist/parse-atrule-prelude.js +556 -652
  9. package/dist/parse-declaration.d.ts +16 -2
  10. package/dist/parse-declaration.js +140 -164
  11. package/dist/parse-dimension-CCn_XRDe.js +177 -0
  12. package/dist/parse-dimension.d.ts +6 -3
  13. package/dist/parse-dimension.js +1 -35
  14. package/dist/parse-selector.d.ts +37 -2
  15. package/dist/parse-selector.js +508 -635
  16. package/dist/parse-utils-DnsZRpfd.js +98 -0
  17. package/dist/parse-value.d.ts +23 -2
  18. package/dist/parse-value.js +176 -224
  19. package/dist/parse.d.ts +38 -8
  20. package/dist/parse.js +274 -350
  21. package/dist/tokenize-BQFB1jXg.js +540 -0
  22. package/dist/tokenize-odLrcjj2.d.ts +110 -0
  23. package/dist/tokenize.d.ts +2 -26
  24. package/dist/tokenize.js +1 -545
  25. package/package.json +20 -26
  26. package/dist/arena.d.ts +0 -59
  27. package/dist/arena.js +0 -290
  28. package/dist/char-types.d.ts +0 -14
  29. package/dist/char-types.js +0 -53
  30. package/dist/constants.d.ts +0 -43
  31. package/dist/constants.js +0 -50
  32. package/dist/css-node.d.ts +0 -202
  33. package/dist/css-node.js +0 -497
  34. package/dist/parse-utils.d.ts +0 -1
  35. package/dist/parse-utils.js +0 -60
  36. package/dist/string-utils.d.ts +0 -99
  37. package/dist/string-utils.js +0 -129
  38. package/dist/token-types.d.ts +0 -35
  39. package/dist/token-types.js +0 -29
  40. package/dist/walk.d.ts +0 -28
  41. package/dist/walk.js +0 -51
@@ -1,7 +1,21 @@
1
- import { CSSNode } from './css-node';
1
+ import { n as Lexer } from "./tokenize-odLrcjj2.js";
2
+ import { E as CSSDataArena, r as CSSNode } from "./css-node-DqyvMXBN.js";
3
+
4
+ //#region src/parse-declaration.d.ts
5
+ /** @internal */
6
+ declare class DeclarationParser {
7
+ private arena;
8
+ private source;
9
+ private value_parser;
10
+ constructor(arena: CSSDataArena, source: string, parse_values?: boolean);
11
+ parse_declaration(start: number, end: number, line?: number, column?: number): number | null;
12
+ parse_declaration_with_lexer(lexer: Lexer, end: number): number | null;
13
+ }
2
14
  /**
3
15
  * Parse a CSS declaration string and return an AST
4
16
  * @param source - The CSS declaration to parse (e.g., "color: red", "margin: 10px !important")
5
17
  * @returns The DECLARATION CSSNode
6
18
  */
7
- export declare function parse_declaration(source: string): CSSNode;
19
+ declare function parse_declaration(source: string): CSSNode;
20
+ //#endregion
21
+ export { DeclarationParser, parse_declaration };
@@ -1,167 +1,143 @@
1
- import { Lexer } from './tokenize.js';
2
- import { CSSDataArena, DECLARATION, FLAG_IMPORTANT, FLAG_BROWSERHACK } from './arena.js';
3
- import { ValueParser } from './parse-value.js';
4
- import { is_vendor_prefixed } from './string-utils.js';
5
- import { TOKEN_AT_KEYWORD, TOKEN_HASH, TOKEN_IDENT, TOKEN_DELIM, TOKEN_LEFT_PAREN, TOKEN_RIGHT_PAREN, TOKEN_LEFT_BRACKET, TOKEN_RIGHT_BRACKET, TOKEN_COMMA, TOKEN_COLON, TOKEN_EOF, TOKEN_SEMICOLON, TOKEN_RIGHT_BRACE, TOKEN_LEFT_BRACE, TOKEN_FUNCTION } from './token-types.js';
6
- import { trim_boundaries } from './parse-utils.js';
7
- import { CSSNode } from './css-node.js';
8
-
9
- class DeclarationParser {
10
- arena;
11
- source;
12
- value_parser;
13
- constructor(arena, source, parse_values = true) {
14
- this.arena = arena;
15
- this.source = source;
16
- this.value_parser = parse_values ? new ValueParser(arena, source) : null;
17
- }
18
- // Parse a declaration range into a declaration node (standalone use)
19
- parse_declaration(start, end, line = 1, column = 1) {
20
- const lexer = new Lexer(this.source);
21
- lexer.seek(start, line, column);
22
- lexer.next_token_fast(true);
23
- return this.parse_declaration_with_lexer(lexer, end);
24
- }
25
- // Parse a declaration using a provided lexer (used by Parser to avoid re-tokenization)
26
- parse_declaration_with_lexer(lexer, end) {
27
- let has_browser_hack = false;
28
- let browser_hack_start = 0;
29
- let browser_hack_line = 1;
30
- let browser_hack_column = 1;
31
- if (lexer.token_type === TOKEN_AT_KEYWORD || lexer.token_type === TOKEN_HASH) {
32
- has_browser_hack = true;
33
- browser_hack_start = lexer.token_start;
34
- browser_hack_line = lexer.token_line;
35
- browser_hack_column = lexer.token_column;
36
- } else if (lexer.token_type === TOKEN_IDENT) {
37
- const first_char = this.source.charCodeAt(lexer.token_start);
38
- if (first_char === 95) {
39
- has_browser_hack = true;
40
- browser_hack_start = lexer.token_start;
41
- browser_hack_line = lexer.token_line;
42
- browser_hack_column = lexer.token_column;
43
- } else if (first_char === 45) {
44
- const second_char = this.source.charCodeAt(lexer.token_start + 1);
45
- const is_custom_property = second_char === 45;
46
- if (!is_custom_property && !is_vendor_prefixed(this.source, lexer.token_start, lexer.token_end)) {
47
- has_browser_hack = true;
48
- browser_hack_start = lexer.token_start;
49
- browser_hack_line = lexer.token_line;
50
- browser_hack_column = lexer.token_column;
51
- }
52
- }
53
- } else {
54
- const is_browser_hack_token = lexer.token_type === TOKEN_DELIM || lexer.token_type === TOKEN_LEFT_PAREN || lexer.token_type === TOKEN_RIGHT_PAREN || lexer.token_type === TOKEN_LEFT_BRACKET || lexer.token_type === TOKEN_RIGHT_BRACKET || lexer.token_type === TOKEN_COMMA || lexer.token_type === TOKEN_COLON;
55
- if (is_browser_hack_token) {
56
- const delim_saved = lexer.save_position();
57
- browser_hack_start = lexer.token_start;
58
- browser_hack_line = lexer.token_line;
59
- browser_hack_column = lexer.token_column;
60
- lexer.next_token_fast(true);
61
- if (lexer.token_type === TOKEN_IDENT) {
62
- has_browser_hack = true;
63
- } else {
64
- lexer.restore_position(delim_saved);
65
- }
66
- }
67
- }
68
- if (lexer.token_type !== TOKEN_IDENT && lexer.token_type !== TOKEN_AT_KEYWORD && lexer.token_type !== TOKEN_HASH) {
69
- return null;
70
- }
71
- let prop_start = has_browser_hack ? browser_hack_start : lexer.token_start;
72
- let prop_end = lexer.token_end;
73
- let decl_line = has_browser_hack ? browser_hack_line : lexer.token_line;
74
- let decl_column = has_browser_hack ? browser_hack_column : lexer.token_column;
75
- const saved = lexer.save_position();
76
- lexer.next_token_fast(true);
77
- if (lexer.token_type !== TOKEN_COLON) {
78
- lexer.restore_position(saved);
79
- return null;
80
- }
81
- lexer.next_token_fast(true);
82
- let declaration = this.arena.create_node(
83
- DECLARATION,
84
- prop_start,
85
- 0,
86
- // length unknown yet
87
- decl_line,
88
- decl_column
89
- );
90
- this.arena.set_content_start_delta(declaration, 0);
91
- this.arena.set_content_length(declaration, prop_end - prop_start);
92
- let value_start = lexer.token_start;
93
- let value_start_line = lexer.token_line;
94
- let value_start_column = lexer.token_column;
95
- let value_end = value_start;
96
- let has_important = false;
97
- let last_end = lexer.token_end;
98
- let paren_depth = 0;
99
- while (lexer.token_type !== TOKEN_EOF && lexer.token_start < end) {
100
- let token_type = lexer.token_type;
101
- if (token_type === TOKEN_LEFT_PAREN || token_type === TOKEN_FUNCTION) {
102
- paren_depth++;
103
- } else if (token_type === TOKEN_RIGHT_PAREN) {
104
- paren_depth--;
105
- }
106
- if (token_type === TOKEN_SEMICOLON && paren_depth === 0) break;
107
- if (token_type === TOKEN_RIGHT_BRACE && paren_depth === 0) break;
108
- if (token_type === TOKEN_LEFT_BRACE) {
109
- lexer.restore_position(saved);
110
- return null;
111
- }
112
- if (token_type === TOKEN_DELIM && this.source[lexer.token_start] === "!") {
113
- value_end = lexer.token_start;
114
- let next_type = lexer.next_token_fast(true);
115
- if (next_type === TOKEN_IDENT) {
116
- has_important = true;
117
- last_end = lexer.token_end;
118
- lexer.next_token_fast(true);
119
- break;
120
- }
121
- }
122
- last_end = lexer.token_end;
123
- value_end = last_end;
124
- lexer.next_token_fast(true);
125
- }
126
- let trimmed = trim_boundaries(this.source, value_start, value_end);
127
- if (trimmed) {
128
- this.arena.set_value_start_delta(declaration, trimmed[0] - prop_start);
129
- this.arena.set_value_length(declaration, trimmed[1] - trimmed[0]);
130
- if (this.value_parser) {
131
- let valueNode = this.value_parser.parse_value(value_start, trimmed[1], value_start_line, value_start_column);
132
- this.arena.append_children(declaration, [valueNode]);
133
- }
134
- } else {
135
- this.arena.set_value_start_delta(declaration, value_start - prop_start);
136
- this.arena.set_value_length(declaration, 0);
137
- if (this.value_parser) {
138
- let valueNode = this.value_parser.parse_value(value_start, value_start, value_start_line, value_start_column);
139
- this.arena.append_children(declaration, [valueNode]);
140
- }
141
- }
142
- if (has_important) {
143
- this.arena.set_flag(declaration, FLAG_IMPORTANT);
144
- }
145
- if (has_browser_hack) {
146
- this.arena.set_flag(declaration, FLAG_BROWSERHACK);
147
- }
148
- if (lexer.token_type === TOKEN_SEMICOLON) {
149
- last_end = lexer.token_end;
150
- lexer.next_token_fast(true);
151
- }
152
- this.arena.set_length(declaration, last_end - prop_start);
153
- return declaration;
154
- }
155
- }
1
+ import { t as Lexer } from "./tokenize-BQFB1jXg.js";
2
+ import { C as CSSDataArena, r as CSSNode } from "./css-node-2ejJUrIw.js";
3
+ import { i as is_vendor_prefixed } from "./parse-dimension-CCn_XRDe.js";
4
+ import { i as trim_boundaries } from "./parse-utils-DnsZRpfd.js";
5
+ import { ValueParser } from "./parse-value.js";
6
+ //#region src/parse-declaration.ts
7
+ /** @internal */
8
+ var DeclarationParser = class {
9
+ arena;
10
+ source;
11
+ value_parser;
12
+ constructor(arena, source, parse_values = true) {
13
+ this.arena = arena;
14
+ this.source = source;
15
+ this.value_parser = parse_values ? new ValueParser(arena, source) : null;
16
+ }
17
+ parse_declaration(start, end, line = 1, column = 1) {
18
+ const lexer = new Lexer(this.source);
19
+ lexer.seek(start, line, column);
20
+ lexer.next_token_fast(true);
21
+ return this.parse_declaration_with_lexer(lexer, end);
22
+ }
23
+ parse_declaration_with_lexer(lexer, end) {
24
+ let has_browser_hack = false;
25
+ let browser_hack_start = 0;
26
+ let browser_hack_line = 1;
27
+ let browser_hack_column = 1;
28
+ if (lexer.token_type === 1) {
29
+ const first_char = this.source.charCodeAt(lexer.token_start);
30
+ if (first_char === 95) {
31
+ has_browser_hack = true;
32
+ browser_hack_start = lexer.token_start;
33
+ browser_hack_line = lexer.token_line;
34
+ browser_hack_column = lexer.token_column;
35
+ } else if (first_char === 45) {
36
+ if (this.source.charCodeAt(lexer.token_start + 1) !== 45 && !is_vendor_prefixed(this.source, lexer.token_start, lexer.token_end)) {
37
+ has_browser_hack = true;
38
+ browser_hack_start = lexer.token_start;
39
+ browser_hack_line = lexer.token_line;
40
+ browser_hack_column = lexer.token_column;
41
+ }
42
+ }
43
+ } else if (lexer.token_type === 3 || lexer.token_type === 4) {
44
+ has_browser_hack = true;
45
+ browser_hack_start = lexer.token_start;
46
+ browser_hack_line = lexer.token_line;
47
+ browser_hack_column = lexer.token_column;
48
+ } else if (lexer.token_type === 9 || lexer.token_type === 21 || lexer.token_type === 22 || lexer.token_type === 19 || lexer.token_type === 20 || lexer.token_type === 18 || lexer.token_type === 16) {
49
+ const delim_saved = lexer.save_position();
50
+ browser_hack_start = lexer.token_start;
51
+ browser_hack_line = lexer.token_line;
52
+ browser_hack_column = lexer.token_column;
53
+ lexer.next_token_fast(true);
54
+ if (lexer.token_type === 1) has_browser_hack = true;
55
+ else lexer.restore_position(delim_saved);
56
+ }
57
+ if (lexer.token_type !== 1 && lexer.token_type !== 3 && lexer.token_type !== 4) return null;
58
+ let prop_start = has_browser_hack ? browser_hack_start : lexer.token_start;
59
+ let prop_end = lexer.token_end;
60
+ let decl_line = has_browser_hack ? browser_hack_line : lexer.token_line;
61
+ let decl_column = has_browser_hack ? browser_hack_column : lexer.token_column;
62
+ const saved = lexer.save_position();
63
+ lexer.next_token_fast(true);
64
+ if (lexer.token_type !== 16) {
65
+ lexer.restore_position(saved);
66
+ return null;
67
+ }
68
+ lexer.next_token_fast(true);
69
+ let declaration = this.arena.create_node(4, prop_start, 0, decl_line, decl_column);
70
+ this.arena.set_content_start_delta(declaration, 0);
71
+ this.arena.set_content_length(declaration, prop_end - prop_start);
72
+ let value_start = lexer.token_start;
73
+ let value_start_line = lexer.token_line;
74
+ let value_start_column = lexer.token_column;
75
+ let value_end = value_start;
76
+ let has_important = false;
77
+ let last_end = lexer.token_end;
78
+ let paren_depth = 0;
79
+ while (lexer.token_type !== 26 && lexer.token_start < end) {
80
+ let token_type = lexer.token_type;
81
+ if (token_type === 21 || token_type === 2) paren_depth++;
82
+ else if (token_type === 22) paren_depth--;
83
+ if (token_type === 17 && paren_depth === 0) break;
84
+ if (token_type === 24 && paren_depth === 0) break;
85
+ if (token_type === 23) {
86
+ lexer.restore_position(saved);
87
+ return null;
88
+ }
89
+ if (token_type === 9 && this.source[lexer.token_start] === "!") {
90
+ value_end = lexer.token_start;
91
+ if (lexer.next_token_fast(true) === 1) {
92
+ has_important = true;
93
+ last_end = lexer.token_end;
94
+ lexer.next_token_fast(true);
95
+ break;
96
+ }
97
+ }
98
+ last_end = lexer.token_end;
99
+ value_end = last_end;
100
+ lexer.next_token_fast(true);
101
+ }
102
+ let trimmed = trim_boundaries(this.source, value_start, value_end);
103
+ if (trimmed) {
104
+ this.arena.set_value_start_delta(declaration, trimmed[0] - prop_start);
105
+ this.arena.set_value_length(declaration, trimmed[1] - trimmed[0]);
106
+ if (this.value_parser) {
107
+ let valueNode = this.value_parser.parse_value(value_start, trimmed[1], value_start_line, value_start_column);
108
+ this.arena.append_children(declaration, [valueNode]);
109
+ } else {
110
+ let rawNode = this.arena.create_node(8, trimmed[0], trimmed[1] - trimmed[0], value_start_line, value_start_column);
111
+ this.arena.append_children(declaration, [rawNode]);
112
+ }
113
+ } else {
114
+ this.arena.set_value_start_delta(declaration, value_start - prop_start);
115
+ this.arena.set_value_length(declaration, 0);
116
+ if (this.value_parser) {
117
+ let valueNode = this.value_parser.parse_value(value_start, value_start, value_start_line, value_start_column);
118
+ this.arena.append_children(declaration, [valueNode]);
119
+ }
120
+ }
121
+ if (has_important) this.arena.set_flag(declaration, 1);
122
+ if (has_browser_hack) this.arena.set_flag(declaration, 128);
123
+ if (lexer.token_type === 17) {
124
+ last_end = lexer.token_end;
125
+ lexer.next_token_fast(true);
126
+ }
127
+ this.arena.set_length(declaration, last_end - prop_start);
128
+ return declaration;
129
+ }
130
+ };
131
+ /**
132
+ * Parse a CSS declaration string and return an AST
133
+ * @param source - The CSS declaration to parse (e.g., "color: red", "margin: 10px !important")
134
+ * @returns The DECLARATION CSSNode
135
+ */
156
136
  function parse_declaration(source) {
157
- const arena = new CSSDataArena(CSSDataArena.capacity_for_source(source.length));
158
- const decl_parser = new DeclarationParser(arena, source);
159
- const decl_index = decl_parser.parse_declaration(0, source.length);
160
- if (decl_index === null) {
161
- const empty = arena.create_node(DECLARATION, 0, 0, 1, 1);
162
- return new CSSNode(arena, source, empty);
163
- }
164
- return new CSSNode(arena, source, decl_index);
137
+ const arena = new CSSDataArena(CSSDataArena.capacity_for_source(source.length));
138
+ const decl_index = new DeclarationParser(arena, source).parse_declaration(0, source.length);
139
+ if (decl_index === null) return new CSSNode(arena, source, arena.create_node(4, 0, 0, 1, 1));
140
+ return new CSSNode(arena, source, decl_index);
165
141
  }
166
-
142
+ //#endregion
167
143
  export { DeclarationParser, parse_declaration };
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Check if a character code is whitespace (space, tab, newline, CR, or FF)
3
+ * @internal
4
+ */
5
+ function is_whitespace(ch) {
6
+ return ch === 32 || ch === 9 || ch === 10 || ch === 13 || ch === 12;
7
+ }
8
+ /** @internal */
9
+ function is_combinator(ch) {
10
+ return ch === 62 || ch === 43 || ch === 126;
11
+ }
12
+ /** @internal */
13
+ function is_digit(ch) {
14
+ return ch >= 48 && ch <= 57;
15
+ }
16
+ /**
17
+ * @param a Base string, MUST be lowercase!
18
+ * @param b Compare string
19
+ */
20
+ function str_equals(a, b) {
21
+ if (a.length !== b.length) return false;
22
+ for (let i = 0; i < a.length; i++) {
23
+ let ca = a.charCodeAt(i);
24
+ let cb = b.charCodeAt(i);
25
+ cb |= 32;
26
+ if (ca !== cb) return false;
27
+ }
28
+ return true;
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
+ */
39
+ function str_starts_with(str, prefix) {
40
+ if (str.length < prefix.length) return false;
41
+ for (let i = 0; i < prefix.length; i++) {
42
+ let ca = str.charCodeAt(i);
43
+ let cb = prefix.charCodeAt(i);
44
+ if (ca >= 65 && ca <= 90) ca |= 32;
45
+ if (ca !== cb) return false;
46
+ }
47
+ return true;
48
+ }
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
+ */
59
+ function str_index_of(str, searchChar) {
60
+ if (searchChar.length === 0) return -1;
61
+ if (searchChar.length === 1) {
62
+ const searchCode = searchChar.charCodeAt(0);
63
+ for (let i = 0; i < str.length; i++) {
64
+ let ca = str.charCodeAt(i);
65
+ if (ca >= 65 && ca <= 90) ca |= 32;
66
+ if (ca === searchCode) return i;
67
+ }
68
+ return -1;
69
+ }
70
+ for (let i = 0; i <= str.length - searchChar.length; i++) {
71
+ let match = true;
72
+ for (let j = 0; j < searchChar.length; j++) {
73
+ let ca = str.charCodeAt(i + j);
74
+ let cb = searchChar.charCodeAt(j);
75
+ if (ca >= 65 && ca <= 90) ca |= 32;
76
+ if (ca !== cb) {
77
+ match = false;
78
+ break;
79
+ }
80
+ }
81
+ if (match) return i;
82
+ }
83
+ return -1;
84
+ }
85
+ function is_vendor_prefixed(source, start, end) {
86
+ if (start === void 0 || end === void 0) {
87
+ start = 0;
88
+ end = source.length;
89
+ }
90
+ if (source.charCodeAt(start) !== 45) return false;
91
+ if (source.charCodeAt(start + 1) === 45) return false;
92
+ if (end - start < 3) return false;
93
+ for (let i = start + 2; i < end; i++) if (source.charCodeAt(i) === 45) return true;
94
+ return false;
95
+ }
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
+ */
109
+ function is_custom(str) {
110
+ if (str.length < 3) return false;
111
+ return str.charCodeAt(0) === 45 && str.charCodeAt(1) === 45;
112
+ }
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
+ */
127
+ function strip_vendor_prefix(str) {
128
+ if (!is_vendor_prefixed(str)) return str;
129
+ for (let i = 2; i < str.length; i++) if (str.charCodeAt(i) === 45) return str.substring(i + 1);
130
+ return str;
131
+ }
132
+ //#endregion
133
+ //#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
+ */
146
+ function parse_dimension(text) {
147
+ let num_end = 0;
148
+ for (let i = 0; i < text.length; i++) {
149
+ let ch = text.charCodeAt(i);
150
+ if (ch === 101 || ch === 69) {
151
+ if (i + 1 < text.length) {
152
+ let next_ch = text.charCodeAt(i + 1);
153
+ if (is_digit(next_ch)) {
154
+ num_end = i + 1;
155
+ continue;
156
+ }
157
+ if ((next_ch === 43 || next_ch === 45) && i + 2 < text.length) {
158
+ if (is_digit(text.charCodeAt(i + 2))) {
159
+ num_end = i + 1;
160
+ continue;
161
+ }
162
+ }
163
+ }
164
+ break;
165
+ }
166
+ if (is_digit(ch) || ch === 46 || ch === 45 || ch === 43) num_end = i + 1;
167
+ else break;
168
+ }
169
+ let num_str = text.substring(0, num_end);
170
+ let unit = text.substring(num_end);
171
+ return {
172
+ value: num_str ? parseFloat(num_str) : 0,
173
+ unit
174
+ };
175
+ }
176
+ //#endregion
177
+ export { is_whitespace as a, str_starts_with as c, is_vendor_prefixed as i, strip_vendor_prefix as l, is_combinator as n, str_equals as o, is_custom as r, str_index_of as s, parse_dimension as t };
@@ -1,3 +1,4 @@
1
+ //#region src/parse-dimension.d.ts
1
2
  /**
2
3
  * Parse a dimension string into numeric value and unit
3
4
  *
@@ -10,7 +11,9 @@
10
11
  * - "1.5em" → { value: 1.5, unit: "em" }
11
12
  * - "-10rem" → { value: -10, unit: "rem" }
12
13
  */
13
- export declare function parse_dimension(text: string): {
14
- value: number;
15
- unit: string;
14
+ declare function parse_dimension(text: string): {
15
+ value: number;
16
+ unit: string;
16
17
  };
18
+ //#endregion
19
+ export { parse_dimension };
@@ -1,36 +1,2 @@
1
- import { is_digit, CHAR_PERIOD, CHAR_MINUS_HYPHEN, CHAR_PLUS } from './string-utils.js';
2
-
3
- function parse_dimension(text) {
4
- let num_end = 0;
5
- for (let i = 0; i < text.length; i++) {
6
- let ch = text.charCodeAt(i);
7
- if (ch === 101 || ch === 69) {
8
- if (i + 1 < text.length) {
9
- let next_ch = text.charCodeAt(i + 1);
10
- if (is_digit(next_ch)) {
11
- num_end = i + 1;
12
- continue;
13
- }
14
- if ((next_ch === 43 || next_ch === 45) && i + 2 < text.length) {
15
- let afterSign = text.charCodeAt(i + 2);
16
- if (is_digit(afterSign)) {
17
- num_end = i + 1;
18
- continue;
19
- }
20
- }
21
- }
22
- break;
23
- }
24
- if (is_digit(ch) || ch === CHAR_PERIOD || ch === CHAR_MINUS_HYPHEN || ch === CHAR_PLUS) {
25
- num_end = i + 1;
26
- } else {
27
- break;
28
- }
29
- }
30
- let num_str = text.substring(0, num_end);
31
- let unit = text.substring(num_end);
32
- let value = num_str ? parseFloat(num_str) : 0;
33
- return { value, unit };
34
- }
35
-
1
+ import { t as parse_dimension } from "./parse-dimension-CCn_XRDe.js";
36
2
  export { parse_dimension };
@@ -1,7 +1,42 @@
1
- import { CSSNode } from './css-node';
1
+ import { E as CSSDataArena, r as CSSNode } from "./css-node-DqyvMXBN.js";
2
+
3
+ //#region src/parse-selector.d.ts
4
+ /** @internal */
5
+ declare class SelectorParser {
6
+ private lexer;
7
+ private arena;
8
+ private source;
9
+ private selector_end;
10
+ constructor(arena: CSSDataArena, source: string);
11
+ parse_selector(start: number, end: number, line?: number, column?: number, allow_relative?: boolean): number | null;
12
+ private parse_selector_list;
13
+ private parse_complex_selector;
14
+ private parse_compound_selector;
15
+ private parse_simple_selector;
16
+ private parse_namespace_local_part;
17
+ private parse_type_or_namespace_selector;
18
+ private parse_universal_or_namespace_selector;
19
+ private parse_empty_namespace_selector;
20
+ private try_parse_combinator;
21
+ private parse_class_selector;
22
+ private parse_attribute_selector;
23
+ private parse_attribute_content;
24
+ private parse_pseudo;
25
+ private parse_pseudo_function;
26
+ private parse_pseudo_function_after_colon;
27
+ private is_nth_pseudo;
28
+ private parse_lang_identifiers;
29
+ private parse_nth_expression;
30
+ private find_of_keyword;
31
+ private create_node;
32
+ private create_node_at;
33
+ private skip_whitespace;
34
+ }
2
35
  /**
3
36
  * Parse a CSS selector string and return an AST
4
37
  * @param source - The CSS selector to parse (e.g., "div.class > p#id")
5
38
  * @returns The root CSSNode of the selector AST
6
39
  */
7
- export declare function parse_selector(source: string): CSSNode;
40
+ declare function parse_selector(source: string): CSSNode;
41
+ //#endregion
42
+ export { SelectorParser, parse_selector };