@projectwallace/css-parser 0.18.8 → 0.18.11
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 +186 -18
- package/dist/{arena-e9O_g2AN.js → arena-Bsf96CQK.js} +27 -19
- package/dist/{arena-BGvFdbj5.d.ts → arena-DvT75bvK.d.ts} +2 -0
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/{css-node-CH5HqF0J.js → css-node-yoUdFtNg.js} +101 -106
- package/dist/index.d.ts +6 -20
- package/dist/index.js +9 -146
- package/dist/{node-types-YnOKcNfU.d.ts → node-types-DG8OKqPu.d.ts} +8 -54
- package/dist/node-types.d.ts +2 -0
- package/dist/node-types.js +142 -0
- package/dist/parse-anplusb.d.ts +2 -2
- package/dist/parse-anplusb.js +5 -4
- package/dist/parse-atrule-prelude.d.ts +4 -3
- package/dist/parse-atrule-prelude.js +82 -77
- package/dist/parse-declaration.d.ts +4 -3
- package/dist/parse-declaration.js +28 -26
- package/dist/parse-dimension.js +46 -1
- package/dist/{parse-selector-PhqFezCi.js → parse-selector-CqIpnBrQ.js} +74 -89
- package/dist/parse-selector.d.ts +2 -2
- package/dist/parse-selector.js +1 -2
- package/dist/parse-value.d.ts +2 -2
- package/dist/parse-value.js +8 -8
- package/dist/parse.d.ts +3 -3
- package/dist/parse.js +49 -47
- package/dist/string-helpers-BMWJduts.d.ts +18 -0
- package/dist/string-helpers.d.ts +2 -0
- package/dist/string-helpers.js +1 -0
- package/dist/{parse-dimension-CQELWb5z.js → string-utils-DiRRd28d.js} +9 -59
- package/dist/token-types-Bqsf5FX-.d.ts +38 -0
- package/dist/token-types.d.ts +2 -0
- package/dist/token-types.js +30 -0
- package/dist/{tokenize-BYl6GvyV.js → tokenize-Ccg58Z_k.js} +79 -96
- package/dist/tokenize.d.ts +97 -2
- package/dist/tokenize.js +1 -2
- package/dist/{value-node-parser-tjY982sG.js → value-node-parser-D0qnA_bD.js} +153 -219
- package/dist/walk.d.ts +3 -2
- package/dist/walk.js +2 -2
- package/package.json +29 -18
- package/dist/tokenize-CDEnYcVG.d.ts +0 -133
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { t as Lexer } from "./tokenize-
|
|
2
|
-
import "./
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
1
|
+
import { t as Lexer } from "./tokenize-Ccg58Z_k.js";
|
|
2
|
+
import "./token-types.js";
|
|
3
|
+
import "./arena-Bsf96CQK.js";
|
|
4
|
+
import { c as str_equals_range, t as is_and_or_not_range } from "./string-utils-DiRRd28d.js";
|
|
5
|
+
import { i as find_colon_at_depth_zero, o as skip_whitespace_and_comments_forward, s as trim_boundaries, t as SelectorParser } from "./parse-selector-CqIpnBrQ.js";
|
|
5
6
|
//#region src/parse-condition.ts
|
|
6
|
-
/** @internal */
|
|
7
7
|
var ConditionParser = class {
|
|
8
8
|
lexer;
|
|
9
9
|
arena;
|
|
@@ -18,12 +18,8 @@ var ConditionParser = class {
|
|
|
18
18
|
this.value_node_parser = value_node_parser;
|
|
19
19
|
this.selector_parser = new SelectorParser(arena, source);
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
this.lexer.pos,
|
|
24
|
-
this.lexer.line,
|
|
25
|
-
this.lexer.column
|
|
26
|
-
];
|
|
21
|
+
seek_to_end(target) {
|
|
22
|
+
target.seek(this.lexer.pos, this.lexer.line, this.lexer.column);
|
|
27
23
|
}
|
|
28
24
|
create_node(type, start, end) {
|
|
29
25
|
return this.arena.create_node(type, start, end - start, this.lexer.token_line, this.lexer.token_column);
|
|
@@ -35,15 +31,14 @@ var ConditionParser = class {
|
|
|
35
31
|
}
|
|
36
32
|
return this.lexer.next_token_fast(false);
|
|
37
33
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
34
|
+
paren_content_end = 0;
|
|
35
|
+
paren_close_end = 0;
|
|
41
36
|
scan_matching_paren() {
|
|
42
37
|
let depth = 1;
|
|
43
38
|
let content_end = this.lexer.pos;
|
|
44
39
|
let close_end = this.lexer.token_end;
|
|
45
40
|
while (this.lexer.pos < this.end && depth > 0) {
|
|
46
|
-
|
|
41
|
+
const token_type = this.next_token();
|
|
47
42
|
if (token_type === 21 || token_type === 2) depth++;
|
|
48
43
|
else if (token_type === 22) {
|
|
49
44
|
depth--;
|
|
@@ -53,42 +48,40 @@ var ConditionParser = class {
|
|
|
53
48
|
}
|
|
54
49
|
} else if (token_type === 26) break;
|
|
55
50
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
depth === 0
|
|
60
|
-
];
|
|
51
|
+
this.paren_content_end = content_end;
|
|
52
|
+
this.paren_close_end = close_end;
|
|
53
|
+
return depth === 0;
|
|
61
54
|
}
|
|
62
55
|
parse_feature_value(start, end) {
|
|
63
56
|
return this.value_node_parser.parse_chain(start, end, this.lexer.line, this.lexer.column);
|
|
64
57
|
}
|
|
65
58
|
wrap_ratio_value(first_node) {
|
|
66
59
|
if (this.arena.get_type(first_node) !== 11) return first_node;
|
|
67
|
-
|
|
60
|
+
const op_node = this.arena.get_next_sibling(first_node);
|
|
68
61
|
if (op_node === 0 || this.arena.get_type(op_node) !== 16) return first_node;
|
|
69
62
|
if (this.arena.get_length(op_node) !== 1) return first_node;
|
|
70
63
|
if (this.source.charCodeAt(this.arena.get_start_offset(op_node)) !== 47) return first_node;
|
|
71
|
-
|
|
64
|
+
const second_node = this.arena.get_next_sibling(op_node);
|
|
72
65
|
if (second_node === 0 || this.arena.get_type(second_node) !== 11) return first_node;
|
|
73
66
|
if (this.arena.get_next_sibling(second_node) !== 0) return first_node;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
67
|
+
const start = this.arena.get_start_offset(first_node);
|
|
68
|
+
const end = this.arena.get_start_offset(second_node) + this.arena.get_length(second_node);
|
|
69
|
+
const ratio_node = this.arena.create_node(58, start, end - start, this.arena.get_start_line(first_node), this.arena.get_start_column(first_node));
|
|
77
70
|
this.arena.set_first_child(ratio_node, first_node);
|
|
78
71
|
this.arena.set_next_sibling(first_node, second_node);
|
|
79
72
|
return ratio_node;
|
|
80
73
|
}
|
|
81
74
|
create_supports_declaration(content_start, content_end, colon_pos) {
|
|
82
|
-
|
|
83
|
-
|
|
75
|
+
const prop_trimmed = trim_boundaries(this.source, content_start, colon_pos);
|
|
76
|
+
const val_trimmed = trim_boundaries(this.source, colon_pos + 1, content_end);
|
|
84
77
|
if (!prop_trimmed) return this.create_node(57, content_start, content_end);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
78
|
+
const decl_start = prop_trimmed[0];
|
|
79
|
+
const decl_end = val_trimmed ? val_trimmed[1] : colon_pos + 1;
|
|
80
|
+
const decl = this.create_node(4, decl_start, decl_end);
|
|
88
81
|
this.arena.set_content_start_delta(decl, 0);
|
|
89
82
|
this.arena.set_content_length(decl, prop_trimmed[1] - prop_trimmed[0]);
|
|
90
83
|
if (val_trimmed) {
|
|
91
|
-
|
|
84
|
+
const value_first = this.parse_feature_value(val_trimmed[0], val_trimmed[1]);
|
|
92
85
|
let value_node;
|
|
93
86
|
if (value_first === 0) value_node = this.arena.create_node(50, val_trimmed[0], 0, this.lexer.token_line, this.lexer.token_column);
|
|
94
87
|
else {
|
|
@@ -97,14 +90,14 @@ var ConditionParser = class {
|
|
|
97
90
|
}
|
|
98
91
|
this.arena.set_first_child(decl, value_node);
|
|
99
92
|
}
|
|
100
|
-
|
|
93
|
+
const supports_decl = this.create_node(57, content_start, content_end);
|
|
101
94
|
this.arena.set_content_start_delta(supports_decl, prop_trimmed[0] - content_start);
|
|
102
95
|
this.arena.set_content_length(supports_decl, prop_trimmed[1] - prop_trimmed[0]);
|
|
103
96
|
this.arena.set_first_child(supports_decl, decl);
|
|
104
97
|
return supports_decl;
|
|
105
98
|
}
|
|
106
99
|
parse_feature_range(feature_start, feature_end, content_start, content_end) {
|
|
107
|
-
|
|
100
|
+
const range_node = this.create_node(39, feature_start, feature_end);
|
|
108
101
|
let first_child = 0;
|
|
109
102
|
let last_child = 0;
|
|
110
103
|
let feature_name_start = -1;
|
|
@@ -113,23 +106,23 @@ var ConditionParser = class {
|
|
|
113
106
|
while (pos < content_end) {
|
|
114
107
|
pos = skip_whitespace_and_comments_forward(this.source, pos, content_end);
|
|
115
108
|
if (pos >= content_end) break;
|
|
116
|
-
|
|
109
|
+
const ch = this.source.charCodeAt(pos);
|
|
117
110
|
if (ch === 60 || ch === 62 || ch === 61) {
|
|
118
|
-
|
|
111
|
+
const op_start = pos++;
|
|
119
112
|
if (pos < content_end && this.source.charCodeAt(pos) === 61) pos++;
|
|
120
|
-
|
|
113
|
+
const op = this.create_node(38, op_start, pos);
|
|
121
114
|
if (first_child === 0) first_child = op;
|
|
122
115
|
else this.arena.set_next_sibling(last_child, op);
|
|
123
116
|
last_child = op;
|
|
124
117
|
} else {
|
|
125
|
-
|
|
118
|
+
const saved = this.lexer.save_position();
|
|
126
119
|
this.lexer.pos = pos;
|
|
127
120
|
this.next_token();
|
|
128
121
|
if (this.lexer.token_type === 1) {
|
|
129
122
|
feature_name_start = this.lexer.token_start;
|
|
130
123
|
feature_name_end = this.lexer.token_end;
|
|
131
124
|
} else {
|
|
132
|
-
|
|
125
|
+
const value_first = this.parse_feature_value(this.lexer.token_start, this.lexer.token_end);
|
|
133
126
|
if (value_first !== 0) {
|
|
134
127
|
if (first_child === 0) first_child = value_first;
|
|
135
128
|
else this.arena.set_next_sibling(last_child, value_first);
|
|
@@ -147,15 +140,6 @@ var ConditionParser = class {
|
|
|
147
140
|
if (first_child !== 0) this.arena.set_first_child(range_node, first_child);
|
|
148
141
|
return range_node;
|
|
149
142
|
}
|
|
150
|
-
/**
|
|
151
|
-
* Parse the content of a media feature — everything between its parentheses, already
|
|
152
|
-
* known by the caller as `[content_start, content_end)`. `feature_start`/`feature_end`
|
|
153
|
-
* are the span of the feature node itself: for a real `@media (min-width: 768px)` feature
|
|
154
|
-
* this includes the surrounding parens (`feature_start < content_start`); for if()'s
|
|
155
|
-
* `media(min-width: 768px)`, media()'s own parens already delimit the content, so callers
|
|
156
|
-
* pass `feature_start === content_start` and `feature_end === content_end`.
|
|
157
|
-
* Returns a MEDIA_FEATURE (name/boolean/name:value) or FEATURE_RANGE (comparison syntax) node.
|
|
158
|
-
*/
|
|
159
143
|
parse_media_feature_content(feature_start, feature_end, content_start, content_end) {
|
|
160
144
|
this.end = content_end;
|
|
161
145
|
let has_comparison = false;
|
|
@@ -163,7 +147,7 @@ var ConditionParser = class {
|
|
|
163
147
|
while (i < content_end) {
|
|
164
148
|
i = skip_whitespace_and_comments_forward(this.source, i, content_end);
|
|
165
149
|
if (i >= content_end) break;
|
|
166
|
-
|
|
150
|
+
const ch = this.source.charCodeAt(i);
|
|
167
151
|
if (ch === 60 || ch === 62 || ch === 61) {
|
|
168
152
|
has_comparison = true;
|
|
169
153
|
break;
|
|
@@ -171,7 +155,7 @@ var ConditionParser = class {
|
|
|
171
155
|
i++;
|
|
172
156
|
}
|
|
173
157
|
if (has_comparison) return this.parse_feature_range(feature_start, feature_end, content_start, content_end);
|
|
174
|
-
|
|
158
|
+
const feature = this.create_node(33, feature_start, feature_end);
|
|
175
159
|
let colon_pos = -1;
|
|
176
160
|
let j = content_start;
|
|
177
161
|
while (j < content_end) {
|
|
@@ -184,20 +168,20 @@ var ConditionParser = class {
|
|
|
184
168
|
j++;
|
|
185
169
|
}
|
|
186
170
|
if (colon_pos === -1) {
|
|
187
|
-
|
|
171
|
+
const trimmed = trim_boundaries(this.source, content_start, content_end);
|
|
188
172
|
if (trimmed) {
|
|
189
173
|
this.arena.set_content_start_delta(feature, trimmed[0] - feature_start);
|
|
190
174
|
this.arena.set_content_length(feature, trimmed[1] - trimmed[0]);
|
|
191
175
|
}
|
|
192
176
|
} else {
|
|
193
|
-
|
|
177
|
+
const name_trimmed = trim_boundaries(this.source, content_start, colon_pos);
|
|
194
178
|
if (name_trimmed) {
|
|
195
179
|
this.arena.set_content_start_delta(feature, name_trimmed[0] - feature_start);
|
|
196
180
|
this.arena.set_content_length(feature, name_trimmed[1] - name_trimmed[0]);
|
|
197
181
|
}
|
|
198
|
-
|
|
182
|
+
const value_trimmed = trim_boundaries(this.source, colon_pos + 1, content_end);
|
|
199
183
|
if (value_trimmed) {
|
|
200
|
-
|
|
184
|
+
const value_first = this.parse_feature_value(value_trimmed[0], value_trimmed[1]);
|
|
201
185
|
if (value_first !== 0) this.arena.set_first_child(feature, this.wrap_ratio_value(value_first));
|
|
202
186
|
}
|
|
203
187
|
}
|
|
@@ -207,9 +191,11 @@ var ConditionParser = class {
|
|
|
207
191
|
this.end = end;
|
|
208
192
|
this.lexer.seek(open_paren_start, line, column);
|
|
209
193
|
this.next_token();
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
194
|
+
const feature_start = this.lexer.token_start;
|
|
195
|
+
const content_start = this.lexer.pos;
|
|
196
|
+
const matched = this.scan_matching_paren();
|
|
197
|
+
const content_end = this.paren_content_end;
|
|
198
|
+
const feature_end = this.paren_close_end;
|
|
213
199
|
if (!matched) return null;
|
|
214
200
|
return this.parse_media_feature_content(feature_start, feature_end, content_start, content_end);
|
|
215
201
|
}
|
|
@@ -217,70 +203,63 @@ var ConditionParser = class {
|
|
|
217
203
|
this.end = end;
|
|
218
204
|
this.lexer.seek(func_start, line, column);
|
|
219
205
|
this.next_token();
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
206
|
+
const func_name_start = this.lexer.token_start;
|
|
207
|
+
const func_name_end = this.lexer.token_end - 1;
|
|
208
|
+
const content_start = this.lexer.token_end;
|
|
209
|
+
this.scan_matching_paren();
|
|
210
|
+
const content_end = this.paren_content_end;
|
|
211
|
+
const func_end = this.paren_close_end;
|
|
212
|
+
const func_node = this.create_node(15, func_start, func_end);
|
|
224
213
|
this.arena.set_content_start_delta(func_node, 0);
|
|
225
|
-
this.arena.set_content_length(func_node,
|
|
214
|
+
this.arena.set_content_length(func_node, func_name_end - func_name_start);
|
|
226
215
|
this.arena.set_value_start_delta(func_node, content_start - func_start);
|
|
227
216
|
this.arena.set_value_length(func_node, content_end - content_start);
|
|
228
|
-
if (
|
|
229
|
-
|
|
217
|
+
if (str_equals_range(this.source, func_name_start, func_name_end, "selector")) {
|
|
218
|
+
const selector_list = this.selector_parser.parse_selector(content_start, content_end, this.lexer.line, this.lexer.column);
|
|
230
219
|
if (selector_list !== null) this.arena.set_first_child(func_node, selector_list);
|
|
231
|
-
} else if (
|
|
232
|
-
|
|
220
|
+
} else if (str_equals_range(this.source, func_name_start, func_name_end, "style")) {
|
|
221
|
+
const decl_child = this.parse_supports_declaration_content(content_start, content_end);
|
|
233
222
|
if (decl_child !== null) this.arena.set_first_child(func_node, decl_child);
|
|
234
223
|
}
|
|
235
224
|
return func_node;
|
|
236
225
|
}
|
|
237
|
-
/**
|
|
238
|
-
* Parse a single `(property: value)` supports declaration from a content range — the
|
|
239
|
-
* `<style-feature>`/`<supports-feature>` grammar shared by `style()`, `@supports (…)`, and
|
|
240
|
-
* `@import … supports(…)`. Returns null if no top-level ':' is found.
|
|
241
|
-
*/
|
|
242
226
|
parse_supports_declaration_content(content_start, content_end) {
|
|
243
|
-
|
|
227
|
+
const colon_pos = find_colon_at_depth_zero(this.source, content_start, content_end);
|
|
244
228
|
if (colon_pos === -1) return null;
|
|
245
229
|
return this.create_supports_declaration(content_start, content_end, colon_pos);
|
|
246
230
|
}
|
|
247
|
-
/**
|
|
248
|
-
* Parse a `<supports-condition>` — the compound and/or/not grammar shared by `@supports`
|
|
249
|
-
* preludes and if()'s `supports(...)` condition function: parenthesized `(property: value)`
|
|
250
|
-
* declarations, `and`/`or`/`not` logical operators, and nested function conditions
|
|
251
|
-
* (`selector()`, `style()`, etc.), chained as flat siblings.
|
|
252
|
-
* `start`/`end` bound the range to scan; the caller has already positioned nothing — this
|
|
253
|
-
* seeks its own lexer, so it's safe to call with any sub-range of the source.
|
|
254
|
-
*/
|
|
255
231
|
parse_supports_condition(start, end, line, column) {
|
|
256
|
-
|
|
232
|
+
const saved_end = this.end;
|
|
257
233
|
this.end = end;
|
|
258
234
|
this.lexer.seek(start, line, column);
|
|
259
|
-
|
|
235
|
+
const nodes = [];
|
|
260
236
|
while (this.lexer.pos < this.end) {
|
|
261
237
|
this.lexer.skip_whitespace_in_range(this.end);
|
|
262
238
|
if (this.lexer.pos >= this.end) break;
|
|
263
239
|
this.next_token();
|
|
264
|
-
|
|
240
|
+
const token_type = this.lexer.token_type;
|
|
265
241
|
if (token_type === 21) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
242
|
+
const feature_start = this.lexer.token_start;
|
|
243
|
+
const content_start = this.lexer.pos;
|
|
244
|
+
const matched = this.scan_matching_paren();
|
|
245
|
+
const content_end = this.paren_content_end;
|
|
246
|
+
const feature_end = this.paren_close_end;
|
|
269
247
|
if (matched) {
|
|
270
|
-
|
|
271
|
-
|
|
248
|
+
const query = this.create_node(36, feature_start, feature_end);
|
|
249
|
+
const trimmed = trim_boundaries(this.source, content_start, content_end);
|
|
272
250
|
if (trimmed) {
|
|
273
251
|
this.arena.set_value_start_delta(query, trimmed[0] - feature_start);
|
|
274
252
|
this.arena.set_value_length(query, trimmed[1] - trimmed[0]);
|
|
275
|
-
|
|
253
|
+
const decl_child = this.parse_supports_declaration_content(trimmed[0], trimmed[1]);
|
|
276
254
|
if (decl_child !== null) this.arena.set_first_child(query, decl_child);
|
|
277
255
|
}
|
|
278
256
|
nodes.push(query);
|
|
279
257
|
}
|
|
280
258
|
} else if (token_type === 1) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
259
|
+
const token_start = this.lexer.token_start;
|
|
260
|
+
const token_end = this.lexer.token_end;
|
|
261
|
+
if (is_and_or_not_range(this.source, token_start, token_end)) {
|
|
262
|
+
const op = this.create_node(38, token_start, token_end);
|
|
284
263
|
nodes.push(op);
|
|
285
264
|
}
|
|
286
265
|
} else if (token_type === 2) nodes.push(this.parse_function_condition(this.lexer.token_start, this.end, this.lexer.token_line, this.lexer.token_column));
|
|
@@ -291,7 +270,6 @@ var ConditionParser = class {
|
|
|
291
270
|
};
|
|
292
271
|
//#endregion
|
|
293
272
|
//#region src/value-node-parser.ts
|
|
294
|
-
/** @internal */
|
|
295
273
|
var ValueNodeParser = class ValueNodeParser {
|
|
296
274
|
lexer;
|
|
297
275
|
arena;
|
|
@@ -314,12 +292,10 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
314
292
|
let first_node = 0;
|
|
315
293
|
let last_node = 0;
|
|
316
294
|
while (this.lexer.pos < this.end) {
|
|
317
|
-
this.lexer.next_token_fast(
|
|
295
|
+
this.lexer.next_token_fast(true);
|
|
318
296
|
if (this.lexer.token_start >= this.end) break;
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
if (token_type === 13) continue;
|
|
322
|
-
let node = this.parse_value_node();
|
|
297
|
+
if (this.lexer.token_type === 26) break;
|
|
298
|
+
const node = this.parse_value_node();
|
|
323
299
|
if (node !== null) {
|
|
324
300
|
if (first_node === 0) first_node = node;
|
|
325
301
|
else this.arena.set_next_sibling(last_node, node);
|
|
@@ -330,9 +306,9 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
330
306
|
return first_node;
|
|
331
307
|
}
|
|
332
308
|
parse_value_node() {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
309
|
+
const token_type = this.lexer.token_type;
|
|
310
|
+
const start = this.lexer.token_start;
|
|
311
|
+
const end = this.lexer.token_end;
|
|
336
312
|
switch (token_type) {
|
|
337
313
|
case 1: return this.create_node(10, start, end);
|
|
338
314
|
case 10: return this.create_node(11, start, end);
|
|
@@ -351,22 +327,24 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
351
327
|
}
|
|
352
328
|
}
|
|
353
329
|
create_node(node_type, start, end) {
|
|
354
|
-
|
|
330
|
+
const node = this.arena.create_node(node_type, start, end - start, this.lexer.token_line, this.lexer.token_column);
|
|
355
331
|
this.arena.set_content_length(node, end - start);
|
|
356
332
|
return node;
|
|
357
333
|
}
|
|
358
334
|
parse_operator_node(start, end) {
|
|
359
|
-
|
|
335
|
+
const ch = this.source.charCodeAt(start);
|
|
360
336
|
if (ch === 43 || ch === 45 || ch === 42 || ch === 47) return this.create_node(16, start, end);
|
|
361
337
|
return null;
|
|
362
338
|
}
|
|
339
|
+
paren_content_end = 0;
|
|
340
|
+
paren_close_end = 0;
|
|
363
341
|
scan_matching_paren(bounded) {
|
|
364
342
|
let depth = 1;
|
|
365
343
|
let content_end = this.lexer.pos;
|
|
366
344
|
let close_end = this.lexer.token_end;
|
|
367
345
|
while ((!bounded || this.lexer.pos < this.end) && depth > 0) {
|
|
368
346
|
this.lexer.next_token_fast(false);
|
|
369
|
-
|
|
347
|
+
const token_type = this.lexer.token_type;
|
|
370
348
|
if (token_type === 26) break;
|
|
371
349
|
if (bounded && this.lexer.token_start >= this.end) break;
|
|
372
350
|
if (token_type === 21 || token_type === 2) depth++;
|
|
@@ -378,30 +356,30 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
378
356
|
}
|
|
379
357
|
}
|
|
380
358
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
depth === 0
|
|
385
|
-
];
|
|
359
|
+
this.paren_content_end = content_end;
|
|
360
|
+
this.paren_close_end = close_end;
|
|
361
|
+
return depth === 0;
|
|
386
362
|
}
|
|
387
363
|
parse_function_node(start, end) {
|
|
388
|
-
|
|
364
|
+
const name_end = end - 1;
|
|
389
365
|
if (str_equals_range(this.source, start, name_end, "if")) return this.parse_if_function_node(start, end);
|
|
390
|
-
|
|
391
|
-
|
|
366
|
+
const is_url = str_equals_range(this.source, start, name_end, "url");
|
|
367
|
+
const node = this.arena.create_node(is_url ? 18 : 15, start, 0, this.lexer.token_line, this.lexer.token_column);
|
|
392
368
|
this.arena.set_content_start_delta(node, 0);
|
|
393
369
|
this.arena.set_content_length(node, name_end - start);
|
|
394
370
|
if (is_url || str_equals_range(this.source, start, name_end, "src")) {
|
|
395
|
-
|
|
371
|
+
const save_pos = this.lexer.save_position();
|
|
396
372
|
this.lexer.next_token_fast(false);
|
|
397
373
|
while (this.lexer.token_type === 13 && this.lexer.pos < this.end) this.lexer.next_token_fast(false);
|
|
398
|
-
|
|
374
|
+
const first_token_type = this.lexer.token_type;
|
|
399
375
|
this.lexer.restore_position(save_pos);
|
|
400
376
|
if (first_token_type === 5) {} else {
|
|
401
377
|
let func_end = end;
|
|
402
|
-
|
|
378
|
+
const content_start = end;
|
|
403
379
|
let content_end = end;
|
|
404
|
-
|
|
380
|
+
const matched = this.scan_matching_paren(false);
|
|
381
|
+
const scanned_content_end = this.paren_content_end;
|
|
382
|
+
const scanned_func_end = this.paren_close_end;
|
|
405
383
|
if (matched) {
|
|
406
384
|
content_end = scanned_content_end;
|
|
407
385
|
func_end = scanned_func_end;
|
|
@@ -416,11 +394,11 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
416
394
|
let last_arg = 0;
|
|
417
395
|
let paren_depth = 1;
|
|
418
396
|
let func_end = end;
|
|
419
|
-
|
|
397
|
+
const content_start = end;
|
|
420
398
|
let content_end = end;
|
|
421
399
|
while (this.lexer.pos < this.end && paren_depth > 0) {
|
|
422
|
-
this.lexer.next_token_fast(
|
|
423
|
-
|
|
400
|
+
this.lexer.next_token_fast(true);
|
|
401
|
+
const token_type = this.lexer.token_type;
|
|
424
402
|
if (token_type === 26) break;
|
|
425
403
|
if (this.lexer.token_start >= this.end) break;
|
|
426
404
|
if (token_type === 22) {
|
|
@@ -431,8 +409,7 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
431
409
|
break;
|
|
432
410
|
}
|
|
433
411
|
}
|
|
434
|
-
|
|
435
|
-
let arg_node = this.parse_value_node();
|
|
412
|
+
const arg_node = this.parse_value_node();
|
|
436
413
|
if (arg_node !== null) {
|
|
437
414
|
if (first_arg === 0) first_arg = arg_node;
|
|
438
415
|
else this.arena.set_next_sibling(last_arg, arg_node);
|
|
@@ -445,32 +422,21 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
445
422
|
if (first_arg !== 0) this.arena.set_first_child(node, first_arg);
|
|
446
423
|
return node;
|
|
447
424
|
}
|
|
448
|
-
/**
|
|
449
|
-
* Parse an if() inline conditional function.
|
|
450
|
-
*
|
|
451
|
-
* Spec grammar (CSS Values Level 5):
|
|
452
|
-
* if( <if-branch>+ )
|
|
453
|
-
* <if-branch> = <if-condition> : <declaration-value>? ;?
|
|
454
|
-
* <if-condition> = style(…) | media(…) | supports(…) | else
|
|
455
|
-
*
|
|
456
|
-
* Each branch becomes an IF_BRANCH child (see the `IfBranch` type in node-types.ts
|
|
457
|
-
* for its shape). Colons/semicolons here are structural separators, not OPERATOR nodes.
|
|
458
|
-
*/
|
|
459
425
|
parse_if_function_node(start, end) {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
426
|
+
const name_end = end - 1;
|
|
427
|
+
const save_line = this.lexer.token_line;
|
|
428
|
+
const save_col = this.lexer.token_column;
|
|
429
|
+
const node = this.arena.create_node(15, start, 0, save_line, save_col);
|
|
464
430
|
this.arena.set_content_start_delta(node, 0);
|
|
465
431
|
this.arena.set_content_length(node, name_end - start);
|
|
466
|
-
|
|
432
|
+
const branches = [];
|
|
467
433
|
let func_end = end;
|
|
468
|
-
|
|
434
|
+
const content_start = end;
|
|
469
435
|
let content_end = end;
|
|
470
436
|
let if_closed = false;
|
|
471
437
|
while (this.lexer.pos < this.end && !if_closed) {
|
|
472
438
|
this.lexer.next_token_fast(false);
|
|
473
|
-
|
|
439
|
+
const tt = this.lexer.token_type;
|
|
474
440
|
if (tt === 26) break;
|
|
475
441
|
if (this.lexer.token_start >= this.end) break;
|
|
476
442
|
if (tt === 22) {
|
|
@@ -479,16 +445,16 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
479
445
|
break;
|
|
480
446
|
}
|
|
481
447
|
if (tt === 13 || tt === 17 || tt === 16) continue;
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
448
|
+
const branch_start = this.lexer.token_start;
|
|
449
|
+
const branch_line = this.lexer.token_line;
|
|
450
|
+
const branch_col = this.lexer.token_column;
|
|
451
|
+
const condition_node = this.parse_if_condition();
|
|
486
452
|
if (condition_node === null) continue;
|
|
487
|
-
|
|
453
|
+
const condition_end_pos = this.arena.get_start_offset(condition_node) + this.arena.get_length(condition_node);
|
|
488
454
|
let colon_found = false;
|
|
489
455
|
while (this.lexer.pos < this.end) {
|
|
490
456
|
this.lexer.next_token_fast(false);
|
|
491
|
-
|
|
457
|
+
const t = this.lexer.token_type;
|
|
492
458
|
if (t === 26) break;
|
|
493
459
|
if (this.lexer.token_start >= this.end) break;
|
|
494
460
|
if (t === 13) continue;
|
|
@@ -503,14 +469,14 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
503
469
|
break;
|
|
504
470
|
}
|
|
505
471
|
}
|
|
506
|
-
|
|
472
|
+
const value_tokens = [];
|
|
507
473
|
let value_start = -1;
|
|
508
474
|
let value_last_end = condition_end_pos;
|
|
509
475
|
let value_line = 0;
|
|
510
476
|
let value_col = 0;
|
|
511
477
|
if (colon_found && !if_closed) while (this.lexer.pos < this.end) {
|
|
512
478
|
this.lexer.next_token_fast(false);
|
|
513
|
-
|
|
479
|
+
const t = this.lexer.token_type;
|
|
514
480
|
if (t === 26) break;
|
|
515
481
|
if (this.lexer.token_start >= this.end) break;
|
|
516
482
|
if (t === 13) continue;
|
|
@@ -521,9 +487,9 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
521
487
|
if_closed = true;
|
|
522
488
|
break;
|
|
523
489
|
}
|
|
524
|
-
|
|
490
|
+
const vnode = this.parse_value_node();
|
|
525
491
|
if (vnode !== null) {
|
|
526
|
-
|
|
492
|
+
const ns = this.arena.get_start_offset(vnode);
|
|
527
493
|
if (value_start === -1) {
|
|
528
494
|
value_start = ns;
|
|
529
495
|
value_line = this.arena.get_start_line(vnode);
|
|
@@ -538,15 +504,15 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
538
504
|
value_node = this.arena.create_node(50, value_start, value_last_end - value_start, value_line, value_col);
|
|
539
505
|
this.arena.append_children(value_node, value_tokens);
|
|
540
506
|
}
|
|
541
|
-
|
|
542
|
-
|
|
507
|
+
const branch_end = value_node === null ? condition_end_pos : value_last_end;
|
|
508
|
+
const branch_node = this.arena.create_node(59, branch_start, branch_end - branch_start, branch_line, branch_col);
|
|
543
509
|
this.arena.set_content_start_delta(branch_node, 0);
|
|
544
510
|
this.arena.set_content_length(branch_node, condition_end_pos - branch_start);
|
|
545
511
|
if (value_start !== -1) {
|
|
546
512
|
this.arena.set_value_start_delta(branch_node, value_start - branch_start);
|
|
547
513
|
this.arena.set_value_length(branch_node, value_last_end - value_start);
|
|
548
514
|
}
|
|
549
|
-
|
|
515
|
+
const branch_children = [condition_node];
|
|
550
516
|
if (value_node !== null) branch_children.push(value_node);
|
|
551
517
|
this.arena.append_children(branch_node, branch_children);
|
|
552
518
|
branches.push(branch_node);
|
|
@@ -557,9 +523,6 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
557
523
|
this.arena.append_children(node, branches);
|
|
558
524
|
return node;
|
|
559
525
|
}
|
|
560
|
-
is_and_or_not(str) {
|
|
561
|
-
return str_equals("and", str) || str_equals("or", str) || str_equals("not", str);
|
|
562
|
-
}
|
|
563
526
|
next_significant_token() {
|
|
564
527
|
while (this.lexer.pos < this.end) {
|
|
565
528
|
this.lexer.next_token_fast(false);
|
|
@@ -569,37 +532,25 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
569
532
|
}
|
|
570
533
|
return 26;
|
|
571
534
|
}
|
|
572
|
-
/**
|
|
573
|
-
* Parse an if()-branch condition:
|
|
574
|
-
* <if-condition> = <boolean-expr[ <if-test> ]> | else
|
|
575
|
-
* <if-test> = style(…) | media(…) | supports(…)
|
|
576
|
-
* i.e. a single test function, the bare "else" identifier, or those test functions
|
|
577
|
-
* combined with not/and/or (e.g. "not style(--x: 1)", "style(--a: 1) and media(width > 600px)").
|
|
578
|
-
* Called with the lexer's current token already positioned at the condition's first token.
|
|
579
|
-
* A simple single-function/"else" condition returns that node directly, unwrapped (matching
|
|
580
|
-
* prior behavior); a compound not/and/or condition wraps the flat operator/function chain in
|
|
581
|
-
* an IF_CONDITION node so IfBranch.condition/.value (single first_child/next_sibling hops)
|
|
582
|
-
* still see exactly one node for "the condition".
|
|
583
|
-
*/
|
|
584
535
|
parse_if_condition() {
|
|
585
536
|
if (this.lexer.token_type === 1) {
|
|
586
|
-
|
|
587
|
-
if (str_equals("else", text)) return this.parse_value_node();
|
|
537
|
+
if (str_equals_range(this.source, this.lexer.token_start, this.lexer.token_end, "else")) return this.parse_value_node();
|
|
588
538
|
}
|
|
589
539
|
let first = 0;
|
|
590
540
|
let last = 0;
|
|
591
541
|
let component_count = 0;
|
|
592
542
|
let compound = false;
|
|
593
543
|
for (;;) {
|
|
594
|
-
|
|
544
|
+
const tt = this.lexer.token_type;
|
|
595
545
|
let component = null;
|
|
596
546
|
let is_operator = false;
|
|
597
547
|
if (tt === 2) component = this.parse_if_condition_function(this.lexer.token_start, this.lexer.token_end);
|
|
598
548
|
else if (tt === 1) {
|
|
599
|
-
|
|
600
|
-
|
|
549
|
+
const token_start = this.lexer.token_start;
|
|
550
|
+
const token_end = this.lexer.token_end;
|
|
551
|
+
if (is_and_or_not_range(this.source, token_start, token_end)) {
|
|
601
552
|
is_operator = true;
|
|
602
|
-
component = this.arena.create_node(38,
|
|
553
|
+
component = this.arena.create_node(38, token_start, token_end - token_start, this.lexer.token_line, this.lexer.token_column);
|
|
603
554
|
} else component = this.parse_value_node();
|
|
604
555
|
} else component = this.parse_value_node();
|
|
605
556
|
if (component !== null) {
|
|
@@ -609,15 +560,14 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
609
560
|
last = component;
|
|
610
561
|
}
|
|
611
562
|
if (tt !== 2 && !is_operator) break;
|
|
612
|
-
|
|
613
|
-
|
|
563
|
+
const saved = this.lexer.save_position();
|
|
564
|
+
const next_tt = this.next_significant_token();
|
|
614
565
|
if (next_tt === 2) {
|
|
615
566
|
compound = true;
|
|
616
567
|
continue;
|
|
617
568
|
}
|
|
618
569
|
if (next_tt === 1) {
|
|
619
|
-
|
|
620
|
-
if (this.is_and_or_not(text)) {
|
|
570
|
+
if (is_and_or_not_range(this.source, this.lexer.token_start, this.lexer.token_end)) {
|
|
621
571
|
compound = true;
|
|
622
572
|
continue;
|
|
623
573
|
}
|
|
@@ -627,72 +577,57 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
627
577
|
}
|
|
628
578
|
if (first === 0) return null;
|
|
629
579
|
if (component_count === 1 && !compound) return first;
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
580
|
+
const wrapper_start = this.arena.get_start_offset(first);
|
|
581
|
+
const last_sibling = this.arena.get_last_sibling(first);
|
|
582
|
+
const wrapper_end = this.arena.get_start_offset(last_sibling) + this.arena.get_length(last_sibling);
|
|
583
|
+
const wrapper = this.arena.create_node(60, wrapper_start, wrapper_end - wrapper_start, this.arena.get_start_line(first), this.arena.get_start_column(first));
|
|
634
584
|
this.arena.set_first_child(wrapper, first);
|
|
635
585
|
return wrapper;
|
|
636
586
|
}
|
|
637
|
-
/**
|
|
638
|
-
* Parse a condition function inside if() — style(), supports(), or media(). Content parsing
|
|
639
|
-
* is delegated to the shared ConditionParser (see parse-condition.ts), so these produce the
|
|
640
|
-
* same node shapes real `@supports`/`@media` conditions do:
|
|
641
|
-
* style()/supports() → SUPPORTS_DECLARATION(s) — supports() gets the full compound
|
|
642
|
-
* <supports-condition> grammar (and/or/not, nested conditions), same as `@supports`.
|
|
643
|
-
* media() → a single MEDIA_FEATURE or FEATURE_RANGE (comparison syntax), same as `@media`.
|
|
644
|
-
* anything else → generic value nodes, as before.
|
|
645
|
-
*
|
|
646
|
-
* Called with the current token at TOKEN_FUNCTION (the '(' already consumed).
|
|
647
|
-
* @param func_start Offset of the function name's first char.
|
|
648
|
-
* @param token_end Offset right after '(' (== lexer.token_end here).
|
|
649
|
-
*/
|
|
650
587
|
parse_if_condition_function(func_start, token_end) {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
let content_start = token_end;
|
|
588
|
+
const func_name_end = token_end - 1;
|
|
589
|
+
const func_line = this.lexer.token_line;
|
|
590
|
+
const func_col = this.lexer.token_column;
|
|
591
|
+
const content_start = token_end;
|
|
656
592
|
let content_end = content_start;
|
|
657
593
|
let func_end = content_start;
|
|
658
|
-
|
|
594
|
+
const matched = this.scan_matching_paren(true);
|
|
595
|
+
const scanned_content_end = this.paren_content_end;
|
|
596
|
+
const scanned_func_end = this.paren_close_end;
|
|
659
597
|
if (matched) {
|
|
660
598
|
content_end = scanned_content_end;
|
|
661
599
|
func_end = scanned_func_end;
|
|
662
600
|
}
|
|
663
|
-
|
|
601
|
+
const func_node = this.arena.create_node(15, func_start, func_end - func_start, func_line, func_col);
|
|
664
602
|
this.arena.set_content_start_delta(func_node, 0);
|
|
665
603
|
this.arena.set_content_length(func_node, func_name_end - func_start);
|
|
666
604
|
this.arena.set_value_start_delta(func_node, content_start - func_start);
|
|
667
605
|
this.arena.set_value_length(func_node, content_end - content_start);
|
|
668
606
|
let child_nodes = [];
|
|
669
|
-
if (
|
|
670
|
-
|
|
607
|
+
if (str_equals_range(this.source, func_start, func_name_end, "style")) {
|
|
608
|
+
const decl = this.condition_parser.parse_supports_declaration_content(content_start, content_end);
|
|
671
609
|
if (decl === null) child_nodes = this.condition_parser.parse_supports_condition(content_start, content_end, func_line, func_col);
|
|
672
610
|
else child_nodes = [decl];
|
|
673
|
-
} else if (
|
|
674
|
-
|
|
611
|
+
} else if (str_equals_range(this.source, func_start, func_name_end, "supports")) {
|
|
612
|
+
const decl = this.condition_parser.parse_supports_declaration_content(content_start, content_end);
|
|
675
613
|
if (decl === null) child_nodes = this.condition_parser.parse_supports_condition(content_start, content_end, func_line, func_col);
|
|
676
614
|
else child_nodes = [decl];
|
|
677
|
-
} else if (
|
|
615
|
+
} else if (str_equals_range(this.source, func_start, func_name_end, "media")) child_nodes = [this.condition_parser.parse_media_feature_content(content_start, content_end, content_start, content_end)];
|
|
678
616
|
else child_nodes = this.parse_value_nodes_in_range(content_start, content_end);
|
|
679
617
|
this.arena.append_children(func_node, child_nodes);
|
|
680
618
|
return func_node;
|
|
681
619
|
}
|
|
682
|
-
/** Parse value tokens in a source sub-range using save/restore to protect lexer state. */
|
|
683
620
|
parse_value_nodes_in_range(start, end) {
|
|
684
|
-
|
|
685
|
-
|
|
621
|
+
const saved_end = this.end;
|
|
622
|
+
const saved_pos = this.lexer.save_position();
|
|
686
623
|
this.end = end;
|
|
687
624
|
this.lexer.seek(start, this.lexer.line, this.lexer.column);
|
|
688
|
-
|
|
625
|
+
const nodes = [];
|
|
689
626
|
while (this.lexer.pos < this.end) {
|
|
690
|
-
this.lexer.next_token_fast(
|
|
627
|
+
this.lexer.next_token_fast(true);
|
|
691
628
|
if (this.lexer.token_start >= this.end) break;
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
if (token_type === 13) continue;
|
|
695
|
-
let node = this.parse_value_node();
|
|
629
|
+
if (this.lexer.token_type === 26) break;
|
|
630
|
+
const node = this.parse_value_node();
|
|
696
631
|
if (node !== null) nodes.push(node);
|
|
697
632
|
}
|
|
698
633
|
this.lexer.restore_position(saved_pos);
|
|
@@ -700,14 +635,14 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
700
635
|
return nodes;
|
|
701
636
|
}
|
|
702
637
|
parse_parenthesis_node(start, end) {
|
|
703
|
-
|
|
638
|
+
const node = this.arena.create_node(17, start, 0, this.lexer.token_line, this.lexer.token_column);
|
|
704
639
|
let first_child = 0;
|
|
705
640
|
let last_child = 0;
|
|
706
641
|
let paren_depth = 1;
|
|
707
642
|
let paren_end = end;
|
|
708
643
|
while (this.lexer.pos < this.end && paren_depth > 0) {
|
|
709
|
-
this.lexer.next_token_fast(
|
|
710
|
-
|
|
644
|
+
this.lexer.next_token_fast(true);
|
|
645
|
+
const token_type = this.lexer.token_type;
|
|
711
646
|
if (token_type === 26) break;
|
|
712
647
|
if (this.lexer.token_start >= this.end) break;
|
|
713
648
|
if (token_type === 22) {
|
|
@@ -717,8 +652,7 @@ var ValueNodeParser = class ValueNodeParser {
|
|
|
717
652
|
break;
|
|
718
653
|
}
|
|
719
654
|
}
|
|
720
|
-
|
|
721
|
-
let child_node = this.parse_value_node();
|
|
655
|
+
const child_node = this.parse_value_node();
|
|
722
656
|
if (child_node !== null) {
|
|
723
657
|
if (first_child === 0) first_child = child_node;
|
|
724
658
|
else this.arena.set_next_sibling(last_child, child_node);
|