@eslint/css-tree 3.5.3 → 3.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/data.cjs CHANGED
@@ -526,8 +526,7 @@ module.exports = {
526
526
  "inset-area": "[[left|center|right|span-left|span-right|x-start|x-end|span-x-start|span-x-end|x-self-start|x-self-end|span-x-self-start|span-x-self-end|span-all]||[top|center|bottom|span-top|span-bottom|y-start|y-end|span-y-start|span-y-end|y-self-start|y-self-end|span-y-self-start|span-y-self-end|span-all]|[block-start|center|block-end|span-block-start|span-block-end|span-all]||[inline-start|center|inline-end|span-inline-start|span-inline-end|span-all]|[self-block-start|self-block-end|span-self-block-start|span-self-block-end|span-all]||[self-inline-start|self-inline-end|span-self-inline-start|span-self-inline-end|span-all]|[start|center|end|span-start|span-end|span-all]{1,2}|[self-start|center|self-end|span-self-start|span-self-end|span-all]{1,2}]",
527
527
  "font-variant-css2": "normal|small-caps",
528
528
  "font-width-css3": "normal|ultra-condensed|extra-condensed|condensed|semi-condensed|semi-expanded|expanded|extra-expanded|ultra-expanded",
529
- "system-family-name": "caption|icon|menu|message-box|small-caption|status-bar",
530
- "parentheses-block": "( <any-value>* )"
529
+ "system-family-name": "caption|icon|menu|message-box|small-caption|status-bar"
531
530
  },
532
531
  "properties": {
533
532
  "--*": "<declaration-value>",
@@ -1198,7 +1197,7 @@ module.exports = {
1198
1197
  "counter-style": {
1199
1198
  "prelude": "<counter-style-name>",
1200
1199
  "descriptors": {
1201
- "additive-symbols": "[<integer>&&<symbol>]#",
1200
+ "additive-symbols": "[<integer [0,∞]>&&<symbol>]#",
1202
1201
  "fallback": "<counter-style-name>",
1203
1202
  "negative": "<symbol> <symbol>?",
1204
1203
  "pad": "<integer>&&<symbol>",
@@ -1274,7 +1273,7 @@ module.exports = {
1274
1273
  "bleed": "auto|<length>",
1275
1274
  "marks": "none|[crop||cross]",
1276
1275
  "page-orientation": "upright|rotate-left|rotate-right",
1277
- "size": "<length>{1,2}|auto|[<page-size>||[portrait|landscape]]"
1276
+ "size": "<length [0,∞]>{1,2}|auto|[<page-size>||[portrait|landscape]]"
1278
1277
  }
1279
1278
  },
1280
1279
  "position-try": {
package/dist/data.js CHANGED
@@ -526,8 +526,7 @@ export default {
526
526
  "inset-area": "[[left|center|right|span-left|span-right|x-start|x-end|span-x-start|span-x-end|x-self-start|x-self-end|span-x-self-start|span-x-self-end|span-all]||[top|center|bottom|span-top|span-bottom|y-start|y-end|span-y-start|span-y-end|y-self-start|y-self-end|span-y-self-start|span-y-self-end|span-all]|[block-start|center|block-end|span-block-start|span-block-end|span-all]||[inline-start|center|inline-end|span-inline-start|span-inline-end|span-all]|[self-block-start|self-block-end|span-self-block-start|span-self-block-end|span-all]||[self-inline-start|self-inline-end|span-self-inline-start|span-self-inline-end|span-all]|[start|center|end|span-start|span-end|span-all]{1,2}|[self-start|center|self-end|span-self-start|span-self-end|span-all]{1,2}]",
527
527
  "font-variant-css2": "normal|small-caps",
528
528
  "font-width-css3": "normal|ultra-condensed|extra-condensed|condensed|semi-condensed|semi-expanded|expanded|extra-expanded|ultra-expanded",
529
- "system-family-name": "caption|icon|menu|message-box|small-caption|status-bar",
530
- "parentheses-block": "( <any-value>* )"
529
+ "system-family-name": "caption|icon|menu|message-box|small-caption|status-bar"
531
530
  },
532
531
  "properties": {
533
532
  "--*": "<declaration-value>",
@@ -1198,7 +1197,7 @@ export default {
1198
1197
  "counter-style": {
1199
1198
  "prelude": "<counter-style-name>",
1200
1199
  "descriptors": {
1201
- "additive-symbols": "[<integer>&&<symbol>]#",
1200
+ "additive-symbols": "[<integer [0,∞]>&&<symbol>]#",
1202
1201
  "fallback": "<counter-style-name>",
1203
1202
  "negative": "<symbol> <symbol>?",
1204
1203
  "pad": "<integer>&&<symbol>",
@@ -1274,7 +1273,7 @@ export default {
1274
1273
  "bleed": "auto|<length>",
1275
1274
  "marks": "none|[crop||cross]",
1276
1275
  "page-orientation": "upright|rotate-left|rotate-right",
1277
- "size": "<length>{1,2}|auto|[<page-size>||[portrait|landscape]]"
1276
+ "size": "<length [0,∞]>{1,2}|auto|[<page-size>||[portrait|landscape]]"
1278
1277
  }
1279
1278
  },
1280
1279
  "position-try": {
package/dist/version.cjs CHANGED
@@ -1 +1 @@
1
- module.exports = "3.5.3";
1
+ module.exports = "3.6.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = "3.5.3";
1
+ export const version = "3.6.0";
package/lib/index.d.ts CHANGED
@@ -1284,7 +1284,7 @@ export class TokenStream {
1284
1284
  lookupOffset(offset: number): number;
1285
1285
 
1286
1286
  /**
1287
- * Skips whitespace and comments and returns the starting index (inclusive) of the `idx`-th non-whitespace/comment token in the `TokenStream`.
1287
+ * Returns the starting index (inclusive) of the `idx`-th non-whitespace/comment token in the `TokenStream`. This method skips whitespace and comment tokens until it finds the specified non-whitespace/comment token.
1288
1288
  *
1289
1289
  * @param index - The index of the non-whitespace/comment token to look up (starting from 0).
1290
1290
  * @returns The starting index of the `idx`-th non-whitespace/comment token, or `EOF` if the index is out of bounds or if the end of the stream is reached before the specified token is found.
@@ -1331,7 +1331,7 @@ export class TokenStream {
1331
1331
  * @param offset - The offset from the current token's starting index (optional). If provided, the function checks the token at the specified offset instead of the current token.
1332
1332
  * @returns True if the token is a delimiter with the specified character code, false otherwise.
1333
1333
  */
1334
- isDelim(code: number, offset: number): boolean;
1334
+ isDelim(code: number, offset?: number): boolean;
1335
1335
 
1336
1336
  /**
1337
1337
  * Skips a specified number of tokens forward in the stream.
@@ -1715,8 +1715,7 @@ export interface WalkContext {
1715
1715
  break: symbol;
1716
1716
 
1717
1717
  /**
1718
- * Prevents the current node from being iterated. No visitor function will
1719
- * be invoked for its properties or children nodes. This value only affects
1718
+ * Prevents the current node from being iterated. No visitor function will be invoked for its properties or children nodes. This value only affects
1720
1719
  * the `enter` visitor; the `leave` visitor is invoked after iterating
1721
1720
  * over all node's properties and children.
1722
1721
  */
@@ -2681,6 +2680,14 @@ interface Parser {
2681
2680
  error: (this: ParserContext, message: string, offset: number) => void;
2682
2681
  }
2683
2682
 
2683
+ // AtruleParseConfig type based on the structure of files in lib/syntax/atrule/
2684
+ interface AtruleParseConfig {
2685
+ parse: {
2686
+ prelude?: ((this: ParserContext) => List<CssNode>) | null;
2687
+ block?: ((this: ParserContext, nested?: boolean) => CssNode) | null;
2688
+ };
2689
+ }
2690
+
2684
2691
  // https://github.com/csstree/csstree/blob/9de5189fadd6fb4e3a149eec0e80d6ed0d0541e5/lib/parser/create.js#L53-L80
2685
2692
  type ParseConfig = {
2686
2693
  context: Record<string, ConsumerFunction | undefined>;
@@ -2740,7 +2747,7 @@ export interface SyntaxConfig<T extends CssNodeCommon = CssNodeCommon> {
2740
2747
  properties: Record<string, string>;
2741
2748
  atrules: Record<string, AtruleSyntax>;
2742
2749
  node: Record<string, Partial<NodeSyntaxConfig<T>>>;
2743
- atrule: Record<string, { parse: ConsumerFunction; }>;
2750
+ atrule: Record<string, AtruleParseConfig>;
2744
2751
  pseudo: Record<string, { parse: ConsumerFunction; }>;
2745
2752
  scope: Record<string, Partial<Recognizer>>;
2746
2753
  features: Record<string, Partial<Recognizer>>;
@@ -34,7 +34,91 @@ import {
34
34
  RightCurlyBracket
35
35
  } from '../tokenizer/index.js';
36
36
 
37
- const calcFunctionNames = ['calc(', '-moz-calc(', '-webkit-calc('];
37
+ // CSS mathematical functions categorized by return type behavior
38
+ // See: https://www.w3.org/TR/css-values-4/#math
39
+
40
+ // Calculation functions that return different types depending on input
41
+ const calcFunctionNames = [
42
+ 'calc(',
43
+ '-moz-calc(',
44
+ '-webkit-calc('
45
+ ];
46
+
47
+ // Comparison functions that return different types depending on input
48
+ const comparisonFunctionNames = [
49
+ 'min(',
50
+ 'max(',
51
+ 'clamp('
52
+ ];
53
+
54
+ // Functions that return a stepped value, i.e. a value that is rounded to the nearest step
55
+ const steppedValueFunctionNames = [
56
+ 'round(',
57
+ 'mod(',
58
+ 'rem('
59
+ ];
60
+
61
+ // Trigonometrical functions that return a <number>
62
+ const trigNumberFunctionNames = [
63
+ 'sin(',
64
+ 'cos(',
65
+ 'tan('
66
+ ];
67
+
68
+ // Trigonometrical functions that return a <angle>
69
+ const trigAngleFunctionNames = [
70
+ 'asin(',
71
+ 'acos(',
72
+ 'atan(',
73
+ 'atan2('
74
+ ];
75
+
76
+ // Other functions that return a <number>
77
+ const otherNumberFunctionNames = [
78
+ 'pow(',
79
+ 'sqrt(',
80
+ 'log(',
81
+ 'exp(',
82
+ 'sign('
83
+ ];
84
+
85
+ // Exponential functions that return a <number> or <dimension> or <percentage>
86
+ const expNumberDimensionPercentageFunctionNames = [
87
+ 'hypot('
88
+ ];
89
+
90
+ // Return the same type as the input
91
+ const signFunctionNames = [
92
+ 'abs('
93
+ ];
94
+
95
+ const numberFunctionNames = [
96
+ ...calcFunctionNames,
97
+ ...comparisonFunctionNames,
98
+ ...steppedValueFunctionNames,
99
+ ...trigNumberFunctionNames,
100
+ ...otherNumberFunctionNames,
101
+ ...expNumberDimensionPercentageFunctionNames,
102
+ ...signFunctionNames
103
+ ];
104
+
105
+ const percentageFunctionNames = [
106
+ ...calcFunctionNames,
107
+ ...comparisonFunctionNames,
108
+ ...steppedValueFunctionNames,
109
+ ...expNumberDimensionPercentageFunctionNames,
110
+ ...signFunctionNames
111
+ ];
112
+
113
+ const dimensionFunctionNames = [
114
+ ...calcFunctionNames,
115
+ ...comparisonFunctionNames,
116
+ ...steppedValueFunctionNames,
117
+ ...trigAngleFunctionNames,
118
+ ...expNumberDimensionPercentageFunctionNames,
119
+ ...signFunctionNames
120
+ ];
121
+
38
122
  const balancePair = new Map([
39
123
  [FunctionToken, RightParenthesis],
40
124
  [LeftParenthesis, RightParenthesis],
@@ -141,16 +225,17 @@ function consumeFunction(token, getNextToken) {
141
225
  return length;
142
226
  }
143
227
 
228
+
144
229
  // TODO: implement
145
230
  // can be used wherever <length>, <frequency>, <angle>, <time>, <percentage>, <number>, or <integer> values are allowed
146
231
  // https://drafts.csswg.org/css-values/#calc-notation
147
- function calc(next) {
232
+ function math(next, functionNames) {
148
233
  return function(token, getNextToken, opts) {
149
234
  if (token === null) {
150
235
  return 0;
151
236
  }
152
237
 
153
- if (token.type === FunctionToken && eqStrAny(token.value, calcFunctionNames)) {
238
+ if (token.type === FunctionToken && eqStrAny(token.value, functionNames)) {
154
239
  return consumeFunction(token, getNextToken);
155
240
  }
156
241
 
@@ -557,12 +642,12 @@ export const productionTypes = {
557
642
  'ident': tokenType(Ident),
558
643
 
559
644
  // percentage
560
- 'percentage': calc(percentage),
645
+ 'percentage': math(percentage, percentageFunctionNames),
561
646
 
562
647
  // numeric
563
648
  'zero': zero(),
564
- 'number': calc(number),
565
- 'integer': calc(integer),
649
+ 'number': math(number, numberFunctionNames),
650
+ 'integer': math(integer, numberFunctionNames),
566
651
 
567
652
  // complex types
568
653
  'custom-ident': customIdent,
@@ -601,15 +686,15 @@ export function createDemensionTypes(units) {
601
686
  } = units || {};
602
687
 
603
688
  return {
604
- 'dimension': calc(dimension(null)),
605
- 'angle': calc(dimension(angle)),
606
- 'decibel': calc(dimension(decibel)),
607
- 'frequency': calc(dimension(frequency)),
608
- 'flex': calc(dimension(flex)),
609
- 'length': calc(zero(dimension(length))),
610
- 'resolution': calc(dimension(resolution)),
611
- 'semitones': calc(dimension(semitones)),
612
- 'time': calc(dimension(time))
689
+ 'dimension': math(dimension(null), dimensionFunctionNames),
690
+ 'angle': math(dimension(angle), dimensionFunctionNames),
691
+ 'decibel': math(dimension(decibel), dimensionFunctionNames),
692
+ 'frequency': math(dimension(frequency), dimensionFunctionNames),
693
+ 'flex': math(dimension(flex), dimensionFunctionNames),
694
+ 'length': math(zero(dimension(length)), dimensionFunctionNames),
695
+ 'resolution': math(dimension(resolution), dimensionFunctionNames),
696
+ 'semitones': math(dimension(semitones), dimensionFunctionNames),
697
+ 'time': math(dimension(time), dimensionFunctionNames)
613
698
  };
614
699
  }
615
700
 
@@ -5,6 +5,7 @@ import {
5
5
  Semicolon,
6
6
  Hash,
7
7
  Colon,
8
+ Ident,
8
9
  AtKeyword,
9
10
  LeftSquareBracket,
10
11
  LeftCurlyBracket,
@@ -44,10 +45,24 @@ function consumeDeclaration() {
44
45
  return node;
45
46
  }
46
47
 
48
+ function isElementSelectorStart() {
49
+ if (this.tokenType !== Ident) {
50
+ return false;
51
+ }
52
+
53
+ const nextTokenType = this.lookupTypeNonSC(1);
54
+
55
+ if (nextTokenType !== Colon && nextTokenType !== Semicolon && nextTokenType !== RightCurlyBracket) {
56
+ return true;
57
+ }
58
+
59
+ return false;
60
+ }
61
+
47
62
  function isSelectorStart() {
48
63
  return this.tokenType === Delim && selectorStarts.has(this.source.charCodeAt(this.tokenStart)) ||
49
64
  this.tokenType === Hash || this.tokenType === LeftSquareBracket ||
50
- this.tokenType === Colon;
65
+ this.tokenType === Colon || isElementSelectorStart.call(this);
51
66
  }
52
67
 
53
68
  export const name = 'Block';
@@ -60,8 +75,7 @@ export const structure = {
60
75
  ]]
61
76
  };
62
77
 
63
- export function parse(isStyleBlock) {
64
- const consumer = isStyleBlock ? consumeDeclaration : consumeRule;
78
+ export function parse(isStyleBlock, { allowNestedRules = false } = {}) {
65
79
  const start = this.tokenStart;
66
80
  let children = this.createList();
67
81
 
@@ -83,10 +97,16 @@ export function parse(isStyleBlock) {
83
97
  break;
84
98
 
85
99
  default:
86
- if (isStyleBlock && isSelectorStart.call(this)) {
87
- children.push(consumeRule.call(this));
100
+ if (isStyleBlock) {
101
+
102
+ if (allowNestedRules && isSelectorStart.call(this)) {
103
+ children.push(consumeRule.call(this));
104
+ } else {
105
+ children.push(consumeDeclaration.call(this));
106
+ }
107
+
88
108
  } else {
89
- children.push(consumer.call(this));
109
+ children.push(consumeRule.call(this));
90
110
  }
91
111
  }
92
112
  }
@@ -35,7 +35,7 @@ export function parse() {
35
35
  prelude = consumeRaw.call(this, startToken);
36
36
  }
37
37
 
38
- block = this.Block(true);
38
+ block = this.Block(true, { allowNestedRules: true });
39
39
 
40
40
  return {
41
41
  type: 'Rule',
@@ -48,4 +48,3 @@ export function generate(node) {
48
48
  this.node(node.prelude);
49
49
  this.node(node.block);
50
50
  }
51
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eslint/css-tree",
3
- "version": "3.5.3",
3
+ "version": "3.6.0",
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,7 +107,7 @@
107
107
  "test:types": "tsc -p tests/types/tsconfig.json"
108
108
  },
109
109
  "dependencies": {
110
- "mdn-data": "2.20.0",
110
+ "mdn-data": "2.21.0",
111
111
  "source-map-js": "^1.0.1"
112
112
  },
113
113
  "devDependencies": {