From 70dafb61e109ac02eabcb6320675e20add254a1b Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Fri, 17 Jan 2020 17:09:55 -0800 Subject: [PATCH 1/3] feat(eslint-plugin): [no-extra-non-null-assert] add fixer --- .../src/rules/no-extra-non-null-assertion.ts | 9 ++- .../rules/no-extra-non-null-assertion.test.ts | 74 ++++++++++++++----- 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts b/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts index 39969de283f..2be0fb6a76b 100644 --- a/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts @@ -10,6 +10,7 @@ export default util.createRule({ category: 'Stylistic Issues', recommended: false, }, + fixable: 'code', schema: [], messages: { noExtraNonNullAssertion: 'Forbidden extra non-null assertion.', @@ -20,7 +21,13 @@ export default util.createRule({ function checkExtraNonNullAssertion( node: TSESTree.TSNonNullExpression, ): void { - context.report({ messageId: 'noExtraNonNullAssertion', node }); + context.report({ + node, + messageId: 'noExtraNonNullAssertion', + fix(fixer) { + return fixer.removeRange([node.range[1] - 1, node.range[1]]); + }, + }); } return { diff --git a/packages/eslint-plugin/tests/rules/no-extra-non-null-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-extra-non-null-assertion.test.ts index 074dc90697e..b73da70574a 100644 --- a/packages/eslint-plugin/tests/rules/no-extra-non-null-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-extra-non-null-assertion.test.ts @@ -31,21 +31,13 @@ function foo(bar?: { n: number }) { { code: ` const foo: { bar: number } | null = null; -const bar = foo!!!!.bar; +const bar = foo!!.bar; + `, + output: ` +const foo: { bar: number } | null = null; +const bar = foo!.bar; `, errors: [ - { - messageId: 'noExtraNonNullAssertion', - endColumn: 19, - column: 13, - line: 3, - }, - { - messageId: 'noExtraNonNullAssertion', - endColumn: 18, - column: 13, - line: 3, - }, { messageId: 'noExtraNonNullAssertion', endColumn: 17, @@ -58,6 +50,11 @@ const bar = foo!!!!.bar; code: ` function foo(bar: number | undefined) { const bar: number = bar!!; +} + `, + output: ` +function foo(bar: number | undefined) { + const bar: number = bar!; } `, errors: [ @@ -73,6 +70,11 @@ function foo(bar: number | undefined) { code: ` function foo(bar?: { n: number }) { return bar!?.n; +} + `, + output: ` +function foo(bar?: { n: number }) { + return bar?.n; } `, errors: [ @@ -84,28 +86,60 @@ function foo(bar?: { n: number }) { }, ], }, + // parentheses { code: ` -function foo(bar?: { n: number }) { - return bar!!!?.n; -} +const foo: { bar: number } | null = null; +const bar = (foo!)!.bar; + `, + output: ` +const foo: { bar: number } | null = null; +const bar = (foo)!.bar; `, errors: [ { messageId: 'noExtraNonNullAssertion', - endColumn: 16, - column: 10, + endColumn: 18, + column: 14, line: 3, }, + ], + }, + { + code: ` +function foo(bar?: { n: number }) { + return (bar!)?.n; +} + `, + output: ` +function foo(bar?: { n: number }) { + return (bar)?.n; +} + `, + errors: [ { messageId: 'noExtraNonNullAssertion', endColumn: 15, - column: 10, + column: 11, line: 3, }, + ], + }, + { + code: ` +function foo(bar?: { n: number }) { + return (bar)!?.n; +} + `, + output: ` +function foo(bar?: { n: number }) { + return (bar)?.n; +} + `, + errors: [ { messageId: 'noExtraNonNullAssertion', - endColumn: 14, + endColumn: 16, column: 10, line: 3, }, From fc04388b85c8374976d8e93d3d54ff00981bda7e Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Fri, 17 Jan 2020 17:22:10 -0800 Subject: [PATCH 2/3] fix: add support for optional call --- .../src/rules/no-extra-non-null-assertion.ts | 1 + .../rules/no-extra-non-null-assertion.test.ts | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts b/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts index 2be0fb6a76b..44182650d14 100644 --- a/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts @@ -33,6 +33,7 @@ export default util.createRule({ return { 'TSNonNullExpression > TSNonNullExpression': checkExtraNonNullAssertion, 'OptionalMemberExpression > TSNonNullExpression': checkExtraNonNullAssertion, + 'OptionalCallExpression > TSNonNullExpression.callee': checkExtraNonNullAssertion, }; }, }); diff --git a/packages/eslint-plugin/tests/rules/no-extra-non-null-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-extra-non-null-assertion.test.ts index b73da70574a..51ff2d2e43f 100644 --- a/packages/eslint-plugin/tests/rules/no-extra-non-null-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-extra-non-null-assertion.test.ts @@ -75,6 +75,26 @@ function foo(bar?: { n: number }) { output: ` function foo(bar?: { n: number }) { return bar?.n; +} + `, + errors: [ + { + messageId: 'noExtraNonNullAssertion', + endColumn: 14, + column: 10, + line: 3, + }, + ], + }, + { + code: ` +function foo(bar?: { n: number }) { + return bar!?.(); +} + `, + output: ` +function foo(bar?: { n: number }) { + return bar?.(); } `, errors: [ @@ -145,5 +165,25 @@ function foo(bar?: { n: number }) { }, ], }, + { + code: ` +function foo(bar?: { n: number }) { + return (bar!)?.(); +} + `, + output: ` +function foo(bar?: { n: number }) { + return (bar)?.(); +} + `, + errors: [ + { + messageId: 'noExtraNonNullAssertion', + endColumn: 15, + column: 11, + line: 3, + }, + ], + }, ], }); From c7965f91260ab0cce46850f10c247ab2a76d678c Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Fri, 17 Jan 2020 18:15:42 -0800 Subject: [PATCH 3/3] docs: oops --- packages/eslint-plugin/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index 2111de5cee3..2ac880f409d 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -111,11 +111,11 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int | [`@typescript-eslint/no-dynamic-delete`](./docs/rules/no-dynamic-delete.md) | Disallow the delete operator with computed key expressions | | :wrench: | | | [`@typescript-eslint/no-empty-interface`](./docs/rules/no-empty-interface.md) | Disallow the declaration of empty interfaces | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/no-explicit-any`](./docs/rules/no-explicit-any.md) | Disallow usage of the `any` type | :heavy_check_mark: | :wrench: | | -| [`@typescript-eslint/no-extra-non-null-assertion`](./docs/rules/no-extra-non-null-assertion.md) | Disallow extra non-null assertion | | | | +| [`@typescript-eslint/no-extra-non-null-assertion`](./docs/rules/no-extra-non-null-assertion.md) | Disallow extra non-null assertion | | :wrench: | | | [`@typescript-eslint/no-extraneous-class`](./docs/rules/no-extraneous-class.md) | Forbids the use of classes as namespaces | | | | | [`@typescript-eslint/no-floating-promises`](./docs/rules/no-floating-promises.md) | Requires Promise-like values to be handled appropriately | | | :thought_balloon: | | [`@typescript-eslint/no-for-in-array`](./docs/rules/no-for-in-array.md) | Disallow iterating over an array with a for-in loop | :heavy_check_mark: | | :thought_balloon: | -| [`@typescript-eslint/no-implied-eval`](./docs/rules/no-implied-eval.md) | Disallow the use of `eval()`-like methods | | | :thought_balloon:| +| [`@typescript-eslint/no-implied-eval`](./docs/rules/no-implied-eval.md) | Disallow the use of `eval()`-like methods | | | :thought_balloon: | | [`@typescript-eslint/no-inferrable-types`](./docs/rules/no-inferrable-types.md) | Disallows explicit type declarations for variables or parameters initialized to a number, string, or boolean | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/no-misused-new`](./docs/rules/no-misused-new.md) | Enforce valid definition of `new` and `constructor` | :heavy_check_mark: | | | | [`@typescript-eslint/no-misused-promises`](./docs/rules/no-misused-promises.md) | Avoid using promises in places not designed to handle them | :heavy_check_mark: | | :thought_balloon: |