From 90fe78eb7593b60efde25c77319b5546ce80df58 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Mar 2021 12:00:40 -0700 Subject: [PATCH 01/14] chore: bump @babel/types from 7.13.12 to 7.13.14 (#3246) Bumps [@babel/types](https://github.com/babel/babel/tree/HEAD/packages/babel-types) from 7.13.12 to 7.13.14. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.13.14/packages/babel-types) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 95ea43fd35cb..faa7f78b2d14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -292,9 +292,9 @@ lodash "^4.17.19" "@babel/types@^7.0.0", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.12.tgz#edbf99208ef48852acdff1c8a681a1e4ade580cd" - integrity sha512-K4nY2xFN4QMvQwkQ+zmBDp6ANMbVNw6BbxWmYA4qNjhR9W+Lj/8ky5MEY2Me5r+B2c6/v6F53oMndG+f9s3IiA== + version "7.13.14" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.14.tgz#c35a4abb15c7cd45a2746d78ab328e362cbace0d" + integrity sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ== dependencies: "@babel/helper-validator-identifier" "^7.12.11" lodash "^4.17.19" From b2ab1408120df0b73f2b94fafdd656e4444aad7b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Mar 2021 12:00:53 -0700 Subject: [PATCH 02/14] chore: bump semver from 7.3.4 to 7.3.5 (#3238) Bumps [semver](https://github.com/npm/node-semver) from 7.3.4 to 7.3.5. - [Release notes](https://github.com/npm/node-semver/releases) - [Changelog](https://github.com/npm/node-semver/blob/master/CHANGELOG.md) - [Commits](https://github.com/npm/node-semver/compare/v7.3.4...v7.3.5) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index faa7f78b2d14..7dc4aa20339c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7776,13 +7776,20 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@7.3.4, semver@7.x, semver@^7.2.1, semver@^7.3.2: +semver@7.3.4: version "7.3.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== dependencies: lru-cache "^6.0.0" +semver@7.x, semver@^7.2.1, semver@^7.3.2: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" From ad797c52a6222ed51ca960ab21abebdd6ad1c11b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Mar 2021 12:01:11 -0700 Subject: [PATCH 03/14] chore: bump @babel/parser from 7.13.12 to 7.13.13 (#3237) Bumps [@babel/parser](https://github.com/babel/babel/tree/HEAD/packages/babel-parser) from 7.13.12 to 7.13.13. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.13.13/packages/babel-parser) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7dc4aa20339c..1e417e260b51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -172,9 +172,9 @@ js-tokens "^4.0.0" "@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.13.10", "@babel/parser@^7.13.11": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.12.tgz#ba320059420774394d3b0c0233ba40e4250b81d1" - integrity sha512-4T7Pb244rxH24yR116LAuJ+adxXXnHhZaLJjegJVKSdoNCe4x1eDBaud5YIcQFcqzsaD5BHvJw5BQ0AZapdCRw== + version "7.13.13" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.13.tgz#42f03862f4aed50461e543270916b47dd501f0df" + integrity sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" From 92a0e11c7850498b99d4ac1474eb78e06ae1f149 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Mar 2021 12:02:17 -0700 Subject: [PATCH 04/14] chore: bump @types/node from 14.14.35 to 14.14.37 (#3239) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 14.14.35 to 14.14.37. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 1e417e260b51..f47a820ae84a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1933,9 +1933,9 @@ integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY= "@types/node@*", "@types/node@>= 8", "@types/node@^14.14.27": - version "14.14.35" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.35.tgz#42c953a4e2b18ab931f72477e7012172f4ffa313" - integrity sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag== + version "14.14.37" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.37.tgz#a3dd8da4eb84a996c36e331df98d82abd76b516e" + integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw== "@types/normalize-package-data@^2.4.0": version "2.4.0" From 1b41d60e7e9c44f929e012761155abf3d39b2cea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Mar 2021 12:02:28 -0700 Subject: [PATCH 05/14] chore: bump @types/jest from 26.0.21 to 26.0.22 (#3240) Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 26.0.21 to 26.0.22. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index f47a820ae84a..4d04b9fd9e93 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1895,9 +1895,9 @@ "@types/jest" "*" "@types/jest@*", "@types/jest@^26.0.20": - version "26.0.21" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.21.tgz#3a73c2731e7e4f0fbaea56ce7ff8c79cf812bd24" - integrity sha512-ab9TyM/69yg7eew9eOwKMUmvIZAKEGZYlq/dhe5/0IMUd/QLJv5ldRMdddSn+u22N13FP3s5jYyktxuBwY0kDA== + version "26.0.22" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.22.tgz#8308a1debdf1b807aa47be2838acdcd91e88fbe6" + integrity sha512-eeWwWjlqxvBxc4oQdkueW5OF/gtfSceKk4OnOAGlUSwS/liBRtZppbJuz1YkgbrbfGOoeBHun9fOvXnjNwrSOw== dependencies: jest-diff "^26.0.0" pretty-format "^26.0.0" From 265a039c7e728b719143e09ee61066039d721f62 Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Tue, 30 Mar 2021 04:37:15 +0900 Subject: [PATCH 06/14] fix(eslint-plugin): [no-unnecessary-type-assertion] correct bad fix for angle bracket assertion (#3244) --- .../rules/no-unnecessary-type-assertion.ts | 24 ++++++++++++------- .../no-unnecessary-type-assertion.test.ts | 16 +++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts b/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts index 5ae12f5a33d6..d051179eee3c 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts @@ -258,15 +258,21 @@ export default util.createRule({ node, messageId: 'unnecessaryAssertion', fix(fixer) { - return originalNode.kind === ts.SyntaxKind.TypeAssertionExpression - ? fixer.removeRange([ - node.range[0], - node.expression.range[0] - 1, - ]) - : fixer.removeRange([ - node.expression.range[1] + 1, - node.range[1], - ]); + if (originalNode.kind === ts.SyntaxKind.TypeAssertionExpression) { + const closingAngleBracket = sourceCode.getTokenAfter( + node.typeAnnotation, + ); + return closingAngleBracket?.value === '>' + ? fixer.removeRange([ + node.range[0], + closingAngleBracket.range[1], + ]) + : null; + } + return fixer.removeRange([ + node.expression.range[1] + 1, + node.range[1], + ]); }, }); } diff --git a/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts index 65d0874dd3af..6d3563a0ccdd 100644 --- a/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts @@ -358,6 +358,22 @@ function foo(bar: T) { }, { code: ` +declare const foo: Foo; +const bar = foo; + `, + output: ` +declare const foo: Foo; +const bar = foo; + `, + errors: [ + { + messageId: 'unnecessaryAssertion', + line: 3, + }, + ], + }, + { + code: ` declare function nonNull(s: string | null); let s: string | null = null; nonNull(s!); From 329ef023090c004694b5996ddb04fdde5b05ebb0 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 29 Mar 2021 15:38:30 -0400 Subject: [PATCH 07/14] fix(eslint-plugin): [no-type-alias] consider `keyof` as an alias (#3242) --- packages/eslint-plugin/src/rules/no-type-alias.ts | 7 ++++--- packages/eslint-plugin/tests/rules/no-type-alias.test.ts | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-type-alias.ts b/packages/eslint-plugin/src/rules/no-type-alias.ts index c53b7d1ee68c..9b80efdd9d64 100644 --- a/packages/eslint-plugin/src/rules/no-type-alias.ts +++ b/packages/eslint-plugin/src/rules/no-type-alias.ts @@ -264,9 +264,10 @@ export default util.createRule({ type.node.type.endsWith('Keyword') || aliasTypes.has(type.node.type) || (type.node.type === AST_NODE_TYPES.TSTypeOperator && - type.node.operator === 'readonly' && - type.node.typeAnnotation && - aliasTypes.has(type.node.typeAnnotation.type)) + (type.node.operator === 'keyof' || + (type.node.operator === 'readonly' && + type.node.typeAnnotation && + aliasTypes.has(type.node.typeAnnotation.type)))) ) { // alias / keyword checkAndReport(allowAliases!, isTopLevel, type, 'Aliases'); diff --git a/packages/eslint-plugin/tests/rules/no-type-alias.test.ts b/packages/eslint-plugin/tests/rules/no-type-alias.test.ts index e06233aeb466..b48acae7e17f 100644 --- a/packages/eslint-plugin/tests/rules/no-type-alias.test.ts +++ b/packages/eslint-plugin/tests/rules/no-type-alias.test.ts @@ -394,6 +394,13 @@ export type ClassValue = code: 'type Foo = typeof bar;', options: [{ allowAliases: 'always' }], }, + { + code: ` +const WithAKey = { AKey: true }; +type KeyNames = keyof typeof SCALARS; + `, + options: [{ allowAliases: 'always' }], + }, { code: 'type Foo = typeof bar | typeof baz;', options: [{ allowAliases: 'in-unions' }], From 62dfcc63f3b6637b0105e2b1551333d7e5d3a215 Mon Sep 17 00:00:00 2001 From: Vitaliy Ryaboy Date: Mon, 29 Mar 2021 21:39:17 +0200 Subject: [PATCH 08/14] docs(eslint-plugin): [typedef] fix typo (#3243) --- packages/eslint-plugin/docs/rules/typedef.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/docs/rules/typedef.md b/packages/eslint-plugin/docs/rules/typedef.md index 6c96fa0317da..03409e110bf8 100644 --- a/packages/eslint-plugin/docs/rules/typedef.md +++ b/packages/eslint-plugin/docs/rules/typedef.md @@ -114,7 +114,7 @@ const mapper = { Examples of **correct** code with `{ "arrowParameter": true }`: ```ts -const logsSize = (size: number) => console.log(text); +const logsSize = (size: number) => console.log(size); ['hello', 'world'].map((text: string) => text.length); From b1aa7dc6971ee8409b729dffb8b69478455734ed Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Fri, 2 Apr 2021 13:19:45 -0700 Subject: [PATCH 09/14] feat(eslint-plugin): [no-unsafe-argument] add rule (#3256) Fixes #791 --- packages/eslint-plugin/README.md | 1 + .../docs/rules/no-unsafe-argument.md | 69 +++++ .../docs/rules/no-unsafe-return.md | 2 +- packages/eslint-plugin/src/configs/all.ts | 1 + packages/eslint-plugin/src/rules/index.ts | 2 + .../src/rules/no-unsafe-argument.ts | 220 ++++++++++++++ .../tests/rules/no-unsafe-argument.test.ts | 268 ++++++++++++++++++ 7 files changed, 562 insertions(+), 1 deletion(-) create mode 100644 packages/eslint-plugin/docs/rules/no-unsafe-argument.md create mode 100644 packages/eslint-plugin/src/rules/no-unsafe-argument.ts create mode 100644 packages/eslint-plugin/tests/rules/no-unsafe-argument.test.ts diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index 69ea06c23082..32b0cbb72316 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -143,6 +143,7 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int | [`@typescript-eslint/no-unnecessary-type-arguments`](./docs/rules/no-unnecessary-type-arguments.md) | Enforces that type arguments will not be used if not required | | :wrench: | :thought_balloon: | | [`@typescript-eslint/no-unnecessary-type-assertion`](./docs/rules/no-unnecessary-type-assertion.md) | Warns if a type assertion does not change the type of an expression | :heavy_check_mark: | :wrench: | :thought_balloon: | | [`@typescript-eslint/no-unnecessary-type-constraint`](./docs/rules/no-unnecessary-type-constraint.md) | Disallows unnecessary constraints on generic types | | :wrench: | | +| [`@typescript-eslint/no-unsafe-argument`](./docs/rules/no-unsafe-argument.md) | Disallows calling an function with an any type value | | | :thought_balloon: | | [`@typescript-eslint/no-unsafe-assignment`](./docs/rules/no-unsafe-assignment.md) | Disallows assigning any to variables and properties | :heavy_check_mark: | | :thought_balloon: | | [`@typescript-eslint/no-unsafe-call`](./docs/rules/no-unsafe-call.md) | Disallows calling an any type value | :heavy_check_mark: | | :thought_balloon: | | [`@typescript-eslint/no-unsafe-member-access`](./docs/rules/no-unsafe-member-access.md) | Disallows member access on any typed variables | :heavy_check_mark: | | :thought_balloon: | diff --git a/packages/eslint-plugin/docs/rules/no-unsafe-argument.md b/packages/eslint-plugin/docs/rules/no-unsafe-argument.md new file mode 100644 index 000000000000..d8e3456d18a8 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/no-unsafe-argument.md @@ -0,0 +1,69 @@ +# Disallows calling an function with an any type value (`no-unsafe-argument`) + +Despite your best intentions, the `any` type can sometimes leak into your codebase. +Call a function with `any` typed argument are not checked at all by TypeScript, so it creates a potential safety hole, and source of bugs in your codebase. + +## Rule Details + +This rule disallows calling a function with `any` in its arguments, and it will disallow spreading `any[]`. +This rule also disallows spreading a tuple type with one of its elements typed as `any`. +This rule also compares the argument's type to the variable's type to ensure you don't pass an unsafe `any` in a generic position to a receiver that's expecting a specific type. For example, it will error if you assign `Set` to an argument declared as `Set`. + +Examples of **incorrect** code for this rule: + +```ts +declare function foo(arg1: string, arg2: number, arg2: string): void; + +const anyTyped = 1 as any; + +foo(...anyTyped); +foo(anyTyped, 1, 'a'); + +const anyArray: any[] = []; +foo(...anyArray); + +const tuple1 = ['a', anyTyped, 'b'] as const; +foo(...tuple1); + +const tuple2 = [1] as const; +foo('a', ...tuple, anyTyped); + +declare function bar(arg1: string, arg2: number, ...rest: string[]): void; +const x = [1, 2] as [number, ...number[]]; +foo('a', ...x, anyTyped); + +declare function baz(arg1: Set, arg2: Map): void; +foo(new Set(), new Map()); +``` + +Examples of **correct** code for this rule: + +```ts +declare function foo(arg1: string, arg2: number, arg2: string): void; + +foo('a', 1, 'b'); + +const tuple1 = ['a', 1, 'b'] as const; +foo(...tuple1); + +declare function bar(arg1: string, arg2: number, ...rest: string[]): void; +const array: string[] = ['a']; +bar('a', 1, ...array); + +declare function baz(arg1: Set, arg2: Map): void; +foo(new Set(), new Map()); +``` + +There are cases where the rule allows passing an argument of `any` to `unknown`. + +Example of `any` to `unknown` assignment that are allowed. + +```ts +declare function foo(arg1: unknown, arg2: Set, arg3: unknown[]): void; +foo(1 as any, new Set(), [] as any[]); +``` + +## Related to + +- [`no-explicit-any`](./no-explicit-any.md) +- TSLint: [`no-unsafe-any`](https://palantir.github.io/tslint/rules/no-unsafe-any/) diff --git a/packages/eslint-plugin/docs/rules/no-unsafe-return.md b/packages/eslint-plugin/docs/rules/no-unsafe-return.md index 9810be3cf16f..225593eb02df 100644 --- a/packages/eslint-plugin/docs/rules/no-unsafe-return.md +++ b/packages/eslint-plugin/docs/rules/no-unsafe-return.md @@ -1,7 +1,7 @@ # Disallows returning any from a function (`no-unsafe-return`) Despite your best intentions, the `any` type can sometimes leak into your codebase. -Returned `any` typed values not checked at all by TypeScript, so it creates a potential safety hole, and source of bugs in your codebase. +Returned `any` typed values are not checked at all by TypeScript, so it creates a potential safety hole, and source of bugs in your codebase. ## Rule Details diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts index 98afc4ae3a45..b21d14efc9f0 100644 --- a/packages/eslint-plugin/src/configs/all.ts +++ b/packages/eslint-plugin/src/configs/all.ts @@ -99,6 +99,7 @@ export = { '@typescript-eslint/no-unnecessary-type-arguments': 'error', '@typescript-eslint/no-unnecessary-type-assertion': 'error', '@typescript-eslint/no-unnecessary-type-constraint': 'error', + '@typescript-eslint/no-unsafe-argument': 'error', '@typescript-eslint/no-unsafe-assignment': 'error', '@typescript-eslint/no-unsafe-call': 'error', '@typescript-eslint/no-unsafe-member-access': 'error', diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index ffa70e57a290..be78db26f806 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -68,6 +68,7 @@ import noUnnecessaryQualifier from './no-unnecessary-qualifier'; import noUnnecessaryTypeArguments from './no-unnecessary-type-arguments'; import noUnnecessaryTypeAssertion from './no-unnecessary-type-assertion'; import noUnnecessaryTypeConstraint from './no-unnecessary-type-constraint'; +import noUnsafeArgument from './no-unsafe-argument'; import noUnsafeAssignment from './no-unsafe-assignment'; import noUnsafeCall from './no-unsafe-call'; import noUnsafeMemberAccess from './no-unsafe-member-access'; @@ -185,6 +186,7 @@ export default { 'no-unnecessary-type-arguments': noUnnecessaryTypeArguments, 'no-unnecessary-type-assertion': noUnnecessaryTypeAssertion, 'no-unnecessary-type-constraint': noUnnecessaryTypeConstraint, + 'no-unsafe-argument': noUnsafeArgument, 'no-unsafe-assignment': noUnsafeAssignment, 'no-unsafe-call': noUnsafeCall, 'no-unsafe-member-access': noUnsafeMemberAccess, diff --git a/packages/eslint-plugin/src/rules/no-unsafe-argument.ts b/packages/eslint-plugin/src/rules/no-unsafe-argument.ts new file mode 100644 index 000000000000..23c8b7bd5080 --- /dev/null +++ b/packages/eslint-plugin/src/rules/no-unsafe-argument.ts @@ -0,0 +1,220 @@ +import { + AST_NODE_TYPES, + TSESTree, +} from '@typescript-eslint/experimental-utils'; +import * as ts from 'typescript'; +import * as util from '../util'; + +type MessageIds = + | 'unsafeArgument' + | 'unsafeTupleSpread' + | 'unsafeArraySpread' + | 'unsafeSpread'; + +class FunctionSignature { + public static create( + checker: ts.TypeChecker, + tsNode: ts.CallLikeExpression, + ): FunctionSignature | null { + const signature = checker.getResolvedSignature(tsNode); + if (!signature) { + return null; + } + + const paramTypes: ts.Type[] = []; + let restType: ts.Type | null = null; + + for (const param of signature.getParameters()) { + const type = checker.getTypeOfSymbolAtLocation(param, tsNode); + + const decl = param.getDeclarations()?.[0]; + if (decl && ts.isParameter(decl) && decl.dotDotDotToken) { + // is a rest param + if (checker.isArrayType(type)) { + restType = checker.getTypeArguments(type)[0]; + } else { + restType = type; + } + break; + } + + paramTypes.push(type); + } + + return new this(paramTypes, restType); + } + + private hasConsumedArguments = false; + + private constructor( + private paramTypes: ts.Type[], + private restType: ts.Type | null, + ) {} + + public getParameterType(index: number): ts.Type | null { + if (index >= this.paramTypes.length || this.hasConsumedArguments) { + return this.restType; + } + return this.paramTypes[index]; + } + + public consumeRemainingArguments(): void { + this.hasConsumedArguments = true; + } +} + +export default util.createRule<[], MessageIds>({ + name: 'no-unsafe-argument', + meta: { + type: 'problem', + docs: { + description: 'Disallows calling an function with an any type value', + category: 'Possible Errors', + // TODO - enable this with next breaking + recommended: false, + requiresTypeChecking: true, + }, + messages: { + unsafeArgument: + 'Unsafe argument of type `{{sender}}` assigned to a parameter of type `{{receiver}}`.', + unsafeTupleSpread: + 'Unsafe spread of a tuple type. The {{index}} element is of type `{{sender}}` and is assigned to a parameter of type `{{reciever}}`.', + unsafeArraySpread: 'Unsafe spread of an `any` array type.', + unsafeSpread: 'Unsafe spread of an `any` type.', + }, + schema: [], + }, + defaultOptions: [], + create(context) { + const { program, esTreeNodeToTSNodeMap } = util.getParserServices(context); + const checker = program.getTypeChecker(); + + return { + 'CallExpression, NewExpression'( + node: TSESTree.CallExpression | TSESTree.NewExpression, + ): void { + if (node.arguments.length === 0) { + return; + } + + // ignore any-typed calls as these are caught by no-unsafe-call + if ( + util.isTypeAnyType( + checker.getTypeAtLocation(esTreeNodeToTSNodeMap.get(node.callee)), + ) + ) { + return; + } + + const tsNode = esTreeNodeToTSNodeMap.get(node); + const signature = FunctionSignature.create(checker, tsNode); + if (!signature) { + return; + } + + let parameterTypeIndex = 0; + for ( + let i = 0; + i < node.arguments.length; + i += 1, parameterTypeIndex += 1 + ) { + const argument = node.arguments[i]; + + switch (argument.type) { + // spreads consume + case AST_NODE_TYPES.SpreadElement: { + const spreadArgType = checker.getTypeAtLocation( + esTreeNodeToTSNodeMap.get(argument.argument), + ); + + if (util.isTypeAnyType(spreadArgType)) { + // foo(...any) + context.report({ + node: argument, + messageId: 'unsafeSpread', + }); + } else if (util.isTypeAnyArrayType(spreadArgType, checker)) { + // foo(...any[]) + + // TODO - we could break down the spread and compare the array type against each argument + context.report({ + node: argument, + messageId: 'unsafeArraySpread', + }); + } else if (checker.isTupleType(spreadArgType)) { + // foo(...[tuple1, tuple2]) + const spreadTypeArguments = checker.getTypeArguments( + spreadArgType, + ); + for ( + let j = 0; + j < spreadTypeArguments.length; + j += 1, parameterTypeIndex += 1 + ) { + const tupleType = spreadTypeArguments[j]; + const parameterType = signature.getParameterType( + parameterTypeIndex, + ); + if (parameterType == null) { + continue; + } + const result = util.isUnsafeAssignment( + tupleType, + parameterType, + checker, + ); + if (result) { + context.report({ + node: argument, + messageId: 'unsafeTupleSpread', + data: { + sender: checker.typeToString(tupleType), + receiver: checker.typeToString(parameterType), + }, + }); + } + } + if (spreadArgType.target.hasRestElement) { + // the last element was a rest - so all remaining defined arguments can be considered "consumed" + // all remaining arguments should be compared against the rest type (if one exists) + signature.consumeRemainingArguments(); + } + } else { + // something that's iterable + // handling this will be pretty complex - so we ignore it for now + // TODO - handle generic iterable case + } + break; + } + + default: { + const parameterType = signature.getParameterType(i); + if (parameterType == null) { + continue; + } + + const argumentType = checker.getTypeAtLocation( + esTreeNodeToTSNodeMap.get(argument), + ); + const result = util.isUnsafeAssignment( + argumentType, + parameterType, + checker, + ); + if (result) { + context.report({ + node: argument, + messageId: 'unsafeArgument', + data: { + sender: checker.typeToString(argumentType), + receiver: checker.typeToString(parameterType), + }, + }); + } + } + } + } + }, + }; + }, +}); diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-argument.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-argument.test.ts new file mode 100644 index 000000000000..395f47344cb2 --- /dev/null +++ b/packages/eslint-plugin/tests/rules/no-unsafe-argument.test.ts @@ -0,0 +1,268 @@ +import rule from '../../src/rules/no-unsafe-argument'; +import { RuleTester, getFixturesRootDir } from '../RuleTester'; + +const ruleTester = new RuleTester({ + parser: '@typescript-eslint/parser', + parserOptions: { + project: './tsconfig.json', + tsconfigRootDir: getFixturesRootDir(), + }, +}); + +ruleTester.run('no-unsafe-argument', rule, { + valid: [ + ` +declare function foo(arg: number): void; +foo(1); + `, + ` +declare function foo(arg: number, arg2: string): void; +foo(1, 'a'); + `, + ` +declare function foo(arg: any): void; +foo(1 as any); + `, + ` +declare function foo(arg: unknown): void; +foo(1 as any); + `, + ` +declare function foo(...arg: number[]): void; +foo(1, 2, 3); + `, + ` +declare function foo(...arg: any[]): void; +foo(1, 2, 3, 4 as any); + `, + ` +declare function foo(arg: number, arg2: number): void; +const x = [1, 2] as const; +foo(...x); + `, + ` +declare function foo(arg: any, arg2: number): void; +const x = [1 as any, 2] as const; +foo(...x); + `, + ` +declare function foo(arg1: string, arg2: string): void; +const x: string[] = []; +foo(...x); + `, + ` +declare function foo(arg1: Set, arg2: Map): void; + +const x = [new Map()] as const; +foo(new Set(), ...x); + `, + ` +declare function foo(arg1: unknown, arg2: Set, arg3: unknown[]): void; +foo(1 as any, new Set(), [] as any[]); + `, + ], + invalid: [ + { + code: ` +declare function foo(arg: number): void; +foo(1 as any); + `, + errors: [ + { + messageId: 'unsafeArgument', + line: 3, + column: 5, + endColumn: 13, + data: { + sender: 'any', + receiver: 'number', + }, + }, + ], + }, + { + code: ` +declare function foo(arg1: number, arg2: string): void; +foo(1, 1 as any); + `, + errors: [ + { + messageId: 'unsafeArgument', + line: 3, + column: 8, + endColumn: 16, + data: { + sender: 'any', + receiver: 'string', + }, + }, + ], + }, + { + code: ` +declare function foo(...arg: number[]): void; +foo(1, 2, 3, 1 as any); + `, + errors: [ + { + messageId: 'unsafeArgument', + line: 3, + column: 14, + endColumn: 22, + data: { + sender: 'any', + receiver: 'number', + }, + }, + ], + }, + { + code: ` +declare function foo(arg: string, ...arg: number[]): void; +foo(1 as any, 1 as any); + `, + errors: [ + { + messageId: 'unsafeArgument', + line: 3, + column: 5, + endColumn: 13, + data: { + sender: 'any', + receiver: 'string', + }, + }, + { + messageId: 'unsafeArgument', + line: 3, + column: 15, + endColumn: 23, + data: { + sender: 'any', + receiver: 'number', + }, + }, + ], + }, + { + code: ` +declare function foo(arg1: string, arg2: number): void; + +foo(...(x as any)); + `, + errors: [ + { + messageId: 'unsafeSpread', + line: 4, + column: 5, + endColumn: 18, + }, + ], + }, + { + code: ` +declare function foo(arg1: string, arg2: number): void; + +foo(...(x as any[])); + `, + errors: [ + { + messageId: 'unsafeArraySpread', + line: 4, + column: 5, + endColumn: 20, + }, + ], + }, + { + code: ` +declare function foo(arg1: string, arg2: number): void; + +const x = ['a', 1 as any] as const; +foo(...x); + `, + errors: [ + { + messageId: 'unsafeTupleSpread', + line: 5, + column: 5, + endColumn: 9, + data: { + sender: 'any', + receiver: 'number', + }, + }, + ], + }, + { + code: ` +declare function foo(arg1: string, arg2: number, arg2: string): void; + +const x = [1] as const; +foo('a', ...x, 1 as any); + `, + errors: [ + { + messageId: 'unsafeArgument', + line: 5, + column: 16, + endColumn: 24, + data: { + sender: 'any', + receiver: 'string', + }, + }, + ], + }, + { + code: ` +declare function foo(arg1: string, arg2: number, ...rest: string[]): void; + +const x = [1, 2] as [number, ...number[]]; +foo('a', ...x, 1 as any); + `, + errors: [ + { + messageId: 'unsafeArgument', + line: 5, + column: 16, + endColumn: 24, + data: { + sender: 'any', + receiver: 'string', + }, + }, + ], + }, + { + code: ` +declare function foo(arg1: Set, arg2: Map): void; + +const x = [new Map()] as const; +foo(new Set(), ...x); + `, + errors: [ + { + messageId: 'unsafeArgument', + line: 5, + column: 5, + endColumn: 19, + data: { + sender: 'Set', + receiver: 'Set', + }, + }, + { + messageId: 'unsafeTupleSpread', + line: 5, + column: 21, + endColumn: 25, + data: { + sender: 'Map', + receiver: 'Map', + }, + }, + ], + }, + ], +}); From b1b26c4843a4cfa209a0c9c3d8bea1de37333b48 Mon Sep 17 00:00:00 2001 From: JounQin Date: Sat, 3 Apr 2021 04:23:32 +0800 Subject: [PATCH 10/14] feat(eslint-plugin): [no-unsafe-call][no-unsafe-member-access] improve report messages for `this` for `noImplicitThis` (#3199) --- .../src/rules/no-unsafe-assignment.ts | 39 +++++++++++++++--- .../eslint-plugin/src/rules/no-unsafe-call.ts | 34 ++++++++++++++- .../src/rules/no-unsafe-member-access.ts | 36 +++++++++++++++- .../src/rules/no-unsafe-return.ts | 38 ++++++++++++++--- .../src/util/getThisExpression.ts | 24 +++++++++++ packages/eslint-plugin/src/util/index.ts | 1 + .../fixtures/tsconfig.noImplicitThis.json | 6 +++ .../tests/rules/no-unsafe-assignment.test.ts | 17 +++++++- .../tests/rules/no-unsafe-call.test.ts | 31 +++++++++++++- .../rules/no-unsafe-member-access.test.ts | 41 ++++++++++++++++++- .../tests/rules/no-unsafe-return.test.ts | 27 +++++++++++- 11 files changed, 276 insertions(+), 18 deletions(-) create mode 100644 packages/eslint-plugin/src/util/getThisExpression.ts create mode 100644 packages/eslint-plugin/tests/fixtures/tsconfig.noImplicitThis.json diff --git a/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts b/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts index 4a8f2a9ea237..ac8152085449 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts @@ -2,8 +2,10 @@ import { TSESTree, AST_NODE_TYPES, } from '@typescript-eslint/experimental-utils'; +import * as tsutils from 'tsutils'; import * as ts from 'typescript'; import * as util from '../util'; +import { getThisExpression } from '../util'; const enum ComparisonType { /** Do no assignment comparison */ @@ -25,13 +27,17 @@ export default util.createRule({ requiresTypeChecking: true, }, messages: { - anyAssignment: 'Unsafe assignment of an any value.', - unsafeArrayPattern: 'Unsafe array destructuring of an any array value.', + anyAssignment: 'Unsafe assignment of an `any` value.', + anyAssignmentThis: [ + 'Unsafe assignment of an `any` value. `this` is typed as `any`.', + 'You can try to fix this by turning on the `noImplicitThis` compiler option, or adding a `this` parameter to the function.', + ].join('\n'), + unsafeArrayPattern: 'Unsafe array destructuring of an `any` array value.', unsafeArrayPatternFromTuple: - 'Unsafe array destructuring of a tuple element with an any value.', + 'Unsafe array destructuring of a tuple element with an `any` value.', unsafeAssignment: 'Unsafe assignment of type {{sender}} to a variable of type {{receiver}}.', - unsafeArraySpread: 'Unsafe spread of an any value in an array.', + unsafeArraySpread: 'Unsafe spread of an `any` value in an array.', }, schema: [], }, @@ -39,6 +45,11 @@ export default util.createRule({ create(context) { const { program, esTreeNodeToTSNodeMap } = util.getParserServices(context); const checker = program.getTypeChecker(); + const compilerOptions = program.getCompilerOptions(); + const isNoImplicitThis = tsutils.isStrictCompilerOptionEnabled( + compilerOptions, + 'noImplicitThis', + ); // returns true if the assignment reported function checkArrayDestructureHelper( @@ -243,9 +254,27 @@ export default util.createRule({ return false; } + let messageId: 'anyAssignment' | 'anyAssignmentThis' = 'anyAssignment'; + + if (!isNoImplicitThis) { + // `var foo = this` + const thisExpression = getThisExpression(senderNode); + if ( + thisExpression && + util.isTypeAnyType( + util.getConstrainedTypeAtLocation( + checker, + esTreeNodeToTSNodeMap.get(thisExpression), + ), + ) + ) { + messageId = 'anyAssignmentThis'; + } + } + context.report({ node: reportingNode, - messageId: 'anyAssignment', + messageId, }); return true; } diff --git a/packages/eslint-plugin/src/rules/no-unsafe-call.ts b/packages/eslint-plugin/src/rules/no-unsafe-call.ts index 0535bfeab316..b08214d36c27 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-call.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-call.ts @@ -1,7 +1,13 @@ import { TSESTree } from '@typescript-eslint/experimental-utils'; +import * as tsutils from 'tsutils'; import * as util from '../util'; +import { getThisExpression } from '../util'; -type MessageIds = 'unsafeCall' | 'unsafeNew' | 'unsafeTemplateTag'; +type MessageIds = + | 'unsafeCall' + | 'unsafeCallThis' + | 'unsafeNew' + | 'unsafeTemplateTag'; export default util.createRule<[], MessageIds>({ name: 'no-unsafe-call', @@ -14,7 +20,11 @@ export default util.createRule<[], MessageIds>({ requiresTypeChecking: true, }, messages: { - unsafeCall: 'Unsafe call of an any typed value.', + unsafeCall: 'Unsafe call of an `any` typed value.', + unsafeCallThis: [ + 'Unsafe call of an `any` typed value. `this` is typed as `any`.', + 'You can try to fix this by turning on the `noImplicitThis` compiler option, or adding a `this` parameter to the function.', + ].join('\n'), unsafeNew: 'Unsafe construction of an any type value.', unsafeTemplateTag: 'Unsafe any typed template tag.', }, @@ -24,6 +34,11 @@ export default util.createRule<[], MessageIds>({ create(context) { const { program, esTreeNodeToTSNodeMap } = util.getParserServices(context); const checker = program.getTypeChecker(); + const compilerOptions = program.getCompilerOptions(); + const isNoImplicitThis = tsutils.isStrictCompilerOptionEnabled( + compilerOptions, + 'noImplicitThis', + ); function checkCall( node: TSESTree.Node, @@ -34,6 +49,21 @@ export default util.createRule<[], MessageIds>({ const type = util.getConstrainedTypeAtLocation(checker, tsNode); if (util.isTypeAnyType(type)) { + if (!isNoImplicitThis) { + // `this()` or `this.foo()` or `this.foo[bar]()` + const thisExpression = getThisExpression(node); + if ( + thisExpression && + util.isTypeAnyType( + util.getConstrainedTypeAtLocation( + checker, + esTreeNodeToTSNodeMap.get(thisExpression), + ), + ) + ) { + messageId = 'unsafeCallThis'; + } + } context.report({ node: reportingNode, messageId: messageId, diff --git a/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts b/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts index b326c754136b..13fd7bf0821b 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts @@ -2,7 +2,9 @@ import { TSESTree, AST_NODE_TYPES, } from '@typescript-eslint/experimental-utils'; +import * as tsutils from 'tsutils'; import * as util from '../util'; +import { getThisExpression } from '../util'; const enum State { Unsafe = 1, @@ -21,7 +23,11 @@ export default util.createRule({ }, messages: { unsafeMemberExpression: - 'Unsafe member access {{property}} on an any value.', + 'Unsafe member access {{property}} on an `any` value.', + unsafeThisMemberExpression: [ + 'Unsafe member access {{property}} on an `any` value. `this` is typed as `any`.', + 'You can try to fix this by turning on the `noImplicitThis` compiler option, or adding a `this` parameter to the function.', + ].join('\n'), unsafeComputedMemberAccess: 'Computed name {{property}} resolves to an any value.', }, @@ -31,6 +37,11 @@ export default util.createRule({ create(context) { const { program, esTreeNodeToTSNodeMap } = util.getParserServices(context); const checker = program.getTypeChecker(); + const compilerOptions = program.getCompilerOptions(); + const isNoImplicitThis = tsutils.isStrictCompilerOptionEnabled( + compilerOptions, + 'noImplicitThis', + ); const sourceCode = context.getSourceCode(); const stateCache = new Map(); @@ -58,9 +69,30 @@ export default util.createRule({ if (state === State.Unsafe) { const propertyName = sourceCode.getText(node.property); + + let messageId: 'unsafeMemberExpression' | 'unsafeThisMemberExpression' = + 'unsafeMemberExpression'; + + if (!isNoImplicitThis) { + // `this.foo` or `this.foo[bar]` + const thisExpression = getThisExpression(node); + + if ( + thisExpression && + util.isTypeAnyType( + util.getConstrainedTypeAtLocation( + checker, + esTreeNodeToTSNodeMap.get(thisExpression), + ), + ) + ) { + messageId = 'unsafeThisMemberExpression'; + } + } + context.report({ node, - messageId: 'unsafeMemberExpression', + messageId, data: { property: node.computed ? `[${propertyName}]` : `.${propertyName}`, }, diff --git a/packages/eslint-plugin/src/rules/no-unsafe-return.ts b/packages/eslint-plugin/src/rules/no-unsafe-return.ts index c2366bc96f2e..a818be4ef4ee 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-return.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-return.ts @@ -2,8 +2,9 @@ import { TSESTree, AST_NODE_TYPES, } from '@typescript-eslint/experimental-utils'; -import { isExpression } from 'tsutils'; +import * as tsutils from 'tsutils'; import * as util from '../util'; +import { getThisExpression } from '../util'; export default util.createRule({ name: 'no-unsafe-return', @@ -16,9 +17,13 @@ export default util.createRule({ requiresTypeChecking: true, }, messages: { - unsafeReturn: 'Unsafe return of an {{type}} typed value', + unsafeReturn: 'Unsafe return of an `{{type}}` typed value.', + unsafeReturnThis: [ + 'Unsafe return of an `{{type}}` typed value. `this` is typed as `any`.', + 'You can try to fix this by turning on the `noImplicitThis` compiler option, or adding a `this` parameter to the function.', + ].join('\n'), unsafeReturnAssignment: - 'Unsafe return of type {{sender}} from function with return type {{receiver}}.', + 'Unsafe return of type `{{sender}}` from function with return type `{{receiver}}`.', }, schema: [], }, @@ -26,6 +31,11 @@ export default util.createRule({ create(context) { const { program, esTreeNodeToTSNodeMap } = util.getParserServices(context); const checker = program.getTypeChecker(); + const compilerOptions = program.getCompilerOptions(); + const isNoImplicitThis = tsutils.isStrictCompilerOptionEnabled( + compilerOptions, + 'noImplicitThis', + ); function getParentFunctionNode( node: TSESTree.Node, @@ -74,7 +84,7 @@ export default util.createRule({ // so we have to use the contextual typing in these cases, i.e. // const foo1: () => Set = () => new Set(); // the return type of the arrow function is Set even though the variable is typed as Set - let functionType = isExpression(functionTSNode) + let functionType = tsutils.isExpression(functionTSNode) ? util.getContextualType(checker, functionTSNode) : checker.getTypeAtLocation(functionTSNode); if (!functionType) { @@ -100,10 +110,28 @@ export default util.createRule({ } } + let messageId: 'unsafeReturn' | 'unsafeReturnThis' = 'unsafeReturn'; + + if (!isNoImplicitThis) { + // `return this` + const thisExpression = getThisExpression(returnNode); + if ( + thisExpression && + util.isTypeAnyType( + util.getConstrainedTypeAtLocation( + checker, + esTreeNodeToTSNodeMap.get(thisExpression), + ), + ) + ) { + messageId = 'unsafeReturnThis'; + } + } + // If the function return type was not unknown/unknown[], mark usage as unsafeReturn. return context.report({ node: reportingNode, - messageId: 'unsafeReturn', + messageId, data: { type: anyType === util.AnyType.Any ? 'any' : 'any[]', }, diff --git a/packages/eslint-plugin/src/util/getThisExpression.ts b/packages/eslint-plugin/src/util/getThisExpression.ts new file mode 100644 index 000000000000..5e2772aebaec --- /dev/null +++ b/packages/eslint-plugin/src/util/getThisExpression.ts @@ -0,0 +1,24 @@ +import { + AST_NODE_TYPES, + TSESTree, +} from '@typescript-eslint/experimental-utils'; + +export function getThisExpression( + node: TSESTree.Node, +): TSESTree.ThisExpression | undefined { + while (node) { + if (node.type === AST_NODE_TYPES.CallExpression) { + node = node.callee; + } else if (node.type === AST_NODE_TYPES.ThisExpression) { + return node; + } else if (node.type === AST_NODE_TYPES.MemberExpression) { + node = node.object; + } else if (node.type === AST_NODE_TYPES.ChainExpression) { + node = node.expression; + } else { + break; + } + } + + return; +} diff --git a/packages/eslint-plugin/src/util/index.ts b/packages/eslint-plugin/src/util/index.ts index e7bb53547fc8..79e142b15fd4 100644 --- a/packages/eslint-plugin/src/util/index.ts +++ b/packages/eslint-plugin/src/util/index.ts @@ -4,6 +4,7 @@ export * from './astUtils'; export * from './collectUnusedVariables'; export * from './createRule'; export * from './getFunctionHeadLoc'; +export * from './getThisExpression'; export * from './getWrappingFixer'; export * from './isTypeReadonly'; export * from './misc'; diff --git a/packages/eslint-plugin/tests/fixtures/tsconfig.noImplicitThis.json b/packages/eslint-plugin/tests/fixtures/tsconfig.noImplicitThis.json new file mode 100644 index 000000000000..c017e51c6e4c --- /dev/null +++ b/packages/eslint-plugin/tests/fixtures/tsconfig.noImplicitThis.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noImplicitThis": false + } +} diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts index 6f3baa3fa1a1..b0f8ec612333 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts @@ -68,7 +68,7 @@ function assignmentTest( const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', parserOptions: { - project: './tsconfig.json', + project: './tsconfig.noImplicitThis.json', tsconfigRootDir: getFixturesRootDir(), }, }); @@ -347,5 +347,20 @@ declare function Foo(props: Props): never; }, ], }, + { + code: ` +function foo() { + const bar = this; +} + `, + errors: [ + { + messageId: 'anyAssignmentThis', + line: 3, + column: 9, + endColumn: 19, + }, + ], + }, ], }); diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-call.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-call.test.ts index 981abb0eadde..1f70c30e248c 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-call.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-call.test.ts @@ -9,7 +9,7 @@ import { const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', parserOptions: { - project: './tsconfig.json', + project: './tsconfig.noImplicitThis.json', tsconfigRootDir: getFixturesRootDir(), }, }); @@ -148,5 +148,34 @@ function foo(x: { tag: any }) { x.tag\`foo\` } }, ], }), + { + code: noFormat` +const methods = { + methodA() { + return this.methodB() + }, + methodB() { + return true + }, + methodC() { + return this() + } +}; + `, + errors: [ + { + messageId: 'unsafeCallThis', + line: 4, + column: 12, + endColumn: 24, + }, + { + messageId: 'unsafeCallThis', + line: 10, + column: 12, + endColumn: 16, + }, + ], + }, ], }); diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts index a9c21f8712b9..491d5e97d9f9 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-member-access.test.ts @@ -9,7 +9,7 @@ import { const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', parserOptions: { - project: './tsconfig.json', + project: './tsconfig.noImplicitThis.json', tsconfigRootDir: getFixturesRootDir(), }, }); @@ -202,5 +202,44 @@ function foo(x: string[], y: any) { x[y] } }, ], }), + { + code: noFormat` +const methods = { + methodA() { + return this.methodB() + }, + methodB() { + const getProperty = () => Math.random() > 0.5 ? 'methodB' : 'methodC' + return this[getProperty()]() + }, + methodC() { + return true + }, + methodD() { + return (this?.methodA)?.() + } +}; + `, + errors: [ + { + messageId: 'unsafeThisMemberExpression', + line: 4, + column: 12, + endColumn: 24, + }, + { + messageId: 'unsafeThisMemberExpression', + line: 8, + column: 12, + endColumn: 31, + }, + { + messageId: 'unsafeThisMemberExpression', + line: 14, + column: 13, + endColumn: 26, + }, + ], + }, ], }); diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-return.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-return.test.ts index 7d7777e46632..5cfd965ab8e1 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-return.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-return.test.ts @@ -9,7 +9,7 @@ import { const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', parserOptions: { - project: './tsconfig.json', + project: './tsconfig.noImplicitThis.json', tsconfigRootDir: getFixturesRootDir(), }, }); @@ -293,5 +293,30 @@ receiver(function test() { }, ], }, + { + code: ` +function foo() { + return this; +} + +function bar() { + return () => this; +} + `, + errors: [ + { + messageId: 'unsafeReturnThis', + line: 3, + column: 3, + endColumn: 15, + }, + { + messageId: 'unsafeReturnThis', + line: 7, + column: 16, + endColumn: 20, + }, + ], + }, ], }); From 02214768a3721d8514c70e00546e861da6581e4d Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 5 Apr 2021 00:49:19 -0400 Subject: [PATCH 11/14] fix(eslint-plugin): always ignore assignments in no-unnecessary-type-assertion (#3235) --- .../rules/no-unnecessary-type-assertion.ts | 29 +++++++++++-------- .../no-unnecessary-type-assertion.test.ts | 12 ++++---- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts b/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts index d051179eee3c..d16f494fc4af 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts @@ -137,19 +137,24 @@ export default util.createRule({ TSNonNullExpression(node): void { if ( node.parent?.type === AST_NODE_TYPES.AssignmentExpression && - node.parent?.operator === '=' && - node.parent.left === node + node.parent.operator === '=' ) { - context.report({ - node, - messageId: 'contextuallyUnnecessary', - fix(fixer) { - return fixer.removeRange([ - node.expression.range[1], - node.range[1], - ]); - }, - }); + if (node.parent.left === node) { + context.report({ + node, + messageId: 'contextuallyUnnecessary', + fix(fixer) { + return fixer.removeRange([ + node.expression.range[1], + node.range[1], + ]); + }, + }); + } + // for all other = assignments we ignore non-null checks + // this is because non-null assertions can change the type-flow of the code + // so whilst they might be unnecessary for the assignment - they are necessary + // for following code return; } diff --git a/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts index 6d3563a0ccdd..7cd169601392 100644 --- a/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts @@ -202,6 +202,12 @@ let a: { b?: string } | undefined; a!.b = ''; `, }, + ` +let value: number | undefined; +let values: number[] = []; + +value = values.pop()!; + `, ], invalid: [ @@ -493,14 +499,10 @@ y! = 0; output: ` let x: number | undefined; let y: number | undefined; -y = x; +y = x!; y = 0; `, errors: [ - { - messageId: 'contextuallyUnnecessary', - line: 4, - }, { messageId: 'contextuallyUnnecessary', line: 5, From 0913f40c87762de198b05a5473b4fb79aeb46967 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 5 Apr 2021 00:51:24 -0400 Subject: [PATCH 12/14] fix(eslint-plugin): [strict-boolean-expressions] account for truthy literals (#3236) --- .../src/rules/strict-boolean-expressions.ts | 49 ++++++++++++------ .../rules/strict-boolean-expressions.test.ts | 51 +++++++++++++++++++ 2 files changed, 85 insertions(+), 15 deletions(-) diff --git a/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts index b8e25d4542a3..87796f9f4279 100644 --- a/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts +++ b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts @@ -308,8 +308,16 @@ export default util.createRule({ return; } + // Known edge case: truthy primitives and nullish values are always valid boolean expressions + if ( + (options.allowNumber && is('nullish', 'truthy number')) || + (options.allowString && is('nullish', 'truthy string')) + ) { + return; + } + // string - if (is('string')) { + if (is('string') || is('truthy string')) { if (!options.allowString) { if (isLogicalNegationExpression(node.parent!)) { // if (!string) @@ -458,7 +466,7 @@ export default util.createRule({ } // number - if (is('number')) { + if (is('number') || is('truthy number')) { if (!options.allowNumber) { if (isArrayLengthExpression(node, typeChecker, parserServices)) { if (isLogicalNegationExpression(node.parent!)) { @@ -701,7 +709,9 @@ export default util.createRule({ | 'nullish' | 'boolean' | 'string' + | 'truthy string' | 'number' + | 'truthy number' | 'object' | 'any' | 'never'; @@ -731,21 +741,30 @@ export default util.createRule({ variantTypes.add('boolean'); } - if ( - types.some(type => tsutils.isTypeFlagSet(type, ts.TypeFlags.StringLike)) - ) { - variantTypes.add('string'); + const strings = types.filter(type => + tsutils.isTypeFlagSet(type, ts.TypeFlags.StringLike), + ); + + if (strings.length) { + if (strings.some(type => type.isStringLiteral() && type.value !== '')) { + variantTypes.add('truthy string'); + } else { + variantTypes.add('string'); + } } - if ( - types.some(type => - tsutils.isTypeFlagSet( - type, - ts.TypeFlags.NumberLike | ts.TypeFlags.BigIntLike, - ), - ) - ) { - variantTypes.add('number'); + const numbers = types.filter(type => + tsutils.isTypeFlagSet( + type, + ts.TypeFlags.NumberLike | ts.TypeFlags.BigIntLike, + ), + ); + if (numbers.length) { + if (numbers.some(type => type.isNumberLiteral() && type.value !== 0)) { + variantTypes.add('truthy number'); + } else { + variantTypes.add('number'); + } } if ( diff --git a/packages/eslint-plugin/tests/rules/strict-boolean-expressions.test.ts b/packages/eslint-plugin/tests/rules/strict-boolean-expressions.test.ts index d24de92ac65f..33ec5ba1badb 100644 --- a/packages/eslint-plugin/tests/rules/strict-boolean-expressions.test.ts +++ b/packages/eslint-plugin/tests/rules/strict-boolean-expressions.test.ts @@ -133,6 +133,57 @@ if (x) { tsconfigRootDir: path.join(rootPath, 'unstrict'), }, }, + + ` +function f(arg: 'a' | null) { + if (arg) console.log(arg); +} + `, + ` +function f(arg: 'a' | 'b' | null) { + if (arg) console.log(arg); +} + `, + { + code: ` +declare const x: 1 | null; +declare const y: 1; +if (x) { +} +if (y) { +} + `, + options: [ + { + allowNumber: true, + }, + ], + }, + ` +function f(arg: 1 | null) { + if (arg) console.log(arg); +} + `, + ` +function f(arg: 1 | 2 | null) { + if (arg) console.log(arg); +} + `, + { + code: ` +declare const x: 'a' | null; +declare const y: 'a'; +if (x) { +} +if (y) { +} + `, + options: [ + { + allowString: true, + }, + ], + }, ], invalid: [ From ccfd68e365391b3f117df96792355f9c3655288c Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 5 Apr 2021 00:54:19 -0400 Subject: [PATCH 13/14] fix(eslint-plugin): [restrict-plus-operands] consider template literal types as strings (#3234) --- packages/eslint-plugin/src/rules/restrict-plus-operands.ts | 5 ++++- .../tests/rules/restrict-plus-operands.test.ts | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts index 0edf8a37d20e..0f3b07e9fb27 100644 --- a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts +++ b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts @@ -57,7 +57,10 @@ export default util.createRule({ if (type.isNumberLiteral()) { return 'number'; } - if (type.isStringLiteral()) { + if ( + type.isStringLiteral() || + util.isTypeFlagSet(type, ts.TypeFlags.TemplateLiteral) + ) { return 'string'; } // is BigIntLiteral diff --git a/packages/eslint-plugin/tests/rules/restrict-plus-operands.test.ts b/packages/eslint-plugin/tests/rules/restrict-plus-operands.test.ts index daa02fa46d9d..af33e3ad3dba 100644 --- a/packages/eslint-plugin/tests/rules/restrict-plus-operands.test.ts +++ b/packages/eslint-plugin/tests/rules/restrict-plus-operands.test.ts @@ -110,6 +110,12 @@ const x = a + b; declare const a: 'string literal' & string; declare const b: string; const x = a + b; + `, + ` +function A(s: string) { + return \`a\${s}b\` as const; +} +const b = A('') + '!'; `, { code: ` From 3181b32d576cb5542cc2346f53cef9d24831f63d Mon Sep 17 00:00:00 2001 From: James Henry Date: Mon, 5 Apr 2021 17:02:11 +0000 Subject: [PATCH 14/14] chore: publish v4.21.0 --- CHANGELOG.md | 21 ++++++++++++++++++++ lerna.json | 2 +- packages/eslint-plugin-internal/CHANGELOG.md | 8 ++++++++ packages/eslint-plugin-internal/package.json | 4 ++-- packages/eslint-plugin-tslint/CHANGELOG.md | 8 ++++++++ packages/eslint-plugin-tslint/package.json | 6 +++--- packages/eslint-plugin/CHANGELOG.md | 21 ++++++++++++++++++++ packages/eslint-plugin/package.json | 6 +++--- packages/experimental-utils/CHANGELOG.md | 8 ++++++++ packages/experimental-utils/package.json | 8 ++++---- packages/parser/CHANGELOG.md | 8 ++++++++ packages/parser/package.json | 10 +++++----- packages/scope-manager/CHANGELOG.md | 8 ++++++++ packages/scope-manager/package.json | 8 ++++---- packages/shared-fixtures/CHANGELOG.md | 8 ++++++++ packages/shared-fixtures/package.json | 2 +- packages/types/CHANGELOG.md | 8 ++++++++ packages/types/package.json | 2 +- packages/typescript-estree/CHANGELOG.md | 8 ++++++++ packages/typescript-estree/package.json | 8 ++++---- packages/visitor-keys/CHANGELOG.md | 8 ++++++++ packages/visitor-keys/package.json | 4 ++-- 22 files changed, 144 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44ebffbf4121..b63444232e33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,27 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.21.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.20.0...v4.21.0) (2021-04-05) + + +### Bug Fixes + +* **eslint-plugin:** [no-type-alias] consider `keyof` as an alias ([#3242](https://github.com/typescript-eslint/typescript-eslint/issues/3242)) ([329ef02](https://github.com/typescript-eslint/typescript-eslint/commit/329ef023090c004694b5996ddb04fdde5b05ebb0)) +* **eslint-plugin:** [no-unnecessary-type-assertion] correct bad fix for angle bracket assertion ([#3244](https://github.com/typescript-eslint/typescript-eslint/issues/3244)) ([265a039](https://github.com/typescript-eslint/typescript-eslint/commit/265a039c7e728b719143e09ee61066039d721f62)) +* **eslint-plugin:** [restrict-plus-operands] consider template literal types as strings ([#3234](https://github.com/typescript-eslint/typescript-eslint/issues/3234)) ([ccfd68e](https://github.com/typescript-eslint/typescript-eslint/commit/ccfd68e365391b3f117df96792355f9c3655288c)) +* **eslint-plugin:** [strict-boolean-expressions] account for truthy literals ([#3236](https://github.com/typescript-eslint/typescript-eslint/issues/3236)) ([0913f40](https://github.com/typescript-eslint/typescript-eslint/commit/0913f40c87762de198b05a5473b4fb79aeb46967)) +* **eslint-plugin:** always ignore assignments in no-unnecessary-type-assertion ([#3235](https://github.com/typescript-eslint/typescript-eslint/issues/3235)) ([0221476](https://github.com/typescript-eslint/typescript-eslint/commit/02214768a3721d8514c70e00546e861da6581e4d)) + + +### Features + +* **eslint-plugin:** [no-unsafe-argument] add rule ([#3256](https://github.com/typescript-eslint/typescript-eslint/issues/3256)) ([b1aa7dc](https://github.com/typescript-eslint/typescript-eslint/commit/b1aa7dc6971ee8409b729dffb8b69478455734ed)), closes [#791](https://github.com/typescript-eslint/typescript-eslint/issues/791) +* **eslint-plugin:** [no-unsafe-call][no-unsafe-member-access] improve report messages for `this` for `noImplicitThis` ([#3199](https://github.com/typescript-eslint/typescript-eslint/issues/3199)) ([b1b26c4](https://github.com/typescript-eslint/typescript-eslint/commit/b1b26c4843a4cfa209a0c9c3d8bea1de37333b48)) + + + + + # [4.20.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.19.0...v4.20.0) (2021-03-29) diff --git a/lerna.json b/lerna.json index 648c75338267..4819dc418597 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "4.20.0", + "version": "4.21.0", "npmClient": "yarn", "useWorkspaces": true, "stream": true diff --git a/packages/eslint-plugin-internal/CHANGELOG.md b/packages/eslint-plugin-internal/CHANGELOG.md index 407982ce241f..891dc4bf1505 100644 --- a/packages/eslint-plugin-internal/CHANGELOG.md +++ b/packages/eslint-plugin-internal/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.21.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.20.0...v4.21.0) (2021-04-05) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal + + + + + # [4.20.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.19.0...v4.20.0) (2021-03-29) **Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index 5334a903a35d..d8402252f45f 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-internal", - "version": "4.20.0", + "version": "4.21.0", "private": true, "main": "dist/index.js", "scripts": { @@ -14,7 +14,7 @@ }, "dependencies": { "@types/prettier": "*", - "@typescript-eslint/experimental-utils": "4.20.0", + "@typescript-eslint/experimental-utils": "4.21.0", "prettier": "*" } } diff --git a/packages/eslint-plugin-tslint/CHANGELOG.md b/packages/eslint-plugin-tslint/CHANGELOG.md index 8a77d768c3a7..cd7ff138b0ff 100644 --- a/packages/eslint-plugin-tslint/CHANGELOG.md +++ b/packages/eslint-plugin-tslint/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.21.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.20.0...v4.21.0) (2021-04-05) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint + + + + + # [4.20.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.19.0...v4.20.0) (2021-03-29) **Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint diff --git a/packages/eslint-plugin-tslint/package.json b/packages/eslint-plugin-tslint/package.json index 4135e7270ea4..00e26e2a6750 100644 --- a/packages/eslint-plugin-tslint/package.json +++ b/packages/eslint-plugin-tslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-tslint", - "version": "4.20.0", + "version": "4.21.0", "main": "dist/index.js", "typings": "src/index.ts", "description": "TSLint wrapper plugin for ESLint", @@ -38,7 +38,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/experimental-utils": "4.20.0", + "@typescript-eslint/experimental-utils": "4.21.0", "lodash": "^4.17.15" }, "peerDependencies": { @@ -48,6 +48,6 @@ }, "devDependencies": { "@types/lodash": "*", - "@typescript-eslint/parser": "4.20.0" + "@typescript-eslint/parser": "4.21.0" } } diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index f9d70654c1f3..890f25c3aacc 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -3,6 +3,27 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.21.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.20.0...v4.21.0) (2021-04-05) + + +### Bug Fixes + +* **eslint-plugin:** [no-type-alias] consider `keyof` as an alias ([#3242](https://github.com/typescript-eslint/typescript-eslint/issues/3242)) ([329ef02](https://github.com/typescript-eslint/typescript-eslint/commit/329ef023090c004694b5996ddb04fdde5b05ebb0)) +* **eslint-plugin:** [no-unnecessary-type-assertion] correct bad fix for angle bracket assertion ([#3244](https://github.com/typescript-eslint/typescript-eslint/issues/3244)) ([265a039](https://github.com/typescript-eslint/typescript-eslint/commit/265a039c7e728b719143e09ee61066039d721f62)) +* **eslint-plugin:** [restrict-plus-operands] consider template literal types as strings ([#3234](https://github.com/typescript-eslint/typescript-eslint/issues/3234)) ([ccfd68e](https://github.com/typescript-eslint/typescript-eslint/commit/ccfd68e365391b3f117df96792355f9c3655288c)) +* **eslint-plugin:** [strict-boolean-expressions] account for truthy literals ([#3236](https://github.com/typescript-eslint/typescript-eslint/issues/3236)) ([0913f40](https://github.com/typescript-eslint/typescript-eslint/commit/0913f40c87762de198b05a5473b4fb79aeb46967)) +* **eslint-plugin:** always ignore assignments in no-unnecessary-type-assertion ([#3235](https://github.com/typescript-eslint/typescript-eslint/issues/3235)) ([0221476](https://github.com/typescript-eslint/typescript-eslint/commit/02214768a3721d8514c70e00546e861da6581e4d)) + + +### Features + +* **eslint-plugin:** [no-unsafe-argument] add rule ([#3256](https://github.com/typescript-eslint/typescript-eslint/issues/3256)) ([b1aa7dc](https://github.com/typescript-eslint/typescript-eslint/commit/b1aa7dc6971ee8409b729dffb8b69478455734ed)), closes [#791](https://github.com/typescript-eslint/typescript-eslint/issues/791) +* **eslint-plugin:** [no-unsafe-call][no-unsafe-member-access] improve report messages for `this` for `noImplicitThis` ([#3199](https://github.com/typescript-eslint/typescript-eslint/issues/3199)) ([b1b26c4](https://github.com/typescript-eslint/typescript-eslint/commit/b1b26c4843a4cfa209a0c9c3d8bea1de37333b48)) + + + + + # [4.20.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.19.0...v4.20.0) (2021-03-29) diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 2200afd28023..c2ee7821e3c7 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin", - "version": "4.20.0", + "version": "4.21.0", "description": "TypeScript plugin for ESLint", "keywords": [ "eslint", @@ -44,8 +44,8 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/experimental-utils": "4.20.0", - "@typescript-eslint/scope-manager": "4.20.0", + "@typescript-eslint/experimental-utils": "4.21.0", + "@typescript-eslint/scope-manager": "4.21.0", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "lodash": "^4.17.15", diff --git a/packages/experimental-utils/CHANGELOG.md b/packages/experimental-utils/CHANGELOG.md index 3eb627a542f8..353715dd4635 100644 --- a/packages/experimental-utils/CHANGELOG.md +++ b/packages/experimental-utils/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.21.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.20.0...v4.21.0) (2021-04-05) + +**Note:** Version bump only for package @typescript-eslint/experimental-utils + + + + + # [4.20.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.19.0...v4.20.0) (2021-03-29) **Note:** Version bump only for package @typescript-eslint/experimental-utils diff --git a/packages/experimental-utils/package.json b/packages/experimental-utils/package.json index 5dc92e6d4ed9..c32aade9b272 100644 --- a/packages/experimental-utils/package.json +++ b/packages/experimental-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/experimental-utils", - "version": "4.20.0", + "version": "4.21.0", "description": "(Experimental) Utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -40,9 +40,9 @@ }, "dependencies": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.20.0", - "@typescript-eslint/types": "4.20.0", - "@typescript-eslint/typescript-estree": "4.20.0", + "@typescript-eslint/scope-manager": "4.21.0", + "@typescript-eslint/types": "4.21.0", + "@typescript-eslint/typescript-estree": "4.21.0", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" }, diff --git a/packages/parser/CHANGELOG.md b/packages/parser/CHANGELOG.md index ae507c9c8990..0704567173f9 100644 --- a/packages/parser/CHANGELOG.md +++ b/packages/parser/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.21.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.20.0...v4.21.0) (2021-04-05) + +**Note:** Version bump only for package @typescript-eslint/parser + + + + + # [4.20.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.19.0...v4.20.0) (2021-03-29) **Note:** Version bump only for package @typescript-eslint/parser diff --git a/packages/parser/package.json b/packages/parser/package.json index 892d0c5ebc2c..eae074a40c87 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/parser", - "version": "4.20.0", + "version": "4.21.0", "description": "An ESLint custom parser which leverages TypeScript ESTree", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -44,14 +44,14 @@ "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" }, "dependencies": { - "@typescript-eslint/scope-manager": "4.20.0", - "@typescript-eslint/types": "4.20.0", - "@typescript-eslint/typescript-estree": "4.20.0", + "@typescript-eslint/scope-manager": "4.21.0", + "@typescript-eslint/types": "4.21.0", + "@typescript-eslint/typescript-estree": "4.21.0", "debug": "^4.1.1" }, "devDependencies": { "@types/glob": "*", - "@typescript-eslint/experimental-utils": "4.20.0", + "@typescript-eslint/experimental-utils": "4.21.0", "glob": "*", "typescript": "*" }, diff --git a/packages/scope-manager/CHANGELOG.md b/packages/scope-manager/CHANGELOG.md index 44f0ff59bf2e..4d2feebf2357 100644 --- a/packages/scope-manager/CHANGELOG.md +++ b/packages/scope-manager/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.21.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.20.0...v4.21.0) (2021-04-05) + +**Note:** Version bump only for package @typescript-eslint/scope-manager + + + + + # [4.20.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.19.0...v4.20.0) (2021-03-29) **Note:** Version bump only for package @typescript-eslint/scope-manager diff --git a/packages/scope-manager/package.json b/packages/scope-manager/package.json index 1c5756b2cf32..d0885fc83b14 100644 --- a/packages/scope-manager/package.json +++ b/packages/scope-manager/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/scope-manager", - "version": "4.20.0", + "version": "4.21.0", "description": "TypeScript scope analyser for ESLint", "keywords": [ "eslint", @@ -39,12 +39,12 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "4.20.0", - "@typescript-eslint/visitor-keys": "4.20.0" + "@typescript-eslint/types": "4.21.0", + "@typescript-eslint/visitor-keys": "4.21.0" }, "devDependencies": { "@types/glob": "*", - "@typescript-eslint/typescript-estree": "4.20.0", + "@typescript-eslint/typescript-estree": "4.21.0", "glob": "*", "jest-specific-snapshot": "*", "make-dir": "*", diff --git a/packages/shared-fixtures/CHANGELOG.md b/packages/shared-fixtures/CHANGELOG.md index d45ba39253b5..4d25f611a9d6 100644 --- a/packages/shared-fixtures/CHANGELOG.md +++ b/packages/shared-fixtures/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.21.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.20.0...v4.21.0) (2021-04-05) + +**Note:** Version bump only for package @typescript-eslint/shared-fixtures + + + + + # [4.20.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.19.0...v4.20.0) (2021-03-29) **Note:** Version bump only for package @typescript-eslint/shared-fixtures diff --git a/packages/shared-fixtures/package.json b/packages/shared-fixtures/package.json index 5e5691bc45ed..ea8929dd167f 100644 --- a/packages/shared-fixtures/package.json +++ b/packages/shared-fixtures/package.json @@ -1,5 +1,5 @@ { "name": "@typescript-eslint/shared-fixtures", - "version": "4.20.0", + "version": "4.21.0", "private": true } diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 8e7dc1f4a42c..f5a546799969 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.21.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.20.0...v4.21.0) (2021-04-05) + +**Note:** Version bump only for package @typescript-eslint/types + + + + + # [4.20.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.19.0...v4.20.0) (2021-03-29) **Note:** Version bump only for package @typescript-eslint/types diff --git a/packages/types/package.json b/packages/types/package.json index 95e52db60ebd..b4b29e94e7b7 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/types", - "version": "4.20.0", + "version": "4.21.0", "description": "Types for the TypeScript-ESTree AST spec", "keywords": [ "eslint", diff --git a/packages/typescript-estree/CHANGELOG.md b/packages/typescript-estree/CHANGELOG.md index 5e6000eecf07..85b800fe52a5 100644 --- a/packages/typescript-estree/CHANGELOG.md +++ b/packages/typescript-estree/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.21.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.20.0...v4.21.0) (2021-04-05) + +**Note:** Version bump only for package @typescript-eslint/typescript-estree + + + + + # [4.20.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.19.0...v4.20.0) (2021-03-29) **Note:** Version bump only for package @typescript-eslint/typescript-estree diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 18addb958652..92e797aae550 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/typescript-estree", - "version": "4.20.0", + "version": "4.21.0", "description": "A parser that converts TypeScript source code into an ESTree compatible form", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -41,8 +41,8 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "4.20.0", - "@typescript-eslint/visitor-keys": "4.20.0", + "@typescript-eslint/types": "4.21.0", + "@typescript-eslint/visitor-keys": "4.21.0", "debug": "^4.1.1", "globby": "^11.0.1", "is-glob": "^4.0.1", @@ -59,7 +59,7 @@ "@types/is-glob": "*", "@types/semver": "*", "@types/tmp": "*", - "@typescript-eslint/shared-fixtures": "4.20.0", + "@typescript-eslint/shared-fixtures": "4.21.0", "glob": "*", "jest-specific-snapshot": "*", "make-dir": "*", diff --git a/packages/visitor-keys/CHANGELOG.md b/packages/visitor-keys/CHANGELOG.md index 1b475f652f87..efd8c85036c5 100644 --- a/packages/visitor-keys/CHANGELOG.md +++ b/packages/visitor-keys/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.21.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.20.0...v4.21.0) (2021-04-05) + +**Note:** Version bump only for package @typescript-eslint/visitor-keys + + + + + # [4.20.0](https://github.com/typescript-eslint/typescript-eslint/compare/v4.19.0...v4.20.0) (2021-03-29) **Note:** Version bump only for package @typescript-eslint/visitor-keys diff --git a/packages/visitor-keys/package.json b/packages/visitor-keys/package.json index e59866242d4a..70a063fac306 100644 --- a/packages/visitor-keys/package.json +++ b/packages/visitor-keys/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/visitor-keys", - "version": "4.20.0", + "version": "4.21.0", "description": "Visitor keys used to help traverse the TypeScript-ESTree AST", "keywords": [ "eslint", @@ -38,7 +38,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "4.20.0", + "@typescript-eslint/types": "4.21.0", "eslint-visitor-keys": "^2.0.0" }, "devDependencies": { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy