From 415532e2e762ef01e2d858e1aa5d5ab5db9a6bca Mon Sep 17 00:00:00 2001 From: Francesco Trotta Date: Fri, 27 Dec 2024 07:20:42 +0100 Subject: [PATCH] fix: make `plugin-kit` types usable in CommonJS --- .github/workflows/ci.yml | 7 +- packages/core/tests/types/cjs-import.test.cts | 10 ++ packages/core/tests/types/tsconfig.json | 2 +- packages/plugin-kit/package.json | 3 +- .../plugin-kit/src/config-comment-parser.js | 4 +- .../tests/types/cjs-import.test.cts | 10 ++ packages/plugin-kit/tests/types/tsconfig.json | 9 ++ packages/plugin-kit/tests/types/types.test.ts | 104 ++++++++++++++++++ 8 files changed, 143 insertions(+), 6 deletions(-) create mode 100644 packages/core/tests/types/cjs-import.test.cts create mode 100644 packages/plugin-kit/tests/types/cjs-import.test.cts create mode 100644 packages/plugin-kit/tests/types/tsconfig.json create mode 100644 packages/plugin-kit/tests/types/types.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dcfd299..95790f0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,8 +55,11 @@ jobs: CI: true test_types: - name: Test Types (core) + name: Test Types (${ matrix.package }) runs-on: ubuntu-latest + strategy: + matrix: + package: [core, plugin-kit] steps: - uses: actions/checkout@v4 @@ -66,7 +69,7 @@ jobs: node-version: "lts/*" - name: npm install and test types - working-directory: packages/core + working-directory: packages/${ matrix.package } run: | npm install npm run build diff --git a/packages/core/tests/types/cjs-import.test.cts b/packages/core/tests/types/cjs-import.test.cts new file mode 100644 index 0000000..2fe5e2b --- /dev/null +++ b/packages/core/tests/types/cjs-import.test.cts @@ -0,0 +1,10 @@ +/** + * @fileoverview CommonJS type import test for ESLint Core. + * @author Francesco Trotta + */ + +//----------------------------------------------------------------------------- +// Imports +//----------------------------------------------------------------------------- + +import "@eslint/core"; diff --git a/packages/core/tests/types/tsconfig.json b/packages/core/tests/types/tsconfig.json index 7bbf5d8..b3220a7 100644 --- a/packages/core/tests/types/tsconfig.json +++ b/packages/core/tests/types/tsconfig.json @@ -5,5 +5,5 @@ "rootDir": "../..", "strict": true }, - "files": ["../../dist/esm/types.d.ts", "types.test.ts"] + "include": [".", "../../dist"] } diff --git a/packages/plugin-kit/package.json b/packages/plugin-kit/package.json index 8113a4f..2498667 100644 --- a/packages/plugin-kit/package.json +++ b/packages/plugin-kit/package.json @@ -37,7 +37,8 @@ "test:jsr": "npx jsr@latest publish --dry-run", "pretest": "npm run build", "test": "mocha tests/", - "test:coverage": "c8 npm test" + "test:coverage": "c8 npm test", + "test:types": "tsc -p tests/types/tsconfig.json" }, "keywords": [ "eslint", diff --git a/packages/plugin-kit/src/config-comment-parser.js b/packages/plugin-kit/src/config-comment-parser.js index 17464d9..e3799bb 100644 --- a/packages/plugin-kit/src/config-comment-parser.js +++ b/packages/plugin-kit/src/config-comment-parser.js @@ -17,8 +17,8 @@ import levn from "levn"; /** @typedef {import("@eslint/core").RuleConfig} RuleConfig */ /** @typedef {import("@eslint/core").RulesConfig} RulesConfig */ -/** @typedef {import("./types.ts").StringConfig} StringConfig */ -/** @typedef {import("./types.ts").BooleanConfig} BooleanConfig */ +/** @typedef {import("./types.ts", { with: { "resolution-mode": "import" } }).StringConfig} StringConfig */ +/** @typedef {import("./types.ts", { with: { "resolution-mode": "import" } }).BooleanConfig} BooleanConfig */ //----------------------------------------------------------------------------- // Helpers diff --git a/packages/plugin-kit/tests/types/cjs-import.test.cts b/packages/plugin-kit/tests/types/cjs-import.test.cts new file mode 100644 index 0000000..98a6ed1 --- /dev/null +++ b/packages/plugin-kit/tests/types/cjs-import.test.cts @@ -0,0 +1,10 @@ +/** + * @fileoverview CommonJS type import test for ESLint Plugin Kit. + * @author Francesco Trotta + */ + +//----------------------------------------------------------------------------- +// Imports +//----------------------------------------------------------------------------- + +import "@eslint/plugin-kit"; diff --git a/packages/plugin-kit/tests/types/tsconfig.json b/packages/plugin-kit/tests/types/tsconfig.json new file mode 100644 index 0000000..b3220a7 --- /dev/null +++ b/packages/plugin-kit/tests/types/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "noEmit": true, + "rootDir": "../..", + "strict": true + }, + "include": [".", "../../dist"] +} diff --git a/packages/plugin-kit/tests/types/types.test.ts b/packages/plugin-kit/tests/types/types.test.ts new file mode 100644 index 0000000..6643887 --- /dev/null +++ b/packages/plugin-kit/tests/types/types.test.ts @@ -0,0 +1,104 @@ +/** + * @fileoverview Type tests for ESLint Plugin Kit. + * @author Francesco Trotta + */ + +//----------------------------------------------------------------------------- +// Imports +//----------------------------------------------------------------------------- + +import { + BooleanConfig, + CallMethodStep, + ConfigCommentParser, + Directive, + DirectiveType, + RulesConfig, + SourceLocation, + SourceRange, + StringConfig, + TextSourceCodeBase, + VisitNodeStep, +} from "@eslint/plugin-kit"; + +//----------------------------------------------------------------------------- +// Tests +//----------------------------------------------------------------------------- + +// CallMethodStep +class TestCallMethodStep extends CallMethodStep { + constructor({ target, args }: { target: string; args: [string, number] }) { + super({ target, args }); + } +} +const step2 = new TestCallMethodStep({ target: "foo", args: ["foo", 42] }); +step2.args satisfies unknown[]; +step2.kind satisfies 2; +step2.target satisfies string; +step2.type satisfies "call"; + +// ConfigCommentParser +const configCommentParser = new ConfigCommentParser(); +configCommentParser.parseDirective("foo") satisfies + | { label: string; value: string; justification: string } + | undefined; +const jsonLikeConfig = configCommentParser.parseJSONLikeConfig("bar"); +if (jsonLikeConfig.ok) { + jsonLikeConfig.config satisfies RulesConfig; +} else { + jsonLikeConfig.error.message satisfies string; +} +configCommentParser.parseListConfig("baz") satisfies BooleanConfig; +configCommentParser.parseStringConfig("qux") satisfies StringConfig; + +// Directive +void ((type: "disable" | "enable" | "disable-next-line" | "disable-line") => { + const directive = new Directive({ + type, + node: {}, + value: "foo", + justification: "bar", + }); + directive.justification satisfies string; + directive.node satisfies unknown; + directive.type satisfies DirectiveType; + directive.value satisfies string; +}); + +// TextSourceCodeBase +class TestTextSourceCode extends TextSourceCodeBase { + declare ast: { foo: string; bar: number }; + constructor({ + text, + ast, + }: { + text: string; + ast: { foo: string; bar: number }; + }) { + super({ text, ast, lineEndingPattern: /\r\n|[\r\n\u2028\u2029]/u }); + } +} +const sourceCode = new TestTextSourceCode({ + text: "text", + ast: { foo: "ABC", bar: 123 }, +}); +sourceCode.ast satisfies { foo: string; bar: number }; +sourceCode.getAncestors({}) satisfies object[]; +sourceCode.getLoc({}) satisfies SourceLocation; +sourceCode.getParent({}) satisfies object | undefined; +sourceCode.getRange({}) satisfies SourceRange; +sourceCode.getText() satisfies string; +sourceCode.getText({}, 0, 1) satisfies string; + +// VisitNodeStep +class TestVisitNodeStep extends VisitNodeStep { + constructor({ target, phase }: { target: object; phase: 1 | 2 }) { + super({ target, phase, args: ["foo", 42] }); + } +} +const step1 = new TestVisitNodeStep({ target: { foo: "bar" }, phase: 2 }); +step1.args satisfies unknown[]; +step1.kind satisfies 1; +step1.phase satisfies 1 | 2; +step1.target satisfies object; +step1.type satisfies "visit";