From c3d1ae901906cb680616268cc297304521e76a3c Mon Sep 17 00:00:00 2001 From: overlookmotel <557937+overlookmotel@users.noreply.github.com> Date: Wed, 28 Jan 2026 23:02:39 +0000 Subject: [PATCH] test(linter/plugins): conformance tester identify known parsers by `parseForESLint` function (#18680) Conformance tester was identifying known parsers specified by test cases by comparing the `parser` object to known values. Instead, compare `parser.parseForESLint` functions. This produces an accurate match even when the test case object is deep cloned which results in the `parser` object being a new (unknown) object. But the `parseForESLint` function stays the same after cloning. `eslint-plugin-sonarjs` does this kind of deep cloning. --- apps/oxlint/conformance/src/index.ts | 12 +++++++----- apps/oxlint/conformance/src/rule_tester.ts | 12 ++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/oxlint/conformance/src/index.ts b/apps/oxlint/conformance/src/index.ts index 5f7b7274874eb..0de2670cbbe6b 100644 --- a/apps/oxlint/conformance/src/index.ts +++ b/apps/oxlint/conformance/src/index.ts @@ -31,7 +31,7 @@ import { TEST_GROUPS } from "./groups/index.ts"; import { setCurrentGroup, setCurrentRule, resetCurrentRule } from "./capture.ts"; import { SHOULD_SKIP_GROUP, SHOULD_SKIP_RULE } from "./filter.ts"; import { generateReport } from "./report.ts"; -import { RuleTester, parserModules, parserModulePaths } from "./rule_tester.ts"; +import { RuleTester, parseForESLintFns, parserPaths } from "./rule_tester.ts"; import type { RuleResult } from "./capture.ts"; import type { Language, TestCase } from "./rule_tester.ts"; @@ -254,8 +254,8 @@ function runGroup(group: TestGroup, mocks: Mocks) { // Get custom parsers console.log(`Loading custom parsers for ${groupName}...`); - parserModules.clear(); - parserModulePaths.clear(); + parseForESLintFns.clear(); + parserPaths.clear(); for (const parserDetails of group.parsers) { const path = resolveFromTestsDir(parserDetails.specifier); @@ -264,8 +264,10 @@ function runGroup(group: TestGroup, mocks: Mocks) { // Set `default` export on parser module to work around apparent bug in `tsx` if (parser && parser.default === undefined) parser.default = parser; - parserModules.set(parser, parserDetails); - parserModulePaths.set(path, parserDetails); + if (typeof parser.parseForESLint === "function") { + parseForESLintFns.set(parser.parseForESLint, parserDetails); + } + parserPaths.set(path, parserDetails); } // Find test files and run tests diff --git a/apps/oxlint/conformance/src/rule_tester.ts b/apps/oxlint/conformance/src/rule_tester.ts index 1777d35108616..a55c9debd4b24 100644 --- a/apps/oxlint/conformance/src/rule_tester.ts +++ b/apps/oxlint/conformance/src/rule_tester.ts @@ -34,9 +34,9 @@ export type ValidTestCase = RuleTester.ValidTestCase & TestCaseExtension; export type InvalidTestCase = RuleTester.InvalidTestCase & TestCaseExtension; export type TestCase = ValidTestCase | InvalidTestCase; -// Maps of parser modules and parser paths to parser details (language + specifier) -export const parserModules: Map = new Map(); -export const parserModulePaths: Map = new Map(); +// Maps of parser `parseForESLint` functions and parser paths to parser details (language + specifier) +export const parseForESLintFns: Map = new Map(); +export const parserPaths: Map = new Map(); // Set up `RuleTester` to use our hooks RuleTester.describe = describe; @@ -174,8 +174,8 @@ function modifyTestCase(test: TestCase): void { // - Old ESLint versions: `test.parser` (absolute path to parser) let parserDetails: ParserDetails | null = null; - if (languageOptions.parser != null) { - parserDetails = parserModules.get(languageOptions.parser) ?? null; + if (languageOptions.parser?.parseForESLint != null) { + parserDetails = parseForESLintFns.get(languageOptions.parser.parseForESLint) ?? null; if (parserDetails !== null) delete languageOptions.parser; } @@ -183,7 +183,7 @@ function modifyTestCase(test: TestCase): void { if (parserDetails !== null) { throw new Error("Both `test.parser` and `test.languageOptions.parser` specified"); } - parserDetails = parserModulePaths.get(test.parser) ?? null; + parserDetails = parserPaths.get(test.parser) ?? null; if (parserDetails === null) { // Set `languageOptions.parser` so an error is thrown. // Store in stored test case so appears in snapshot.