@projectwallace/css-parser 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/arena.d.ts +24 -11
- package/dist/{string-utils-tMt2O9RW.js → css-node-BzCSxoLM.js} +263 -90
- package/dist/css-node.d.ts +11 -4
- package/dist/index.d.ts +6 -3
- package/dist/index.js +6 -5
- package/dist/{lexer-DXablYMZ.js → lexer-CtBKgfVv.js} +30 -0
- package/dist/lexer.d.ts +20 -0
- package/dist/parse-anplusb.d.ts +22 -0
- package/dist/parse-anplusb.js +220 -0
- package/dist/parse-atrule-prelude.d.ts +24 -0
- package/dist/parse-atrule-prelude.js +452 -3
- package/dist/parse-selector.d.ts +30 -0
- package/dist/parse-selector.js +614 -3
- package/dist/parse-utils.d.ts +56 -0
- package/dist/parse-value.d.ts +22 -0
- package/dist/parse-value.js +142 -0
- package/dist/parse.d.ts +34 -2
- package/dist/parse.js +51 -194
- package/dist/string-utils.d.ts +14 -13
- package/dist/tokenize.js +1 -1
- package/dist/walk.d.ts +1 -1
- package/package.json +9 -1
- package/dist/at-rule-prelude-parser-Cj8ecgQp.js +0 -467
- package/dist/at-rule-prelude-parser.d.ts +0 -24
- package/dist/parser.d.ts +0 -34
- package/dist/selector-parser-C-u1epDB.js +0 -370
- package/dist/selector-parser.d.ts +0 -25
- package/dist/value-parser.d.ts +0 -19
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CSSDataArena } from './arena';
|
|
2
|
+
import { CSSNode } from './css-node';
|
|
3
|
+
export declare class ValueParser {
|
|
4
|
+
private lexer;
|
|
5
|
+
private arena;
|
|
6
|
+
private source;
|
|
7
|
+
private value_end;
|
|
8
|
+
constructor(arena: CSSDataArena, source: string);
|
|
9
|
+
parse_value(start: number, end: number): number[];
|
|
10
|
+
private is_whitespace_token;
|
|
11
|
+
private parse_value_node;
|
|
12
|
+
private create_node;
|
|
13
|
+
private create_operator_node;
|
|
14
|
+
private parse_operator_node;
|
|
15
|
+
private parse_function_node;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Parse a CSS declaration value string and return an array of value AST nodes
|
|
19
|
+
* @param value_string - The CSS value to parse (e.g., "1px solid red")
|
|
20
|
+
* @returns An array of CSSNode objects representing the parsed value
|
|
21
|
+
*/
|
|
22
|
+
export declare function parse_value(value_string: string): CSSNode[];
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { L as Lexer, y as TOKEN_EOF, q as TOKEN_COMMA, h as TOKEN_DELIM, a as TOKEN_FUNCTION, c as TOKEN_HASH, d as TOKEN_STRING, k as TOKEN_DIMENSION, j as TOKEN_PERCENTAGE, i as TOKEN_NUMBER, T as TOKEN_IDENT, t as TOKEN_LEFT_PAREN, u as TOKEN_RIGHT_PAREN } from './lexer-CtBKgfVv.js';
|
|
2
|
+
import { T as CSSDataArena, C as CSSNode, a5 as is_whitespace, r as NODE_VALUE_OPERATOR, p as NODE_VALUE_COLOR, o as NODE_VALUE_STRING, n as NODE_VALUE_DIMENSION, m as NODE_VALUE_NUMBER, l as NODE_VALUE_KEYWORD, a0 as CHAR_PLUS, ai as CHAR_MINUS_HYPHEN, a3 as CHAR_ASTERISK, aj as CHAR_FORWARD_SLASH, q as NODE_VALUE_FUNCTION } from './css-node-BzCSxoLM.js';
|
|
3
|
+
|
|
4
|
+
class ValueParser {
|
|
5
|
+
lexer;
|
|
6
|
+
arena;
|
|
7
|
+
source;
|
|
8
|
+
value_end;
|
|
9
|
+
constructor(arena, source) {
|
|
10
|
+
this.arena = arena;
|
|
11
|
+
this.source = source;
|
|
12
|
+
this.lexer = new Lexer(source, false);
|
|
13
|
+
this.value_end = 0;
|
|
14
|
+
}
|
|
15
|
+
// Parse a declaration value range into value nodes
|
|
16
|
+
// Returns array of value node indices
|
|
17
|
+
parse_value(start, end) {
|
|
18
|
+
this.value_end = end;
|
|
19
|
+
this.lexer.pos = start;
|
|
20
|
+
this.lexer.line = 1;
|
|
21
|
+
let nodes = [];
|
|
22
|
+
while (this.lexer.pos < this.value_end) {
|
|
23
|
+
this.lexer.next_token_fast(false);
|
|
24
|
+
if (this.lexer.token_start >= this.value_end) break;
|
|
25
|
+
let token_type = this.lexer.token_type;
|
|
26
|
+
if (token_type === TOKEN_EOF) break;
|
|
27
|
+
if (this.is_whitespace_token()) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
let node = this.parse_value_node();
|
|
31
|
+
if (node !== null) {
|
|
32
|
+
nodes.push(node);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return nodes;
|
|
36
|
+
}
|
|
37
|
+
is_whitespace_token() {
|
|
38
|
+
let start = this.lexer.token_start;
|
|
39
|
+
let end = this.lexer.token_end;
|
|
40
|
+
if (start >= end) return false;
|
|
41
|
+
for (let i = start; i < end; i++) {
|
|
42
|
+
let ch = this.source.charCodeAt(i);
|
|
43
|
+
if (!is_whitespace(ch)) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
parse_value_node() {
|
|
50
|
+
let token_type = this.lexer.token_type;
|
|
51
|
+
let start = this.lexer.token_start;
|
|
52
|
+
let end = this.lexer.token_end;
|
|
53
|
+
switch (token_type) {
|
|
54
|
+
case TOKEN_IDENT:
|
|
55
|
+
return this.create_node(NODE_VALUE_KEYWORD, start, end);
|
|
56
|
+
case TOKEN_NUMBER:
|
|
57
|
+
return this.create_node(NODE_VALUE_NUMBER, start, end);
|
|
58
|
+
case TOKEN_PERCENTAGE:
|
|
59
|
+
case TOKEN_DIMENSION:
|
|
60
|
+
return this.create_node(NODE_VALUE_DIMENSION, start, end);
|
|
61
|
+
case TOKEN_STRING:
|
|
62
|
+
return this.create_node(NODE_VALUE_STRING, start, end);
|
|
63
|
+
case TOKEN_HASH:
|
|
64
|
+
return this.create_node(NODE_VALUE_COLOR, start, end);
|
|
65
|
+
case TOKEN_FUNCTION:
|
|
66
|
+
return this.parse_function_node(start, end);
|
|
67
|
+
case TOKEN_DELIM:
|
|
68
|
+
return this.parse_operator_node(start, end);
|
|
69
|
+
case TOKEN_COMMA:
|
|
70
|
+
return this.create_node(NODE_VALUE_OPERATOR, start, end);
|
|
71
|
+
default:
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
create_node(node_type, start, end) {
|
|
76
|
+
let node = this.arena.create_node();
|
|
77
|
+
this.arena.set_type(node, node_type);
|
|
78
|
+
this.arena.set_start_offset(node, start);
|
|
79
|
+
this.arena.set_length(node, end - start);
|
|
80
|
+
this.arena.set_content_start(node, start);
|
|
81
|
+
this.arena.set_content_length(node, end - start);
|
|
82
|
+
return node;
|
|
83
|
+
}
|
|
84
|
+
create_operator_node(start, end) {
|
|
85
|
+
return this.create_node(NODE_VALUE_OPERATOR, start, end);
|
|
86
|
+
}
|
|
87
|
+
parse_operator_node(start, end) {
|
|
88
|
+
let ch = this.source.charCodeAt(start);
|
|
89
|
+
if (ch === CHAR_PLUS || ch === CHAR_MINUS_HYPHEN || ch === CHAR_ASTERISK || ch === CHAR_FORWARD_SLASH) {
|
|
90
|
+
return this.create_operator_node(start, end);
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
parse_function_node(start, end) {
|
|
95
|
+
let node = this.arena.create_node();
|
|
96
|
+
this.arena.set_type(node, NODE_VALUE_FUNCTION);
|
|
97
|
+
this.arena.set_start_offset(node, start);
|
|
98
|
+
let name_end = end - 1;
|
|
99
|
+
this.arena.set_content_start(node, start);
|
|
100
|
+
this.arena.set_content_length(node, name_end - start);
|
|
101
|
+
let args = [];
|
|
102
|
+
let paren_depth = 1;
|
|
103
|
+
let func_end = end;
|
|
104
|
+
while (this.lexer.pos < this.value_end && paren_depth > 0) {
|
|
105
|
+
this.lexer.next_token_fast(false);
|
|
106
|
+
let token_type = this.lexer.token_type;
|
|
107
|
+
if (token_type === TOKEN_EOF) break;
|
|
108
|
+
if (this.lexer.token_start >= this.value_end) break;
|
|
109
|
+
if (token_type === TOKEN_LEFT_PAREN || token_type === TOKEN_FUNCTION) {
|
|
110
|
+
paren_depth++;
|
|
111
|
+
} else if (token_type === TOKEN_RIGHT_PAREN) {
|
|
112
|
+
paren_depth--;
|
|
113
|
+
if (paren_depth === 0) {
|
|
114
|
+
func_end = this.lexer.token_end;
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (this.is_whitespace_token()) continue;
|
|
119
|
+
let arg_node = this.parse_value_node();
|
|
120
|
+
if (arg_node !== null) {
|
|
121
|
+
args.push(arg_node);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
this.arena.set_length(node, func_end - start);
|
|
125
|
+
if (args.length > 0) {
|
|
126
|
+
this.arena.set_first_child(node, args[0]);
|
|
127
|
+
this.arena.set_last_child(node, args[args.length - 1]);
|
|
128
|
+
for (let i = 0; i < args.length - 1; i++) {
|
|
129
|
+
this.arena.set_next_sibling(args[i], args[i + 1]);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return node;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function parse_value(value_string) {
|
|
136
|
+
const arena = new CSSDataArena(CSSDataArena.capacity_for_source(value_string.length));
|
|
137
|
+
const value_parser = new ValueParser(arena, value_string);
|
|
138
|
+
const node_indices = value_parser.parse_value(0, value_string.length);
|
|
139
|
+
return node_indices.map((index) => new CSSNode(arena, value_string, index));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export { ValueParser, parse_value };
|
package/dist/parse.d.ts
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { CSSDataArena } from './arena';
|
|
2
|
+
import { CSSNode } from './css-node';
|
|
3
|
+
export interface ParserOptions {
|
|
4
|
+
skip_comments?: boolean;
|
|
5
|
+
parse_values?: boolean;
|
|
6
|
+
parse_selectors?: boolean;
|
|
7
|
+
parse_atrule_preludes?: boolean;
|
|
8
|
+
}
|
|
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
|
+
}
|
|
3
34
|
/**
|
|
4
35
|
* Parse CSS and return an AST
|
|
5
36
|
* @param source - The CSS source code to parse
|
|
@@ -7,3 +38,4 @@ import type { CSSNode } from './css-node';
|
|
|
7
38
|
* @returns The root CSSNode of the AST
|
|
8
39
|
*/
|
|
9
40
|
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_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,185 +1,9 @@
|
|
|
1
|
-
import { L as Lexer, y as TOKEN_EOF,
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const CH_MINUS = 45;
|
|
8
|
-
const CH_ASTERISK = 42;
|
|
9
|
-
const CH_SLASH = 47;
|
|
10
|
-
class ValueParser {
|
|
11
|
-
lexer;
|
|
12
|
-
arena;
|
|
13
|
-
source;
|
|
14
|
-
value_end;
|
|
15
|
-
constructor(arena, source) {
|
|
16
|
-
this.arena = arena;
|
|
17
|
-
this.source = source;
|
|
18
|
-
this.lexer = new Lexer(source, false);
|
|
19
|
-
this.value_end = 0;
|
|
20
|
-
}
|
|
21
|
-
// Parse a declaration value range into value nodes
|
|
22
|
-
// Returns array of value node indices
|
|
23
|
-
parse_value(start, end) {
|
|
24
|
-
this.value_end = end;
|
|
25
|
-
this.lexer.pos = start;
|
|
26
|
-
this.lexer.line = 1;
|
|
27
|
-
let nodes = [];
|
|
28
|
-
while (this.lexer.pos < this.value_end) {
|
|
29
|
-
this.lexer.next_token_fast(false);
|
|
30
|
-
if (this.lexer.token_start >= this.value_end) break;
|
|
31
|
-
let token_type = this.lexer.token_type;
|
|
32
|
-
if (token_type === TOKEN_EOF) break;
|
|
33
|
-
if (this.is_whitespace_token()) {
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
let node = this.parse_value_node();
|
|
37
|
-
if (node !== null) {
|
|
38
|
-
nodes.push(node);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return nodes;
|
|
42
|
-
}
|
|
43
|
-
is_whitespace_token() {
|
|
44
|
-
let start = this.lexer.token_start;
|
|
45
|
-
let end = this.lexer.token_end;
|
|
46
|
-
if (start >= end) return false;
|
|
47
|
-
for (let i = start; i < end; i++) {
|
|
48
|
-
let ch = this.source.charCodeAt(i);
|
|
49
|
-
if (!is_whitespace(ch)) {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
parse_value_node() {
|
|
56
|
-
let token_type = this.lexer.token_type;
|
|
57
|
-
let start = this.lexer.token_start;
|
|
58
|
-
let end = this.lexer.token_end;
|
|
59
|
-
switch (token_type) {
|
|
60
|
-
case TOKEN_IDENT:
|
|
61
|
-
return this.create_keyword_node(start, end);
|
|
62
|
-
case TOKEN_NUMBER:
|
|
63
|
-
return this.create_number_node(start, end);
|
|
64
|
-
case TOKEN_PERCENTAGE:
|
|
65
|
-
case TOKEN_DIMENSION:
|
|
66
|
-
return this.create_dimension_node(start, end);
|
|
67
|
-
case TOKEN_STRING:
|
|
68
|
-
return this.create_string_node(start, end);
|
|
69
|
-
case TOKEN_HASH:
|
|
70
|
-
return this.create_color_node(start, end);
|
|
71
|
-
case TOKEN_FUNCTION:
|
|
72
|
-
return this.parse_function_node(start, end);
|
|
73
|
-
case TOKEN_DELIM:
|
|
74
|
-
return this.parse_operator_node(start, end);
|
|
75
|
-
case TOKEN_COMMA:
|
|
76
|
-
return this.create_operator_node(start, end);
|
|
77
|
-
default:
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
create_keyword_node(start, end) {
|
|
82
|
-
let node = this.arena.create_node();
|
|
83
|
-
this.arena.set_type(node, NODE_VALUE_KEYWORD);
|
|
84
|
-
this.arena.set_start_offset(node, start);
|
|
85
|
-
this.arena.set_length(node, end - start);
|
|
86
|
-
this.arena.set_content_start(node, start);
|
|
87
|
-
this.arena.set_content_length(node, end - start);
|
|
88
|
-
return node;
|
|
89
|
-
}
|
|
90
|
-
create_number_node(start, end) {
|
|
91
|
-
let node = this.arena.create_node();
|
|
92
|
-
this.arena.set_type(node, NODE_VALUE_NUMBER);
|
|
93
|
-
this.arena.set_start_offset(node, start);
|
|
94
|
-
this.arena.set_length(node, end - start);
|
|
95
|
-
this.arena.set_content_start(node, start);
|
|
96
|
-
this.arena.set_content_length(node, end - start);
|
|
97
|
-
return node;
|
|
98
|
-
}
|
|
99
|
-
create_dimension_node(start, end) {
|
|
100
|
-
let node = this.arena.create_node();
|
|
101
|
-
this.arena.set_type(node, NODE_VALUE_DIMENSION);
|
|
102
|
-
this.arena.set_start_offset(node, start);
|
|
103
|
-
this.arena.set_length(node, end - start);
|
|
104
|
-
this.arena.set_content_start(node, start);
|
|
105
|
-
this.arena.set_content_length(node, end - start);
|
|
106
|
-
return node;
|
|
107
|
-
}
|
|
108
|
-
create_string_node(start, end) {
|
|
109
|
-
let node = this.arena.create_node();
|
|
110
|
-
this.arena.set_type(node, NODE_VALUE_STRING);
|
|
111
|
-
this.arena.set_start_offset(node, start);
|
|
112
|
-
this.arena.set_length(node, end - start);
|
|
113
|
-
this.arena.set_content_start(node, start);
|
|
114
|
-
this.arena.set_content_length(node, end - start);
|
|
115
|
-
return node;
|
|
116
|
-
}
|
|
117
|
-
create_color_node(start, end) {
|
|
118
|
-
let node = this.arena.create_node();
|
|
119
|
-
this.arena.set_type(node, NODE_VALUE_COLOR);
|
|
120
|
-
this.arena.set_start_offset(node, start);
|
|
121
|
-
this.arena.set_length(node, end - start);
|
|
122
|
-
this.arena.set_content_start(node, start);
|
|
123
|
-
this.arena.set_content_length(node, end - start);
|
|
124
|
-
return node;
|
|
125
|
-
}
|
|
126
|
-
create_operator_node(start, end) {
|
|
127
|
-
let node = this.arena.create_node();
|
|
128
|
-
this.arena.set_type(node, NODE_VALUE_OPERATOR);
|
|
129
|
-
this.arena.set_start_offset(node, start);
|
|
130
|
-
this.arena.set_length(node, end - start);
|
|
131
|
-
this.arena.set_content_start(node, start);
|
|
132
|
-
this.arena.set_content_length(node, end - start);
|
|
133
|
-
return node;
|
|
134
|
-
}
|
|
135
|
-
parse_operator_node(start, end) {
|
|
136
|
-
let ch = this.source.charCodeAt(start);
|
|
137
|
-
if (ch === CH_PLUS || ch === CH_MINUS || ch === CH_ASTERISK || ch === CH_SLASH) {
|
|
138
|
-
return this.create_operator_node(start, end);
|
|
139
|
-
}
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
parse_function_node(start, end) {
|
|
143
|
-
let node = this.arena.create_node();
|
|
144
|
-
this.arena.set_type(node, NODE_VALUE_FUNCTION);
|
|
145
|
-
this.arena.set_start_offset(node, start);
|
|
146
|
-
let name_end = end - 1;
|
|
147
|
-
this.arena.set_content_start(node, start);
|
|
148
|
-
this.arena.set_content_length(node, name_end - start);
|
|
149
|
-
let args = [];
|
|
150
|
-
let paren_depth = 1;
|
|
151
|
-
let func_end = end;
|
|
152
|
-
while (this.lexer.pos < this.value_end && paren_depth > 0) {
|
|
153
|
-
this.lexer.next_token_fast(false);
|
|
154
|
-
let token_type = this.lexer.token_type;
|
|
155
|
-
if (token_type === TOKEN_EOF) break;
|
|
156
|
-
if (this.lexer.token_start >= this.value_end) break;
|
|
157
|
-
if (token_type === TOKEN_LEFT_PAREN) {
|
|
158
|
-
paren_depth++;
|
|
159
|
-
} else if (token_type === TOKEN_RIGHT_PAREN) {
|
|
160
|
-
paren_depth--;
|
|
161
|
-
if (paren_depth === 0) {
|
|
162
|
-
func_end = this.lexer.token_end;
|
|
163
|
-
break;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
if (this.is_whitespace_token()) continue;
|
|
167
|
-
let arg_node = this.parse_value_node();
|
|
168
|
-
if (arg_node !== null) {
|
|
169
|
-
args.push(arg_node);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
this.arena.set_length(node, func_end - start);
|
|
173
|
-
if (args.length > 0) {
|
|
174
|
-
this.arena.set_first_child(node, args[0]);
|
|
175
|
-
this.arena.set_last_child(node, args[args.length - 1]);
|
|
176
|
-
for (let i = 0; i < args.length - 1; i++) {
|
|
177
|
-
this.arena.set_next_sibling(args[i], args[i + 1]);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return node;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
1
|
+
import { L as Lexer, y as TOKEN_EOF, b as TOKEN_AT_KEYWORD, v as TOKEN_LEFT_BRACE, w as TOKEN_RIGHT_BRACE, T as TOKEN_IDENT, o as TOKEN_COLON, p as TOKEN_SEMICOLON, h as TOKEN_DELIM } from './lexer-CtBKgfVv.js';
|
|
2
|
+
import { T as CSSDataArena, k as NODE_STYLESHEET, C as CSSNode, N as NODE_STYLE_RULE, U as FLAG_HAS_BLOCK, V as NODE_BLOCK, W as FLAG_HAS_DECLARATIONS, s as NODE_SELECTOR_LIST, i as NODE_DECLARATION, X as is_vendor_prefixed, Y as FLAG_VENDOR_PREFIXED, Z as trim_boundaries, S as FLAG_IMPORTANT, g as NODE_AT_RULE } from './css-node-BzCSxoLM.js';
|
|
3
|
+
export { h as NODE_COMMENT, J as NODE_PRELUDE_CONTAINER_QUERY, M as NODE_PRELUDE_IDENTIFIER, Q as NODE_PRELUDE_IMPORT_LAYER, R as NODE_PRELUDE_IMPORT_SUPPORTS, P as NODE_PRELUDE_IMPORT_URL, L as NODE_PRELUDE_LAYER_NAME, H as NODE_PRELUDE_MEDIA_FEATURE, G as NODE_PRELUDE_MEDIA_QUERY, I as NODE_PRELUDE_MEDIA_TYPE, O as NODE_PRELUDE_OPERATOR, K as NODE_PRELUDE_SUPPORTS_QUERY, j as NODE_SELECTOR, w as NODE_SELECTOR_ATTRIBUTE, u as NODE_SELECTOR_CLASS, z as NODE_SELECTOR_COMBINATOR, v as NODE_SELECTOR_ID, _ as NODE_SELECTOR_LANG, D as NODE_SELECTOR_NESTING, E as NODE_SELECTOR_NTH, F as NODE_SELECTOR_NTH_OF, x as NODE_SELECTOR_PSEUDO_CLASS, y as NODE_SELECTOR_PSEUDO_ELEMENT, t as NODE_SELECTOR_TYPE, B as NODE_SELECTOR_UNIVERSAL, p as NODE_VALUE_COLOR, n as NODE_VALUE_DIMENSION, q as NODE_VALUE_FUNCTION, l as NODE_VALUE_KEYWORD, m as NODE_VALUE_NUMBER, r as NODE_VALUE_OPERATOR, o as NODE_VALUE_STRING } from './css-node-BzCSxoLM.js';
|
|
4
|
+
import { ValueParser } from './parse-value.js';
|
|
5
|
+
import { SelectorParser } from './parse-selector.js';
|
|
6
|
+
import { AtRulePreludeParser } from './parse-atrule-prelude.js';
|
|
183
7
|
|
|
184
8
|
let DECLARATION_AT_RULES = /* @__PURE__ */ new Set(["font-face", "font-feature-values", "page", "property", "counter-style"]);
|
|
185
9
|
let CONDITIONAL_AT_RULES = /* @__PURE__ */ new Set(["media", "supports", "container", "layer", "nest"]);
|
|
@@ -273,15 +97,23 @@ class Parser {
|
|
|
273
97
|
if (this.peek_type() !== TOKEN_LEFT_BRACE) {
|
|
274
98
|
return null;
|
|
275
99
|
}
|
|
100
|
+
let block_start = this.lexer.token_end;
|
|
276
101
|
this.next_token();
|
|
277
102
|
this.arena.set_flag(style_rule, FLAG_HAS_BLOCK);
|
|
103
|
+
let block_line = this.lexer.token_line;
|
|
104
|
+
let block_column = this.lexer.token_column;
|
|
105
|
+
let block_node = this.arena.create_node();
|
|
106
|
+
this.arena.set_type(block_node, NODE_BLOCK);
|
|
107
|
+
this.arena.set_start_offset(block_node, block_start);
|
|
108
|
+
this.arena.set_start_line(block_node, block_line);
|
|
109
|
+
this.arena.set_start_column(block_node, block_column);
|
|
278
110
|
while (!this.is_eof()) {
|
|
279
111
|
let token_type = this.peek_type();
|
|
280
112
|
if (token_type === TOKEN_RIGHT_BRACE) break;
|
|
281
113
|
if (token_type === TOKEN_AT_KEYWORD) {
|
|
282
114
|
let nested_at_rule = this.parse_atrule();
|
|
283
115
|
if (nested_at_rule !== null) {
|
|
284
|
-
this.arena.append_child(
|
|
116
|
+
this.arena.append_child(block_node, nested_at_rule);
|
|
285
117
|
} else {
|
|
286
118
|
this.next_token();
|
|
287
119
|
}
|
|
@@ -290,21 +122,27 @@ class Parser {
|
|
|
290
122
|
let declaration = this.parse_declaration();
|
|
291
123
|
if (declaration !== null) {
|
|
292
124
|
this.arena.set_flag(style_rule, FLAG_HAS_DECLARATIONS);
|
|
293
|
-
this.arena.append_child(
|
|
125
|
+
this.arena.append_child(block_node, declaration);
|
|
294
126
|
continue;
|
|
295
127
|
}
|
|
296
128
|
let nested_rule = this.parse_style_rule();
|
|
297
129
|
if (nested_rule !== null) {
|
|
298
|
-
this.arena.append_child(
|
|
130
|
+
this.arena.append_child(block_node, nested_rule);
|
|
299
131
|
} else {
|
|
300
132
|
this.next_token();
|
|
301
133
|
}
|
|
302
134
|
}
|
|
135
|
+
let block_end = this.lexer.token_start;
|
|
136
|
+
let rule_end = this.lexer.token_end;
|
|
303
137
|
if (this.peek_type() === TOKEN_RIGHT_BRACE) {
|
|
138
|
+
block_end = this.lexer.token_start;
|
|
139
|
+
rule_end = this.lexer.token_end;
|
|
304
140
|
this.next_token();
|
|
305
141
|
}
|
|
142
|
+
this.arena.set_length(block_node, block_end - block_start);
|
|
143
|
+
this.arena.append_child(style_rule, block_node);
|
|
306
144
|
this.arena.set_start_offset(style_rule, rule_start);
|
|
307
|
-
this.arena.set_length(style_rule,
|
|
145
|
+
this.arena.set_length(style_rule, rule_end - rule_start);
|
|
308
146
|
return style_rule;
|
|
309
147
|
}
|
|
310
148
|
// Parse a selector (everything before '{')
|
|
@@ -341,8 +179,10 @@ class Parser {
|
|
|
341
179
|
let prop_end = this.lexer.token_end;
|
|
342
180
|
let decl_line = this.lexer.token_line;
|
|
343
181
|
let decl_column = this.lexer.token_column;
|
|
182
|
+
const saved = this.lexer.save_position();
|
|
344
183
|
this.next_token();
|
|
345
184
|
if (this.peek_type() !== TOKEN_COLON) {
|
|
185
|
+
this.lexer.restore_position(saved);
|
|
346
186
|
return null;
|
|
347
187
|
}
|
|
348
188
|
this.next_token();
|
|
@@ -363,12 +203,17 @@ class Parser {
|
|
|
363
203
|
while (!this.is_eof()) {
|
|
364
204
|
let token_type = this.peek_type();
|
|
365
205
|
if (token_type === TOKEN_SEMICOLON || token_type === TOKEN_RIGHT_BRACE) break;
|
|
206
|
+
if (token_type === TOKEN_LEFT_BRACE) {
|
|
207
|
+
this.lexer.restore_position(saved);
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
366
210
|
if (token_type === TOKEN_DELIM && this.source[this.lexer.token_start] === "!") {
|
|
367
211
|
value_end = this.lexer.token_start;
|
|
368
212
|
let next_type = this.lexer.next_token_fast();
|
|
369
213
|
if (next_type === TOKEN_IDENT) {
|
|
370
214
|
has_important = true;
|
|
371
215
|
last_end = this.lexer.token_end;
|
|
216
|
+
this.next_token();
|
|
372
217
|
break;
|
|
373
218
|
}
|
|
374
219
|
}
|
|
@@ -439,8 +284,16 @@ class Parser {
|
|
|
439
284
|
}
|
|
440
285
|
let last_end = this.lexer.token_end;
|
|
441
286
|
if (this.peek_type() === TOKEN_LEFT_BRACE) {
|
|
287
|
+
let block_start = this.lexer.token_end;
|
|
442
288
|
this.next_token();
|
|
443
289
|
this.arena.set_flag(at_rule, FLAG_HAS_BLOCK);
|
|
290
|
+
let block_line = this.lexer.token_line;
|
|
291
|
+
let block_column = this.lexer.token_column;
|
|
292
|
+
let block_node = this.arena.create_node();
|
|
293
|
+
this.arena.set_type(block_node, NODE_BLOCK);
|
|
294
|
+
this.arena.set_start_offset(block_node, block_start);
|
|
295
|
+
this.arena.set_start_line(block_node, block_line);
|
|
296
|
+
this.arena.set_start_column(block_node, block_column);
|
|
444
297
|
let has_declarations = this.atrule_has_declarations(at_rule_name);
|
|
445
298
|
let is_conditional = this.atrule_is_conditional(at_rule_name);
|
|
446
299
|
if (has_declarations) {
|
|
@@ -449,7 +302,7 @@ class Parser {
|
|
|
449
302
|
if (token_type === TOKEN_RIGHT_BRACE) break;
|
|
450
303
|
let declaration = this.parse_declaration();
|
|
451
304
|
if (declaration !== null) {
|
|
452
|
-
this.arena.append_child(
|
|
305
|
+
this.arena.append_child(block_node, declaration);
|
|
453
306
|
} else {
|
|
454
307
|
this.next_token();
|
|
455
308
|
}
|
|
@@ -461,7 +314,7 @@ class Parser {
|
|
|
461
314
|
if (token_type === TOKEN_AT_KEYWORD) {
|
|
462
315
|
let nested_at_rule = this.parse_atrule();
|
|
463
316
|
if (nested_at_rule !== null) {
|
|
464
|
-
this.arena.append_child(
|
|
317
|
+
this.arena.append_child(block_node, nested_at_rule);
|
|
465
318
|
} else {
|
|
466
319
|
this.next_token();
|
|
467
320
|
}
|
|
@@ -469,12 +322,12 @@ class Parser {
|
|
|
469
322
|
}
|
|
470
323
|
let declaration = this.parse_declaration();
|
|
471
324
|
if (declaration !== null) {
|
|
472
|
-
this.arena.append_child(
|
|
325
|
+
this.arena.append_child(block_node, declaration);
|
|
473
326
|
continue;
|
|
474
327
|
}
|
|
475
328
|
let nested_rule = this.parse_style_rule();
|
|
476
329
|
if (nested_rule !== null) {
|
|
477
|
-
this.arena.append_child(
|
|
330
|
+
this.arena.append_child(block_node, nested_rule);
|
|
478
331
|
} else {
|
|
479
332
|
this.next_token();
|
|
480
333
|
}
|
|
@@ -485,16 +338,21 @@ class Parser {
|
|
|
485
338
|
if (token_type === TOKEN_RIGHT_BRACE) break;
|
|
486
339
|
let rule = this.parse_rule();
|
|
487
340
|
if (rule !== null) {
|
|
488
|
-
this.arena.append_child(
|
|
341
|
+
this.arena.append_child(block_node, rule);
|
|
489
342
|
} else {
|
|
490
343
|
this.next_token();
|
|
491
344
|
}
|
|
492
345
|
}
|
|
493
346
|
}
|
|
494
347
|
if (this.peek_type() === TOKEN_RIGHT_BRACE) {
|
|
495
|
-
|
|
348
|
+
let block_end = this.lexer.token_start;
|
|
496
349
|
this.next_token();
|
|
350
|
+
last_end = this.lexer.token_end;
|
|
351
|
+
this.arena.set_length(block_node, block_end - block_start);
|
|
352
|
+
} else {
|
|
353
|
+
this.arena.set_length(block_node, last_end - block_start);
|
|
497
354
|
}
|
|
355
|
+
this.arena.append_child(at_rule, block_node);
|
|
498
356
|
} else if (this.peek_type() === TOKEN_SEMICOLON) {
|
|
499
357
|
last_end = this.lexer.token_end;
|
|
500
358
|
this.next_token();
|
|
@@ -511,10 +369,9 @@ class Parser {
|
|
|
511
369
|
return CONDITIONAL_AT_RULES.has(name.toLowerCase());
|
|
512
370
|
}
|
|
513
371
|
}
|
|
514
|
-
|
|
515
372
|
function parse(source, options) {
|
|
516
373
|
const parser = new Parser(source, options);
|
|
517
374
|
return parser.parse();
|
|
518
375
|
}
|
|
519
376
|
|
|
520
|
-
export { parse };
|
|
377
|
+
export { FLAG_IMPORTANT, NODE_AT_RULE, NODE_BLOCK, NODE_DECLARATION, NODE_SELECTOR_LIST, NODE_STYLESHEET, NODE_STYLE_RULE, Parser, parse };
|
package/dist/string-utils.d.ts
CHANGED
|
@@ -6,23 +6,24 @@ export declare const CHAR_FORM_FEED = 12;
|
|
|
6
6
|
export declare const CHAR_FORWARD_SLASH = 47;
|
|
7
7
|
export declare const CHAR_ASTERISK = 42;
|
|
8
8
|
export declare const CHAR_MINUS_HYPHEN = 45;
|
|
9
|
+
export declare const CHAR_SINGLE_QUOTE = 39;
|
|
10
|
+
export declare const CHAR_DOUBLE_QUOTE = 34;
|
|
11
|
+
export declare const CHAR_PLUS = 43;
|
|
12
|
+
export declare const CHAR_PERIOD = 46;
|
|
13
|
+
export declare const CHAR_TILDE = 126;
|
|
14
|
+
export declare const CHAR_GREATER_THAN = 62;
|
|
15
|
+
export declare const CHAR_AMPERSAND = 38;
|
|
16
|
+
export declare const CHAR_EQUALS = 61;
|
|
17
|
+
export declare const CHAR_PIPE = 124;
|
|
18
|
+
export declare const CHAR_DOLLAR = 36;
|
|
19
|
+
export declare const CHAR_CARET = 94;
|
|
20
|
+
export declare const CHAR_COLON = 58;
|
|
9
21
|
/**
|
|
10
22
|
* Check if a character code is whitespace (space, tab, newline, CR, or FF)
|
|
11
23
|
*/
|
|
12
24
|
export declare function is_whitespace(ch: number): boolean;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*
|
|
16
|
-
* @param source - The source string
|
|
17
|
-
* @param start - Start offset in source
|
|
18
|
-
* @param end - End offset in source
|
|
19
|
-
* @returns [trimmed_start, trimmed_end] or null if all whitespace/comments
|
|
20
|
-
*
|
|
21
|
-
* Skips whitespace (space, tab, newline, CR, FF) and CSS comments from both ends
|
|
22
|
-
* of the specified range. Returns the trimmed boundaries or null if the range
|
|
23
|
-
* contains only whitespace and comments.
|
|
24
|
-
*/
|
|
25
|
-
export declare function trim_boundaries(source: string, start: number, end: number): [number, number] | null;
|
|
25
|
+
export declare function is_combinator(ch: number): boolean;
|
|
26
|
+
export declare function is_digit(ch: number): boolean;
|
|
26
27
|
/**
|
|
27
28
|
* @param a Base string, MUST be lowercase!
|
|
28
29
|
* @param b Compare string
|
package/dist/tokenize.js
CHANGED
package/dist/walk.d.ts
CHANGED
|
@@ -16,5 +16,5 @@ interface WalkEnterLeaveOptions {
|
|
|
16
16
|
* @param node - The root node to start walking from
|
|
17
17
|
* @param options - Object with optional enter and leave callback functions
|
|
18
18
|
*/
|
|
19
|
-
export declare function
|
|
19
|
+
export declare function traverse(node: CSSNode, { enter, leave }?: WalkEnterLeaveOptions): void;
|
|
20
20
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@projectwallace/css-parser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "High-performance CSS lexer and parser, optimized for CSS inspection and analysis",
|
|
5
5
|
"author": "Bart Veneman <bat@projectwallace.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,6 +34,14 @@
|
|
|
34
34
|
"./parse-atrule-prelude": {
|
|
35
35
|
"types": "./dist/parse-atrule-prelude.d.ts",
|
|
36
36
|
"import": "./dist/parse-atrule-prelude.js"
|
|
37
|
+
},
|
|
38
|
+
"./parse-value": {
|
|
39
|
+
"types": "./dist/parse-value.d.ts",
|
|
40
|
+
"import": "./dist/parse-value.js"
|
|
41
|
+
},
|
|
42
|
+
"./parse-anplusb": {
|
|
43
|
+
"types": "./dist/parse-anplusb.d.ts",
|
|
44
|
+
"import": "./dist/parse-anplusb.js"
|
|
37
45
|
}
|
|
38
46
|
},
|
|
39
47
|
"files": [
|