diff --git a/package.json b/package.json
index 7184ee88..3b08f94b 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,8 @@
"eslint-visitor-keys": "^4.0.0",
"espree": "^10.0.0",
"postcss": "^8.4.49",
- "postcss-scss": "^4.0.9"
+ "postcss-scss": "^4.0.9",
+ "postcss-selector-parser": "^7.0.0"
},
"devDependencies": {
"@changesets/changelog-github": "^0.5.0",
diff --git a/tests/fixtures/parser/selector-parsing/simple-css-input.svelte b/tests/fixtures/parser/selector-parsing/simple-css-input.svelte
new file mode 100644
index 00000000..15be4986
--- /dev/null
+++ b/tests/fixtures/parser/selector-parsing/simple-css-input.svelte
@@ -0,0 +1,25 @@
+
+
+Hello!
+
+{a}
+
+
diff --git a/tests/fixtures/parser/selector-parsing/simple-css-output.json b/tests/fixtures/parser/selector-parsing/simple-css-output.json
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fixtures/parser/selector-parsing/simple-postcss-input.svelte b/tests/fixtures/parser/selector-parsing/simple-postcss-input.svelte
new file mode 100644
index 00000000..68cfd1a3
--- /dev/null
+++ b/tests/fixtures/parser/selector-parsing/simple-postcss-input.svelte
@@ -0,0 +1,20 @@
+
+
+
diff --git a/tests/fixtures/parser/selector-parsing/simple-postcss-output.json b/tests/fixtures/parser/selector-parsing/simple-postcss-output.json
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/fixtures/parser/selector-parsing/simple-scss-input.svelte b/tests/fixtures/parser/selector-parsing/simple-scss-input.svelte
new file mode 100644
index 00000000..4f5df63b
--- /dev/null
+++ b/tests/fixtures/parser/selector-parsing/simple-scss-input.svelte
@@ -0,0 +1,26 @@
+
+
+
diff --git a/tests/fixtures/parser/selector-parsing/simple-scss-output.json b/tests/fixtures/parser/selector-parsing/simple-scss-output.json
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/src/parser/selector-parsing.ts b/tests/src/parser/selector-parsing.ts
new file mode 100644
index 00000000..920e8e68
--- /dev/null
+++ b/tests/src/parser/selector-parsing.ts
@@ -0,0 +1,56 @@
+import assert from "assert";
+import fs from "fs";
+import path from "path";
+import type { Node } from "postcss";
+import type { Root as SelectorRoot } from "postcss-selector-parser";
+
+import { parseForESLint } from "../../../src/index.js";
+import {
+ generateParserOptions,
+ listupFixtures,
+ selectorNodeToJson,
+} from "./test-utils.js";
+
+const dirname = path.dirname(new URL(import.meta.url).pathname);
+const SELECTOR_PARSING_FIXTURE_ROOT = path.resolve(
+ dirname,
+ "../../fixtures/parser/selector-parsing",
+);
+
+function parse(code: string, filePath: string, config: any) {
+ return parseForESLint(code, generateParserOptions({ filePath }, config));
+}
+
+describe("Check for AST.", () => {
+ for (const {
+ input,
+ inputFileName,
+ outputFileName,
+ config,
+ meetRequirements,
+ } of listupFixtures(SELECTOR_PARSING_FIXTURE_ROOT)) {
+ if (!meetRequirements("parse")) {
+ continue;
+ }
+ describe(inputFileName, () => {
+ let services: any;
+
+ it("most to generate the expected selector AST.", () => {
+ services = parse(input, inputFileName, config).services;
+ if (!meetRequirements("test")) {
+ return;
+ }
+ const styleContext = services.getStyleContext();
+ assert.strictEqual(styleContext.status, "success");
+ const selectorASTs: SelectorRoot[] = [];
+ styleContext.sourceAst.walk((node: Node) => {
+ if (node.type === "rule") {
+ selectorASTs.push(services.getStyleSelectorAST(node));
+ }
+ });
+ const output = fs.readFileSync(outputFileName, "utf8");
+ assert.strictEqual(`${selectorASTs.map(selectorNodeToJson)}\n`, output);
+ });
+ });
+ }
+});
diff --git a/tests/src/parser/test-utils.ts b/tests/src/parser/test-utils.ts
index b269816f..646c5dd1 100644
--- a/tests/src/parser/test-utils.ts
+++ b/tests/src/parser/test-utils.ts
@@ -5,6 +5,7 @@ import type { Linter, Scope as ESLintScope } from "eslint";
import { LinesAndColumns } from "../../../src/context/index.js";
import type { Reference, Scope, ScopeManager, Variable } from "eslint-scope";
import type * as TSESScopes from "@typescript-eslint/scope-manager";
+import type { Node as SelectorNode } from "postcss-selector-parser";
import type { SvelteNode } from "../../../src/ast/index.js";
import type { StyleContext } from "../../../src/index.js";
import { TS_GLOBALS } from "./ts-vars.js";
@@ -480,6 +481,17 @@ export function styleContextToJson(styleContext: StyleContext): string {
}
}
+export function selectorNodeToJson(node: SelectorNode): string {
+ return JSON.stringify(node, nodeReplacer, 2);
+
+ function nodeReplacer(key: string, value: any): any {
+ if (key === "parent" || key.startsWith("_")) {
+ return undefined;
+ }
+ return value;
+ }
+}
+
function normalizeScope(scope: Scope | TSESScopes.Scope): any {
let variables = scope.variables as TSESScopes.Variable[];
if (scope.type === "global") {