Skip to content

Commit

Permalink
feat(eslint-plugin): [prefer-optional-chain] added option to convert …
Browse files Browse the repository at this point in the history
…to suggestion fixer (#1965)
  • Loading branch information
tianxinx99 committed May 4, 2020
1 parent 7f3fba3 commit 2f0824b
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 11 deletions.
15 changes: 15 additions & 0 deletions packages/eslint-plugin/docs/rules/prefer-optional-chain.md
Expand Up @@ -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.
Expand Down
62 changes: 51 additions & 11 deletions 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';

Expand Down Expand Up @@ -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<Options, MessageIds>({
name: 'prefer-optional-chain',
meta: {
type: 'suggestion',
Expand All @@ -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 {
[[
Expand Down Expand Up @@ -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),
],
},
],
});
}
}
},
};
Expand Down
51 changes: 51 additions & 0 deletions packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts
Expand Up @@ -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 => <This Requires Spaces />);',
options: [
{
suggestInsteadOfAutofix: true,
},
],
output: null,
errors: [
{
messageId: 'preferOptionalChain',
line: 1,
column: 1,
suggestions: [
{
messageId: 'optionalChainSuggest',
output: 'foo?.bar(baz => <This Requires Spaces />);',
},
],
},
],
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
],
});

0 comments on commit 2f0824b

Please sign in to comment.