diff --git a/src/index.ts b/src/index.ts index 5345cd55..11c52431 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,6 @@ import { TSESLint } from '@typescript-eslint/utils' -import { parser, plugin as tseslintPlugin } from 'typescript-eslint' -import eslintCommentsPlugin from 'eslint-plugin-eslint-comments' -import importPlugin from 'eslint-plugin-import' -import nPlugin from 'eslint-plugin-n' -import promisePlugin from 'eslint-plugin-promise' -import { rules } from './rules.js' +import { parser } from 'typescript-eslint' +import { rules, plugins } from './rules.js' const eslintRuleNames = [ ...new TSESLint.Linter({ configType: 'eslintrc' }).getRules().keys(), @@ -25,13 +21,7 @@ const config: TSESLint.FlatConfig.Config = { projectService: true, }, }, - plugins: { - '@typescript-eslint': tseslintPlugin, - 'eslint-comments': eslintCommentsPlugin, - import: importPlugin, - n: nPlugin, - promise: promisePlugin, - }, + plugins, rules: { ...Object.fromEntries( namesOfEslintRulesForWhichWeAreUsingTsEquivalents.map((name) => [ diff --git a/src/rules.ts b/src/rules.ts index 2580a480..3cb91e84 100644 --- a/src/rules.ts +++ b/src/rules.ts @@ -1,449 +1,48 @@ import type { TSESLint } from '@typescript-eslint/utils' +import _ from 'lodash' -export const tseslintRules: Record = { - '@typescript-eslint/adjacent-overload-signatures': ['error'], - '@typescript-eslint/array-type': ['error', { default: 'array-simple' }], - '@typescript-eslint/await-thenable': ['error'], - '@typescript-eslint/ban-ts-comment': [ - 'error', - { - 'ts-expect-error': 'allow-with-description', - 'ts-ignore': true, - 'ts-nocheck': true, - 'ts-check': false, - // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- just enough to prevent abbreviations - minimumDescriptionLength: 3, - }, - ], - '@typescript-eslint/ban-tslint-comment': ['error'], - '@typescript-eslint/class-literal-property-style': ['error', 'fields'], - '@typescript-eslint/class-methods-use-this': [ - 'error', - { - exceptMethods: [], - enforceForClassFields: true, - ignoreOverrideMethods: false, - ignoreClassesThatImplementAnInterface: false, - }, - ], - '@typescript-eslint/consistent-generic-constructors': [ - 'error', - 'constructor', - ], - '@typescript-eslint/consistent-indexed-object-style': ['error', 'record'], - '@typescript-eslint/consistent-type-assertions': [ - 'error', - { - assertionStyle: 'as', - objectLiteralTypeAssertions: 'never', - }, - ], - '@typescript-eslint/consistent-type-definitions': ['error', 'interface'], - '@typescript-eslint/consistent-type-exports': [ - 'error', - { - fixMixedExportsWithInlineTypeSpecifier: true, - }, - ], - '@typescript-eslint/consistent-type-imports': [ - 'error', - { - prefer: 'type-imports', - disallowTypeAnnotations: true, - fixStyle: 'inline-type-imports', - }, - ], - '@typescript-eslint/dot-notation': [ - 'error', - { - allowIndexSignaturePropertyAccess: false, - allowKeywords: true, - allowPattern: '', - allowPrivateClassPropertyAccess: false, - allowProtectedClassPropertyAccess: false, - }, - ], - '@typescript-eslint/explicit-function-return-type': [ - 'error', - { - allowExpressions: true, - allowHigherOrderFunctions: true, - allowTypedFunctionExpressions: true, - allowDirectConstAssertionInArrowFunctions: true, - }, - ], - '@typescript-eslint/init-declarations': ['error', 'always'], - // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- an arbitrary count - '@typescript-eslint/max-params': ['error', { max: 4 }], - '@typescript-eslint/method-signature-style': ['error'], - '@typescript-eslint/naming-convention': [ - 'error', - { - selector: 'variableLike', - leadingUnderscore: 'allow', - trailingUnderscore: 'allow', - format: ['camelCase', 'PascalCase', 'UPPER_CASE'], - }, - ], - '@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', - { ignoreArrowShorthand: false, ignoreVoidOperator: false }, - ], - '@typescript-eslint/no-deprecated': ['warn'], - '@typescript-eslint/no-dupe-class-members': ['error'], - '@typescript-eslint/no-duplicate-enum-values': ['error'], - '@typescript-eslint/no-duplicate-type-constituents': [ - 'error', - { ignoreIntersections: false, ignoreUnions: false }, - ], - '@typescript-eslint/no-dynamic-delete': ['error'], - '@typescript-eslint/no-empty-function': [ - 'error', - { - allow: [], - }, - ], - '@typescript-eslint/no-empty-object-type': [ - 'error', - { allowInterfaces: 'with-single-extends', allowObjectTypes: 'never' }, - ], - '@typescript-eslint/no-explicit-any': [ - 'error', - { fixToUnknown: false, ignoreRestArgs: false }, - ], - '@typescript-eslint/no-extra-non-null-assertion': ['error'], - '@typescript-eslint/no-extraneous-class': [ - 'error', - { allowWithDecorator: true }, - ], - '@typescript-eslint/no-floating-promises': ['error'], - '@typescript-eslint/no-for-in-array': ['error'], - '@typescript-eslint/no-implied-eval': ['error'], - '@typescript-eslint/no-import-type-side-effects': ['error'], - '@typescript-eslint/no-inferrable-types': [ - 'error', - { ignoreParameters: false, ignoreProperties: false }, - ], - '@typescript-eslint/no-invalid-void-type': ['error'], - '@typescript-eslint/no-loop-func': ['error'], - '@typescript-eslint/no-magic-numbers': [ - 'error', - { - ignore: [], - ignoreArrayIndexes: false, - ignoreDefaultValues: false, - ignoreClassFieldInitialValues: false, - // https://github.com/mightyiam/eslint-config-love/issues/1786 - enforceConst: false, - detectObjects: true, - ignoreEnums: true, - ignoreNumericLiteralTypes: false, - ignoreReadonlyClassProperties: true, - ignoreTypeIndexes: false, - }, - ], - '@typescript-eslint/no-meaningless-void-operator': [ - 'error', - { checkNever: true }, - ], - '@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-require-imports': [ - 'error', - { allow: [], allowAsImport: false }, - ], - '@typescript-eslint/no-this-alias': ['error', { allowDestructuring: true }], - '@typescript-eslint/no-unnecessary-boolean-literal-compare': ['error'], - '@typescript-eslint/no-unnecessary-condition': [ - 'error', - { - allowConstantLoopConditions: true, - }, - ], - '@typescript-eslint/no-unnecessary-parameter-property-assignment': ['error'], - '@typescript-eslint/no-unnecessary-qualifier': ['error'], - '@typescript-eslint/no-unnecessary-template-expression': ['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-unnecessary-type-parameters': ['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-function-type': ['error'], - '@typescript-eslint/no-unsafe-member-access': ['error'], - '@typescript-eslint/no-unsafe-return': ['error'], - '@typescript-eslint/no-unsafe-unary-minus': ['error'], - '@typescript-eslint/no-unused-expressions': [ - 'error', - { - allowShortCircuit: true, - allowTernary: true, - allowTaggedTemplates: true, - enforceForJSX: false, - }, - ], - '@typescript-eslint/no-unused-vars': [ - 'error', - { - args: 'none', - caughtErrors: 'none', - ignoreRestSiblings: true, - vars: 'all', - }, - ], - '@typescript-eslint/no-use-before-define': [ - 'error', - { - functions: false, - classes: false, - enums: false, - variables: false, - typedefs: false, - }, - ], - '@typescript-eslint/no-useless-constructor': ['error'], - '@typescript-eslint/no-useless-empty-export': ['error'], - '@typescript-eslint/no-wrapper-object-types': ['error'], - '@typescript-eslint/non-nullable-type-assertion-style': ['error'], - '@typescript-eslint/only-throw-error': [ - 'error', - { allowThrowingAny: false, allowThrowingUnknown: false }, - ], - '@typescript-eslint/prefer-as-const': ['error'], - '@typescript-eslint/prefer-destructuring': [ - 'error', - { array: true, object: true }, - { - enforceForRenamedProperties: true, - enforceForDeclarationWithTypeAnnotation: false, - }, - ], - '@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', - { allowBitwiseExpressions: true }, - ], - '@typescript-eslint/prefer-namespace-keyword': ['error'], - '@typescript-eslint/prefer-nullish-coalescing': [ - 'error', - { ignoreConditionalTests: false, ignoreMixedLogicalExpressions: false }, - ], - '@typescript-eslint/prefer-optional-chain': ['error'], - '@typescript-eslint/prefer-promise-reject-errors': ['error'], - '@typescript-eslint/prefer-readonly': ['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', - { allowSingleElementEquality: 'never' }, - ], - '@typescript-eslint/promise-function-async': ['error'], - '@typescript-eslint/require-array-sort-compare': [ - 'error', - { ignoreStringArrays: true }, - ], - '@typescript-eslint/restrict-plus-operands': [ - 'error', - { skipCompoundAssignments: false }, - ], - '@typescript-eslint/restrict-template-expressions': [ - 'error', - { allowNumber: true }, - ], - '@typescript-eslint/return-await': ['error', 'always'], - '@typescript-eslint/strict-boolean-expressions': [ - 'error', - { - allowString: false, - allowNumber: false, - allowNullableObject: false, - allowNullableBoolean: false, - allowNullableString: false, - allowNullableNumber: false, - allowAny: false, - }, - ], - '@typescript-eslint/triple-slash-reference': [ - 'error', - { lib: 'never', path: 'never', types: 'never' }, - ], - '@typescript-eslint/unbound-method': ['error', { ignoreStatic: false }], -} +import eslintCommentsRules from './rules/eslint-comments.js' +import eslintRules from './rules/eslint.js' +import nRules from './rules/n.js' +import promiseRules from './rules/promise.js' +import typescriptEslint from './rules/typescript-eslint.js' +import importRules from './rules/import.js' -export const eslintRules: Record = { - 'accessor-pairs': [ - 'error', - { setWithoutGet: true, getWithoutSet: false, enforceForClassMembers: true }, - ], - 'array-callback-return': [ - 'error', - { - allowImplicit: false, - allowVoid: false, - checkForEach: false, - }, - ], - 'arrow-body-style': [ - 'error', - 'as-needed', - { requireReturnForObjectLiteral: false }, - ], - 'constructor-super': ['error'], - curly: ['error', 'multi-line'], - 'default-case-last': ['error'], - eqeqeq: ['error', 'always', { null: 'ignore' }], - 'new-cap': ['error', { newIsCap: true, capIsNew: false, properties: true }], - 'no-async-promise-executor': ['error'], - 'no-caller': ['error'], - 'no-case-declarations': ['error'], - 'no-class-assign': ['error'], - 'no-compare-neg-zero': ['error'], - 'no-cond-assign': ['error'], - 'no-const-assign': ['error'], - 'no-constant-condition': ['error', { checkLoops: false }], - 'no-control-regex': ['error'], - 'no-debugger': ['error'], - 'no-delete-var': ['error'], - 'no-dupe-args': ['error'], - 'no-dupe-keys': ['error'], - 'no-duplicate-case': ['error'], - 'no-empty': ['error', { allowEmptyCatch: true }], - 'no-empty-character-class': ['error'], - 'no-empty-pattern': ['error'], - 'no-eval': ['error'], - 'no-ex-assign': ['error'], - 'no-extend-native': ['error'], - 'no-extra-bind': ['error'], - 'no-extra-boolean-cast': ['error'], - 'no-fallthrough': ['error'], - 'no-func-assign': ['error'], - 'no-global-assign': ['error'], - 'no-import-assign': ['error'], - 'no-invalid-regexp': ['error'], - 'no-irregular-whitespace': ['error'], - 'no-iterator': ['error'], - 'no-labels': ['error', { allowLoop: false, allowSwitch: false }], - 'no-lone-blocks': ['error'], - 'no-loss-of-precision': ['error'], - 'no-misleading-character-class': ['error'], - 'no-multi-str': ['error'], - 'no-new': ['error'], - 'no-new-func': ['error'], - 'no-new-native-nonconstructor': ['error'], - 'no-new-wrappers': ['error'], - 'no-obj-calls': ['error'], - 'no-object-constructor': ['error'], - 'no-octal': ['error'], - 'no-octal-escape': ['error'], - 'no-proto': ['error'], - 'no-prototype-builtins': ['error'], - 'no-regex-spaces': ['error'], - 'no-return-assign': ['error', 'except-parens'], - 'no-self-assign': ['error', { props: true }], - 'no-self-compare': ['error'], - 'no-sequences': ['error'], - 'no-shadow-restricted-names': ['error'], - 'no-sparse-arrays': ['error'], - 'no-template-curly-in-string': ['error'], - 'no-this-before-super': ['error'], - 'no-throw-literal': ['off'], - 'no-unexpected-multiline': ['error'], - 'no-unmodified-loop-condition': ['error'], - 'no-unneeded-ternary': ['error', { defaultAssignment: false }], - 'no-unreachable': ['error'], - 'no-unreachable-loop': ['error'], - 'no-unsafe-finally': ['error'], - 'no-unsafe-negation': ['error'], - 'no-useless-backreference': ['error'], - 'no-useless-call': ['error'], - 'no-useless-catch': ['error'], - 'no-useless-computed-key': ['error'], - 'no-useless-escape': ['error'], - 'no-useless-rename': ['error'], - 'no-useless-return': ['error'], - 'no-var': ['error'], - 'no-void': ['error', { allowAsStatement: true }], - 'no-with': ['error'], - 'object-shorthand': ['warn', 'properties'], - 'one-var': ['error', { initialized: 'never' }], - 'prefer-const': [ - 'error', - { destructuring: 'all', ignoreReadBeforeAssign: false }, - ], - 'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }], - 'symbol-description': ['error'], - 'unicode-bom': ['error', 'never'], - 'use-isnan': [ - 'error', - { - enforceForSwitchCase: true, - enforceForIndexOf: true, - }, - ], - 'valid-typeof': ['error', { requireStringLiterals: true }], - yoda: ['error', 'never'], +export interface PluginUsage { + pluginName: string + plugin: TSESLint.FlatConfig.Plugin | 'eslint' + rules: Record } -export const eslintCommentsRules: Record< - string, - TSESLint.SharedConfig.RuleEntry -> = { - 'eslint-comments/require-description': [ - 'error', - { - ignore: ['eslint-enable', 'eslint-env'], - }, - ], -} +const imports: PluginUsage[] = [ + typescriptEslint, + eslintCommentsRules, + eslintRules, + nRules, + promiseRules, + importRules, +] -export const importRules: Record = { - 'import/export': ['error'], - 'import/first': ['error'], - 'import/no-absolute-path': [ - 'error', - { esmodule: true, commonjs: true, amd: false }, - ], - 'import/no-duplicates': ['error'], - 'import/no-named-default': ['error'], - 'import/no-webpack-loader-syntax': ['error'], +interface Exports { + rulesPerPlugin: Record + rules: TSESLint.SharedConfig.RulesRecord + plugins: Record } -export const nRules: Record = { - 'n/handle-callback-err': ['error', '^(err|error)$'], - 'n/no-callback-literal': ['error'], - 'n/no-deprecated-api': ['error'], - 'n/no-exports-assign': ['error'], - 'n/no-new-require': ['error'], - 'n/no-path-concat': ['error'], - 'n/process-exit-as-throw': ['error'], -} +export const { rulesPerPlugin, rules, plugins }: Exports = + imports.reduce( + (acc, { pluginName, plugin, rules: localRules }) => { + if (plugin !== 'eslint') { + acc.plugins[pluginName] = plugin + } -export const promiseRules: Record = { - 'promise/param-names': ['error'], -} + const rules = _.mapKeys(localRules, (_rule, localRuleName) => + plugin === 'eslint' ? localRuleName : `${pluginName}/${localRuleName}`, + ) + acc.rulesPerPlugin[pluginName] = rules + acc.rules = { ...acc.rules, ...rules } -export const rules: Record = { - ...eslintCommentsRules, - ...eslintRules, - ...importRules, - ...nRules, - ...promiseRules, - ...tseslintRules, -} + return acc + }, + { rulesPerPlugin: {}, rules: {}, plugins: {} }, + ) diff --git a/src/rules/eslint-comments.ts b/src/rules/eslint-comments.ts new file mode 100644 index 00000000..b6f628e4 --- /dev/null +++ b/src/rules/eslint-comments.ts @@ -0,0 +1,17 @@ +import plugin from 'eslint-plugin-eslint-comments' +import type { PluginUsage } from '../rules.js' + +const rules: PluginUsage = { + pluginName: 'eslint-comments', + plugin, + rules: { + 'require-description': [ + 'error', + { + ignore: ['eslint-enable', 'eslint-env'], + }, + ], + }, +} + +export default rules diff --git a/src/rules/eslint.ts b/src/rules/eslint.ts new file mode 100644 index 00000000..34f4300c --- /dev/null +++ b/src/rules/eslint.ts @@ -0,0 +1,125 @@ +import type { PluginUsage } from '../rules.js' + +const rules: PluginUsage = { + pluginName: '', + plugin: 'eslint', + rules: { + 'accessor-pairs': [ + 'error', + { + setWithoutGet: true, + getWithoutSet: false, + enforceForClassMembers: true, + }, + ], + 'array-callback-return': [ + 'error', + { + allowImplicit: false, + allowVoid: false, + checkForEach: false, + }, + ], + 'arrow-body-style': [ + 'error', + 'as-needed', + { requireReturnForObjectLiteral: false }, + ], + 'constructor-super': ['error'], + curly: ['error', 'multi-line'], + 'default-case-last': ['error'], + eqeqeq: ['error', 'always', { null: 'ignore' }], + 'new-cap': ['error', { newIsCap: true, capIsNew: false, properties: true }], + 'no-async-promise-executor': ['error'], + 'no-caller': ['error'], + 'no-case-declarations': ['error'], + 'no-class-assign': ['error'], + 'no-compare-neg-zero': ['error'], + 'no-cond-assign': ['error'], + 'no-const-assign': ['error'], + 'no-constant-condition': ['error', { checkLoops: false }], + 'no-control-regex': ['error'], + 'no-debugger': ['error'], + 'no-delete-var': ['error'], + 'no-dupe-args': ['error'], + 'no-dupe-keys': ['error'], + 'no-duplicate-case': ['error'], + 'no-empty': ['error', { allowEmptyCatch: true }], + 'no-empty-character-class': ['error'], + 'no-empty-pattern': ['error'], + 'no-eval': ['error'], + 'no-ex-assign': ['error'], + 'no-extend-native': ['error'], + 'no-extra-bind': ['error'], + 'no-extra-boolean-cast': ['error'], + 'no-fallthrough': ['error'], + 'no-func-assign': ['error'], + 'no-global-assign': ['error'], + 'no-import-assign': ['error'], + 'no-invalid-regexp': ['error'], + 'no-irregular-whitespace': ['error'], + 'no-iterator': ['error'], + 'no-labels': ['error', { allowLoop: false, allowSwitch: false }], + 'no-lone-blocks': ['error'], + 'no-loss-of-precision': ['error'], + 'no-misleading-character-class': ['error'], + 'no-multi-str': ['error'], + 'no-new': ['error'], + 'no-new-func': ['error'], + 'no-new-native-nonconstructor': ['error'], + 'no-new-wrappers': ['error'], + 'no-obj-calls': ['error'], + 'no-object-constructor': ['error'], + 'no-octal': ['error'], + 'no-octal-escape': ['error'], + 'no-proto': ['error'], + 'no-prototype-builtins': ['error'], + 'no-regex-spaces': ['error'], + 'no-return-assign': ['error', 'except-parens'], + 'no-self-assign': ['error', { props: true }], + 'no-self-compare': ['error'], + 'no-sequences': ['error'], + 'no-shadow-restricted-names': ['error'], + 'no-sparse-arrays': ['error'], + 'no-template-curly-in-string': ['error'], + 'no-this-before-super': ['error'], + 'no-throw-literal': ['off'], + 'no-unexpected-multiline': ['error'], + 'no-unmodified-loop-condition': ['error'], + 'no-unneeded-ternary': ['error', { defaultAssignment: false }], + 'no-unreachable': ['error'], + 'no-unreachable-loop': ['error'], + 'no-unsafe-finally': ['error'], + 'no-unsafe-negation': ['error'], + 'no-useless-backreference': ['error'], + 'no-useless-call': ['error'], + 'no-useless-catch': ['error'], + 'no-useless-computed-key': ['error'], + 'no-useless-escape': ['error'], + 'no-useless-rename': ['error'], + 'no-useless-return': ['error'], + 'no-var': ['error'], + 'no-void': ['error', { allowAsStatement: true }], + 'no-with': ['error'], + 'object-shorthand': ['warn', 'properties'], + 'one-var': ['error', { initialized: 'never' }], + 'prefer-const': [ + 'error', + { destructuring: 'all', ignoreReadBeforeAssign: false }, + ], + 'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }], + 'symbol-description': ['error'], + 'unicode-bom': ['error', 'never'], + 'use-isnan': [ + 'error', + { + enforceForSwitchCase: true, + enforceForIndexOf: true, + }, + ], + 'valid-typeof': ['error', { requireStringLiterals: true }], + yoda: ['error', 'never'], + }, +} + +export default rules diff --git a/src/rules/import.ts b/src/rules/import.ts new file mode 100644 index 00000000..59e51488 --- /dev/null +++ b/src/rules/import.ts @@ -0,0 +1,20 @@ +import plugin from 'eslint-plugin-import' +import type { PluginUsage } from '../rules.js' + +const rules: PluginUsage = { + pluginName: 'import', + plugin, + rules: { + export: ['error'], + first: ['error'], + 'no-absolute-path': [ + 'error', + { esmodule: true, commonjs: true, amd: false }, + ], + 'no-duplicates': ['error'], + 'no-named-default': ['error'], + 'no-webpack-loader-syntax': ['error'], + }, +} + +export default rules diff --git a/src/rules/n.ts b/src/rules/n.ts new file mode 100644 index 00000000..41ec70f3 --- /dev/null +++ b/src/rules/n.ts @@ -0,0 +1,18 @@ +import plugin from 'eslint-plugin-n' +import type { PluginUsage } from '../rules.js' + +const rules: PluginUsage = { + pluginName: 'n', + plugin, + rules: { + 'handle-callback-err': ['error', '^(err|error)$'], + 'no-callback-literal': ['error'], + 'no-deprecated-api': ['error'], + 'no-exports-assign': ['error'], + 'no-new-require': ['error'], + 'no-path-concat': ['error'], + 'process-exit-as-throw': ['error'], + }, +} + +export default rules diff --git a/src/rules/promise.ts b/src/rules/promise.ts new file mode 100644 index 00000000..97d7c2a4 --- /dev/null +++ b/src/rules/promise.ts @@ -0,0 +1,12 @@ +import plugin from 'eslint-plugin-promise' +import type { PluginUsage } from '../rules.js' + +const rules: PluginUsage = { + pluginName: 'promise', + plugin, + rules: { + 'param-names': ['error'], + }, +} + +export default rules diff --git a/src/rules/typescript-eslint.ts b/src/rules/typescript-eslint.ts new file mode 100644 index 00000000..78e9b6f7 --- /dev/null +++ b/src/rules/typescript-eslint.ts @@ -0,0 +1,271 @@ +import type { PluginUsage } from '../rules.js' +import { plugin } from 'typescript-eslint' + +const rules: PluginUsage = { + pluginName: '@typescript-eslint', + plugin, + rules: { + 'adjacent-overload-signatures': ['error'], + 'array-type': ['error', { default: 'array-simple' }], + 'await-thenable': ['error'], + 'ban-ts-comment': [ + 'error', + { + 'ts-expect-error': 'allow-with-description', + 'ts-ignore': true, + 'ts-nocheck': true, + 'ts-check': false, + // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- just enough to prevent abbreviations + minimumDescriptionLength: 3, + }, + ], + 'ban-tslint-comment': ['error'], + 'class-literal-property-style': ['error', 'fields'], + 'class-methods-use-this': [ + 'error', + { + exceptMethods: [], + enforceForClassFields: true, + ignoreOverrideMethods: false, + ignoreClassesThatImplementAnInterface: false, + }, + ], + 'consistent-generic-constructors': ['error', 'constructor'], + 'consistent-indexed-object-style': ['error', 'record'], + 'consistent-type-assertions': [ + 'error', + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'never', + }, + ], + 'consistent-type-definitions': ['error', 'interface'], + 'consistent-type-exports': [ + 'error', + { + fixMixedExportsWithInlineTypeSpecifier: true, + }, + ], + 'consistent-type-imports': [ + 'error', + { + prefer: 'type-imports', + disallowTypeAnnotations: true, + fixStyle: 'inline-type-imports', + }, + ], + 'dot-notation': [ + 'error', + { + allowIndexSignaturePropertyAccess: false, + allowKeywords: true, + allowPattern: '', + allowPrivateClassPropertyAccess: false, + allowProtectedClassPropertyAccess: false, + }, + ], + 'explicit-function-return-type': [ + 'error', + { + allowExpressions: true, + allowHigherOrderFunctions: true, + allowTypedFunctionExpressions: true, + allowDirectConstAssertionInArrowFunctions: true, + }, + ], + 'init-declarations': ['error', 'always'], + // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- an arbitrary count + 'max-params': ['error', { max: 4 }], + 'method-signature-style': ['error'], + 'naming-convention': [ + 'error', + { + selector: 'variableLike', + leadingUnderscore: 'allow', + trailingUnderscore: 'allow', + format: ['camelCase', 'PascalCase', 'UPPER_CASE'], + }, + ], + 'no-array-constructor': ['error'], + 'no-array-delete': ['error'], + 'no-base-to-string': ['error'], + 'no-confusing-non-null-assertion': ['error'], + 'no-confusing-void-expression': [ + 'error', + { ignoreArrowShorthand: false, ignoreVoidOperator: false }, + ], + 'no-deprecated': ['warn'], + 'no-dupe-class-members': ['error'], + 'no-duplicate-enum-values': ['error'], + 'no-duplicate-type-constituents': [ + 'error', + { ignoreIntersections: false, ignoreUnions: false }, + ], + 'no-dynamic-delete': ['error'], + 'no-empty-function': [ + 'error', + { + allow: [], + }, + ], + 'no-empty-object-type': [ + 'error', + { allowInterfaces: 'with-single-extends', allowObjectTypes: 'never' }, + ], + 'no-explicit-any': [ + 'error', + { fixToUnknown: false, ignoreRestArgs: false }, + ], + 'no-extra-non-null-assertion': ['error'], + 'no-extraneous-class': ['error', { allowWithDecorator: true }], + 'no-floating-promises': ['error'], + 'no-for-in-array': ['error'], + 'no-implied-eval': ['error'], + 'no-import-type-side-effects': ['error'], + 'no-inferrable-types': [ + 'error', + { ignoreParameters: false, ignoreProperties: false }, + ], + 'no-invalid-void-type': ['error'], + 'no-loop-func': ['error'], + 'no-magic-numbers': [ + 'error', + { + ignore: [], + ignoreArrayIndexes: false, + ignoreDefaultValues: false, + ignoreClassFieldInitialValues: false, + // https://github.com/mightyiam/eslint-config-love/issues/1786 + enforceConst: false, + detectObjects: true, + ignoreEnums: true, + ignoreNumericLiteralTypes: false, + ignoreReadonlyClassProperties: true, + ignoreTypeIndexes: false, + }, + ], + 'no-meaningless-void-operator': ['error', { checkNever: true }], + 'no-misused-new': ['error'], + 'no-misused-promises': ['error'], + 'no-mixed-enums': ['error'], + 'no-namespace': ['error'], + 'no-non-null-asserted-nullish-coalescing': ['error'], + 'no-non-null-asserted-optional-chain': ['error'], + 'no-non-null-assertion': ['error'], + 'no-redundant-type-constituents': ['error'], + 'no-require-imports': ['error', { allow: [], allowAsImport: false }], + 'no-this-alias': ['error', { allowDestructuring: true }], + 'no-unnecessary-boolean-literal-compare': ['error'], + 'no-unnecessary-condition': [ + 'error', + { + allowConstantLoopConditions: true, + }, + ], + 'no-unnecessary-parameter-property-assignment': ['error'], + 'no-unnecessary-qualifier': ['error'], + 'no-unnecessary-template-expression': ['error'], + 'no-unnecessary-type-arguments': ['error'], + 'no-unnecessary-type-assertion': ['error'], + 'no-unnecessary-type-constraint': ['error'], + 'no-unnecessary-type-parameters': ['error'], + 'no-unsafe-argument': ['error'], + 'no-unsafe-assignment': ['error'], + 'no-unsafe-call': ['error'], + 'no-unsafe-declaration-merging': ['error'], + 'no-unsafe-enum-comparison': ['error'], + 'no-unsafe-function-type': ['error'], + 'no-unsafe-member-access': ['error'], + 'no-unsafe-return': ['error'], + 'no-unsafe-unary-minus': ['error'], + 'no-unused-expressions': [ + 'error', + { + allowShortCircuit: true, + allowTernary: true, + allowTaggedTemplates: true, + enforceForJSX: false, + }, + ], + 'no-unused-vars': [ + 'error', + { + args: 'none', + caughtErrors: 'none', + ignoreRestSiblings: true, + vars: 'all', + }, + ], + 'no-use-before-define': [ + 'error', + { + functions: false, + classes: false, + enums: false, + variables: false, + typedefs: false, + }, + ], + 'no-useless-constructor': ['error'], + 'no-useless-empty-export': ['error'], + 'no-wrapper-object-types': ['error'], + 'non-nullable-type-assertion-style': ['error'], + 'only-throw-error': [ + 'error', + { allowThrowingAny: false, allowThrowingUnknown: false }, + ], + 'prefer-as-const': ['error'], + 'prefer-destructuring': [ + 'error', + { array: true, object: true }, + { + enforceForRenamedProperties: true, + enforceForDeclarationWithTypeAnnotation: false, + }, + ], + 'prefer-find': ['error'], + 'prefer-for-of': ['error'], + 'prefer-function-type': ['error'], + 'prefer-includes': ['error'], + 'prefer-literal-enum-member': ['error', { allowBitwiseExpressions: true }], + 'prefer-namespace-keyword': ['error'], + 'prefer-nullish-coalescing': [ + 'error', + { ignoreConditionalTests: false, ignoreMixedLogicalExpressions: false }, + ], + 'prefer-optional-chain': ['error'], + 'prefer-promise-reject-errors': ['error'], + 'prefer-readonly': ['error'], + 'prefer-reduce-type-parameter': ['error'], + 'prefer-regexp-exec': ['error'], + 'prefer-return-this-type': ['error'], + 'prefer-string-starts-ends-with': [ + 'error', + { allowSingleElementEquality: 'never' }, + ], + 'promise-function-async': ['error'], + 'require-array-sort-compare': ['error', { ignoreStringArrays: true }], + 'restrict-plus-operands': ['error', { skipCompoundAssignments: false }], + 'restrict-template-expressions': ['error', { allowNumber: true }], + 'return-await': ['error', 'always'], + 'strict-boolean-expressions': [ + 'error', + { + allowString: false, + allowNumber: false, + allowNullableObject: false, + allowNullableBoolean: false, + allowNullableString: false, + allowNullableNumber: false, + allowAny: false, + }, + ], + 'triple-slash-reference': [ + 'error', + { lib: 'never', path: 'never', types: 'never' }, + ], + 'unbound-method': ['error', { ignoreStatic: false }], + }, +} + +export default rules diff --git a/src/test/_rules_to_consider.ts b/src/test/_rules_to_consider.ts index 8b7d8bda..e54914d9 100644 --- a/src/test/_rules_to_consider.ts +++ b/src/test/_rules_to_consider.ts @@ -1,206 +1,194 @@ -export const eslintCommentsRulesToConsider = [ - 'eslint-comments/disable-enable-pair', - 'eslint-comments/no-aggregating-enable', - 'eslint-comments/no-duplicate-disable', - 'eslint-comments/no-restricted-disable', - 'eslint-comments/no-unlimited-disable', - 'eslint-comments/no-unused-disable', - 'eslint-comments/no-unused-enable', - 'eslint-comments/no-use', -] - -export const eslintRulesToConsider = [ - 'block-scoped-var', - 'capitalized-comments', - 'complexity', - 'consistent-this', - 'default-case', - 'for-direction', - 'func-name-matching', - 'func-names', - 'func-style', - 'getter-return', - 'grouped-accessor-pairs', - 'guard-for-in', - 'id-denylist', - 'id-length', - 'id-match', - 'logical-assignment-operators', - 'max-classes-per-file', - 'max-depth', - 'max-lines', - 'max-lines-per-function', - 'max-nested-callbacks', - 'max-statements', - 'no-alert', - 'no-await-in-loop', - 'no-bitwise', - 'no-console', - 'no-constant-binary-expression', - 'no-constructor-return', - 'no-continue', - 'no-div-regex', - 'no-dupe-else-if', - 'no-duplicate-imports', - 'no-else-return', - 'no-empty-static-block', - 'no-eq-null', - 'no-extra-label', - 'no-implicit-coercion', - 'no-implicit-globals', - 'no-inline-comments', - 'no-inner-declarations', - 'no-invalid-this', - 'no-label-var', - 'no-lonely-if', - 'no-multi-assign', - 'no-negated-condition', - 'no-nested-ternary', - 'no-nonoctal-decimal-escape', - 'no-param-reassign', - 'no-plusplus', - 'no-promise-executor-return', - 'no-restricted-exports', - 'no-restricted-globals', - 'no-restricted-properties', - 'no-restricted-syntax', - 'no-script-url', - 'no-setter-return', - 'no-ternary', - 'no-undef', - 'no-undefined', - 'no-underscore-dangle', - 'no-unsafe-optional-chaining', - 'no-unused-labels', - 'no-unused-private-class-members', - 'no-useless-assignment', - 'no-useless-concat', - 'no-warning-comments', - 'operator-assignment', - 'prefer-arrow-callback', - 'prefer-exponentiation-operator', - 'prefer-named-capture-group', - 'prefer-numeric-literals', - 'prefer-object-has-own', - 'prefer-object-spread', - 'prefer-rest-params', - 'prefer-spread', - 'prefer-template', - 'radix', - 'require-atomic-updates', - 'require-await', - 'require-unicode-regexp', - 'require-yield', - 'sort-imports', - 'sort-keys', - 'sort-vars', - 'strict', - 'vars-on-top', -] - -export const importRulesToConsider = [ - 'import/consistent-type-specifier-style', - 'import/default', - 'import/dynamic-import-chunkname', - 'import/exports-last', - 'import/extensions', - 'import/group-exports', - 'import/max-dependencies', - 'import/named', - 'import/namespace', - 'import/newline-after-import', - 'import/no-amd', - 'import/no-anonymous-default-export', - 'import/no-commonjs', - 'import/no-cycle', - 'import/no-default-export', - 'import/no-deprecated', - 'import/no-dynamic-require', - 'import/no-empty-named-blocks', - 'import/no-extraneous-dependencies', - 'import/no-import-module-exports', - 'import/no-internal-modules', - 'import/no-mutable-exports', - 'import/no-named-as-default', - 'import/no-named-as-default-member', - 'import/no-named-export', - 'import/no-namespace', - 'import/no-nodejs-modules', - 'import/no-relative-packages', - 'import/no-relative-parent-imports', - 'import/no-restricted-paths', - 'import/no-self-import', - 'import/no-unassigned-import', - 'import/no-unresolved', - 'import/no-unused-modules', - 'import/no-useless-path-segments', - 'import/order', - 'import/prefer-default-export', - 'import/unambiguous', -] - -export const nRulesToConsider = [ - 'n/callback-return', - 'n/exports-style', - 'n/file-extension-in-import', - 'n/global-require', - 'n/hashbang', - 'n/no-extraneous-import', - 'n/no-extraneous-require', - 'n/no-missing-import', - 'n/no-missing-require', - 'n/no-mixed-requires', - 'n/no-process-env', - 'n/no-process-exit', - 'n/no-sync', - 'n/no-unpublished-bin', - 'n/no-unpublished-import', - 'n/no-unpublished-require', - 'n/no-unsupported-features/es-builtins', - 'n/no-unsupported-features/es-syntax', - 'n/no-unsupported-features/node-builtins', - 'n/prefer-global/buffer', - 'n/prefer-global/console', - 'n/prefer-global/process', - 'n/prefer-global/text-decoder', - 'n/prefer-global/text-encoder', - 'n/prefer-global/url', - 'n/prefer-global/url-search-params', - 'n/prefer-node-protocol', - 'n/prefer-promises/dns', - 'n/prefer-promises/fs', -] - -export const promiseRulesToConsider = [ - 'promise/always-return', - 'promise/avoid-new', - 'promise/catch-or-return', - 'promise/no-callback-in-promise', - 'promise/no-multiple-resolved', - 'promise/no-native', - 'promise/no-nesting', - 'promise/no-new-statics', - 'promise/no-promise-in-callback', - 'promise/no-return-in-finally', - 'promise/no-return-wrap', - 'promise/prefer-await-to-callbacks', - 'promise/prefer-await-to-then', - 'promise/spec-only', - 'promise/valid-params', -] - -export const tseslintRulesToConsider = [ - '@typescript-eslint/require-await', - '@typescript-eslint/switch-exhaustiveness-check', - '@typescript-eslint/unified-signatures', - '@typescript-eslint/use-unknown-in-catch-callback-variable', -] - -export const rulesToConsider = [ - ...eslintCommentsRulesToConsider, - ...eslintRulesToConsider, - ...importRulesToConsider, - ...nRulesToConsider, - ...promiseRulesToConsider, - ...tseslintRulesToConsider, -] +export const rulesToConsider: Record = { + 'eslint-comments': [ + 'eslint-comments/disable-enable-pair', + 'eslint-comments/no-aggregating-enable', + 'eslint-comments/no-duplicate-disable', + 'eslint-comments/no-restricted-disable', + 'eslint-comments/no-unlimited-disable', + 'eslint-comments/no-unused-disable', + 'eslint-comments/no-unused-enable', + 'eslint-comments/no-use', + ], + '': [ + 'block-scoped-var', + 'capitalized-comments', + 'complexity', + 'consistent-this', + 'default-case', + 'for-direction', + 'func-name-matching', + 'func-names', + 'func-style', + 'getter-return', + 'grouped-accessor-pairs', + 'guard-for-in', + 'id-denylist', + 'id-length', + 'id-match', + 'logical-assignment-operators', + 'max-classes-per-file', + 'max-depth', + 'max-lines', + 'max-lines-per-function', + 'max-nested-callbacks', + 'max-statements', + 'no-alert', + 'no-await-in-loop', + 'no-bitwise', + 'no-console', + 'no-constant-binary-expression', + 'no-constructor-return', + 'no-continue', + 'no-div-regex', + 'no-dupe-else-if', + 'no-duplicate-imports', + 'no-else-return', + 'no-empty-static-block', + 'no-eq-null', + 'no-extra-label', + 'no-implicit-coercion', + 'no-implicit-globals', + 'no-inline-comments', + 'no-inner-declarations', + 'no-invalid-this', + 'no-label-var', + 'no-lonely-if', + 'no-multi-assign', + 'no-negated-condition', + 'no-nested-ternary', + 'no-nonoctal-decimal-escape', + 'no-param-reassign', + 'no-plusplus', + 'no-promise-executor-return', + 'no-restricted-exports', + 'no-restricted-globals', + 'no-restricted-properties', + 'no-restricted-syntax', + 'no-script-url', + 'no-setter-return', + 'no-ternary', + 'no-undef', + 'no-undefined', + 'no-underscore-dangle', + 'no-unsafe-optional-chaining', + 'no-unused-labels', + 'no-unused-private-class-members', + 'no-useless-assignment', + 'no-useless-concat', + 'no-warning-comments', + 'operator-assignment', + 'prefer-arrow-callback', + 'prefer-exponentiation-operator', + 'prefer-named-capture-group', + 'prefer-numeric-literals', + 'prefer-object-has-own', + 'prefer-object-spread', + 'prefer-rest-params', + 'prefer-spread', + 'prefer-template', + 'radix', + 'require-atomic-updates', + 'require-await', + 'require-unicode-regexp', + 'require-yield', + 'sort-imports', + 'sort-keys', + 'sort-vars', + 'strict', + 'vars-on-top', + ], + import: [ + 'import/consistent-type-specifier-style', + 'import/default', + 'import/dynamic-import-chunkname', + 'import/exports-last', + 'import/extensions', + 'import/group-exports', + 'import/max-dependencies', + 'import/named', + 'import/namespace', + 'import/newline-after-import', + 'import/no-amd', + 'import/no-anonymous-default-export', + 'import/no-commonjs', + 'import/no-cycle', + 'import/no-default-export', + 'import/no-deprecated', + 'import/no-dynamic-require', + 'import/no-empty-named-blocks', + 'import/no-extraneous-dependencies', + 'import/no-import-module-exports', + 'import/no-internal-modules', + 'import/no-mutable-exports', + 'import/no-named-as-default', + 'import/no-named-as-default-member', + 'import/no-named-export', + 'import/no-namespace', + 'import/no-nodejs-modules', + 'import/no-relative-packages', + 'import/no-relative-parent-imports', + 'import/no-restricted-paths', + 'import/no-self-import', + 'import/no-unassigned-import', + 'import/no-unresolved', + 'import/no-unused-modules', + 'import/no-useless-path-segments', + 'import/order', + 'import/prefer-default-export', + 'import/unambiguous', + ], + n: [ + 'n/callback-return', + 'n/exports-style', + 'n/file-extension-in-import', + 'n/global-require', + 'n/hashbang', + 'n/no-extraneous-import', + 'n/no-extraneous-require', + 'n/no-missing-import', + 'n/no-missing-require', + 'n/no-mixed-requires', + 'n/no-process-env', + 'n/no-process-exit', + 'n/no-sync', + 'n/no-unpublished-bin', + 'n/no-unpublished-import', + 'n/no-unpublished-require', + 'n/no-unsupported-features/es-builtins', + 'n/no-unsupported-features/es-syntax', + 'n/no-unsupported-features/node-builtins', + 'n/prefer-global/buffer', + 'n/prefer-global/console', + 'n/prefer-global/process', + 'n/prefer-global/text-decoder', + 'n/prefer-global/text-encoder', + 'n/prefer-global/url', + 'n/prefer-global/url-search-params', + 'n/prefer-node-protocol', + 'n/prefer-promises/dns', + 'n/prefer-promises/fs', + ], + promise: [ + 'promise/always-return', + 'promise/avoid-new', + 'promise/catch-or-return', + 'promise/no-callback-in-promise', + 'promise/no-multiple-resolved', + 'promise/no-native', + 'promise/no-nesting', + 'promise/no-new-statics', + 'promise/no-promise-in-callback', + 'promise/no-return-in-finally', + 'promise/no-return-wrap', + 'promise/prefer-await-to-callbacks', + 'promise/prefer-await-to-then', + 'promise/spec-only', + 'promise/valid-params', + ], + '@typescript-eslint': [ + '@typescript-eslint/require-await', + '@typescript-eslint/switch-exhaustiveness-check', + '@typescript-eslint/unified-signatures', + '@typescript-eslint/use-unknown-in-catch-callback-variable', + ], +} diff --git a/src/test/rules.ts b/src/test/rules.ts index 719a4b3e..2d2c5df4 100644 --- a/src/test/rules.ts +++ b/src/test/rules.ts @@ -8,15 +8,7 @@ import { equivalents, ourRules } from './_util.js' import _ from 'lodash' import { TSESLint } from '@typescript-eslint/utils' import { intentionallyUnusedRules } from './_intentionally-unused-rules.js' -import { - eslintCommentsRulesToConsider, - eslintRulesToConsider, - importRulesToConsider, - nRulesToConsider, - promiseRulesToConsider, - rulesToConsider, - tseslintRulesToConsider, -} from './_rules_to_consider.js' +import { rulesToConsider } from './_rules_to_consider.js' import { expectedEslintCommentsRules, expectedEslintRules, @@ -25,14 +17,7 @@ import { expectedPromiseRules, expectedTseslintRules, } from './_expected-exported-value.js' -import { - eslintCommentsRules, - eslintRules, - importRules, - nRules, - promiseRules, - tseslintRules, -} from '../rules.js' +import { rulesPerPlugin } from '../rules.js' const knownEslintRules = new TSESLint.Linter({ configType: 'eslintrc', @@ -74,7 +59,7 @@ const usedRules = Object.keys(ourRules) const acknowledgedRules = [ ...deprecatedKnownRules, - ...rulesToConsider, + ...Object.values(rulesToConsider).flat(), ...intentionallyUnusedRules, ...usedRules, ] @@ -87,8 +72,8 @@ test('rule names valid', (t) => { }) test('no intersection between lists', (t) => { - const lists = { - rulesToConsider, + const lists: Record = { + rulesToConsider: Object.values(rulesToConsider).flat(), intentionallyUnusedRules, usedRules, deprecatedKnownRules, @@ -150,24 +135,17 @@ test('JS equivalent rules are off', async (t) => { test('rule lists and objects are sorted', (t) => { const actualRuleLists = { - eslintRulesToConsider, - eslintCommentsRulesToConsider, - importRulesToConsider, - nRulesToConsider, - promiseRulesToConsider, - tseslintRulesToConsider, - expectedEslintCommentsRules: Object.keys(expectedEslintCommentsRules), - expectedEslintRules: Object.keys(expectedEslintRules), - expectedImportRules: Object.keys(expectedImportRules), - expectedNRules: Object.keys(expectedNRules), - expectedPromiseRules: Object.keys(expectedPromiseRules), - expectedTseslintRules: Object.keys(expectedTseslintRules), - eslintCommentsRules: Object.keys(eslintCommentsRules), - eslintRules: Object.keys(eslintRules), - importRules: Object.keys(importRules), - nRules: Object.keys(nRules), - promiseRules: Object.keys(promiseRules), - tseslintRules: Object.keys(tseslintRules), + ..._.mapKeys( + rulesToConsider, + (_rules, pluginName) => `rules to consider/${pluginName}`, + ), + 'expected rules/eslint-comments': Object.keys(expectedEslintCommentsRules), + 'expected rules/eslint': Object.keys(expectedEslintRules), + 'expected rules/import': Object.keys(expectedImportRules), + 'expected rules/n': Object.keys(expectedNRules), + 'expected rules/promise': Object.keys(expectedPromiseRules), + 'expected rules/@typescript-eslint': Object.keys(expectedTseslintRules), + ..._.mapValues(rulesPerPlugin, (rules) => Object.keys(rules)), } const sortedRuleLists = Object.fromEntries( diff --git a/src/types.d.ts b/src/types.d.ts index ab484bad..1c31f8e3 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -1,41 +1,41 @@ declare module 'eslint-plugin-eslint-comments' { import type { TSESLint } from '@typescript-eslint/utils' - const plugin: TSESLint.Linter.Plugin + const plugin: TSESLint.FlatConfig.Plugin export default plugin } declare module 'eslint-plugin-eslint-comments_bottom' { import type { TSESLint } from '@typescript-eslint/utils' - const plugin: TSESLint.Linter.Plugin + const plugin: TSESLint.FlatConfig.Plugin export default plugin } declare module 'eslint-plugin-n' { import type { TSESLint } from '@typescript-eslint/utils' - const plugin: TSESLint.Linter.Plugin + const plugin: TSESLint.FlatConfig.Plugin export default plugin } declare module 'eslint-plugin-n_bottom' { import type { TSESLint } from '@typescript-eslint/utils' - const plugin: TSESLint.Linter.Plugin + const plugin: TSESLint.FlatConfig.Plugin export default plugin } declare module 'eslint-plugin-import' { import type { TSESLint } from '@typescript-eslint/utils' - const plugin: TSESLint.Linter.Plugin + const plugin: TSESLint.FlatConfig.Plugin export default plugin } declare module 'eslint-plugin-import_bottom' { import type { TSESLint } from '@typescript-eslint/utils' - const plugin: TSESLint.Linter.Plugin + const plugin: TSESLint.FlatConfig.Plugin export default plugin } declare module 'eslint-plugin-promise' { import type { TSESLint } from '@typescript-eslint/utils' - const plugin: TSESLint.Linter.Plugin + const plugin: TSESLint.FlatConfig.Plugin export default plugin } declare module 'eslint-plugin-promise_bottom' { import type { TSESLint } from '@typescript-eslint/utils' - const plugin: TSESLint.Linter.Plugin + const plugin: TSESLint.FlatConfig.Plugin export default plugin } declare module 'eslint_bottom' {