From 8ef5f4bffcf0904a28ada92a224a378d309407a4 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Wed, 7 Feb 2024 13:22:08 +1030 Subject: [PATCH] feat: add support for flat configs (#7935) --- .cspell.json | 2 + .eslintignore | 17 - .eslintrc.js | 457 --------------- .github/renovate.json5 | 5 + .github/workflows/ci.yml | 2 + .vscode/settings.json | 2 + .../@nx-eslint-npm-17.3.1-a2f85d8c50.patch | 14 + docs/Packages.mdx | 1 + docs/packages/TypeScript_ESLint.mdx | 126 +++++ eslint.config.js | 8 + eslint.config.mjs | 534 ++++++++++++++++++ nx.json | 3 +- package.json | 6 +- packages/ast-spec/project.json | 4 +- packages/eslint-plugin-internal/index.d.ts | 9 + packages/eslint-plugin-internal/package.json | 1 + packages/eslint-plugin-internal/project.json | 4 +- packages/eslint-plugin-internal/tsconfig.json | 2 +- packages/eslint-plugin-tslint/project.json | 4 +- .../eslint-plugin/eslint-recommended-raw.d.ts | 5 + packages/eslint-plugin/index.d.ts | 6 +- packages/eslint-plugin/package.json | 4 + packages/eslint-plugin/project.json | 4 +- 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 | 31 +- packages/integration-tests/project.json | 4 +- packages/parser/project.json | 4 +- packages/parser/src/parser.ts | 3 +- packages/repo-tools/project.json | 4 +- packages/repo-tools/src/generate-configs.mts | 137 +++-- packages/repo-tools/src/generate-lib.mts | 11 +- packages/repo-tools/src/generate-sponsors.mts | 2 +- packages/repo-tools/src/paths.mts | 5 + packages/repo-tools/tsconfig.build.json | 3 + .../project.json | 4 +- packages/scope-manager/project.json | 4 +- packages/type-utils/project.json | 4 +- packages/types/project.json | 4 +- packages/types/src/parser-options.ts | 2 +- .../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 | 166 ++++++ .../typescript-eslint/src/configs/base.ts | 14 + .../src/configs/disable-type-checked.ts | 68 +++ .../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 | 4 +- packages/utils/project.json | 4 +- packages/visitor-keys/project.json | 4 +- packages/website-eslint/package.json | 2 +- packages/website-eslint/project.json | 4 +- packages/website/project.json | 4 +- packages/website/sidebars/sidebar.base.js | 1 + tsconfig.base.json | 9 +- tsconfig.eslint.json => tsconfig.json | 9 +- 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 | 62 +- 81 files changed, 2122 insertions(+), 629 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc.js create mode 100644 .yarn/patches/@nx-eslint-npm-17.3.1-a2f85d8c50.patch create mode 100644 docs/packages/TypeScript_ESLint.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/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 tsconfig.eslint.json => tsconfig.json (68%) 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 c5bd12a5c9a..99feed384c1 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 431bc803029..00000000000 --- 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 1398b8f04d8..00000000000 --- 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 255a9a7bc38..bed1f941a20 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 225405e2f4d..ba2829c7f2c 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 896fbaebbb3..ac5f882cbc0 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/.yarn/patches/@nx-eslint-npm-17.3.1-a2f85d8c50.patch b/.yarn/patches/@nx-eslint-npm-17.3.1-a2f85d8c50.patch new file mode 100644 index 00000000000..66c1c932b81 --- /dev/null +++ b/.yarn/patches/@nx-eslint-npm-17.3.1-a2f85d8c50.patch @@ -0,0 +1,14 @@ +diff --git a/src/executors/lint/utility/eslint-utils.js b/src/executors/lint/utility/eslint-utils.js +index e5c40146ef3560047c0e3db88c80f8bf5042602a..86388a67f570249c2a23df47662a878ed774968b 100644 +--- a/src/executors/lint/utility/eslint-utils.js ++++ b/src/executors/lint/utility/eslint-utils.js +@@ -38,7 +38,8 @@ async function resolveAndInstantiateESLint(eslintConfigPath, options, useFlatCon + * not be any html files in the project, so keeping it true would break linting every time + */ + errorOnUnmatchedPattern: false, +- reportUnusedDisableDirectives: options.reportUnusedDisableDirectives || undefined, ++ // https://github.com/nrwl/nx/pull/21405 ++ // reportUnusedDisableDirectives: options.reportUnusedDisableDirectives || undefined, + }; + if (useFlatConfig) { + if (typeof options.useEslintrc !== 'undefined') { diff --git a/docs/Packages.mdx b/docs/Packages.mdx index 52406fc6c11..e26b877518f 100644 --- a/docs/Packages.mdx +++ b/docs/Packages.mdx @@ -14,5 +14,6 @@ They are: - [`@typescript-eslint/parser`](./packages/Parser.mdx): An ESLint parser which allows for ESLint to lint TypeScript source code. - [`@typescript-eslint/rule-tester`](./packages/Rule_Tester.mdx): A utility for testing ESLint rules. - [`@typescript-eslint/scope-manager`](./packages/Scope_Manager.mdx): A fork of [`eslint-scope`](https://github.com/eslint/eslint-scope), enhanced to support TypeScript functionality. +- [`@typescript-eslint/typescript-eslint`](./packages/TypeScript_ESLint.mdx): Tooling which enables you to use TypeScript with ESLint. - [`@typescript-eslint/typescript-estree`](./packages/TypeScript_ESTree.mdx): The underlying code used by [`@typescript-eslint/parser`](./packages/Parser.mdx) that converts TypeScript source code into an [ESTree](https://github.com/estree/estree)-compatible form. - [`@typescript-eslint/utils`](./packages/Utils.mdx): Utilities for working with TypeScript + ESLint together. diff --git a/docs/packages/TypeScript_ESLint.mdx b/docs/packages/TypeScript_ESLint.mdx new file mode 100644 index 00000000000..8f0463620e8 --- /dev/null +++ b/docs/packages/TypeScript_ESLint.mdx @@ -0,0 +1,126 @@ +--- +id: typescript-eslint +sidebar_label: typescript-eslint +--- + +# `typescript-eslint` + +> 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. + +This package exports the following: + +| name | description | +| --------- | ---------------------------------------------------------- | +| `config` | A utility function for creating type-safe flat configs | +| `configs` | [Our eslint (flat) configs](../linting/Configurations.mdx) | +| `parser` | [Our parser](./Parser.mdx) | +| `plugin` | [Our plugin](./ESLint_Plugin.mdx) | + +## Usage + +The `tseslint.config` function is a simple utility which does a few things. First and foremost it is a strictly typed function - meaning it allows you to write type-safe configs! + +The simplest usage would be: + +```js title="eslint.config.js" +// @ts-check + +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; + +export default tseslint.config( + eslint.configs.recommended, + ...tseslint.configs.recommended, +); +``` + +You can also declare our plugin and parser in your config via this package. For example this config would enable our plugin, our parser, and type-aware linting with a few of our popular type-aware rules: + +```js title="eslint.config.js" +// @ts-check + +import tseslint from 'typescript-eslint'; + +export default tseslint.config({ + plugins: { + '@typescript-eslint': tseslint.plugin, + }, + languageOptions: { + parser: tseslint.parser, + parserOptions: { + project: true, + }, + }, + rules: { + '@typescript-eslint/no-unsafe-argument': 'error', + '@typescript-eslint/no-unsafe-assignment': 'error', + '@typescript-eslint/no-unsafe-call': 'error', + '@typescript-eslint/no-unsafe-member-access': 'error', + '@typescript-eslint/no-unsafe-return': 'error', + }, +}); +``` + +:::warning +We **_strongly_** recommend declaring our plugin with the namespace `@typescript-eslint` as shown above. If you use our shared configs this is the namespace that they use. This has been the standard namespace for our plugin for many years and is what users are most familiar with. + +You may choose a different namespace - but note that currently [flat configs allow the same plugin to be registered, configured, and have duplicate reports under multiple namespaces](https://github.com/eslint/eslint/discussions/17766). +::: + +### Flat config `extends` + +The `tseslint.config` utility function also adds handling for the `extends` property on flat config objects. This allows you to more easily extend shared configs for specific file patterns whilst also overriding rules/options provided by those configs: + +```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', + }, +}); + +// is the same as writing + +export default [ + ...[ + eslint.configs.recommended, + ...tseslint.configs.recommended, + ].map(conf => ({ + ...conf, + files: ['**/*.ts'], + })), + { + files: ['**/*.ts'], + rules: { + '@typescript-eslint/array-type': 'error', + '@typescript-eslint/consistent-type-imports': 'error', + }, + }, +]; +``` + +We found that this is a pretty common operation when writing ESLint configs which is why we provided this convenience property - for example in codebases with type-aware linting a config object like this is a very common way to disable TS-specific linting setups on JS files: + +```js +export default [ + { + 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', + }, + }, +]; +``` diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000000..218cd0a70eb --- /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 00000000000..66399e018ce --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,534 @@ +// @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/typescript-eslint/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 e8a4c3be16b..6f8ca39d33d 100644 --- a/nx.json +++ b/nx.json @@ -60,7 +60,8 @@ "dependsOn": ["eslint-plugin:build"], "inputs": [ "default", - "{workspaceRoot}/.eslintrc.js", + "{workspaceRoot}/eslint.config.js", + "{workspaceRoot}/eslint.config.mjs", "{workspaceRoot}/yarn.lock", "{workspaceRoot}/.eslintignore", { diff --git a/package.json b/package.json index 72b3ef35759..a611dc176d8 100644 --- a/package.json +++ b/package.json @@ -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.3.1", "@nx/jest": "17.3.1", "@nx/workspace": "17.3.1", @@ -97,6 +99,7 @@ "eslint-plugin-unicorn": "^50.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", @@ -138,7 +141,8 @@ "pretty-format": "^29", "react-split-pane@^0.1.92": "patch:react-split-pane@npm%3A0.1.92#./.yarn/patches/react-split-pane-npm-0.1.92-93dbf51dff.patch", "tsx": "^4.6.2", - "typescript": "5.3.3" + "typescript": "5.3.3", + "@nx/eslint@17.3.1": "patch:@nx/eslint@npm%3A17.3.1#./.yarn/patches/@nx-eslint-npm-17.3.1-a2f85d8c50.patch" }, "packageManager": "yarn@3.7.0" } diff --git a/packages/ast-spec/project.json b/packages/ast-spec/project.json index f870803d844..0076bc88031 100644 --- a/packages/ast-spec/project.json +++ b/packages/ast-spec/project.json @@ -14,9 +14,7 @@ }, "lint": { "executor": "@nx/eslint:lint", - "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 00000000000..8c2962c75da --- /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 8e31ab2be3f..8d5b625d77d 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -3,6 +3,7 @@ "version": "6.21.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 6beb16149d0..36836344938 100644 --- a/packages/eslint-plugin-internal/project.json +++ b/packages/eslint-plugin-internal/project.json @@ -6,9 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/eslint-plugin-internal/tsconfig.json b/packages/eslint-plugin-internal/tsconfig.json index e6b1a56b81a..82010fffb1f 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 7e22fdf1975..dc5d5b11a63 100644 --- a/packages/eslint-plugin-tslint/project.json +++ b/packages/eslint-plugin-tslint/project.json @@ -6,9 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "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 00000000000..da4a8496b4f --- /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 30f22e9b09e..756a025eb97 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 8c19df75b90..7020b9bb7a4 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": { diff --git a/packages/eslint-plugin/project.json b/packages/eslint-plugin/project.json index 7288e9b589d..56e47529dd1 100644 --- a/packages/eslint-plugin/project.json +++ b/packages/eslint-plugin/project.json @@ -6,9 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/eslint-plugin/rules.d.ts b/packages/eslint-plugin/rules.d.ts index 1778ba33ca7..71745fe4ef7 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 635577ad41d..f211b9dc1bd 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` - import type { ClassicConfig } from '@typescript-eslint/utils/ts-eslint'; export = { diff --git a/packages/eslint-plugin/src/configs/disable-type-checked.ts b/packages/eslint-plugin/src/configs/disable-type-checked.ts index 14b710d8f85..09a5c07fd3e 100644 --- a/packages/eslint-plugin/src/configs/disable-type-checked.ts +++ b/packages/eslint-plugin/src/configs/disable-type-checked.ts @@ -8,7 +8,7 @@ import type { ClassicConfig } from '@typescript-eslint/utils/ts-eslint'; 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 00000000000..aafff1c61c1 --- /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 5f1b184c454..a141543b588 100644 --- a/packages/eslint-plugin/src/configs/eslint-recommended.ts +++ b/packages/eslint-plugin/src/configs/eslint-recommended.ts @@ -3,34 +3,11 @@ * - disables rules from eslint:recommended which are already handled by TypeScript. * - enables rules that make sense due to TS's typechecking / transpilation. */ + import type { ClassicConfig } from '@typescript-eslint/utils/ts-eslint'; +import eslintRecommended_raw from './eslint-recommended-raw'; + 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')], } satisfies ClassicConfig.Config; diff --git a/packages/integration-tests/project.json b/packages/integration-tests/project.json index 03d6a94e4a9..0299e92d157 100644 --- a/packages/integration-tests/project.json +++ b/packages/integration-tests/project.json @@ -6,9 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/parser/project.json b/packages/parser/project.json index ae6d7311c39..94b5289ff17 100644 --- a/packages/parser/project.json +++ b/packages/parser/project.json @@ -6,9 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/parser/src/parser.ts b/packages/parser/src/parser.ts index 8577dd61bcc..17c5a2ff61b 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/project.json b/packages/repo-tools/project.json index 004771f02e5..e90305a7593 100644 --- a/packages/repo-tools/project.json +++ b/packages/repo-tools/project.json @@ -6,9 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/repo-tools/src/generate-configs.mts b/packages/repo-tools/src/generate-configs.mts index 58ab129a8a8..acf7819a461 100644 --- a/packages/repo-tools/src/generate-configs.mts +++ b/packages/repo-tools/src/generate-configs.mts @@ -1,16 +1,21 @@ -import * as fs from 'node:fs'; -import * as path from 'node:path'; +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 prettier from 'prettier'; -import { PACKAGES_ESLINT_PLUGIN, REPO_ROOT } from './paths.mts'; +import { + PACKAGES_ESLINT_PLUGIN, + PACKAGES_TYPESCRIPT_ESLINT, + PRETTIER_CONFIG_PATH, +} from './paths.mts'; // no need for us to bring in an entire dependency for a few simple terminal colors const chalk = { @@ -31,12 +36,30 @@ const AUTO_GENERATED_COMMENT_LINES = [ '', ] 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 { - function addAutoGeneratedComment(code: string): string { + function addAutoGeneratedComment(code?: string): string { return [...AUTO_GENERATED_COMMENT_LINES, code].join('\n'); } - const prettierConfig = await prettier.resolveConfig(REPO_ROOT); + const prettierConfig = await prettier.resolveConfig('file.ts', { + config: PRETTIER_CONFIG_PATH, + }); type LinterConfigRules = Record; @@ -63,7 +86,6 @@ async function main(): Promise { ] as const, ), ); - const EXTENDS = ['./configs/base', './configs/eslint-recommended']; type RuleEntry = [string, RuleModule]; @@ -141,38 +163,101 @@ 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 = [ + const classicCode = [ "import type { ClassicConfig } from '@typescript-eslint/utils/ts-eslint';", '', - `export = ${JSON.stringify(getConfig())} satisfies ClassicConfig.Config;`, + `export = ${JSON.stringify(config)} satisfies ClassicConfig.Config;`, ].join('\n'); - const configStr = await prettier.format(addAutoGeneratedComment(code), { + 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.join(PACKAGES_ESLINT_PLUGIN, 'src', 'configs', `${name}.ts`), - configStr, + path.join(PACKAGES_TYPESCRIPT_ESLINT, '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), {}, @@ -190,28 +275,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: { @@ -262,7 +325,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-lib.mts b/packages/repo-tools/src/generate-lib.mts index bb169f8a138..a66ccea5db3 100644 --- a/packages/repo-tools/src/generate-lib.mts +++ b/packages/repo-tools/src/generate-lib.mts @@ -16,7 +16,12 @@ import prettier from 'prettier'; import { rimraf } from 'rimraf'; import ts from 'typescript'; -import { PACKAGES_SCOPE_MANAGER, PACKAGES_TYPES, REPO_ROOT } from './paths.mts'; +import { + PACKAGES_SCOPE_MANAGER, + PACKAGES_TYPES, + PRETTIER_CONFIG_PATH, + REPO_ROOT, +} from './paths.mts'; function parseAndAnalyze( code: string, @@ -57,7 +62,9 @@ function addAutoGeneratedComment(code: string[]): string { ].join('\n'); } -const PRETTIER_CONFIG = prettier.resolveConfig(REPO_ROOT); +const PRETTIER_CONFIG = prettier.resolveConfig('file.ts', { + config: PRETTIER_CONFIG_PATH, +}); 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'); diff --git a/packages/repo-tools/src/generate-sponsors.mts b/packages/repo-tools/src/generate-sponsors.mts index fbb4530e79d..142029a6133 100644 --- a/packages/repo-tools/src/generate-sponsors.mts +++ b/packages/repo-tools/src/generate-sponsors.mts @@ -3,7 +3,7 @@ import * as fs from 'fs'; import * as path from 'path'; import prettier from 'prettier'; -import { PACKAGES_WEBSITE } from './paths.mjs'; +import { PACKAGES_WEBSITE } from './paths.mts'; const graphqlEndpoint = 'https://api.opencollective.com/graphql/v2'; diff --git a/packages/repo-tools/src/paths.mts b/packages/repo-tools/src/paths.mts index c5dd2b2889c..6f761c6877c 100644 --- a/packages/repo-tools/src/paths.mts +++ b/packages/repo-tools/src/paths.mts @@ -9,4 +9,9 @@ export const PACKAGES = path.join(REPO_ROOT, 'packages'); 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_TYPESCRIPT_ESLINT = path.join( + PACKAGES, + 'typescript-eslint', +); export const PACKAGES_WEBSITE = path.join(PACKAGES, 'website'); +export const PRETTIER_CONFIG_PATH = path.join(REPO_ROOT, '.prettierrc.json'); diff --git a/packages/repo-tools/tsconfig.build.json b/packages/repo-tools/tsconfig.build.json index b9ac3e1b977..992e2f19be7 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 608360d9e21..266c06799b2 100644 --- a/packages/rule-schema-to-typescript-types/project.json +++ b/packages/rule-schema-to-typescript-types/project.json @@ -6,9 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/scope-manager/project.json b/packages/scope-manager/project.json index d289b7c2265..7dbb09b7608 100644 --- a/packages/scope-manager/project.json +++ b/packages/scope-manager/project.json @@ -51,9 +51,7 @@ }, "lint": { "executor": "@nx/eslint:lint", - "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 b8e6995299c..4ac211280e6 100644 --- a/packages/type-utils/project.json +++ b/packages/type-utils/project.json @@ -6,9 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/types/project.json b/packages/types/project.json index e816e6460a9..d470995b1e1 100644 --- a/packages/types/project.json +++ b/packages/types/project.json @@ -6,9 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/types/src/parser-options.ts b/packages/types/src/parser-options.ts index 12f5e20144d..e84e3ab2566 100644 --- a/packages/types/src/parser-options.ts +++ b/packages/types/src/parser-options.ts @@ -62,7 +62,7 @@ interface ParserOptions { filePath?: string; jsDocParsingMode?: JSDocParsingMode; loc?: boolean; - programs?: Program | null; + programs?: Program[] | null; project?: string[] | string | boolean | null; projectFolderIgnoreList?: (RegExp | string)[]; range?: boolean; 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 00000000000..88b83019e01 --- /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 39431a7e3f5..a4ecb716da8 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 75cd8266b5e..f30e095e652 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 00000000000..51af07ca639 --- /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 [ + * { + * ...eslint.configs.recommended, + * files: ['** /*.ts'], + * }, + * ...tseslint.configs.recommended.map(conf => ({ + * ...conf, + * files: ['** /*.ts'], + * })), + * { + * 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'; + * + * export default tseslint.config( + * eslint.configs.recommended, + * ...tseslint.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 00000000000..f891ff9b92f --- /dev/null +++ b/packages/typescript-eslint/src/configs/all.ts @@ -0,0 +1,166 @@ +// 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-find': '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 00000000000..a25249a1822 --- /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 00000000000..da3a0b7256d --- /dev/null +++ b/packages/typescript-eslint/src/configs/disable-type-checked.ts @@ -0,0 +1,68 @@ +// 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-find': '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 00000000000..b9885922ecc --- /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 00000000000..7d9ac811e1c --- /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 00000000000..ae5103d9fea --- /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 00000000000..c1c4628d0cd --- /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 00000000000..e54b7d07322 --- /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 00000000000..3923973100b --- /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 00000000000..4db1a78f9a0 --- /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 8a15f9183b5..ea63e2c9301 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 00000000000..1b88f58b6e9 --- /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 721f067fa2d..231f8f93a01 100644 --- a/packages/typescript-estree/project.json +++ b/packages/typescript-estree/project.json @@ -6,9 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/utils/project.json b/packages/utils/project.json index e4fe0453ec4..fe765a0faff 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -6,9 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/visitor-keys/project.json b/packages/visitor-keys/project.json index 88d75e2b244..d1536ce04de 100644 --- a/packages/visitor-keys/project.json +++ b/packages/visitor-keys/project.json @@ -6,9 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/website-eslint/package.json b/packages/website-eslint/package.json index 41df425383d..6408c38f62b 100644 --- a/packages/website-eslint/package.json +++ b/packages/website-eslint/package.json @@ -27,7 +27,7 @@ "@typescript-eslint/utils": "6.21.0" }, "devDependencies": { - "@eslint/js": "8.56.0", + "@eslint/js": "*", "@typescript-eslint/eslint-plugin": "6.21.0", "@typescript-eslint/parser": "6.21.0", "@typescript-eslint/scope-manager": "6.21.0", diff --git a/packages/website-eslint/project.json b/packages/website-eslint/project.json index 79f41a0c16a..52ed1e539c3 100644 --- a/packages/website-eslint/project.json +++ b/packages/website-eslint/project.json @@ -6,9 +6,7 @@ "targets": { "lint": { "executor": "@nx/eslint:lint", - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/website/project.json b/packages/website/project.json index 8ff9f56ffdf..c9b3f62d96f 100644 --- a/packages/website/project.json +++ b/packages/website/project.json @@ -14,9 +14,7 @@ }, "lint": { "executor": "@nx/eslint:lint", - "options": { - "ignorePath": ".eslintignore" - } + "outputs": ["{options.outputFile}"] } } } diff --git a/packages/website/sidebars/sidebar.base.js b/packages/website/sidebars/sidebar.base.js index b4f68f1ac8d..4184f99dad0 100644 --- a/packages/website/sidebars/sidebar.base.js +++ b/packages/website/sidebars/sidebar.base.js @@ -72,6 +72,7 @@ module.exports = { 'packages/rule-tester', 'packages/scope-manager', 'packages/typescript-estree', + 'packages/typescript-eslint', 'packages/utils', ], label: 'Packages', diff --git a/tsconfig.base.json b/tsconfig.base.json index fd7ed6a809f..a00dd38697a 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 68% rename from tsconfig.eslint.json rename to tsconfig.json index 7e9f118ed40..91c6d707c01 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.json @@ -2,15 +2,18 @@ "compilerOptions": { "types": ["@types/node"], "noEmit": true, - "allowJs": true + "allowJs": true, }, "extends": "./tsconfig.base.json", "include": [ + "typings", "tools/**/*.ts", "tools/**/*.mts", ".eslintrc.js", + "eslint.config.js", + "eslint.config.mjs", "jest.config.base.js", "jest.config.js", - "jest.preset.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 00000000000..279a27f80fa --- /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 00000000000..f0afd05081f --- /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 00000000000..60742fad493 --- /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 00000000000..c7ccc8577e8 --- /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 00000000000..3f7082bb233 --- /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 00000000000..d5fba291eb1 --- /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 00000000000..ff5f964ccc0 --- /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 00000000000..d1199b9c685 --- /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 00000000000..fd515a9f662 --- /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 00000000000..fa0e2752590 --- /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 00000000000..78462ba5c88 --- /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 00000000000..6e50127f6b4 --- /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 326bf00e0be..d1eb45bf973 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4099,7 +4099,14 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:8.56.0": +"@eslint/js@npm:*": + version: 8.53.0 + resolution: "@eslint/js@npm:8.53.0" + checksum: e0d5cfb0000aaee237c8e6d6d6e366faa60b1ef7f928ce17778373aa44d3b886368f6d5e1f97f913f0f16801aad016db8b8df78418c9d18825c15590328028af + languageName: node + linkType: hard + +"@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 @@ -4130,13 +4137,13 @@ __metadata: linkType: hard "@humanwhocodes/config-array@npm:^0.11.13": - version: 0.11.14 - resolution: "@humanwhocodes/config-array@npm:0.11.14" + version: 0.11.13 + resolution: "@humanwhocodes/config-array@npm:0.11.13" dependencies: - "@humanwhocodes/object-schema": ^2.0.2 - debug: ^4.3.1 + "@humanwhocodes/object-schema": ^2.0.1 + debug: ^4.1.1 minimatch: ^3.0.5 - checksum: 861ccce9eaea5de19546653bccf75bf09fe878bc39c3aab00aeee2d2a0e654516adad38dd1098aab5e3af0145bbcbf3f309bdf4d964f8dab9dcd5834ae4c02f2 + checksum: f8ea57b0d7ed7f2d64cd3944654976829d9da91c04d9c860e18804729a33f7681f78166ef4c761850b8c324d362f7d53f14c5c44907a6b38b32c703ff85e4805 languageName: node linkType: hard @@ -4147,10 +4154,10 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/object-schema@npm:^2.0.2": - version: 2.0.2 - resolution: "@humanwhocodes/object-schema@npm:2.0.2" - checksum: 2fc11503361b5fb4f14714c700c02a3f4c7c93e9acd6b87a29f62c522d90470f364d6161b03d1cc618b979f2ae02aed1106fd29d302695d8927e2fc8165ba8ee +"@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 @@ -4785,6 +4792,27 @@ __metadata: languageName: node linkType: hard +"@nx/eslint@patch:@nx/eslint@npm%3A17.3.1#./.yarn/patches/@nx-eslint-npm-17.3.1-a2f85d8c50.patch::locator=%40typescript-eslint%2Ftypescript-eslint%40workspace%3A.": + version: 17.3.1 + resolution: "@nx/eslint@patch:@nx/eslint@npm%3A17.3.1#./.yarn/patches/@nx-eslint-npm-17.3.1-a2f85d8c50.patch::version=17.3.1&hash=406746&locator=%40typescript-eslint%2Ftypescript-eslint%40workspace%3A." + dependencies: + "@nx/devkit": 17.3.1 + "@nx/js": 17.3.1 + "@nx/linter": 17.3.1 + tslib: ^2.3.0 + typescript: ~5.3.2 + peerDependencies: + eslint: ^8.0.0 + js-yaml: 4.1.0 + peerDependenciesMeta: + eslint: + optional: true + js-yaml: + optional: true + checksum: 6fb0c072953a2a6d64a038590b4dbda134b55f32a1c12d2913a5de91f4208cd9b6dde866c4e15ba8ed6115a69d36f2cbf5cc72a53c8fcdaf96cf2b96060131b2 + languageName: node + linkType: hard + "@nx/jest@npm:17.3.1": version: 17.3.1 resolution: "@nx/jest@npm:17.3.1" @@ -6476,6 +6504,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.3.1 "@nx/jest": 17.3.1 "@nx/workspace": 17.3.1 @@ -6513,6 +6543,7 @@ __metadata: eslint-plugin-unicorn: ^50.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 @@ -6653,7 +6684,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.21.0 "@typescript-eslint/parser": 6.21.0 "@typescript-eslint/scope-manager": 6.21.0 @@ -11621,6 +11652,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"