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 @@ +
+
Hello
+ + World! +
+ + 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 @@ +
+
Hello
+ + World! +
+ + 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") {