From ad7e3c0db1c4c6f7ac808ed350838ef6ea2d901c Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Wed, 15 Nov 2023 20:50:01 +1030 Subject: [PATCH] feat: add support for flat configs --- .cspell.json | 2 + .eslintignore | 17 - .eslintrc.js | 457 --------------- .github/renovate.json5 | 5 + .github/workflows/ci.yml | 2 + .vscode/settings.json | 2 + docs/packages/Core.mdx | 12 + docs/packages/Parser.mdx | 10 +- eslint.config.js | 8 + eslint.config.mjs | 533 ++++++++++++++++++ nx.json | 4 +- package.json | 10 +- packages/ast-spec/project.json | 5 +- packages/eslint-plugin-internal/index.d.ts | 9 + packages/eslint-plugin-internal/package.json | 1 + packages/eslint-plugin-internal/project.json | 5 +- packages/eslint-plugin-internal/src/index.ts | 10 + packages/eslint-plugin-internal/tsconfig.json | 2 +- packages/eslint-plugin-tslint/project.json | 5 +- .../eslint-plugin/eslint-recommended-raw.d.ts | 5 + packages/eslint-plugin/index.d.ts | 6 +- packages/eslint-plugin/package.json | 6 +- packages/eslint-plugin/project.json | 5 +- packages/eslint-plugin/rules.d.ts | 1 + packages/eslint-plugin/src/configs/base.ts | 7 - .../src/configs/disable-type-checked.ts | 2 +- .../src/configs/eslint-recommended-raw.ts | 44 ++ .../src/configs/eslint-recommended.ts | 30 +- packages/eslint-plugin/src/index.ts | 10 + .../lines-between-class-members.shot | 52 +- .../no-restricted-imports.shot | 4 + packages/integration-tests/project.json | 5 +- packages/parser/project.json | 5 +- packages/parser/src/parser.ts | 3 +- packages/repo-tools/package.json | 8 +- packages/repo-tools/project.json | 5 +- .../src/generate-configs.mts} | 175 +++--- ...tributors.ts => generate-contributors.mts} | 12 +- .../src/{generate-lib.ts => generate-lib.mts} | 37 +- ...rate-sponsors.ts => generate-sponsors.mts} | 4 +- packages/repo-tools/src/paths.mts | 13 + packages/repo-tools/tsconfig.build.json | 3 + .../project.json | 5 +- packages/scope-manager/project.json | 5 +- packages/type-utils/project.json | 5 +- packages/types/project.json | 5 +- packages/types/src/parser-options.ts | 4 +- .../typescript-eslint/{LICENCE => LICENSE} | 0 packages/typescript-eslint/jest.config.js | 8 + packages/typescript-eslint/package.json | 1 - packages/typescript-eslint/project.json | 5 +- .../typescript-eslint/src/config-helper.ts | 86 +++ packages/typescript-eslint/src/configs/all.ts | 165 ++++++ .../typescript-eslint/src/configs/base.ts | 14 + .../src/configs/disable-type-checked.ts | 67 +++ .../src/configs/eslint-recommended.ts | 12 + .../src/configs/recommended-type-checked.ts | 64 +++ .../src/configs/recommended.ts | 43 ++ .../src/configs/strict-type-checked.ts | 89 +++ .../typescript-eslint/src/configs/strict.ts | 53 ++ .../src/configs/stylistic-type-checked.ts | 45 ++ .../src/configs/stylistic.ts | 39 ++ packages/typescript-eslint/src/index.ts | 45 +- .../typescript-eslint/tests/configs.test.ts | 213 +++++++ packages/typescript-estree/project.json | 5 +- .../parseSettings/getProjectConfigFiles.ts | 7 +- .../typescript-estree/src/parser-options.ts | 2 +- .../tests/lib/semanticInfo.test.ts | 4 +- .../test-utils/expectToHaveParserServices.ts | 2 +- .../{tools => tests/test-utils}/test-utils.ts | 4 +- .../test-utils}/tserror-serializer.ts | 2 +- packages/utils/project.json | 5 +- packages/utils/src/ts-eslint/Config.ts | 18 +- packages/utils/src/ts-eslint/Linter.ts | 4 +- packages/utils/src/ts-eslint/Parser.ts | 35 +- packages/visitor-keys/project.json | 5 +- packages/website-eslint/package.json | 2 +- packages/website-eslint/project.json | 5 +- packages/website/project.json | 5 +- tsconfig.base.json | 9 +- tsconfig.eslint.json => tsconfig.json | 2 + typings/eslint-plugin-eslint-comments.d.ts | 14 + typings/eslint-plugin-eslint-plugin.d.ts | 19 + typings/eslint-plugin-import.d.ts | 21 + typings/eslint-plugin-jest.d.ts | 21 + typings/eslint-plugin-jsdoc.d.ts | 25 + typings/eslint-plugin-jsx-a11y.d.ts | 15 + typings/eslint-plugin-react-hooks.d.ts | 14 + typings/eslint-plugin-react.d.ts | 16 + typings/eslint-plugin-simple-import-sort.d.ts | 8 + typings/eslint-plugin-unicorn.d.ts | 15 + typings/eslint__eslintrc.d.ts | 22 + typings/eslint__js.d.ts | 11 + yarn.lock | 149 ++++- 94 files changed, 2228 insertions(+), 752 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc.js create mode 100644 docs/packages/Core.mdx create mode 100644 eslint.config.js create mode 100644 eslint.config.mjs create mode 100644 packages/eslint-plugin-internal/index.d.ts create mode 100644 packages/eslint-plugin/eslint-recommended-raw.d.ts create mode 100644 packages/eslint-plugin/src/configs/eslint-recommended-raw.ts rename packages/{eslint-plugin/tools/generate-configs.ts => repo-tools/src/generate-configs.mts} (60%) rename packages/repo-tools/src/{generate-contributors.ts => generate-contributors.mts} (96%) rename packages/repo-tools/src/{generate-lib.ts => generate-lib.mts} (95%) rename packages/repo-tools/src/{generate-sponsors.ts => generate-sponsors.mts} (97%) create mode 100644 packages/repo-tools/src/paths.mts rename packages/typescript-eslint/{LICENCE => LICENSE} (100%) create mode 100644 packages/typescript-eslint/jest.config.js create mode 100644 packages/typescript-eslint/src/config-helper.ts create mode 100644 packages/typescript-eslint/src/configs/all.ts create mode 100644 packages/typescript-eslint/src/configs/base.ts create mode 100644 packages/typescript-eslint/src/configs/disable-type-checked.ts create mode 100644 packages/typescript-eslint/src/configs/eslint-recommended.ts create mode 100644 packages/typescript-eslint/src/configs/recommended-type-checked.ts create mode 100644 packages/typescript-eslint/src/configs/recommended.ts create mode 100644 packages/typescript-eslint/src/configs/strict-type-checked.ts create mode 100644 packages/typescript-eslint/src/configs/strict.ts create mode 100644 packages/typescript-eslint/src/configs/stylistic-type-checked.ts create mode 100644 packages/typescript-eslint/src/configs/stylistic.ts create mode 100644 packages/typescript-eslint/tests/configs.test.ts rename packages/typescript-estree/tests/{lib => }/test-utils/expectToHaveParserServices.ts (94%) rename packages/typescript-estree/{tools => tests/test-utils}/test-utils.ts (99%) rename packages/typescript-estree/{tools => tests/test-utils}/tserror-serializer.ts (93%) rename tsconfig.eslint.json => tsconfig.json (88%) create mode 100644 typings/eslint-plugin-eslint-comments.d.ts create mode 100644 typings/eslint-plugin-eslint-plugin.d.ts create mode 100644 typings/eslint-plugin-import.d.ts create mode 100644 typings/eslint-plugin-jest.d.ts create mode 100644 typings/eslint-plugin-jsdoc.d.ts create mode 100644 typings/eslint-plugin-jsx-a11y.d.ts create mode 100644 typings/eslint-plugin-react-hooks.d.ts create mode 100644 typings/eslint-plugin-react.d.ts create mode 100644 typings/eslint-plugin-simple-import-sort.d.ts create mode 100644 typings/eslint-plugin-unicorn.d.ts create mode 100644 typings/eslint__eslintrc.d.ts create mode 100644 typings/eslint__js.d.ts diff --git a/.cspell.json b/.cspell.json index c5bd12a5c9ab..99feed384c1f 100644 --- a/.cspell.json +++ b/.cspell.json @@ -100,6 +100,8 @@ "noninteractive", "Nrwl", "nullish", + "nx", + "nx's", "onboarded", "OOM", "OOMs", diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 431bc8030293..000000000000 --- a/.eslintignore +++ /dev/null @@ -1,17 +0,0 @@ -node_modules -dist -jest.config.js -fixtures -coverage -__snapshots__ -.docusaurus -build - -# Files copied as part of the build -packages/types/src/generated/**/*.ts - -# Playground types downloaded from the web -packages/website/src/vendor - -# see the file header in eslint-base.test.js for more info -packages/rule-tester/tests/eslint-base diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 1398b8f04d87..000000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,457 +0,0 @@ -// @ts-check -/** @type {import('./packages/utils/src/ts-eslint/Linter').Linter.Config} */ -module.exports = { - root: true, - plugins: [ - '@typescript-eslint', - '@typescript-eslint/internal', - 'deprecation', - 'eslint-comments', - 'eslint-plugin', - 'import', - 'jest', - 'jsdoc', - 'simple-import-sort', - 'unicorn', - ], - env: { - es2020: true, - node: true, - }, - extends: [ - 'eslint:recommended', - 'plugin:eslint-plugin/recommended', - 'plugin:jsdoc/recommended-typescript-error', - 'plugin:@typescript-eslint/strict-type-checked', - 'plugin:@typescript-eslint/stylistic-type-checked', - ], - parserOptions: { - allowAutomaticSingleRunInference: true, - cacheLifetime: { - // we pretty well never create/change tsconfig structure - so no need to ever evict the cache - // in the rare case that we do - just need to manually restart their IDE. - glob: 'Infinity', - }, - project: [ - './tsconfig.eslint.json', - './packages/*/tsconfig.json', - /** - * We are currently in the process of transitioning to nx's out of the box structure and - * so need to manually specify converted packages' tsconfig.build.json and tsconfig.spec.json - * files here for now in addition to the tsconfig.json glob pattern. - * - * TODO(#4665): Clean this up once all packages have been transitioned. - */ - './packages/scope-manager/tsconfig.build.json', - './packages/scope-manager/tsconfig.spec.json', - ], - tsconfigRootDir: __dirname, - }, - rules: { - // make sure we're not leveraging any deprecated APIs - 'deprecation/deprecation': 'error', - - // TODO(#7130): Investigate changing these in or removing these from presets - '@typescript-eslint/no-confusing-void-expression': 'off', - '@typescript-eslint/prefer-string-starts-ends-with': 'off', - - // - // our plugin :D - // - - '@typescript-eslint/ban-ts-comment': [ - 'error', - { - 'ts-expect-error': 'allow-with-description', - 'ts-ignore': true, - 'ts-nocheck': true, - 'ts-check': false, - minimumDescriptionLength: 5, - }, - ], - '@typescript-eslint/consistent-type-imports': [ - 'error', - { prefer: 'type-imports', disallowTypeAnnotations: true }, - ], - '@typescript-eslint/explicit-function-return-type': [ - 'error', - { allowIIFEs: true }, - ], - '@typescript-eslint/no-explicit-any': 'error', - '@typescript-eslint/no-non-null-assertion': 'off', - 'no-constant-condition': 'off', - '@typescript-eslint/no-unnecessary-condition': [ - 'error', - { allowConstantLoopConditions: true }, - ], - '@typescript-eslint/no-var-requires': 'off', - '@typescript-eslint/prefer-literal-enum-member': [ - 'error', - { - allowBitwiseExpressions: true, - }, - ], - '@typescript-eslint/unbound-method': 'off', - '@typescript-eslint/restrict-template-expressions': [ - 'error', - { - allowNumber: true, - allowBoolean: true, - allowAny: true, - allowNullish: true, - allowRegExp: true, - }, - ], - '@typescript-eslint/no-unused-vars': [ - 'error', - { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, - ], - '@typescript-eslint/prefer-nullish-coalescing': [ - 'error', - { - ignoreConditionalTests: true, - ignorePrimitives: true, - }, - ], - - // - // Internal repo rules - // - - '@typescript-eslint/internal/no-poorly-typed-ts-props': 'error', - '@typescript-eslint/internal/no-typescript-default-import': 'error', - '@typescript-eslint/internal/prefer-ast-types-enum': 'error', - - // - // eslint-base - // - - curly: ['error', 'all'], - eqeqeq: [ - 'error', - 'always', - { - null: 'never', - }, - ], - 'logical-assignment-operators': 'error', - 'no-else-return': 'error', - 'no-mixed-operators': 'error', - 'no-console': 'error', - 'no-process-exit': 'error', - 'no-fallthrough': [ - 'error', - { commentPattern: '.*intentional fallthrough.*' }, - ], - 'one-var': ['error', 'never'], - - // - // eslint-plugin-eslint-comment - // - - // require a eslint-enable comment for every eslint-disable comment - 'eslint-comments/disable-enable-pair': [ - 'error', - { - allowWholeFile: true, - }, - ], - // disallow a eslint-enable comment for multiple eslint-disable comments - 'eslint-comments/no-aggregating-enable': 'error', - // disallow duplicate eslint-disable comments - 'eslint-comments/no-duplicate-disable': 'error', - // disallow eslint-disable comments without rule names - 'eslint-comments/no-unlimited-disable': 'error', - // disallow unused eslint-disable comments - 'eslint-comments/no-unused-disable': 'error', - // disallow unused eslint-enable comments - 'eslint-comments/no-unused-enable': 'error', - // disallow ESLint directive-comments - 'eslint-comments/no-use': [ - 'error', - { - allow: [ - 'eslint-disable', - 'eslint-disable-line', - 'eslint-disable-next-line', - 'eslint-enable', - 'global', - ], - }, - ], - - // - // eslint-plugin-import - // - - // disallow non-import statements appearing before import statements - 'import/first': 'error', - // Require a newline after the last import/require in a group - 'import/newline-after-import': 'error', - // Forbid import of modules using absolute paths - 'import/no-absolute-path': 'error', - // disallow AMD require/define - 'import/no-amd': 'error', - // forbid default exports - we want to standardize on named exports so that imported names are consistent - 'import/no-default-export': 'error', - // disallow imports from duplicate paths - 'import/no-duplicates': 'error', - // Forbid the use of extraneous packages - 'import/no-extraneous-dependencies': [ - 'error', - { - devDependencies: true, - peerDependencies: true, - optionalDependencies: false, - }, - ], - // Forbid mutable exports - 'import/no-mutable-exports': 'error', - // Prevent importing the default as if it were named - 'import/no-named-default': 'error', - // Prohibit named exports - 'import/no-named-export': 'off', // we want everything to be a named export - // Forbid a module from importing itself - 'import/no-self-import': 'error', - // Require modules with a single export to use a default export - 'import/prefer-default-export': 'off', // we want everything to be named - - // enforce a sort order across the codebase - 'simple-import-sort/imports': 'error', - - // - // eslint-plugin-jsdoc - // - - // We often use @remarks or other ad-hoc tag names - 'jsdoc/check-tag-names': 'off', - // https://github.com/gajus/eslint-plugin-jsdoc/issues/1169 - 'jsdoc/check-param-names': 'off', - // https://github.com/gajus/eslint-plugin-jsdoc/issues/1175 - 'jsdoc/require-jsdoc': 'off', - 'jsdoc/require-param': 'off', - 'jsdoc/require-returns': 'off', - 'jsdoc/require-yields': 'off', - 'jsdoc/tag-lines': 'off', - - // - // eslint-plugin-unicorn - // - - 'unicorn/no-typeof-undefined': 'error', - }, - overrides: [ - { - files: ['*.js'], - extends: ['plugin:@typescript-eslint/disable-type-checked'], - rules: { - // turn off other type-aware rules - 'deprecation/deprecation': 'off', - '@typescript-eslint/internal/no-poorly-typed-ts-props': 'off', - - // turn off rules that don't apply to JS code - '@typescript-eslint/explicit-function-return-type': 'off', - }, - }, - // all test files - { - files: [ - './packages/*/tests/**/*.spec.ts', - './packages/*/tests/**/*.test.ts', - './packages/*/tests/**/spec.ts', - './packages/*/tests/**/test.ts', - './packages/parser/tests/**/*.ts', - './packages/integration-tests/tools/integration-test-base.ts', - './packages/integration-tests/tools/pack-packages.ts', - ], - env: { - 'jest/globals': true, - }, - rules: { - '@typescript-eslint/no-empty-function': [ - 'error', - { allow: ['arrowFunctions'] }, - ], - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-return': 'off', - 'eslint-plugin/consistent-output': 'off', // Might eventually be removed from `eslint-plugin/recommended`: https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/284 - 'jest/no-disabled-tests': 'error', - 'jest/no-focused-tests': 'error', - 'jest/no-alias-methods': 'error', - 'jest/no-identical-title': 'error', - 'jest/no-jasmine-globals': 'error', - 'jest/no-test-prefixes': 'error', - 'jest/no-done-callback': 'error', - 'jest/no-test-return-statement': 'error', - 'jest/prefer-to-be': 'error', - 'jest/prefer-to-contain': 'error', - 'jest/prefer-to-have-length': 'error', - 'jest/prefer-spy-on': 'error', - 'jest/valid-expect': 'error', - 'jest/no-deprecated-functions': 'error', - }, - }, - // test utility scripts and website js files - { - files: ['tests/**/*.js'], - rules: { - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-return': 'off', - '@typescript-eslint/restrict-plus-operands': 'off', - }, - }, - // plugin source files - { - files: [ - './packages/eslint-plugin-internal/**/*.ts', - './packages/eslint-plugin-tslint/**/*.ts', - './packages/eslint-plugin/**/*.ts', - ], - rules: { - '@typescript-eslint/internal/no-typescript-estree-import': 'error', - }, - }, - // plugin rule source files - { - files: [ - './packages/eslint-plugin-internal/src/rules/**/*.ts', - './packages/eslint-plugin-tslint/src/rules/**/*.ts', - './packages/eslint-plugin/src/configs/**/*.ts', - './packages/eslint-plugin/src/rules/**/*.ts', - ], - rules: { - 'eslint-plugin/require-meta-docs-description': [ - 'error', - { pattern: '^(Enforce|Require|Disallow) .+[^. ]$' }, - ], - - // specifically for rules - default exports makes the tooling easier - 'import/no-default-export': 'off', - - 'no-restricted-syntax': [ - 'error', - { - selector: - 'ExportDefaultDeclaration Property[key.name="create"] MemberExpression[object.name="context"][property.name="options"]', - message: - "Retrieve options from create's second parameter so that defaultOptions are applied.", - }, - ], - }, - }, - // plugin rule tests - { - files: [ - './packages/eslint-plugin-internal/tests/rules/**/*.test.ts', - './packages/eslint-plugin-tslint/tests/rules/**/*.test.ts', - './packages/eslint-plugin/tests/rules/**/*.test.ts', - './packages/eslint-plugin/tests/eslint-rules/**/*.test.ts', - ], - rules: { - '@typescript-eslint/internal/plugin-test-formatting': 'error', - }, - }, - // files which list all the things - { - files: ['./packages/eslint-plugin/src/rules/index.ts'], - rules: { - // enforce alphabetical ordering - 'sort-keys': 'error', - 'import/order': ['error', { alphabetize: { order: 'asc' } }], - }, - }, - // tools and tests - { - files: [ - '**/tools/**/*.*t*', - '**/tests/**/*.ts', - './packages/repo-tools/**/*.*t*', - './packages/integration-tests/**/*.*t*', - ], - rules: { - // allow console logs in tools and tests - 'no-console': 'off', - }, - }, - // generated files - { - files: [ - './packages/scope-manager/src/lib/*.ts', - './packages/eslint-plugin/src/configs/*.ts', - ], - rules: { - '@typescript-eslint/internal/no-poorly-typed-ts-props': 'off', - '@typescript-eslint/internal/no-typescript-default-import': 'off', - '@typescript-eslint/internal/prefer-ast-types-enum': 'off', - }, - }, - // ast spec specific standardization - { - files: ['./packages/ast-spec/src/**/*.ts'], - rules: { - // disallow ALL unused vars - '@typescript-eslint/no-unused-vars': 'error', - '@typescript-eslint/sort-type-constituents': 'error', - }, - }, - { - files: ['./packages/ast-spec/**/*.ts'], - rules: { - 'no-restricted-imports': [ - 'error', - { - name: '@typescript-eslint/typescript-estree', - message: - 'To prevent nx build errors, all `typescript-estree` imports should be done via `packages/ast-spec/tests/util/parsers/typescript-estree-import.ts`.', - }, - ], - }, - }, - { - files: ['rollup.config.ts'], - rules: { - 'import/no-default-export': 'off', - }, - }, - { - files: ['./packages/website/**/*.{ts,tsx,mts,cts,js,jsx}'], - extends: [ - 'plugin:jsx-a11y/recommended', - 'plugin:react/recommended', - 'plugin:react-hooks/recommended', - ], - plugins: ['jsx-a11y', 'react', 'react-hooks'], - rules: { - '@typescript-eslint/internal/prefer-ast-types-enum': 'off', - 'import/no-default-export': 'off', - 'react/jsx-no-target-blank': 'off', - 'react/no-unescaped-entities': 'off', - 'react-hooks/exhaustive-deps': 'warn', // TODO: enable it later - }, - settings: { - react: { - version: 'detect', - }, - }, - }, - { - files: ['./packages/website/src/**/*.{ts,tsx}'], - rules: { - 'import/no-default-export': 'off', - // allow console logs in the website to help with debugging things in production - 'no-console': 'off', - }, - }, - { - files: ['./packages/website-eslint/src/mock/**/*.js', '*.d.ts'], - rules: { - // mocks and declaration files have to mirror their original package - 'import/no-default-export': 'off', - }, - }, - ], -}; diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 255a9a7bc38a..bed1f941a209 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -78,6 +78,11 @@ matchPackagePrefixes: ['@types/jest', 'jest', '@jest'], groupName: 'jest', }, + { + matchPackageNames: ['eslint'], + matchPackagePrefixes: ['@eslint'], + groupName: 'eslint', + }, ], postUpdateOptions: [ // run yarn dedupe to cleanup the lockfile after updates diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9951a2cc4bcd..922e4fda6c6c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,6 +113,8 @@ jobs: - name: Run Check run: yarn ${{ matrix.lint-task }} + env: + ESLINT_USE_FLAT_CONFIG: true stylelint: name: Stylelint diff --git a/.vscode/settings.json b/.vscode/settings.json index 896fbaebbb3a..ac5f882cbc0e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,8 @@ "typescript", "typescriptreact" ], + // required to make the extension pickup the flat config + "eslint.experimental.useFlatConfig": true, // When enabled, will trim trailing whitespace when saving a file. "files.trimTrailingWhitespace": true, diff --git a/docs/packages/Core.mdx b/docs/packages/Core.mdx new file mode 100644 index 000000000000..d20d5dcd33df --- /dev/null +++ b/docs/packages/Core.mdx @@ -0,0 +1,12 @@ +--- +id: core +sidebar_label: core +--- + +# `@typescript-eslint/core` + +> Tooling which enables you to use TypeScript with ESLint + +This package is the main entrypoint that you can use to consume our tooling with ESLint. + +// TODO(bradzacher) - docs on using the tooling diff --git a/docs/packages/Parser.mdx b/docs/packages/Parser.mdx index 5d5860493103..35f61e0d8a69 100644 --- a/docs/packages/Parser.mdx +++ b/docs/packages/Parser.mdx @@ -45,8 +45,8 @@ interface ParserOptions { jsxFragmentName?: string | null; jsxPragma?: string | null; lib?: string[]; - programs?: import('typescript').Program; - project?: string | string[] | true; + programs?: import('typescript').Program[]; + project?: string | string[] | true | boolean | null; projectFolderIgnoreList?: string[]; tsconfigRootDir?: string; warnOnUnsupportedTypeScriptVersion?: boolean; @@ -212,13 +212,17 @@ This option allows you to provide a path to your project's `tsconfig.json`. **Th // array of paths and/or glob patterns project: ['./packages/**/tsconfig.json', './separate-package/tsconfig.json']; + + // ways to disable type-aware linting (useful for overrides configs) + project: false; + project: null; ``` - If `true`, each source file's parse will find the nearest `tsconfig.json` file to that source file. - This is done by checking that source file's directory tree for the nearest `tsconfig.json`. -- If you use project references, TypeScript will not automatically use project references to resolve files. This means that you will have to add each referenced tsconfig to the `project` field either separately, or via a glob. +- If you use project references, TypeScript will **not** automatically use project references to resolve files. This means that you will have to add each referenced tsconfig to the `project` field either separately, or via a glob. - Note that using wide globs `**` in your `parserOptions.project` may cause performance implications. Instead of globs that use `**` to recursively check all folders, prefer paths that use a single `*` at a time. For more info see [#2611](https://github.com/typescript-eslint/typescript-eslint/issues/2611). diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 000000000000..218cd0a70eb4 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,8 @@ +// @ts-check + +// TODO - https://github.com/eslint/eslint/pull/17909 +// either it gets back-ported (https://github.com/eslint/eslint/issues/17966) or we wait till v9 + +/** @type {import('@typescript-eslint/utils/ts-eslint').FlatConfig.ConfigPromise} */ +const config = (async () => (await import('./eslint.config.mjs')).default)(); +module.exports = config; diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000000..8ebb01f69537 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,533 @@ +// @ts-check + +import url from 'node:url'; + +import { FlatCompat } from '@eslint/eslintrc'; +import eslint from '@eslint/js'; +import tseslintInternalPlugin from '@typescript-eslint/eslint-plugin-internal'; +import deprecationPlugin from 'eslint-plugin-deprecation'; +import eslintCommentsPlugin from 'eslint-plugin-eslint-comments'; +import eslintPluginPlugin from 'eslint-plugin-eslint-plugin'; +import importPlugin from 'eslint-plugin-import'; +import jestPlugin from 'eslint-plugin-jest'; +import jsdocPlugin from 'eslint-plugin-jsdoc'; +import jsxA11yPlugin from 'eslint-plugin-jsx-a11y'; +import reactPlugin from 'eslint-plugin-react'; +import reactHooksPlugin from 'eslint-plugin-react-hooks'; +import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort'; +import unicornPlugin from 'eslint-plugin-unicorn'; +import globals from 'globals'; +import tseslint from 'typescript-eslint'; + +const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); +const compat = new FlatCompat({ baseDirectory: __dirname }); + +export default tseslint.config( + // register all of the plugins up-front + { + // note - intentionally uses computed syntax to make it easy to sort the keys + plugins: { + ['@typescript-eslint']: tseslint.plugin, + ['@typescript-eslint/internal']: tseslintInternalPlugin, + ['deprecation']: deprecationPlugin, + ['eslint-comments']: eslintCommentsPlugin, + ['eslint-plugin']: eslintPluginPlugin, + ['import']: importPlugin, + ['jest']: jestPlugin, + ['jsdoc']: jsdocPlugin, + ['jsx-a11y']: jsxA11yPlugin, + ['react-hooks']: reactHooksPlugin, + ['react']: reactPlugin, + ['simple-import-sort']: simpleImportSortPlugin, + ['unicorn']: unicornPlugin, + }, + }, + { + // config with just ignores is the replacement for `.eslintignore` + ignores: [ + '**/jest.config.js', + '**/node_modules/**', + '**/dist/**', + '**/fixtures/**', + '**/coverage/**', + '**/__snapshots__/**', + '**/.docusaurus/**', + '**/build/**', + // Files copied as part of the build + 'packages/types/src/generated/**/*.ts', + // Playground types downloaded from the web + 'packages/website/src/vendor', + // see the file header in eslint-base.test.js for more info + 'packages/rule-tester/tests/eslint-base', + ], + }, + + // extends ... + eslint.configs.recommended, + ...compat.config(eslintPluginPlugin.configs.recommended), + ...tseslint.configs.strictTypeChecked, + ...tseslint.configs.stylisticTypeChecked, + jsdocPlugin.configs['flat/recommended-typescript-error'], + + // base config + { + languageOptions: { + globals: { + ...globals.es2020, + ...globals.node, + }, + parserOptions: { + allowAutomaticSingleRunInference: true, + cacheLifetime: { + // we pretty well never create/change tsconfig structure - so no need to ever evict the cache + // in the rare case that we do - just need to manually restart their IDE. + glob: 'Infinity', + }, + sourceType: 'module', + project: [ + 'tsconfig.json', + 'packages/*/tsconfig.json', + /** + * We are currently in the process of transitioning to nx's out of the box structure and + * so need to manually specify converted packages' tsconfig.build.json and tsconfig.spec.json + * files here for now in addition to the tsconfig.json glob pattern. + * + * TODO(#4665): Clean this up once all packages have been transitioned. + */ + 'packages/scope-manager/tsconfig.build.json', + 'packages/scope-manager/tsconfig.spec.json', + ], + tsconfigRootDir: __dirname, + warnOnUnsupportedTypeScriptVersion: false, + }, + }, + rules: { + // make sure we're not leveraging any deprecated APIs + 'deprecation/deprecation': 'error', + + // TODO(#7130): Investigate changing these in or removing these from presets + '@typescript-eslint/no-confusing-void-expression': 'off', + '@typescript-eslint/prefer-string-starts-ends-with': 'off', + + // + // our plugin :D + // + + '@typescript-eslint/ban-ts-comment': [ + 'error', + { + 'ts-expect-error': 'allow-with-description', + 'ts-ignore': true, + 'ts-nocheck': true, + 'ts-check': false, + minimumDescriptionLength: 5, + }, + ], + '@typescript-eslint/consistent-type-imports': [ + 'error', + { prefer: 'type-imports', disallowTypeAnnotations: true }, + ], + '@typescript-eslint/explicit-function-return-type': [ + 'error', + { allowIIFEs: true }, + ], + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-non-null-assertion': 'off', + 'no-constant-condition': 'off', + '@typescript-eslint/no-unnecessary-condition': [ + 'error', + { allowConstantLoopConditions: true }, + ], + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/prefer-literal-enum-member': [ + 'error', + { + allowBitwiseExpressions: true, + }, + ], + '@typescript-eslint/unbound-method': 'off', + '@typescript-eslint/restrict-template-expressions': [ + 'error', + { + allowNumber: true, + allowBoolean: true, + allowAny: true, + allowNullish: true, + allowRegExp: true, + }, + ], + '@typescript-eslint/no-unused-vars': [ + 'error', + { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, + ], + '@typescript-eslint/prefer-nullish-coalescing': [ + 'error', + { + ignoreConditionalTests: true, + ignorePrimitives: true, + }, + ], + + // + // Internal repo rules + // + + '@typescript-eslint/internal/no-poorly-typed-ts-props': 'error', + '@typescript-eslint/internal/no-typescript-default-import': 'error', + '@typescript-eslint/internal/prefer-ast-types-enum': 'error', + + // + // eslint-base + // + + curly: ['error', 'all'], + eqeqeq: [ + 'error', + 'always', + { + null: 'never', + }, + ], + 'logical-assignment-operators': 'error', + 'no-else-return': 'error', + 'no-mixed-operators': 'error', + 'no-console': 'error', + 'no-process-exit': 'error', + 'no-fallthrough': [ + 'error', + { commentPattern: '.*intentional fallthrough.*' }, + ], + 'one-var': ['error', 'never'], + + // + // eslint-plugin-eslint-comment + // + + // require a eslint-enable comment for every eslint-disable comment + 'eslint-comments/disable-enable-pair': [ + 'error', + { + allowWholeFile: true, + }, + ], + // disallow a eslint-enable comment for multiple eslint-disable comments + 'eslint-comments/no-aggregating-enable': 'error', + // disallow duplicate eslint-disable comments + 'eslint-comments/no-duplicate-disable': 'error', + // disallow eslint-disable comments without rule names + 'eslint-comments/no-unlimited-disable': 'error', + // disallow unused eslint-disable comments + 'eslint-comments/no-unused-disable': 'error', + // disallow unused eslint-enable comments + 'eslint-comments/no-unused-enable': 'error', + // disallow ESLint directive-comments + 'eslint-comments/no-use': [ + 'error', + { + allow: [ + 'eslint-disable', + 'eslint-disable-line', + 'eslint-disable-next-line', + 'eslint-enable', + 'global', + ], + }, + ], + + // + // eslint-plugin-import + // + + // disallow non-import statements appearing before import statements + 'import/first': 'error', + // Require a newline after the last import/require in a group + 'import/newline-after-import': 'error', + // Forbid import of modules using absolute paths + 'import/no-absolute-path': 'error', + // disallow AMD require/define + 'import/no-amd': 'error', + // forbid default exports - we want to standardize on named exports so that imported names are consistent + 'import/no-default-export': 'error', + // disallow imports from duplicate paths + 'import/no-duplicates': 'error', + // Forbid the use of extraneous packages + 'import/no-extraneous-dependencies': [ + 'error', + { + devDependencies: true, + peerDependencies: true, + optionalDependencies: false, + }, + ], + // Forbid mutable exports + 'import/no-mutable-exports': 'error', + // Prevent importing the default as if it were named + 'import/no-named-default': 'error', + // Prohibit named exports + 'import/no-named-export': 'off', // we want everything to be a named export + // Forbid a module from importing itself + 'import/no-self-import': 'error', + // Require modules with a single export to use a default export + 'import/prefer-default-export': 'off', // we want everything to be named + + // enforce a sort order across the codebase + 'simple-import-sort/imports': 'error', + + // + // eslint-plugin-jsdoc + // + + // We often use @remarks or other ad-hoc tag names + 'jsdoc/check-tag-names': 'off', + // https://github.com/gajus/eslint-plugin-jsdoc/issues/1169 + 'jsdoc/check-param-names': 'off', + // https://github.com/gajus/eslint-plugin-jsdoc/issues/1175 + 'jsdoc/require-jsdoc': 'off', + 'jsdoc/require-param': 'off', + 'jsdoc/require-returns': 'off', + 'jsdoc/require-yields': 'off', + 'jsdoc/tag-lines': 'off', + + // + // eslint-plugin-unicorn + // + + 'unicorn/no-typeof-undefined': 'error', + }, + }, + { + files: ['**/*.js'], + extends: [tseslint.configs.disableTypeChecked], + rules: { + // turn off other type-aware rules + 'deprecation/deprecation': 'off', + '@typescript-eslint/internal/no-poorly-typed-ts-props': 'off', + + // turn off rules that don't apply to JS code + '@typescript-eslint/explicit-function-return-type': 'off', + }, + }, + + // + // test file linting + // + + // define the jest globals for all test files + { + files: ['packages/*/tests/**/*.{ts,tsx,cts,mts}'], + languageOptions: { + globals: { + ...jestPlugin.environments.globals.globals, + }, + }, + }, + // test file specific configuration + { + files: [ + 'packages/*/tests/**/*.spec.{ts,tsx,cts,mts}', + 'packages/*/tests/**/*.test.{ts,tsx,cts,mts}', + 'packages/*/tests/**/spec.{ts,tsx,cts,mts}', + 'packages/*/tests/**/test.{ts,tsx,cts,mts}', + 'packages/parser/tests/**/*.{ts,tsx,cts,mts}', + 'packages/integration-tests/tools/integration-test-base.{ts,tsx,cts,mts}', + 'packages/integration-tests/tools/pack-packages.{ts,tsx,cts,mts}', + ], + rules: { + '@typescript-eslint/no-empty-function': [ + 'error', + { allow: ['arrowFunctions'] }, + ], + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + 'eslint-plugin/consistent-output': 'off', // Might eventually be removed from `eslint-plugin/recommended`: https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/284 + 'jest/no-disabled-tests': 'error', + 'jest/no-focused-tests': 'error', + 'jest/no-alias-methods': 'error', + 'jest/no-identical-title': 'error', + 'jest/no-jasmine-globals': 'error', + 'jest/no-test-prefixes': 'error', + 'jest/no-done-callback': 'error', + 'jest/no-test-return-statement': 'error', + 'jest/prefer-to-be': 'error', + 'jest/prefer-to-contain': 'error', + 'jest/prefer-to-have-length': 'error', + 'jest/prefer-spy-on': 'error', + 'jest/valid-expect': 'error', + 'jest/no-deprecated-functions': 'error', + }, + }, + // plugin rule tests + { + files: [ + 'packages/eslint-plugin-internal/tests/rules/**/*.test.{ts,tsx,cts,mts}', + 'packages/eslint-plugin-tslint/tests/rules/**/*.test.{ts,tsx,cts,mts}', + 'packages/eslint-plugin/tests/rules/**/*.test.{ts,tsx,cts,mts}', + 'packages/eslint-plugin/tests/eslint-rules/**/*.test.{ts,tsx,cts,mts}', + ], + rules: { + '@typescript-eslint/internal/plugin-test-formatting': 'error', + }, + }, + + // + // tools and tests + // + { + files: [ + '**/tools/**/*.{ts,tsx,cts,mts}', + '**/tests/**/*.{ts,tsx,cts,mts}', + 'packages/repo-tools/**/*.{ts,tsx,cts,mts}', + 'packages/integration-tests/**/*.{ts,tsx,cts,mts}', + ], + rules: { + // allow console logs in tools and tests + 'no-console': 'off', + }, + }, + { + files: ['eslint.config.{js,cjs,mjs}'], + rules: { + // requirement + 'import/no-default-export': 'off', + }, + }, + + // + // plugin source file linting + // + + { + files: [ + 'packages/eslint-plugin-internal/**/*.{ts,tsx,cts,mts}', + 'packages/eslint-plugin-tslint/**/*.{ts,tsx,cts,mts}', + 'packages/eslint-plugin/**/*.{ts,tsx,cts,mts}', + ], + rules: { + '@typescript-eslint/internal/no-typescript-estree-import': 'error', + }, + }, + { + files: [ + 'packages/eslint-plugin-internal/src/rules/**/*.{ts,tsx,cts,mts}', + 'packages/eslint-plugin-tslint/src/rules/**/*.{ts,tsx,cts,mts}', + 'packages/eslint-plugin/src/configs/**/*.{ts,tsx,cts,mts}', + 'packages/core/src/configs/**/*.{ts,tsx,cts,mts}', + 'packages/eslint-plugin/src/rules/**/*.{ts,tsx,cts,mts}', + ], + rules: { + 'eslint-plugin/require-meta-docs-description': [ + 'error', + { pattern: '^(Enforce|Require|Disallow) .+[^. ]$' }, + ], + + // specifically for rules - default exports makes the tooling easier + 'import/no-default-export': 'off', + + 'no-restricted-syntax': [ + 'error', + { + selector: + 'ExportDefaultDeclaration Property[key.name="create"] MemberExpression[object.name="context"][property.name="options"]', + message: + "Retrieve options from create's second parameter so that defaultOptions are applied.", + }, + ], + }, + }, + { + files: ['packages/eslint-plugin/src/rules/index.ts'], + rules: { + // enforce alphabetical ordering + 'sort-keys': 'error', + 'import/order': ['error', { alphabetize: { order: 'asc' } }], + }, + }, + + // + // generated files + // + + { + files: [ + 'packages/scope-manager/src/lib/*.{ts,tsx,cts,mts}', + 'packages/eslint-plugin/src/configs/*.{ts,tsx,cts,mts}', + 'packages/core/src/configs/*.{ts,tsx,cts,mts}', + ], + rules: { + '@typescript-eslint/internal/no-poorly-typed-ts-props': 'off', + '@typescript-eslint/internal/no-typescript-default-import': 'off', + '@typescript-eslint/internal/prefer-ast-types-enum': 'off', + }, + }, + + // + // ast spec linting + // + + { + files: ['packages/ast-spec/src/**/*.{ts,tsx,cts,mts}'], + rules: { + // disallow ALL unused vars + '@typescript-eslint/no-unused-vars': 'error', + '@typescript-eslint/sort-type-constituents': 'error', + }, + }, + { + files: ['packages/ast-spec/**/*.{ts,tsx,cts,mts}'], + rules: { + 'no-restricted-imports': [ + 'error', + { + name: '@typescript-eslint/typescript-estree', + message: + 'To prevent nx build errors, all `typescript-estree` imports should be done via `packages/ast-spec/tests/util/parsers/typescript-estree-import.ts`.', + }, + ], + }, + }, + + // + // website linting + // + + { + files: ['packages/website/**/*.{ts,tsx,mts,cts,js,jsx}'], + extends: [ + ...compat.config(jsxA11yPlugin.configs.recommended), + ...compat.config(reactPlugin.configs.recommended), + ...compat.config(reactHooksPlugin.configs.recommended), + ], + rules: { + '@typescript-eslint/internal/prefer-ast-types-enum': 'off', + 'import/no-default-export': 'off', + 'react/jsx-no-target-blank': 'off', + 'react/no-unescaped-entities': 'off', + 'react-hooks/exhaustive-deps': 'warn', // TODO: enable it later + }, + settings: { + react: { + version: 'detect', + }, + }, + }, + { + files: ['packages/website/src/**/*.{ts,tsx,cts,mts}'], + rules: { + 'import/no-default-export': 'off', + // allow console logs in the website to help with debugging things in production + 'no-console': 'off', + }, + }, + { + files: [ + 'packages/website-eslint/src/mock/**/*.js', + '**/*.d.{ts,tsx,cts,mts}', + ], + rules: { + // mocks and declaration files have to mirror their original package + 'import/no-default-export': 'off', + }, + }, +); diff --git a/nx.json b/nx.json index d85a0833983e..c4db4f4af512 100644 --- a/nx.json +++ b/nx.json @@ -38,10 +38,10 @@ "cache": true }, "lint": { - "dependsOn": ["eslint-plugin:build"], + "dependsOn": ["eslint-plugin:build", "parser:build", "core:build"], "inputs": [ "default", - "{workspaceRoot}/.eslintrc.js", + "{workspaceRoot}/eslint.config.js", "{workspaceRoot}/yarn.lock", "{workspaceRoot}/.eslintignore", { diff --git a/package.json b/package.json index a684e231281c..757e765a2600 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "clean": "nx run-many --target=clean", "format": "prettier --write .", "generate-breaking-changes": "npx nx run eslint-plugin:generate-breaking-changes", - "generate-configs": "npx nx run eslint-plugin:generate:configs", + "generate-configs": "npx nx run repo-tools:generate-configs", "generate-contributors": "npx nx run repo-tools:generate-contributors", "generate-sponsors": "npx nx run repo-tools:generate-sponsors", "generate-website-dts": "npx nx run website:generate-website-dts", @@ -60,6 +60,8 @@ "@babel/eslint-parser": "^7.23.3", "@babel/parser": "^7.23.3", "@babel/types": "^7.23.3", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "^8.56.0", "@nx/eslint": "17.2.8", "@nx/jest": "17.2.8", "@nx/workspace": "17.2.8", @@ -79,12 +81,13 @@ "@types/semver": "^7.5.0", "@types/tmp": "^0.2.3", "@types/yargs": "^17.0.32", - "@typescript-eslint/eslint-plugin-internal": "workspace:packages/eslint-plugin-internal", + "@typescript-eslint/eslint-plugin-internal": "workspace:^", "console-fail-test": "^0.2.3", + "cross-env": "^7.0.3", "cross-fetch": "^4.0.0", "cspell": "^7.0.0", "downlevel-dts": ">=0.11.0", - "eslint": "^8.47.0", + "eslint": "^8.56.0", "eslint-plugin-deprecation": "^2.0.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-eslint-plugin": "^5.1.0", @@ -98,6 +101,7 @@ "eslint-plugin-unicorn": "^48.0.1", "execa": "7.1.1", "glob": "^10.3.3", + "globals": "^13.23.0", "husky": "^8.0.3", "jest": "29.7.0", "jest-diff": "^29.6.2", diff --git a/packages/ast-spec/project.json b/packages/ast-spec/project.json index 1771bfa7b55e..0076bc880318 100644 --- a/packages/ast-spec/project.json +++ b/packages/ast-spec/project.json @@ -14,10 +14,7 @@ }, "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/eslint-plugin-internal/index.d.ts b/packages/eslint-plugin-internal/index.d.ts new file mode 100644 index 000000000000..8c2962c75da3 --- /dev/null +++ b/packages/eslint-plugin-internal/index.d.ts @@ -0,0 +1,9 @@ +import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'; + +import type rules from './rules'; + +declare const cjsExport: { + meta: FlatConfig.PluginMeta; + rules: typeof rules; +}; +export = cjsExport; diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index 06347f372c2c..cf4f38a90d77 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -3,6 +3,7 @@ "version": "6.20.0", "private": true, "main": "dist/index.js", + "types": "index.d.ts", "scripts": { "build": "tsc -b tsconfig.build.json", "clean": "tsc -b tsconfig.build.json --clean", diff --git a/packages/eslint-plugin-internal/project.json b/packages/eslint-plugin-internal/project.json index 235431ed3ce5..36836344938c 100644 --- a/packages/eslint-plugin-internal/project.json +++ b/packages/eslint-plugin-internal/project.json @@ -6,10 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/eslint-plugin-internal/src/index.ts b/packages/eslint-plugin-internal/src/index.ts index 0802acef98a8..cb15326b4dfe 100644 --- a/packages/eslint-plugin-internal/src/index.ts +++ b/packages/eslint-plugin-internal/src/index.ts @@ -1,5 +1,15 @@ import rules from './rules'; +// note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder +const { name, version } = require('../package.json') as { + name: string; + version: string; +}; + export = { rules, + meta: { + name, + version, + }, }; diff --git a/packages/eslint-plugin-internal/tsconfig.json b/packages/eslint-plugin-internal/tsconfig.json index cc78ba59388e..83713e5c8bf0 100644 --- a/packages/eslint-plugin-internal/tsconfig.json +++ b/packages/eslint-plugin-internal/tsconfig.json @@ -5,6 +5,6 @@ "target": "ES2022", "rootDir": "." }, - "include": ["src", "typings", "tests"], + "include": ["src", "typings", "tests", "index.d.ts"], "references": [{ "path": "../utils/tsconfig.build.json" }] } diff --git a/packages/eslint-plugin-tslint/project.json b/packages/eslint-plugin-tslint/project.json index ed97991ef7ae..dc5d5b11a632 100644 --- a/packages/eslint-plugin-tslint/project.json +++ b/packages/eslint-plugin-tslint/project.json @@ -6,10 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/eslint-plugin/eslint-recommended-raw.d.ts b/packages/eslint-plugin/eslint-recommended-raw.d.ts new file mode 100644 index 000000000000..da4a8496b4f3 --- /dev/null +++ b/packages/eslint-plugin/eslint-recommended-raw.d.ts @@ -0,0 +1,5 @@ +declare const config: (style: 'glob' | 'minimatch') => { + files: string[]; + rules: Record; +}; +export default config; diff --git a/packages/eslint-plugin/index.d.ts b/packages/eslint-plugin/index.d.ts index 30f22e9b09ef..756a025eb97d 100644 --- a/packages/eslint-plugin/index.d.ts +++ b/packages/eslint-plugin/index.d.ts @@ -1,9 +1,13 @@ -import type { ClassicConfig } from '@typescript-eslint/utils/ts-eslint'; +import type { + ClassicConfig, + FlatConfig, +} from '@typescript-eslint/utils/ts-eslint'; import type rules from './rules'; declare const cjsExport: { configs: Record; + meta: FlatConfig.PluginMeta; rules: typeof rules; }; export = cjsExport; diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index c10641310051..1dce853e378b 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -21,6 +21,10 @@ "./use-at-your-own-risk/rules": { "types": "./rules.d.ts", "default": "./dist/rules/index.js" + }, + "./use-at-your-own-risk/eslint-recommended-raw": { + "types": "./eslint-recommended-raw.d.ts", + "default": "./dist/configs/eslint-recommended-raw.js" } }, "engines": { @@ -49,7 +53,7 @@ "postclean": "rimraf dist && rimraf coverage", "format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore", "generate:breaking-changes": "yarn tsx tools/generate-breaking-changes.mts", - "generate:configs": "yarn tsx tools/generate-configs.ts", + "generate:configs": "npx nx run repo-tools:generate-configs", "lint": "npx nx lint", "test": "jest --coverage --logHeapUsage", "test-single": "jest --no-coverage", diff --git a/packages/eslint-plugin/project.json b/packages/eslint-plugin/project.json index a4967a65143c..56e47529dd19 100644 --- a/packages/eslint-plugin/project.json +++ b/packages/eslint-plugin/project.json @@ -6,10 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/eslint-plugin/rules.d.ts b/packages/eslint-plugin/rules.d.ts index 1778ba33ca75..71745fe4ef77 100644 --- a/packages/eslint-plugin/rules.d.ts +++ b/packages/eslint-plugin/rules.d.ts @@ -42,4 +42,5 @@ export type TypeScriptESLintRules = Record< RuleModule >; declare const rules: TypeScriptESLintRules; +// eslint-disable-next-line import/no-default-export export default rules; diff --git a/packages/eslint-plugin/src/configs/base.ts b/packages/eslint-plugin/src/configs/base.ts index 628ed42b760c..652bf9db1eea 100644 --- a/packages/eslint-plugin/src/configs/base.ts +++ b/packages/eslint-plugin/src/configs/base.ts @@ -1,10 +1,3 @@ -// THIS CODE WAS AUTOMATICALLY GENERATED -// DO NOT EDIT THIS CODE BY HAND -// SEE https://typescript-eslint.io/linting/configs -// -// For developers working in the typescript-eslint monorepo: -// You can regenerate it using `yarn generate:configs` - export = { parser: '@typescript-eslint/parser', parserOptions: { sourceType: 'module' }, diff --git a/packages/eslint-plugin/src/configs/disable-type-checked.ts b/packages/eslint-plugin/src/configs/disable-type-checked.ts index 4cd82bf2414e..ef30de7f2d3d 100644 --- a/packages/eslint-plugin/src/configs/disable-type-checked.ts +++ b/packages/eslint-plugin/src/configs/disable-type-checked.ts @@ -6,7 +6,7 @@ // You can regenerate it using `yarn generate:configs` export = { - parserOptions: { project: null, program: null }, + parserOptions: { project: false, program: null }, rules: { '@typescript-eslint/await-thenable': 'off', '@typescript-eslint/consistent-type-exports': 'off', diff --git a/packages/eslint-plugin/src/configs/eslint-recommended-raw.ts b/packages/eslint-plugin/src/configs/eslint-recommended-raw.ts new file mode 100644 index 000000000000..aafff1c61c19 --- /dev/null +++ b/packages/eslint-plugin/src/configs/eslint-recommended-raw.ts @@ -0,0 +1,44 @@ +// NOTE: this file is isolated to be shared across legacy and flat configs +// it is exported via `./use-at-your-own-risk/eslint-recommended-raw` +// and it has types manually defined in `./eslint-recommended-raw.d.ts` + +/** + * This is a compatibility ruleset that: + * - disables rules from eslint:recommended which are already handled by TypeScript. + * - enables rules that make sense due to TS's typechecking / transpilation. + */ +export default ( + style: 'glob' | 'minimatch', +): { + files: string[]; + rules: Record; +} => ({ + files: + style === 'glob' + ? // classic configs use glob syntax + ['*.ts', '*.tsx', '*.mts', '*.cts'] + : // flat configs use minimatch syntax + ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts'], + rules: { + 'constructor-super': 'off', // ts(2335) & ts(2377) + 'getter-return': 'off', // ts(2378) + 'no-const-assign': 'off', // ts(2588) + 'no-dupe-args': 'off', // ts(2300) + 'no-dupe-class-members': 'off', // ts(2393) & ts(2300) + 'no-dupe-keys': 'off', // ts(1117) + 'no-func-assign': 'off', // ts(2630) + 'no-import-assign': 'off', // ts(2632) & ts(2540) + 'no-new-symbol': 'off', // ts(7009) + 'no-obj-calls': 'off', // ts(2349) + 'no-redeclare': 'off', // ts(2451) + 'no-setter-return': 'off', // ts(2408) + 'no-this-before-super': 'off', // ts(2376) & ts(17009) + 'no-undef': 'off', // ts(2304) & ts(2552) + 'no-unreachable': 'off', // ts(7027) + 'no-unsafe-negation': 'off', // ts(2365) & ts(2322) & ts(2358) + 'no-var': 'error', // ts transpiles let/const to var, so no need for vars any more + 'prefer-const': 'error', // ts provides better types with const + 'prefer-rest-params': 'error', // ts provides better types with rest args over arguments + 'prefer-spread': 'error', // ts transpiles spread to apply, so no need for manual apply + }, +}); diff --git a/packages/eslint-plugin/src/configs/eslint-recommended.ts b/packages/eslint-plugin/src/configs/eslint-recommended.ts index a1cdae8759d2..643105047421 100644 --- a/packages/eslint-plugin/src/configs/eslint-recommended.ts +++ b/packages/eslint-plugin/src/configs/eslint-recommended.ts @@ -1,34 +1,10 @@ +import eslintRecommended_raw from './eslint-recommended-raw'; + /** * This is a compatibility ruleset that: * - disables rules from eslint:recommended which are already handled by TypeScript. * - enables rules that make sense due to TS's typechecking / transpilation. */ export = { - overrides: [ - { - files: ['*.ts', '*.tsx', '*.mts', '*.cts'], - rules: { - 'constructor-super': 'off', // ts(2335) & ts(2377) - 'getter-return': 'off', // ts(2378) - 'no-const-assign': 'off', // ts(2588) - 'no-dupe-args': 'off', // ts(2300) - 'no-dupe-class-members': 'off', // ts(2393) & ts(2300) - 'no-dupe-keys': 'off', // ts(1117) - 'no-func-assign': 'off', // ts(2630) - 'no-import-assign': 'off', // ts(2632) & ts(2540) - 'no-new-symbol': 'off', // ts(7009) - 'no-obj-calls': 'off', // ts(2349) - 'no-redeclare': 'off', // ts(2451) - 'no-setter-return': 'off', // ts(2408) - 'no-this-before-super': 'off', // ts(2376) & ts(17009) - 'no-undef': 'off', // ts(2304) & ts(2552) - 'no-unreachable': 'off', // ts(7027) - 'no-unsafe-negation': 'off', // ts(2365) & ts(2322) & ts(2358) - 'no-var': 'error', // ts transpiles let/const to var, so no need for vars any more - 'prefer-const': 'error', // ts provides better types with const - 'prefer-rest-params': 'error', // ts provides better types with rest args over arguments - 'prefer-spread': 'error', // ts transpiles spread to apply, so no need for manual apply - }, - }, - ], + overrides: [eslintRecommended_raw('glob')], }; diff --git a/packages/eslint-plugin/src/index.ts b/packages/eslint-plugin/src/index.ts index ece2bb0a20fc..40f159cb0e41 100644 --- a/packages/eslint-plugin/src/index.ts +++ b/packages/eslint-plugin/src/index.ts @@ -10,6 +10,12 @@ import stylistic from './configs/stylistic'; import stylisticTypeChecked from './configs/stylistic-type-checked'; import rules from './rules'; +// note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder +const { name, version } = require('../package.json') as { + name: string; + version: string; +}; + export = { configs: { all, @@ -25,5 +31,9 @@ export = { stylistic, 'stylistic-type-checked': stylisticTypeChecked, }, + meta: { + name, + version, + }, rules, }; diff --git a/packages/eslint-plugin/tests/schema-snapshots/lines-between-class-members.shot b/packages/eslint-plugin/tests/schema-snapshots/lines-between-class-members.shot index 9e8924e05e83..00566333498a 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/lines-between-class-members.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/lines-between-class-members.shot @@ -6,7 +6,38 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos [ { - "enum": ["always", "never"] + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "enforce": { + "items": { + "additionalProperties": false, + "properties": { + "blankLine": { + "enum": ["always", "never"] + }, + "next": { + "enum": ["*", "field", "method"] + }, + "prev": { + "enum": ["*", "field", "method"] + } + }, + "required": ["blankLine", "prev", "next"], + "type": "object" + }, + "minItems": 1, + "type": "array" + } + }, + "required": ["enforce"], + "type": "object" + }, + { + "enum": ["always", "never"] + } + ] }, { "additionalProperties": false, @@ -28,7 +59,24 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos # TYPES: type Options = [ - 'always' | 'never', + ( + | 'always' + | 'never' + | { + enforce: [ + { + blankLine: 'always' | 'never'; + next: '*' | 'field' | 'method'; + prev: '*' | 'field' | 'method'; + }, + ...{ + blankLine: 'always' | 'never'; + next: '*' | 'field' | 'method'; + prev: '*' | 'field' | 'method'; + }[], + ]; + } + ), { exceptAfterOverload?: boolean; exceptAfterSingleLine?: boolean; diff --git a/packages/eslint-plugin/tests/schema-snapshots/no-restricted-imports.shot b/packages/eslint-plugin/tests/schema-snapshots/no-restricted-imports.shot index e41e144b41c9..1fbe61748f34 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/no-restricted-imports.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/no-restricted-imports.shot @@ -110,6 +110,9 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "type": "array", "uniqueItems": true }, + "importNamePattern": { + "type": "string" + }, "importNames": { "items": { "type": "string" @@ -173,6 +176,7 @@ type Options = allowTypeImports?: boolean; caseSensitive?: boolean; group: [string, ...string[]]; + importNamePattern?: string; importNames?: [string, ...string[]]; message?: string; }[] diff --git a/packages/integration-tests/project.json b/packages/integration-tests/project.json index 262793adf20f..0299e92d157c 100644 --- a/packages/integration-tests/project.json +++ b/packages/integration-tests/project.json @@ -6,10 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/parser/project.json b/packages/parser/project.json index a0ee6fe12177..94b5289ff17e 100644 --- a/packages/parser/project.json +++ b/packages/parser/project.json @@ -6,10 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/parser/src/parser.ts b/packages/parser/src/parser.ts index 8577dd61bccd..17c5a2ff61b9 100644 --- a/packages/parser/src/parser.ts +++ b/packages/parser/src/parser.ts @@ -10,6 +10,7 @@ import type { TSESTreeOptions, } from '@typescript-eslint/typescript-estree'; import { parseAndGenerateServices } from '@typescript-eslint/typescript-estree'; +import type { VisitorKeys } from '@typescript-eslint/visitor-keys'; import { visitorKeys } from '@typescript-eslint/visitor-keys'; import debug from 'debug'; import type * as ts from 'typescript'; @@ -24,7 +25,7 @@ interface ParseForESLintResult { comments?: TSESTree.Comment[]; }; services: ParserServices; - visitorKeys: typeof visitorKeys; + visitorKeys: VisitorKeys; scopeManager: ScopeManager; } diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index e791791d6d9b..dc5a7affedbf 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -6,9 +6,10 @@ "//": "NOTE: intentionally no build step in this package", "apply-canary-version": "tsx ./src/apply-canary-version.mts", "format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore", - "generate-contributors": "tsx ./src/generate-contributors.ts", - "generate-sponsors": "tsx ./src/generate-sponsors.ts", - "generate-lib": "tsx ./src/generate-lib.ts", + "generate-configs": "tsx ./src/generate-configs.mts", + "generate-contributors": "tsx ./src/generate-contributors.mts", + "generate-sponsors": "tsx ./src/generate-sponsors.mts", + "generate-lib": "tsx ./src/generate-lib.mts", "lint": "npx nx lint", "postinstall-script": "tsx ./src/postinstall.mts", "test": "jest --coverage", @@ -17,6 +18,7 @@ "devDependencies": { "@nx/devkit": "*", "@prettier/sync": "*", + "cross-env": "*", "cross-fetch": "*", "execa": "*", "prettier": "^3.0.3", diff --git a/packages/repo-tools/project.json b/packages/repo-tools/project.json index 911b3bd5b194..e90305a75938 100644 --- a/packages/repo-tools/project.json +++ b/packages/repo-tools/project.json @@ -6,10 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/eslint-plugin/tools/generate-configs.ts b/packages/repo-tools/src/generate-configs.mts similarity index 60% rename from packages/eslint-plugin/tools/generate-configs.ts rename to packages/repo-tools/src/generate-configs.mts index fb60d86449b9..e06cf8e205ea 100644 --- a/packages/eslint-plugin/tools/generate-configs.ts +++ b/packages/repo-tools/src/generate-configs.mts @@ -1,15 +1,17 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +import eslintPlugin from '@typescript-eslint/eslint-plugin'; import type { ClassicConfig, + FlatConfig, Linter, RuleModule, RuleRecommendation, } from '@typescript-eslint/utils/ts-eslint'; -import * as fs from 'fs'; -import * as path from 'path'; import prettier from 'prettier'; -import * as url from 'url'; -import type RulesFile from '../src/rules'; +import { PACKAGES_CORE, PACKAGES_ESLINT_PLUGIN, REPO_ROOT } from './paths.mts'; // no need for us to bring in an entire dependency for a few simple terminal colors const chalk = { @@ -20,37 +22,38 @@ const chalk = { gray: (val: string): string => `\x1B[90m${val}\x1B[39m`, }; -interface RulesObject { - default: { - default: typeof RulesFile; - }; -} +const AUTO_GENERATED_COMMENT_LINES = [ + '// THIS CODE WAS AUTOMATICALLY GENERATED', + '// DO NOT EDIT THIS CODE BY HAND', + '// SEE https://typescript-eslint.io/linting/configs', + '//', + '// For developers working in the typescript-eslint monorepo:', + '// You can regenerate it using `yarn generate:configs`', + '', +] as const; + +const EXTENDS_MODULES = [ + { + name: 'baseConfig', + packageRelativePath: './configs/base', + moduleRelativePath: './base', + }, + { + name: 'eslintRecommendedConfig', + packageRelativePath: './configs/eslint-recommended', + moduleRelativePath: './eslint-recommended', + }, +] as const; +const CLASSIC_EXTENDS: readonly string[] = EXTENDS_MODULES.map( + mod => mod.packageRelativePath, +); async function main(): Promise { - // TODO: Standardize & simplify these tools/* scripts once v6 is more stable - // @ts-expect-error -- ts-node allows us to use import.meta - const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); - - const { - default: { default: rules }, - } = - // @ts-expect-error -- We don't support ESM imports of local code yet. - (await import('../dist/rules/index.js')) as RulesObject; - - function addAutoGeneratedComment(code: string): string { - return [ - '// THIS CODE WAS AUTOMATICALLY GENERATED', - '// DO NOT EDIT THIS CODE BY HAND', - '// SEE https://typescript-eslint.io/linting/configs', - '//', - '// For developers working in the typescript-eslint monorepo:', - '// You can regenerate it using `yarn generate:configs`', - '', - code, - ].join('\n'); + function addAutoGeneratedComment(code?: string): string { + return [...AUTO_GENERATED_COMMENT_LINES, code].join('\n'); } - const prettierConfig = await prettier.resolveConfig(__dirname); + const prettierConfig = await prettier.resolveConfig(REPO_ROOT); type LinterConfigRules = Record; @@ -60,12 +63,12 @@ async function main(): Promise { } const RULE_NAME_PREFIX = '@typescript-eslint/'; - const MAX_RULE_NAME_LENGTH = Object.keys(rules).reduce( + const MAX_RULE_NAME_LENGTH = Object.keys(eslintPlugin.rules).reduce( (acc, name) => Math.max(acc, name.length), 0, ); const BASE_RULES_TO_BE_OVERRIDDEN = new Map( - Object.entries(rules) + Object.entries(eslintPlugin.rules) .filter(([, rule]) => rule.meta.docs?.extendsBaseRule) .map( ([ruleName, rule]) => @@ -77,12 +80,11 @@ async function main(): Promise { ] as const, ), ); - const EXTENDS = ['./configs/base', './configs/eslint-recommended']; type RuleEntry = [string, RuleModule]; - const allRuleEntries: RuleEntry[] = Object.entries(rules).sort((a, b) => - a[0].localeCompare(b[0]), + const allRuleEntries: RuleEntry[] = Object.entries(eslintPlugin.rules).sort( + (a, b) => a[0].localeCompare(b[0]), ); interface RuleFilter { @@ -155,34 +157,97 @@ async function main(): Promise { const hyphens = '-'.repeat(35 - Math.ceil(name.length / 2)); console.log(chalk.blueBright(`\n${hyphens} ${name}.ts ${hyphens}`)); + const config = getConfig(); + + // + // 1. Classic Config - written to the eslint-plugin package + // These configs are just JSON blobs that we write as TS files + // + // note: we use `export =` because ESLint will import these configs via a commonjs import - const code = `export = ${JSON.stringify(getConfig())};`; - const configStr = await prettier.format(addAutoGeneratedComment(code), { + const classicCode = `export = ${JSON.stringify(config)};`; + const classicConfigStr = await prettier.format( + addAutoGeneratedComment(classicCode), + { + parser: 'typescript', + ...prettierConfig, + }, + ); + fs.writeFileSync( + path.join(PACKAGES_ESLINT_PLUGIN, 'src', 'configs', `${name}.ts`), + classicConfigStr, + ); + + // + // 2. Flat Config - written to the core package + // These configs are actual TS modules that import other configs + // + const flatCode: string[] = [ + ...AUTO_GENERATED_COMMENT_LINES, + "import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint';", + '', + ]; + const flatExtends: string[] = []; + const flatConfig: FlatConfig.Config = { + rules: config.rules, + }; + if (config.extends) { + for (const extendPath of config.extends) { + const config = EXTENDS_MODULES.find( + mod => mod.packageRelativePath === extendPath, + ); + if (config == null) { + throw new Error("Couldn't find config"); + } + flatCode.push( + `import ${config.name} from '${config.moduleRelativePath}';`, + ); + flatExtends.push(config.name); + } + flatCode.push(''); + } + if (config.parserOptions) { + flatConfig.languageOptions ??= {}; + flatConfig.languageOptions.parserOptions = config.parserOptions; + } + + const flatConfigJson = JSON.stringify(flatConfig); + if (flatExtends.length > 0) { + flatCode.push( + 'export default (plugin: FlatConfig.Plugin, parser: FlatConfig.Parser): FlatConfig.ConfigArray => [', + ...flatExtends.map(ext => `${ext}(plugin, parser),`), + flatConfigJson, + '];', + ); + } else { + flatCode.push( + `export default (_plugin: FlatConfig.Plugin, _parser: FlatConfig.Parser): FlatConfig.Config => (${flatConfigJson});`, + ); + } + const flatConfigStr = await prettier.format(flatCode.join('\n'), { parser: 'typescript', ...prettierConfig, }); fs.writeFileSync( - path.resolve(__dirname, `../src/configs/${name}.ts`), - configStr, + path.join(PACKAGES_CORE, 'src', 'configs', `${name}.ts`), + flatConfigStr, ); } interface ExtendedConfigSettings { - extraExtends?: readonly string[]; name: string; filters?: RuleFilter; ruleEntries: readonly RuleEntry[]; } async function writeExtendedConfig({ - extraExtends = [], filters: ruleFilter, name, ruleEntries, }: ExtendedConfigSettings): Promise { await writeConfig( () => ({ - extends: [...EXTENDS, ...extraExtends], + extends: [...CLASSIC_EXTENDS], rules: ruleEntries.reduce( (config, entry) => reducer(config, entry, ruleFilter), {}, @@ -200,28 +265,6 @@ async function main(): Promise { ); } - await writeConfig((): LinterConfig => { - const baseConfig: LinterConfig = { - parser: '@typescript-eslint/parser', - parserOptions: { - sourceType: 'module', - }, - plugins: ['@typescript-eslint'], - }; - - console.log(chalk.gray('Config values:')); - - const longestKey = Object.keys(baseConfig).reduce( - (previous, next) => Math.max(previous, next.length), - 0, - ); - for (const [key, value] of Object.entries(baseConfig)) { - console.log(' ', key.padEnd(longestKey), value); - } - - return baseConfig; - }, 'base'); - await writeExtendedConfig({ name: 'all', filters: { @@ -272,7 +315,7 @@ async function main(): Promise { await writeConfig( () => ({ parserOptions: { - project: null, + project: false, program: null, }, rules: allRuleEntries.reduce( diff --git a/packages/repo-tools/src/generate-contributors.ts b/packages/repo-tools/src/generate-contributors.mts similarity index 96% rename from packages/repo-tools/src/generate-contributors.ts rename to packages/repo-tools/src/generate-contributors.mts index 92300d17ba1b..db9d72550c52 100644 --- a/packages/repo-tools/src/generate-contributors.ts +++ b/packages/repo-tools/src/generate-contributors.mts @@ -2,9 +2,12 @@ // https://developer.github.com/v3/repos/#list-contributors // this endpoint returns a list of contributors sorted by number of contributions +import fs from 'node:fs'; +import path from 'node:path'; + import fetch from 'cross-fetch'; -import * as fs from 'fs'; -import * as path from 'path'; + +import { REPO_ROOT } from './paths.mts'; const IGNORED_USERS = new Set([ 'dependabot[bot]', @@ -130,10 +133,7 @@ function writeTable(contributors: User[], perLine = 5): void { ); lines.push(''); - fs.writeFileSync( - path.join(__dirname, '../../../CONTRIBUTORS.md'), - lines.join('\n'), - ); + fs.writeFileSync(path.join(REPO_ROOT, 'CONTRIBUTORS.md'), lines.join('\n')); } async function main(): Promise { diff --git a/packages/repo-tools/src/generate-lib.ts b/packages/repo-tools/src/generate-lib.mts similarity index 95% rename from packages/repo-tools/src/generate-lib.ts rename to packages/repo-tools/src/generate-lib.mts index c9a0a722a02c..9f4bf761bf6f 100644 --- a/packages/repo-tools/src/generate-lib.ts +++ b/packages/repo-tools/src/generate-lib.mts @@ -1,3 +1,6 @@ +import fs from 'node:fs'; +import path from 'node:path'; + import prettier from '@prettier/sync'; import type { AnalyzeOptions, @@ -10,11 +13,11 @@ import { AST_TOKEN_TYPES } from '@typescript-eslint/types'; import type { TSESTreeOptions } from '@typescript-eslint/typescript-estree'; import { parse } from '@typescript-eslint/typescript-estree'; import { ESLint } from '@typescript-eslint/utils/ts-eslint'; -import * as fs from 'fs'; -import * as path from 'path'; import { rimraf } from 'rimraf'; import * as ts from 'typescript'; +import { PACKAGES_SCOPE_MANAGER, PACKAGES_TYPES, REPO_ROOT } from './paths.mts'; + function parseAndAnalyze( code: string, analyzeOptions: AnalyzeOptions, @@ -55,35 +58,13 @@ function addAutoGeneratedComment(code: string[]): string { } const PRETTIER_CONFIG = prettier.resolveConfig(__dirname); -const TS_LIB_FOLDER = path.resolve( - __dirname, - '..', - '..', - '..', - 'node_modules', - 'typescript', - 'lib', -); -const OUTPUT_FOLDER = path.resolve( - __dirname, - '..', - '..', - 'scope-manager', - 'src', - 'lib', -); -const TYPES_FILE = path.resolve( - __dirname, - '..', - '..', - 'types', - 'src', - 'lib.ts', -); +const TS_LIB_FOLDER = path.join(REPO_ROOT, 'node_modules', 'typescript', 'lib'); +const OUTPUT_FOLDER = path.join(PACKAGES_SCOPE_MANAGER, 'src', 'lib'); +const TYPES_FILE = path.join(PACKAGES_TYPES, 'src', 'lib.ts'); const BARREL_PATH = path.join(OUTPUT_FOLDER, 'index.ts'); const BASE_CONFIG_MODULE_NAME = 'base-config'; -const SHARED_CONFIG_MODULE = path.resolve( +const SHARED_CONFIG_MODULE = path.join( OUTPUT_FOLDER, `${BASE_CONFIG_MODULE_NAME}.ts`, ); diff --git a/packages/repo-tools/src/generate-sponsors.ts b/packages/repo-tools/src/generate-sponsors.mts similarity index 97% rename from packages/repo-tools/src/generate-sponsors.ts rename to packages/repo-tools/src/generate-sponsors.mts index e07e311ec67c..142029a61333 100644 --- a/packages/repo-tools/src/generate-sponsors.ts +++ b/packages/repo-tools/src/generate-sponsors.mts @@ -3,6 +3,8 @@ import * as fs from 'fs'; import * as path from 'path'; import prettier from 'prettier'; +import { PACKAGES_WEBSITE } from './paths.mts'; + const graphqlEndpoint = 'https://api.opencollective.com/graphql/v2'; const queries = { @@ -166,7 +168,7 @@ async function main(): Promise { }) .sort((a, b) => b.totalDonations - a.totalDonations); - const rcPath = path.resolve(__dirname, '../../website/data/sponsors.json'); + const rcPath = path.join(PACKAGES_WEBSITE, 'data', 'sponsors.json'); fs.writeFileSync(rcPath, await stringifyObject(rcPath, allSponsorsConfig)); } diff --git a/packages/repo-tools/src/paths.mts b/packages/repo-tools/src/paths.mts new file mode 100644 index 000000000000..1e6d101a2012 --- /dev/null +++ b/packages/repo-tools/src/paths.mts @@ -0,0 +1,13 @@ +import path from 'node:path'; +import url from 'node:url'; + +const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); + +export const REPO_ROOT = path.resolve(__dirname, '..', '..', '..'); +export const PACKAGES = path.join(REPO_ROOT, 'packages'); + +export const PACKAGES_CORE = path.join(PACKAGES, 'core'); +export const PACKAGES_ESLINT_PLUGIN = path.join(PACKAGES, 'eslint-plugin'); +export const PACKAGES_SCOPE_MANAGER = path.join(PACKAGES, 'scope-manager'); +export const PACKAGES_TYPES = path.join(PACKAGES, 'types'); +export const PACKAGES_WEBSITE = path.join(PACKAGES, 'website'); diff --git a/packages/repo-tools/tsconfig.build.json b/packages/repo-tools/tsconfig.build.json index b9ac3e1b9770..992e2f19be74 100644 --- a/packages/repo-tools/tsconfig.build.json +++ b/packages/repo-tools/tsconfig.build.json @@ -1,6 +1,9 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { + // repo tools are executed with tsx + "allowImportingTsExtensions": true, + "noEmit": true, "composite": true, "outDir": "./dist", "rootDir": "./src", diff --git a/packages/rule-schema-to-typescript-types/project.json b/packages/rule-schema-to-typescript-types/project.json index 6ada6d7344ff..266c06799b21 100644 --- a/packages/rule-schema-to-typescript-types/project.json +++ b/packages/rule-schema-to-typescript-types/project.json @@ -6,10 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/scope-manager/project.json b/packages/scope-manager/project.json index aa7e748088ec..ba61ab957251 100644 --- a/packages/scope-manager/project.json +++ b/packages/scope-manager/project.json @@ -51,10 +51,7 @@ }, "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] }, "test": { "executor": "@nx/jest:jest" diff --git a/packages/type-utils/project.json b/packages/type-utils/project.json index db349093e901..4ac211280e6b 100644 --- a/packages/type-utils/project.json +++ b/packages/type-utils/project.json @@ -6,10 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/types/project.json b/packages/types/project.json index 9aea796fd5a9..d470995b1e15 100644 --- a/packages/types/project.json +++ b/packages/types/project.json @@ -6,10 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/types/src/parser-options.ts b/packages/types/src/parser-options.ts index 885645f4bbae..e84e3ab25667 100644 --- a/packages/types/src/parser-options.ts +++ b/packages/types/src/parser-options.ts @@ -62,8 +62,8 @@ interface ParserOptions { filePath?: string; jsDocParsingMode?: JSDocParsingMode; loc?: boolean; - programs?: Program | null; - project?: string[] | string | true | null; + programs?: Program[] | null; + project?: string[] | string | boolean | null; projectFolderIgnoreList?: (RegExp | string)[]; range?: boolean; sourceType?: SourceType; diff --git a/packages/typescript-eslint/LICENCE b/packages/typescript-eslint/LICENSE similarity index 100% rename from packages/typescript-eslint/LICENCE rename to packages/typescript-eslint/LICENSE diff --git a/packages/typescript-eslint/jest.config.js b/packages/typescript-eslint/jest.config.js new file mode 100644 index 000000000000..88b83019e018 --- /dev/null +++ b/packages/typescript-eslint/jest.config.js @@ -0,0 +1,8 @@ +'use strict'; + +// @ts-check +/** @type {import('@jest/types').Config.InitialOptions} */ +module.exports = { + ...require('../../jest.config.base.js'), + testRegex: './tests/.+\\.ts$', +}; diff --git a/packages/typescript-eslint/package.json b/packages/typescript-eslint/package.json index efd1b4486c46..f0cbe7b99950 100644 --- a/packages/typescript-eslint/package.json +++ b/packages/typescript-eslint/package.json @@ -9,7 +9,6 @@ "LICENSE" ], "type": "commonjs", - "private": true, "exports": { ".": { "types": "./dist/index.d.ts", diff --git a/packages/typescript-eslint/project.json b/packages/typescript-eslint/project.json index 75cd8266b5ec..f30e095e6523 100644 --- a/packages/typescript-eslint/project.json +++ b/packages/typescript-eslint/project.json @@ -6,10 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/typescript-eslint/src/config-helper.ts b/packages/typescript-eslint/src/config-helper.ts new file mode 100644 index 000000000000..61063d608805 --- /dev/null +++ b/packages/typescript-eslint/src/config-helper.ts @@ -0,0 +1,86 @@ +import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'; + +interface ConfigWithExtends extends FlatConfig.Config { + /** + * Allows you to "extend" a set of configs similar to `extends` from the + * classic configs. + * + * This is just a convenience short-hand to help reduce duplication. + * + * ```js + * export default tseslint.config({ + * files: ['** /*.ts'], + * extends: [ + * eslint.configs.recommended, + * tseslint.configs.recommended, + * ], + * rules: { + * '@typescript-eslint/array-type': 'error', + * '@typescript-eslint/consistent-type-imports': 'error', + * }, + * }) + * + * // expands to + * + * export default [ + * { + * files: ['** /*.ts'], + * ...eslint.configs.recommended, + * }, + * { + * files: ['** /*.ts'], + * ...tseslint.configs.recommended, + * }, + * { + * files: ['** /*.ts'], + * rules: { + * '@typescript-eslint/array-type': 'error', + * '@typescript-eslint/consistent-type-imports': 'error', + * }, + * }, + * ] + * ``` + */ + extends?: FlatConfig.ConfigArray; +} + +/** + * Utility function to make it easy to strictly type your "Flat" config file + * @example + * ```js + * // @ts-check + * + * import eslint from '@eslint/js'; + * import tseslint from '@typescript-eslint/core'; + * + * export default tseslint.config( + * tseslint.configs.recommended, + * eslint.configs.recommended, + * { + * rules: { + * '@typescript-eslint/array-type': 'error', + * }, + * }, + * ); + * ``` + */ +export function config( + ...configs: ConfigWithExtends[] +): FlatConfig.ConfigArray { + return configs.flatMap(configWithExtends => { + const { extends: extendsArr, ...config } = configWithExtends; + if (extendsArr == null || extendsArr.length === 0) { + return config; + } + + if (config.files) { + const files = config.files; + return [ + ...extendsArr.map(conf => ({ ...conf, files: [...files] })), + config, + ]; + } + + return [...extendsArr, config]; + }); +} diff --git a/packages/typescript-eslint/src/configs/all.ts b/packages/typescript-eslint/src/configs/all.ts new file mode 100644 index 000000000000..e366ba92800b --- /dev/null +++ b/packages/typescript-eslint/src/configs/all.ts @@ -0,0 +1,165 @@ +// THIS CODE WAS AUTOMATICALLY GENERATED +// DO NOT EDIT THIS CODE BY HAND +// SEE https://typescript-eslint.io/linting/configs +// +// For developers working in the typescript-eslint monorepo: +// You can regenerate it using `yarn generate:configs` + +import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'; + +import baseConfig from './base'; +import eslintRecommendedConfig from './eslint-recommended'; + +export default ( + plugin: FlatConfig.Plugin, + parser: FlatConfig.Parser, +): FlatConfig.ConfigArray => [ + baseConfig(plugin, parser), + eslintRecommendedConfig(plugin, parser), + { + rules: { + '@typescript-eslint/adjacent-overload-signatures': 'error', + '@typescript-eslint/array-type': 'error', + '@typescript-eslint/await-thenable': 'error', + '@typescript-eslint/ban-ts-comment': 'error', + '@typescript-eslint/ban-tslint-comment': 'error', + '@typescript-eslint/ban-types': 'error', + '@typescript-eslint/class-literal-property-style': 'error', + 'class-methods-use-this': 'off', + '@typescript-eslint/class-methods-use-this': 'error', + '@typescript-eslint/consistent-generic-constructors': 'error', + '@typescript-eslint/consistent-indexed-object-style': 'error', + '@typescript-eslint/consistent-type-assertions': 'error', + '@typescript-eslint/consistent-type-definitions': 'error', + '@typescript-eslint/consistent-type-exports': 'error', + '@typescript-eslint/consistent-type-imports': 'error', + 'default-param-last': 'off', + '@typescript-eslint/default-param-last': 'error', + 'dot-notation': 'off', + '@typescript-eslint/dot-notation': 'error', + '@typescript-eslint/explicit-function-return-type': 'error', + '@typescript-eslint/explicit-member-accessibility': 'error', + '@typescript-eslint/explicit-module-boundary-types': 'error', + 'init-declarations': 'off', + '@typescript-eslint/init-declarations': 'error', + 'max-params': 'off', + '@typescript-eslint/max-params': 'error', + '@typescript-eslint/member-ordering': 'error', + '@typescript-eslint/method-signature-style': 'error', + '@typescript-eslint/naming-convention': 'error', + 'no-array-constructor': 'off', + '@typescript-eslint/no-array-constructor': 'error', + '@typescript-eslint/no-array-delete': 'error', + '@typescript-eslint/no-base-to-string': 'error', + '@typescript-eslint/no-confusing-non-null-assertion': 'error', + '@typescript-eslint/no-confusing-void-expression': 'error', + 'no-dupe-class-members': 'off', + '@typescript-eslint/no-dupe-class-members': 'error', + '@typescript-eslint/no-duplicate-enum-values': 'error', + '@typescript-eslint/no-duplicate-type-constituents': 'error', + '@typescript-eslint/no-dynamic-delete': 'error', + 'no-empty-function': 'off', + '@typescript-eslint/no-empty-function': 'error', + '@typescript-eslint/no-empty-interface': 'error', + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-extra-non-null-assertion': 'error', + '@typescript-eslint/no-extraneous-class': 'error', + '@typescript-eslint/no-floating-promises': 'error', + '@typescript-eslint/no-for-in-array': 'error', + 'no-implied-eval': 'off', + '@typescript-eslint/no-implied-eval': 'error', + '@typescript-eslint/no-import-type-side-effects': 'error', + '@typescript-eslint/no-inferrable-types': 'error', + 'no-invalid-this': 'off', + '@typescript-eslint/no-invalid-this': 'error', + '@typescript-eslint/no-invalid-void-type': 'error', + 'no-loop-func': 'off', + '@typescript-eslint/no-loop-func': 'error', + 'no-loss-of-precision': 'off', + '@typescript-eslint/no-loss-of-precision': 'error', + 'no-magic-numbers': 'off', + '@typescript-eslint/no-magic-numbers': 'error', + '@typescript-eslint/no-meaningless-void-operator': 'error', + '@typescript-eslint/no-misused-new': 'error', + '@typescript-eslint/no-misused-promises': 'error', + '@typescript-eslint/no-mixed-enums': 'error', + '@typescript-eslint/no-namespace': 'error', + '@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error', + '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', + '@typescript-eslint/no-non-null-assertion': 'error', + 'no-redeclare': 'off', + '@typescript-eslint/no-redeclare': 'error', + '@typescript-eslint/no-redundant-type-constituents': 'error', + '@typescript-eslint/no-require-imports': 'error', + 'no-restricted-imports': 'off', + '@typescript-eslint/no-restricted-imports': 'error', + 'no-shadow': 'off', + '@typescript-eslint/no-shadow': 'error', + '@typescript-eslint/no-this-alias': 'error', + 'no-throw-literal': 'off', + '@typescript-eslint/no-throw-literal': 'error', + '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error', + '@typescript-eslint/no-unnecessary-condition': 'error', + '@typescript-eslint/no-unnecessary-qualifier': 'error', + '@typescript-eslint/no-unnecessary-type-arguments': 'error', + '@typescript-eslint/no-unnecessary-type-assertion': 'error', + '@typescript-eslint/no-unnecessary-type-constraint': 'error', + '@typescript-eslint/no-unsafe-argument': 'error', + '@typescript-eslint/no-unsafe-assignment': 'error', + '@typescript-eslint/no-unsafe-call': 'error', + '@typescript-eslint/no-unsafe-declaration-merging': 'error', + '@typescript-eslint/no-unsafe-enum-comparison': 'error', + '@typescript-eslint/no-unsafe-member-access': 'error', + '@typescript-eslint/no-unsafe-return': 'error', + '@typescript-eslint/no-unsafe-unary-minus': 'error', + 'no-unused-expressions': 'off', + '@typescript-eslint/no-unused-expressions': 'error', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'error', + 'no-use-before-define': 'off', + '@typescript-eslint/no-use-before-define': 'error', + 'no-useless-constructor': 'off', + '@typescript-eslint/no-useless-constructor': 'error', + '@typescript-eslint/no-useless-empty-export': 'error', + '@typescript-eslint/no-useless-template-literals': 'error', + '@typescript-eslint/no-var-requires': 'error', + '@typescript-eslint/non-nullable-type-assertion-style': 'error', + '@typescript-eslint/parameter-properties': 'error', + '@typescript-eslint/prefer-as-const': 'error', + 'prefer-destructuring': 'off', + '@typescript-eslint/prefer-destructuring': 'error', + '@typescript-eslint/prefer-enum-initializers': 'error', + '@typescript-eslint/prefer-for-of': 'error', + '@typescript-eslint/prefer-function-type': 'error', + '@typescript-eslint/prefer-includes': 'error', + '@typescript-eslint/prefer-literal-enum-member': 'error', + '@typescript-eslint/prefer-namespace-keyword': 'error', + '@typescript-eslint/prefer-nullish-coalescing': 'error', + '@typescript-eslint/prefer-optional-chain': 'error', + 'prefer-promise-reject-errors': 'off', + '@typescript-eslint/prefer-promise-reject-errors': 'error', + '@typescript-eslint/prefer-readonly': 'error', + '@typescript-eslint/prefer-readonly-parameter-types': 'error', + '@typescript-eslint/prefer-reduce-type-parameter': 'error', + '@typescript-eslint/prefer-regexp-exec': 'error', + '@typescript-eslint/prefer-return-this-type': 'error', + '@typescript-eslint/prefer-string-starts-ends-with': 'error', + '@typescript-eslint/prefer-ts-expect-error': 'error', + '@typescript-eslint/promise-function-async': 'error', + '@typescript-eslint/require-array-sort-compare': 'error', + 'require-await': 'off', + '@typescript-eslint/require-await': 'error', + '@typescript-eslint/restrict-plus-operands': 'error', + '@typescript-eslint/restrict-template-expressions': 'error', + 'no-return-await': 'off', + '@typescript-eslint/return-await': 'error', + '@typescript-eslint/sort-type-constituents': 'error', + '@typescript-eslint/strict-boolean-expressions': 'error', + '@typescript-eslint/switch-exhaustiveness-check': 'error', + '@typescript-eslint/triple-slash-reference': 'error', + '@typescript-eslint/typedef': 'error', + '@typescript-eslint/unbound-method': 'error', + '@typescript-eslint/unified-signatures': 'error', + }, + }, +]; diff --git a/packages/typescript-eslint/src/configs/base.ts b/packages/typescript-eslint/src/configs/base.ts new file mode 100644 index 000000000000..a25249a18225 --- /dev/null +++ b/packages/typescript-eslint/src/configs/base.ts @@ -0,0 +1,14 @@ +import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'; + +export default ( + plugin: FlatConfig.Plugin, + parser: FlatConfig.Parser, +): FlatConfig.Config => ({ + languageOptions: { + parser, + parserOptions: { sourceType: 'module' }, + }, + plugins: { + '@typescript-eslint': plugin, + }, +}); diff --git a/packages/typescript-eslint/src/configs/disable-type-checked.ts b/packages/typescript-eslint/src/configs/disable-type-checked.ts new file mode 100644 index 000000000000..fa52425e4f40 --- /dev/null +++ b/packages/typescript-eslint/src/configs/disable-type-checked.ts @@ -0,0 +1,67 @@ +// THIS CODE WAS AUTOMATICALLY GENERATED +// DO NOT EDIT THIS CODE BY HAND +// SEE https://typescript-eslint.io/linting/configs +// +// For developers working in the typescript-eslint monorepo: +// You can regenerate it using `yarn generate:configs` + +import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'; + +export default ( + _plugin: FlatConfig.Plugin, + _parser: FlatConfig.Parser, +): FlatConfig.Config => ({ + rules: { + '@typescript-eslint/await-thenable': 'off', + '@typescript-eslint/consistent-type-exports': 'off', + '@typescript-eslint/dot-notation': 'off', + '@typescript-eslint/naming-convention': 'off', + '@typescript-eslint/no-array-delete': 'off', + '@typescript-eslint/no-base-to-string': 'off', + '@typescript-eslint/no-confusing-void-expression': 'off', + '@typescript-eslint/no-duplicate-type-constituents': 'off', + '@typescript-eslint/no-floating-promises': 'off', + '@typescript-eslint/no-for-in-array': 'off', + '@typescript-eslint/no-implied-eval': 'off', + '@typescript-eslint/no-meaningless-void-operator': 'off', + '@typescript-eslint/no-misused-promises': 'off', + '@typescript-eslint/no-mixed-enums': 'off', + '@typescript-eslint/no-redundant-type-constituents': 'off', + '@typescript-eslint/no-throw-literal': 'off', + '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'off', + '@typescript-eslint/no-unnecessary-condition': 'off', + '@typescript-eslint/no-unnecessary-qualifier': 'off', + '@typescript-eslint/no-unnecessary-type-arguments': 'off', + '@typescript-eslint/no-unnecessary-type-assertion': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-enum-comparison': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-unsafe-unary-minus': 'off', + '@typescript-eslint/no-useless-template-literals': 'off', + '@typescript-eslint/non-nullable-type-assertion-style': 'off', + '@typescript-eslint/prefer-destructuring': 'off', + '@typescript-eslint/prefer-includes': 'off', + '@typescript-eslint/prefer-nullish-coalescing': 'off', + '@typescript-eslint/prefer-optional-chain': 'off', + '@typescript-eslint/prefer-promise-reject-errors': 'off', + '@typescript-eslint/prefer-readonly': 'off', + '@typescript-eslint/prefer-readonly-parameter-types': 'off', + '@typescript-eslint/prefer-reduce-type-parameter': 'off', + '@typescript-eslint/prefer-regexp-exec': 'off', + '@typescript-eslint/prefer-return-this-type': 'off', + '@typescript-eslint/prefer-string-starts-ends-with': 'off', + '@typescript-eslint/promise-function-async': 'off', + '@typescript-eslint/require-array-sort-compare': 'off', + '@typescript-eslint/require-await': 'off', + '@typescript-eslint/restrict-plus-operands': 'off', + '@typescript-eslint/restrict-template-expressions': 'off', + '@typescript-eslint/return-await': 'off', + '@typescript-eslint/strict-boolean-expressions': 'off', + '@typescript-eslint/switch-exhaustiveness-check': 'off', + '@typescript-eslint/unbound-method': 'off', + }, + languageOptions: { parserOptions: { project: false, program: null } }, +}); diff --git a/packages/typescript-eslint/src/configs/eslint-recommended.ts b/packages/typescript-eslint/src/configs/eslint-recommended.ts new file mode 100644 index 000000000000..b9885922ecc1 --- /dev/null +++ b/packages/typescript-eslint/src/configs/eslint-recommended.ts @@ -0,0 +1,12 @@ +import config from '@typescript-eslint/eslint-plugin/use-at-your-own-risk/eslint-recommended-raw'; +import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'; + +/** + * This is a compatibility ruleset that: + * - disables rules from eslint:recommended which are already handled by TypeScript. + * - enables rules that make sense due to TS's typechecking / transpilation. + */ +export default ( + _plugin: FlatConfig.Plugin, + _parser: FlatConfig.Parser, +): FlatConfig.Config => config('minimatch'); diff --git a/packages/typescript-eslint/src/configs/recommended-type-checked.ts b/packages/typescript-eslint/src/configs/recommended-type-checked.ts new file mode 100644 index 000000000000..7d9ac811e1c7 --- /dev/null +++ b/packages/typescript-eslint/src/configs/recommended-type-checked.ts @@ -0,0 +1,64 @@ +// THIS CODE WAS AUTOMATICALLY GENERATED +// DO NOT EDIT THIS CODE BY HAND +// SEE https://typescript-eslint.io/linting/configs +// +// For developers working in the typescript-eslint monorepo: +// You can regenerate it using `yarn generate:configs` + +import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'; + +import baseConfig from './base'; +import eslintRecommendedConfig from './eslint-recommended'; + +export default ( + plugin: FlatConfig.Plugin, + parser: FlatConfig.Parser, +): FlatConfig.ConfigArray => [ + baseConfig(plugin, parser), + eslintRecommendedConfig(plugin, parser), + { + rules: { + '@typescript-eslint/await-thenable': 'error', + '@typescript-eslint/ban-ts-comment': 'error', + '@typescript-eslint/ban-types': 'error', + 'no-array-constructor': 'off', + '@typescript-eslint/no-array-constructor': 'error', + '@typescript-eslint/no-base-to-string': 'error', + '@typescript-eslint/no-duplicate-enum-values': 'error', + '@typescript-eslint/no-duplicate-type-constituents': 'error', + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-extra-non-null-assertion': 'error', + '@typescript-eslint/no-floating-promises': 'error', + '@typescript-eslint/no-for-in-array': 'error', + 'no-implied-eval': 'off', + '@typescript-eslint/no-implied-eval': 'error', + 'no-loss-of-precision': 'off', + '@typescript-eslint/no-loss-of-precision': 'error', + '@typescript-eslint/no-misused-new': 'error', + '@typescript-eslint/no-misused-promises': 'error', + '@typescript-eslint/no-namespace': 'error', + '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', + '@typescript-eslint/no-redundant-type-constituents': 'error', + '@typescript-eslint/no-this-alias': 'error', + '@typescript-eslint/no-unnecessary-type-assertion': 'error', + '@typescript-eslint/no-unnecessary-type-constraint': 'error', + '@typescript-eslint/no-unsafe-argument': 'error', + '@typescript-eslint/no-unsafe-assignment': 'error', + '@typescript-eslint/no-unsafe-call': 'error', + '@typescript-eslint/no-unsafe-declaration-merging': 'error', + '@typescript-eslint/no-unsafe-enum-comparison': 'error', + '@typescript-eslint/no-unsafe-member-access': 'error', + '@typescript-eslint/no-unsafe-return': 'error', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'error', + '@typescript-eslint/no-var-requires': 'error', + '@typescript-eslint/prefer-as-const': 'error', + 'require-await': 'off', + '@typescript-eslint/require-await': 'error', + '@typescript-eslint/restrict-plus-operands': 'error', + '@typescript-eslint/restrict-template-expressions': 'error', + '@typescript-eslint/triple-slash-reference': 'error', + '@typescript-eslint/unbound-method': 'error', + }, + }, +]; diff --git a/packages/typescript-eslint/src/configs/recommended.ts b/packages/typescript-eslint/src/configs/recommended.ts new file mode 100644 index 000000000000..ae5103d9fea8 --- /dev/null +++ b/packages/typescript-eslint/src/configs/recommended.ts @@ -0,0 +1,43 @@ +// THIS CODE WAS AUTOMATICALLY GENERATED +// DO NOT EDIT THIS CODE BY HAND +// SEE https://typescript-eslint.io/linting/configs +// +// For developers working in the typescript-eslint monorepo: +// You can regenerate it using `yarn generate:configs` + +import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'; + +import baseConfig from './base'; +import eslintRecommendedConfig from './eslint-recommended'; + +export default ( + plugin: FlatConfig.Plugin, + parser: FlatConfig.Parser, +): FlatConfig.ConfigArray => [ + baseConfig(plugin, parser), + eslintRecommendedConfig(plugin, parser), + { + rules: { + '@typescript-eslint/ban-ts-comment': 'error', + '@typescript-eslint/ban-types': 'error', + 'no-array-constructor': 'off', + '@typescript-eslint/no-array-constructor': 'error', + '@typescript-eslint/no-duplicate-enum-values': 'error', + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-extra-non-null-assertion': 'error', + 'no-loss-of-precision': 'off', + '@typescript-eslint/no-loss-of-precision': 'error', + '@typescript-eslint/no-misused-new': 'error', + '@typescript-eslint/no-namespace': 'error', + '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', + '@typescript-eslint/no-this-alias': 'error', + '@typescript-eslint/no-unnecessary-type-constraint': 'error', + '@typescript-eslint/no-unsafe-declaration-merging': 'error', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'error', + '@typescript-eslint/no-var-requires': 'error', + '@typescript-eslint/prefer-as-const': 'error', + '@typescript-eslint/triple-slash-reference': 'error', + }, + }, +]; diff --git a/packages/typescript-eslint/src/configs/strict-type-checked.ts b/packages/typescript-eslint/src/configs/strict-type-checked.ts new file mode 100644 index 000000000000..c1c4628d0cdf --- /dev/null +++ b/packages/typescript-eslint/src/configs/strict-type-checked.ts @@ -0,0 +1,89 @@ +// THIS CODE WAS AUTOMATICALLY GENERATED +// DO NOT EDIT THIS CODE BY HAND +// SEE https://typescript-eslint.io/linting/configs +// +// For developers working in the typescript-eslint monorepo: +// You can regenerate it using `yarn generate:configs` + +import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'; + +import baseConfig from './base'; +import eslintRecommendedConfig from './eslint-recommended'; + +export default ( + plugin: FlatConfig.Plugin, + parser: FlatConfig.Parser, +): FlatConfig.ConfigArray => [ + baseConfig(plugin, parser), + eslintRecommendedConfig(plugin, parser), + { + rules: { + '@typescript-eslint/await-thenable': 'error', + '@typescript-eslint/ban-ts-comment': 'error', + '@typescript-eslint/ban-types': 'error', + 'no-array-constructor': 'off', + '@typescript-eslint/no-array-constructor': 'error', + '@typescript-eslint/no-array-delete': 'error', + '@typescript-eslint/no-base-to-string': 'error', + '@typescript-eslint/no-confusing-void-expression': 'error', + '@typescript-eslint/no-duplicate-enum-values': 'error', + '@typescript-eslint/no-duplicate-type-constituents': 'error', + '@typescript-eslint/no-dynamic-delete': 'error', + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-extra-non-null-assertion': 'error', + '@typescript-eslint/no-extraneous-class': 'error', + '@typescript-eslint/no-floating-promises': 'error', + '@typescript-eslint/no-for-in-array': 'error', + 'no-implied-eval': 'off', + '@typescript-eslint/no-implied-eval': 'error', + '@typescript-eslint/no-invalid-void-type': 'error', + 'no-loss-of-precision': 'off', + '@typescript-eslint/no-loss-of-precision': 'error', + '@typescript-eslint/no-meaningless-void-operator': 'error', + '@typescript-eslint/no-misused-new': 'error', + '@typescript-eslint/no-misused-promises': 'error', + '@typescript-eslint/no-mixed-enums': 'error', + '@typescript-eslint/no-namespace': 'error', + '@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error', + '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', + '@typescript-eslint/no-non-null-assertion': 'error', + '@typescript-eslint/no-redundant-type-constituents': 'error', + '@typescript-eslint/no-this-alias': 'error', + 'no-throw-literal': 'off', + '@typescript-eslint/no-throw-literal': 'error', + '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error', + '@typescript-eslint/no-unnecessary-condition': 'error', + '@typescript-eslint/no-unnecessary-type-arguments': 'error', + '@typescript-eslint/no-unnecessary-type-assertion': 'error', + '@typescript-eslint/no-unnecessary-type-constraint': 'error', + '@typescript-eslint/no-unsafe-argument': 'error', + '@typescript-eslint/no-unsafe-assignment': 'error', + '@typescript-eslint/no-unsafe-call': 'error', + '@typescript-eslint/no-unsafe-declaration-merging': 'error', + '@typescript-eslint/no-unsafe-enum-comparison': 'error', + '@typescript-eslint/no-unsafe-member-access': 'error', + '@typescript-eslint/no-unsafe-return': 'error', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'error', + 'no-useless-constructor': 'off', + '@typescript-eslint/no-useless-constructor': 'error', + '@typescript-eslint/no-useless-template-literals': 'error', + '@typescript-eslint/no-var-requires': 'error', + '@typescript-eslint/prefer-as-const': 'error', + '@typescript-eslint/prefer-includes': 'error', + '@typescript-eslint/prefer-literal-enum-member': 'error', + 'prefer-promise-reject-errors': 'off', + '@typescript-eslint/prefer-promise-reject-errors': 'error', + '@typescript-eslint/prefer-reduce-type-parameter': 'error', + '@typescript-eslint/prefer-return-this-type': 'error', + '@typescript-eslint/prefer-ts-expect-error': 'error', + 'require-await': 'off', + '@typescript-eslint/require-await': 'error', + '@typescript-eslint/restrict-plus-operands': 'error', + '@typescript-eslint/restrict-template-expressions': 'error', + '@typescript-eslint/triple-slash-reference': 'error', + '@typescript-eslint/unbound-method': 'error', + '@typescript-eslint/unified-signatures': 'error', + }, + }, +]; diff --git a/packages/typescript-eslint/src/configs/strict.ts b/packages/typescript-eslint/src/configs/strict.ts new file mode 100644 index 000000000000..e54b7d07322e --- /dev/null +++ b/packages/typescript-eslint/src/configs/strict.ts @@ -0,0 +1,53 @@ +// THIS CODE WAS AUTOMATICALLY GENERATED +// DO NOT EDIT THIS CODE BY HAND +// SEE https://typescript-eslint.io/linting/configs +// +// For developers working in the typescript-eslint monorepo: +// You can regenerate it using `yarn generate:configs` + +import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'; + +import baseConfig from './base'; +import eslintRecommendedConfig from './eslint-recommended'; + +export default ( + plugin: FlatConfig.Plugin, + parser: FlatConfig.Parser, +): FlatConfig.ConfigArray => [ + baseConfig(plugin, parser), + eslintRecommendedConfig(plugin, parser), + { + rules: { + '@typescript-eslint/ban-ts-comment': 'error', + '@typescript-eslint/ban-types': 'error', + 'no-array-constructor': 'off', + '@typescript-eslint/no-array-constructor': 'error', + '@typescript-eslint/no-duplicate-enum-values': 'error', + '@typescript-eslint/no-dynamic-delete': 'error', + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-extra-non-null-assertion': 'error', + '@typescript-eslint/no-extraneous-class': 'error', + '@typescript-eslint/no-invalid-void-type': 'error', + 'no-loss-of-precision': 'off', + '@typescript-eslint/no-loss-of-precision': 'error', + '@typescript-eslint/no-misused-new': 'error', + '@typescript-eslint/no-namespace': 'error', + '@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error', + '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', + '@typescript-eslint/no-non-null-assertion': 'error', + '@typescript-eslint/no-this-alias': 'error', + '@typescript-eslint/no-unnecessary-type-constraint': 'error', + '@typescript-eslint/no-unsafe-declaration-merging': 'error', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'error', + 'no-useless-constructor': 'off', + '@typescript-eslint/no-useless-constructor': 'error', + '@typescript-eslint/no-var-requires': 'error', + '@typescript-eslint/prefer-as-const': 'error', + '@typescript-eslint/prefer-literal-enum-member': 'error', + '@typescript-eslint/prefer-ts-expect-error': 'error', + '@typescript-eslint/triple-slash-reference': 'error', + '@typescript-eslint/unified-signatures': 'error', + }, + }, +]; diff --git a/packages/typescript-eslint/src/configs/stylistic-type-checked.ts b/packages/typescript-eslint/src/configs/stylistic-type-checked.ts new file mode 100644 index 000000000000..3923973100b3 --- /dev/null +++ b/packages/typescript-eslint/src/configs/stylistic-type-checked.ts @@ -0,0 +1,45 @@ +// THIS CODE WAS AUTOMATICALLY GENERATED +// DO NOT EDIT THIS CODE BY HAND +// SEE https://typescript-eslint.io/linting/configs +// +// For developers working in the typescript-eslint monorepo: +// You can regenerate it using `yarn generate:configs` + +import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'; + +import baseConfig from './base'; +import eslintRecommendedConfig from './eslint-recommended'; + +export default ( + plugin: FlatConfig.Plugin, + parser: FlatConfig.Parser, +): FlatConfig.ConfigArray => [ + baseConfig(plugin, parser), + eslintRecommendedConfig(plugin, parser), + { + rules: { + '@typescript-eslint/adjacent-overload-signatures': 'error', + '@typescript-eslint/array-type': 'error', + '@typescript-eslint/ban-tslint-comment': 'error', + '@typescript-eslint/class-literal-property-style': 'error', + '@typescript-eslint/consistent-generic-constructors': 'error', + '@typescript-eslint/consistent-indexed-object-style': 'error', + '@typescript-eslint/consistent-type-assertions': 'error', + '@typescript-eslint/consistent-type-definitions': 'error', + 'dot-notation': 'off', + '@typescript-eslint/dot-notation': 'error', + '@typescript-eslint/no-confusing-non-null-assertion': 'error', + 'no-empty-function': 'off', + '@typescript-eslint/no-empty-function': 'error', + '@typescript-eslint/no-empty-interface': 'error', + '@typescript-eslint/no-inferrable-types': 'error', + '@typescript-eslint/non-nullable-type-assertion-style': 'error', + '@typescript-eslint/prefer-for-of': 'error', + '@typescript-eslint/prefer-function-type': 'error', + '@typescript-eslint/prefer-namespace-keyword': 'error', + '@typescript-eslint/prefer-nullish-coalescing': 'error', + '@typescript-eslint/prefer-optional-chain': 'error', + '@typescript-eslint/prefer-string-starts-ends-with': 'error', + }, + }, +]; diff --git a/packages/typescript-eslint/src/configs/stylistic.ts b/packages/typescript-eslint/src/configs/stylistic.ts new file mode 100644 index 000000000000..4db1a78f9a0a --- /dev/null +++ b/packages/typescript-eslint/src/configs/stylistic.ts @@ -0,0 +1,39 @@ +// THIS CODE WAS AUTOMATICALLY GENERATED +// DO NOT EDIT THIS CODE BY HAND +// SEE https://typescript-eslint.io/linting/configs +// +// For developers working in the typescript-eslint monorepo: +// You can regenerate it using `yarn generate:configs` + +import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'; + +import baseConfig from './base'; +import eslintRecommendedConfig from './eslint-recommended'; + +export default ( + plugin: FlatConfig.Plugin, + parser: FlatConfig.Parser, +): FlatConfig.ConfigArray => [ + baseConfig(plugin, parser), + eslintRecommendedConfig(plugin, parser), + { + rules: { + '@typescript-eslint/adjacent-overload-signatures': 'error', + '@typescript-eslint/array-type': 'error', + '@typescript-eslint/ban-tslint-comment': 'error', + '@typescript-eslint/class-literal-property-style': 'error', + '@typescript-eslint/consistent-generic-constructors': 'error', + '@typescript-eslint/consistent-indexed-object-style': 'error', + '@typescript-eslint/consistent-type-assertions': 'error', + '@typescript-eslint/consistent-type-definitions': 'error', + '@typescript-eslint/no-confusing-non-null-assertion': 'error', + 'no-empty-function': 'off', + '@typescript-eslint/no-empty-function': 'error', + '@typescript-eslint/no-empty-interface': 'error', + '@typescript-eslint/no-inferrable-types': 'error', + '@typescript-eslint/prefer-for-of': 'error', + '@typescript-eslint/prefer-function-type': 'error', + '@typescript-eslint/prefer-namespace-keyword': 'error', + }, + }, +]; diff --git a/packages/typescript-eslint/src/index.ts b/packages/typescript-eslint/src/index.ts index 8a15f9183b55..ea63e2c93011 100644 --- a/packages/typescript-eslint/src/index.ts +++ b/packages/typescript-eslint/src/index.ts @@ -1,2 +1,43 @@ -// TODO(bradzacher) #7935 -export {}; +import pluginBase from '@typescript-eslint/eslint-plugin'; +import * as parserBase from '@typescript-eslint/parser'; +import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'; + +import { config } from './config-helper'; +import allConfig from './configs/all'; +import baseConfig from './configs/base'; +import disableTypeCheckedConfig from './configs/disable-type-checked'; +import eslintRecommendedConfig from './configs/eslint-recommended'; +import recommendedConfig from './configs/recommended'; +import recommendedTypeCheckedConfig from './configs/recommended-type-checked'; +import strictConfig from './configs/strict'; +import strictTypeCheckedConfig from './configs/strict-type-checked'; +import stylisticConfig from './configs/stylistic'; +import stylisticTypeCheckedConfig from './configs/stylistic-type-checked'; + +const parser: FlatConfig.Parser = { + meta: parserBase.meta, + parseForESLint: parserBase.parseForESLint, +}; + +const plugin: FlatConfig.Plugin = { + meta: pluginBase.meta, + rules: pluginBase.rules, +}; + +export = { + config, + configs: { + all: allConfig(plugin, parser), + base: baseConfig(plugin, parser), + disableTypeChecked: disableTypeCheckedConfig(plugin, parser), + eslintRecommended: eslintRecommendedConfig(plugin, parser), + recommended: recommendedConfig(plugin, parser), + recommendedTypeChecked: recommendedTypeCheckedConfig(plugin, parser), + strict: strictConfig(plugin, parser), + strictTypeChecked: strictTypeCheckedConfig(plugin, parser), + stylistic: stylisticConfig(plugin, parser), + stylisticTypeChecked: stylisticTypeCheckedConfig(plugin, parser), + }, + parser, + plugin, +}; diff --git a/packages/typescript-eslint/tests/configs.test.ts b/packages/typescript-eslint/tests/configs.test.ts new file mode 100644 index 000000000000..1b88f58b6e98 --- /dev/null +++ b/packages/typescript-eslint/tests/configs.test.ts @@ -0,0 +1,213 @@ +import rules from '@typescript-eslint/eslint-plugin/use-at-your-own-risk/rules'; +import type { + FlatConfig, + RuleRecommendation, +} from '@typescript-eslint/utils/ts-eslint'; + +import plugin from '../src/index'; + +const RULE_NAME_PREFIX = '@typescript-eslint/'; +const EXTENSION_RULES = Object.entries(rules) + .filter(([, rule]) => rule.meta.docs?.extendsBaseRule) + .map( + ([ruleName, rule]) => + [ + `${RULE_NAME_PREFIX}${ruleName}`, + typeof rule.meta.docs?.extendsBaseRule === 'string' + ? rule.meta.docs.extendsBaseRule + : ruleName, + ] as const, + ); + +function entriesToObject(value: [string, T][]): Record { + return value.reduce>((accum, [k, v]) => { + accum[k] = v; + return accum; + }, {}); +} + +function filterRules( + values: FlatConfig.Rules | undefined, +): [string, FlatConfig.RuleEntry][] { + expect(values).toBeDefined(); + return Object.entries(values!) + .filter((pair): pair is [string, FlatConfig.RuleEntry] => pair[1] != null) + .filter(([name]) => name.startsWith(RULE_NAME_PREFIX)); +} + +interface FilterAndMapRuleConfigsSettings { + excludeDeprecated?: boolean; + excludeTypeChecked?: boolean; + recommendations?: (RuleRecommendation | undefined)[]; +} + +function filterAndMapRuleConfigs({ + excludeDeprecated, + excludeTypeChecked, + recommendations, +}: FilterAndMapRuleConfigsSettings = {}): [string, string][] { + let result = Object.entries(rules); + + if (excludeDeprecated) { + result = result.filter(([, rule]) => !rule.meta.deprecated); + } + + if (excludeTypeChecked) { + result = result.filter(([, rule]) => !rule.meta.docs?.requiresTypeChecking); + } + + if (recommendations) { + result = result.filter(([, rule]) => + recommendations.includes(rule.meta.docs?.recommended), + ); + } + + return result.map(([name]) => [`${RULE_NAME_PREFIX}${name}`, 'error']); +} + +function itHasBaseRulesOverriden( + unfilteredConfigRules: FlatConfig.Rules | undefined, +): void { + it('has the base rules overriden by the appropriate extension rules', () => { + expect(unfilteredConfigRules).toBeDefined(); + const ruleNames = new Set(Object.keys(unfilteredConfigRules!)); + EXTENSION_RULES.forEach(([ruleName, extRuleName]) => { + if (ruleNames.has(ruleName)) { + // this looks a little weird, but it provides the cleanest test output style + expect(unfilteredConfigRules).toMatchObject({ + ...unfilteredConfigRules, + [extRuleName]: 'off', + }); + } + }); + }); +} + +describe('all.ts', () => { + const unfilteredConfigRules = plugin.configs.all[2]?.rules; + + it('contains all of the rules', () => { + const configRules = filterRules(unfilteredConfigRules); + // note: exclude deprecated rules, this config is allowed to change between minor versions + const ruleConfigs = filterAndMapRuleConfigs({ + excludeDeprecated: true, + }); + + expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + }); + + itHasBaseRulesOverriden(unfilteredConfigRules); +}); + +describe('disable-type-checked.ts', () => { + const unfilteredConfigRules = plugin.configs.disableTypeChecked.rules; + + it('disables all type checked rules', () => { + const configRules = filterRules(unfilteredConfigRules); + + const ruleConfigs: [string, string][] = Object.entries(rules) + .filter(([, rule]) => rule.meta.docs?.requiresTypeChecking) + .map(([name]) => [`${RULE_NAME_PREFIX}${name}`, 'off']); + + expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + }); +}); + +describe('recommended.ts', () => { + const unfilteredConfigRules = plugin.configs.recommended[2]?.rules; + + it('contains all recommended rules, excluding type checked ones', () => { + const configRules = filterRules(unfilteredConfigRules); + // note: include deprecated rules so that the config doesn't change between major bumps + const ruleConfigs = filterAndMapRuleConfigs({ + excludeTypeChecked: true, + recommendations: ['recommended'], + }); + + expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + }); + + itHasBaseRulesOverriden(unfilteredConfigRules); +}); + +describe('recommended-type-checked.ts', () => { + const unfilteredConfigRules = plugin.configs.recommendedTypeChecked[2]?.rules; + + it('contains all recommended rules', () => { + const configRules = filterRules(unfilteredConfigRules); + // note: include deprecated rules so that the config doesn't change between major bumps + const ruleConfigs = filterAndMapRuleConfigs({ + recommendations: ['recommended'], + }); + + expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + }); + + itHasBaseRulesOverriden(unfilteredConfigRules); +}); + +describe('strict.ts', () => { + const unfilteredConfigRules = plugin.configs.strict[2]?.rules; + + it('contains all strict rules, excluding type checked ones', () => { + const configRules = filterRules(unfilteredConfigRules); + // note: exclude deprecated rules, this config is allowed to change between minor versions + const ruleConfigs = filterAndMapRuleConfigs({ + excludeDeprecated: true, + excludeTypeChecked: true, + recommendations: ['recommended', 'strict'], + }); + + expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + }); + + itHasBaseRulesOverriden(unfilteredConfigRules); +}); + +describe('strict-type-checked.ts', () => { + const unfilteredConfigRules = plugin.configs.strictTypeChecked[2]?.rules; + + it('contains all strict rules', () => { + const configRules = filterRules(unfilteredConfigRules); + // note: exclude deprecated rules, this config is allowed to change between minor versions + const ruleConfigs = filterAndMapRuleConfigs({ + excludeDeprecated: true, + recommendations: ['recommended', 'strict'], + }); + expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + }); + + itHasBaseRulesOverriden(unfilteredConfigRules); +}); + +describe('stylistic.ts', () => { + const unfilteredConfigRules = plugin.configs.stylistic[2]?.rules; + + it('contains all stylistic rules, excluding deprecated or type checked ones', () => { + const configRules = filterRules(unfilteredConfigRules); + // note: include deprecated rules so that the config doesn't change between major bumps + const ruleConfigs = filterAndMapRuleConfigs({ + excludeTypeChecked: true, + recommendations: ['stylistic'], + }); + + expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + }); + + itHasBaseRulesOverriden(unfilteredConfigRules); +}); + +describe('stylistic-type-checked.ts', () => { + const unfilteredConfigRules = plugin.configs.stylisticTypeChecked[2]?.rules; + const configRules = filterRules(unfilteredConfigRules); + // note: include deprecated rules so that the config doesn't change between major bumps + const ruleConfigs = filterAndMapRuleConfigs({ + recommendations: ['stylistic'], + }); + + it('contains all stylistic rules, excluding deprecated ones', () => { + expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + }); + + itHasBaseRulesOverriden(unfilteredConfigRules); +}); diff --git a/packages/typescript-estree/project.json b/packages/typescript-estree/project.json index 146f87708349..231f8f93a011 100644 --- a/packages/typescript-estree/project.json +++ b/packages/typescript-estree/project.json @@ -6,10 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts b/packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts index 64af27985f0e..1765f2cb1250 100644 --- a/packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts +++ b/packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts @@ -2,7 +2,8 @@ import debug from 'debug'; import * as fs from 'fs'; import * as path from 'path'; -import type { ParseSettings } from '.'; +import type { TSESTreeOptions } from '../parser-options'; +import type { ParseSettings } from './index'; const log = debug('typescript-eslint:typescript-estree:getProjectConfigFiles'); @@ -20,10 +21,10 @@ export function getProjectConfigFiles( ParseSettings, 'filePath' | 'tsconfigMatchCache' | 'tsconfigRootDir' >, - project: string[] | string | true | null | undefined, + project: TSESTreeOptions['project'], ): string[] | null { if (project !== true) { - if (project == null) { + if (project == null || project === false) { return null; } if (Array.isArray(project)) { diff --git a/packages/typescript-estree/src/parser-options.ts b/packages/typescript-estree/src/parser-options.ts index e86be6d50996..0753c29f8c38 100644 --- a/packages/typescript-estree/src/parser-options.ts +++ b/packages/typescript-estree/src/parser-options.ts @@ -167,7 +167,7 @@ interface ParseAndGenerateServicesOptions extends ParseOptions { * or `true` to find the nearest tsconfig.json to the file. * If this is provided, type information will be returned. */ - project?: string[] | string | true | null; + project?: string[] | string | boolean | null; /** * If you provide a glob (or globs) to the project option, you can use this option to ignore certain folders from diff --git a/packages/typescript-estree/tests/lib/semanticInfo.test.ts b/packages/typescript-estree/tests/lib/semanticInfo.test.ts index 9b6d353d48c4..f5f78934a880 100644 --- a/packages/typescript-estree/tests/lib/semanticInfo.test.ts +++ b/packages/typescript-estree/tests/lib/semanticInfo.test.ts @@ -9,12 +9,12 @@ import type { ParseAndGenerateServicesResult } from '../../src/parser'; import { parseAndGenerateServices } from '../../src/parser'; import type { TSESTreeOptions } from '../../src/parser-options'; import type { TSESTree } from '../../src/ts-estree'; +import { expectToHaveParserServices } from '../test-utils/expectToHaveParserServices'; import { createSnapshotTestBlock, formatSnapshotName, parseCodeAndGenerateServices, -} from '../../tools/test-utils'; -import { expectToHaveParserServices } from './test-utils/expectToHaveParserServices'; +} from '../test-utils/test-utils'; const FIXTURES_DIR = './tests/fixtures/semanticInfo'; const testFiles = glob.sync(`**/*.src.ts`, { diff --git a/packages/typescript-estree/tests/lib/test-utils/expectToHaveParserServices.ts b/packages/typescript-estree/tests/test-utils/expectToHaveParserServices.ts similarity index 94% rename from packages/typescript-estree/tests/lib/test-utils/expectToHaveParserServices.ts rename to packages/typescript-estree/tests/test-utils/expectToHaveParserServices.ts index d087dd3c54b2..3b9f902b1886 100644 --- a/packages/typescript-estree/tests/lib/test-utils/expectToHaveParserServices.ts +++ b/packages/typescript-estree/tests/test-utils/expectToHaveParserServices.ts @@ -1,7 +1,7 @@ import type { ParserServices, ParserServicesWithTypeInformation, -} from '../../../src'; +} from '../../src'; export function expectToHaveParserServices( services: ParserServices | null | undefined, diff --git a/packages/typescript-estree/tools/test-utils.ts b/packages/typescript-estree/tests/test-utils/test-utils.ts similarity index 99% rename from packages/typescript-estree/tools/test-utils.ts rename to packages/typescript-estree/tests/test-utils/test-utils.ts index 7e37d4bac0c6..bb8fbf290136 100644 --- a/packages/typescript-estree/tools/test-utils.ts +++ b/packages/typescript-estree/tests/test-utils/test-utils.ts @@ -2,8 +2,8 @@ import type { ParseAndGenerateServicesResult, TSESTree, TSESTreeOptions, -} from '../src'; -import { parse as parserParse, parseAndGenerateServices } from '../src'; +} from '../../src'; +import { parse as parserParse, parseAndGenerateServices } from '../../src'; export function parseCodeAndGenerateServices( code: string, diff --git a/packages/typescript-estree/tools/tserror-serializer.ts b/packages/typescript-estree/tests/test-utils/tserror-serializer.ts similarity index 93% rename from packages/typescript-estree/tools/tserror-serializer.ts rename to packages/typescript-estree/tests/test-utils/tserror-serializer.ts index dc6cfd1771c0..ebd0996e98c0 100644 --- a/packages/typescript-estree/tools/tserror-serializer.ts +++ b/packages/typescript-estree/tests/test-utils/tserror-serializer.ts @@ -1,6 +1,6 @@ import type { Plugin } from 'pretty-format'; -import { TSError } from '../src/node-utils'; +import { TSError } from '../../src/node-utils'; export const serializer: Plugin = { test: (val: unknown): val is TSError => val instanceof TSError, diff --git a/packages/utils/project.json b/packages/utils/project.json index 89fa0c819d51..fe765a0faff4 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -6,10 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/utils/src/ts-eslint/Config.ts b/packages/utils/src/ts-eslint/Config.ts index 534a41d0e07e..b88eae95a88b 100644 --- a/packages/utils/src/ts-eslint/Config.ts +++ b/packages/utils/src/ts-eslint/Config.ts @@ -119,7 +119,7 @@ export namespace ClassicConfig { export namespace FlatConfig { export type EcmaVersion = ParserOptionsTypes.EcmaVersion; export type GlobalsConfig = SharedConfig.GlobalsConfig; - export type Parser = ParserType.ParserModule; + export type Parser = ParserType.LooseParserModule; export type ParserOptions = SharedConfig.ParserOptions; export type Processor = ProcessorType.ProcessorModule; export type RuleEntry = SharedConfig.RuleEntry; @@ -131,6 +131,9 @@ export namespace FlatConfig { export type SeverityString = SharedConfig.SeverityString; export type SourceType = ParserOptionsTypes.SourceType | 'commonjs'; + export interface SharedConfigs { + [key: string]: Config; + } export interface PluginMeta { /** * The meta.name property should match the npm package name for your plugin. @@ -146,7 +149,7 @@ export namespace FlatConfig { * Shared configurations bundled with the plugin. * Users will reference these directly in their config (i.e. `plugin.configs.recommended`). */ - configs?: Record; + configs?: SharedConfigs; /** * Metadata about your plugin for easier debugging and more effective caching of plugins. */ @@ -165,7 +168,13 @@ export namespace FlatConfig { rules?: Record; } export interface Plugins { - [pluginAlias: string]: Plugin; + /** + * We intentionally omit the `configs` key from this object because it avoids + * type conflicts with old plugins that haven't updated their configs to flat configs yet. + * It's valid to reference these old plugins because ESLint won't access the + * `.config` property of a plugin when evaluating a flat config. + */ + [pluginAlias: string]: Omit; } export interface LinterOptions { @@ -262,5 +271,6 @@ export namespace FlatConfig { settings?: Settings; } export type ConfigArray = Config[]; - export type ConfigFile = ConfigArray | (() => Promise); + export type ConfigPromise = Promise; + export type ConfigFile = ConfigArray | ConfigPromise; } diff --git a/packages/utils/src/ts-eslint/Linter.ts b/packages/utils/src/ts-eslint/Linter.ts index f48ae9c32b0a..978ce3ed26aa 100644 --- a/packages/utils/src/ts-eslint/Linter.ts +++ b/packages/utils/src/ts-eslint/Linter.ts @@ -26,7 +26,7 @@ declare class LinterBase { * @param parserId Name of the parser * @param parserModule The parser object */ - defineParser(parserId: string, parserModule: Parser.ParserModule): void; + defineParser(parserId: string, parserModule: Parser.LooseParserModule): void; /** * Defines a new linting rule. @@ -243,7 +243,7 @@ namespace Linter { } /** @deprecated use Parser.ParserModule */ - export type ParserModule = Parser.ParserModule; + export type ParserModule = Parser.LooseParserModule; /** @deprecated use Parser.ParseResult */ export type ESLintParseResult = Parser.ParseResult; diff --git a/packages/utils/src/ts-eslint/Parser.ts b/packages/utils/src/ts-eslint/Parser.ts index e709ef70df6c..cfc97ac12f8b 100644 --- a/packages/utils/src/ts-eslint/Parser.ts +++ b/packages/utils/src/ts-eslint/Parser.ts @@ -38,6 +38,39 @@ export namespace Parser { parseForESLint(text: string, options?: ParserOptions): ParseResult; }; + /** + * A loose definition of the ParserModule type for use with configs + * This type intended to relax validation of configs so that parsers that have + * different AST types or scope managers can still be passed to configs + */ + export type LooseParserModule = + | { + /** + * Information about the parser to uniquely identify it when serializing. + */ + meta?: ParserMeta; + /** + * Parses the given text into an ESTree AST + */ + parse(text: string, options?: unknown): unknown; + } + | { + /** + * Information about the parser to uniquely identify it when serializing. + */ + meta?: ParserMeta; + /** + * Parses the given text into an AST + */ + parseForESLint( + text: string, + options?: unknown, + ): { + // intentionally not using a Record to preserve optionals + [k in keyof ParseResult]: unknown; + }; + }; + export interface ParseResult { /** * The ESTree AST @@ -66,6 +99,6 @@ export namespace Parser { // eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style export interface VisitorKeys { - [nodeType: string]: string[]; + [nodeType: string]: readonly string[]; } } diff --git a/packages/visitor-keys/project.json b/packages/visitor-keys/project.json index 5bdacb98ffca..d1536ce04de0 100644 --- a/packages/visitor-keys/project.json +++ b/packages/visitor-keys/project.json @@ -6,10 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/website-eslint/package.json b/packages/website-eslint/package.json index 23f9035f86ae..1806a5c8a45c 100644 --- a/packages/website-eslint/package.json +++ b/packages/website-eslint/package.json @@ -27,7 +27,7 @@ "@typescript-eslint/utils": "6.20.0" }, "devDependencies": { - "@eslint/js": "8.56.0", + "@eslint/js": "*", "@typescript-eslint/eslint-plugin": "6.20.0", "@typescript-eslint/parser": "6.20.0", "@typescript-eslint/scope-manager": "6.20.0", diff --git a/packages/website-eslint/project.json b/packages/website-eslint/project.json index 3ed597db7262..52ed1e539c3e 100644 --- a/packages/website-eslint/project.json +++ b/packages/website-eslint/project.json @@ -6,10 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/website/project.json b/packages/website/project.json index 34ab1692e8f0..c9b3f62d96f5 100644 --- a/packages/website/project.json +++ b/packages/website/project.json @@ -14,10 +14,7 @@ }, "lint": { "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/tsconfig.base.json b/tsconfig.base.json index fd7ed6a809f3..a00dd38697a3 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -6,15 +6,16 @@ "declaration": true, "declarationMap": true, "esModuleInterop": true, + "lib": ["ES2021"], "module": "Node16", - "moduleResolution": "node16", + "moduleResolution": "Node16", "noImplicitReturns": true, + "paths": {}, "pretty": true, + "resolveJsonModule": true, "skipLibCheck": true, "sourceMap": true, "strict": true, - "target": "ES2021", - "lib": ["ES2021"], - "paths": {} + "target": "ES2021" } } diff --git a/tsconfig.eslint.json b/tsconfig.json similarity index 88% rename from tsconfig.eslint.json rename to tsconfig.json index 7e9f118ed405..ed328447a15c 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.json @@ -6,9 +6,11 @@ }, "extends": "./tsconfig.base.json", "include": [ + "typings", "tools/**/*.ts", "tools/**/*.mts", ".eslintrc.js", + "eslint.config.js", "jest.config.base.js", "jest.config.js", "jest.preset.js" diff --git a/typings/eslint-plugin-eslint-comments.d.ts b/typings/eslint-plugin-eslint-comments.d.ts new file mode 100644 index 000000000000..279a27f80faa --- /dev/null +++ b/typings/eslint-plugin-eslint-comments.d.ts @@ -0,0 +1,14 @@ +declare module 'eslint-plugin-eslint-comments' { + import type { + ClassicConfig, + Linter, + } from '@typescript-eslint/utils/ts-eslint'; + + declare const exprt: { + configs: { + recommended: ClassicConfig.Config; + }; + rules: NonNullable; + }; + export = exprt; +} diff --git a/typings/eslint-plugin-eslint-plugin.d.ts b/typings/eslint-plugin-eslint-plugin.d.ts new file mode 100644 index 000000000000..f0afd05081f2 --- /dev/null +++ b/typings/eslint-plugin-eslint-plugin.d.ts @@ -0,0 +1,19 @@ +declare module 'eslint-plugin-eslint-plugin' { + import type { + ClassicConfig, + Linter, + } from '@typescript-eslint/utils/ts-eslint'; + + declare const exprt: { + configs: { + all: ClassicConfig.Config; + recommended: ClassicConfig.Config; + rules: ClassicConfig.Config; + tests: ClassicConfig.Config; + 'rules-recommended': ClassicConfig.Config; + 'tests-recommended': ClassicConfig.Config; + }; + rules: NonNullable; + }; + export = exprt; +} diff --git a/typings/eslint-plugin-import.d.ts b/typings/eslint-plugin-import.d.ts new file mode 100644 index 000000000000..60742fad493a --- /dev/null +++ b/typings/eslint-plugin-import.d.ts @@ -0,0 +1,21 @@ +declare module 'eslint-plugin-import' { + import type { + ClassicConfig, + Linter, + } from '@typescript-eslint/utils/ts-eslint'; + + declare const exprt: { + configs: { + recommended: ClassicConfig.Config; + errors: ClassicConfig.Config; + warnings: ClassicConfig.Config; + 'stage-0': ClassicConfig.Config; + react: ClassicConfig.Config; + 'react-native': ClassicConfig.Config; + electron: ClassicConfig.Config; + typescript: ClassicConfig.Config; + }; + rules: NonNullable; + }; + export = exprt; +} diff --git a/typings/eslint-plugin-jest.d.ts b/typings/eslint-plugin-jest.d.ts new file mode 100644 index 000000000000..c7ccc8577e89 --- /dev/null +++ b/typings/eslint-plugin-jest.d.ts @@ -0,0 +1,21 @@ +declare module 'eslint-plugin-jest' { + import type { + ClassicConfig, + Linter, + } from '@typescript-eslint/utils/ts-eslint'; + + declare const exprt: { + configs: { + all: ClassicConfig.Config; + recommended: ClassicConfig.Config; + style: ClassicConfig.Config; + }; + environments: { + globals: { + globals: ClassicConfig.EnvironmentConfig; + }; + }; + rules: NonNullable; + }; + export = exprt; +} diff --git a/typings/eslint-plugin-jsdoc.d.ts b/typings/eslint-plugin-jsdoc.d.ts new file mode 100644 index 000000000000..3f7082bb233b --- /dev/null +++ b/typings/eslint-plugin-jsdoc.d.ts @@ -0,0 +1,25 @@ +declare module 'eslint-plugin-jsdoc' { + import type { + ClassicConfig, + FlatConfig, + Linter, + } from '@typescript-eslint/utils/ts-eslint'; + + declare const exprt: { + configs: { + 'flat/recommended': FlatConfig.Config; + 'flat/recommended-error': FlatConfig.Config; + 'flat/recommended-typescript': FlatConfig.Config; + 'flat/recommended-typescript-error': FlatConfig.Config; + 'flat/recommended-typescript-flavor': FlatConfig.Config; + 'flat/recommended-typescript-flavor-error': FlatConfig.Config; + }; + environments: { + globals: { + globals: ClassicConfig.EnvironmentConfig; + }; + }; + rules: NonNullable; + }; + export = exprt; +} diff --git a/typings/eslint-plugin-jsx-a11y.d.ts b/typings/eslint-plugin-jsx-a11y.d.ts new file mode 100644 index 000000000000..d5fba291eb1f --- /dev/null +++ b/typings/eslint-plugin-jsx-a11y.d.ts @@ -0,0 +1,15 @@ +declare module 'eslint-plugin-jsx-a11y' { + import type { + ClassicConfig, + Linter, + } from '@typescript-eslint/utils/ts-eslint'; + + declare const exprt: { + configs: { + recommended: ClassicConfig.Config; + strict: ClassicConfig.Config; + }; + rules: NonNullable; + }; + export = exprt; +} diff --git a/typings/eslint-plugin-react-hooks.d.ts b/typings/eslint-plugin-react-hooks.d.ts new file mode 100644 index 000000000000..ff5f964ccc0a --- /dev/null +++ b/typings/eslint-plugin-react-hooks.d.ts @@ -0,0 +1,14 @@ +declare module 'eslint-plugin-react-hooks' { + import type { + ClassicConfig, + Linter, + } from '@typescript-eslint/utils/ts-eslint'; + + declare const exprt: { + configs: { + recommended: ClassicConfig.Config; + }; + rules: NonNullable; + }; + export = exprt; +} diff --git a/typings/eslint-plugin-react.d.ts b/typings/eslint-plugin-react.d.ts new file mode 100644 index 000000000000..d1199b9c6850 --- /dev/null +++ b/typings/eslint-plugin-react.d.ts @@ -0,0 +1,16 @@ +declare module 'eslint-plugin-react' { + import type { + ClassicConfig, + Linter, + } from '@typescript-eslint/utils/ts-eslint'; + + declare const exprt: { + configs: { + recommended: ClassicConfig.Config; + all: ClassicConfig.Config; + 'jsx-runtime': ClassicConfig.Config; + }; + rules: NonNullable; + }; + export = exprt; +} diff --git a/typings/eslint-plugin-simple-import-sort.d.ts b/typings/eslint-plugin-simple-import-sort.d.ts new file mode 100644 index 000000000000..fd515a9f662b --- /dev/null +++ b/typings/eslint-plugin-simple-import-sort.d.ts @@ -0,0 +1,8 @@ +declare module 'eslint-plugin-simple-import-sort' { + import type { Linter } from '@typescript-eslint/utils/ts-eslint'; + + declare const exprt: { + rules: NonNullable; + }; + export = exprt; +} diff --git a/typings/eslint-plugin-unicorn.d.ts b/typings/eslint-plugin-unicorn.d.ts new file mode 100644 index 000000000000..fa0e2752590a --- /dev/null +++ b/typings/eslint-plugin-unicorn.d.ts @@ -0,0 +1,15 @@ +declare module 'eslint-plugin-unicorn' { + import type { + ClassicConfig, + Linter, + } from '@typescript-eslint/utils/ts-eslint'; + + declare const exprt: { + configs: { + recommended: ClassicConfig.Config; + all: ClassicConfig.Config; + }; + rules: NonNullable; + }; + export = exprt; +} diff --git a/typings/eslint__eslintrc.d.ts b/typings/eslint__eslintrc.d.ts new file mode 100644 index 000000000000..78462ba5c884 --- /dev/null +++ b/typings/eslint__eslintrc.d.ts @@ -0,0 +1,22 @@ +declare module '@eslint/eslintrc' { + import type { + ClassicConfig, + FlatConfig, + } from '@typescript-eslint/utils/ts-eslint'; + + declare class FlatCompat { + constructor(options?: { + baseDirectory?: string; + resolvePluginsRelativeTo?: string; + }); + + config(eslintrcConfig: ClassicConfig.Config): FlatConfig.ConfigArray; + env(envConfig: ClassicConfig.EnvironmentConfig): FlatConfig.ConfigArray; + extends(...configsToExtend: string[]): FlatConfig.ConfigArray; + plugins(...plugins: string[]): FlatConfig.ConfigArray; + } + declare const exprt: { + FlatCompat: typeof FlatCompat; + }; + export = exprt; +} diff --git a/typings/eslint__js.d.ts b/typings/eslint__js.d.ts new file mode 100644 index 000000000000..6e50127f6b4d --- /dev/null +++ b/typings/eslint__js.d.ts @@ -0,0 +1,11 @@ +declare module '@eslint/js' { + import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'; + + declare const exprt: { + configs: { + all: FlatConfig.Config; + recommended: FlatConfig.Config; + }; + }; + export = exprt; +} diff --git a/yarn.lock b/yarn.lock index a1c9a9cbec37..6f058732ea30 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3248,9 +3248,9 @@ __metadata: languageName: node linkType: hard -"@eslint/eslintrc@npm:^2.1.2": - version: 2.1.2 - resolution: "@eslint/eslintrc@npm:2.1.2" +"@eslint/eslintrc@npm:^2.1.4": + version: 2.1.4 + resolution: "@eslint/eslintrc@npm:2.1.4" dependencies: ajv: ^6.12.4 debug: ^4.3.2 @@ -3261,18 +3261,25 @@ __metadata: js-yaml: ^4.1.0 minimatch: ^3.1.2 strip-json-comments: ^3.1.1 - checksum: bc742a1e3b361f06fedb4afb6bf32cbd27171292ef7924f61c62f2aed73048367bcc7ac68f98c06d4245cd3fabc43270f844e3c1699936d4734b3ac5398814a7 + checksum: 10957c7592b20ca0089262d8c2a8accbad14b4f6507e35416c32ee6b4dbf9cad67dfb77096bbd405405e9ada2b107f3797fe94362e1c55e0b09d6e90dd149127 + languageName: node + linkType: hard + +"@eslint/js@npm:*": + version: 8.53.0 + resolution: "@eslint/js@npm:8.53.0" + checksum: e0d5cfb0000aaee237c8e6d6d6e366faa60b1ef7f928ce17778373aa44d3b886368f6d5e1f97f913f0f16801aad016db8b8df78418c9d18825c15590328028af languageName: node linkType: hard -"@eslint/js@npm:8.48.0": - version: 8.48.0 - resolution: "@eslint/js@npm:8.48.0" - checksum: b2755f9c0ee810c886eba3c50dcacb184ba5a5cd1cbc01988ee506ad7340653cae0bd55f1d95c64b56dfc6d25c2caa7825335ffd2c50165bae9996fe0f396851 +"@eslint/js@npm:8.55.0": + version: 8.55.0 + resolution: "@eslint/js@npm:8.55.0" + checksum: fa33ef619f0646ed15649b0c2e313e4d9ccee8425884bdbfc78020d6b6b64c0c42fa9d83061d0e6158e1d4274f03f0f9008786540e2efab8fcdc48082259908c languageName: node linkType: hard -"@eslint/js@npm:8.56.0": +"@eslint/js@npm:8.56.0, @eslint/js@npm:^8.56.0": version: 8.56.0 resolution: "@eslint/js@npm:8.56.0" checksum: 5804130574ef810207bdf321c265437814e7a26f4e6fac9b496de3206afd52f533e09ec002a3be06cd9adcc9da63e727f1883938e663c4e4751c007d5b58e539 @@ -3302,14 +3309,14 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.11.10": - version: 0.11.10 - resolution: "@humanwhocodes/config-array@npm:0.11.10" +"@humanwhocodes/config-array@npm:^0.11.13": + version: 0.11.13 + resolution: "@humanwhocodes/config-array@npm:0.11.13" dependencies: - "@humanwhocodes/object-schema": ^1.2.1 + "@humanwhocodes/object-schema": ^2.0.1 debug: ^4.1.1 minimatch: ^3.0.5 - checksum: 1b1302e2403d0e35bc43e66d67a2b36b0ad1119efc704b5faff68c41f791a052355b010fb2d27ef022670f550de24cd6d08d5ecf0821c16326b7dcd0ee5d5d8a + checksum: f8ea57b0d7ed7f2d64cd3944654976829d9da91c04d9c860e18804729a33f7681f78166ef4c761850b8c324d362f7d53f14c5c44907a6b38b32c703ff85e4805 languageName: node linkType: hard @@ -3320,10 +3327,10 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/object-schema@npm:^1.2.1": - version: 1.2.1 - resolution: "@humanwhocodes/object-schema@npm:1.2.1" - checksum: a824a1ec31591231e4bad5787641f59e9633827d0a2eaae131a288d33c9ef0290bd16fda8da6f7c0fcb014147865d12118df10db57f27f41e20da92369fcb3f1 +"@humanwhocodes/object-schema@npm:^2.0.1": + version: 2.0.1 + resolution: "@humanwhocodes/object-schema@npm:2.0.1" + checksum: 24929487b1ed48795d2f08346a0116cc5ee4634848bce64161fb947109352c562310fd159fc64dda0e8b853307f5794605191a9547f7341158559ca3c8262a45 languageName: node linkType: hard @@ -5388,7 +5395,7 @@ __metadata: languageName: unknown linkType: soft -"@typescript-eslint/eslint-plugin-internal@workspace:packages/eslint-plugin-internal": +"@typescript-eslint/eslint-plugin-internal@workspace:^, @typescript-eslint/eslint-plugin-internal@workspace:packages/eslint-plugin-internal": version: 0.0.0-use.local resolution: "@typescript-eslint/eslint-plugin-internal@workspace:packages/eslint-plugin-internal" dependencies: @@ -5503,6 +5510,7 @@ __metadata: dependencies: "@nx/devkit": "*" "@prettier/sync": "*" + cross-env: "*" cross-fetch: "*" execa: "*" prettier: ^3.0.3 @@ -5626,6 +5634,8 @@ __metadata: "@babel/eslint-parser": ^7.23.3 "@babel/parser": ^7.23.3 "@babel/types": ^7.23.3 + "@eslint/eslintrc": ^2.1.4 + "@eslint/js": ^8.56.0 "@nx/eslint": 17.2.8 "@nx/jest": 17.2.8 "@nx/workspace": 17.2.8 @@ -5645,12 +5655,13 @@ __metadata: "@types/semver": ^7.5.0 "@types/tmp": ^0.2.3 "@types/yargs": ^17.0.32 - "@typescript-eslint/eslint-plugin-internal": "workspace:packages/eslint-plugin-internal" + "@typescript-eslint/eslint-plugin-internal": "workspace:^" console-fail-test: ^0.2.3 + cross-env: ^7.0.3 cross-fetch: ^4.0.0 cspell: ^7.0.0 downlevel-dts: ">=0.11.0" - eslint: ^8.47.0 + eslint: ^8.56.0 eslint-plugin-deprecation: ^2.0.0 eslint-plugin-eslint-comments: ^3.2.0 eslint-plugin-eslint-plugin: ^5.1.0 @@ -5664,6 +5675,7 @@ __metadata: eslint-plugin-unicorn: ^48.0.1 execa: 7.1.1 glob: ^10.3.3 + globals: ^13.23.0 husky: ^8.0.3 jest: 29.7.0 jest-diff: ^29.6.2 @@ -5804,7 +5816,7 @@ __metadata: version: 0.0.0-use.local resolution: "@typescript-eslint/website-eslint@workspace:packages/website-eslint" dependencies: - "@eslint/js": 8.56.0 + "@eslint/js": "*" "@typescript-eslint/eslint-plugin": 6.20.0 "@typescript-eslint/parser": 6.20.0 "@typescript-eslint/scope-manager": 6.20.0 @@ -5823,6 +5835,13 @@ __metadata: languageName: unknown linkType: soft +"@ungap/structured-clone@npm:^1.2.0": + version: 1.2.0 + resolution: "@ungap/structured-clone@npm:1.2.0" + checksum: 4f656b7b4672f2ce6e272f2427d8b0824ed11546a601d8d5412b9d7704e83db38a8d9f402ecdf2b9063fc164af842ad0ec4a55819f621ed7e7ea4d1efcc74524 + languageName: node + linkType: hard + "@webassemblyjs/ast@npm:1.11.5, @webassemblyjs/ast@npm:^1.11.5": version: 1.11.5 resolution: "@webassemblyjs/ast@npm:1.11.5" @@ -7964,6 +7983,18 @@ __metadata: languageName: node linkType: hard +"cross-env@npm:*, cross-env@npm:^7.0.3": + version: 7.0.3 + resolution: "cross-env@npm:7.0.3" + dependencies: + cross-spawn: ^7.0.1 + bin: + cross-env: src/bin/cross-env.js + cross-env-shell: src/bin/cross-env-shell.js + checksum: 26f2f3ea2ab32617f57effb70d329c2070d2f5630adc800985d8b30b56e8bf7f5f439dd3a0358b79cee6f930afc23cf8e23515f17ccfb30092c6b62c6b630a79 + languageName: node + linkType: hard + "cross-fetch@npm:*, cross-fetch@npm:^4.0.0": version: 4.0.0 resolution: "cross-fetch@npm:4.0.0" @@ -7982,7 +8013,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": +"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": version: 7.0.3 resolution: "cross-spawn@npm:7.0.3" dependencies: @@ -9597,17 +9628,18 @@ __metadata: languageName: node linkType: hard -"eslint@npm:*, eslint@npm:^8.47.0": - version: 8.48.0 - resolution: "eslint@npm:8.48.0" +"eslint@npm:*": + version: 8.55.0 + resolution: "eslint@npm:8.55.0" dependencies: "@eslint-community/eslint-utils": ^4.2.0 "@eslint-community/regexpp": ^4.6.1 - "@eslint/eslintrc": ^2.1.2 - "@eslint/js": 8.48.0 - "@humanwhocodes/config-array": ^0.11.10 + "@eslint/eslintrc": ^2.1.4 + "@eslint/js": 8.55.0 + "@humanwhocodes/config-array": ^0.11.13 "@humanwhocodes/module-importer": ^1.0.1 "@nodelib/fs.walk": ^1.2.8 + "@ungap/structured-clone": ^1.2.0 ajv: ^6.12.4 chalk: ^4.0.0 cross-spawn: ^7.0.2 @@ -9640,7 +9672,55 @@ __metadata: text-table: ^0.2.0 bin: eslint: bin/eslint.js - checksum: f20b359a4f8123fec5c033577368cc020d42978b1b45303974acd8da7a27063168ee3fe297ab5b35327162f6a93154063e3ce6577102f70f9809aff793db9bd0 + checksum: 83f82a604559dc1faae79d28fdf3dfc9e592ca221052e2ea516e1b379b37e77e4597705a16880e2f5ece4f79087c1dd13fd7f6e9746f794a401175519db18b41 + languageName: node + linkType: hard + +"eslint@npm:^8.56.0": + version: 8.56.0 + resolution: "eslint@npm:8.56.0" + dependencies: + "@eslint-community/eslint-utils": ^4.2.0 + "@eslint-community/regexpp": ^4.6.1 + "@eslint/eslintrc": ^2.1.4 + "@eslint/js": 8.56.0 + "@humanwhocodes/config-array": ^0.11.13 + "@humanwhocodes/module-importer": ^1.0.1 + "@nodelib/fs.walk": ^1.2.8 + "@ungap/structured-clone": ^1.2.0 + ajv: ^6.12.4 + chalk: ^4.0.0 + cross-spawn: ^7.0.2 + debug: ^4.3.2 + doctrine: ^3.0.0 + escape-string-regexp: ^4.0.0 + eslint-scope: ^7.2.2 + eslint-visitor-keys: ^3.4.3 + espree: ^9.6.1 + esquery: ^1.4.2 + esutils: ^2.0.2 + fast-deep-equal: ^3.1.3 + file-entry-cache: ^6.0.1 + find-up: ^5.0.0 + glob-parent: ^6.0.2 + globals: ^13.19.0 + graphemer: ^1.4.0 + ignore: ^5.2.0 + imurmurhash: ^0.1.4 + is-glob: ^4.0.0 + is-path-inside: ^3.0.3 + js-yaml: ^4.1.0 + json-stable-stringify-without-jsonify: ^1.0.1 + levn: ^0.4.1 + lodash.merge: ^4.6.2 + minimatch: ^3.1.2 + natural-compare: ^1.4.0 + optionator: ^0.9.3 + strip-ansi: ^6.0.1 + text-table: ^0.2.0 + bin: + eslint: bin/eslint.js + checksum: 883436d1e809b4a25d9eb03d42f584b84c408dbac28b0019f6ea07b5177940bf3cca86208f749a6a1e0039b63e085ee47aca1236c30721e91f0deef5cc5a5136 languageName: node linkType: hard @@ -10715,6 +10795,15 @@ __metadata: languageName: node linkType: hard +"globals@npm:^13.23.0": + version: 13.23.0 + resolution: "globals@npm:13.23.0" + dependencies: + type-fest: ^0.20.2 + checksum: 194c97cf8d1ef6ba59417234c2386549c4103b6e5f24b1ff1952de61a4753e5d2069435ba629de711a6480b1b1d114a98e2ab27f85e966d5a10c319c3bbd3dc3 + languageName: node + linkType: hard + "globalthis@npm:^1.0.3": version: 1.0.3 resolution: "globalthis@npm:1.0.3"