Skip to content
This repository was archived by the owner on Oct 3, 2024. It is now read-only.

Commit 27617cb

Browse files
improve 'prefer-single-boolean-return': report when next statement returns boolean (#324)
Co-authored-by: Dimitri POSTOLOV <[email protected]>
1 parent 1d6b198 commit 27617cb

File tree

5 files changed

+127
-13
lines changed

5 files changed

+127
-13
lines changed

docs/rules/no-empty-collection.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ if (strings.includes("foo")) {} // Noncompliant
1111

1212
for (str of strings) {} // Noncompliant
1313

14-
strings.forEach(str =&gt; doSomething(str)); // Noncompliant
14+
strings.forEach(str => doSomething(str)); // Noncompliant
1515
```

docs/rules/prefer-single-boolean-return.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# prefer-single-boolean-return
22

3-
Return of boolean literal statements wrapped into `if-then-else` ones should be simplified.
3+
Return of boolean literal statements wrapped into `if-then-else` flow should be simplified.
44

55
## Noncompliant Code Example
66

@@ -12,6 +12,15 @@ if (expression) {
1212
}
1313
```
1414

15+
or
16+
17+
```javascript
18+
if (expression) {
19+
return true;
20+
}
21+
return false;
22+
```
23+
1524
## Compliant Solution
1625

1726
```javascript
Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,58 @@
11
src/Ghost/core/server/adapters/storage/utils.js: 39
22
src/Ghost/core/server/api/notifications.js: 73
3-
src/brackets/src/extensions/default/DebugCommands/main.js: 345
3+
src/Ghost/core/server/config/utils.js: 13
4+
src/Ghost/core/server/update-check.js: 237
5+
src/Ghost/core/server/web/utils.js: 45
6+
src/angular.js/src/ngMock/angular-mocks.js: 1980
7+
src/angular.js/src/ngParseExt/ucd.js: 561,1215
8+
src/brackets/src/JSUtils/ScopeManager.js: 234,262
9+
src/brackets/src/LiveDevelopment/Documents/HTMLDocument.js: 255
10+
src/brackets/src/command/KeyBindingManager.js: 1069
11+
src/brackets/src/extensibility/node/package-validator.js: 74
12+
src/brackets/src/extensions/default/DebugCommands/main.js: 345,433
13+
src/brackets/src/extensions/default/InlineTimingFunctionEditor/TimingFunctionUtils.js: 157,239
14+
src/brackets/src/extensions/default/JavaScriptCodeHints/main.js: 784
15+
src/brackets/src/extensions/default/JavaScriptRefactoring/RefactoringUtils.js: 189
16+
src/brackets/src/extensions/default/PrefsCodeHints/main.js: 201,369
17+
src/brackets/src/extensions/default/UrlCodeHints/main.js: 308
18+
src/brackets/src/language/CSSUtils.js: 1130
19+
src/brackets/src/preferences/PreferencesBase.js: 1143
420
src/brackets/src/search/FindUtils.js: 431
21+
src/brackets/src/utils/ValidationUtils.js: 46
22+
src/create-react-app/packages/react-dev-utils/eslintFormatter.js: 15
23+
src/jest/packages/expect/src/utils.js: 163
24+
src/jest/packages/jest-cli/src/cli/index.js: 252
25+
src/jest/packages/jest-cli/src/run_jest.js: 161
26+
src/jest/packages/jest-message-util/src/index.js: 188
27+
src/jest/packages/jest-runtime/src/should_instrument.js: 78
28+
src/jquery/external/qunit/qunit.js: 1703
29+
src/jquery/external/sinon/sinon.js: 220
30+
src/react-native/Libraries/Components/ScrollResponder.js: 179
31+
src/react-native/Libraries/Renderer/ReactFabric-dev.js: 10866
32+
src/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js: 11236
33+
src/react/packages/react-dom/src/shared/DOMProperty.js: 101
34+
src/react/packages/react-reconciler/src/ReactFiberHydrationContext.js: 272
35+
src/react/packages/shared/isTextInputElement.js: 38
36+
src/reveal.js/js/reveal.js: 5203
37+
src/spectrum/admin/src/helpers/utils.js: 41
38+
src/spectrum/api/models/invoice.js: 83
39+
src/spectrum/api/queries/channel/isArchived.js: 5
40+
src/spectrum/api/queries/directMessageThread/utils.js: 16
41+
src/spectrum/api/queries/meta/isAdmin.js: 6
42+
src/spectrum/src/components/chatInput/index.js: 101
43+
src/spectrum/src/components/composer/utils.js: 25
544
src/spectrum/src/components/message/index.js: 17
45+
src/spectrum/src/components/threadFeed/index.js: 156
46+
src/spectrum/src/helpers/utils.js: 85
47+
src/spectrum/src/views/community/components/memberGrid.js: 54
48+
src/spectrum/src/views/community/components/moderatorList.js: 36
49+
src/spectrum/src/views/dashboard/components/communityList.js: 68
50+
src/spectrum/src/views/dashboard/components/threadFeed.js: 81
51+
src/spectrum/src/views/dashboard/components/upsellExploreCommunities.js: 48
52+
src/spectrum/src/views/directMessages/index.js: 63
53+
src/spectrum/src/views/navbar/components/messagesTab.js: 64
54+
src/spectrum/src/views/navbar/components/notificationsTab.js: 109
55+
src/spectrum/src/views/navbar/index.js: 70
56+
src/spectrum/src/views/notifications/index.js: 120
57+
src/spectrum/src/views/pages/pricing/components/communityList.js: 43
58+
src/three.js/src/math/Ray.js: 352

src/rules/prefer-single-boolean-return.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ import docsUrl from '../utils/docs-url';
3030
const rule: TSESLint.RuleModule<string, string[]> = {
3131
meta: {
3232
messages: {
33-
replaceIfThenElseByReturn:
34-
'Replace this if-then-else statement by a single return statement.',
33+
replaceIfThenElseByReturn: 'Replace this if-then-else flow by a single return statement.',
3534
},
3635
schema: [],
3736
type: 'suggestion',
@@ -44,23 +43,35 @@ const rule: TSESLint.RuleModule<string, string[]> = {
4443
},
4544
create(context) {
4645
return {
47-
IfStatement(node: TSESTree.Node) {
48-
const ifStmt = node as TSESTree.IfStatement;
46+
IfStatement(node: TSESTree.IfStatement) {
4947
if (
5048
// ignore `else if`
51-
!isIfStatement(ifStmt.parent) &&
52-
// `ifStmt.alternate` can be `null`, replace it with `undefined` in this case
53-
returnsBoolean(ifStmt.alternate || undefined) &&
54-
returnsBoolean(ifStmt.consequent)
49+
!isIfStatement(node.parent) &&
50+
returnsBoolean(node.consequent) &&
51+
alternateReturnsBoolean(node)
5552
) {
5653
context.report({
5754
messageId: 'replaceIfThenElseByReturn',
58-
node: ifStmt,
55+
node,
5956
});
6057
}
6158
},
6259
};
6360

61+
function alternateReturnsBoolean(node: TSESTree.IfStatement) {
62+
if (node.alternate) {
63+
return returnsBoolean(node.alternate);
64+
}
65+
66+
const { parent } = node;
67+
if (parent?.type === 'BlockStatement') {
68+
const ifStmtIndex = parent.body.findIndex(stmt => stmt === node);
69+
return isSimpleReturnBooleanLiteral(parent.body[ifStmtIndex + 1]);
70+
}
71+
72+
return false;
73+
}
74+
6475
function returnsBoolean(statement: TSESTree.Statement | undefined) {
6576
return (
6677
statement !== undefined &&
@@ -76,7 +87,7 @@ const rule: TSESLint.RuleModule<string, string[]> = {
7687
);
7788
}
7889

79-
function isSimpleReturnBooleanLiteral(statement: TSESTree.Statement) {
90+
function isSimpleReturnBooleanLiteral(statement: TSESTree.Node) {
8091
// `statement.argument` can be `null`, replace it with `undefined` in this case
8192
return isReturnStatement(statement) && isBooleanLiteral(statement.argument || undefined);
8293
}

tests/rules/prefer-single-boolean-return.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,5 +186,46 @@ ruleTester.run('prefer-single-boolean-return', rule, {
186186
},
187187
],
188188
},
189+
{
190+
code: `
191+
function fn() {
192+
if (foo) {
193+
if (something) {
194+
return true
195+
}
196+
return false
197+
}
198+
199+
if (bar) {
200+
if (something) {
201+
return false
202+
}
203+
return true
204+
}
205+
206+
if (baz) {
207+
if (something) {
208+
return false
209+
}
210+
}
211+
}
212+
`,
213+
errors: [
214+
{
215+
messageId: 'replaceIfThenElseByReturn',
216+
line: 4,
217+
column: 13,
218+
endLine: 6,
219+
endColumn: 14,
220+
},
221+
{
222+
messageId: 'replaceIfThenElseByReturn',
223+
line: 11,
224+
column: 13,
225+
endLine: 13,
226+
endColumn: 14,
227+
},
228+
],
229+
},
189230
],
190231
});

0 commit comments

Comments
 (0)