@eslint/css-tree 3.6.9 → 4.0.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/LICENSE +1 -1
- package/README.md +2 -2
- package/cjs/definition-syntax/parse.cjs +63 -23
- package/cjs/generator/create.cjs +10 -2
- package/cjs/generator/token-before.cjs +9 -10
- package/cjs/lexer/Lexer.cjs +6 -2
- package/cjs/lexer/generic.cjs +44 -1
- package/cjs/parser/create.cjs +37 -13
- package/data/patch.json +34 -1
- package/dist/csstree.esm.js +9 -9
- package/dist/csstree.js +9 -9
- package/dist/data.cjs +99 -41
- package/dist/data.js +99 -41
- package/dist/version.cjs +1 -1
- package/dist/version.js +1 -1
- package/lib/definition-syntax/parse.js +63 -23
- package/lib/generator/create.js +10 -2
- package/lib/generator/token-before.js +9 -11
- package/lib/index.d.ts +127 -12
- package/lib/lexer/Lexer.js +6 -2
- package/lib/lexer/generic.js +32 -1
- package/lib/parser/create.js +37 -13
- package/package.json +8 -8
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
WhiteSpace,
|
|
3
2
|
Delim,
|
|
4
3
|
Ident,
|
|
5
4
|
Function as FunctionToken,
|
|
@@ -20,17 +19,20 @@ import {
|
|
|
20
19
|
const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
|
|
21
20
|
const HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
|
|
22
21
|
|
|
22
|
+
// code:
|
|
23
|
+
// 0xxxxxxx x0000000 - char code (0x80 for non-ASCII) or delim value
|
|
24
|
+
// 00000000 0xxxxxx0 - token type (0 for delim, 1 for token)
|
|
25
|
+
// 00000000 0000000x - reserved for carriage emit flag (0 for no space, 1 for space)
|
|
23
26
|
const code = (type, value) => {
|
|
24
27
|
if (type === Delim) {
|
|
25
28
|
type = value;
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
if (typeof type === 'string') {
|
|
29
|
-
|
|
30
|
-
return charCode > 0x7F ? 0x8000 : charCode << 8;
|
|
32
|
+
type = Math.min(type.charCodeAt(0), 0x80) << 6; // replace non-ASCII with 0x80
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
return type;
|
|
35
|
+
return type << 1;
|
|
34
36
|
};
|
|
35
37
|
|
|
36
38
|
// https://www.w3.org/TR/css-syntax-3/#serialization
|
|
@@ -167,14 +169,10 @@ function createMap(pairs) {
|
|
|
167
169
|
type !== FunctionToken &&
|
|
168
170
|
type !== CDC) ||
|
|
169
171
|
(nextCharCode === PLUSSIGN)
|
|
170
|
-
? isWhiteSpaceRequired.has(prevCode << 16 | nextCharCode <<
|
|
171
|
-
: isWhiteSpaceRequired.has(prevCode << 16 | nextCode);
|
|
172
|
+
? isWhiteSpaceRequired.has((prevCode & 0xFFFE) << 16 | nextCharCode << 7)
|
|
173
|
+
: isWhiteSpaceRequired.has((prevCode & 0xFFFE) << 16 | nextCode);
|
|
172
174
|
|
|
173
|
-
|
|
174
|
-
this.emit(' ', WhiteSpace, true);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
return nextCode;
|
|
175
|
+
return nextCode | emitWs;
|
|
178
176
|
};
|
|
179
177
|
}
|
|
180
178
|
|
package/lib/index.d.ts
CHANGED
|
@@ -2921,14 +2921,64 @@ interface SyntaxMatchGraph {
|
|
|
2921
2921
|
source: DSNode;
|
|
2922
2922
|
}
|
|
2923
2923
|
|
|
2924
|
+
/**
|
|
2925
|
+
* Kinds of syntax descriptors created by the lexer.
|
|
2926
|
+
*/
|
|
2927
|
+
type SyntaxDescriptorType = "AtruleDescriptor" | "AtrulePrelude" | "Property" | "Type";
|
|
2928
|
+
|
|
2929
|
+
/**
|
|
2930
|
+
* The built-in unit groups stored on a `Lexer` instance.
|
|
2931
|
+
*/
|
|
2932
|
+
interface LexerUnits {
|
|
2933
|
+
/**
|
|
2934
|
+
* Length units such as `px`, `em`, and `vh`.
|
|
2935
|
+
*/
|
|
2936
|
+
length: string[];
|
|
2937
|
+
|
|
2938
|
+
/**
|
|
2939
|
+
* Angle units such as `deg` and `rad`.
|
|
2940
|
+
*/
|
|
2941
|
+
angle: string[];
|
|
2942
|
+
|
|
2943
|
+
/**
|
|
2944
|
+
* Time units such as `s` and `ms`.
|
|
2945
|
+
*/
|
|
2946
|
+
time: string[];
|
|
2947
|
+
|
|
2948
|
+
/**
|
|
2949
|
+
* Frequency units such as `hz` and `khz`.
|
|
2950
|
+
*/
|
|
2951
|
+
frequency: string[];
|
|
2952
|
+
|
|
2953
|
+
/**
|
|
2954
|
+
* Resolution units such as `dpi` and `dppx`.
|
|
2955
|
+
*/
|
|
2956
|
+
resolution: string[];
|
|
2957
|
+
|
|
2958
|
+
/**
|
|
2959
|
+
* Flex units such as `fr`.
|
|
2960
|
+
*/
|
|
2961
|
+
flex: string[];
|
|
2962
|
+
|
|
2963
|
+
/**
|
|
2964
|
+
* Volume-related decibel units.
|
|
2965
|
+
*/
|
|
2966
|
+
decibel: string[];
|
|
2967
|
+
|
|
2968
|
+
/**
|
|
2969
|
+
* Pitch-related semitone units.
|
|
2970
|
+
*/
|
|
2971
|
+
semitones: string[];
|
|
2972
|
+
}
|
|
2973
|
+
|
|
2924
2974
|
/**
|
|
2925
2975
|
* Describes a syntax rule or definition.
|
|
2926
2976
|
*/
|
|
2927
|
-
type SyntaxDescriptor = {
|
|
2977
|
+
type SyntaxDescriptor<Kind extends SyntaxDescriptorType = SyntaxDescriptorType> = {
|
|
2928
2978
|
/**
|
|
2929
2979
|
* The type of the syntax descriptor (e.g., "Type", "Property").
|
|
2930
2980
|
*/
|
|
2931
|
-
type:
|
|
2981
|
+
type: Kind;
|
|
2932
2982
|
|
|
2933
2983
|
/**
|
|
2934
2984
|
* The name of the syntax descriptor.
|
|
@@ -2946,9 +2996,9 @@ type SyntaxDescriptor = {
|
|
|
2946
2996
|
serializable: boolean;
|
|
2947
2997
|
|
|
2948
2998
|
/**
|
|
2949
|
-
* The syntax
|
|
2999
|
+
* The parsed definition-syntax AST, or `null` for function-backed descriptors.
|
|
2950
3000
|
*/
|
|
2951
|
-
syntax:
|
|
3001
|
+
syntax: DSNode | null;
|
|
2952
3002
|
|
|
2953
3003
|
/**
|
|
2954
3004
|
* The graph of syntax matches for this descriptor, or `null` if none exists.
|
|
@@ -2958,9 +3008,34 @@ type SyntaxDescriptor = {
|
|
|
2958
3008
|
/**
|
|
2959
3009
|
* A reference to a graph of syntax matches, or `null` if none exists.
|
|
2960
3010
|
*/
|
|
2961
|
-
matchRef
|
|
3011
|
+
matchRef: SyntaxMatchGraph | null;
|
|
2962
3012
|
};
|
|
2963
3013
|
|
|
3014
|
+
/**
|
|
3015
|
+
* An at-rule definition exposed through `Lexer#atrules`.
|
|
3016
|
+
*/
|
|
3017
|
+
interface LexerAtruleDefinition {
|
|
3018
|
+
/**
|
|
3019
|
+
* Discriminator for at-rule entries.
|
|
3020
|
+
*/
|
|
3021
|
+
type: "Atrule";
|
|
3022
|
+
|
|
3023
|
+
/**
|
|
3024
|
+
* The at-rule name.
|
|
3025
|
+
*/
|
|
3026
|
+
name: string;
|
|
3027
|
+
|
|
3028
|
+
/**
|
|
3029
|
+
* The descriptor for the at-rule prelude, if one exists.
|
|
3030
|
+
*/
|
|
3031
|
+
prelude: SyntaxDescriptor<"AtrulePrelude"> | null;
|
|
3032
|
+
|
|
3033
|
+
/**
|
|
3034
|
+
* At-rule descriptors keyed by descriptor name, if any.
|
|
3035
|
+
*/
|
|
3036
|
+
descriptors: Record<string, SyntaxDescriptor<"AtruleDescriptor"> | undefined> | null;
|
|
3037
|
+
}
|
|
3038
|
+
|
|
2964
3039
|
/**
|
|
2965
3040
|
* Represents a fragment match, including its parent list and nodes.
|
|
2966
3041
|
*/
|
|
@@ -2996,6 +3071,46 @@ type LexerValidationResult = {
|
|
|
2996
3071
|
* It provides utilities for handling at-rules, properties, types, and general syntax.
|
|
2997
3072
|
*/
|
|
2998
3073
|
export class Lexer {
|
|
3074
|
+
/**
|
|
3075
|
+
* CSS-wide keywords accepted by the lexer.
|
|
3076
|
+
*/
|
|
3077
|
+
cssWideKeywords: string[];
|
|
3078
|
+
|
|
3079
|
+
/**
|
|
3080
|
+
* The associated `Syntax` instance, if the lexer was created from one.
|
|
3081
|
+
*/
|
|
3082
|
+
syntax: Syntax | undefined;
|
|
3083
|
+
|
|
3084
|
+
/**
|
|
3085
|
+
* Whether generic types are enabled for this lexer.
|
|
3086
|
+
*/
|
|
3087
|
+
generic: boolean;
|
|
3088
|
+
|
|
3089
|
+
/**
|
|
3090
|
+
* Known CSS units grouped by unit family.
|
|
3091
|
+
*/
|
|
3092
|
+
units: LexerUnits;
|
|
3093
|
+
|
|
3094
|
+
/**
|
|
3095
|
+
* Known at-rule definitions keyed by at-rule name.
|
|
3096
|
+
*/
|
|
3097
|
+
atrules: Record<string, LexerAtruleDefinition | undefined>;
|
|
3098
|
+
|
|
3099
|
+
/**
|
|
3100
|
+
* Known property definitions keyed by property name.
|
|
3101
|
+
*/
|
|
3102
|
+
properties: Record<string, SyntaxDescriptor<"Property"> | undefined>;
|
|
3103
|
+
|
|
3104
|
+
/**
|
|
3105
|
+
* Known type definitions keyed by type name.
|
|
3106
|
+
*/
|
|
3107
|
+
types: Record<string, SyntaxDescriptor<"Type"> | undefined>;
|
|
3108
|
+
|
|
3109
|
+
/**
|
|
3110
|
+
* Node structure validators used by `checkStructure()`.
|
|
3111
|
+
*/
|
|
3112
|
+
structure: Structure;
|
|
3113
|
+
|
|
2999
3114
|
/**
|
|
3000
3115
|
* Creates a new `Lexer` instance.
|
|
3001
3116
|
*
|
|
@@ -3147,13 +3262,13 @@ export class Lexer {
|
|
|
3147
3262
|
findAllFragments(ast: AnyCssNode, type: string, name: string): FragmentMatch[];
|
|
3148
3263
|
|
|
3149
3264
|
/**
|
|
3150
|
-
* Retrieves the
|
|
3265
|
+
* Retrieves the definition for an at-rule.
|
|
3151
3266
|
*
|
|
3152
3267
|
* @param atruleName - The name of the at-rule.
|
|
3153
3268
|
* @param fallbackBasename - (Optional) Whether to use a fallback basename.
|
|
3154
|
-
* @returns The
|
|
3269
|
+
* @returns The at-rule definition or `null` if not found.
|
|
3155
3270
|
*/
|
|
3156
|
-
getAtrule(atruleName: string, fallbackBasename?: boolean):
|
|
3271
|
+
getAtrule(atruleName: string, fallbackBasename?: boolean): LexerAtruleDefinition | null;
|
|
3157
3272
|
|
|
3158
3273
|
/**
|
|
3159
3274
|
* Retrieves the prelude descriptor for an at-rule.
|
|
@@ -3162,7 +3277,7 @@ export class Lexer {
|
|
|
3162
3277
|
* @param fallbackBasename - (Optional) Whether to use a fallback basename.
|
|
3163
3278
|
* @returns The syntax descriptor or `null` if not found.
|
|
3164
3279
|
*/
|
|
3165
|
-
getAtrulePrelude(atruleName: string, fallbackBasename?: boolean): SyntaxDescriptor | null;
|
|
3280
|
+
getAtrulePrelude(atruleName: string, fallbackBasename?: boolean): SyntaxDescriptor<"AtrulePrelude"> | null;
|
|
3166
3281
|
|
|
3167
3282
|
/**
|
|
3168
3283
|
* Retrieves the descriptor for an at-rule's property.
|
|
@@ -3171,7 +3286,7 @@ export class Lexer {
|
|
|
3171
3286
|
* @param name - The property name.
|
|
3172
3287
|
* @returns The syntax descriptor or `null` if not found.
|
|
3173
3288
|
*/
|
|
3174
|
-
getAtruleDescriptor(atruleName: string, name: string): SyntaxDescriptor | null;
|
|
3289
|
+
getAtruleDescriptor(atruleName: string, name: string): SyntaxDescriptor<"AtruleDescriptor"> | null;
|
|
3175
3290
|
|
|
3176
3291
|
/**
|
|
3177
3292
|
* Retrieves the syntax descriptor for a property.
|
|
@@ -3180,7 +3295,7 @@ export class Lexer {
|
|
|
3180
3295
|
* @param fallbackBasename - (Optional) Whether to use a fallback basename.
|
|
3181
3296
|
* @returns The syntax descriptor or `null` if not found.
|
|
3182
3297
|
*/
|
|
3183
|
-
getProperty(propertyName: string, fallbackBasename?: boolean): SyntaxDescriptor | null;
|
|
3298
|
+
getProperty(propertyName: string, fallbackBasename?: boolean): SyntaxDescriptor<"Property"> | null;
|
|
3184
3299
|
|
|
3185
3300
|
/**
|
|
3186
3301
|
* Retrieves the syntax descriptor for a type.
|
|
@@ -3188,7 +3303,7 @@ export class Lexer {
|
|
|
3188
3303
|
* @param name - The name of the type.
|
|
3189
3304
|
* @returns The syntax descriptor or `null` if not found.
|
|
3190
3305
|
*/
|
|
3191
|
-
getType(name: string): SyntaxDescriptor | null;
|
|
3306
|
+
getType(name: string): SyntaxDescriptor<"Type"> | null;
|
|
3192
3307
|
|
|
3193
3308
|
/**
|
|
3194
3309
|
* Validates the syntax rules and properties.
|
package/lib/lexer/Lexer.js
CHANGED
|
@@ -439,9 +439,13 @@ export class Lexer {
|
|
|
439
439
|
return atrule && atrule.prelude || null;
|
|
440
440
|
}
|
|
441
441
|
getAtruleDescriptor(atruleName, name) {
|
|
442
|
-
|
|
443
|
-
|
|
442
|
+
const atrule = this.getAtrule(atruleName);
|
|
443
|
+
const descriptor = names.keyword(name);
|
|
444
|
+
const descriptorEntry = atrule && atrule.descriptors
|
|
445
|
+
? atrule.descriptors[descriptor.name] || atrule.descriptors[descriptor.basename]
|
|
444
446
|
: null;
|
|
447
|
+
|
|
448
|
+
return descriptorEntry || null;
|
|
445
449
|
}
|
|
446
450
|
getProperty(propertyName, fallbackBasename = true) {
|
|
447
451
|
const property = names.property(propertyName);
|
package/lib/lexer/generic.js
CHANGED
|
@@ -698,10 +698,41 @@ export function createDemensionTypes(units) {
|
|
|
698
698
|
};
|
|
699
699
|
}
|
|
700
700
|
|
|
701
|
+
// The <attr-unit> production matches any identifier that is an ASCII case-insensitive
|
|
702
|
+
// match for the name of a CSS dimension unit, such as px, or the <delim-token> %.
|
|
703
|
+
function createAttrUnit(units) {
|
|
704
|
+
const unitSet = new Set();
|
|
705
|
+
|
|
706
|
+
for (const group of unitGroups) {
|
|
707
|
+
if (Array.isArray(units[group])) {
|
|
708
|
+
for (const unit of units[group]) {
|
|
709
|
+
unitSet.add(unit.toLowerCase());
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
return function attrUnit(token) {
|
|
715
|
+
if (token === null) {
|
|
716
|
+
return 0;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if (token.type === Delim && token.value === '%') {
|
|
720
|
+
return 1;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
if (token.type === Ident && unitSet.has(token.value.toLowerCase())) {
|
|
724
|
+
return 1;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
return 0;
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
|
|
701
731
|
export function createGenericTypes(units) {
|
|
702
732
|
return {
|
|
703
733
|
...tokenTypes,
|
|
704
734
|
...productionTypes,
|
|
705
|
-
...createDemensionTypes(units)
|
|
735
|
+
...createDemensionTypes(units),
|
|
736
|
+
'attr-unit': createAttrUnit(units)
|
|
706
737
|
};
|
|
707
738
|
};
|
package/lib/parser/create.js
CHANGED
|
@@ -29,6 +29,36 @@ const SEMICOLON = 0x003B; // U+003B SEMICOLON (;)
|
|
|
29
29
|
const LEFTCURLYBRACKET = 0x007B; // U+007B LEFT CURLY BRACKET ({)
|
|
30
30
|
const NULL = 0;
|
|
31
31
|
|
|
32
|
+
const arrayMethods = {
|
|
33
|
+
createList() {
|
|
34
|
+
return [];
|
|
35
|
+
},
|
|
36
|
+
createSingleNodeList(node) {
|
|
37
|
+
return [node];
|
|
38
|
+
},
|
|
39
|
+
getFirstListNode(list) {
|
|
40
|
+
return list && list[0] || null;
|
|
41
|
+
},
|
|
42
|
+
getLastListNode(list) {
|
|
43
|
+
return list && list.length > 0 ? list[list.length - 1] : null;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const listMethods = {
|
|
48
|
+
createList() {
|
|
49
|
+
return new List();
|
|
50
|
+
},
|
|
51
|
+
createSingleNodeList(node) {
|
|
52
|
+
return new List().appendData(node);
|
|
53
|
+
},
|
|
54
|
+
getFirstListNode(list) {
|
|
55
|
+
return list && list.first;
|
|
56
|
+
},
|
|
57
|
+
getLastListNode(list) {
|
|
58
|
+
return list && list.last;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
32
62
|
function createParseContext(name) {
|
|
33
63
|
return function() {
|
|
34
64
|
return this[name]();
|
|
@@ -110,18 +140,10 @@ export function createParser(config) {
|
|
|
110
140
|
return code === SEMICOLON ? 2 : 0;
|
|
111
141
|
},
|
|
112
142
|
|
|
113
|
-
createList
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return new List().appendData(node);
|
|
118
|
-
},
|
|
119
|
-
getFirstListNode(list) {
|
|
120
|
-
return list && list.first;
|
|
121
|
-
},
|
|
122
|
-
getLastListNode(list) {
|
|
123
|
-
return list && list.last;
|
|
124
|
-
},
|
|
143
|
+
createList: NOOP,
|
|
144
|
+
createSingleNodeList: NOOP,
|
|
145
|
+
getFirstListNode: NOOP,
|
|
146
|
+
getLastListNode: NOOP,
|
|
125
147
|
|
|
126
148
|
parseWithFallback(consumer, fallback) {
|
|
127
149
|
const startIndex = this.tokenIndex;
|
|
@@ -346,12 +368,14 @@ export function createParser(config) {
|
|
|
346
368
|
parser.parseValue = 'parseValue' in options ? Boolean(options.parseValue) : true;
|
|
347
369
|
parser.parseCustomProperty = 'parseCustomProperty' in options ? Boolean(options.parseCustomProperty) : false;
|
|
348
370
|
|
|
349
|
-
const { context = 'default', onComment, onToken } = options;
|
|
371
|
+
const { context = 'default', list = true, onComment, onToken } = options;
|
|
350
372
|
|
|
351
373
|
if (context in parser.context === false) {
|
|
352
374
|
throw new Error('Unknown context `' + context + '`');
|
|
353
375
|
}
|
|
354
376
|
|
|
377
|
+
Object.assign(parser, list ? listMethods : arrayMethods);
|
|
378
|
+
|
|
355
379
|
if (Array.isArray(onToken)) {
|
|
356
380
|
parser.forEachToken((type, start, end) => {
|
|
357
381
|
onToken.push({ type, start, end });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint/css-tree",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "A tool set for CSS: fast detailed parser (CSS → AST), walker (AST traversal), generator (AST → CSS) and lexer (validation and matching) based on specs and browser implementations",
|
|
5
5
|
"author": "Roman Dvornov <rdvornov@gmail.com> (https://github.com/lahmatiy)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -107,21 +107,21 @@
|
|
|
107
107
|
"test:types": "tsc -p tests/types/tsconfig.json"
|
|
108
108
|
},
|
|
109
109
|
"dependencies": {
|
|
110
|
-
"mdn-data": "2.
|
|
111
|
-
"source-map-js": "^1.
|
|
110
|
+
"mdn-data": "2.27.1",
|
|
111
|
+
"source-map-js": "^1.2.1"
|
|
112
112
|
},
|
|
113
113
|
"devDependencies": {
|
|
114
|
-
"c8": "^
|
|
114
|
+
"c8": "^11.0.0",
|
|
115
115
|
"clap": "^2.0.1",
|
|
116
|
-
"esbuild": "^0.
|
|
117
|
-
"eslint": "^8.
|
|
116
|
+
"esbuild": "^0.27.3",
|
|
117
|
+
"eslint": "^8.50.0",
|
|
118
118
|
"json-to-ast": "^2.1.0",
|
|
119
119
|
"mocha": "^9.2.2",
|
|
120
|
-
"rollup": "^2.
|
|
120
|
+
"rollup": "^2.80.0",
|
|
121
121
|
"typescript": "^5.7.3"
|
|
122
122
|
},
|
|
123
123
|
"engines": {
|
|
124
|
-
"node": "^
|
|
124
|
+
"node": "^20.19.0 || ^22.13.0 || >=24"
|
|
125
125
|
},
|
|
126
126
|
"files": [
|
|
127
127
|
"data",
|