@projectwallace/css-parser 0.12.4 → 0.13.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 +2 -1
- package/dist/arena.js +3 -2
- package/dist/constants.d.ts +1 -1
- package/dist/css-node.d.ts +13 -9
- package/dist/css-node.js +106 -60
- package/dist/index.js +1 -1
- package/dist/parse-value.js +4 -2
- package/dist/token-types.d.ts +2 -1
- package/dist/token-types.js +2 -1
- package/dist/tokenize.js +50 -1
- package/package.json +1 -1
package/dist/arena.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export declare const FUNCTION = 15;
|
|
|
14
14
|
export declare const OPERATOR = 16;
|
|
15
15
|
export declare const PARENTHESIS = 17;
|
|
16
16
|
export declare const URL = 18;
|
|
17
|
-
export declare const
|
|
17
|
+
export declare const UNICODE_RANGE = 19;
|
|
18
18
|
export declare const SELECTOR_LIST = 20;
|
|
19
19
|
export declare const TYPE_SELECTOR = 21;
|
|
20
20
|
export declare const CLASS_SELECTOR = 22;
|
|
@@ -37,6 +37,7 @@ export declare const LAYER_NAME = 37;
|
|
|
37
37
|
export declare const PRELUDE_OPERATOR = 38;
|
|
38
38
|
export declare const FEATURE_RANGE = 39;
|
|
39
39
|
export declare const AT_RULE_PRELUDE = 40;
|
|
40
|
+
export declare const VALUE = 50;
|
|
40
41
|
export declare const FLAG_IMPORTANT: number;
|
|
41
42
|
export declare const FLAG_HAS_ERROR: number;
|
|
42
43
|
export declare const FLAG_LENGTH_OVERFLOW: number;
|
package/dist/arena.js
CHANGED
|
@@ -15,7 +15,7 @@ const FUNCTION = 15;
|
|
|
15
15
|
const OPERATOR = 16;
|
|
16
16
|
const PARENTHESIS = 17;
|
|
17
17
|
const URL = 18;
|
|
18
|
-
const
|
|
18
|
+
const UNICODE_RANGE = 19;
|
|
19
19
|
const SELECTOR_LIST = 20;
|
|
20
20
|
const TYPE_SELECTOR = 21;
|
|
21
21
|
const CLASS_SELECTOR = 22;
|
|
@@ -38,6 +38,7 @@ const LAYER_NAME = 37;
|
|
|
38
38
|
const PRELUDE_OPERATOR = 38;
|
|
39
39
|
const FEATURE_RANGE = 39;
|
|
40
40
|
const AT_RULE_PRELUDE = 40;
|
|
41
|
+
const VALUE = 50;
|
|
41
42
|
const FLAG_IMPORTANT = 1 << 0;
|
|
42
43
|
const FLAG_HAS_ERROR = 1 << 1;
|
|
43
44
|
const FLAG_LENGTH_OVERFLOW = 1 << 2;
|
|
@@ -285,4 +286,4 @@ class CSSDataArena {
|
|
|
285
286
|
}
|
|
286
287
|
}
|
|
287
288
|
|
|
288
|
-
export { ATTRIBUTE_SELECTOR, ATTR_FLAG_CASE_INSENSITIVE, ATTR_FLAG_CASE_SENSITIVE, ATTR_FLAG_NONE, ATTR_OPERATOR_CARET_EQUAL, ATTR_OPERATOR_DOLLAR_EQUAL, ATTR_OPERATOR_EQUAL, ATTR_OPERATOR_NONE, ATTR_OPERATOR_PIPE_EQUAL, ATTR_OPERATOR_STAR_EQUAL, ATTR_OPERATOR_TILDE_EQUAL, AT_RULE, AT_RULE_PRELUDE, BLOCK, CLASS_SELECTOR, COMBINATOR, COMMENT, CONTAINER_QUERY, CSSDataArena, DECLARATION, DIMENSION, FEATURE_RANGE, FLAG_BROWSERHACK, FLAG_HAS_BLOCK, FLAG_HAS_DECLARATIONS, FLAG_HAS_ERROR, FLAG_HAS_PARENS, FLAG_IMPORTANT, FLAG_LENGTH_OVERFLOW, FUNCTION, HASH, IDENTIFIER, ID_SELECTOR, LANG_SELECTOR, LAYER_NAME, MEDIA_FEATURE, MEDIA_QUERY, MEDIA_TYPE, NESTING_SELECTOR, NTH_OF_SELECTOR, NTH_SELECTOR, NUMBER, OPERATOR, PARENTHESIS, PRELUDE_OPERATOR, PSEUDO_CLASS_SELECTOR, PSEUDO_ELEMENT_SELECTOR, SELECTOR, SELECTOR_LIST, STRING, STYLESHEET, STYLE_RULE, SUPPORTS_QUERY, TYPE_SELECTOR, UNIVERSAL_SELECTOR, URL, VALUE };
|
|
289
|
+
export { ATTRIBUTE_SELECTOR, ATTR_FLAG_CASE_INSENSITIVE, ATTR_FLAG_CASE_SENSITIVE, ATTR_FLAG_NONE, ATTR_OPERATOR_CARET_EQUAL, ATTR_OPERATOR_DOLLAR_EQUAL, ATTR_OPERATOR_EQUAL, ATTR_OPERATOR_NONE, ATTR_OPERATOR_PIPE_EQUAL, ATTR_OPERATOR_STAR_EQUAL, ATTR_OPERATOR_TILDE_EQUAL, AT_RULE, AT_RULE_PRELUDE, BLOCK, CLASS_SELECTOR, COMBINATOR, COMMENT, CONTAINER_QUERY, CSSDataArena, DECLARATION, DIMENSION, FEATURE_RANGE, FLAG_BROWSERHACK, FLAG_HAS_BLOCK, FLAG_HAS_DECLARATIONS, FLAG_HAS_ERROR, FLAG_HAS_PARENS, FLAG_IMPORTANT, FLAG_LENGTH_OVERFLOW, FUNCTION, HASH, IDENTIFIER, ID_SELECTOR, LANG_SELECTOR, LAYER_NAME, MEDIA_FEATURE, MEDIA_QUERY, MEDIA_TYPE, NESTING_SELECTOR, NTH_OF_SELECTOR, NTH_SELECTOR, NUMBER, OPERATOR, PARENTHESIS, PRELUDE_OPERATOR, PSEUDO_CLASS_SELECTOR, PSEUDO_ELEMENT_SELECTOR, SELECTOR, SELECTOR_LIST, STRING, STYLESHEET, STYLE_RULE, SUPPORTS_QUERY, TYPE_SELECTOR, UNICODE_RANGE, UNIVERSAL_SELECTOR, URL, VALUE };
|
package/dist/constants.d.ts
CHANGED
package/dist/css-node.d.ts
CHANGED
|
@@ -17,7 +17,8 @@ export declare const TYPE_NAMES: {
|
|
|
17
17
|
readonly 16: "Operator";
|
|
18
18
|
readonly 17: "Parentheses";
|
|
19
19
|
readonly 18: "Url";
|
|
20
|
-
readonly 19: "
|
|
20
|
+
readonly 19: "UnicodeRange";
|
|
21
|
+
readonly 50: "Value";
|
|
21
22
|
readonly 20: "SelectorList";
|
|
22
23
|
readonly 21: "TypeSelector";
|
|
23
24
|
readonly 22: "ClassSelector";
|
|
@@ -42,6 +43,8 @@ export declare const TYPE_NAMES: {
|
|
|
42
43
|
readonly 40: "AtrulePrelude";
|
|
43
44
|
};
|
|
44
45
|
export type TypeName = (typeof TYPE_NAMES)[keyof typeof TYPE_NAMES] | 'unknown';
|
|
46
|
+
export declare const ATTR_OPERATOR_NAMES: Record<number, string | null>;
|
|
47
|
+
export declare const ATTR_FLAG_NAMES: Record<number, string | null>;
|
|
45
48
|
export type CSSNodeType = typeof STYLESHEET | typeof STYLE_RULE | typeof AT_RULE | typeof DECLARATION | typeof SELECTOR | typeof COMMENT | typeof BLOCK | typeof IDENTIFIER | typeof NUMBER | typeof DIMENSION | typeof STRING | typeof HASH | typeof FUNCTION | typeof OPERATOR | typeof PARENTHESIS | typeof URL | typeof VALUE | typeof SELECTOR_LIST | typeof TYPE_SELECTOR | typeof CLASS_SELECTOR | typeof ID_SELECTOR | typeof ATTRIBUTE_SELECTOR | typeof PSEUDO_CLASS_SELECTOR | typeof PSEUDO_ELEMENT_SELECTOR | typeof COMBINATOR | typeof UNIVERSAL_SELECTOR | typeof NESTING_SELECTOR | typeof NTH_SELECTOR | typeof NTH_OF_SELECTOR | typeof LANG_SELECTOR | typeof MEDIA_QUERY | typeof MEDIA_FEATURE | typeof MEDIA_TYPE | typeof CONTAINER_QUERY | typeof SUPPORTS_QUERY | typeof LAYER_NAME | typeof PRELUDE_OPERATOR | typeof FEATURE_RANGE | typeof AT_RULE_PRELUDE;
|
|
46
49
|
export interface CloneOptions {
|
|
47
50
|
/**
|
|
@@ -59,18 +62,18 @@ export type PlainCSSNode = {
|
|
|
59
62
|
type: number;
|
|
60
63
|
type_name: TypeName;
|
|
61
64
|
text: string;
|
|
62
|
-
children
|
|
65
|
+
children?: PlainCSSNode[];
|
|
63
66
|
name?: string;
|
|
64
67
|
property?: string;
|
|
65
|
-
value?: string | number | null;
|
|
68
|
+
value?: PlainCSSNode | string | number | null;
|
|
66
69
|
unit?: string;
|
|
67
70
|
prelude?: PlainCSSNode | null;
|
|
68
71
|
is_important?: boolean;
|
|
69
72
|
is_vendor_prefixed?: boolean;
|
|
70
73
|
is_browserhack?: boolean;
|
|
71
74
|
has_error?: boolean;
|
|
72
|
-
attr_operator?:
|
|
73
|
-
attr_flags?:
|
|
75
|
+
attr_operator?: string | null;
|
|
76
|
+
attr_flags?: string | null;
|
|
74
77
|
nth_a?: string | null;
|
|
75
78
|
nth_b?: string | null;
|
|
76
79
|
line?: number;
|
|
@@ -84,19 +87,20 @@ export declare class CSSNode {
|
|
|
84
87
|
private source;
|
|
85
88
|
private index;
|
|
86
89
|
constructor(arena: CSSDataArena, source: string, index: number);
|
|
90
|
+
private get_content;
|
|
87
91
|
/** Get node type as number (for performance) */
|
|
88
92
|
get type(): CSSNodeType;
|
|
89
93
|
/** Get node type as human-readable string */
|
|
90
94
|
get type_name(): TypeName;
|
|
91
95
|
/** Get the full text of this node from source */
|
|
92
96
|
get text(): string;
|
|
93
|
-
/** Get the "content" text (
|
|
94
|
-
get name(): string;
|
|
97
|
+
/** Get the "content" text (at-rule name for at-rules, layer name for import layers) */
|
|
98
|
+
get name(): string | undefined;
|
|
95
99
|
/**
|
|
96
100
|
* Alias for name (for declarations: "color" in "color: blue")
|
|
97
101
|
* More semantic than `name` for declaration nodes
|
|
98
102
|
*/
|
|
99
|
-
get property(): string;
|
|
103
|
+
get property(): string | undefined;
|
|
100
104
|
/**
|
|
101
105
|
* Get the value text (for declarations: "blue" in "color: blue")
|
|
102
106
|
* For dimension/number nodes: returns the numeric value as a number
|
|
@@ -104,7 +108,7 @@ export declare class CSSNode {
|
|
|
104
108
|
* For URL nodes with quoted string: returns the string with quotes (consistent with STRING node)
|
|
105
109
|
* For URL nodes with unquoted URL: returns the URL content without quotes
|
|
106
110
|
*/
|
|
107
|
-
get value(): CSSNode | string | number | null;
|
|
111
|
+
get value(): CSSNode | string | number | null | undefined;
|
|
108
112
|
/** Get the numeric value for NUMBER and DIMENSION nodes, or null for other node types */
|
|
109
113
|
get value_as_number(): number | null;
|
|
110
114
|
/**
|
package/dist/css-node.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DECLARATION, DIMENSION, NUMBER, URL, STRING, AT_RULE, AT_RULE_PRELUDE, STYLE_RULE, ATTRIBUTE_SELECTOR, FLAG_IMPORTANT, FLAG_BROWSERHACK, IDENTIFIER, FUNCTION, PSEUDO_ELEMENT_SELECTOR, PSEUDO_CLASS_SELECTOR, FLAG_HAS_ERROR, FLAG_HAS_BLOCK, FLAG_HAS_DECLARATIONS, BLOCK, COMMENT, FLAG_HAS_PARENS, NTH_SELECTOR, NTH_OF_SELECTOR, SELECTOR_LIST, FEATURE_RANGE, PRELUDE_OPERATOR, LAYER_NAME, SUPPORTS_QUERY, CONTAINER_QUERY, MEDIA_TYPE,
|
|
1
|
+
import { DECLARATION, OPERATOR, SELECTOR, MEDIA_FEATURE, DIMENSION, NUMBER, URL, STRING, AT_RULE, AT_RULE_PRELUDE, STYLE_RULE, ATTRIBUTE_SELECTOR, FLAG_IMPORTANT, FLAG_BROWSERHACK, IDENTIFIER, FUNCTION, PSEUDO_ELEMENT_SELECTOR, PSEUDO_CLASS_SELECTOR, FLAG_HAS_ERROR, FLAG_HAS_BLOCK, FLAG_HAS_DECLARATIONS, BLOCK, COMMENT, FLAG_HAS_PARENS, NTH_SELECTOR, NTH_OF_SELECTOR, SELECTOR_LIST, FEATURE_RANGE, PRELUDE_OPERATOR, LAYER_NAME, SUPPORTS_QUERY, CONTAINER_QUERY, MEDIA_TYPE, MEDIA_QUERY, LANG_SELECTOR, NESTING_SELECTOR, UNIVERSAL_SELECTOR, COMBINATOR, ID_SELECTOR, CLASS_SELECTOR, TYPE_SELECTOR, VALUE, UNICODE_RANGE, PARENTHESIS, HASH, STYLESHEET, ATTR_OPERATOR_STAR_EQUAL, ATTR_OPERATOR_DOLLAR_EQUAL, ATTR_OPERATOR_CARET_EQUAL, ATTR_OPERATOR_PIPE_EQUAL, ATTR_OPERATOR_TILDE_EQUAL, ATTR_OPERATOR_EQUAL, ATTR_OPERATOR_NONE, ATTR_FLAG_CASE_SENSITIVE, ATTR_FLAG_CASE_INSENSITIVE, ATTR_FLAG_NONE } from './arena.js';
|
|
2
2
|
import { str_starts_with, is_vendor_prefixed, is_whitespace, CHAR_MINUS_HYPHEN, CHAR_PLUS } from './string-utils.js';
|
|
3
3
|
import { parse_dimension } from './parse-dimension.js';
|
|
4
4
|
|
|
@@ -19,6 +19,7 @@ const TYPE_NAMES = {
|
|
|
19
19
|
[OPERATOR]: "Operator",
|
|
20
20
|
[PARENTHESIS]: "Parentheses",
|
|
21
21
|
[URL]: "Url",
|
|
22
|
+
[UNICODE_RANGE]: "UnicodeRange",
|
|
22
23
|
[VALUE]: "Value",
|
|
23
24
|
[SELECTOR_LIST]: "SelectorList",
|
|
24
25
|
[TYPE_SELECTOR]: "TypeSelector",
|
|
@@ -43,6 +44,20 @@ const TYPE_NAMES = {
|
|
|
43
44
|
[FEATURE_RANGE]: "MediaFeatureRange",
|
|
44
45
|
[AT_RULE_PRELUDE]: "AtrulePrelude"
|
|
45
46
|
};
|
|
47
|
+
const ATTR_OPERATOR_NAMES = {
|
|
48
|
+
[ATTR_OPERATOR_NONE]: null,
|
|
49
|
+
[ATTR_OPERATOR_EQUAL]: "=",
|
|
50
|
+
[ATTR_OPERATOR_TILDE_EQUAL]: "~=",
|
|
51
|
+
[ATTR_OPERATOR_PIPE_EQUAL]: "|=",
|
|
52
|
+
[ATTR_OPERATOR_CARET_EQUAL]: "^=",
|
|
53
|
+
[ATTR_OPERATOR_DOLLAR_EQUAL]: "$=",
|
|
54
|
+
[ATTR_OPERATOR_STAR_EQUAL]: "*="
|
|
55
|
+
};
|
|
56
|
+
const ATTR_FLAG_NAMES = {
|
|
57
|
+
[ATTR_FLAG_NONE]: null,
|
|
58
|
+
[ATTR_FLAG_CASE_INSENSITIVE]: "i",
|
|
59
|
+
[ATTR_FLAG_CASE_SENSITIVE]: "s"
|
|
60
|
+
};
|
|
46
61
|
class CSSNode {
|
|
47
62
|
arena;
|
|
48
63
|
source;
|
|
@@ -59,6 +74,12 @@ class CSSNode {
|
|
|
59
74
|
__get_arena() {
|
|
60
75
|
return this.arena;
|
|
61
76
|
}
|
|
77
|
+
get_content() {
|
|
78
|
+
let start = this.arena.get_content_start(this.index);
|
|
79
|
+
let length = this.arena.get_content_length(this.index);
|
|
80
|
+
if (length === 0) return "";
|
|
81
|
+
return this.source.substring(start, start + length);
|
|
82
|
+
}
|
|
62
83
|
/** Get node type as number (for performance) */
|
|
63
84
|
get type() {
|
|
64
85
|
return this.arena.get_type(this.index);
|
|
@@ -73,19 +94,20 @@ class CSSNode {
|
|
|
73
94
|
let length = this.arena.get_length(this.index);
|
|
74
95
|
return this.source.substring(start, start + length);
|
|
75
96
|
}
|
|
76
|
-
/** Get the "content" text (
|
|
97
|
+
/** Get the "content" text (at-rule name for at-rules, layer name for import layers) */
|
|
77
98
|
get name() {
|
|
78
|
-
let
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return this.source.substring(start, start + length);
|
|
99
|
+
let { type } = this;
|
|
100
|
+
if (type === DECLARATION || type === OPERATOR || type === SELECTOR) return;
|
|
101
|
+
return this.get_content();
|
|
82
102
|
}
|
|
83
103
|
/**
|
|
84
104
|
* Alias for name (for declarations: "color" in "color: blue")
|
|
85
105
|
* More semantic than `name` for declaration nodes
|
|
86
106
|
*/
|
|
87
107
|
get property() {
|
|
88
|
-
|
|
108
|
+
let { type } = this;
|
|
109
|
+
if (type !== DECLARATION && type !== MEDIA_FEATURE) return;
|
|
110
|
+
return this.get_content();
|
|
89
111
|
}
|
|
90
112
|
/**
|
|
91
113
|
* Get the value text (for declarations: "blue" in "color: blue")
|
|
@@ -95,32 +117,34 @@ class CSSNode {
|
|
|
95
117
|
* For URL nodes with unquoted URL: returns the URL content without quotes
|
|
96
118
|
*/
|
|
97
119
|
get value() {
|
|
98
|
-
let { type, text } = this;
|
|
99
|
-
if (type === DECLARATION &&
|
|
100
|
-
return
|
|
120
|
+
let { type, text, first_child } = this;
|
|
121
|
+
if (type === DECLARATION && first_child) {
|
|
122
|
+
return first_child;
|
|
101
123
|
}
|
|
102
124
|
if (type === DIMENSION) {
|
|
103
125
|
return parse_dimension(text).value;
|
|
104
126
|
}
|
|
105
127
|
if (type === NUMBER) {
|
|
106
|
-
return Number.parseFloat(
|
|
128
|
+
return Number.parseFloat(text);
|
|
107
129
|
}
|
|
108
130
|
if (type === URL) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return firstChild.text;
|
|
131
|
+
if (first_child?.type === STRING) {
|
|
132
|
+
return first_child.text;
|
|
112
133
|
}
|
|
113
134
|
if (str_starts_with(text, "url(")) {
|
|
114
|
-
let
|
|
115
|
-
let
|
|
116
|
-
if (
|
|
117
|
-
let content = text.substring(
|
|
135
|
+
let open_paren = text.indexOf("(");
|
|
136
|
+
let close_paren = text.lastIndexOf(")");
|
|
137
|
+
if (open_paren !== -1 && close_paren !== -1 && close_paren > open_paren) {
|
|
138
|
+
let content = text.substring(open_paren + 1, close_paren).trim();
|
|
118
139
|
return content;
|
|
119
140
|
}
|
|
120
141
|
} else if (text.startsWith('"') || text.startsWith("'")) {
|
|
121
142
|
return text;
|
|
122
143
|
}
|
|
123
144
|
}
|
|
145
|
+
if (type === OPERATOR) {
|
|
146
|
+
return this.get_content();
|
|
147
|
+
}
|
|
124
148
|
let start = this.arena.get_value_start(this.index);
|
|
125
149
|
let length = this.arena.get_value_length(this.index);
|
|
126
150
|
if (length === 0) return null;
|
|
@@ -128,11 +152,11 @@ class CSSNode {
|
|
|
128
152
|
}
|
|
129
153
|
/** Get the numeric value for NUMBER and DIMENSION nodes, or null for other node types */
|
|
130
154
|
get value_as_number() {
|
|
131
|
-
let text = this
|
|
132
|
-
if (
|
|
155
|
+
let { text, type } = this;
|
|
156
|
+
if (type === NUMBER) {
|
|
133
157
|
return Number.parseFloat(text);
|
|
134
158
|
}
|
|
135
|
-
if (
|
|
159
|
+
if (type === DIMENSION) {
|
|
136
160
|
return parse_dimension(text).value;
|
|
137
161
|
}
|
|
138
162
|
return null;
|
|
@@ -191,14 +215,14 @@ class CSSNode {
|
|
|
191
215
|
get is_vendor_prefixed() {
|
|
192
216
|
switch (this.type) {
|
|
193
217
|
case DECLARATION:
|
|
194
|
-
return is_vendor_prefixed(this.
|
|
218
|
+
return is_vendor_prefixed(this.get_content());
|
|
195
219
|
case PSEUDO_CLASS_SELECTOR:
|
|
196
220
|
case PSEUDO_ELEMENT_SELECTOR:
|
|
197
|
-
return is_vendor_prefixed(this.
|
|
221
|
+
return is_vendor_prefixed(this.get_content());
|
|
198
222
|
case AT_RULE:
|
|
199
|
-
return is_vendor_prefixed(this.
|
|
223
|
+
return is_vendor_prefixed(this.get_content());
|
|
200
224
|
case FUNCTION:
|
|
201
|
-
return is_vendor_prefixed(this.
|
|
225
|
+
return is_vendor_prefixed(this.get_content());
|
|
202
226
|
case IDENTIFIER:
|
|
203
227
|
return is_vendor_prefixed(this.text);
|
|
204
228
|
default:
|
|
@@ -211,10 +235,11 @@ class CSSNode {
|
|
|
211
235
|
}
|
|
212
236
|
/** Check if this node has a prelude (at-rules and style rules) */
|
|
213
237
|
get has_prelude() {
|
|
214
|
-
|
|
238
|
+
let { type } = this;
|
|
239
|
+
if (type === AT_RULE) {
|
|
215
240
|
return this.arena.get_value_length(this.index) > 0;
|
|
216
241
|
}
|
|
217
|
-
if (
|
|
242
|
+
if (type === STYLE_RULE) {
|
|
218
243
|
return this.first_child !== null;
|
|
219
244
|
}
|
|
220
245
|
return false;
|
|
@@ -229,16 +254,17 @@ class CSSNode {
|
|
|
229
254
|
}
|
|
230
255
|
/** Get the block node (for style rules and at-rules with blocks) */
|
|
231
256
|
get block() {
|
|
232
|
-
|
|
257
|
+
let { type } = this;
|
|
258
|
+
if (type === STYLE_RULE) {
|
|
233
259
|
let first = this.first_child;
|
|
234
260
|
if (!first) return null;
|
|
235
|
-
let
|
|
236
|
-
if (
|
|
237
|
-
return
|
|
261
|
+
let block_node = first.next_sibling;
|
|
262
|
+
if (block_node?.type === BLOCK) {
|
|
263
|
+
return block_node;
|
|
238
264
|
}
|
|
239
265
|
return null;
|
|
240
266
|
}
|
|
241
|
-
if (
|
|
267
|
+
if (type === AT_RULE) {
|
|
242
268
|
let child = this.first_child;
|
|
243
269
|
while (child) {
|
|
244
270
|
if (child.type === BLOCK && !child.next_sibling) {
|
|
@@ -309,7 +335,8 @@ class CSSNode {
|
|
|
309
335
|
* This allows formatters to distinguish :lang() from :hover
|
|
310
336
|
*/
|
|
311
337
|
get has_children() {
|
|
312
|
-
|
|
338
|
+
let { type } = this;
|
|
339
|
+
if (type === PSEUDO_CLASS_SELECTOR || type === PSEUDO_ELEMENT_SELECTOR) {
|
|
313
340
|
if (this.arena.has_flag(this.index, FLAG_HAS_PARENS)) {
|
|
314
341
|
return true;
|
|
315
342
|
}
|
|
@@ -337,22 +364,24 @@ class CSSNode {
|
|
|
337
364
|
// --- An+B Expression Helpers (for NODE_SELECTOR_NTH) ---
|
|
338
365
|
/** Get the 'a' coefficient from An+B expression (e.g., "2n" from "2n+1", "odd" from "odd") */
|
|
339
366
|
get nth_a() {
|
|
340
|
-
|
|
341
|
-
|
|
367
|
+
let { type, arena, index } = this;
|
|
368
|
+
if (type !== NTH_SELECTOR && type !== NTH_OF_SELECTOR) return void 0;
|
|
369
|
+
let len = arena.get_content_length(index);
|
|
342
370
|
if (len === 0) return void 0;
|
|
343
|
-
let start =
|
|
371
|
+
let start = arena.get_content_start(index);
|
|
344
372
|
return this.source.substring(start, start + len);
|
|
345
373
|
}
|
|
346
374
|
/** Get the 'b' coefficient from An+B expression (e.g., "+1" from "2n+1") */
|
|
347
375
|
get nth_b() {
|
|
348
|
-
|
|
349
|
-
|
|
376
|
+
let { type, arena, index, source } = this;
|
|
377
|
+
if (type !== NTH_SELECTOR && type !== NTH_OF_SELECTOR) return void 0;
|
|
378
|
+
let len = arena.get_value_length(index);
|
|
350
379
|
if (len === 0) return void 0;
|
|
351
|
-
let start =
|
|
352
|
-
let value =
|
|
380
|
+
let start = arena.get_value_start(index);
|
|
381
|
+
let value = source.substring(start, start + len);
|
|
353
382
|
let check_pos = start - 1;
|
|
354
383
|
while (check_pos >= 0) {
|
|
355
|
-
let ch =
|
|
384
|
+
let ch = source.charCodeAt(check_pos);
|
|
356
385
|
if (is_whitespace(ch)) {
|
|
357
386
|
check_pos--;
|
|
358
387
|
continue;
|
|
@@ -406,29 +435,45 @@ class CSSNode {
|
|
|
406
435
|
*/
|
|
407
436
|
clone(options = {}) {
|
|
408
437
|
const { deep = true, locations = false } = options;
|
|
438
|
+
let { type, name, property, value, unit } = this;
|
|
409
439
|
let plain = {
|
|
410
|
-
type
|
|
440
|
+
type,
|
|
411
441
|
type_name: this.type_name,
|
|
412
|
-
text: this.text
|
|
413
|
-
children: []
|
|
442
|
+
text: this.text
|
|
414
443
|
};
|
|
415
|
-
if (
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
444
|
+
if (name) {
|
|
445
|
+
plain.name = name;
|
|
446
|
+
}
|
|
447
|
+
if (property) {
|
|
448
|
+
plain.property = property;
|
|
449
|
+
}
|
|
450
|
+
if (value) {
|
|
451
|
+
plain.value = value;
|
|
452
|
+
if (unit) {
|
|
453
|
+
plain.unit = unit;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (type === DECLARATION) {
|
|
457
|
+
let { is_important, is_browserhack } = this;
|
|
458
|
+
if (is_important) {
|
|
459
|
+
plain.is_important = true;
|
|
460
|
+
}
|
|
461
|
+
if (is_browserhack) {
|
|
462
|
+
plain.is_browserhack = true;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
let { is_vendor_prefixed: is_vendor_prefixed2, has_error } = this;
|
|
466
|
+
if (is_vendor_prefixed2) {
|
|
467
|
+
plain.is_vendor_prefixed = true;
|
|
420
468
|
}
|
|
421
|
-
if (
|
|
422
|
-
plain.
|
|
423
|
-
plain.is_browserhack = this.is_browserhack;
|
|
469
|
+
if (has_error) {
|
|
470
|
+
plain.has_error = true;
|
|
424
471
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
plain.attr_operator = this.attr_operator;
|
|
429
|
-
plain.attr_flags = this.attr_flags;
|
|
472
|
+
if (type === ATTRIBUTE_SELECTOR) {
|
|
473
|
+
plain.attr_operator = ATTR_OPERATOR_NAMES[this.attr_operator];
|
|
474
|
+
plain.attr_flags = ATTR_FLAG_NAMES[this.attr_flags];
|
|
430
475
|
}
|
|
431
|
-
if (
|
|
476
|
+
if (type === NTH_SELECTOR || type === NTH_OF_SELECTOR) {
|
|
432
477
|
plain.nth_a = this.nth_a;
|
|
433
478
|
plain.nth_b = this.nth_b;
|
|
434
479
|
}
|
|
@@ -439,7 +484,8 @@ class CSSNode {
|
|
|
439
484
|
plain.length = this.length;
|
|
440
485
|
plain.end = this.end;
|
|
441
486
|
}
|
|
442
|
-
if (deep) {
|
|
487
|
+
if (deep && type !== DECLARATION) {
|
|
488
|
+
plain.children = [];
|
|
443
489
|
for (let child of this.children) {
|
|
444
490
|
plain.children.push(child.clone({ deep: true, locations }));
|
|
445
491
|
}
|
|
@@ -448,4 +494,4 @@ class CSSNode {
|
|
|
448
494
|
}
|
|
449
495
|
}
|
|
450
496
|
|
|
451
|
-
export { CSSNode, TYPE_NAMES };
|
|
497
|
+
export { ATTR_FLAG_NAMES, ATTR_OPERATOR_NAMES, CSSNode, TYPE_NAMES };
|
package/dist/index.js
CHANGED
|
@@ -10,4 +10,4 @@ export { is_custom, is_vendor_prefixed, str_equals, str_index_of, str_starts_wit
|
|
|
10
10
|
export { CSSNode, TYPE_NAMES } from './css-node.js';
|
|
11
11
|
export { ATTRIBUTE_SELECTOR, ATTR_FLAG_CASE_INSENSITIVE, ATTR_FLAG_CASE_SENSITIVE, ATTR_FLAG_NONE, ATTR_OPERATOR_CARET_EQUAL, ATTR_OPERATOR_DOLLAR_EQUAL, ATTR_OPERATOR_EQUAL, ATTR_OPERATOR_NONE, ATTR_OPERATOR_PIPE_EQUAL, ATTR_OPERATOR_STAR_EQUAL, ATTR_OPERATOR_TILDE_EQUAL, AT_RULE, AT_RULE_PRELUDE, BLOCK, CLASS_SELECTOR, COMBINATOR, COMMENT, CONTAINER_QUERY, DECLARATION, DIMENSION, FEATURE_RANGE, FLAG_IMPORTANT, FUNCTION, HASH, IDENTIFIER, ID_SELECTOR, LANG_SELECTOR, LAYER_NAME, MEDIA_FEATURE, MEDIA_QUERY, MEDIA_TYPE, NESTING_SELECTOR, NTH_OF_SELECTOR, NTH_SELECTOR, NUMBER, OPERATOR, PARENTHESIS, PRELUDE_OPERATOR, PSEUDO_CLASS_SELECTOR, PSEUDO_ELEMENT_SELECTOR, SELECTOR, SELECTOR_LIST, STRING, STYLESHEET, STYLE_RULE, SUPPORTS_QUERY, TYPE_SELECTOR, UNIVERSAL_SELECTOR, URL, VALUE } from './arena.js';
|
|
12
12
|
export { NODE_TYPES } from './constants.js';
|
|
13
|
-
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 } from './token-types.js';
|
|
13
|
+
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_UNICODE_RANGE, TOKEN_URL, TOKEN_WHITESPACE } from './token-types.js';
|
package/dist/parse-value.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Lexer } from './tokenize.js';
|
|
2
|
-
import { CSSDataArena, VALUE, OPERATOR, HASH, STRING, DIMENSION, NUMBER, IDENTIFIER, URL, FUNCTION, PARENTHESIS } from './arena.js';
|
|
3
|
-
import { TOKEN_EOF, TOKEN_LEFT_PAREN, TOKEN_COMMA, TOKEN_DELIM, TOKEN_FUNCTION, TOKEN_HASH, TOKEN_STRING, TOKEN_DIMENSION, TOKEN_PERCENTAGE, TOKEN_NUMBER, TOKEN_IDENT, TOKEN_RIGHT_PAREN } from './token-types.js';
|
|
2
|
+
import { CSSDataArena, VALUE, OPERATOR, UNICODE_RANGE, HASH, STRING, DIMENSION, NUMBER, IDENTIFIER, URL, FUNCTION, PARENTHESIS } from './arena.js';
|
|
3
|
+
import { TOKEN_EOF, TOKEN_LEFT_PAREN, TOKEN_COMMA, TOKEN_DELIM, TOKEN_FUNCTION, TOKEN_UNICODE_RANGE, TOKEN_HASH, TOKEN_STRING, TOKEN_DIMENSION, TOKEN_PERCENTAGE, TOKEN_NUMBER, TOKEN_IDENT, TOKEN_RIGHT_PAREN } from './token-types.js';
|
|
4
4
|
import { is_whitespace, CHAR_PLUS, CHAR_MINUS_HYPHEN, CHAR_ASTERISK, CHAR_FORWARD_SLASH, str_equals } from './string-utils.js';
|
|
5
5
|
import { CSSNode } from './css-node.js';
|
|
6
6
|
|
|
@@ -78,6 +78,8 @@ class ValueParser {
|
|
|
78
78
|
return this.create_node(STRING, start, end);
|
|
79
79
|
case TOKEN_HASH:
|
|
80
80
|
return this.create_node(HASH, start, end);
|
|
81
|
+
case TOKEN_UNICODE_RANGE:
|
|
82
|
+
return this.create_node(UNICODE_RANGE, start, end);
|
|
81
83
|
case TOKEN_FUNCTION:
|
|
82
84
|
return this.parse_function_node(start, end);
|
|
83
85
|
case TOKEN_DELIM:
|
package/dist/token-types.d.ts
CHANGED
|
@@ -24,7 +24,8 @@ export declare const TOKEN_LEFT_BRACE = 23;
|
|
|
24
24
|
export declare const TOKEN_RIGHT_BRACE = 24;
|
|
25
25
|
export declare const TOKEN_COMMENT = 25;
|
|
26
26
|
export declare const TOKEN_EOF = 26;
|
|
27
|
-
export
|
|
27
|
+
export declare const TOKEN_UNICODE_RANGE = 27;
|
|
28
|
+
export type TokenType = typeof TOKEN_IDENT | typeof TOKEN_FUNCTION | typeof TOKEN_AT_KEYWORD | typeof TOKEN_HASH | typeof TOKEN_STRING | typeof TOKEN_BAD_STRING | typeof TOKEN_URL | typeof TOKEN_BAD_URL | typeof TOKEN_DELIM | typeof TOKEN_NUMBER | typeof TOKEN_PERCENTAGE | typeof TOKEN_DIMENSION | typeof TOKEN_WHITESPACE | typeof TOKEN_CDO | typeof TOKEN_CDC | typeof TOKEN_COLON | typeof TOKEN_SEMICOLON | typeof TOKEN_COMMA | typeof TOKEN_LEFT_BRACKET | typeof TOKEN_RIGHT_BRACKET | typeof TOKEN_LEFT_PAREN | typeof TOKEN_RIGHT_PAREN | typeof TOKEN_LEFT_BRACE | typeof TOKEN_RIGHT_BRACE | typeof TOKEN_COMMENT | typeof TOKEN_EOF | typeof TOKEN_UNICODE_RANGE;
|
|
28
29
|
export type Token = {
|
|
29
30
|
type: TokenType;
|
|
30
31
|
start: number;
|
package/dist/token-types.js
CHANGED
|
@@ -24,5 +24,6 @@ const TOKEN_LEFT_BRACE = 23;
|
|
|
24
24
|
const TOKEN_RIGHT_BRACE = 24;
|
|
25
25
|
const TOKEN_COMMENT = 25;
|
|
26
26
|
const TOKEN_EOF = 26;
|
|
27
|
+
const TOKEN_UNICODE_RANGE = 27;
|
|
27
28
|
|
|
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 };
|
|
29
|
+
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_UNICODE_RANGE, TOKEN_URL, TOKEN_WHITESPACE };
|
package/dist/tokenize.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { char_types, CHAR_WHITESPACE, CHAR_NEWLINE, CHAR_DIGIT, is_ident_start, is_newline, is_hex_digit, is_whitespace, is_ident_char } from './char-types.js';
|
|
2
|
-
import { TOKEN_EOF, TOKEN_RIGHT_PAREN, TOKEN_LEFT_PAREN, TOKEN_RIGHT_BRACKET, TOKEN_LEFT_BRACKET, TOKEN_COMMA, TOKEN_SEMICOLON, TOKEN_COLON, TOKEN_RIGHT_BRACE, TOKEN_LEFT_BRACE, TOKEN_CDO, TOKEN_CDC, TOKEN_DELIM, TOKEN_WHITESPACE, TOKEN_STRING, TOKEN_BAD_STRING, TOKEN_PERCENTAGE, TOKEN_DIMENSION, TOKEN_NUMBER, TOKEN_FUNCTION, TOKEN_IDENT, TOKEN_AT_KEYWORD, TOKEN_HASH } from './token-types.js';
|
|
2
|
+
import { TOKEN_EOF, TOKEN_RIGHT_PAREN, TOKEN_LEFT_PAREN, TOKEN_RIGHT_BRACKET, TOKEN_LEFT_BRACKET, TOKEN_COMMA, TOKEN_SEMICOLON, TOKEN_COLON, TOKEN_RIGHT_BRACE, TOKEN_LEFT_BRACE, TOKEN_CDO, TOKEN_CDC, TOKEN_DELIM, TOKEN_WHITESPACE, TOKEN_STRING, TOKEN_BAD_STRING, TOKEN_PERCENTAGE, TOKEN_DIMENSION, TOKEN_NUMBER, TOKEN_FUNCTION, TOKEN_IDENT, TOKEN_UNICODE_RANGE, TOKEN_AT_KEYWORD, TOKEN_HASH } from './token-types.js';
|
|
3
3
|
|
|
4
4
|
const CHAR_LEFT_BRACE = 123;
|
|
5
5
|
const CHAR_RIGHT_BRACE = 125;
|
|
@@ -26,6 +26,9 @@ const CHAR_PLUS = 43;
|
|
|
26
26
|
const CHAR_PERCENT = 37;
|
|
27
27
|
const CHAR_LOWERCASE_E = 101;
|
|
28
28
|
const CHAR_UPPERCASE_E = 69;
|
|
29
|
+
const CHAR_LOWERCASE_U = 117;
|
|
30
|
+
const CHAR_UPPERCASE_U = 85;
|
|
31
|
+
const CHAR_QUESTION_MARK = 63;
|
|
29
32
|
const CHAR_CARRIAGE_RETURN = 13;
|
|
30
33
|
const CHAR_LINE_FEED = 10;
|
|
31
34
|
class Lexer {
|
|
@@ -330,12 +333,58 @@ class Lexer {
|
|
|
330
333
|
break;
|
|
331
334
|
}
|
|
332
335
|
}
|
|
336
|
+
if (this.pos - start === 1) {
|
|
337
|
+
let first_ch = this.source.charCodeAt(start);
|
|
338
|
+
if ((first_ch === CHAR_LOWERCASE_U || first_ch === CHAR_UPPERCASE_U) && this.pos < this.source.length && this.source.charCodeAt(this.pos) === CHAR_PLUS) {
|
|
339
|
+
return this.consume_unicode_range(start, start_line, start_column);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
333
342
|
if (this.pos < this.source.length && this.source.charCodeAt(this.pos) === CHAR_LEFT_PAREN) {
|
|
334
343
|
this.advance();
|
|
335
344
|
return this.make_token(TOKEN_FUNCTION, start, this.pos, start_line, start_column);
|
|
336
345
|
}
|
|
337
346
|
return this.make_token(TOKEN_IDENT, start, this.pos, start_line, start_column);
|
|
338
347
|
}
|
|
348
|
+
consume_unicode_range(start, start_line, start_column) {
|
|
349
|
+
this.advance();
|
|
350
|
+
let hex_digits = 0;
|
|
351
|
+
let has_question = false;
|
|
352
|
+
while (this.pos < this.source.length && hex_digits < 6) {
|
|
353
|
+
let ch = this.source.charCodeAt(this.pos);
|
|
354
|
+
if (is_hex_digit(ch)) {
|
|
355
|
+
if (has_question) {
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
this.advance();
|
|
359
|
+
hex_digits++;
|
|
360
|
+
} else if (ch === CHAR_QUESTION_MARK) {
|
|
361
|
+
this.advance();
|
|
362
|
+
hex_digits++;
|
|
363
|
+
has_question = true;
|
|
364
|
+
} else {
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (has_question) {
|
|
369
|
+
return this.make_token(TOKEN_UNICODE_RANGE, start, this.pos, start_line, start_column);
|
|
370
|
+
}
|
|
371
|
+
if (this.pos < this.source.length && this.source.charCodeAt(this.pos) === CHAR_HYPHEN) {
|
|
372
|
+
if (this.pos + 1 < this.source.length && is_hex_digit(this.source.charCodeAt(this.pos + 1))) {
|
|
373
|
+
this.advance();
|
|
374
|
+
let end_hex_digits = 0;
|
|
375
|
+
while (this.pos < this.source.length && end_hex_digits < 6) {
|
|
376
|
+
let ch = this.source.charCodeAt(this.pos);
|
|
377
|
+
if (is_hex_digit(ch)) {
|
|
378
|
+
this.advance();
|
|
379
|
+
end_hex_digits++;
|
|
380
|
+
} else {
|
|
381
|
+
break;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return this.make_token(TOKEN_UNICODE_RANGE, start, this.pos, start_line, start_column);
|
|
387
|
+
}
|
|
339
388
|
consume_at_keyword(start_line, start_column) {
|
|
340
389
|
let start = this.pos;
|
|
341
390
|
this.advance();
|
package/package.json
CHANGED