eslint-plugin-sonarjs 0.7.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jfrog/projects/npm.yaml +8 -0
- package/README.md +21 -2
- package/lib/index.d.ts +5 -3
- package/lib/index.js +38 -28
- package/lib/index.js.map +1 -1
- package/lib/rules/cognitive-complexity.d.ts +2 -2
- package/lib/rules/cognitive-complexity.js +100 -42
- package/lib/rules/cognitive-complexity.js.map +1 -1
- package/lib/rules/elseif-without-else.d.ts +3 -0
- package/lib/rules/elseif-without-else.js +61 -0
- package/lib/rules/elseif-without-else.js.map +1 -0
- package/lib/rules/max-switch-cases.d.ts +3 -2
- package/lib/rules/max-switch-cases.js +21 -8
- package/lib/rules/max-switch-cases.js.map +1 -1
- package/lib/rules/no-all-duplicated-branches.d.ts +2 -2
- package/lib/rules/no-all-duplicated-branches.js +21 -13
- package/lib/rules/no-all-duplicated-branches.js.map +1 -1
- package/lib/rules/no-collapsible-if.d.ts +2 -2
- package/lib/rules/no-collapsible-if.js +20 -9
- package/lib/rules/no-collapsible-if.js.map +1 -1
- package/lib/rules/no-collection-size-mischeck.d.ts +2 -2
- package/lib/rules/no-collection-size-mischeck.js +25 -13
- package/lib/rules/no-collection-size-mischeck.js.map +1 -1
- package/lib/rules/no-duplicate-string.d.ts +3 -2
- package/lib/rules/no-duplicate-string.js +44 -20
- package/lib/rules/no-duplicate-string.js.map +1 -1
- package/lib/rules/no-duplicated-branches.d.ts +2 -2
- package/lib/rules/no-duplicated-branches.js +41 -26
- package/lib/rules/no-duplicated-branches.js.map +1 -1
- package/lib/rules/no-element-overwrite.d.ts +2 -2
- package/lib/rules/no-element-overwrite.js +37 -20
- package/lib/rules/no-element-overwrite.js.map +1 -1
- package/lib/rules/no-empty-collection.d.ts +3 -0
- package/lib/rules/no-empty-collection.js +199 -0
- package/lib/rules/no-empty-collection.js.map +1 -0
- package/lib/rules/no-extra-arguments.d.ts +2 -2
- package/lib/rules/no-extra-arguments.js +50 -31
- package/lib/rules/no-extra-arguments.js.map +1 -1
- package/lib/rules/no-gratuitous-expressions.d.ts +3 -0
- package/lib/rules/no-gratuitous-expressions.js +213 -0
- package/lib/rules/no-gratuitous-expressions.js.map +1 -0
- package/lib/rules/no-identical-conditions.d.ts +2 -2
- package/lib/rules/no-identical-conditions.js +23 -9
- package/lib/rules/no-identical-conditions.js.map +1 -1
- package/lib/rules/no-identical-expressions.d.ts +2 -2
- package/lib/rules/no-identical-expressions.js +39 -15
- package/lib/rules/no-identical-expressions.js.map +1 -1
- package/lib/rules/no-identical-functions.d.ts +2 -2
- package/lib/rules/no-identical-functions.js +29 -20
- package/lib/rules/no-identical-functions.js.map +1 -1
- package/lib/rules/no-ignored-return.d.ts +3 -0
- package/lib/rules/no-ignored-return.js +266 -0
- package/lib/rules/no-ignored-return.js.map +1 -0
- package/lib/rules/no-inverted-boolean-check.d.ts +2 -2
- package/lib/rules/no-inverted-boolean-check.js +30 -17
- package/lib/rules/no-inverted-boolean-check.js.map +1 -1
- package/lib/rules/no-nested-switch.d.ts +3 -0
- package/lib/rules/no-nested-switch.js +51 -0
- package/lib/rules/no-nested-switch.js.map +1 -0
- package/lib/rules/no-nested-template-literals.d.ts +3 -0
- package/lib/rules/no-nested-template-literals.js +48 -0
- package/lib/rules/no-nested-template-literals.js.map +1 -0
- package/lib/rules/no-one-iteration-loop.d.ts +2 -2
- package/lib/rules/no-one-iteration-loop.js +22 -13
- package/lib/rules/no-one-iteration-loop.js.map +1 -1
- package/lib/rules/no-redundant-boolean.d.ts +2 -2
- package/lib/rules/no-redundant-boolean.js +21 -12
- package/lib/rules/no-redundant-boolean.js.map +1 -1
- package/lib/rules/no-redundant-jump.d.ts +2 -2
- package/lib/rules/no-redundant-jump.js +19 -11
- package/lib/rules/no-redundant-jump.js.map +1 -1
- package/lib/rules/no-same-line-conditional.d.ts +2 -2
- package/lib/rules/no-same-line-conditional.js +21 -10
- package/lib/rules/no-same-line-conditional.js.map +1 -1
- package/lib/rules/no-small-switch.d.ts +2 -2
- package/lib/rules/no-small-switch.js +17 -5
- package/lib/rules/no-small-switch.js.map +1 -1
- package/lib/rules/no-unused-collection.d.ts +2 -2
- package/lib/rules/no-unused-collection.js +38 -20
- package/lib/rules/no-unused-collection.js.map +1 -1
- package/lib/rules/no-use-of-empty-return-value.d.ts +2 -2
- package/lib/rules/no-use-of-empty-return-value.js +37 -25
- package/lib/rules/no-use-of-empty-return-value.js.map +1 -1
- package/lib/rules/no-useless-catch.d.ts +2 -2
- package/lib/rules/no-useless-catch.js +21 -7
- package/lib/rules/no-useless-catch.js.map +1 -1
- package/lib/rules/non-existent-operator.d.ts +3 -0
- package/lib/rules/non-existent-operator.js +81 -0
- package/lib/rules/non-existent-operator.js.map +1 -0
- package/lib/rules/prefer-immediate-return.d.ts +2 -2
- package/lib/rules/prefer-immediate-return.js +41 -31
- package/lib/rules/prefer-immediate-return.js.map +1 -1
- package/lib/rules/prefer-object-literal.d.ts +2 -2
- package/lib/rules/prefer-object-literal.js +21 -12
- package/lib/rules/prefer-object-literal.js.map +1 -1
- package/lib/rules/prefer-single-boolean-return.d.ts +2 -2
- package/lib/rules/prefer-single-boolean-return.js +17 -25
- package/lib/rules/prefer-single-boolean-return.js.map +1 -1
- package/lib/rules/prefer-while.d.ts +2 -2
- package/lib/rules/prefer-while.js +16 -6
- package/lib/rules/prefer-while.js.map +1 -1
- package/lib/utils/collections.js +15 -15
- package/lib/utils/conditions.d.ts +6 -6
- package/lib/utils/conditions.js +4 -2
- package/lib/utils/conditions.js.map +1 -1
- package/lib/utils/docs-url.d.ts +1 -0
- package/lib/utils/docs-url.js +28 -0
- package/lib/utils/docs-url.js.map +1 -0
- package/lib/utils/equivalence.d.ts +2 -3
- package/lib/utils/equivalence.js +2 -1
- package/lib/utils/equivalence.js.map +1 -1
- package/lib/utils/index.d.ts +4 -0
- package/lib/utils/index.js +36 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/locations.d.ts +13 -11
- package/lib/utils/locations.js +63 -26
- package/lib/utils/locations.js.map +1 -1
- package/lib/utils/nodes.d.ts +22 -24
- package/lib/utils/nodes.js +25 -30
- package/lib/utils/nodes.js.map +1 -1
- package/lib/utils/parser-services.d.ts +2 -2
- package/lib/utils/parser-services.js +1 -1
- package/lib/utils/parser-services.js.map +1 -1
- package/lib/utils/utils-ast.d.ts +3 -0
- package/lib/utils/utils-ast.js +31 -0
- package/lib/utils/utils-ast.js.map +1 -0
- package/lib/utils/utils-collection.d.ts +1 -0
- package/lib/utils/utils-collection.js +24 -0
- package/lib/utils/utils-collection.js.map +1 -0
- package/lib/utils/utils-parent.d.ts +3 -0
- package/lib/utils/utils-parent.js +21 -0
- package/lib/utils/utils-parent.js.map +1 -0
- package/lib/utils/utils-type.d.ts +3 -0
- package/lib/utils/utils-type.js +28 -0
- package/lib/utils/utils-type.js.map +1 -0
- package/package.json +27 -23
- package/wss-unified-agent.config +20 -0
- package/.cirrus/nodejs-10.Dockerfile +0 -29
- package/.cirrus/nodejs-12.Dockerfile +0 -28
- package/.cirrus/nodejs-14.Dockerfile +0 -28
- package/.cirrus/nodejs-15.Dockerfile +0 -28
- package/.cirrus.yml +0 -47
package/README.md
CHANGED
|
@@ -10,24 +10,31 @@ Rules in this category aim to find places in code which have a high chance of be
|
|
|
10
10
|
|
|
11
11
|
* All branches in a conditional structure should not have exactly the same implementation ([`no-all-duplicated-branches`])
|
|
12
12
|
* Collection elements should not be replaced unconditionally ([`no-element-overwrite`])
|
|
13
|
+
* Empty collections should not be accessed or iterated ([`no-empty-collection`])
|
|
13
14
|
* Function calls should not pass extra arguments ([`no-extra-arguments`])
|
|
14
15
|
* Related "if/else if" statements should not have the same condition ([`no-identical-conditions`])
|
|
15
16
|
* Identical expressions should not be used on both sides of a binary operator ([`no-identical-expressions`])
|
|
17
|
+
* Return values from functions without side effects should not be ignored ([`no-ignored-return`]) (*uses-types*)
|
|
16
18
|
* Loops with at most one iteration should be refactored ([`no-one-iteration-loop`])
|
|
17
19
|
* The output of functions that don't return anything should not be used ([`no-use-of-empty-return-value`])
|
|
20
|
+
* Non-existent operators '=+', '=-' and '=!' should not be used ([`non-existent-operator`])
|
|
18
21
|
|
|
19
22
|
### Code Smell Detection :pig:
|
|
20
23
|
|
|
21
24
|
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.
|
|
22
25
|
|
|
23
26
|
* Cognitive Complexity of functions should not be too high ([`cognitive-complexity`])
|
|
27
|
+
* "if ... else if" constructs should end with "else" clauses ([`elseif-without-else`]) (*disabled*)
|
|
24
28
|
* "switch" statements should not have too many "case" clauses ([`max-switch-cases`])
|
|
25
29
|
* Collapsible "if" statements should be merged ([`no-collapsible-if`])
|
|
26
|
-
* Collection sizes and array length comparisons should make sense ([`no-collection-size-mischeck`])
|
|
30
|
+
* Collection sizes and array length comparisons should make sense ([`no-collection-size-mischeck`]) (*uses-types*)
|
|
27
31
|
* String literals should not be duplicated ([`no-duplicate-string`])
|
|
28
32
|
* Two branches in a conditional structure should not have exactly the same implementation ([`no-duplicated-branches`])
|
|
33
|
+
* Boolean expressions should not be gratuitous ([`no-gratuitous-expressions`])
|
|
29
34
|
* Functions should not have identical implementations ([`no-identical-functions`])
|
|
30
35
|
* Boolean checks should not be inverted ([`no-inverted-boolean-check`]) (:wrench: *fixable*)
|
|
36
|
+
* "switch" statements should not be nested ([`no-nested-switch`])
|
|
37
|
+
* Template literals should not be nested ([`no-nested-template-literals`])
|
|
31
38
|
* Boolean literals should not be redundant ([`no-redundant-boolean`])
|
|
32
39
|
* Jump statements should not be redundant ([`no-redundant-jump`])
|
|
33
40
|
* Conditionals should start on new lines ([`no-same-line-conditional`])
|
|
@@ -40,6 +47,7 @@ Code Smells, or maintainability issues, are raised for places of code which migh
|
|
|
40
47
|
* A "while" loop should be used instead of a "for" loop ([`prefer-while`]) (:wrench: *fixable*)
|
|
41
48
|
|
|
42
49
|
[`cognitive-complexity`]: ./docs/rules/cognitive-complexity.md
|
|
50
|
+
[`elseif-without-else`]: ./docs/rules/elseif-without-else.md
|
|
43
51
|
[`max-switch-cases`]: ./docs/rules/max-switch-cases.md
|
|
44
52
|
[`no-all-duplicated-branches`]: ./docs/rules/no-all-duplicated-branches.md
|
|
45
53
|
[`no-collapsible-if`]: ./docs/rules/no-collapsible-if.md
|
|
@@ -47,11 +55,16 @@ Code Smells, or maintainability issues, are raised for places of code which migh
|
|
|
47
55
|
[`no-duplicate-string`]: ./docs/rules/no-duplicate-string.md
|
|
48
56
|
[`no-duplicated-branches`]: ./docs/rules/no-duplicated-branches.md
|
|
49
57
|
[`no-element-overwrite`]: ./docs/rules/no-element-overwrite.md
|
|
58
|
+
[`no-empty-collection`]: ./docs/rules/no-empty-collection.md
|
|
50
59
|
[`no-extra-arguments`]: ./docs/rules/no-extra-arguments.md
|
|
60
|
+
[`no-gratuitous-expressions`]: ./docs/rules/no-gratuitous-expressions.md
|
|
51
61
|
[`no-identical-conditions`]: ./docs/rules/no-identical-conditions.md
|
|
52
62
|
[`no-identical-expressions`]: ./docs/rules/no-identical-expressions.md
|
|
53
63
|
[`no-identical-functions`]: ./docs/rules/no-identical-functions.md
|
|
64
|
+
[`no-ignored-return`]: ./docs/rules/no-ignored-return.md
|
|
54
65
|
[`no-inverted-boolean-check`]: ./docs/rules/no-inverted-boolean-check.md
|
|
66
|
+
[`no-nested-switch`]: ./docs/rules/no-nested-switch.md
|
|
67
|
+
[`no-nested-template-literals`]: ./docs/rules/no-nested-template-literals.md
|
|
55
68
|
[`no-one-iteration-loop`]: ./docs/rules/no-one-iteration-loop.md
|
|
56
69
|
[`no-redundant-boolean`]: ./docs/rules/no-redundant-boolean.md
|
|
57
70
|
[`no-redundant-jump`]: ./docs/rules/no-redundant-jump.md
|
|
@@ -60,6 +73,7 @@ Code Smells, or maintainability issues, are raised for places of code which migh
|
|
|
60
73
|
[`no-use-of-empty-return-value`]: ./docs/rules/no-use-of-empty-return-value.md
|
|
61
74
|
[`no-unused-collection`]: ./docs/rules/no-unused-collection.md
|
|
62
75
|
[`no-useless-catch`]: ./docs/rules/no-useless-catch.md
|
|
76
|
+
[`non-existent-operator`]: ./docs/rules/non-existent-operator.md
|
|
63
77
|
[`prefer-immediate-return`]: ./docs/rules/prefer-immediate-return.md
|
|
64
78
|
[`prefer-object-literal`]: ./docs/rules/prefer-object-literal.md
|
|
65
79
|
[`prefer-single-boolean-return`]: ./docs/rules/prefer-single-boolean-return.md
|
|
@@ -67,7 +81,8 @@ Code Smells, or maintainability issues, are raised for places of code which migh
|
|
|
67
81
|
|
|
68
82
|
## Prerequisites
|
|
69
83
|
|
|
70
|
-
Node.js (>=
|
|
84
|
+
* Node.js (>=12.x).
|
|
85
|
+
* ESLint 5.x, 6.x, 7.x or 8.x (peer dependency for the plugin).
|
|
71
86
|
|
|
72
87
|
## Usage
|
|
73
88
|
|
|
@@ -106,7 +121,11 @@ npm install eslint-plugin-sonarjs -g # or install globally
|
|
|
106
121
|
}
|
|
107
122
|
}
|
|
108
123
|
```
|
|
124
|
+
* To enable all rules of this plugin, use `@typescript-eslint/parser` as a parser for ESLint ([like we do](https://github.com/SonarSource/eslint-plugin-sonarjs/blob/6e06d59a233e07b28fbbd6398e08b9b0c63b18f9/.eslintrc.js#L4)) and set the [parserOptions.project](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#parseroptionsproject) option. Thanks to it, type information is available, which is beneficial or even essential for some rules.
|
|
109
125
|
|
|
126
|
+
## Available Configurations
|
|
127
|
+
|
|
128
|
+
This plugin provides only `recommended` configuration. Almost all rules are activated in this profile with a few exceptions (check `disabled` tag in the rules list). `recommended` configuration activates rules with `error` severity.
|
|
110
129
|
## Contributing
|
|
111
130
|
|
|
112
131
|
You want to participate in the development of the project? Have a look at our [contributing](./docs/CONTRIBUTING.md) guide!
|
package/lib/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare const sonarjsRuleModules:
|
|
1
|
+
import type { TSESLint } from '@typescript-eslint/experimental-utils';
|
|
2
|
+
declare const sonarjsRuleModules: {
|
|
3
|
+
[key: string]: any;
|
|
4
|
+
};
|
|
3
5
|
declare const configs: {
|
|
4
|
-
recommended: Linter.Config & {
|
|
6
|
+
recommended: TSESLint.Linter.Config & {
|
|
5
7
|
plugins: string[];
|
|
6
8
|
};
|
|
7
9
|
};
|
package/lib/index.js
CHANGED
|
@@ -2,38 +2,48 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.configs = exports.rules = void 0;
|
|
4
4
|
const sonarjsRules = [
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
5
|
+
'cognitive-complexity',
|
|
6
|
+
'elseif-without-else',
|
|
7
|
+
'max-switch-cases',
|
|
8
|
+
'no-all-duplicated-branches',
|
|
9
|
+
'no-collapsible-if',
|
|
10
|
+
'no-collection-size-mischeck',
|
|
11
|
+
'no-duplicate-string',
|
|
12
|
+
'no-duplicated-branches',
|
|
13
|
+
'no-element-overwrite',
|
|
14
|
+
'no-empty-collection',
|
|
15
|
+
'no-extra-arguments',
|
|
16
|
+
'no-gratuitous-expressions',
|
|
17
|
+
'no-identical-conditions',
|
|
18
|
+
'no-identical-expressions',
|
|
19
|
+
'no-identical-functions',
|
|
20
|
+
'no-ignored-return',
|
|
21
|
+
'no-inverted-boolean-check',
|
|
22
|
+
'no-nested-switch',
|
|
23
|
+
'no-nested-template-literals',
|
|
24
|
+
'no-one-iteration-loop',
|
|
25
|
+
'no-redundant-boolean',
|
|
26
|
+
'no-redundant-jump',
|
|
27
|
+
'no-same-line-conditional',
|
|
28
|
+
'no-small-switch',
|
|
29
|
+
'no-unused-collection',
|
|
30
|
+
'no-use-of-empty-return-value',
|
|
31
|
+
'no-useless-catch',
|
|
32
|
+
'non-existent-operator',
|
|
33
|
+
'prefer-immediate-return',
|
|
34
|
+
'prefer-object-literal',
|
|
35
|
+
'prefer-single-boolean-return',
|
|
36
|
+
'prefer-while',
|
|
30
37
|
];
|
|
31
38
|
const sonarjsRuleModules = {};
|
|
32
39
|
exports.rules = sonarjsRuleModules;
|
|
33
40
|
const configs = {
|
|
34
|
-
recommended: { plugins: [
|
|
41
|
+
recommended: { plugins: ['sonarjs'], rules: {} },
|
|
35
42
|
};
|
|
36
43
|
exports.configs = configs;
|
|
37
|
-
sonarjsRules.forEach(rule =>
|
|
38
|
-
|
|
44
|
+
sonarjsRules.forEach(rule => {
|
|
45
|
+
sonarjsRuleModules[rule] = require(`./rules/${rule}`);
|
|
46
|
+
const { meta: { docs: { recommended }, }, } = sonarjsRuleModules[rule];
|
|
47
|
+
configs.recommended.rules[`sonarjs/${rule}`] = recommended === false ? 'off' : recommended;
|
|
48
|
+
});
|
|
39
49
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAqBA,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAqBA,MAAM,YAAY,GAAa;IAC7B,sBAAsB;IACtB,qBAAqB;IACrB,kBAAkB;IAClB,4BAA4B;IAC5B,mBAAmB;IACnB,6BAA6B;IAC7B,qBAAqB;IACrB,wBAAwB;IACxB,sBAAsB;IACtB,qBAAqB;IACrB,oBAAoB;IACpB,2BAA2B;IAC3B,yBAAyB;IACzB,0BAA0B;IAC1B,wBAAwB;IACxB,mBAAmB;IACnB,2BAA2B;IAC3B,kBAAkB;IAClB,6BAA6B;IAC7B,uBAAuB;IACvB,sBAAsB;IACtB,mBAAmB;IACnB,0BAA0B;IAC1B,iBAAiB;IACjB,sBAAsB;IACtB,8BAA8B;IAC9B,kBAAkB;IAClB,uBAAuB;IACvB,yBAAyB;IACzB,uBAAuB;IACvB,8BAA8B;IAC9B,cAAc;CACf,CAAC;AAEF,MAAM,kBAAkB,GAA2B,EAAE,CAAC;AAgBvB,mCAAK;AAdpC,MAAM,OAAO,GAAoE;IAC/E,WAAW,EAAE,EAAE,OAAO,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;CACjD,CAAC;AAYoC,0BAAO;AAV7C,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;IAC1B,kBAAkB,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IACtD,MAAM,EACJ,IAAI,EAAE,EACJ,IAAI,EAAE,EAAE,WAAW,EAAE,GACtB,GACF,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,CAAC,WAAW,CAAC,KAAM,CAAC,WAAW,IAAI,EAAE,CAAC,GAAG,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC;AAC9F,CAAC,CAAC,CAAC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare const rule:
|
|
1
|
+
import type { TSESLint } from '@typescript-eslint/experimental-utils';
|
|
2
|
+
declare const rule: TSESLint.RuleModule<string, (number | 'metric' | 'sonar-runtime')[]>;
|
|
3
3
|
export = rule;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
3
|
* eslint-plugin-sonarjs
|
|
4
|
-
* Copyright (C) 2018 SonarSource SA
|
|
4
|
+
* Copyright (C) 2018-2021 SonarSource SA
|
|
5
5
|
* mailto:info AT sonarsource DOT com
|
|
6
6
|
*
|
|
7
7
|
* This program is free software; you can redistribute it and/or
|
|
@@ -18,24 +18,36 @@
|
|
|
18
18
|
* along with this program; if not, write to the Free Software Foundation,
|
|
19
19
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
20
20
|
*/
|
|
21
|
-
// https://
|
|
21
|
+
// https://sonarsource.github.io/rspec/#/rspec/S3776
|
|
22
22
|
const nodes_1 = require("../utils/nodes");
|
|
23
23
|
const locations_1 = require("../utils/locations");
|
|
24
|
+
const docs_url_1 = require("../utils/docs-url");
|
|
24
25
|
const DEFAULT_THRESHOLD = 15;
|
|
26
|
+
const message = 'Refactor this function to reduce its Cognitive Complexity from {{complexityAmount}} to the {{threshold}} allowed.';
|
|
25
27
|
const rule = {
|
|
26
28
|
meta: {
|
|
27
|
-
|
|
29
|
+
messages: {
|
|
30
|
+
refactorFunction: message,
|
|
31
|
+
sonarRuntime: '{{sonarRuntimeData}}',
|
|
32
|
+
fileComplexity: '{{complexityAmount}}',
|
|
33
|
+
},
|
|
34
|
+
type: 'suggestion',
|
|
35
|
+
docs: {
|
|
36
|
+
description: 'Cognitive Complexity of functions should not be too high',
|
|
37
|
+
recommended: 'error',
|
|
38
|
+
url: (0, docs_url_1.default)(__filename),
|
|
39
|
+
},
|
|
28
40
|
schema: [
|
|
29
|
-
{ type:
|
|
41
|
+
{ type: 'integer', minimum: 0 },
|
|
30
42
|
{
|
|
31
43
|
// internal parameter
|
|
32
|
-
enum: [
|
|
44
|
+
enum: ['sonar-runtime', 'metric'],
|
|
33
45
|
},
|
|
34
46
|
],
|
|
35
47
|
},
|
|
36
48
|
create(context) {
|
|
37
|
-
const threshold =
|
|
38
|
-
const isFileComplexity = context.options.includes(
|
|
49
|
+
const threshold = typeof context.options[0] === 'number' ? context.options[0] : DEFAULT_THRESHOLD;
|
|
50
|
+
const isFileComplexity = context.options.includes('metric');
|
|
39
51
|
/** Complexity of the file */
|
|
40
52
|
let fileComplexity = 0;
|
|
41
53
|
/** Complexity of the current function if it is *not* considered nested to the first level function */
|
|
@@ -46,6 +58,18 @@ const rule = {
|
|
|
46
58
|
let nesting = 0;
|
|
47
59
|
/** Indicator if the current top level function has a structural (generated by control flow statements) complexity */
|
|
48
60
|
let topLevelHasStructuralComplexity = false;
|
|
61
|
+
/** Indicator if the current top level function is React functional component */
|
|
62
|
+
const reactFunctionalComponent = {
|
|
63
|
+
nameStartsWithCapital: false,
|
|
64
|
+
returnsJsx: false,
|
|
65
|
+
isConfirmed() {
|
|
66
|
+
return this.nameStartsWithCapital && this.returnsJsx;
|
|
67
|
+
},
|
|
68
|
+
init(node) {
|
|
69
|
+
this.nameStartsWithCapital = nameStartsWithCapital(node);
|
|
70
|
+
this.returnsJsx = false;
|
|
71
|
+
},
|
|
72
|
+
};
|
|
49
73
|
/** Own (not including nested functions) complexity of the current top function */
|
|
50
74
|
let topLevelOwnComplexity = [];
|
|
51
75
|
/** Nodes that should increase nesting level */
|
|
@@ -56,18 +80,18 @@ const rule = {
|
|
|
56
80
|
const enclosingFunctions = [];
|
|
57
81
|
let secondLevelFunctions = [];
|
|
58
82
|
return {
|
|
59
|
-
|
|
83
|
+
':function': (node) => {
|
|
60
84
|
onEnterFunction(node);
|
|
61
85
|
},
|
|
62
|
-
|
|
86
|
+
':function:exit'(node) {
|
|
63
87
|
onLeaveFunction(node);
|
|
64
88
|
},
|
|
65
|
-
|
|
89
|
+
'*'(node) {
|
|
66
90
|
if (nestingNodes.has(node)) {
|
|
67
91
|
nesting++;
|
|
68
92
|
}
|
|
69
93
|
},
|
|
70
|
-
|
|
94
|
+
'*:exit'(node) {
|
|
71
95
|
if (nestingNodes.has(node)) {
|
|
72
96
|
nesting--;
|
|
73
97
|
nestingNodes.delete(node);
|
|
@@ -76,11 +100,14 @@ const rule = {
|
|
|
76
100
|
Program() {
|
|
77
101
|
fileComplexity = 0;
|
|
78
102
|
},
|
|
79
|
-
|
|
103
|
+
'Program:exit'(node) {
|
|
80
104
|
if (isFileComplexity) {
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
105
|
+
// value from the message will be saved in SonarQube as file complexity metric
|
|
106
|
+
context.report({
|
|
107
|
+
node,
|
|
108
|
+
messageId: 'fileComplexity',
|
|
109
|
+
data: { complexityAmount: fileComplexity },
|
|
110
|
+
});
|
|
84
111
|
}
|
|
85
112
|
},
|
|
86
113
|
IfStatement(node) {
|
|
@@ -119,14 +146,15 @@ const rule = {
|
|
|
119
146
|
ConditionalExpression(node) {
|
|
120
147
|
visitConditionalExpression(node);
|
|
121
148
|
},
|
|
149
|
+
ReturnStatement(node) {
|
|
150
|
+
visitReturnStatement(node);
|
|
151
|
+
},
|
|
122
152
|
};
|
|
123
|
-
function getThreshold() {
|
|
124
|
-
return context.options[0] !== undefined ? context.options[0] : DEFAULT_THRESHOLD;
|
|
125
|
-
}
|
|
126
153
|
function onEnterFunction(node) {
|
|
127
154
|
if (enclosingFunctions.length === 0) {
|
|
128
155
|
// top level function
|
|
129
156
|
topLevelHasStructuralComplexity = false;
|
|
157
|
+
reactFunctionalComponent.init(node);
|
|
130
158
|
topLevelOwnComplexity = [];
|
|
131
159
|
secondLevelFunctions = [];
|
|
132
160
|
}
|
|
@@ -145,17 +173,17 @@ const rule = {
|
|
|
145
173
|
enclosingFunctions.pop();
|
|
146
174
|
if (enclosingFunctions.length === 0) {
|
|
147
175
|
// top level function
|
|
148
|
-
if (topLevelHasStructuralComplexity) {
|
|
176
|
+
if (topLevelHasStructuralComplexity && !reactFunctionalComponent.isConfirmed()) {
|
|
149
177
|
let totalComplexity = topLevelOwnComplexity;
|
|
150
178
|
secondLevelFunctions.forEach(secondLevelFunction => {
|
|
151
179
|
totalComplexity = totalComplexity.concat(secondLevelFunction.complexityIfNested);
|
|
152
180
|
});
|
|
153
|
-
checkFunction(totalComplexity, locations_1.getMainFunctionTokenLocation(node,
|
|
181
|
+
checkFunction(totalComplexity, (0, locations_1.getMainFunctionTokenLocation)(node, node.parent, context));
|
|
154
182
|
}
|
|
155
183
|
else {
|
|
156
|
-
checkFunction(topLevelOwnComplexity, locations_1.getMainFunctionTokenLocation(node,
|
|
184
|
+
checkFunction(topLevelOwnComplexity, (0, locations_1.getMainFunctionTokenLocation)(node, node.parent, context));
|
|
157
185
|
secondLevelFunctions.forEach(secondLevelFunction => {
|
|
158
|
-
checkFunction(secondLevelFunction.complexityIfThisSecondaryIsTopLevel, locations_1.getMainFunctionTokenLocation(secondLevelFunction.node, secondLevelFunction.parent, context));
|
|
186
|
+
checkFunction(secondLevelFunction.complexityIfThisSecondaryIsTopLevel, (0, locations_1.getMainFunctionTokenLocation)(secondLevelFunction.node, secondLevelFunction.parent, context));
|
|
159
187
|
});
|
|
160
188
|
}
|
|
161
189
|
}
|
|
@@ -163,10 +191,10 @@ const rule = {
|
|
|
163
191
|
// second level function
|
|
164
192
|
secondLevelFunctions.push({
|
|
165
193
|
node,
|
|
166
|
-
parent:
|
|
194
|
+
parent: node.parent,
|
|
167
195
|
complexityIfNested,
|
|
168
196
|
complexityIfThisSecondaryIsTopLevel: complexityIfNotNested,
|
|
169
|
-
loc: locations_1.getMainFunctionTokenLocation(node,
|
|
197
|
+
loc: (0, locations_1.getMainFunctionTokenLocation)(node, node.parent, context),
|
|
170
198
|
});
|
|
171
199
|
}
|
|
172
200
|
else {
|
|
@@ -175,10 +203,10 @@ const rule = {
|
|
|
175
203
|
}
|
|
176
204
|
}
|
|
177
205
|
function visitIfStatement(ifStatement) {
|
|
178
|
-
const parent =
|
|
179
|
-
const { loc: ifLoc } = locations_1.getFirstToken(ifStatement, context);
|
|
206
|
+
const { parent } = ifStatement;
|
|
207
|
+
const { loc: ifLoc } = (0, locations_1.getFirstToken)(ifStatement, context);
|
|
180
208
|
// if the current `if` statement is `else if`, do not count it in structural complexity
|
|
181
|
-
if (nodes_1.isIfStatement(parent) && parent.alternate === ifStatement) {
|
|
209
|
+
if ((0, nodes_1.isIfStatement)(parent) && parent.alternate === ifStatement) {
|
|
182
210
|
addComplexity(ifLoc);
|
|
183
211
|
}
|
|
184
212
|
else {
|
|
@@ -189,44 +217,66 @@ const rule = {
|
|
|
189
217
|
// if `else` branch is not `else if` then
|
|
190
218
|
// - increase nesting level inside `else` statement
|
|
191
219
|
// - add +1 complexity
|
|
192
|
-
if (ifStatement.alternate && !nodes_1.isIfStatement(ifStatement.alternate)) {
|
|
220
|
+
if (ifStatement.alternate && !(0, nodes_1.isIfStatement)(ifStatement.alternate)) {
|
|
193
221
|
nestingNodes.add(ifStatement.alternate);
|
|
194
|
-
const elseTokenLoc = locations_1.getFirstTokenAfter(ifStatement.consequent, context).loc;
|
|
222
|
+
const elseTokenLoc = (0, locations_1.getFirstTokenAfter)(ifStatement.consequent, context).loc;
|
|
195
223
|
addComplexity(elseTokenLoc);
|
|
196
224
|
}
|
|
197
225
|
}
|
|
198
226
|
function visitLoop(loop) {
|
|
199
|
-
addStructuralComplexity(locations_1.getFirstToken(loop, context).loc);
|
|
227
|
+
addStructuralComplexity((0, locations_1.getFirstToken)(loop, context).loc);
|
|
200
228
|
nestingNodes.add(loop.body);
|
|
201
229
|
}
|
|
202
230
|
function visitSwitchStatement(switchStatement) {
|
|
203
|
-
addStructuralComplexity(locations_1.getFirstToken(switchStatement, context).loc);
|
|
231
|
+
addStructuralComplexity((0, locations_1.getFirstToken)(switchStatement, context).loc);
|
|
204
232
|
for (const switchCase of switchStatement.cases) {
|
|
205
233
|
nestingNodes.add(switchCase);
|
|
206
234
|
}
|
|
207
235
|
}
|
|
208
236
|
function visitContinueOrBreakStatement(statement) {
|
|
209
237
|
if (statement.label) {
|
|
210
|
-
addComplexity(locations_1.getFirstToken(statement, context).loc);
|
|
238
|
+
addComplexity((0, locations_1.getFirstToken)(statement, context).loc);
|
|
211
239
|
}
|
|
212
240
|
}
|
|
213
241
|
function visitCatchClause(catchClause) {
|
|
214
|
-
addStructuralComplexity(locations_1.getFirstToken(catchClause, context).loc);
|
|
242
|
+
addStructuralComplexity((0, locations_1.getFirstToken)(catchClause, context).loc);
|
|
215
243
|
nestingNodes.add(catchClause.body);
|
|
216
244
|
}
|
|
217
245
|
function visitConditionalExpression(conditionalExpression) {
|
|
218
|
-
const questionTokenLoc = locations_1.getFirstTokenAfter(conditionalExpression.test, context).loc;
|
|
246
|
+
const questionTokenLoc = (0, locations_1.getFirstTokenAfter)(conditionalExpression.test, context).loc;
|
|
219
247
|
addStructuralComplexity(questionTokenLoc);
|
|
220
248
|
nestingNodes.add(conditionalExpression.consequent);
|
|
221
249
|
nestingNodes.add(conditionalExpression.alternate);
|
|
222
250
|
}
|
|
251
|
+
function visitReturnStatement({ argument }) {
|
|
252
|
+
// top level function
|
|
253
|
+
if (enclosingFunctions.length === 1 &&
|
|
254
|
+
argument &&
|
|
255
|
+
['JSXElement', 'JSXFragment'].includes(argument.type)) {
|
|
256
|
+
reactFunctionalComponent.returnsJsx = true;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function nameStartsWithCapital(node) {
|
|
260
|
+
const checkFirstLetter = (name) => {
|
|
261
|
+
const firstLetter = name[0];
|
|
262
|
+
return firstLetter === firstLetter.toUpperCase();
|
|
263
|
+
};
|
|
264
|
+
if (!(0, nodes_1.isArrowFunctionExpression)(node) && node.id) {
|
|
265
|
+
return checkFirstLetter(node.id.name);
|
|
266
|
+
}
|
|
267
|
+
const { parent } = node;
|
|
268
|
+
if (parent && parent.type === 'VariableDeclarator' && parent.id.type === 'Identifier') {
|
|
269
|
+
return checkFirstLetter(parent.id.name);
|
|
270
|
+
}
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
223
273
|
function visitLogicalExpression(logicalExpression) {
|
|
224
274
|
if (!consideredLogicalExpressions.has(logicalExpression)) {
|
|
225
275
|
const flattenedLogicalExpressions = flattenLogicalExpression(logicalExpression);
|
|
226
276
|
let previous;
|
|
227
277
|
for (const current of flattenedLogicalExpressions) {
|
|
228
278
|
if (!previous || previous.operator !== current.operator) {
|
|
229
|
-
const operatorTokenLoc = locations_1.getFirstTokenAfter(logicalExpression.left, context).loc;
|
|
279
|
+
const operatorTokenLoc = (0, locations_1.getFirstTokenAfter)(logicalExpression.left, context).loc;
|
|
230
280
|
addComplexity(operatorTokenLoc);
|
|
231
281
|
}
|
|
232
282
|
previous = current;
|
|
@@ -234,9 +284,13 @@ const rule = {
|
|
|
234
284
|
}
|
|
235
285
|
}
|
|
236
286
|
function flattenLogicalExpression(node) {
|
|
237
|
-
if (nodes_1.isLogicalExpression(node)) {
|
|
287
|
+
if ((0, nodes_1.isLogicalExpression)(node)) {
|
|
238
288
|
consideredLogicalExpressions.add(node);
|
|
239
|
-
return [
|
|
289
|
+
return [
|
|
290
|
+
...flattenLogicalExpression(node.left),
|
|
291
|
+
node,
|
|
292
|
+
...flattenLogicalExpression(node.right),
|
|
293
|
+
];
|
|
240
294
|
}
|
|
241
295
|
return [];
|
|
242
296
|
}
|
|
@@ -283,13 +337,17 @@ const rule = {
|
|
|
283
337
|
if (complexityAmount > threshold) {
|
|
284
338
|
const secondaryLocations = complexity.map(complexityPoint => {
|
|
285
339
|
const { complexity, location } = complexityPoint;
|
|
286
|
-
const message = complexity === 1 ?
|
|
287
|
-
return locations_1.issueLocation(location, undefined, message);
|
|
340
|
+
const message = complexity === 1 ? '+1' : `+${complexity} (incl. ${complexity - 1} for nesting)`;
|
|
341
|
+
return (0, locations_1.issueLocation)(location, undefined, message);
|
|
288
342
|
});
|
|
289
|
-
locations_1.report(context, {
|
|
290
|
-
|
|
343
|
+
(0, locations_1.report)(context, {
|
|
344
|
+
messageId: 'refactorFunction',
|
|
345
|
+
data: {
|
|
346
|
+
complexityAmount,
|
|
347
|
+
threshold,
|
|
348
|
+
},
|
|
291
349
|
loc,
|
|
292
|
-
}, secondaryLocations, complexityAmount - threshold);
|
|
350
|
+
}, secondaryLocations, message, complexityAmount - threshold);
|
|
293
351
|
}
|
|
294
352
|
}
|
|
295
353
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cognitive-complexity.js","sourceRoot":"","sources":["../../src/rules/cognitive-complexity.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,
|
|
1
|
+
{"version":3,"file":"cognitive-complexity.js","sourceRoot":"","sources":["../../src/rules/cognitive-complexity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* eslint-plugin-sonarjs
|
|
4
|
+
* Copyright (C) 2018-2021 SonarSource SA
|
|
5
|
+
* mailto:info AT sonarsource DOT com
|
|
6
|
+
*
|
|
7
|
+
* This program is free software; you can redistribute it and/or
|
|
8
|
+
* modify it under the terms of the GNU Lesser General Public
|
|
9
|
+
* License as published by the Free Software Foundation; either
|
|
10
|
+
* version 3 of the License, or (at your option) any later version.
|
|
11
|
+
*
|
|
12
|
+
* This program is distributed in the hope that it will be useful,
|
|
13
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
15
|
+
* Lesser General Public License for more details.
|
|
16
|
+
*
|
|
17
|
+
* You should have received a copy of the GNU Lesser General Public License
|
|
18
|
+
* along with this program; if not, write to the Free Software Foundation,
|
|
19
|
+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
20
|
+
*/
|
|
21
|
+
// https://sonarsource.github.io/rspec/#/rspec/S126
|
|
22
|
+
const docs_url_1 = require("../utils/docs-url");
|
|
23
|
+
const rule = {
|
|
24
|
+
meta: {
|
|
25
|
+
messages: {
|
|
26
|
+
addMissingElseClause: 'Add the missing "else" clause.',
|
|
27
|
+
},
|
|
28
|
+
schema: [],
|
|
29
|
+
type: 'suggestion',
|
|
30
|
+
docs: {
|
|
31
|
+
description: '"if ... else if" constructs should end with "else" clauses',
|
|
32
|
+
recommended: false,
|
|
33
|
+
url: (0, docs_url_1.default)(__filename),
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
create(context) {
|
|
37
|
+
return {
|
|
38
|
+
IfStatement: (node) => {
|
|
39
|
+
const ifstmt = node;
|
|
40
|
+
if (isElseIf(ifstmt) && !ifstmt.alternate) {
|
|
41
|
+
const sourceCode = context.getSourceCode();
|
|
42
|
+
const elseKeyword = sourceCode.getTokenBefore(node, token => token.type === 'Keyword' && token.value === 'else');
|
|
43
|
+
const ifKeyword = sourceCode.getFirstToken(node, token => token.type === 'Keyword' && token.value === 'if');
|
|
44
|
+
context.report({
|
|
45
|
+
messageId: 'addMissingElseClause',
|
|
46
|
+
loc: {
|
|
47
|
+
start: elseKeyword.loc.start,
|
|
48
|
+
end: ifKeyword.loc.end,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
function isElseIf(node) {
|
|
57
|
+
const { parent } = node;
|
|
58
|
+
return (parent === null || parent === void 0 ? void 0 : parent.type) === 'IfStatement' && parent.alternate === node;
|
|
59
|
+
}
|
|
60
|
+
module.exports = rule;
|
|
61
|
+
//# sourceMappingURL=elseif-without-else.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elseif-without-else.js","sourceRoot":"","sources":["../../src/rules/elseif-without-else.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,mDAAmD;AAGnD,gDAAwC;AAExC,MAAM,IAAI,GAA0C;IAClD,IAAI,EAAE;QACJ,QAAQ,EAAE;YACR,oBAAoB,EAAE,gCAAgC;SACvD;QACD,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EAAE,4DAA4D;YACzE,WAAW,EAAE,KAAK;YAClB,GAAG,EAAE,IAAA,kBAAO,EAAC,UAAU,CAAC;SACzB;KACF;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,WAAW,EAAE,CAAC,IAAmB,EAAE,EAAE;gBACnC,MAAM,MAAM,GAAG,IAA4B,CAAC;gBAC5C,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;oBACzC,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;oBAC3C,MAAM,WAAW,GAAG,UAAU,CAAC,cAAc,CAC3C,IAAI,EACJ,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM,CAC5D,CAAC;oBACF,MAAM,SAAS,GAAG,UAAU,CAAC,aAAa,CACxC,IAAI,EACJ,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI,CAC1D,CAAC;oBACF,OAAO,CAAC,MAAM,CAAC;wBACb,SAAS,EAAE,sBAAsB;wBACjC,GAAG,EAAE;4BACH,KAAK,EAAE,WAAY,CAAC,GAAG,CAAC,KAAK;4BAC7B,GAAG,EAAE,SAAU,CAAC,GAAG,CAAC,GAAG;yBACxB;qBACF,CAAC,CAAC;iBACJ;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,SAAS,QAAQ,CAAC,IAA0B;IAC1C,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACxB,OAAO,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,IAAI,MAAK,aAAa,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,CAAC;AACrE,CAAC;AAED,iBAAS,IAAI,CAAC"}
|