From ae9c13c09a589408ff6313b12c1362f63aeab75a Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Tue, 3 Sep 2024 17:27:42 -0400 Subject: [PATCH 1/5] chore: fully type check packages/*/src files --- .github/workflows/ci.yml | 3 ++ CONTRIBUTING.md | 40 +++++++++++++++++++ package.json | 2 + packages/compat/src/fixup-rules.js | 2 + packages/compat/tsconfig.json | 10 +---- packages/config-array/tsconfig.json | 10 +---- packages/core/tsconfig.json | 10 +---- packages/migrate-config/tsconfig.json | 10 +---- packages/object-schema/tsconfig.json | 10 +---- packages/plugin-kit/src/@types/levn.d.ts | 8 ---- .../plugin-kit/src/config-comment-parser.js | 5 ++- packages/plugin-kit/src/source-code.js | 4 +- packages/plugin-kit/tsconfig.json | 11 +---- scripts/build.js | 4 +- tsconfig.base.json | 17 ++++++++ tsconfig.json | 8 ++++ types/levn.d.ts | 36 +++++++++++++++++ 17 files changed, 127 insertions(+), 63 deletions(-) create mode 100644 CONTRIBUTING.md delete mode 100644 packages/plugin-kit/src/@types/levn.d.ts create mode 100644 tsconfig.base.json create mode 100644 tsconfig.json create mode 100644 types/levn.d.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb045a0..b55b1a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,9 @@ jobs: - name: Lint Files run: npm run lint + - name: Type Check Files + run: npm run tsc + - name: Check Formatting run: npm run fmt:check diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..733077a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,40 @@ +# Contributing + +Please be sure to read the contribution guidelines before making or requesting a change. + +## Code of Conduct + +This project adheres to the [OpenJS Foundation Code of Conduct](https://eslint.org/conduct). We kindly request that you read over our code of conduct before contributing. + +## Commands + +### Building + +[Rollup](https://rollupjs.org) and [TypeScript](https://www.typescriptlang.org) are used to turn source files in `packages/*/src/` into outputs in `packages/*/lib/`. + +```shell +npm run build +``` + +### Linting + +ESLint is linted using ESLint. +[Building](#building) the project must be done before it can lint itself. + +```shell +npm run lint +``` + +### Type Checking + +This project is written in JavaScript and uses [TypeScript](https://www.typescriptlang.org) to validate types declared in JSDoc comments. + +```shell +npm run tsc +``` + +Add `--watch` to run in a "watch" mode: + +```shell +npm run tsc -- --watch +``` diff --git a/package.json b/package.json index 7e799ef..fd44b8a 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "build": "node scripts/build.js", "build:readme": "node tools/update-readme.js", "lint": "eslint .", + "tsc": "tsc", "lint:fix": "eslint --fix .", "fmt": "prettier --write .", "fmt:check": "prettier --check .", @@ -27,6 +28,7 @@ "!(*.{js,ts})": "prettier --write --ignore-unknown" }, "devDependencies": { + "@types/mocha": "^10.0.7", "common-tags": "^1.8.2", "eslint": "^9.4.0", "eslint-config-eslint": "^11.0.0", diff --git a/packages/compat/src/fixup-rules.js b/packages/compat/src/fixup-rules.js index 96916c2..5408421 100644 --- a/packages/compat/src/fixup-rules.js +++ b/packages/compat/src/fixup-rules.js @@ -161,6 +161,7 @@ export function fixupRule(ruleDefinition) { currentNode = args[methodName === "onCodePathSegmentLoop" ? 2 : 1]; + // @ts-expect-error -- method.call is any from Object.entries, but we know its type is fine return method.call(visitor, ...args); }; @@ -171,6 +172,7 @@ export function fixupRule(ruleDefinition) { visitor[methodName] = (...args) => { currentNode = args[0]; + // @ts-expect-error -- method.call is any from Object.entries, but we know its type is fine return method.call(visitor, ...args); }; } diff --git a/packages/compat/tsconfig.json b/packages/compat/tsconfig.json index 3fa504c..5d8149a 100644 --- a/packages/compat/tsconfig.json +++ b/packages/compat/tsconfig.json @@ -1,13 +1,7 @@ { + "extends": "../../tsconfig.base.json", "files": ["src/index.js"], "compilerOptions": { - "declaration": true, - "emitDeclarationOnly": true, - "allowJs": true, - "checkJs": true, - "outDir": "dist/esm", - "target": "ES2022", - "moduleResolution": "NodeNext", - "module": "NodeNext" + "outDir": "dist/esm" } } diff --git a/packages/config-array/tsconfig.json b/packages/config-array/tsconfig.json index 3fa504c..5d8149a 100644 --- a/packages/config-array/tsconfig.json +++ b/packages/config-array/tsconfig.json @@ -1,13 +1,7 @@ { + "extends": "../../tsconfig.base.json", "files": ["src/index.js"], "compilerOptions": { - "declaration": true, - "emitDeclarationOnly": true, - "allowJs": true, - "checkJs": true, - "outDir": "dist/esm", - "target": "ES2022", - "moduleResolution": "NodeNext", - "module": "NodeNext" + "outDir": "dist/esm" } } diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index cbeabd7..67750a2 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -1,13 +1,7 @@ { + "extends": "../../tsconfig.base.json", "files": ["src/types.ts"], "compilerOptions": { - "declaration": true, - "emitDeclarationOnly": true, - "allowJs": true, - "checkJs": true, - "outDir": "dist/esm", - "target": "ES2022", - "moduleResolution": "NodeNext", - "module": "NodeNext" + "outDir": "dist/esm" } } diff --git a/packages/migrate-config/tsconfig.json b/packages/migrate-config/tsconfig.json index 08bc479..4e6f7b3 100644 --- a/packages/migrate-config/tsconfig.json +++ b/packages/migrate-config/tsconfig.json @@ -1,13 +1,7 @@ { + "extends": "../../tsconfig.base.json", "files": ["src/migrate-config-cli.js"], "compilerOptions": { - "declaration": true, - "emitDeclarationOnly": true, - "allowJs": true, - "checkJs": true, - "outDir": "dist/esm", - "target": "ES2022", - "moduleResolution": "NodeNext", - "module": "NodeNext" + "outDir": "dist/esm" } } diff --git a/packages/object-schema/tsconfig.json b/packages/object-schema/tsconfig.json index 3fa504c..5d8149a 100644 --- a/packages/object-schema/tsconfig.json +++ b/packages/object-schema/tsconfig.json @@ -1,13 +1,7 @@ { + "extends": "../../tsconfig.base.json", "files": ["src/index.js"], "compilerOptions": { - "declaration": true, - "emitDeclarationOnly": true, - "allowJs": true, - "checkJs": true, - "outDir": "dist/esm", - "target": "ES2022", - "moduleResolution": "NodeNext", - "module": "NodeNext" + "outDir": "dist/esm" } } diff --git a/packages/plugin-kit/src/@types/levn.d.ts b/packages/plugin-kit/src/@types/levn.d.ts deleted file mode 100644 index 94414cc..0000000 --- a/packages/plugin-kit/src/@types/levn.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -declare module "levn" { - interface ParseOptions { - explicit?: boolean; - customTypes: Record; - } - - function parse(type: string, input: string, options?: ParseOptions): object; -} diff --git a/packages/plugin-kit/src/config-comment-parser.js b/packages/plugin-kit/src/config-comment-parser.js index f22f97a..82d1f8b 100644 --- a/packages/plugin-kit/src/config-comment-parser.js +++ b/packages/plugin-kit/src/config-comment-parser.js @@ -9,7 +9,6 @@ // Imports //------------------------------------------------------------------------------ -// @ts-ignore -- don't feel like fighting with TypeScript right now import levn from "levn"; //----------------------------------------------------------------------------- @@ -123,7 +122,9 @@ export class ConfigCommentParser { parseJSONLikeConfig(string) { // Parses a JSON-like comment by the same way as parsing CLI option. try { - const items = levn.parse("Object", string) || {}; + const items = /** @type {RulesConfig} */ ( + levn.parse("Object", string) || {} + ); /* * When the configuration has any invalid severities, it should be completely diff --git a/packages/plugin-kit/src/source-code.js b/packages/plugin-kit/src/source-code.js index 13854cc..c5411b0 100644 --- a/packages/plugin-kit/src/source-code.js +++ b/packages/plugin-kit/src/source-code.js @@ -174,7 +174,7 @@ export class Directive { /** * The node representing the directive. - * @type {unknown} + * @type {object} * @readonly */ node; @@ -198,7 +198,7 @@ export class Directive { * Creates a new instance. * @param {Object} options The options for the directive. * @param {"disable"|"enable"|"disable-next-line"|"disable-line"} options.type The type of directive. - * @param {unknown} options.node The node representing the directive. + * @param {object} options.node The node representing the directive. * @param {string} options.value The value of the directive. * @param {string} options.justification The justification for the directive. */ diff --git a/packages/plugin-kit/tsconfig.json b/packages/plugin-kit/tsconfig.json index 960debf..779639c 100644 --- a/packages/plugin-kit/tsconfig.json +++ b/packages/plugin-kit/tsconfig.json @@ -1,15 +1,8 @@ { + "extends": "../../tsconfig.base.json", "files": ["src/index.js"], "compilerOptions": { - "declaration": true, - "emitDeclarationOnly": true, - "allowJs": true, - "checkJs": true, "outDir": "dist/esm", - "target": "ES2022", - "moduleResolution": "NodeNext", - "module": "NodeNext", - "strict": true, - "typeRoots": ["node_modules/@types", "src/@types"] + "strict": true } } diff --git a/scripts/build.js b/scripts/build.js index 2200225..22d4bee 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -67,8 +67,8 @@ async function calculatePackageDependencies(packageDirs) { } /** - * Creates an array of directories to be built in order to sastify dependencies. - * @param {Map}} dependencies The + * Creates an array of directories to be built in order to satisfy dependencies. + * @param {Map}>} dependencies The * dependencies between packages. * @returns {Array} An array of directories to be built in order. */ diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..64e381c --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "declaration": true, + "emitDeclarationOnly": true, + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "target": "ES2022", + + // TODO: Over time, enable these strict options + "noImplicitAny": false, + "strictNullChecks": false, + "useUnknownInCatchVariables": false + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..f4bf5d8 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.base.json", + "include": ["packages/*/src"], + "compilerOptions": { + "emitDeclarationOnly": false, + "noEmit": true + } +} diff --git a/types/levn.d.ts b/types/levn.d.ts new file mode 100644 index 0000000..61e75b7 --- /dev/null +++ b/types/levn.d.ts @@ -0,0 +1,36 @@ +/** + * @todo This should be contributed up to DefinitelyTyped to make a `@types/levn` package. + */ +declare module "levn" { + export interface ParseOptions { + explicit?: boolean | undefined; + customTypes?: Record; + } + + export interface CustomParseType { + typeOf: string; + validate: (value: unknown) => boolean; + cast: (value: unknown) => CastedValue; + } + + export interface CastedValue { + type: string; + value: Value; + } + + // TODO: This comes from type-check. + export type ParsedType = unknown; + + export function parse( + type: string, + string: string, + options?: unknown, + ): unknown; + + export function parsedTypeParse( + parsedType: string, + options?: unknown, + ): unknown; + + export const VERSION: string; +} From cb49807c6027cb4acfa5d42581904da299dd3664 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Tue, 3 Sep 2024 17:48:07 -0400 Subject: [PATCH 2/5] chore: remove unnecessary type assertion --- packages/plugin-kit/src/config-comment-parser.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/plugin-kit/src/config-comment-parser.js b/packages/plugin-kit/src/config-comment-parser.js index 82d1f8b..e4489c0 100644 --- a/packages/plugin-kit/src/config-comment-parser.js +++ b/packages/plugin-kit/src/config-comment-parser.js @@ -122,9 +122,7 @@ export class ConfigCommentParser { parseJSONLikeConfig(string) { // Parses a JSON-like comment by the same way as parsing CLI option. try { - const items = /** @type {RulesConfig} */ ( - levn.parse("Object", string) || {} - ); + const items = levn.parse("Object", string) || {}; /* * When the configuration has any invalid severities, it should be completely From b0cbf31177c939aa0600b394545144fa1d97753a Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Tue, 3 Sep 2024 17:49:14 -0400 Subject: [PATCH 3/5] chore: remove unnecessary unknown/object type changes --- packages/plugin-kit/src/source-code.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin-kit/src/source-code.js b/packages/plugin-kit/src/source-code.js index c5411b0..13854cc 100644 --- a/packages/plugin-kit/src/source-code.js +++ b/packages/plugin-kit/src/source-code.js @@ -174,7 +174,7 @@ export class Directive { /** * The node representing the directive. - * @type {object} + * @type {unknown} * @readonly */ node; @@ -198,7 +198,7 @@ export class Directive { * Creates a new instance. * @param {Object} options The options for the directive. * @param {"disable"|"enable"|"disable-next-line"|"disable-line"} options.type The type of directive. - * @param {object} options.node The node representing the directive. + * @param {unknown} options.node The node representing the directive. * @param {string} options.value The value of the directive. * @param {string} options.justification The justification for the directive. */ From ebeb4c8c028b4747a7b7ac9193f50893174097a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Wed, 4 Sep 2024 19:57:19 -0400 Subject: [PATCH 4/5] Update CONTRIBUTING.md Co-authored-by: Nicholas C. Zakas --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 733077a..4f3c108 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ This project adheres to the [OpenJS Foundation Code of Conduct](https://eslint.o ### Building -[Rollup](https://rollupjs.org) and [TypeScript](https://www.typescriptlang.org) are used to turn source files in `packages/*/src/` into outputs in `packages/*/lib/`. +[Rollup](https://rollupjs.org) and [TypeScript](https://www.typescriptlang.org) are used to turn source files in `packages/*/src/` into outputs in `packages/*/dist/`. ```shell npm run build From 3e4c6e50ba26537786cf2287be135c7a1c238d1b Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Wed, 4 Sep 2024 20:23:48 -0400 Subject: [PATCH 5/5] Remove strict mode --- packages/compat/src/fixup-rules.js | 2 -- tsconfig.base.json | 8 +------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/compat/src/fixup-rules.js b/packages/compat/src/fixup-rules.js index 5408421..96916c2 100644 --- a/packages/compat/src/fixup-rules.js +++ b/packages/compat/src/fixup-rules.js @@ -161,7 +161,6 @@ export function fixupRule(ruleDefinition) { currentNode = args[methodName === "onCodePathSegmentLoop" ? 2 : 1]; - // @ts-expect-error -- method.call is any from Object.entries, but we know its type is fine return method.call(visitor, ...args); }; @@ -172,7 +171,6 @@ export function fixupRule(ruleDefinition) { visitor[methodName] = (...args) => { currentNode = args[0]; - // @ts-expect-error -- method.call is any from Object.entries, but we know its type is fine return method.call(visitor, ...args); }; } diff --git a/tsconfig.base.json b/tsconfig.base.json index 64e381c..c5740a8 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -6,12 +6,6 @@ "emitDeclarationOnly": true, "module": "NodeNext", "moduleResolution": "NodeNext", - "strict": true, - "target": "ES2022", - - // TODO: Over time, enable these strict options - "noImplicitAny": false, - "strictNullChecks": false, - "useUnknownInCatchVariables": false + "target": "ES2022" } }