Skip to content

Commit 52b6085

Browse files
committed
feat(eslint-plugin): [prefer-nullish-coalescing][prefer-optional-chain] remove unsafe fixers
These fixers are very unsafe and even providing default options for them are a bad idea. This ensures that they are suggestion fixers in all cases, and removes the options that allow them not to be.
1 parent ae82ea4 commit 52b6085

7 files changed

+271
-215
lines changed

packages/eslint-plugin/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int
146146
| [`@typescript-eslint/prefer-function-type`](./docs/rules/prefer-function-type.md) | Use function types instead of interfaces with call signatures | | :wrench: | |
147147
| [`@typescript-eslint/prefer-includes`](./docs/rules/prefer-includes.md) | Enforce `includes` method over `indexOf` method | | :wrench: | :thought_balloon: |
148148
| [`@typescript-eslint/prefer-namespace-keyword`](./docs/rules/prefer-namespace-keyword.md) | Require the use of the `namespace` keyword instead of the `module` keyword to declare custom TypeScript modules | :heavy_check_mark: | :wrench: | |
149-
| [`@typescript-eslint/prefer-nullish-coalescing`](./docs/rules/prefer-nullish-coalescing.md) | Enforce the usage of the nullish coalescing operator instead of logical chaining | | :wrench: | :thought_balloon: |
150-
| [`@typescript-eslint/prefer-optional-chain`](./docs/rules/prefer-optional-chain.md) | Prefer using concise optional chain expressions instead of chained logical ands | | :wrench: | |
149+
| [`@typescript-eslint/prefer-nullish-coalescing`](./docs/rules/prefer-nullish-coalescing.md) | Enforce the usage of the nullish coalescing operator instead of logical chaining | | | :thought_balloon: |
150+
| [`@typescript-eslint/prefer-optional-chain`](./docs/rules/prefer-optional-chain.md) | Prefer using concise optional chain expressions instead of chained logical ands | | | |
151151
| [`@typescript-eslint/prefer-readonly`](./docs/rules/prefer-readonly.md) | Requires that private members are marked as `readonly` if they're never modified outside of the constructor | | :wrench: | :thought_balloon: |
152152
| [`@typescript-eslint/prefer-readonly-parameter-types`](./docs/rules/prefer-readonly-parameter-types.md) | Requires that function parameters are typed as readonly to prevent accidental mutation of inputs | | | :thought_balloon: |
153153
| [`@typescript-eslint/prefer-reduce-type-parameter`](./docs/rules/prefer-reduce-type-parameter.md) | Prefer using type parameter when calling `Array#reduce` instead of casting | | :wrench: | :thought_balloon: |

packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,13 @@ type Options = [
4646
{
4747
ignoreConditionalTests?: boolean;
4848
ignoreMixedLogicalExpressions?: boolean;
49-
forceSuggestionFixer?: boolean;
5049
},
5150
];
5251

5352
const defaultOptions = [
5453
{
5554
ignoreConditionalTests: true,
5655
ignoreMixedLogicalExpressions: true,
57-
forceSuggestionFixer: false,
5856
},
5957
];
6058
```
@@ -133,12 +131,6 @@ a ?? (b && c && d);
133131

134132
**_NOTE:_** Errors for this specific case will be presented as suggestions (see below), instead of fixes. This is because it is not always safe to automatically convert `||` to `??` within a mixed logical expression, as we cannot tell the intended precedence of the operator. Note that by design, `??` requires parentheses when used with `&&` or `||` in the same expression.
135133

136-
### `forceSuggestionFixer`
137-
138-
Setting this option to `true` will cause the rule to use ESLint's "suggested fix" mode for all fixes. _This option is provided as to aid in transitioning your codebase onto this rule_.
139-
140-
Suggestion fixes cannot be automatically applied via the `--fix` CLI command, but can be _manually_ chosen to be applied one at a time via an IDE or similar. This makes it safe to run autofixers on an existing codebase without worrying about potential runtime behavior changes from this rule's fixer.
141-
142134
## When Not To Use It
143135

144136
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.

packages/eslint-plugin/docs/rules/prefer-optional-chain.md

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,7 @@ foo?.a?.b?.method?.();
7070
foo?.a?.b?.c?.d?.e;
7171
```
7272

73-
## Options
74-
75-
The rule accepts an options object with the following properties:
76-
77-
```ts
78-
type Options = {
79-
// if true, the rule will only provide suggested fixes instead of automatically modifying code
80-
suggestInsteadOfAutofix?: boolean;
81-
};
82-
83-
const defaults = {
84-
suggestInsteadOfAutofix: false,
85-
};
86-
```
73+
**Note:** there are a few edge cases where this rule will false positive. Use your best judgement when evaluating reported errors.
8774

8875
## When Not To Use It
8976

packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ export type Options = [
1010
{
1111
ignoreConditionalTests?: boolean;
1212
ignoreMixedLogicalExpressions?: boolean;
13-
forceSuggestionFixer?: boolean;
1413
},
1514
];
16-
export type MessageIds = 'preferNullish';
15+
export type MessageIds = 'preferNullish' | 'suggestNullish';
1716

1817
export default util.createRule<Options, MessageIds>({
1918
name: 'prefer-nullish-coalescing',
@@ -27,10 +26,10 @@ export default util.createRule<Options, MessageIds>({
2726
suggestion: true,
2827
requiresTypeChecking: true,
2928
},
30-
fixable: 'code',
3129
messages: {
3230
preferNullish:
3331
'Prefer using nullish coalescing operator (`??`) instead of a logical or (`||`), as it is a safer operator.',
32+
suggestNullish: 'Fix to nullish coalescing operator (`??`).',
3433
},
3534
schema: [
3635
{
@@ -54,19 +53,9 @@ export default util.createRule<Options, MessageIds>({
5453
{
5554
ignoreConditionalTests: true,
5655
ignoreMixedLogicalExpressions: true,
57-
forceSuggestionFixer: false,
5856
},
5957
],
60-
create(
61-
context,
62-
[
63-
{
64-
ignoreConditionalTests,
65-
ignoreMixedLogicalExpressions,
66-
forceSuggestionFixer,
67-
},
68-
],
69-
) {
58+
create(context, [{ ignoreConditionalTests, ignoreMixedLogicalExpressions }]) {
7059
const parserServices = util.getParserServices(context);
7160
const sourceCode = context.getSourceCode();
7261
const checker = parserServices.program.getTypeChecker();
@@ -119,23 +108,15 @@ export default util.createRule<Options, MessageIds>({
119108
yield fixer.replaceText(barBarOperator, '??');
120109
}
121110

122-
const fixer =
123-
isMixedLogical || forceSuggestionFixer
124-
? // suggestion instead for cases where we aren't sure if the fixer is completely safe
125-
({
126-
suggest: [
127-
{
128-
messageId: 'preferNullish',
129-
fix,
130-
},
131-
],
132-
} as const)
133-
: { fix };
134-
135111
context.report({
136112
node: barBarOperator,
137113
messageId: 'preferNullish',
138-
...fixer,
114+
suggest: [
115+
{
116+
messageId: 'suggestNullish',
117+
fix,
118+
},
119+
],
139120
});
140121
},
141122
};

packages/eslint-plugin/src/rules/prefer-optional-chain.ts

Lines changed: 15 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,7 @@ The AST will look like this:
3131
}
3232
*/
3333

34-
type Options = [
35-
{
36-
suggestInsteadOfAutofix?: boolean;
37-
},
38-
];
39-
40-
type MessageIds = 'preferOptionalChain' | 'optionalChainSuggest';
41-
42-
export default util.createRule<Options, MessageIds>({
34+
export default util.createRule({
4335
name: 'prefer-optional-chain',
4436
meta: {
4537
type: 'suggestion',
@@ -50,30 +42,15 @@ export default util.createRule<Options, MessageIds>({
5042
recommended: false,
5143
suggestion: true,
5244
},
53-
fixable: 'code',
5445
messages: {
5546
preferOptionalChain:
5647
"Prefer using an optional chain expression instead, as it's more concise and easier to read.",
5748
optionalChainSuggest: 'Change to an optional chain.',
5849
},
59-
schema: [
60-
{
61-
type: 'object',
62-
properties: {
63-
suggestInsteadOfAutofix: {
64-
type: 'boolean',
65-
},
66-
},
67-
additionalProperties: false,
68-
},
69-
],
50+
schema: [],
7051
},
71-
defaultOptions: [
72-
{
73-
suggestInsteadOfAutofix: false,
74-
},
75-
],
76-
create(context, [options]) {
52+
defaultOptions: [],
53+
create(context) {
7754
const sourceCode = context.getSourceCode();
7855
return {
7956
[[
@@ -189,28 +166,18 @@ export default util.createRule<Options, MessageIds>({
189166
} ${sourceCode.getText(previous.right.right)}`;
190167
}
191168

192-
if (!options.suggestInsteadOfAutofix) {
193-
context.report({
194-
node: previous,
195-
messageId: 'preferOptionalChain',
196-
fix(fixer) {
197-
return fixer.replaceText(previous, optionallyChainedCode);
169+
context.report({
170+
node: previous,
171+
messageId: 'preferOptionalChain',
172+
suggest: [
173+
{
174+
messageId: 'optionalChainSuggest',
175+
fix: (fixer): TSESLint.RuleFix[] => [
176+
fixer.replaceText(previous, optionallyChainedCode),
177+
],
198178
},
199-
});
200-
} else {
201-
context.report({
202-
node: previous,
203-
messageId: 'preferOptionalChain',
204-
suggest: [
205-
{
206-
messageId: 'optionalChainSuggest',
207-
fix: (fixer): TSESLint.RuleFix[] => [
208-
fixer.replaceText(previous, optionallyChainedCode),
209-
],
210-
},
211-
],
212-
});
213-
}
179+
],
180+
});
214181
}
215182
},
216183
};

0 commit comments

Comments
 (0)
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