From 7927d66146ec842d54123c4cd5ba6bba165df53a Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sun, 27 Nov 2022 19:06:30 -0500 Subject: [PATCH 1/3] chore(eslint-plugin): remove deprecated rules for v6 --- .../docs/rules/no-duplicate-imports.md | 12 - .../docs/rules/no-implicit-any-catch.md | 73 -- .../docs/rules/no-parameter-properties.md | 406 ---------- .../sort-type-union-intersection-members.md | 106 --- packages/eslint-plugin/src/configs/all.ts | 1 - packages/eslint-plugin/src/rules/index.ts | 8 - .../src/rules/no-duplicate-imports.ts | 127 ---- .../src/rules/no-implicit-any-catch.ts | 96 --- .../src/rules/no-parameter-properties.ts | 114 --- .../sort-type-union-intersection-members.ts | 272 ------- .../src/util/getESLintCoreRule.ts | 1 - .../tests/rules/no-duplicate-imports.test.ts | 180 ----- .../tests/rules/no-implicit-any-catch.test.ts | 78 -- .../rules/no-parameter-properties.test.ts | 714 ------------------ ...rt-type-union-intersection-members.test.ts | 338 --------- .../eslint-plugin/typings/eslint-rules.d.ts | 26 - 16 files changed, 2552 deletions(-) delete mode 100644 packages/eslint-plugin/docs/rules/no-duplicate-imports.md delete mode 100644 packages/eslint-plugin/docs/rules/no-implicit-any-catch.md delete mode 100644 packages/eslint-plugin/docs/rules/no-parameter-properties.md delete mode 100644 packages/eslint-plugin/docs/rules/sort-type-union-intersection-members.md delete mode 100644 packages/eslint-plugin/src/rules/no-duplicate-imports.ts delete mode 100644 packages/eslint-plugin/src/rules/no-implicit-any-catch.ts delete mode 100644 packages/eslint-plugin/src/rules/no-parameter-properties.ts delete mode 100644 packages/eslint-plugin/src/rules/sort-type-union-intersection-members.ts delete mode 100644 packages/eslint-plugin/tests/rules/no-duplicate-imports.test.ts delete mode 100644 packages/eslint-plugin/tests/rules/no-implicit-any-catch.test.ts delete mode 100644 packages/eslint-plugin/tests/rules/no-parameter-properties.test.ts delete mode 100644 packages/eslint-plugin/tests/rules/sort-type-union-intersection-members.test.ts diff --git a/packages/eslint-plugin/docs/rules/no-duplicate-imports.md b/packages/eslint-plugin/docs/rules/no-duplicate-imports.md deleted file mode 100644 index 5f523a7b0f4..00000000000 --- a/packages/eslint-plugin/docs/rules/no-duplicate-imports.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -description: 'Disallow duplicate imports.' ---- - -> 🛑 This file is source code, not the primary documentation location! 🛑 -> -> See **https://typescript-eslint.io/rules/no-duplicate-imports** for documentation. - -:::danger Deprecated - -This rule has been deprecated in favour of the [`import/no-duplicates`](https://github.com/import-js/eslint-plugin-import/blob/HEAD/docs/rules/no-duplicates.md) rule. -::: diff --git a/packages/eslint-plugin/docs/rules/no-implicit-any-catch.md b/packages/eslint-plugin/docs/rules/no-implicit-any-catch.md deleted file mode 100644 index ea75c981890..00000000000 --- a/packages/eslint-plugin/docs/rules/no-implicit-any-catch.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -description: 'Disallow usage of the implicit `any` type in catch clauses.' ---- - -> 🛑 This file is source code, not the primary documentation location! 🛑 -> -> See **https://typescript-eslint.io/rules/no-implicit-any-catch** for documentation. - -:::danger Deprecated - -This rule has been deprecated as TypeScript versions >=4 includes a `useUnknownInCatchVariables` compiler option with the same check. -::: - -TypeScript 4.0 added support for adding an explicit `any` or `unknown` type annotation on a catch clause variable. - -By default, TypeScript will type a catch clause variable as `any`, so explicitly annotating it as `unknown` can add a lot of safety to your codebase. - -The `noImplicitAny` flag in TypeScript does not cover this for backwards compatibility reasons, however you can use `useUnknownInCatchVariables` (part of `strict`) instead of this rule. - -## DEPRECATED - -## Examples - -This rule requires an explicit type to be declared on a catch clause variable. - - - -### ❌ Incorrect - -```ts -try { - // ... -} catch (e) { - // ... -} -``` - -### ✅ Correct - - - - -```ts -try { - // ... -} catch (e: unknown) { - // ... -} -``` - - - -## Options - -### `allowExplicitAny` - -The follow is is **_not_** considered a warning with `{ allowExplicitAny: true }` - -```ts -try { - // ... -} catch (e: any) { - // ... -} -``` - -## When Not To Use It - -If you are not using TypeScript 4.0 (or greater), then you will not be able to use this rule, annotations on catch clauses is not supported. - -## Further Reading - -- [TypeScript 4.0 Release Notes](https://devblogs.microsoft.com/typescript/announcing-typescript-4-0/#unknown-on-catch) diff --git a/packages/eslint-plugin/docs/rules/no-parameter-properties.md b/packages/eslint-plugin/docs/rules/no-parameter-properties.md deleted file mode 100644 index 16a91864d59..00000000000 --- a/packages/eslint-plugin/docs/rules/no-parameter-properties.md +++ /dev/null @@ -1,406 +0,0 @@ ---- -description: 'Disallow the use of parameter properties in class constructors.' ---- - -> 🛑 This file is source code, not the primary documentation location! 🛑 -> -> See **https://typescript-eslint.io/rules/no-parameter-properties** for documentation. - -:::danger Deprecated - -This rule has been deprecated in favour of the equivalent, better named [`parameter-properties`](./parameter-properties.md) rule. -::: - -Parameter properties can be confusing to those new to TypeScript as they are less explicit than other ways -of declaring and initializing class members. - -## Examples - -This rule disallows the use of parameter properties in constructors, forcing the user to explicitly -declare all properties in the class. - -## Options - -This rule, in its default state, does not require any argument and would completely disallow the use of parameter properties. -If you would like to allow certain types of parameter properties then you may pass an object with the following options: - -- `allows`, an array containing one or more of the allowed modifiers. Valid values are: - - `readonly`, allows **readonly** parameter properties. - - `private`, allows **private** parameter properties. - - `protected`, allows **protected** parameter properties. - - `public`, allows **public** parameter properties. - - `private readonly`, allows **private readonly** parameter properties. - - `protected readonly`, allows **protected readonly** parameter properties. - - `public readonly`, allows **public readonly** parameter properties. - -### default - -Examples of code for this rule with no options at all: - - - -#### ❌ Incorrect - -```ts -class Foo { - constructor(readonly name: string) {} -} - -class Foo { - constructor(private name: string) {} -} - -class Foo { - constructor(protected name: string) {} -} - -class Foo { - constructor(public name: string) {} -} - -class Foo { - constructor(private readonly name: string) {} -} - -class Foo { - constructor(protected readonly name: string) {} -} - -class Foo { - constructor(public readonly name: string) {} -} -``` - -#### ✅ Correct - -```ts -class Foo { - constructor(name: string) {} -} -``` - -### readonly - -Examples of code for the `{ "allows": ["readonly"] }` options: - - - -#### ❌ Incorrect - -```ts -class Foo { - constructor(private name: string) {} -} - -class Foo { - constructor(protected name: string) {} -} - -class Foo { - constructor(public name: string) {} -} - -class Foo { - constructor(private readonly name: string) {} -} - -class Foo { - constructor(protected readonly name: string) {} -} - -class Foo { - constructor(public readonly name: string) {} -} -``` - -#### ✅ Correct - -```ts -class Foo { - constructor(name: string) {} -} - -class Foo { - constructor(readonly name: string) {} -} -``` - -### private - -Examples of code for the `{ "allows": ["private"] }` options: - - - -#### ❌ Incorrect - -```ts -class Foo { - constructor(readonly name: string) {} -} - -class Foo { - constructor(protected name: string) {} -} - -class Foo { - constructor(public name: string) {} -} - -class Foo { - constructor(private readonly name: string) {} -} - -class Foo { - constructor(protected readonly name: string) {} -} - -class Foo { - constructor(public readonly name: string) {} -} -``` - -#### ✅ Correct - -```ts -class Foo { - constructor(name: string) {} -} - -class Foo { - constructor(private name: string) {} -} -``` - -### protected - -Examples of code for the `{ "allows": ["protected"] }` options: - - - -#### ❌ Incorrect - -```ts -class Foo { - constructor(readonly name: string) {} -} - -class Foo { - constructor(private name: string) {} -} - -class Foo { - constructor(public name: string) {} -} - -class Foo { - constructor(private readonly name: string) {} -} - -class Foo { - constructor(protected readonly name: string) {} -} - -class Foo { - constructor(public readonly name: string) {} -} -``` - -#### ✅ Correct - -```ts -class Foo { - constructor(name: string) {} -} - -class Foo { - constructor(protected name: string) {} -} -``` - -### public - -Examples of code for the `{ "allows": ["public"] }` options: - - - -#### ❌ Incorrect - -```ts -class Foo { - constructor(readonly name: string) {} -} - -class Foo { - constructor(private name: string) {} -} - -class Foo { - constructor(protected name: string) {} -} - -class Foo { - constructor(private readonly name: string) {} -} - -class Foo { - constructor(protected readonly name: string) {} -} - -class Foo { - constructor(public readonly name: string) {} -} -``` - -#### ✅ Correct - -```ts -class Foo { - constructor(name: string) {} -} - -class Foo { - constructor(public name: string) {} -} -``` - -### private readonly - -Examples of code for the `{ "allows": ["private readonly"] }` options: - - - -#### ❌ Incorrect - -```ts -class Foo { - constructor(readonly name: string) {} -} - -class Foo { - constructor(private name: string) {} -} - -class Foo { - constructor(protected name: string) {} -} - -class Foo { - constructor(public name: string) {} -} - -class Foo { - constructor(protected readonly name: string) {} -} - -class Foo { - constructor(public readonly name: string) {} -} -``` - -#### ✅ Correct - -```ts -class Foo { - constructor(name: string) {} -} - -class Foo { - constructor(private readonly name: string) {} -} -``` - -### protected readonly - -Examples of code for the `{ "allows": ["protected readonly"] }` options: - - - -#### ❌ Incorrect - -```ts -class Foo { - constructor(readonly name: string) {} -} - -class Foo { - constructor(private name: string) {} -} - -class Foo { - constructor(protected name: string) {} -} - -class Foo { - constructor(public name: string) {} -} - -class Foo { - constructor(private readonly name: string) {} -} - -class Foo { - constructor(public readonly name: string) {} -} -``` - -#### ✅ Correct - -```ts -class Foo { - constructor(name: string) {} -} - -class Foo { - constructor(protected readonly name: string) {} -} -``` - -### public readonly - -Examples of code for the `{ "allows": ["public readonly"] }` options: - - - -#### ❌ Incorrect - -```ts -class Foo { - constructor(readonly name: string) {} -} - -class Foo { - constructor(private name: string) {} -} - -class Foo { - constructor(protected name: string) {} -} - -class Foo { - constructor(public name: string) {} -} - -class Foo { - constructor(private readonly name: string) {} -} - -class Foo { - constructor(protected readonly name: string) {} -} -``` - -#### ✅ Correct - -```ts -class Foo { - constructor(name: string) {} -} - -class Foo { - constructor(public readonly name: string) {} -} -``` - -## When Not To Use It - -If you don't care about the using parameter properties in constructors, then you will not need this rule. diff --git a/packages/eslint-plugin/docs/rules/sort-type-union-intersection-members.md b/packages/eslint-plugin/docs/rules/sort-type-union-intersection-members.md deleted file mode 100644 index edaa195df6b..00000000000 --- a/packages/eslint-plugin/docs/rules/sort-type-union-intersection-members.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -description: 'Enforce members of a type union/intersection to be sorted alphabetically.' ---- - -> 🛑 This file is source code, not the primary documentation location! 🛑 -> -> See **https://typescript-eslint.io/rules/sort-type-union-intersection-members** for documentation. - -:::danger Deprecated - -This rule has been renamed to [`sort-type-constituents`](./sort-type-constituents.md). -::: - -Sorting union (`|`) and intersection (`&`) types can help: - -- keep your codebase standardized -- find repeated types -- reduce diff churn - -This rule reports on any types that aren't sorted alphabetically. - -> Types are sorted case-insensitively and treating numbers like a human would, falling back to character code sorting in case of ties. - -## Examples - - - -### ❌ Incorrect - -```ts -type T1 = B | A; - -type T2 = { b: string } & { a: string }; - -type T3 = [1, 2, 4] & [1, 2, 3]; - -type T4 = - | [1, 2, 4] - | [1, 2, 3] - | { b: string } - | { a: string } - | (() => void) - | (() => string) - | 'b' - | 'a' - | 'b' - | 'a' - | readonly string[] - | readonly number[] - | string[] - | number[] - | B - | A - | string - | any; -``` - -### ✅ Correct - -```ts -type T1 = A | B; - -type T2 = { a: string } & { b: string }; - -type T3 = [1, 2, 3] & [1, 2, 4]; - -type T4 = - | any - | string - | A - | B - | number[] - | string[] - | readonly number[] - | readonly string[] - | 'a' - | 'b' - | 'a' - | 'b' - | (() => string) - | (() => void) - | { a: string } - | { b: string } - | [1, 2, 3] - | [1, 2, 4]; -``` - -## Options - -### `groupOrder` - -Each member of the type is placed into a group, and then the rule sorts alphabetically within each group. -The ordering of groups is determined by this option. - -- `conditional` - Conditional types (`A extends B ? C : D`) -- `function` - Function and constructor types (`() => void`, `new () => type`) -- `import` - Import types (`import('path')`) -- `intersection` - Intersection types (`A & B`) -- `keyword` - Keyword types (`any`, `string`, etc) -- `literal` - Literal types (`1`, `'b'`, `true`, etc) -- `named` - Named types (`A`, `A['prop']`, `B[]`, `Array`) -- `object` - Object types (`{ a: string }`, `{ [key: string]: number }`) -- `operator` - Operator types (`keyof A`, `typeof B`, `readonly C[]`) -- `tuple` - Tuple types (`[A, B, C]`) -- `union` - Union types (`A | B`) -- `nullish` - `null` and `undefined` diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts index 20ea892f581..25c42ad0f39 100644 --- a/packages/eslint-plugin/src/configs/all.ts +++ b/packages/eslint-plugin/src/configs/all.ts @@ -53,7 +53,6 @@ export = { 'no-dupe-class-members': 'off', '@typescript-eslint/no-dupe-class-members': 'error', '@typescript-eslint/no-duplicate-enum-values': 'error', - 'no-duplicate-imports': 'off', '@typescript-eslint/no-dynamic-delete': 'error', 'no-empty-function': 'off', '@typescript-eslint/no-empty-function': 'error', diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index 8a3c2bbf437..ac17f4a4247 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -34,7 +34,6 @@ import confusingNonNullAssertionLikeNotEqual from './no-confusing-non-null-asser import noConfusingVoidExpression from './no-confusing-void-expression'; import noDupeClassMembers from './no-dupe-class-members'; import noDuplicateEnumValues from './no-duplicate-enum-values'; -import noDuplicateImports from './no-duplicate-imports'; import noDynamicDelete from './no-dynamic-delete'; import noEmptyFunction from './no-empty-function'; import noEmptyInterface from './no-empty-interface'; @@ -45,7 +44,6 @@ import noExtraSemi from './no-extra-semi'; import noExtraneousClass from './no-extraneous-class'; import noFloatingPromises from './no-floating-promises'; import noForInArray from './no-for-in-array'; -import noImplicitAnyCatch from './no-implicit-any-catch'; import noImpliedEval from './no-implied-eval'; import noInferrableTypes from './no-inferrable-types'; import noInvalidThis from './no-invalid-this'; @@ -60,7 +58,6 @@ import noNamespace from './no-namespace'; import noNonNullAssertedNullishCoalescing from './no-non-null-asserted-nullish-coalescing'; import noNonNullAssertedOptionalChain from './no-non-null-asserted-optional-chain'; import noNonNullAssertion from './no-non-null-assertion'; -import noParameterProperties from './no-parameter-properties'; import noRedeclare from './no-redeclare'; import noRedundantTypeConstituents from './no-redundant-type-constituents'; import noRequireImports from './no-require-imports'; @@ -116,7 +113,6 @@ import restrictTemplateExpressions from './restrict-template-expressions'; import returnAwait from './return-await'; import semi from './semi'; import sortTypeConstituents from './sort-type-constituents'; -import sortTypeUnionIntersectionMembers from './sort-type-union-intersection-members'; import spaceBeforeBlocks from './space-before-blocks'; import spaceBeforeFunctionParen from './space-before-function-paren'; import spaceInfixOps from './space-infix-ops'; @@ -165,7 +161,6 @@ export default { 'no-confusing-void-expression': noConfusingVoidExpression, 'no-dupe-class-members': noDupeClassMembers, 'no-duplicate-enum-values': noDuplicateEnumValues, - 'no-duplicate-imports': noDuplicateImports, 'no-dynamic-delete': noDynamicDelete, 'no-empty-function': noEmptyFunction, 'no-empty-interface': noEmptyInterface, @@ -176,7 +171,6 @@ export default { 'no-extraneous-class': noExtraneousClass, 'no-floating-promises': noFloatingPromises, 'no-for-in-array': noForInArray, - 'no-implicit-any-catch': noImplicitAnyCatch, 'no-implied-eval': noImpliedEval, 'no-inferrable-types': noInferrableTypes, 'no-invalid-this': noInvalidThis, @@ -191,7 +185,6 @@ export default { 'no-non-null-asserted-nullish-coalescing': noNonNullAssertedNullishCoalescing, 'no-non-null-asserted-optional-chain': noNonNullAssertedOptionalChain, 'no-non-null-assertion': noNonNullAssertion, - 'no-parameter-properties': noParameterProperties, 'no-redeclare': noRedeclare, 'no-redundant-type-constituents': noRedundantTypeConstituents, 'no-require-imports': noRequireImports, @@ -247,7 +240,6 @@ export default { 'return-await': returnAwait, semi: semi, 'sort-type-constituents': sortTypeConstituents, - 'sort-type-union-intersection-members': sortTypeUnionIntersectionMembers, 'space-before-blocks': spaceBeforeBlocks, 'space-before-function-paren': spaceBeforeFunctionParen, 'space-infix-ops': spaceInfixOps, diff --git a/packages/eslint-plugin/src/rules/no-duplicate-imports.ts b/packages/eslint-plugin/src/rules/no-duplicate-imports.ts deleted file mode 100644 index c84fd26468f..00000000000 --- a/packages/eslint-plugin/src/rules/no-duplicate-imports.ts +++ /dev/null @@ -1,127 +0,0 @@ -import type { TSESTree } from '@typescript-eslint/utils'; -import { AST_NODE_TYPES } from '@typescript-eslint/utils'; - -import * as util from '../util'; -import { getESLintCoreRule } from '../util/getESLintCoreRule'; - -const baseRule = getESLintCoreRule('no-duplicate-imports'); - -type Options = util.InferOptionsTypeFromRule; -type MessageIds = util.InferMessageIdsTypeFromRule; - -export default util.createRule({ - name: 'no-duplicate-imports', - meta: { - deprecated: true, - replacedBy: ['import/no-duplicates'], - type: 'problem', - docs: { - description: 'Disallow duplicate imports', - recommended: false, - extendsBaseRule: true, - }, - hasSuggestions: baseRule.meta.hasSuggestions, - schema: baseRule.meta.schema, - messages: { - ...baseRule.meta.messages, - importType: '{{module}} type import is duplicated.', - importTypeAs: '{{module}} type import is duplicated as type export.', - exportType: '{{module}} type export is duplicated.', - exportTypeAs: '{{module}} type export is duplicated as type import.', - }, - }, - defaultOptions: [ - { - includeExports: false, - }, - ], - create(context, [{ includeExports }]) { - const rules = baseRule.create(context); - const typeMemberImports = new Set(); - const typeDefaultImports = new Set(); - const typeExports = new Set(); - - function report( - messageId: MessageIds, - node: TSESTree.Node, - module: string, - ): void { - context.report({ - messageId, - node, - data: { - module, - }, - }); - } - - function isAllMemberImport(node: TSESTree.ImportDeclaration): boolean { - return node.specifiers.every( - specifier => specifier.type === AST_NODE_TYPES.ImportSpecifier, - ); - } - - function checkTypeImport(node: TSESTree.ImportDeclaration): void { - if (node.source) { - const value = node.source.value; - const isMemberImport = isAllMemberImport(node); - if ( - isMemberImport - ? typeMemberImports.has(value) - : typeDefaultImports.has(value) - ) { - report('importType', node, value); - } - - if (includeExports && typeExports.has(value)) { - report('importTypeAs', node, value); - } - if (isMemberImport) { - typeMemberImports.add(value); - } else { - typeDefaultImports.add(value); - } - } - } - - function checkTypeExport( - node: TSESTree.ExportNamedDeclaration | TSESTree.ExportAllDeclaration, - ): void { - if (node.source) { - const value = node.source.value; - if (typeExports.has(value)) { - report('exportType', node, value); - } - if (typeMemberImports.has(value) || typeDefaultImports.has(value)) { - report('exportTypeAs', node, value); - } - typeExports.add(value); - } - } - - return { - ...rules, - ImportDeclaration(node): void { - if (node.importKind === 'type') { - checkTypeImport(node); - return; - } - rules.ImportDeclaration(node); - }, - ExportNamedDeclaration(node): void { - if (includeExports && node.exportKind === 'type') { - checkTypeExport(node); - return; - } - rules.ExportNamedDeclaration?.(node); - }, - ExportAllDeclaration(node): void { - if (includeExports && node.exportKind === 'type') { - checkTypeExport(node); - return; - } - rules.ExportAllDeclaration?.(node); - }, - }; - }, -}); diff --git a/packages/eslint-plugin/src/rules/no-implicit-any-catch.ts b/packages/eslint-plugin/src/rules/no-implicit-any-catch.ts deleted file mode 100644 index bed757b8072..00000000000 --- a/packages/eslint-plugin/src/rules/no-implicit-any-catch.ts +++ /dev/null @@ -1,96 +0,0 @@ -import type { TSESLint } from '@typescript-eslint/utils'; -import { AST_NODE_TYPES } from '@typescript-eslint/utils'; - -import * as util from '../util'; - -export type Options = [ - { - allowExplicitAny: boolean; - }, -]; -export type MessageIds = - | 'implicitAnyInCatch' - | 'explicitAnyInCatch' - | 'suggestExplicitUnknown'; - -export default util.createRule({ - name: 'no-implicit-any-catch', - meta: { - deprecated: true, - type: 'suggestion', - docs: { - description: 'Disallow usage of the implicit `any` type in catch clauses', - recommended: false, - }, - fixable: 'code', - hasSuggestions: true, - messages: { - implicitAnyInCatch: 'Implicit any in catch clause.', - explicitAnyInCatch: 'Explicit any in catch clause.', - suggestExplicitUnknown: - 'Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct.', - }, - schema: [ - { - type: 'object', - additionalProperties: false, - properties: { - allowExplicitAny: { - description: - 'Whether to disallow specifying `: any` as the error type as well. See also `no-explicit-any`.', - type: 'boolean', - }, - }, - }, - ], - }, - defaultOptions: [ - { - allowExplicitAny: false, - }, - ], - create(context, [{ allowExplicitAny }]) { - return { - CatchClause(node): void { - if (!node.param) { - return; // ignore catch without variable - } - - if (!node.param.typeAnnotation) { - context.report({ - node, - messageId: 'implicitAnyInCatch', - suggest: [ - { - messageId: 'suggestExplicitUnknown', - fix(fixer): TSESLint.RuleFix { - return fixer.insertTextAfter(node.param!, ': unknown'); - }, - }, - ], - }); - } else if ( - !allowExplicitAny && - node.param.typeAnnotation.typeAnnotation.type === - AST_NODE_TYPES.TSAnyKeyword - ) { - context.report({ - node, - messageId: 'explicitAnyInCatch', - suggest: [ - { - messageId: 'suggestExplicitUnknown', - fix(fixer): TSESLint.RuleFix { - return fixer.replaceText( - node.param!.typeAnnotation!, - ': unknown', - ); - }, - }, - ], - }); - } - }, - }; - }, -}); diff --git a/packages/eslint-plugin/src/rules/no-parameter-properties.ts b/packages/eslint-plugin/src/rules/no-parameter-properties.ts deleted file mode 100644 index 3952dfc581f..00000000000 --- a/packages/eslint-plugin/src/rules/no-parameter-properties.ts +++ /dev/null @@ -1,114 +0,0 @@ -import type { TSESTree } from '@typescript-eslint/utils'; -import { AST_NODE_TYPES } from '@typescript-eslint/utils'; - -import * as util from '../util'; - -type Modifier = - | 'readonly' - | 'private' - | 'protected' - | 'public' - | 'private readonly' - | 'protected readonly' - | 'public readonly'; -type Options = [ - { - allows: Modifier[]; - }, -]; -type MessageIds = 'noParamProp'; - -export default util.createRule({ - name: 'no-parameter-properties', - meta: { - deprecated: true, - replacedBy: ['@typescript-eslint/parameter-properties'], - type: 'problem', - docs: { - description: - 'Disallow the use of parameter properties in class constructors', - // too opinionated to be recommended - recommended: false, - }, - messages: { - noParamProp: - 'Property {{parameter}} cannot be declared in the constructor.', - }, - schema: [ - { - type: 'object', - properties: { - allows: { - type: 'array', - items: { - enum: [ - 'readonly', - 'private', - 'protected', - 'public', - 'private readonly', - 'protected readonly', - 'public readonly', - ], - }, - minItems: 1, - }, - }, - additionalProperties: false, - }, - ], - }, - defaultOptions: [ - { - allows: [], - }, - ], - create(context, [{ allows }]) { - /** - * Gets the modifiers of `node`. - * @param node the node to be inspected. - */ - function getModifiers(node: TSESTree.TSParameterProperty): Modifier { - const modifiers: Modifier[] = []; - - if (node.accessibility) { - modifiers.push(node.accessibility); - } - if (node.readonly) { - modifiers.push('readonly'); - } - - return modifiers.filter(Boolean).join(' ') as Modifier; - } - - return { - TSParameterProperty(node): void { - const modifiers = getModifiers(node); - - if (!allows.includes(modifiers)) { - // HAS to be an identifier or assignment or TSC will throw - if ( - node.parameter.type !== AST_NODE_TYPES.Identifier && - node.parameter.type !== AST_NODE_TYPES.AssignmentPattern - ) { - return; - } - - const name = - node.parameter.type === AST_NODE_TYPES.Identifier - ? node.parameter.name - : // has to be an Identifier or TSC will throw an error - (node.parameter.left as TSESTree.Identifier).name; - - context.report({ - node, - messageId: 'noParamProp', - data: { - parameter: name, - }, - }); - } - }, - }; - }, -}); diff --git a/packages/eslint-plugin/src/rules/sort-type-union-intersection-members.ts b/packages/eslint-plugin/src/rules/sort-type-union-intersection-members.ts deleted file mode 100644 index a65f6c38e93..00000000000 --- a/packages/eslint-plugin/src/rules/sort-type-union-intersection-members.ts +++ /dev/null @@ -1,272 +0,0 @@ -import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; -import { AST_NODE_TYPES } from '@typescript-eslint/utils'; - -import * as util from '../util'; -import { getEnumNames } from '../util'; - -enum Group { - conditional = 'conditional', - function = 'function', - import = 'import', - intersection = 'intersection', - keyword = 'keyword', - nullish = 'nullish', - literal = 'literal', - named = 'named', - object = 'object', - operator = 'operator', - tuple = 'tuple', - union = 'union', -} - -function getGroup(node: TSESTree.TypeNode): Group { - switch (node.type) { - case AST_NODE_TYPES.TSConditionalType: - return Group.conditional; - - case AST_NODE_TYPES.TSConstructorType: - case AST_NODE_TYPES.TSFunctionType: - return Group.function; - - case AST_NODE_TYPES.TSImportType: - return Group.import; - - case AST_NODE_TYPES.TSIntersectionType: - return Group.intersection; - - case AST_NODE_TYPES.TSAnyKeyword: - case AST_NODE_TYPES.TSBigIntKeyword: - case AST_NODE_TYPES.TSBooleanKeyword: - case AST_NODE_TYPES.TSNeverKeyword: - case AST_NODE_TYPES.TSNumberKeyword: - case AST_NODE_TYPES.TSObjectKeyword: - case AST_NODE_TYPES.TSStringKeyword: - case AST_NODE_TYPES.TSSymbolKeyword: - case AST_NODE_TYPES.TSThisType: - case AST_NODE_TYPES.TSUnknownKeyword: - case AST_NODE_TYPES.TSIntrinsicKeyword: - return Group.keyword; - - case AST_NODE_TYPES.TSNullKeyword: - case AST_NODE_TYPES.TSUndefinedKeyword: - case AST_NODE_TYPES.TSVoidKeyword: - return Group.nullish; - - case AST_NODE_TYPES.TSLiteralType: - case AST_NODE_TYPES.TSTemplateLiteralType: - return Group.literal; - - case AST_NODE_TYPES.TSArrayType: - case AST_NODE_TYPES.TSIndexedAccessType: - case AST_NODE_TYPES.TSInferType: - case AST_NODE_TYPES.TSTypeReference: - case AST_NODE_TYPES.TSQualifiedName: - return Group.named; - - case AST_NODE_TYPES.TSMappedType: - case AST_NODE_TYPES.TSTypeLiteral: - return Group.object; - - case AST_NODE_TYPES.TSTypeOperator: - case AST_NODE_TYPES.TSTypeQuery: - return Group.operator; - - case AST_NODE_TYPES.TSTupleType: - return Group.tuple; - - case AST_NODE_TYPES.TSUnionType: - return Group.union; - - // These types should never occur as part of a union/intersection - case AST_NODE_TYPES.TSAbstractKeyword: - case AST_NODE_TYPES.TSAsyncKeyword: - case AST_NODE_TYPES.TSDeclareKeyword: - case AST_NODE_TYPES.TSExportKeyword: - case AST_NODE_TYPES.TSNamedTupleMember: - case AST_NODE_TYPES.TSOptionalType: - case AST_NODE_TYPES.TSPrivateKeyword: - case AST_NODE_TYPES.TSProtectedKeyword: - case AST_NODE_TYPES.TSPublicKeyword: - case AST_NODE_TYPES.TSReadonlyKeyword: - case AST_NODE_TYPES.TSRestType: - case AST_NODE_TYPES.TSStaticKeyword: - case AST_NODE_TYPES.TSTypePredicate: - /* istanbul ignore next */ - throw new Error(`Unexpected Type ${node.type}`); - } -} - -function requiresParentheses(node: TSESTree.TypeNode): boolean { - return ( - node.type === AST_NODE_TYPES.TSFunctionType || - node.type === AST_NODE_TYPES.TSConstructorType - ); -} - -export type Options = [ - { - checkIntersections?: boolean; - checkUnions?: boolean; - groupOrder?: string[]; - }, -]; -export type MessageIds = 'notSorted' | 'notSortedNamed' | 'suggestFix'; - -export default util.createRule({ - name: 'sort-type-union-intersection-members', - meta: { - deprecated: true, - type: 'suggestion', - docs: { - description: - 'Enforce members of a type union/intersection to be sorted alphabetically', - recommended: false, - }, - fixable: 'code', - hasSuggestions: true, - messages: { - notSorted: '{{type}} type members must be sorted.', - notSortedNamed: '{{type}} type {{name}} members must be sorted.', - suggestFix: 'Sort members of type (removes all comments).', - }, - replacedBy: ['@typescript-eslint/sort-type-constituents'], - schema: [ - { - type: 'object', - properties: { - checkIntersections: { - description: 'Whether to check intersection types.', - type: 'boolean', - }, - checkUnions: { - description: 'Whether to check union types.', - type: 'boolean', - }, - groupOrder: { - description: 'Ordering of the groups.', - type: 'array', - items: { - type: 'string', - enum: getEnumNames(Group), - }, - }, - }, - }, - ], - }, - defaultOptions: [ - { - checkIntersections: true, - checkUnions: true, - groupOrder: [ - Group.named, - Group.keyword, - Group.operator, - Group.literal, - Group.function, - Group.import, - Group.conditional, - Group.object, - Group.tuple, - Group.intersection, - Group.union, - Group.nullish, - ], - }, - ], - create(context, [{ checkIntersections, checkUnions, groupOrder }]) { - const sourceCode = context.getSourceCode(); - - const collator = new Intl.Collator('en', { - sensitivity: 'base', - numeric: true, - }); - - function checkSorting( - node: TSESTree.TSIntersectionType | TSESTree.TSUnionType, - ): void { - const sourceOrder = node.types.map(type => { - const group = groupOrder?.indexOf(getGroup(type)) ?? -1; - return { - group: group === -1 ? Number.MAX_SAFE_INTEGER : group, - node: type, - text: sourceCode.getText(type), - }; - }); - const expectedOrder = [...sourceOrder].sort((a, b) => { - if (a.group !== b.group) { - return a.group - b.group; - } - - return ( - collator.compare(a.text, b.text) || - (a.text < b.text ? -1 : a.text > b.text ? 1 : 0) - ); - }); - - const hasComments = node.types.some(type => { - const count = - sourceCode.getCommentsBefore(type).length + - sourceCode.getCommentsAfter(type).length; - return count > 0; - }); - - for (let i = 0; i < expectedOrder.length; i += 1) { - if (expectedOrder[i].node !== sourceOrder[i].node) { - let messageId: MessageIds = 'notSorted'; - const data = { - name: '', - type: - node.type === AST_NODE_TYPES.TSIntersectionType - ? 'Intersection' - : 'Union', - }; - if (node.parent.type === AST_NODE_TYPES.TSTypeAliasDeclaration) { - messageId = 'notSortedNamed'; - data.name = node.parent.id.name; - } - - const fix: TSESLint.ReportFixFunction = fixer => { - const sorted = expectedOrder - .map(t => (requiresParentheses(t.node) ? `(${t.text})` : t.text)) - .join( - node.type === AST_NODE_TYPES.TSIntersectionType ? ' & ' : ' | ', - ); - - return fixer.replaceText(node, sorted); - }; - return context.report({ - node, - messageId, - data, - // don't autofix if any of the types have leading/trailing comments - // the logic for preserving them correctly is a pain - we may implement this later - ...(hasComments - ? { - suggest: [ - { - messageId: 'suggestFix', - fix, - }, - ], - } - : { fix }), - }); - } - } - } - - return { - ...(checkIntersections && { - TSIntersectionType(node): void { - checkSorting(node); - }, - }), - ...(checkUnions && { - TSUnionType(node): void { - checkSorting(node); - }, - }), - }; - }, -}); diff --git a/packages/eslint-plugin/src/util/getESLintCoreRule.ts b/packages/eslint-plugin/src/util/getESLintCoreRule.ts index 1678903acd3..86dfcc9393d 100644 --- a/packages/eslint-plugin/src/util/getESLintCoreRule.ts +++ b/packages/eslint-plugin/src/util/getESLintCoreRule.ts @@ -16,7 +16,6 @@ interface RuleMap { 'lines-between-class-members': typeof import('eslint/lib/rules/lines-between-class-members'); 'no-dupe-args': typeof import('eslint/lib/rules/no-dupe-args'); 'no-dupe-class-members': typeof import('eslint/lib/rules/no-dupe-class-members'); - 'no-duplicate-imports': typeof import('eslint/lib/rules/no-duplicate-imports'); 'no-empty-function': typeof import('eslint/lib/rules/no-empty-function'); 'no-extra-parens': typeof import('eslint/lib/rules/no-extra-parens'); 'no-extra-semi': typeof import('eslint/lib/rules/no-extra-semi'); diff --git a/packages/eslint-plugin/tests/rules/no-duplicate-imports.test.ts b/packages/eslint-plugin/tests/rules/no-duplicate-imports.test.ts deleted file mode 100644 index fae90720e7e..00000000000 --- a/packages/eslint-plugin/tests/rules/no-duplicate-imports.test.ts +++ /dev/null @@ -1,180 +0,0 @@ -import rule from '../../src/rules/no-duplicate-imports'; -import { RuleTester } from '../RuleTester'; - -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', -}); - -ruleTester.run('no-duplicate-imports', rule, { - valid: [ - { - code: "import type foo from 'foo';", - }, - { - code: "import type { foo } from 'foo';", - }, - { - code: ` - import type { foo } from 'foo'; - import type Bar from 'foo'; - `, - }, - { - code: ` - import type Foo from 'foo'; - import type { bar } from 'foo'; - `, - }, - { - code: ` - import type Foo from 'foo'; - import type { bar as Bar } from 'foo'; - `, - }, - { - code: ` - import foo from 'foo'; - import type bar from 'foo'; - `, - }, - { - code: ` - import { foo } from 'foo'; - import type { bar } from 'foo'; - `, - }, - { - code: ` - import type { foo } from 'foo'; - export type foo = foo; - `, - }, - { - code: ` - import type { foo } from 'foo'; - export type { foo }; - `, - }, - { - code: ` - export { foo } from 'foo'; - export type { foo } from 'foo'; - `, - }, - { - code: ` - export type * as foo from 'foo'; - export type * as bar from 'foo'; - `, - }, - { - code: ` - import type { bar } from 'foo'; - export type { foo } from 'foo'; - `, - }, - { - code: ` - import type { foo } from 'foo'; - export type { bar } from 'bar'; - `, - options: [{ includeExports: true }], - }, - { - code: ` - import type { foo } from 'foo'; - export type { bar }; - `, - options: [{ includeExports: true }], - }, - { - code: ` - import type Foo from 'foo'; - import type { bar } from 'foo'; - export type { bar }; - `, - options: [{ includeExports: true }], - }, - ], - invalid: [ - { - code: ` - import type foo from 'foo'; - import type bar from 'foo'; - `, - errors: [ - { - messageId: 'importType', - data: { - module: 'foo', - }, - }, - ], - }, - { - code: ` - import type { foo } from 'foo'; - import type { bar } from 'foo'; - `, - errors: [{ messageId: 'importType' }], - }, - { - code: ` - export type { foo } from 'foo'; - import type { bar } from 'foo'; - `, - options: [{ includeExports: true }], - errors: [{ messageId: 'importTypeAs' }], - }, - { - code: ` - import type foo from 'foo'; - export type * from 'foo'; - `, - options: [{ includeExports: true }], - errors: [{ messageId: 'exportTypeAs' }], - }, - { - code: ` - import type { foo } from 'foo'; - export type { foo } from 'foo'; - `, - options: [{ includeExports: true }], - errors: [{ messageId: 'exportTypeAs' }], - }, - { - code: ` - import type Foo from 'foo'; - import type { bar } from 'foo'; - export type { bar } from 'foo'; - `, - options: [{ includeExports: true }], - errors: [{ messageId: 'exportTypeAs' }], - }, - { - code: ` - export type * as foo from 'foo'; - export type * as bar from 'foo'; - `, - options: [{ includeExports: true }], - errors: [{ messageId: 'exportType' }], - }, - - // check base rule - { - code: ` - import foo from 'foo'; - import bar from 'foo'; - `, - errors: [{ messageId: 'import' }], - }, - { - code: ` - import foo from 'foo'; - export { foo } from 'foo'; - `, - options: [{ includeExports: true }], - errors: [{ messageId: 'exportAs' }], - }, - ], -}); diff --git a/packages/eslint-plugin/tests/rules/no-implicit-any-catch.test.ts b/packages/eslint-plugin/tests/rules/no-implicit-any-catch.test.ts deleted file mode 100644 index e04b03889ca..00000000000 --- a/packages/eslint-plugin/tests/rules/no-implicit-any-catch.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -/* eslint-disable eslint-comments/no-use */ -// TODO - prettier currently removes the type annotations, re-enable this once prettier is updated -/* eslint "@typescript-eslint/internal/plugin-test-formatting": ["error", { formatWithPrettier: false }] */ -/* eslint-enable eslint-comments/no-use */ - -import rule from '../../src/rules/no-implicit-any-catch'; -import { RuleTester } from '../RuleTester'; - -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', -}); - -ruleTester.run('no-implicit-any-catch', rule, { - valid: [ - ` -try { -} catch (e1: unknown) {} - `, - { - code: ` -try { -} catch (e2: any) {} - `, - options: [{ allowExplicitAny: true }], - }, - ], - invalid: [ - { - code: ` -try { -} catch (e3) {} - `, - errors: [ - { - line: 3, - column: 3, - messageId: 'implicitAnyInCatch', - endLine: 3, - endColumn: 16, - suggestions: [ - { - messageId: 'suggestExplicitUnknown', - output: ` -try { -} catch (e3: unknown) {} - `, - }, - ], - }, - ], - }, - { - code: ` -try { -} catch (e4: any) {} - `, - options: [{ allowExplicitAny: false }], - errors: [ - { - line: 3, - column: 3, - messageId: 'explicitAnyInCatch', - endLine: 3, - endColumn: 21, - suggestions: [ - { - messageId: 'suggestExplicitUnknown', - output: ` -try { -} catch (e4: unknown) {} - `, - }, - ], - }, - ], - }, - ], -}); diff --git a/packages/eslint-plugin/tests/rules/no-parameter-properties.test.ts b/packages/eslint-plugin/tests/rules/no-parameter-properties.test.ts deleted file mode 100644 index f4f7fb03d2d..00000000000 --- a/packages/eslint-plugin/tests/rules/no-parameter-properties.test.ts +++ /dev/null @@ -1,714 +0,0 @@ -import rule from '../../src/rules/no-parameter-properties'; -import { RuleTester } from '../RuleTester'; - -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', -}); - -ruleTester.run('no-parameter-properties', rule, { - valid: [ - ` -class Foo { - constructor(name: string) {} -} - `, - ` -class Foo { - constructor(...name: string[]) {} -} - `, - ` -class Foo { - constructor(name: string, age: number) {} -} - `, - ` -class Foo { - constructor(name: string); - constructor(name: string, age?: number) {} -} - `, - { - code: ` -class Foo { - constructor(readonly name: string) {} -} - `, - options: [{ allows: ['readonly'] }], - }, - { - code: ` -class Foo { - constructor(private name: string) {} -} - `, - options: [{ allows: ['private'] }], - }, - { - code: ` -class Foo { - constructor(protected name: string) {} -} - `, - options: [{ allows: ['protected'] }], - }, - { - code: ` -class Foo { - constructor(public name: string) {} -} - `, - options: [{ allows: ['public'] }], - }, - { - code: ` -class Foo { - constructor(private readonly name: string) {} -} - `, - options: [{ allows: ['private readonly'] }], - }, - { - code: ` -class Foo { - constructor(protected readonly name: string) {} -} - `, - options: [{ allows: ['protected readonly'] }], - }, - { - code: ` -class Foo { - constructor(public readonly name: string) {} -} - `, - options: [{ allows: ['public readonly'] }], - }, - { - code: ` -class Foo { - constructor(readonly name: string, private age: number) {} -} - `, - options: [{ allows: ['readonly', 'private'] }], - }, - { - code: ` -class Foo { - constructor(public readonly name: string, private age: number) {} -} - `, - options: [{ allows: ['public readonly', 'private'] }], - }, - // Semantically invalid test case - ` -class Foo { - constructor(private ...name: string[]) {} -} - `, - // Semantically invalid test case - ` -class Foo { - constructor(private [test]: [string]) {} -} - `, - ], - invalid: [ - { - code: ` -class Foo { - constructor(readonly name: string) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(private name: string) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(protected name: string) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(public name: string) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(private readonly name: string) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(protected readonly name: string) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(public readonly name: string) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(public name: string, age: number) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(private name: string, private age: number) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - { - messageId: 'noParamProp', - data: { - parameter: 'age', - }, - line: 3, - column: 37, - }, - ], - }, - { - code: ` -class Foo { - constructor(protected name: string, protected age: number) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - { - messageId: 'noParamProp', - data: { - parameter: 'age', - }, - line: 3, - column: 39, - }, - ], - }, - { - code: ` -class Foo { - constructor(public name: string, public age: number) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - { - messageId: 'noParamProp', - data: { - parameter: 'age', - }, - line: 3, - column: 36, - }, - ], - }, - { - code: ` -class Foo { - constructor(name: string); - constructor(private name: string, age?: number) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 4, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(private name: string); - constructor(private name: string, age?: number) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 4, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(private name: string); - constructor(private name: string, private age?: number) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 4, - column: 15, - }, - { - messageId: 'noParamProp', - data: { - parameter: 'age', - }, - line: 4, - column: 37, - }, - ], - }, - { - code: ` -class Foo { - constructor(name: string); - constructor(protected name: string, age?: number) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 4, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(protected name: string); - constructor(protected name: string, age?: number) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 4, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(protected name: string); - constructor(protected name: string, protected age?: number) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 4, - column: 15, - }, - { - messageId: 'noParamProp', - data: { - parameter: 'age', - }, - line: 4, - column: 39, - }, - ], - }, - { - code: ` -class Foo { - constructor(name: string); - constructor(public name: string, age?: number) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 4, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(public name: string); - constructor(public name: string, age?: number) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 4, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(public name: string); - constructor(public name: string, public age?: number) {} -} - `, - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 4, - column: 15, - }, - { - messageId: 'noParamProp', - data: { - parameter: 'age', - }, - line: 4, - column: 36, - }, - ], - }, - - { - code: ` -class Foo { - constructor(readonly name: string) {} -} - `, - options: [{ allows: ['private'] }], - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(private name: string) {} -} - `, - options: [{ allows: ['readonly'] }], - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(protected name: string) {} -} - `, - options: [ - { - allows: ['readonly', 'private', 'public', 'protected readonly'], - }, - ], - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(public name: string) {} -} - `, - options: [ - { - allows: [ - 'readonly', - 'private', - 'protected', - 'protected readonly', - 'public readonly', - ], - }, - ], - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(private readonly name: string) {} -} - `, - options: [{ allows: ['readonly', 'private'] }], - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(protected readonly name: string) {} -} - `, - options: [ - { - allows: [ - 'readonly', - 'protected', - 'private readonly', - 'public readonly', - ], - }, - ], - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'name', - }, - line: 3, - column: 15, - }, - ], - }, - { - code: ` -class Foo { - constructor(private name: string); - constructor(private name: string, protected age?: number) {} -} - `, - options: [{ allows: ['private'] }], - errors: [ - { - messageId: 'noParamProp', - data: { - parameter: 'age', - }, - line: 4, - column: 37, - }, - ], - }, - ], -}); diff --git a/packages/eslint-plugin/tests/rules/sort-type-union-intersection-members.test.ts b/packages/eslint-plugin/tests/rules/sort-type-union-intersection-members.test.ts deleted file mode 100644 index a24959d8b6a..00000000000 --- a/packages/eslint-plugin/tests/rules/sort-type-union-intersection-members.test.ts +++ /dev/null @@ -1,338 +0,0 @@ -import type { TSESLint } from '@typescript-eslint/utils'; - -import type { - MessageIds, - Options, -} from '../../src/rules/sort-type-union-intersection-members'; -import rule from '../../src/rules/sort-type-union-intersection-members'; -import { noFormat, RuleTester } from '../RuleTester'; - -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', -}); - -const valid = (operator: '|' | '&'): TSESLint.ValidTestCase[] => [ - { - code: `type T = A ${operator} B;`, - }, - { - code: `type T = A ${operator} /* comment */ B;`, - }, - { - code: `type T = 'A' ${operator} 'B';`, - }, - { - code: `type T = 1 ${operator} 2;`, - }, - { - code: noFormat`type T = (A) ${operator} (B);`, - }, - { - code: `type T = { a: string } ${operator} { b: string };`, - }, - { - code: `type T = [1, 2, 3] ${operator} [1, 2, 4];`, - }, - { - code: `type T = (() => string) ${operator} (() => void);`, - }, - { - code: `type T = () => string ${operator} void;`, - }, - { - // testing the default ordering - code: noFormat` -type T = - ${operator} A - ${operator} B - ${operator} C.D - ${operator} D.E - ${operator} intrinsic - ${operator} number[] - ${operator} string[] - ${operator} any - ${operator} string - ${operator} symbol - ${operator} this - ${operator} readonly number[] - ${operator} readonly string[] - ${operator} 'a' - ${operator} 'b' - ${operator} "a" - ${operator} "b" - ${operator} (() => string) - ${operator} (() => void) - ${operator} (new () => string) - ${operator} (new () => void) - ${operator} import('bar') - ${operator} import('foo') - ${operator} (number extends string ? unknown : never) - ${operator} (string extends string ? unknown : never) - ${operator} { [a in string]: string } - ${operator} { [a: string]: string } - ${operator} { [b in string]: string } - ${operator} { [b: string]: string } - ${operator} { a: string } - ${operator} { b: string } - ${operator} [1, 2, 3] - ${operator} [1, 2, 4] - ${operator} (A & B) - ${operator} (B & C) - ${operator} (A | B) - ${operator} (B | C) - ${operator} null - ${operator} undefined - `, - }, -]; -const invalid = ( - operator: '|' | '&', -): TSESLint.InvalidTestCase[] => { - const type = operator === '|' ? 'Union' : 'Intersection'; - return [ - { - code: `type T = B ${operator} A;`, - output: `type T = A ${operator} B;`, - errors: [ - { - messageId: 'notSortedNamed', - data: { - type, - name: 'T', - }, - }, - ], - }, - { - code: `type T = 'B' ${operator} 'A';`, - output: `type T = 'A' ${operator} 'B';`, - errors: [ - { - messageId: 'notSortedNamed', - data: { - type, - name: 'T', - }, - }, - ], - }, - { - code: `type T = 2 ${operator} 1;`, - output: `type T = 1 ${operator} 2;`, - errors: [ - { - messageId: 'notSortedNamed', - data: { - type, - name: 'T', - }, - }, - ], - }, - { - code: noFormat`type T = (B) ${operator} (A);`, - output: `type T = A ${operator} B;`, - errors: [ - { - messageId: 'notSortedNamed', - data: { - type, - name: 'T', - }, - }, - ], - }, - { - code: `type T = { b: string } ${operator} { a: string };`, - output: `type T = { a: string } ${operator} { b: string };`, - errors: [ - { - messageId: 'notSortedNamed', - data: { - type, - name: 'T', - }, - }, - ], - }, - { - code: `type T = [1, 2, 4] ${operator} [1, 2, 3];`, - output: `type T = [1, 2, 3] ${operator} [1, 2, 4];`, - errors: [ - { - messageId: 'notSortedNamed', - data: { - type, - name: 'T', - }, - }, - ], - }, - { - code: `type T = (() => void) ${operator} (() => string);`, - output: `type T = (() => string) ${operator} (() => void);`, - errors: [ - { - messageId: 'notSortedNamed', - data: { - type, - name: 'T', - }, - }, - ], - }, - { - code: `type T = () => void ${operator} string;`, - output: `type T = () => string ${operator} void;`, - errors: [ - { - messageId: 'notSorted', - data: { - type, - }, - }, - ], - }, - { - code: `type T = () => undefined ${operator} null;`, - output: `type T = () => null ${operator} undefined;`, - errors: [ - { - messageId: 'notSorted', - data: { - type, - }, - }, - ], - }, - { - code: noFormat` -type T = - ${operator} [1, 2, 4] - ${operator} [1, 2, 3] - ${operator} { b: string } - ${operator} { a: string } - ${operator} (() => void) - ${operator} (() => string) - ${operator} "b" - ${operator} "a" - ${operator} 'b' - ${operator} 'a' - ${operator} readonly string[] - ${operator} readonly number[] - ${operator} string[] - ${operator} number[] - ${operator} D.E - ${operator} C.D - ${operator} B - ${operator} A - ${operator} undefined - ${operator} null - ${operator} string - ${operator} any; - `, - output: ` -type T = - A ${operator} B ${operator} C.D ${operator} D.E ${operator} number[] ${operator} string[] ${operator} any ${operator} string ${operator} readonly number[] ${operator} readonly string[] ${operator} 'a' ${operator} 'b' ${operator} "a" ${operator} "b" ${operator} (() => string) ${operator} (() => void) ${operator} { a: string } ${operator} { b: string } ${operator} [1, 2, 3] ${operator} [1, 2, 4] ${operator} null ${operator} undefined; - `, - errors: [ - { - messageId: 'notSortedNamed', - data: { - type, - name: 'T', - }, - }, - ], - }, - { - code: `type T = B ${operator} /* comment */ A;`, - output: null, - errors: [ - { - messageId: 'notSortedNamed', - data: { - type, - name: 'T', - }, - suggestions: [ - { - messageId: 'suggestFix', - output: `type T = A ${operator} B;`, - }, - ], - }, - ], - }, - { - code: `type T = (() => /* comment */ A) ${operator} B;`, - output: `type T = B ${operator} (() => /* comment */ A);`, - errors: [ - { - messageId: 'notSortedNamed', - data: { - type, - name: 'T', - }, - suggestions: null, - }, - ], - }, - { - code: `type Expected = (new (x: number) => boolean) ${operator} string;`, - output: `type Expected = string ${operator} (new (x: number) => boolean);`, - errors: [ - { - messageId: 'notSortedNamed', - }, - ], - }, - ]; -}; - -ruleTester.run('sort-type-union-intersection-members', rule, { - valid: [ - ...valid('|'), - { - code: 'type T = B | A;', - options: [ - { - checkUnions: false, - }, - ], - }, - - ...valid('&'), - { - code: 'type T = B & A;', - options: [ - { - checkIntersections: false, - }, - ], - }, - - { - code: noFormat` -type T = [1] | 'a' | 'b' | "b" | 1 | 2 | {}; - `, - options: [ - { - groupOrder: ['tuple', 'literal', 'object'], - }, - ], - }, - { - // if not specified - groups should be placed last - code: ` -type T = 1 | string | {} | A; - `, - options: [ - { - groupOrder: ['literal', 'keyword'], - }, - ], - }, - ], - invalid: [...invalid('|'), ...invalid('&')], -}); diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index 09b54ae4a51..951c1d706df 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -797,32 +797,6 @@ declare module 'eslint/lib/rules/comma-dangle' { export = rule; } -declare module 'eslint/lib/rules/no-duplicate-imports' { - import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; - - const rule: TSESLint.RuleModule< - | 'import' - | 'importAs' - | 'export' - | 'exportAs' - | 'importType' - | 'importTypeAs' - | 'exportType' - | 'exportTypeAs', - [ - { - includeExports?: boolean; - }, - ], - { - ImportDeclaration(node: TSESTree.ImportDeclaration): void; - ExportNamedDeclaration?(node: TSESTree.ExportNamedDeclaration): void; - ExportAllDeclaration?(node: TSESTree.ExportAllDeclaration): void; - } - >; - export = rule; -} - declare module 'eslint/lib/rules/space-infix-ops' { import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; From bcf03f5fc9c6427238950143db659b1d0b896d12 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 5 Dec 2022 22:44:08 -0500 Subject: [PATCH 2/3] Added deprecation page for no-duplicate-imports --- .../eslint-plugin/docs/rules/no-duplicate-imports.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 packages/eslint-plugin/docs/rules/no-duplicate-imports.md diff --git a/packages/eslint-plugin/docs/rules/no-duplicate-imports.md b/packages/eslint-plugin/docs/rules/no-duplicate-imports.md new file mode 100644 index 00000000000..9bf40498092 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/no-duplicate-imports.md @@ -0,0 +1,10 @@ +:::danger Deprecated + +This rule has been deprecated in favour of the [`import/no-duplicates`](https://github.com/import-js/eslint-plugin-import/blob/HEAD/docs/rules/no-duplicates.md) rule. + +::: + + From 5d3d14e9e7da9249c8b970ffd6a825f8f4d99864 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Thu, 8 Dec 2022 11:08:13 -0500 Subject: [PATCH 3/3] Fixed unit test --- packages/eslint-plugin/tests/docs.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/tests/docs.test.ts b/packages/eslint-plugin/tests/docs.test.ts index e7872a962c9..c42fe1ee42d 100644 --- a/packages/eslint-plugin/tests/docs.test.ts +++ b/packages/eslint-plugin/tests/docs.test.ts @@ -40,10 +40,11 @@ function tokenIsH2( describe('Validating rule docs', () => { const ignoredFiles = new Set([ - // this rule doc was left behind on purpose for legacy reasons - 'camelcase.md', 'README.md', 'TEMPLATE.md', + // these rule docs were left behind on purpose for legacy reasons + 'camelcase.md', + 'no-duplicate-imports.md', ]); it('All rules must have a corresponding rule doc', () => { const files = fs