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

Commit 4600fd7

Browse files
add max-switch-cases rule (#77)
1 parent e20175a commit 4600fd7

File tree

6 files changed

+170
-0
lines changed

6 files changed

+170
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Rules in this category aim to find places in code which have a high chance to be
2323
Code Smells, or maintainability issues, are raised for places of code which might be costly to change in the future. These rules also help to keep the high code quality and readability. And finally some rules report issues on different suspicious code patters.
2424

2525
* Cognitive Complexity of functions should not be too high ([`cognitive-complexity`])
26+
* "switch" statements should not have too many "case" clauses ([`max-switch-cases`])
2627
* Two branches in a conditional structure should not have exactly the same implementation ([`no-duplicated-branches`])
2728
* Functions should not have identical implementations ([`no-identical-functions`])
2829
* Boolean checks should not be inverted ([`no-inverted-boolean-check`])
@@ -34,6 +35,7 @@ Code Smells, or maintainability issues, are raised for places of code which migh
3435
* A "while" loop should be used instead of a "for" loop ([`prefer-while`]) (:wrench: *fixable*)
3536

3637
[`cognitive-complexity`]: ./docs/rules/cognitive-complexity.md
38+
[`max-switch-cases`]: ./docs/rules/max-switch-cases.md
3739
[`no-all-duplicated-branches`]: ./docs/rules/no-all-duplicated-branches.md
3840
[`no-duplicated-branches`]: ./docs/rules/no-duplicated-branches.md
3941
[`no-element-overwrite`]: ./docs/rules/no-element-overwrite.md

docs/rules/max-switch-cases.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
## max-switch-cases
2+
3+
When `switch` statements have large sets of `case` clauses, it is usually an attempt to map two sets of data. A real map structure would be more readable and maintainable, and should be used instead.
4+
5+
#Options
6+
7+
This rule has a numeric option (defaulted to 30) to specify the maximum number of switch cases.
8+
9+
```
10+
{
11+
"max-switch-cases": ["error", 10]
12+
}
13+
```

ruling/snapshots/max-switch-cases

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
src/create-react-app/packages/react-scripts/fixtures/kitchensink/src/App.js: 53
2+
src/three.js/src/loaders/Loader.js: 175

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { Linter } from "eslint";
2121

2222
const sonarjsRules: [string, Linter.RuleLevel][] = [
2323
["cognitive-complexity", "error"],
24+
["max-switch-cases", "error"],
2425
["no-all-duplicated-branches", "error"],
2526
["no-duplicated-branches", "error"],
2627
["no-element-overwrite", "error"],

src/rules/max-switch-cases.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* eslint-plugin-sonarjs
3+
* Copyright (C) 2018 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-1479
21+
22+
import { Rule } from "eslint";
23+
import { Node, SwitchStatement, SwitchCase } from "estree";
24+
25+
const MESSAGE = "Reduce the number of non-empty switch cases from {{numSwitchCases}} to at most {{maxSwitchCases}}.";
26+
27+
const DEFAULT_MAX_SWITCH_CASES = 30;
28+
let maxSwitchCases = DEFAULT_MAX_SWITCH_CASES;
29+
30+
const rule: Rule.RuleModule = {
31+
meta: {
32+
schema: [
33+
{
34+
type: "integer",
35+
minimum: 0,
36+
},
37+
],
38+
},
39+
create(context: Rule.RuleContext) {
40+
if (context.options.length > 0) {
41+
maxSwitchCases = context.options[0];
42+
}
43+
return { SwitchStatement: (node: Node) => visitSwitchStatement(node as SwitchStatement, context) };
44+
},
45+
};
46+
47+
function visitSwitchStatement(switchStatement: SwitchStatement, context: Rule.RuleContext) {
48+
const nonEmptyCases = switchStatement.cases.filter(
49+
switchCase => switchCase.consequent.length > 0 && !isDefaultCase(switchCase),
50+
);
51+
if (nonEmptyCases.length > maxSwitchCases) {
52+
const switchKeyword = context.getSourceCode().getFirstToken(switchStatement);
53+
context.report({
54+
message: MESSAGE,
55+
loc: switchKeyword!.loc,
56+
data: { numSwitchCases: nonEmptyCases.length + "", maxSwitchCases: maxSwitchCases + "" },
57+
});
58+
}
59+
}
60+
61+
function isDefaultCase(switchCase: SwitchCase) {
62+
return switchCase.test === null;
63+
}
64+
65+
export = rule;
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* eslint-plugin-sonarjs
3+
* Copyright (C) 2018 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 "eslint";
21+
22+
const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2018 } });
23+
import rule = require("../../src/rules/max-switch-cases");
24+
25+
ruleTester.run("max-switch-cases", rule, {
26+
valid: [
27+
{
28+
code: `switch(i) {
29+
case 1:
30+
f();
31+
case 2:
32+
g();
33+
}`,
34+
},
35+
// default branch is excluded
36+
{
37+
code: `switch(i) {
38+
case 1:
39+
f();
40+
case 2:
41+
g();
42+
default:
43+
console.log("foo");
44+
}`,
45+
options: [2],
46+
},
47+
// empty branches are not counted
48+
{
49+
code: `switch(i) {
50+
case 1:
51+
case 2:
52+
g();
53+
case 3:
54+
console.log("foo");
55+
}`,
56+
options: [2],
57+
},
58+
// empty switch statement
59+
{
60+
code: `switch(i) {}`,
61+
},
62+
],
63+
invalid: [
64+
{
65+
code: `switch(i) {
66+
case 1:
67+
f();
68+
case 2:
69+
g();
70+
}`,
71+
options: [1],
72+
errors: [
73+
{
74+
message: message(2, 1),
75+
line: 1,
76+
endLine: 1,
77+
column: 1,
78+
endColumn: 7,
79+
},
80+
],
81+
},
82+
],
83+
});
84+
85+
function message(numSwitchCases: number, maxSwitchCases: number) {
86+
return `Reduce the number of non-empty switch cases from ${numSwitchCases} to at most ${maxSwitchCases}.`;
87+
}

0 commit comments

Comments
 (0)