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

Commit d3130ac

Browse files
Rule S1821: "switch" statements should not be nested (#241)
1 parent b720cff commit d3130ac

File tree

6 files changed

+262
-0
lines changed

6 files changed

+262
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Code Smells, or maintainability issues, are raised for places of code which migh
3030
* Two branches in a conditional structure should not have exactly the same implementation ([`no-duplicated-branches`])
3131
* Functions should not have identical implementations ([`no-identical-functions`])
3232
* Boolean checks should not be inverted ([`no-inverted-boolean-check`]) (:wrench: *fixable*)
33+
* "switch" statements should not be nested ([`no-nested-switch`])
3334
* Template literals should not be nested ([`no-nested-template-literals`])
3435
* Boolean literals should not be redundant ([`no-redundant-boolean`])
3536
* Jump statements should not be redundant ([`no-redundant-jump`])
@@ -56,6 +57,7 @@ Code Smells, or maintainability issues, are raised for places of code which migh
5657
[`no-identical-expressions`]: ./docs/rules/no-identical-expressions.md
5758
[`no-identical-functions`]: ./docs/rules/no-identical-functions.md
5859
[`no-inverted-boolean-check`]: ./docs/rules/no-inverted-boolean-check.md
60+
[`no-nested-switch`]: ./docs/rules/no-nested-switch.md
5961
[`no-nested-template-literals`]: ./docs/rules/no-nested-template-literals.md
6062
[`no-one-iteration-loop`]: ./docs/rules/no-one-iteration-loop.md
6163
[`no-redundant-boolean`]: ./docs/rules/no-redundant-boolean.md

docs/rules/no-nested-switch.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# no-nested-switch
2+
3+
Nested `switch` structures are difficult to understand because you can easily confuse the cases of an inner `switch` as belonging to an outer statement. Therefore nested `switch` statements should be avoided.
4+
5+
Specifically, you should structure your code to avoid the need for nested `switch` statements, but if you cannot, then consider moving the inner `switch` to another function.
6+
7+
## Noncompliant Code Example
8+
9+
```javascript
10+
function foo(n, m) {
11+
switch (n) {
12+
case 0:
13+
switch (m) { // Noncompliant; nested switch
14+
// ...
15+
}
16+
case 1:
17+
// ...
18+
default:
19+
// ...
20+
}
21+
}
22+
```
23+
24+
## Compliant Solution
25+
26+
```javascript
27+
function foo(n, m) {
28+
switch (n) {
29+
case 0:
30+
bar(m);
31+
case 1:
32+
// ...
33+
default:
34+
// ...
35+
}
36+
}
37+
38+
function bar(m) {
39+
switch(m) {
40+
// ...
41+
}
42+
}
43+
```

ruling/snapshots/no-nested-switch

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
src/react-native/Libraries/Renderer/ReactFabric-dev.js: 3913,9895,10737,10758
2+
src/react-native/Libraries/Renderer/ReactFabric-prod.js: 1452,3961
3+
src/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js: 4292,10265,11107,11128
4+
src/react-native/Libraries/Renderer/ReactNativeRenderer-prod.js: 1668,4454
5+
src/react/packages/react-is/src/ReactIs.js: 32,40
6+
src/react/packages/react-reconciler/src/ReactFiber.js: 354
7+
src/react/packages/react-reconciler/src/ReactFiberCommitWork.js: 263
8+
src/react/packages/react-reconciler/src/ReactFiberHydrationContext.js: 140,161
9+
src/react/packages/react/src/ReactChildren.js: 124
10+
src/react/scripts/rollup/forks.js: 44,96
11+
src/react/scripts/rollup/packaging.js: 46

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const sonarjsRules: [string, TSESLint.Linter.RuleLevel][] = [
3434
['no-identical-functions', 'error'],
3535
['no-identical-expressions', 'error'],
3636
['no-inverted-boolean-check', 'error'],
37+
['no-nested-switch', 'error'],
3738
['no-nested-template-literals', 'error'],
3839
['no-one-iteration-loop', 'error'],
3940
['no-redundant-boolean', 'error'],

src/rules/no-nested-switch.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* eslint-plugin-sonarjs
3+
* Copyright (C) 2018-2021 SonarSource SA
4+
* mailto:info AT sonarsource DOT com
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 3 of the License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this program; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
*/
20+
// https://jira.sonarsource.com/browse/RSPEC-1821
21+
22+
import { TSESTree } from '@typescript-eslint/experimental-utils';
23+
import { Rule } from '../utils/types';
24+
25+
const message = 'Refactor the code to eliminate this nested "switch".';
26+
27+
const rule: Rule.RuleModule = {
28+
meta: {
29+
type: 'suggestion',
30+
},
31+
create(context: Rule.RuleContext) {
32+
return {
33+
'SwitchStatement SwitchStatement': (node: TSESTree.Node) => {
34+
const switchToken = context
35+
.getSourceCode()
36+
.getFirstToken(node, token => token.value === 'switch');
37+
context.report({
38+
message,
39+
loc: switchToken!.loc,
40+
});
41+
},
42+
};
43+
},
44+
};
45+
46+
export = rule;
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
* eslint-plugin-sonarjs
3+
* Copyright (C) 2018-2021 SonarSource SA
4+
* mailto:info AT sonarsource DOT com
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 3 of the License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this program; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
*/
20+
import { ruleTester } from '../rule-tester';
21+
import * as rule from '../../src/rules/no-nested-switch';
22+
23+
const MESSAGE = 'Refactor the code to eliminate this nested "switch".';
24+
25+
ruleTester.run('switch statements should not be nested', rule, {
26+
valid: [
27+
{
28+
code: `switch (x) {
29+
case 1: a; break;
30+
default: b;
31+
};`,
32+
},
33+
],
34+
invalid: [
35+
{
36+
code: `switch (x) {
37+
case 1: a; break;
38+
case 2:
39+
switch (y) {
40+
case 3: c; break;
41+
default: d;
42+
};
43+
break;
44+
default: b;
45+
}`,
46+
errors: [
47+
{
48+
message: MESSAGE,
49+
line: 4,
50+
endLine: 4,
51+
column: 11,
52+
endColumn: 17,
53+
},
54+
],
55+
},
56+
{
57+
code: `switch (x) {
58+
case 1: a; break;
59+
case 2: {
60+
switch (y) {
61+
case 3: c; break;
62+
default: d;
63+
};
64+
switch (z) {
65+
case 3: c; break;
66+
default: d;
67+
};
68+
break;
69+
}
70+
default: b;
71+
}`,
72+
errors: [
73+
{
74+
message: MESSAGE,
75+
line: 4,
76+
endLine: 4,
77+
column: 15,
78+
endColumn: 21,
79+
},
80+
{
81+
message: MESSAGE,
82+
line: 8,
83+
endLine: 8,
84+
column: 15,
85+
endColumn: 21,
86+
},
87+
],
88+
},
89+
{
90+
code: `switch (x) {
91+
case 1: a; break;
92+
case 2:
93+
switch (y) {
94+
case 3: c;
95+
default:
96+
switch (z) {
97+
case 4: d; break;
98+
default: e;
99+
}
100+
}
101+
break;
102+
default: b;
103+
}`,
104+
errors: [
105+
{
106+
message: MESSAGE,
107+
line: 4,
108+
endLine: 4,
109+
column: 15,
110+
endColumn: 21,
111+
},
112+
{
113+
message: MESSAGE,
114+
line: 7,
115+
endLine: 7,
116+
column: 19,
117+
endColumn: 25,
118+
},
119+
],
120+
},
121+
{
122+
code: `switch (x) {
123+
case 1: a;
124+
case 2: b;
125+
default:
126+
switch (y) {
127+
case 3: c;
128+
default: d;
129+
}
130+
}`,
131+
errors: [
132+
{
133+
message: MESSAGE,
134+
line: 5,
135+
endLine: 5,
136+
column: 15,
137+
endColumn: 21,
138+
},
139+
],
140+
},
141+
{
142+
code: `switch (x) {
143+
case 1:
144+
let isideFunction = () => {
145+
switch (y) {}
146+
}
147+
}`,
148+
errors: [
149+
{
150+
message: MESSAGE,
151+
line: 4,
152+
endLine: 4,
153+
column: 17,
154+
endColumn: 23,
155+
},
156+
],
157+
},
158+
],
159+
});

0 commit comments

Comments
 (0)