@eslint/css-tree 3.6.6 → 3.6.8

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/version.cjs CHANGED
@@ -1 +1 @@
1
- module.exports = "3.6.6";
1
+ module.exports = "3.6.8";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = "3.6.6";
1
+ export const version = "3.6.8";
@@ -66,8 +66,31 @@ function isElementSelectorStart() {
66
66
  }
67
67
 
68
68
  function isSelectorStart() {
69
- return this.tokenType === Delim && selectorStarts.has(this.source.charCodeAt(this.tokenStart)) ||
70
- this.tokenType === Hash || this.tokenType === LeftSquareBracket ||
69
+ // Check for Delim tokens that might be selector starts
70
+ if (this.tokenType === Delim && selectorStarts.has(this.source.charCodeAt(this.tokenStart))) {
71
+ const code = this.source.charCodeAt(this.tokenStart);
72
+
73
+ // Special case: browser hack prefixes (*, +, &) followed immediately by an ident
74
+ // (no whitespace) are declarations, not selectors. Examples: *zoom: 1; +width: 100px; &prop: value;
75
+ if (code === STAR || code === PLUSSIGN || code === AMPERSAND) {
76
+ const nextToken = this.lookupType(1);
77
+ const nextTokenNonSC = this.lookupTypeNonSC(1);
78
+
79
+ // If next token is Ident and there's no whitespace between, it's a declaration
80
+ if (nextToken === Ident && nextTokenNonSC === Ident) {
81
+ return false;
82
+ }
83
+ }
84
+ return true;
85
+ }
86
+
87
+ // Hash can be either a Hash token (#id selector) or Delim(#) + Ident (browser hack)
88
+ // When it's a Hash token, it's a selector. When it's Delim, check if followed by Ident without whitespace
89
+ if (this.tokenType === Hash) {
90
+ return true;
91
+ }
92
+
93
+ return this.tokenType === LeftSquareBracket ||
71
94
  this.tokenType === Colon || isElementSelectorStart.call(this);
72
95
  }
73
96
 
@@ -2,15 +2,85 @@ import {
2
2
  WhiteSpace,
3
3
  Comment,
4
4
  Semicolon,
5
- AtKeyword
5
+ AtKeyword,
6
+ Delim,
7
+ Hash,
8
+ LeftSquareBracket,
9
+ Colon,
10
+ Ident,
11
+ RightCurlyBracket,
12
+ LeftCurlyBracket,
13
+ Comma
6
14
  } from '../../tokenizer/index.js';
7
15
 
8
16
  const AMPERSAND = 0x0026; // U+0026 AMPERSAND (&)
17
+ const DOT = 0x002E; // U+002E FULL STOP (.)
18
+ const STAR = 0x002A; // U+002A ASTERISK (*);
19
+ const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
20
+ const GREATERTHANSIGN = 0x003E; // U+003E GREATER-THAN SIGN (>)
21
+ const TILDE = 0x007E; // U+007E TILDE (~)
22
+
23
+ const selectorStarts = new Set([
24
+ AMPERSAND,
25
+ DOT,
26
+ STAR,
27
+ PLUSSIGN,
28
+ GREATERTHANSIGN,
29
+ TILDE
30
+ ]);
9
31
 
10
32
  function consumeRaw() {
11
33
  return this.Raw(this.consumeUntilSemicolonIncluded, true);
12
34
  }
13
35
 
36
+ function isElementSelectorStart() {
37
+ if (this.tokenType !== Ident) {
38
+ return false;
39
+ }
40
+
41
+ const nextTokenType = this.lookupTypeNonSC(1);
42
+
43
+ // If next token is a left curly bracket, it's definitely a selector (e.g., "div { ... }")
44
+ if (nextTokenType === LeftCurlyBracket) {
45
+ return true;
46
+ }
47
+
48
+ // If next token is semicolon, comma, or closing brace, it's definitely a declaration
49
+ if (nextTokenType === Semicolon || nextTokenType === Comma || nextTokenType === RightCurlyBracket) {
50
+ return false;
51
+ }
52
+
53
+ // Special handling for colon case - could be pseudo-class/pseudo-element or property
54
+ if (nextTokenType === Colon) {
55
+ // Look ahead further to see what follows the colon
56
+ const afterColonType = this.lookupTypeNonSC(2);
57
+
58
+ // If after colon there's an identifier (pseudo-class/pseudo-element name),
59
+ // check what comes after that
60
+ if (afterColonType === Ident) {
61
+ const afterPseudoType = this.lookupTypeNonSC(3);
62
+ // If it's followed by {, it's definitely a selector (e.g., "div:hover { ... }")
63
+ if (afterPseudoType === LeftCurlyBracket) {
64
+ return true;
65
+ }
66
+ // Otherwise, it's a property (e.g., "transition: opacity 1s")
67
+ return false;
68
+ }
69
+ // If after colon there's not an identifier, it's a property
70
+ return false;
71
+ }
72
+
73
+ // For other token types (dimensions, numbers, strings, etc.), assume it's a declaration
74
+ // This handles cases like multi-value properties
75
+ return false;
76
+ }
77
+
78
+ function isSelectorStart() {
79
+ return this.tokenType === Delim && selectorStarts.has(this.source.charCodeAt(this.tokenStart)) ||
80
+ this.tokenType === Hash || this.tokenType === LeftSquareBracket ||
81
+ this.tokenType === Colon || isElementSelectorStart.call(this);
82
+ }
83
+
14
84
  export const name = 'DeclarationList';
15
85
  export const structure = {
16
86
  children: [[
@@ -37,7 +107,7 @@ export function parse() {
37
107
  break;
38
108
 
39
109
  default:
40
- if (this.isDelim(AMPERSAND)) {
110
+ if (isSelectorStart.call(this)) {
41
111
  children.push(this.parseWithFallback(this.Rule, consumeRaw));
42
112
  } else {
43
113
  children.push(this.parseWithFallback(this.Declaration, consumeRaw));
@@ -9,6 +9,20 @@ function eatIdentifierOrAsterisk() {
9
9
  this.error('Identifier or asterisk is expected');
10
10
  }
11
11
 
12
+ // Check if asterisk is followed immediately by an ident (no whitespace)
13
+ // This is invalid in selectors (e.g., "*foo" should error, "* foo" or "*:hover" is ok)
14
+ if (this.isDelim(ASTERISK)) {
15
+ const currentTokenEnd = this.tokenStart + 1; // asterisk is 1 char
16
+ this.next();
17
+
18
+ // If next token is an ident and starts immediately after asterisk, it's an error
19
+ if (this.tokenType === Ident && this.tokenStart === currentTokenEnd) {
20
+ this.error('Whitespace is required between universal selector and type selector');
21
+ }
22
+
23
+ return;
24
+ }
25
+
12
26
  this.next();
13
27
  }
14
28
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eslint/css-tree",
3
- "version": "3.6.6",
3
+ "version": "3.6.8",
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",