From 0defdb8bbc8fed7b05d2daf1d0419cb1bf3b4bb9 Mon Sep 17 00:00:00 2001 From: Tianxin Xu Date: Fri, 1 May 2020 21:25:52 -0500 Subject: [PATCH 1/7] feat: added option to convert to suggestion fixer --- .../src/rules/prefer-optional-chain.ts | 63 +++++++++++++++---- .../tests/rules/prefer-optional-chain.test.ts | 52 +++++++++++++++ 2 files changed, 104 insertions(+), 11 deletions(-) diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts index 0ec33df81801..9ebf7f428730 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts @@ -1,6 +1,7 @@ import { AST_NODE_TYPES, TSESTree, + TSESLint, } from '@typescript-eslint/experimental-utils'; import * as util from '../util'; @@ -29,7 +30,16 @@ The AST will look like this: right: foo.bar.baz.buzz } */ -export default util.createRule({ + +type Options = [ + { + suggestInsteadOfAutofix?: boolean; + }, +]; + +type MessageIds = 'preferOptionalChain' | 'optionalChainSuggest'; + +export default util.createRule({ name: 'prefer-optional-chain', meta: { type: 'suggestion', @@ -43,11 +53,27 @@ export default util.createRule({ messages: { preferOptionalChain: "Prefer using an optional chain expression instead, as it's more concise and easier to read.", + optionalChainSuggest: + "You should use an optional chain expression instead, as it's more concise and easier to read.", }, - schema: [], + schema: [ + { + type: 'object', + properties: { + autofix: { + type: 'boolean', + }, + }, + additionalProperties: false, + }, + ], }, - defaultOptions: [], - create(context) { + defaultOptions: [ + { + suggestInsteadOfAutofix: false, + }, + ], + create(context, [options]) { const sourceCode = context.getSourceCode(); return { [[ @@ -163,13 +189,28 @@ export default util.createRule({ } ${sourceCode.getText(previous.right.right)}`; } - context.report({ - node: previous, - messageId: 'preferOptionalChain', - fix(fixer) { - return fixer.replaceText(previous, optionallyChainedCode); - }, - }); + if (!options.suggestInsteadOfAutofix) { + context.report({ + node: previous, + messageId: 'preferOptionalChain', + fix(fixer) { + return fixer.replaceText(previous, optionallyChainedCode); + }, + }); + } else { + context.report({ + node: previous, + messageId: 'preferOptionalChain', + suggest: [ + { + messageId: 'optionalChainSuggest', + fix: (fixer): TSESLint.RuleFix[] => [ + fixer.replaceText(previous, optionallyChainedCode), + ], + }, + ], + }); + } } }, }; diff --git a/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts b/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts index eed61d687e42..3dd41dacaa84 100644 --- a/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts @@ -291,5 +291,57 @@ ruleTester.run('prefer-optional-chain', rule, { }, ], }, + // using suggestion instead of autofix + { + code: + 'foo && foo.bar != null && foo.bar.baz !== undefined && foo.bar.baz.buzz;', + options: [ + { + suggestInsteadOfAutofix: true, + }, + ], + output: + 'foo && foo.bar != null && foo.bar.baz !== undefined && foo.bar.baz.buzz;', + errors: [ + { + messageId: 'preferOptionalChain', + line: 1, + column: 1, + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: 'foo?.bar?.baz?.buzz;', + }, + ], + }, + ], + }, + { + code: 'foo && foo.bar(baz => );', + options: [ + { + suggestInsteadOfAutofix: true, + }, + ], + output: 'foo && foo.bar(baz => );', + errors: [ + { + messageId: 'preferOptionalChain', + line: 1, + column: 1, + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: 'foo?.bar(baz => );', + }, + ], + }, + ], + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, ], }); From 3e8b8f99dbddc4ea50fc6ca00f054d5951a24a1d Mon Sep 17 00:00:00 2001 From: Tianxin Xu Date: Fri, 1 May 2020 22:06:24 -0500 Subject: [PATCH 2/7] feat: added option to convert to suggestion fixer --- .../docs/rules/prefer-optional-chain.md | 15 +++++++++++++++ .../src/rules/prefer-optional-chain.ts | 1 - 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/docs/rules/prefer-optional-chain.md b/packages/eslint-plugin/docs/rules/prefer-optional-chain.md index 9a046b3d82f8..be3352a282bb 100644 --- a/packages/eslint-plugin/docs/rules/prefer-optional-chain.md +++ b/packages/eslint-plugin/docs/rules/prefer-optional-chain.md @@ -70,6 +70,21 @@ foo?.a?.b?.method?.(); foo?.a?.b?.c?.d?.e; ``` +## Options + +The rule accepts an options object with the following properties: + +```ts +type Options = { + // if true, the rule will only provide suggested fixes instead of automatically modifying code + suggestInsteadOfAutofix?: boolean; +}; + +const defaults = { + suggestInsteadOfAutofix: false, +}; +``` + ## When Not To Use It If you are not using TypeScript 3.7 (or greater), then you will not be able to use this rule, as the operator is not supported. diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts index 9ebf7f428730..cafd93f34a89 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts @@ -64,7 +64,6 @@ export default util.createRule({ type: 'boolean', }, }, - additionalProperties: false, }, ], }, From 77505b33c052122aa78824d47d1a5d3a6cc4c474 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 3 May 2020 21:13:20 -0700 Subject: [PATCH 3/7] Update prefer-optional-chain.ts --- packages/eslint-plugin/src/rules/prefer-optional-chain.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts index cafd93f34a89..31adc45be530 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts @@ -53,8 +53,7 @@ export default util.createRule({ messages: { preferOptionalChain: "Prefer using an optional chain expression instead, as it's more concise and easier to read.", - optionalChainSuggest: - "You should use an optional chain expression instead, as it's more concise and easier to read.", + optionalChainSuggest: 'Change to an optional chain.', }, schema: [ { From f379b2162469d073d6ad3e78ebd2766d82ce689f Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 3 May 2020 21:14:11 -0700 Subject: [PATCH 4/7] Update prefer-optional-chain.ts --- packages/eslint-plugin/src/rules/prefer-optional-chain.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts index 31adc45be530..043bfac9dffa 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts @@ -63,6 +63,7 @@ export default util.createRule({ type: 'boolean', }, }, + additionalProperties: false, }, ], }, From e8ace9e288cb998e3fd3f58f3e50672db83066de Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 3 May 2020 21:17:18 -0700 Subject: [PATCH 5/7] fix schema --- packages/eslint-plugin/src/rules/prefer-optional-chain.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts index 043bfac9dffa..7c8580089849 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts @@ -59,7 +59,7 @@ export default util.createRule({ { type: 'object', properties: { - autofix: { + suggestInsteadOfAutofix: { type: 'boolean', }, }, From 59cfa678844acc041d9ab089709d1353c6deadde Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 3 May 2020 21:17:50 -0700 Subject: [PATCH 6/7] use null output for suggestion tests --- .../eslint-plugin/tests/rules/prefer-optional-chain.test.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts b/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts index 3dd41dacaa84..d2c4b28b75ca 100644 --- a/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts @@ -300,8 +300,7 @@ ruleTester.run('prefer-optional-chain', rule, { suggestInsteadOfAutofix: true, }, ], - output: - 'foo && foo.bar != null && foo.bar.baz !== undefined && foo.bar.baz.buzz;', + output: null, errors: [ { messageId: 'preferOptionalChain', @@ -323,7 +322,7 @@ ruleTester.run('prefer-optional-chain', rule, { suggestInsteadOfAutofix: true, }, ], - output: 'foo && foo.bar(baz => );', + output: null errors: [ { messageId: 'preferOptionalChain', From b52198b84108ce6c8c8821634ceb869c0cf2cd03 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 3 May 2020 21:19:31 -0700 Subject: [PATCH 7/7] fix my typo --- .../eslint-plugin/tests/rules/prefer-optional-chain.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts b/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts index d2c4b28b75ca..c6eb323827a5 100644 --- a/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts @@ -322,7 +322,7 @@ ruleTester.run('prefer-optional-chain', rule, { suggestInsteadOfAutofix: true, }, ], - output: null + output: null, errors: [ { messageId: 'preferOptionalChain',