@projectwallace/css-parser 0.12.0 → 0.12.2
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/parse-anplusb.js +2 -2
- package/dist/parse-atrule-prelude.js +16 -8
- package/dist/parse-selector.js +40 -24
- package/package.json +1 -1
package/dist/parse-anplusb.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Lexer } from './tokenize.js';
|
|
|
2
2
|
import { NTH_SELECTOR, CSSDataArena } from './arena.js';
|
|
3
3
|
import { TOKEN_IDENT, TOKEN_DELIM, TOKEN_DIMENSION, TOKEN_NUMBER } from './token-types.js';
|
|
4
4
|
import { str_equals, CHAR_MINUS_HYPHEN, CHAR_PLUS, str_index_of } from './string-utils.js';
|
|
5
|
-
import {
|
|
5
|
+
import { skip_whitespace_and_comments_forward } from './parse-utils.js';
|
|
6
6
|
import { CSSNode } from './css-node.js';
|
|
7
7
|
|
|
8
8
|
class ANplusBParser {
|
|
@@ -186,7 +186,7 @@ class ANplusBParser {
|
|
|
186
186
|
return null;
|
|
187
187
|
}
|
|
188
188
|
skip_whitespace() {
|
|
189
|
-
this.lexer.pos =
|
|
189
|
+
this.lexer.pos = skip_whitespace_and_comments_forward(this.source, this.lexer.pos, this.expr_end);
|
|
190
190
|
}
|
|
191
191
|
create_anplusb_node(start, a_start, a_end, b_start, b_end) {
|
|
192
192
|
const node = this.arena.create_node(NTH_SELECTOR, start, this.lexer.pos - start, this.lexer.line, 1);
|
|
@@ -2,7 +2,7 @@ import { Lexer } from './tokenize.js';
|
|
|
2
2
|
import { CSSDataArena, PRELUDE_OPERATOR, MEDIA_TYPE, MEDIA_QUERY, MEDIA_FEATURE, FUNCTION, IDENTIFIER, CONTAINER_QUERY, SUPPORTS_QUERY, LAYER_NAME, STRING, URL, DIMENSION, NUMBER, FEATURE_RANGE } from './arena.js';
|
|
3
3
|
import { TOKEN_COMMA, TOKEN_IDENT, TOKEN_LEFT_PAREN, TOKEN_RIGHT_PAREN, TOKEN_FUNCTION, TOKEN_EOF, TOKEN_WHITESPACE, TOKEN_STRING, TOKEN_URL, TOKEN_DIMENSION, TOKEN_PERCENTAGE, TOKEN_NUMBER } from './token-types.js';
|
|
4
4
|
import { strip_vendor_prefix, str_equals, CHAR_LESS_THAN, CHAR_GREATER_THAN, CHAR_EQUALS, CHAR_COLON, is_whitespace } from './string-utils.js';
|
|
5
|
-
import {
|
|
5
|
+
import { skip_whitespace_and_comments_forward, trim_boundaries } from './parse-utils.js';
|
|
6
6
|
import { CSSNode } from './css-node.js';
|
|
7
7
|
|
|
8
8
|
class AtRulePreludeParser {
|
|
@@ -134,23 +134,31 @@ class AtRulePreludeParser {
|
|
|
134
134
|
let content_end = this.lexer.token_start;
|
|
135
135
|
let feature_end = this.lexer.token_end;
|
|
136
136
|
let has_comparison = false;
|
|
137
|
-
|
|
137
|
+
let i = content_start;
|
|
138
|
+
while (i < content_end) {
|
|
139
|
+
i = skip_whitespace_and_comments_forward(this.source, i, content_end);
|
|
140
|
+
if (i >= content_end) break;
|
|
138
141
|
let ch = this.source.charCodeAt(i);
|
|
139
142
|
if (ch === CHAR_LESS_THAN || ch === CHAR_GREATER_THAN || ch === CHAR_EQUALS) {
|
|
140
143
|
has_comparison = true;
|
|
141
144
|
break;
|
|
142
145
|
}
|
|
146
|
+
i++;
|
|
143
147
|
}
|
|
144
148
|
if (has_comparison) {
|
|
145
149
|
return this.parse_feature_range(feature_start, feature_end, content_start, content_end);
|
|
146
150
|
}
|
|
147
151
|
let feature = this.create_node(MEDIA_FEATURE, feature_start, feature_end);
|
|
148
152
|
let colon_pos = -1;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
153
|
+
let j = content_start;
|
|
154
|
+
while (j < content_end) {
|
|
155
|
+
j = skip_whitespace_and_comments_forward(this.source, j, content_end);
|
|
156
|
+
if (j >= content_end) break;
|
|
157
|
+
if (this.source.charCodeAt(j) === CHAR_COLON) {
|
|
158
|
+
colon_pos = j;
|
|
152
159
|
break;
|
|
153
160
|
}
|
|
161
|
+
j++;
|
|
154
162
|
}
|
|
155
163
|
if (colon_pos !== -1) {
|
|
156
164
|
let name_trimmed = trim_boundaries(this.source, content_start, colon_pos);
|
|
@@ -458,9 +466,9 @@ class AtRulePreludeParser {
|
|
|
458
466
|
this.lexer.restore_position(saved);
|
|
459
467
|
return null;
|
|
460
468
|
}
|
|
461
|
-
// Helper: Skip whitespace
|
|
469
|
+
// Helper: Skip whitespace and comments
|
|
462
470
|
skip_whitespace() {
|
|
463
|
-
this.lexer.pos =
|
|
471
|
+
this.lexer.pos = skip_whitespace_and_comments_forward(this.source, this.lexer.pos, this.prelude_end);
|
|
464
472
|
}
|
|
465
473
|
// Helper: Peek at next token type without consuming
|
|
466
474
|
peek_token_type() {
|
|
@@ -524,7 +532,7 @@ class AtRulePreludeParser {
|
|
|
524
532
|
let feature_name_end = -1;
|
|
525
533
|
let pos = content_start;
|
|
526
534
|
while (pos < content_end) {
|
|
527
|
-
pos =
|
|
535
|
+
pos = skip_whitespace_and_comments_forward(this.source, pos, content_end);
|
|
528
536
|
if (pos >= content_end) break;
|
|
529
537
|
let ch = this.source.charCodeAt(pos);
|
|
530
538
|
if (ch === CHAR_LESS_THAN || ch === CHAR_GREATER_THAN || ch === CHAR_EQUALS) {
|
package/dist/parse-selector.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Lexer } from './tokenize.js';
|
|
|
2
2
|
import { CSSDataArena, SELECTOR_LIST, SELECTOR, COMBINATOR, NESTING_SELECTOR, ID_SELECTOR, TYPE_SELECTOR, UNIVERSAL_SELECTOR, CLASS_SELECTOR, ATTRIBUTE_SELECTOR, ATTR_OPERATOR_NONE, ATTR_FLAG_NONE, ATTR_OPERATOR_EQUAL, ATTR_OPERATOR_TILDE_EQUAL, ATTR_OPERATOR_PIPE_EQUAL, ATTR_OPERATOR_CARET_EQUAL, ATTR_OPERATOR_DOLLAR_EQUAL, ATTR_OPERATOR_STAR_EQUAL, ATTR_FLAG_CASE_INSENSITIVE, ATTR_FLAG_CASE_SENSITIVE, PSEUDO_ELEMENT_SELECTOR, PSEUDO_CLASS_SELECTOR, FLAG_HAS_PARENS, LANG_SELECTOR, NTH_OF_SELECTOR } from './arena.js';
|
|
3
3
|
import { TOKEN_COMMA, TOKEN_DELIM, TOKEN_EOF, TOKEN_WHITESPACE, TOKEN_FUNCTION, TOKEN_COLON, TOKEN_LEFT_BRACKET, TOKEN_HASH, TOKEN_IDENT, TOKEN_RIGHT_BRACKET, TOKEN_LEFT_PAREN, TOKEN_RIGHT_PAREN, TOKEN_STRING } from './token-types.js';
|
|
4
4
|
import { skip_whitespace_and_comments_forward, skip_whitespace_and_comments_backward, skip_whitespace_forward } from './parse-utils.js';
|
|
5
|
-
import { CHAR_GREATER_THAN, CHAR_PLUS, CHAR_TILDE, CHAR_PERIOD, CHAR_ASTERISK, CHAR_AMPERSAND, CHAR_PIPE,
|
|
5
|
+
import { CHAR_GREATER_THAN, CHAR_PLUS, CHAR_TILDE, CHAR_PERIOD, CHAR_ASTERISK, CHAR_AMPERSAND, CHAR_PIPE, is_combinator, is_whitespace, CHAR_EQUALS, CHAR_CARET, CHAR_DOLLAR, CHAR_SINGLE_QUOTE, CHAR_DOUBLE_QUOTE, CHAR_COLON, str_equals, CHAR_FORWARD_SLASH } from './string-utils.js';
|
|
6
6
|
import { ANplusBParser } from './parse-anplusb.js';
|
|
7
7
|
import { CSSNode } from './css-node.js';
|
|
8
8
|
|
|
@@ -38,7 +38,13 @@ class SelectorParser {
|
|
|
38
38
|
let selector_column = this.lexer.column;
|
|
39
39
|
let complex_selector = this.parse_complex_selector(allow_relative);
|
|
40
40
|
if (complex_selector !== null) {
|
|
41
|
-
let selector_wrapper = this.arena.create_node(
|
|
41
|
+
let selector_wrapper = this.arena.create_node(
|
|
42
|
+
SELECTOR,
|
|
43
|
+
selector_start,
|
|
44
|
+
this.lexer.pos - selector_start,
|
|
45
|
+
selector_line,
|
|
46
|
+
selector_column
|
|
47
|
+
);
|
|
42
48
|
this.arena.set_content_start_delta(selector_wrapper, 0);
|
|
43
49
|
this.arena.set_content_length(selector_wrapper, this.lexer.pos - selector_start);
|
|
44
50
|
let last_component = complex_selector;
|
|
@@ -81,7 +87,13 @@ class SelectorParser {
|
|
|
81
87
|
if (token_type === TOKEN_DELIM) {
|
|
82
88
|
let ch = this.source.charCodeAt(this.lexer.token_start);
|
|
83
89
|
if (ch === CHAR_GREATER_THAN || ch === CHAR_PLUS || ch === CHAR_TILDE) {
|
|
84
|
-
let combinator = this.create_node_at(
|
|
90
|
+
let combinator = this.create_node_at(
|
|
91
|
+
COMBINATOR,
|
|
92
|
+
this.lexer.token_start,
|
|
93
|
+
this.lexer.token_end,
|
|
94
|
+
this.lexer.token_line,
|
|
95
|
+
this.lexer.token_column
|
|
96
|
+
);
|
|
85
97
|
components.push(combinator);
|
|
86
98
|
this.skip_whitespace();
|
|
87
99
|
} else {
|
|
@@ -210,22 +222,30 @@ class SelectorParser {
|
|
|
210
222
|
// Parse type selector or namespace selector (ns|E or ns|*)
|
|
211
223
|
// Called when we've seen an IDENT token
|
|
212
224
|
parse_type_or_namespace_selector(start, end) {
|
|
225
|
+
const saved = this.lexer.save_position();
|
|
226
|
+
this.skip_whitespace();
|
|
213
227
|
if (this.lexer.pos < this.selector_end && this.source.charCodeAt(this.lexer.pos) === CHAR_PIPE) {
|
|
214
228
|
this.lexer.pos++;
|
|
215
229
|
let node = this.parse_namespace_local_part(start, start, end - start);
|
|
216
230
|
if (node !== null) return node;
|
|
217
231
|
this.lexer.pos = end;
|
|
232
|
+
} else {
|
|
233
|
+
this.lexer.restore_position(saved);
|
|
218
234
|
}
|
|
219
235
|
return this.create_node(TYPE_SELECTOR, start, end);
|
|
220
236
|
}
|
|
221
237
|
// Parse universal selector or namespace selector (*|E or *|*)
|
|
222
238
|
// Called when we've seen a * DELIM token
|
|
223
239
|
parse_universal_or_namespace_selector(start, end) {
|
|
240
|
+
const saved = this.lexer.save_position();
|
|
241
|
+
this.skip_whitespace();
|
|
224
242
|
if (this.lexer.pos < this.selector_end && this.source.charCodeAt(this.lexer.pos) === CHAR_PIPE) {
|
|
225
243
|
this.lexer.pos++;
|
|
226
244
|
let node = this.parse_namespace_local_part(start, start, end - start);
|
|
227
245
|
if (node !== null) return node;
|
|
228
246
|
this.lexer.pos = end;
|
|
247
|
+
} else {
|
|
248
|
+
this.lexer.restore_position(saved);
|
|
229
249
|
}
|
|
230
250
|
return this.create_node(UNIVERSAL_SELECTOR, start, end);
|
|
231
251
|
}
|
|
@@ -239,16 +259,9 @@ class SelectorParser {
|
|
|
239
259
|
let whitespace_start = this.lexer.pos;
|
|
240
260
|
let whitespace_start_line = this.lexer.line;
|
|
241
261
|
let whitespace_start_column = this.lexer.column;
|
|
242
|
-
let has_whitespace =
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (ch === CHAR_SPACE || ch === CHAR_TAB || ch === CHAR_NEWLINE || ch === CHAR_CARRIAGE_RETURN || ch === CHAR_FORM_FEED) {
|
|
246
|
-
has_whitespace = true;
|
|
247
|
-
this.lexer.advance();
|
|
248
|
-
} else {
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
262
|
+
let has_whitespace = this.lexer.pos < this.selector_end;
|
|
263
|
+
this.skip_whitespace();
|
|
264
|
+
has_whitespace = has_whitespace && this.lexer.pos > whitespace_start;
|
|
252
265
|
if (this.lexer.pos >= this.selector_end) {
|
|
253
266
|
this.lexer.pos = whitespace_start;
|
|
254
267
|
this.lexer.line = whitespace_start_line;
|
|
@@ -266,14 +279,7 @@ class SelectorParser {
|
|
|
266
279
|
this.lexer.pos = whitespace_start;
|
|
267
280
|
this.lexer.line = whitespace_start_line;
|
|
268
281
|
this.lexer.column = whitespace_start_column;
|
|
269
|
-
|
|
270
|
-
let ch = this.source.charCodeAt(this.lexer.pos);
|
|
271
|
-
if (ch === CHAR_SPACE || ch === CHAR_TAB || ch === CHAR_NEWLINE || ch === CHAR_CARRIAGE_RETURN || ch === CHAR_FORM_FEED) {
|
|
272
|
-
this.lexer.advance();
|
|
273
|
-
} else {
|
|
274
|
-
break;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
282
|
+
this.skip_whitespace();
|
|
277
283
|
return this.create_node_at(COMBINATOR, whitespace_start, this.lexer.pos, whitespace_start_line, whitespace_start_column);
|
|
278
284
|
}
|
|
279
285
|
this.lexer.pos = whitespace_start;
|
|
@@ -422,10 +428,14 @@ class SelectorParser {
|
|
|
422
428
|
// Parse pseudo-class or pseudo-element (:hover, ::before)
|
|
423
429
|
parse_pseudo(start) {
|
|
424
430
|
const saved = this.lexer.save_position();
|
|
431
|
+
const saved_ws = this.lexer.save_position();
|
|
432
|
+
this.skip_whitespace();
|
|
425
433
|
let is_pseudo_element = false;
|
|
426
434
|
if (this.lexer.pos < this.selector_end && this.source.charCodeAt(this.lexer.pos) === CHAR_COLON) {
|
|
427
435
|
is_pseudo_element = true;
|
|
428
436
|
this.lexer.pos++;
|
|
437
|
+
} else {
|
|
438
|
+
this.lexer.restore_position(saved_ws);
|
|
429
439
|
}
|
|
430
440
|
this.lexer.next_token_fast(false);
|
|
431
441
|
let token_type = this.lexer.token_type;
|
|
@@ -566,16 +576,22 @@ class SelectorParser {
|
|
|
566
576
|
return anplusb_parser.parse_anplusb(start, end, this.lexer.line);
|
|
567
577
|
}
|
|
568
578
|
}
|
|
569
|
-
// Find the position of standalone "of" keyword
|
|
579
|
+
// Find the position of standalone "of" keyword (case-insensitive)
|
|
570
580
|
find_of_keyword(start, end) {
|
|
571
|
-
|
|
572
|
-
|
|
581
|
+
let i = start;
|
|
582
|
+
while (i < end - 1) {
|
|
583
|
+
i = skip_whitespace_and_comments_forward(this.source, i, end);
|
|
584
|
+
if (i >= end - 1) break;
|
|
585
|
+
let ch1 = this.source.charCodeAt(i);
|
|
586
|
+
let ch2 = this.source.charCodeAt(i + 1);
|
|
587
|
+
if ((ch1 === 111 || ch1 === 79) && (ch2 === 102 || ch2 === 70)) {
|
|
573
588
|
let before_ok = i === start || is_whitespace(this.source.charCodeAt(i - 1));
|
|
574
589
|
let after_ok = i + 2 >= end || is_whitespace(this.source.charCodeAt(i + 2));
|
|
575
590
|
if (before_ok && after_ok) {
|
|
576
591
|
return i;
|
|
577
592
|
}
|
|
578
593
|
}
|
|
594
|
+
i++;
|
|
579
595
|
}
|
|
580
596
|
return -1;
|
|
581
597
|
}
|
package/package.json
CHANGED