From 2f0824b0a41f3043b6242fc1d49faae540abaf22 Mon Sep 17 00:00:00 2001 From: tianxinx99 <10507315+tianxinx99@users.noreply.github.com> Date: Sun, 3 May 2020 23:50:48 -0500 Subject: [PATCH] feat(eslint-plugin): [prefer-optional-chain] added option to convert to suggestion fixer (#1965) --- .../docs/rules/prefer-optional-chain.md | 15 +++++ .../src/rules/prefer-optional-chain.ts | 62 +++++++++++++++---- .../tests/rules/prefer-optional-chain.test.ts | 51 +++++++++++++++ 3 files changed, 117 insertions(+), 11 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/prefer-optional-chain.md b/packages/eslint-plugin/docs/rules/prefer-optional-chain.md index 9a046b3d82f..be3352a282b 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 0ec33df8180..7c858008984 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,26 @@ export default util.createRule({ messages: { preferOptionalChain: "Prefer using an optional chain expression instead, as it's more concise and easier to read.", + optionalChainSuggest: 'Change to an optional chain.', }, - schema: [], + schema: [ + { + type: 'object', + properties: { + suggestInsteadOfAutofix: { + type: 'boolean', + }, + }, + additionalProperties: false, + }, + ], }, - defaultOptions: [], - create(context) { + defaultOptions: [ + { + suggestInsteadOfAutofix: false, + }, + ], + create(context, [options]) { const sourceCode = context.getSourceCode(); return { [[ @@ -163,13 +188,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 eed61d687e4..c6eb323827a 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,56 @@ 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: null, + errors: [ + { + messageId: 'preferOptionalChain', + line: 1, + column: 1, + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: 'foo?.bar?.baz?.buzz;', + }, + ], + }, + ], + }, + { + code: 'foo && foo.bar(baz => );', + options: [ + { + suggestInsteadOfAutofix: true, + }, + ], + output: null, + errors: [ + { + messageId: 'preferOptionalChain', + line: 1, + column: 1, + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: 'foo?.bar(baz => );', + }, + ], + }, + ], + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, ], });