@projectwallace/css-parser 0.6.7 → 0.7.1
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/dist/arena.d.ts +36 -91
- package/dist/arena.js +280 -0
- package/dist/char-types.js +55 -0
- package/dist/constants.d.ts +1 -0
- package/dist/css-node.d.ts +43 -5
- package/dist/css-node.js +455 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -24
- package/dist/lexer.d.ts +1 -37
- package/dist/{lexer-CtBKgfVv.js → lexer.js} +3 -81
- package/dist/parse-anplusb.d.ts +0 -20
- package/dist/parse-anplusb.js +28 -30
- package/dist/parse-atrule-prelude.d.ts +0 -25
- package/dist/parse-atrule-prelude.js +36 -42
- package/dist/parse-selector.d.ts +0 -30
- package/dist/parse-selector.js +64 -66
- package/dist/parse-utils.d.ts +0 -40
- package/dist/parse-utils.js +92 -0
- package/dist/parse-value.d.ts +0 -16
- package/dist/parse-value.js +50 -49
- package/dist/parse.d.ts +0 -27
- package/dist/parse.js +96 -73
- package/dist/string-utils.d.ts +0 -6
- package/dist/string-utils.js +63 -0
- package/dist/token-types.js +28 -0
- package/dist/tokenize.js +2 -1
- package/dist/walk.js +21 -0
- package/package.json +8 -10
- package/dist/css-node-GOEvp2OO.js +0 -876
package/dist/parse.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { CSSDataArena } from './arena';
|
|
2
1
|
import { CSSNode } from './css-node';
|
|
3
2
|
export interface ParserOptions {
|
|
4
3
|
skip_comments?: boolean;
|
|
@@ -6,31 +5,6 @@ export interface ParserOptions {
|
|
|
6
5
|
parse_selectors?: boolean;
|
|
7
6
|
parse_atrule_preludes?: boolean;
|
|
8
7
|
}
|
|
9
|
-
export declare class Parser {
|
|
10
|
-
private source;
|
|
11
|
-
private lexer;
|
|
12
|
-
private arena;
|
|
13
|
-
private value_parser;
|
|
14
|
-
private selector_parser;
|
|
15
|
-
private prelude_parser;
|
|
16
|
-
private parse_values_enabled;
|
|
17
|
-
private parse_selectors_enabled;
|
|
18
|
-
private parse_atrule_preludes_enabled;
|
|
19
|
-
constructor(source: string, options?: ParserOptions);
|
|
20
|
-
get_arena(): CSSDataArena;
|
|
21
|
-
get_source(): string;
|
|
22
|
-
private next_token;
|
|
23
|
-
private peek_type;
|
|
24
|
-
private is_eof;
|
|
25
|
-
parse(): CSSNode;
|
|
26
|
-
private parse_rule;
|
|
27
|
-
private parse_style_rule;
|
|
28
|
-
private parse_selector;
|
|
29
|
-
private parse_declaration;
|
|
30
|
-
private parse_atrule;
|
|
31
|
-
private atrule_has_declarations;
|
|
32
|
-
private atrule_is_conditional;
|
|
33
|
-
}
|
|
34
8
|
/**
|
|
35
9
|
* Parse CSS and return an AST
|
|
36
10
|
* @param source - The CSS source code to parse
|
|
@@ -38,4 +12,3 @@ export declare class Parser {
|
|
|
38
12
|
* @returns The root CSSNode of the AST
|
|
39
13
|
*/
|
|
40
14
|
export declare function parse(source: string, options?: ParserOptions): CSSNode;
|
|
41
|
-
export { NODE_STYLESHEET, NODE_STYLE_RULE, NODE_AT_RULE, NODE_DECLARATION, NODE_SELECTOR, NODE_COMMENT, NODE_BLOCK, NODE_VALUE_KEYWORD, NODE_VALUE_NUMBER, NODE_VALUE_DIMENSION, NODE_VALUE_STRING, NODE_VALUE_COLOR, NODE_VALUE_FUNCTION, NODE_VALUE_OPERATOR, NODE_VALUE_PARENTHESIS, NODE_SELECTOR_LIST, NODE_SELECTOR_TYPE, NODE_SELECTOR_CLASS, NODE_SELECTOR_ID, NODE_SELECTOR_ATTRIBUTE, NODE_SELECTOR_PSEUDO_CLASS, NODE_SELECTOR_PSEUDO_ELEMENT, NODE_SELECTOR_COMBINATOR, NODE_SELECTOR_UNIVERSAL, NODE_SELECTOR_NESTING, NODE_SELECTOR_NTH, NODE_SELECTOR_NTH_OF, NODE_SELECTOR_LANG, NODE_PRELUDE_MEDIA_QUERY, NODE_PRELUDE_MEDIA_FEATURE, NODE_PRELUDE_MEDIA_TYPE, NODE_PRELUDE_CONTAINER_QUERY, NODE_PRELUDE_SUPPORTS_QUERY, NODE_PRELUDE_LAYER_NAME, NODE_PRELUDE_IDENTIFIER, NODE_PRELUDE_OPERATOR, NODE_PRELUDE_IMPORT_URL, NODE_PRELUDE_IMPORT_LAYER, NODE_PRELUDE_IMPORT_SUPPORTS, FLAG_IMPORTANT, } from './arena';
|
package/dist/parse.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { Lexer } from './lexer.js';
|
|
2
|
+
import { CSSDataArena, STYLESHEET, STYLE_RULE, FLAG_HAS_BLOCK, BLOCK, FLAG_HAS_DECLARATIONS, SELECTOR_LIST, DECLARATION, FLAG_VENDOR_PREFIXED, FLAG_IMPORTANT, AT_RULE } from './arena.js';
|
|
3
|
+
import { CSSNode } from './css-node.js';
|
|
4
4
|
import { ValueParser } from './parse-value.js';
|
|
5
5
|
import { SelectorParser } from './parse-selector.js';
|
|
6
6
|
import { AtRulePreludeParser } from './parse-atrule-prelude.js';
|
|
7
|
+
import { TOKEN_EOF, TOKEN_AT_KEYWORD, TOKEN_LEFT_BRACE, TOKEN_RIGHT_BRACE, TOKEN_IDENT, TOKEN_COLON, TOKEN_SEMICOLON, TOKEN_DELIM } from './token-types.js';
|
|
8
|
+
import { is_vendor_prefixed } from './string-utils.js';
|
|
9
|
+
import { trim_boundaries } from './parse-utils.js';
|
|
7
10
|
|
|
8
11
|
let DECLARATION_AT_RULES = /* @__PURE__ */ new Set(["font-face", "font-feature-values", "page", "property", "counter-style"]);
|
|
9
12
|
let CONDITIONAL_AT_RULES = /* @__PURE__ */ new Set(["media", "supports", "container", "layer", "nest"]);
|
|
@@ -54,20 +57,23 @@ class Parser {
|
|
|
54
57
|
// Parse the entire stylesheet and return the root CSSNode
|
|
55
58
|
parse() {
|
|
56
59
|
this.next_token();
|
|
57
|
-
let stylesheet = this.arena.create_node(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
let stylesheet = this.arena.create_node(
|
|
61
|
+
STYLESHEET,
|
|
62
|
+
0,
|
|
63
|
+
this.source.length,
|
|
64
|
+
1,
|
|
65
|
+
1
|
|
66
|
+
);
|
|
67
|
+
let rules = [];
|
|
63
68
|
while (!this.is_eof()) {
|
|
64
69
|
let rule = this.parse_rule();
|
|
65
70
|
if (rule !== null) {
|
|
66
|
-
|
|
71
|
+
rules.push(rule);
|
|
67
72
|
} else {
|
|
68
73
|
this.next_token();
|
|
69
74
|
}
|
|
70
75
|
}
|
|
76
|
+
this.arena.append_children(stylesheet, rules);
|
|
71
77
|
return new CSSNode(this.arena, this.source, stylesheet);
|
|
72
78
|
}
|
|
73
79
|
// Parse a rule (style rule or at-rule)
|
|
@@ -86,14 +92,15 @@ class Parser {
|
|
|
86
92
|
let rule_start = this.lexer.token_start;
|
|
87
93
|
let rule_line = this.lexer.token_line;
|
|
88
94
|
let rule_column = this.lexer.token_column;
|
|
89
|
-
let style_rule = this.arena.create_node(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
let style_rule = this.arena.create_node(
|
|
96
|
+
STYLE_RULE,
|
|
97
|
+
rule_start,
|
|
98
|
+
0,
|
|
99
|
+
// length unknown yet
|
|
100
|
+
rule_line,
|
|
101
|
+
rule_column
|
|
102
|
+
);
|
|
93
103
|
let selector = this.parse_selector();
|
|
94
|
-
if (selector !== null) {
|
|
95
|
-
this.arena.append_child(style_rule, selector);
|
|
96
|
-
}
|
|
97
104
|
if (this.peek_type() !== TOKEN_LEFT_BRACE) {
|
|
98
105
|
return null;
|
|
99
106
|
}
|
|
@@ -102,18 +109,22 @@ class Parser {
|
|
|
102
109
|
this.arena.set_flag(style_rule, FLAG_HAS_BLOCK);
|
|
103
110
|
let block_line = this.lexer.token_line;
|
|
104
111
|
let block_column = this.lexer.token_column;
|
|
105
|
-
let block_node = this.arena.create_node(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
let block_node = this.arena.create_node(
|
|
113
|
+
BLOCK,
|
|
114
|
+
block_start,
|
|
115
|
+
0,
|
|
116
|
+
// length unknown yet
|
|
117
|
+
block_line,
|
|
118
|
+
block_column
|
|
119
|
+
);
|
|
120
|
+
let block_children = [];
|
|
110
121
|
while (!this.is_eof()) {
|
|
111
122
|
let token_type = this.peek_type();
|
|
112
123
|
if (token_type === TOKEN_RIGHT_BRACE) break;
|
|
113
124
|
if (token_type === TOKEN_AT_KEYWORD) {
|
|
114
125
|
let nested_at_rule = this.parse_atrule();
|
|
115
126
|
if (nested_at_rule !== null) {
|
|
116
|
-
|
|
127
|
+
block_children.push(nested_at_rule);
|
|
117
128
|
} else {
|
|
118
129
|
this.next_token();
|
|
119
130
|
}
|
|
@@ -122,12 +133,12 @@ class Parser {
|
|
|
122
133
|
let declaration = this.parse_declaration();
|
|
123
134
|
if (declaration !== null) {
|
|
124
135
|
this.arena.set_flag(style_rule, FLAG_HAS_DECLARATIONS);
|
|
125
|
-
|
|
136
|
+
block_children.push(declaration);
|
|
126
137
|
continue;
|
|
127
138
|
}
|
|
128
139
|
let nested_rule = this.parse_style_rule();
|
|
129
140
|
if (nested_rule !== null) {
|
|
130
|
-
|
|
141
|
+
block_children.push(nested_rule);
|
|
131
142
|
} else {
|
|
132
143
|
this.next_token();
|
|
133
144
|
}
|
|
@@ -140,9 +151,14 @@ class Parser {
|
|
|
140
151
|
this.next_token();
|
|
141
152
|
}
|
|
142
153
|
this.arena.set_length(block_node, block_end - block_start);
|
|
143
|
-
this.arena.
|
|
144
|
-
this.arena.set_start_offset(style_rule, rule_start);
|
|
154
|
+
this.arena.append_children(block_node, block_children);
|
|
145
155
|
this.arena.set_length(style_rule, rule_end - rule_start);
|
|
156
|
+
let style_rule_children = [];
|
|
157
|
+
if (selector !== null) {
|
|
158
|
+
style_rule_children.push(selector);
|
|
159
|
+
}
|
|
160
|
+
style_rule_children.push(block_node);
|
|
161
|
+
this.arena.append_children(style_rule, style_rule_children);
|
|
146
162
|
return style_rule;
|
|
147
163
|
}
|
|
148
164
|
// Parse a selector (everything before '{')
|
|
@@ -162,12 +178,13 @@ class Parser {
|
|
|
162
178
|
return selectorNode;
|
|
163
179
|
}
|
|
164
180
|
}
|
|
165
|
-
let selector = this.arena.create_node(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
181
|
+
let selector = this.arena.create_node(
|
|
182
|
+
SELECTOR_LIST,
|
|
183
|
+
selector_start,
|
|
184
|
+
last_end - selector_start,
|
|
185
|
+
selector_line,
|
|
186
|
+
selector_column
|
|
187
|
+
);
|
|
171
188
|
return selector;
|
|
172
189
|
}
|
|
173
190
|
// Parse a declaration: property: value;
|
|
@@ -186,12 +203,15 @@ class Parser {
|
|
|
186
203
|
return null;
|
|
187
204
|
}
|
|
188
205
|
this.next_token();
|
|
189
|
-
let declaration = this.arena.create_node(
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
206
|
+
let declaration = this.arena.create_node(
|
|
207
|
+
DECLARATION,
|
|
208
|
+
prop_start,
|
|
209
|
+
0,
|
|
210
|
+
// length unknown yet
|
|
211
|
+
decl_line,
|
|
212
|
+
decl_column
|
|
213
|
+
);
|
|
214
|
+
this.arena.set_content_start_delta(declaration, 0);
|
|
195
215
|
this.arena.set_content_length(declaration, prop_end - prop_start);
|
|
196
216
|
if (is_vendor_prefixed(this.source, prop_start, prop_end)) {
|
|
197
217
|
this.arena.set_flag(declaration, FLAG_VENDOR_PREFIXED);
|
|
@@ -223,17 +243,11 @@ class Parser {
|
|
|
223
243
|
}
|
|
224
244
|
let trimmed = trim_boundaries(this.source, value_start, value_end);
|
|
225
245
|
if (trimmed) {
|
|
226
|
-
this.arena.
|
|
246
|
+
this.arena.set_value_start_delta(declaration, trimmed[0] - prop_start);
|
|
227
247
|
this.arena.set_value_length(declaration, trimmed[1] - trimmed[0]);
|
|
228
248
|
if (this.parse_values_enabled && this.value_parser) {
|
|
229
249
|
let valueNodes = this.value_parser.parse_value(trimmed[0], trimmed[1]);
|
|
230
|
-
|
|
231
|
-
this.arena.set_first_child(declaration, valueNodes[0]);
|
|
232
|
-
this.arena.set_last_child(declaration, valueNodes[valueNodes.length - 1]);
|
|
233
|
-
for (let i = 0; i < valueNodes.length - 1; i++) {
|
|
234
|
-
this.arena.set_next_sibling(valueNodes[i], valueNodes[i + 1]);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
250
|
+
this.arena.append_children(declaration, valueNodes);
|
|
237
251
|
}
|
|
238
252
|
}
|
|
239
253
|
if (has_important) {
|
|
@@ -254,32 +268,35 @@ class Parser {
|
|
|
254
268
|
let at_rule_start = this.lexer.token_start;
|
|
255
269
|
let at_rule_line = this.lexer.token_line;
|
|
256
270
|
let at_rule_column = this.lexer.token_column;
|
|
257
|
-
let at_rule_name = this.source.substring(this.lexer.token_start + 1, this.lexer.token_end);
|
|
258
271
|
let name_start = this.lexer.token_start + 1;
|
|
259
|
-
let name_length =
|
|
272
|
+
let name_length = this.lexer.token_end - name_start;
|
|
273
|
+
let at_rule_name = this.source.substring(name_start, this.lexer.token_end);
|
|
260
274
|
this.next_token();
|
|
261
|
-
let at_rule = this.arena.create_node(
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
275
|
+
let at_rule = this.arena.create_node(
|
|
276
|
+
AT_RULE,
|
|
277
|
+
at_rule_start,
|
|
278
|
+
0,
|
|
279
|
+
// length unknown yet
|
|
280
|
+
at_rule_line,
|
|
281
|
+
at_rule_column
|
|
282
|
+
);
|
|
283
|
+
this.arena.set_content_start_delta(at_rule, name_start - at_rule_start);
|
|
267
284
|
this.arena.set_content_length(at_rule, name_length);
|
|
268
285
|
let prelude_start = this.lexer.token_start;
|
|
269
286
|
let prelude_end = prelude_start;
|
|
270
|
-
while (!this.is_eof()
|
|
287
|
+
while (!this.is_eof()) {
|
|
288
|
+
let token_type = this.peek_type();
|
|
289
|
+
if (token_type === TOKEN_LEFT_BRACE || token_type === TOKEN_SEMICOLON) break;
|
|
271
290
|
prelude_end = this.lexer.token_end;
|
|
272
291
|
this.next_token();
|
|
273
292
|
}
|
|
274
293
|
let trimmed = trim_boundaries(this.source, prelude_start, prelude_end);
|
|
294
|
+
let prelude_nodes = [];
|
|
275
295
|
if (trimmed) {
|
|
276
|
-
this.arena.
|
|
296
|
+
this.arena.set_value_start_delta(at_rule, trimmed[0] - at_rule_start);
|
|
277
297
|
this.arena.set_value_length(at_rule, trimmed[1] - trimmed[0]);
|
|
278
298
|
if (this.prelude_parser) {
|
|
279
|
-
|
|
280
|
-
for (let prelude_node of prelude_nodes) {
|
|
281
|
-
this.arena.append_child(at_rule, prelude_node);
|
|
282
|
-
}
|
|
299
|
+
prelude_nodes = this.prelude_parser.parse_prelude(at_rule_name, trimmed[0], trimmed[1], at_rule_line, at_rule_column);
|
|
283
300
|
}
|
|
284
301
|
}
|
|
285
302
|
let last_end = this.lexer.token_end;
|
|
@@ -289,20 +306,24 @@ class Parser {
|
|
|
289
306
|
this.arena.set_flag(at_rule, FLAG_HAS_BLOCK);
|
|
290
307
|
let block_line = this.lexer.token_line;
|
|
291
308
|
let block_column = this.lexer.token_column;
|
|
292
|
-
let block_node = this.arena.create_node(
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
309
|
+
let block_node = this.arena.create_node(
|
|
310
|
+
BLOCK,
|
|
311
|
+
block_start,
|
|
312
|
+
0,
|
|
313
|
+
// length unknown yet
|
|
314
|
+
block_line,
|
|
315
|
+
block_column
|
|
316
|
+
);
|
|
297
317
|
let has_declarations = this.atrule_has_declarations(at_rule_name);
|
|
298
318
|
let is_conditional = this.atrule_is_conditional(at_rule_name);
|
|
319
|
+
let block_children = [];
|
|
299
320
|
if (has_declarations) {
|
|
300
321
|
while (!this.is_eof()) {
|
|
301
322
|
let token_type = this.peek_type();
|
|
302
323
|
if (token_type === TOKEN_RIGHT_BRACE) break;
|
|
303
324
|
let declaration = this.parse_declaration();
|
|
304
325
|
if (declaration !== null) {
|
|
305
|
-
|
|
326
|
+
block_children.push(declaration);
|
|
306
327
|
} else {
|
|
307
328
|
this.next_token();
|
|
308
329
|
}
|
|
@@ -314,7 +335,7 @@ class Parser {
|
|
|
314
335
|
if (token_type === TOKEN_AT_KEYWORD) {
|
|
315
336
|
let nested_at_rule = this.parse_atrule();
|
|
316
337
|
if (nested_at_rule !== null) {
|
|
317
|
-
|
|
338
|
+
block_children.push(nested_at_rule);
|
|
318
339
|
} else {
|
|
319
340
|
this.next_token();
|
|
320
341
|
}
|
|
@@ -322,12 +343,12 @@ class Parser {
|
|
|
322
343
|
}
|
|
323
344
|
let declaration = this.parse_declaration();
|
|
324
345
|
if (declaration !== null) {
|
|
325
|
-
|
|
346
|
+
block_children.push(declaration);
|
|
326
347
|
continue;
|
|
327
348
|
}
|
|
328
349
|
let nested_rule = this.parse_style_rule();
|
|
329
350
|
if (nested_rule !== null) {
|
|
330
|
-
|
|
351
|
+
block_children.push(nested_rule);
|
|
331
352
|
} else {
|
|
332
353
|
this.next_token();
|
|
333
354
|
}
|
|
@@ -338,7 +359,7 @@ class Parser {
|
|
|
338
359
|
if (token_type === TOKEN_RIGHT_BRACE) break;
|
|
339
360
|
let rule = this.parse_rule();
|
|
340
361
|
if (rule !== null) {
|
|
341
|
-
|
|
362
|
+
block_children.push(rule);
|
|
342
363
|
} else {
|
|
343
364
|
this.next_token();
|
|
344
365
|
}
|
|
@@ -352,12 +373,14 @@ class Parser {
|
|
|
352
373
|
} else {
|
|
353
374
|
this.arena.set_length(block_node, last_end - block_start);
|
|
354
375
|
}
|
|
355
|
-
this.arena.
|
|
376
|
+
this.arena.append_children(block_node, block_children);
|
|
377
|
+
prelude_nodes.push(block_node);
|
|
356
378
|
} else if (this.peek_type() === TOKEN_SEMICOLON) {
|
|
357
379
|
last_end = this.lexer.token_end;
|
|
358
380
|
this.next_token();
|
|
359
381
|
}
|
|
360
382
|
this.arena.set_length(at_rule, last_end - at_rule_start);
|
|
383
|
+
this.arena.append_children(at_rule, prelude_nodes);
|
|
361
384
|
return at_rule;
|
|
362
385
|
}
|
|
363
386
|
// Determine if an at-rule contains declarations or nested rules
|
|
@@ -374,4 +397,4 @@ function parse(source, options) {
|
|
|
374
397
|
return parser.parse();
|
|
375
398
|
}
|
|
376
399
|
|
|
377
|
-
export {
|
|
400
|
+
export { Parser, parse };
|
package/dist/string-utils.d.ts
CHANGED
|
@@ -18,12 +18,6 @@ export declare const CHAR_PIPE = 124;
|
|
|
18
18
|
export declare const CHAR_DOLLAR = 36;
|
|
19
19
|
export declare const CHAR_CARET = 94;
|
|
20
20
|
export declare const CHAR_COLON = 58;
|
|
21
|
-
/**
|
|
22
|
-
* Check if a character code is whitespace (space, tab, newline, CR, or FF)
|
|
23
|
-
*/
|
|
24
|
-
export declare function is_whitespace(ch: number): boolean;
|
|
25
|
-
export declare function is_combinator(ch: number): boolean;
|
|
26
|
-
export declare function is_digit(ch: number): boolean;
|
|
27
21
|
/**
|
|
28
22
|
* @param a Base string, MUST be lowercase!
|
|
29
23
|
* @param b Compare string
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const CHAR_SPACE = 32;
|
|
2
|
+
const CHAR_TAB = 9;
|
|
3
|
+
const CHAR_NEWLINE = 10;
|
|
4
|
+
const CHAR_CARRIAGE_RETURN = 13;
|
|
5
|
+
const CHAR_FORM_FEED = 12;
|
|
6
|
+
const CHAR_FORWARD_SLASH = 47;
|
|
7
|
+
const CHAR_ASTERISK = 42;
|
|
8
|
+
const CHAR_MINUS_HYPHEN = 45;
|
|
9
|
+
const CHAR_SINGLE_QUOTE = 39;
|
|
10
|
+
const CHAR_DOUBLE_QUOTE = 34;
|
|
11
|
+
const CHAR_PLUS = 43;
|
|
12
|
+
const CHAR_PERIOD = 46;
|
|
13
|
+
const CHAR_TILDE = 126;
|
|
14
|
+
const CHAR_GREATER_THAN = 62;
|
|
15
|
+
const CHAR_AMPERSAND = 38;
|
|
16
|
+
const CHAR_EQUALS = 61;
|
|
17
|
+
const CHAR_PIPE = 124;
|
|
18
|
+
const CHAR_DOLLAR = 36;
|
|
19
|
+
const CHAR_CARET = 94;
|
|
20
|
+
const CHAR_COLON = 58;
|
|
21
|
+
function is_whitespace(ch) {
|
|
22
|
+
return ch === CHAR_SPACE || ch === CHAR_TAB || ch === CHAR_NEWLINE || ch === CHAR_CARRIAGE_RETURN || ch === CHAR_FORM_FEED;
|
|
23
|
+
}
|
|
24
|
+
function is_combinator(ch) {
|
|
25
|
+
return ch === CHAR_GREATER_THAN || ch === CHAR_PLUS || ch === CHAR_TILDE;
|
|
26
|
+
}
|
|
27
|
+
function is_digit(ch) {
|
|
28
|
+
return ch >= 48 && ch <= 57;
|
|
29
|
+
}
|
|
30
|
+
function str_equals(a, b) {
|
|
31
|
+
if (a.length !== b.length) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
for (let i = 0; i < a.length; i++) {
|
|
35
|
+
let ca = a.charCodeAt(i);
|
|
36
|
+
let cb = b.charCodeAt(i);
|
|
37
|
+
cb |= 32;
|
|
38
|
+
if (ca !== cb) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
function is_vendor_prefixed(source, start, end) {
|
|
45
|
+
if (source.charCodeAt(start) !== CHAR_MINUS_HYPHEN) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (source.charCodeAt(start + 1) === CHAR_MINUS_HYPHEN) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
let length = end - start;
|
|
52
|
+
if (length < 3) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
for (let i = start + 2; i < end; i++) {
|
|
56
|
+
if (source.charCodeAt(i) === CHAR_MINUS_HYPHEN) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { CHAR_AMPERSAND, CHAR_ASTERISK, CHAR_CARET, CHAR_CARRIAGE_RETURN, CHAR_COLON, CHAR_DOLLAR, CHAR_DOUBLE_QUOTE, CHAR_EQUALS, CHAR_FORM_FEED, CHAR_FORWARD_SLASH, CHAR_GREATER_THAN, CHAR_MINUS_HYPHEN, CHAR_NEWLINE, CHAR_PERIOD, CHAR_PIPE, CHAR_PLUS, CHAR_SINGLE_QUOTE, CHAR_SPACE, CHAR_TAB, CHAR_TILDE, is_combinator, is_digit, is_vendor_prefixed, is_whitespace, str_equals };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const TOKEN_IDENT = 1;
|
|
2
|
+
const TOKEN_FUNCTION = 2;
|
|
3
|
+
const TOKEN_AT_KEYWORD = 3;
|
|
4
|
+
const TOKEN_HASH = 4;
|
|
5
|
+
const TOKEN_STRING = 5;
|
|
6
|
+
const TOKEN_BAD_STRING = 6;
|
|
7
|
+
const TOKEN_URL = 7;
|
|
8
|
+
const TOKEN_BAD_URL = 8;
|
|
9
|
+
const TOKEN_DELIM = 9;
|
|
10
|
+
const TOKEN_NUMBER = 10;
|
|
11
|
+
const TOKEN_PERCENTAGE = 11;
|
|
12
|
+
const TOKEN_DIMENSION = 12;
|
|
13
|
+
const TOKEN_WHITESPACE = 13;
|
|
14
|
+
const TOKEN_CDO = 14;
|
|
15
|
+
const TOKEN_CDC = 15;
|
|
16
|
+
const TOKEN_COLON = 16;
|
|
17
|
+
const TOKEN_SEMICOLON = 17;
|
|
18
|
+
const TOKEN_COMMA = 18;
|
|
19
|
+
const TOKEN_LEFT_BRACKET = 19;
|
|
20
|
+
const TOKEN_RIGHT_BRACKET = 20;
|
|
21
|
+
const TOKEN_LEFT_PAREN = 21;
|
|
22
|
+
const TOKEN_RIGHT_PAREN = 22;
|
|
23
|
+
const TOKEN_LEFT_BRACE = 23;
|
|
24
|
+
const TOKEN_RIGHT_BRACE = 24;
|
|
25
|
+
const TOKEN_COMMENT = 25;
|
|
26
|
+
const TOKEN_EOF = 26;
|
|
27
|
+
|
|
28
|
+
export { TOKEN_AT_KEYWORD, TOKEN_BAD_STRING, TOKEN_BAD_URL, TOKEN_CDC, TOKEN_CDO, TOKEN_COLON, TOKEN_COMMA, TOKEN_COMMENT, TOKEN_DELIM, TOKEN_DIMENSION, TOKEN_EOF, TOKEN_FUNCTION, TOKEN_HASH, TOKEN_IDENT, TOKEN_LEFT_BRACE, TOKEN_LEFT_BRACKET, TOKEN_LEFT_PAREN, TOKEN_NUMBER, TOKEN_PERCENTAGE, TOKEN_RIGHT_BRACE, TOKEN_RIGHT_BRACKET, TOKEN_RIGHT_PAREN, TOKEN_SEMICOLON, TOKEN_STRING, TOKEN_URL, TOKEN_WHITESPACE };
|
package/dist/tokenize.js
CHANGED
package/dist/walk.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
function walk(node, callback, depth = 0) {
|
|
2
|
+
callback(node, depth);
|
|
3
|
+
let child = node.first_child;
|
|
4
|
+
while (child) {
|
|
5
|
+
walk(child, callback, depth + 1);
|
|
6
|
+
child = child.next_sibling;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
const NOOP = function() {
|
|
10
|
+
};
|
|
11
|
+
function traverse(node, { enter = NOOP, leave = NOOP } = {}) {
|
|
12
|
+
enter(node);
|
|
13
|
+
let child = node.first_child;
|
|
14
|
+
while (child) {
|
|
15
|
+
traverse(child, { enter, leave });
|
|
16
|
+
child = child.next_sibling;
|
|
17
|
+
}
|
|
18
|
+
leave(node);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { traverse, walk };
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@projectwallace/css-parser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
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",
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/projectwallace/css-parser.git"
|
|
10
|
+
},
|
|
11
|
+
"issues": "https://github.com/projectwallace/css-parser/issues",
|
|
12
|
+
"homepage": "https://github.com/projectwallace/css-parser",
|
|
13
13
|
"type": "module",
|
|
14
14
|
"main": "./dist/index.js",
|
|
15
15
|
"module": "./dist/index.js",
|
|
@@ -56,8 +56,7 @@
|
|
|
56
56
|
"benchmark:memory": "npm run build && node --expose-gc benchmark/memory.ts",
|
|
57
57
|
"lint": "oxlint --config .oxlintrc.json",
|
|
58
58
|
"lint-package": "publint",
|
|
59
|
-
"check": "tsc --noEmit"
|
|
60
|
-
"knip": "knip"
|
|
59
|
+
"check": "tsc --noEmit"
|
|
61
60
|
},
|
|
62
61
|
"keywords": [
|
|
63
62
|
"css",
|
|
@@ -72,7 +71,6 @@
|
|
|
72
71
|
"@vitest/coverage-v8": "^4.0.8",
|
|
73
72
|
"bootstrap": "^5.3.8",
|
|
74
73
|
"css-tree": "^3.1.0",
|
|
75
|
-
"knip": "^5.69.1",
|
|
76
74
|
"oxlint": "^1.28.0",
|
|
77
75
|
"postcss": "^8.5.6",
|
|
78
76
|
"prettier": "^3.6.2",
|