eslint-plugin-sonarjs 0.4.0 → 0.7.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.
Files changed (81) hide show
  1. package/.cirrus/nodejs-10.Dockerfile +29 -0
  2. package/.cirrus/nodejs-12.Dockerfile +28 -0
  3. package/.cirrus/nodejs-14.Dockerfile +28 -0
  4. package/.cirrus/nodejs-15.Dockerfile +28 -0
  5. package/.cirrus.yml +47 -0
  6. package/.eslintignore +1 -0
  7. package/README.md +14 -8
  8. package/lib/index.d.ts +3 -1
  9. package/lib/index.js +11 -6
  10. package/lib/index.js.map +1 -1
  11. package/lib/rules/cognitive-complexity.js +91 -65
  12. package/lib/rules/cognitive-complexity.js.map +1 -1
  13. package/lib/rules/max-switch-cases.js +10 -9
  14. package/lib/rules/max-switch-cases.js.map +1 -1
  15. package/lib/rules/no-all-duplicated-branches.js +21 -18
  16. package/lib/rules/no-all-duplicated-branches.js.map +1 -1
  17. package/lib/rules/no-collapsible-if.js +11 -10
  18. package/lib/rules/no-collapsible-if.js.map +1 -1
  19. package/lib/rules/no-collection-size-mischeck.d.ts +3 -0
  20. package/lib/rules/no-collection-size-mischeck.js +65 -0
  21. package/lib/rules/no-collection-size-mischeck.js.map +1 -0
  22. package/lib/rules/no-duplicate-string.js +23 -20
  23. package/lib/rules/no-duplicate-string.js.map +1 -1
  24. package/lib/rules/no-duplicated-branches.js +42 -37
  25. package/lib/rules/no-duplicated-branches.js.map +1 -1
  26. package/lib/rules/no-element-overwrite.js +34 -35
  27. package/lib/rules/no-element-overwrite.js.map +1 -1
  28. package/lib/rules/no-extra-arguments.js +45 -42
  29. package/lib/rules/no-extra-arguments.js.map +1 -1
  30. package/lib/rules/no-identical-conditions.js +12 -11
  31. package/lib/rules/no-identical-conditions.js.map +1 -1
  32. package/lib/rules/no-identical-expressions.js +12 -13
  33. package/lib/rules/no-identical-expressions.js.map +1 -1
  34. package/lib/rules/no-identical-functions.js +25 -25
  35. package/lib/rules/no-identical-functions.js.map +1 -1
  36. package/lib/rules/no-inverted-boolean-check.js +17 -13
  37. package/lib/rules/no-inverted-boolean-check.js.map +1 -1
  38. package/lib/rules/no-one-iteration-loop.js +24 -22
  39. package/lib/rules/no-one-iteration-loop.js.map +1 -1
  40. package/lib/rules/no-redundant-boolean.js +14 -11
  41. package/lib/rules/no-redundant-boolean.js.map +1 -1
  42. package/lib/rules/no-redundant-jump.d.ts +3 -0
  43. package/lib/rules/no-redundant-jump.js +67 -0
  44. package/lib/rules/no-redundant-jump.js.map +1 -0
  45. package/lib/rules/no-same-line-conditional.d.ts +3 -0
  46. package/lib/rules/no-same-line-conditional.js +72 -0
  47. package/lib/rules/no-same-line-conditional.js.map +1 -0
  48. package/lib/rules/no-small-switch.js +11 -8
  49. package/lib/rules/no-small-switch.js.map +1 -1
  50. package/lib/rules/no-unused-collection.d.ts +3 -0
  51. package/lib/rules/no-unused-collection.js +164 -0
  52. package/lib/rules/no-unused-collection.js.map +1 -0
  53. package/lib/rules/no-use-of-empty-return-value.js +29 -28
  54. package/lib/rules/no-use-of-empty-return-value.js.map +1 -1
  55. package/lib/rules/no-useless-catch.js +14 -9
  56. package/lib/rules/no-useless-catch.js.map +1 -1
  57. package/lib/rules/prefer-immediate-return.js +30 -29
  58. package/lib/rules/prefer-immediate-return.js.map +1 -1
  59. package/lib/rules/prefer-object-literal.js +20 -16
  60. package/lib/rules/prefer-object-literal.js.map +1 -1
  61. package/lib/rules/prefer-single-boolean-return.js +8 -5
  62. package/lib/rules/prefer-single-boolean-return.js.map +1 -1
  63. package/lib/rules/prefer-while.js +18 -14
  64. package/lib/rules/prefer-while.js.map +1 -1
  65. package/lib/utils/collections.d.ts +2 -0
  66. package/lib/utils/collections.js +41 -0
  67. package/lib/utils/collections.js.map +1 -0
  68. package/lib/utils/conditions.js +12 -11
  69. package/lib/utils/conditions.js.map +1 -1
  70. package/lib/utils/equivalence.js +3 -2
  71. package/lib/utils/equivalence.js.map +1 -1
  72. package/lib/utils/locations.d.ts +1 -0
  73. package/lib/utils/locations.js +31 -14
  74. package/lib/utils/locations.js.map +1 -1
  75. package/lib/utils/nodes.d.ts +1 -1
  76. package/lib/utils/nodes.js +3 -2
  77. package/lib/utils/nodes.js.map +1 -1
  78. package/lib/utils/parser-services.d.ts +5 -0
  79. package/lib/utils/parser-services.js +8 -0
  80. package/lib/utils/parser-services.js.map +1 -0
  81. package/package.json +49 -26
@@ -0,0 +1,29 @@
1
+ FROM gcr.io/language-team/base:latest
2
+
3
+ USER root
4
+
5
+ ENV NODE_VERSION v10.23.2
6
+
7
+ RUN wget -U "nodejs" -q -O nodejs.tar.xz https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-x64.tar.xz \
8
+ && tar -xJf "nodejs.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \
9
+ && rm nodejs.tar.xz \
10
+ && ln -s /usr/local/bin/node /usr/local/bin/nodejs
11
+
12
+ ENV YARN_VERSION 1.22.5
13
+
14
+ RUN curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
15
+ && mkdir -p /opt \
16
+ && tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ \
17
+ && ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn \
18
+ && ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg \
19
+ && rm yarn-v$YARN_VERSION.tar.gz
20
+
21
+ RUN curl "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.3.0.2102.zip" -o /tmp/sonar-scanner.zip \
22
+ && unzip -d /opt /tmp/sonar-scanner.zip \
23
+ && mv /opt/sonar-scanner-4.3.0.2102 /opt/sonar-scanner \
24
+ && rm /tmp/sonar-scanner.zip
25
+
26
+ USER sonarsource
27
+
28
+ ENV PATH "/opt/sonar-scanner/bin:${PATH}"
29
+ ENV SONARCLOUD_ANALYSIS true
@@ -0,0 +1,28 @@
1
+ FROM gcr.io/language-team/base:latest
2
+
3
+ USER root
4
+
5
+ ENV NODE_VERSION v12.20.1
6
+
7
+ RUN wget -U "nodejs" -q -O nodejs.tar.xz https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-x64.tar.xz \
8
+ && tar -xJf "nodejs.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \
9
+ && rm nodejs.tar.xz \
10
+ && ln -s /usr/local/bin/node /usr/local/bin/nodejs
11
+
12
+ ENV YARN_VERSION 1.22.5
13
+
14
+ RUN curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
15
+ && mkdir -p /opt \
16
+ && tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ \
17
+ && ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn \
18
+ && ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg \
19
+ && rm yarn-v$YARN_VERSION.tar.gz
20
+
21
+ RUN curl "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.3.0.2102.zip" -o /tmp/sonar-scanner.zip \
22
+ && unzip -d /opt /tmp/sonar-scanner.zip \
23
+ && mv /opt/sonar-scanner-4.3.0.2102 /opt/sonar-scanner \
24
+ && rm /tmp/sonar-scanner.zip
25
+
26
+ USER sonarsource
27
+
28
+ ENV PATH "/opt/sonar-scanner/bin:${PATH}"
@@ -0,0 +1,28 @@
1
+ FROM gcr.io/language-team/base:latest
2
+
3
+ USER root
4
+
5
+ ENV NODE_VERSION v14.15.4
6
+
7
+ RUN wget -U "nodejs" -q -O nodejs.tar.xz https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-x64.tar.xz \
8
+ && tar -xJf "nodejs.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \
9
+ && rm nodejs.tar.xz \
10
+ && ln -s /usr/local/bin/node /usr/local/bin/nodejs
11
+
12
+ ENV YARN_VERSION 1.22.5
13
+
14
+ RUN curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
15
+ && mkdir -p /opt \
16
+ && tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ \
17
+ && ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn \
18
+ && ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg \
19
+ && rm yarn-v$YARN_VERSION.tar.gz
20
+
21
+ RUN curl "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.3.0.2102.zip" -o /tmp/sonar-scanner.zip \
22
+ && unzip -d /opt /tmp/sonar-scanner.zip \
23
+ && mv /opt/sonar-scanner-4.3.0.2102 /opt/sonar-scanner \
24
+ && rm /tmp/sonar-scanner.zip
25
+
26
+ USER sonarsource
27
+
28
+ ENV PATH "/opt/sonar-scanner/bin:${PATH}"
@@ -0,0 +1,28 @@
1
+ FROM gcr.io/language-team/base:latest
2
+
3
+ USER root
4
+
5
+ ENV NODE_VERSION v15.10.0
6
+
7
+ RUN wget -U "nodejs" -q -O nodejs.tar.xz https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-x64.tar.xz \
8
+ && tar -xJf "nodejs.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \
9
+ && rm nodejs.tar.xz \
10
+ && ln -s /usr/local/bin/node /usr/local/bin/nodejs
11
+
12
+ ENV YARN_VERSION 1.22.5
13
+
14
+ RUN curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
15
+ && mkdir -p /opt \
16
+ && tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ \
17
+ && ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn \
18
+ && ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg \
19
+ && rm yarn-v$YARN_VERSION.tar.gz
20
+
21
+ RUN curl "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.3.0.2102.zip" -o /tmp/sonar-scanner.zip \
22
+ && unzip -d /opt /tmp/sonar-scanner.zip \
23
+ && mv /opt/sonar-scanner-4.3.0.2102 /opt/sonar-scanner \
24
+ && rm /tmp/sonar-scanner.zip
25
+
26
+ USER sonarsource
27
+
28
+ ENV PATH "/opt/sonar-scanner/bin:${PATH}"
package/.cirrus.yml ADDED
@@ -0,0 +1,47 @@
1
+ gcp_credentials: ENCRYPTED[!17c59813193e86cc337bce848b358412b90f50bc5fe1b8b39d363cdf14a41ebe76cfba0482e7f81d076994b9f6dbfb4c!]
2
+
3
+ env:
4
+ GITHUB_TOKEN: ENCRYPTED[!f272985ea5b49b3cf9c414b98de6a8e9096be47bfcee52f33311ba3131a2af637c1b956f49585b7757dd84b7c030233a!]
5
+ SONAR_TOKEN: ENCRYPTED[!4e5894b7b32f763db69e70fb56188d3f42539db36374b1f97c425f37a7ecd441c28a9da267c461b9cc8fb53124f14c22!]
6
+ NPM_DEPLOYER_AUTH: ENCRYPTED[!f4021c529fe14ea134a81e2a147782f095a68c3805328c09409e06e229f66e7fbe742e1b3c522a0cdc2187e730de3814!]
7
+ # Use bash (instead of sh on linux or cmd.exe on windows)
8
+ CIRRUS_SHELL: bash
9
+
10
+ only_sonarsource_qa: &ONLY_SONARSOURCE_QA
11
+ only_if: $CIRRUS_USER_COLLABORATOR == 'true' && ($CIRRUS_PR != "" || $CIRRUS_BRANCH == "master" || $CIRRUS_BRANCH =~ "branch-.*" || $CIRRUS_BRANCH =~ "dogfood-on-.*")
12
+
13
+ container_definition: &CONTAINER_DEFINITION
14
+ builder_image_project: language-team
15
+ builder_image_name: docker-builder-lt-v1
16
+ cluster_name: cirrus-ci-lt-cluster
17
+ zone: us-central1-a
18
+ namespace: default
19
+ use_in_memory_disk: true
20
+
21
+ plugin_qa_task:
22
+ <<: *ONLY_SONARSOURCE_QA
23
+ gke_container:
24
+ matrix:
25
+ - dockerfile: .cirrus/nodejs-10.Dockerfile
26
+ - dockerfile: .cirrus/nodejs-12.Dockerfile
27
+ - dockerfile: .cirrus/nodejs-14.Dockerfile
28
+ - dockerfile: .cirrus/nodejs-15.Dockerfile
29
+ <<: *CONTAINER_DEFINITION
30
+ cpu: 3
31
+ memory: 8G
32
+ env:
33
+ CIRRUS_CLONE_DEPTH: 10
34
+ SONARSOURCE_QA: true
35
+ npmrc_file:
36
+ path: ${HOME}/.npmrc
37
+ variable_name: NPM_DEPLOYER_AUTH
38
+ script:
39
+ - init_git_submodules -r
40
+ - yarn
41
+ - yarn typecheck
42
+ - yarn build
43
+ - ./scripts/test-ci.sh
44
+ - yarn prettier --list-different "{src,tests}/**/*.{js,ts}"
45
+ - yarn lint
46
+ - yarn ruling
47
+ - ./scripts/analyze_and_publish.sh
package/.eslintignore ADDED
@@ -0,0 +1 @@
1
+ tests/resources
package/README.md CHANGED
@@ -1,9 +1,7 @@
1
- # eslint-plugin-sonarjs [![npm version](https://badge.fury.io/js/eslint-plugin-sonarjs.svg)](https://badge.fury.io/js/eslint-plugin-sonarjs) [![Build Status](https://travis-ci.org/SonarSource/eslint-plugin-sonarjs.svg?branch=master)](https://travis-ci.org/SonarSource/eslint-plugin-sonarjs) [![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=eslint-plugin-sonarjs&metric=alert_status)](https://sonarcloud.io/dashboard?id=eslint-plugin-sonarjs) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=eslint-plugin-sonarjs&metric=coverage)](https://sonarcloud.io/dashboard?id=eslint-plugin-sonarjs)
1
+ # eslint-plugin-sonarjs [![npm version](https://badge.fury.io/js/eslint-plugin-sonarjs.svg)](https://badge.fury.io/js/eslint-plugin-sonarjs) [![Build Status](https://api.cirrus-ci.com/github/SonarSource/eslint-plugin-sonarjs.svg?branch=master)](https://cirrus-ci.com/github/SonarSource/eslint-plugin-sonarjs) [![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=eslint-plugin-sonarjs&metric=alert_status)](https://sonarcloud.io/dashboard?id=eslint-plugin-sonarjs) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=eslint-plugin-sonarjs&metric=coverage)](https://sonarcloud.io/dashboard?id=eslint-plugin-sonarjs)
2
2
 
3
3
  SonarJS rules for ESLint to detect bugs and suspicious patterns in your code.
4
4
 
5
- _[We also have a plugin for TSLint](https://github.com/SonarSource/SonarTS)_
6
-
7
5
  ## Rules
8
6
 
9
7
  ### Bug Detection :bug:
@@ -25,22 +23,27 @@ Code Smells, or maintainability issues, are raised for places of code which migh
25
23
  * Cognitive Complexity of functions should not be too high ([`cognitive-complexity`])
26
24
  * "switch" statements should not have too many "case" clauses ([`max-switch-cases`])
27
25
  * Collapsible "if" statements should be merged ([`no-collapsible-if`])
26
+ * Collection sizes and array length comparisons should make sense ([`no-collection-size-mischeck`])
28
27
  * String literals should not be duplicated ([`no-duplicate-string`])
29
28
  * Two branches in a conditional structure should not have exactly the same implementation ([`no-duplicated-branches`])
30
29
  * Functions should not have identical implementations ([`no-identical-functions`])
31
- * Boolean checks should not be inverted ([`no-inverted-boolean-check`])
30
+ * Boolean checks should not be inverted ([`no-inverted-boolean-check`]) (:wrench: *fixable*)
32
31
  * Boolean literals should not be redundant ([`no-redundant-boolean`])
32
+ * Jump statements should not be redundant ([`no-redundant-jump`])
33
+ * Conditionals should start on new lines ([`no-same-line-conditional`])
33
34
  * "switch" statements should have at least 3 "case" clauses ([`no-small-switch`])
35
+ * Collection and array contents should be used ([`no-unused-collection`])
34
36
  * "catch" clauses should do more than rethrow ([`no-useless-catch`])
35
37
  * Local variables should not be declared and then immediately returned or thrown ([`prefer-immediate-return`]) (:wrench: *fixable*)
36
38
  * Object literal syntax should be used ([`prefer-object-literal`])
37
39
  * Return of boolean expressions should not be wrapped into an "if-then-else" statement ([`prefer-single-boolean-return`])
38
- * A "while" loop should be used instead of a "for" loop ([`prefer-while`]) (:wrench: *fixable*)
40
+ * A "while" loop should be used instead of a "for" loop ([`prefer-while`]) (:wrench: *fixable*)
39
41
 
40
42
  [`cognitive-complexity`]: ./docs/rules/cognitive-complexity.md
41
43
  [`max-switch-cases`]: ./docs/rules/max-switch-cases.md
42
44
  [`no-all-duplicated-branches`]: ./docs/rules/no-all-duplicated-branches.md
43
45
  [`no-collapsible-if`]: ./docs/rules/no-collapsible-if.md
46
+ [`no-collection-size-mischeck`]: ./docs/rules/no-collection-size-mischeck.md
44
47
  [`no-duplicate-string`]: ./docs/rules/no-duplicate-string.md
45
48
  [`no-duplicated-branches`]: ./docs/rules/no-duplicated-branches.md
46
49
  [`no-element-overwrite`]: ./docs/rules/no-element-overwrite.md
@@ -51,8 +54,11 @@ Code Smells, or maintainability issues, are raised for places of code which migh
51
54
  [`no-inverted-boolean-check`]: ./docs/rules/no-inverted-boolean-check.md
52
55
  [`no-one-iteration-loop`]: ./docs/rules/no-one-iteration-loop.md
53
56
  [`no-redundant-boolean`]: ./docs/rules/no-redundant-boolean.md
57
+ [`no-redundant-jump`]: ./docs/rules/no-redundant-jump.md
58
+ [`no-same-line-conditional`]: ./docs/rules/no-same-line-conditional.md
54
59
  [`no-small-switch`]: ./docs/rules/no-small-switch.md
55
60
  [`no-use-of-empty-return-value`]: ./docs/rules/no-use-of-empty-return-value.md
61
+ [`no-unused-collection`]: ./docs/rules/no-unused-collection.md
56
62
  [`no-useless-catch`]: ./docs/rules/no-useless-catch.md
57
63
  [`prefer-immediate-return`]: ./docs/rules/prefer-immediate-return.md
58
64
  [`prefer-object-literal`]: ./docs/rules/prefer-object-literal.md
@@ -61,7 +67,7 @@ Code Smells, or maintainability issues, are raised for places of code which migh
61
67
 
62
68
  ## Prerequisites
63
69
 
64
- Node.js (>=6.x).
70
+ Node.js (>=10.x).
65
71
 
66
72
  ## Usage
67
73
 
@@ -91,12 +97,12 @@ npm install eslint-plugin-sonarjs -g # or install globally
91
97
 
92
98
  * or enable only some rules manually:
93
99
 
94
- ```json
100
+ ```javascript
95
101
  {
96
102
  "rules": {
97
103
  "sonarjs/cognitive-complexity": "error",
98
104
  "sonarjs/no-identical-expressions": "error"
99
- // etc
105
+ // etc.
100
106
  }
101
107
  }
102
108
  ```
package/lib/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { Linter } from "eslint";
2
2
  declare const sonarjsRuleModules: any;
3
3
  declare const configs: {
4
- recommended: Linter.Config;
4
+ recommended: Linter.Config & {
5
+ plugins: string[];
6
+ };
5
7
  };
6
8
  export { sonarjsRuleModules as rules, configs };
package/lib/index.js CHANGED
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- var sonarjsRules = [
3
+ exports.configs = exports.rules = void 0;
4
+ const sonarjsRules = [
4
5
  ["cognitive-complexity", "error"],
5
6
  ["max-switch-cases", "error"],
6
7
  ["no-all-duplicated-branches", "error"],
7
8
  ["no-collapsible-if", "error"],
9
+ ["no-collection-size-mischeck", "error"],
8
10
  ["no-duplicate-string", "error"],
9
11
  ["no-duplicated-branches", "error"],
10
12
  ["no-element-overwrite", "error"],
@@ -15,7 +17,10 @@ var sonarjsRules = [
15
17
  ["no-inverted-boolean-check", "error"],
16
18
  ["no-one-iteration-loop", "error"],
17
19
  ["no-redundant-boolean", "error"],
20
+ ["no-redundant-jump", "error"],
21
+ ["no-same-line-conditional", "error"],
18
22
  ["no-small-switch", "error"],
23
+ ["no-unused-collection", "error"],
19
24
  ["no-use-of-empty-return-value", "error"],
20
25
  ["no-useless-catch", "error"],
21
26
  ["prefer-immediate-return", "error"],
@@ -23,12 +28,12 @@ var sonarjsRules = [
23
28
  ["prefer-single-boolean-return", "error"],
24
29
  ["prefer-while", "error"],
25
30
  ];
26
- var sonarjsRuleModules = {};
31
+ const sonarjsRuleModules = {};
27
32
  exports.rules = sonarjsRuleModules;
28
- var configs = {
29
- recommended: { rules: {} },
33
+ const configs = {
34
+ recommended: { plugins: ["sonarjs"], rules: {} },
30
35
  };
31
36
  exports.configs = configs;
32
- sonarjsRules.forEach(function (rule) { return (sonarjsRuleModules[rule[0]] = require("./rules/" + rule[0])); });
33
- sonarjsRules.forEach(function (rule) { return (configs.recommended.rules["sonarjs/" + rule[0]] = rule[1]); });
37
+ sonarjsRules.forEach(rule => (sonarjsRuleModules[rule[0]] = require(`./rules/${rule[0]}`)));
38
+ sonarjsRules.forEach(rule => (configs.recommended.rules[`sonarjs/${rule[0]}`] = rule[1]));
34
39
  //# 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,IAAM,YAAY,GAAiC;IACjD,CAAC,sBAAsB,EAAE,OAAO,CAAC;IACjC,CAAC,kBAAkB,EAAE,OAAO,CAAC;IAC7B,CAAC,4BAA4B,EAAE,OAAO,CAAC;IACvC,CAAC,mBAAmB,EAAE,OAAO,CAAC;IAC9B,CAAC,qBAAqB,EAAE,OAAO,CAAC;IAChC,CAAC,wBAAwB,EAAE,OAAO,CAAC;IACnC,CAAC,sBAAsB,EAAE,OAAO,CAAC;IACjC,CAAC,oBAAoB,EAAE,OAAO,CAAC;IAC/B,CAAC,yBAAyB,EAAE,OAAO,CAAC;IACpC,CAAC,wBAAwB,EAAE,OAAO,CAAC;IACnC,CAAC,0BAA0B,EAAE,OAAO,CAAC;IACrC,CAAC,2BAA2B,EAAE,OAAO,CAAC;IACtC,CAAC,uBAAuB,EAAE,OAAO,CAAC;IAClC,CAAC,sBAAsB,EAAE,OAAO,CAAC;IACjC,CAAC,iBAAiB,EAAE,OAAO,CAAC;IAC5B,CAAC,8BAA8B,EAAE,OAAO,CAAC;IACzC,CAAC,kBAAkB,EAAE,OAAO,CAAC;IAC7B,CAAC,yBAAyB,EAAE,OAAO,CAAC;IACpC,CAAC,uBAAuB,EAAE,OAAO,CAAC;IAClC,CAAC,8BAA8B,EAAE,OAAO,CAAC;IACzC,CAAC,cAAc,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,IAAM,kBAAkB,GAAQ,EAAE,CAAC;AASJ,mCAAK;AAPpC,IAAM,OAAO,GAAmC;IAC9C,WAAW,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;CAC3B,CAAC;AAKoC,0BAAO;AAH7C,YAAY,CAAC,OAAO,CAAC,UAAA,IAAI,IAAI,OAAA,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,aAAW,IAAI,CAAC,CAAC,CAAG,CAAC,CAAC,EAA7D,CAA6D,CAAC,CAAC;AAC5F,YAAY,CAAC,OAAO,CAAC,UAAA,IAAI,IAAI,OAAA,CAAC,OAAO,CAAC,WAAW,CAAC,KAAM,CAAC,aAAW,IAAI,CAAC,CAAC,CAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,EAA5D,CAA4D,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAqBA,MAAM,YAAY,GAAiC;IACjD,CAAC,sBAAsB,EAAE,OAAO,CAAC;IACjC,CAAC,kBAAkB,EAAE,OAAO,CAAC;IAC7B,CAAC,4BAA4B,EAAE,OAAO,CAAC;IACvC,CAAC,mBAAmB,EAAE,OAAO,CAAC;IAC9B,CAAC,6BAA6B,EAAE,OAAO,CAAC;IACxC,CAAC,qBAAqB,EAAE,OAAO,CAAC;IAChC,CAAC,wBAAwB,EAAE,OAAO,CAAC;IACnC,CAAC,sBAAsB,EAAE,OAAO,CAAC;IACjC,CAAC,oBAAoB,EAAE,OAAO,CAAC;IAC/B,CAAC,yBAAyB,EAAE,OAAO,CAAC;IACpC,CAAC,wBAAwB,EAAE,OAAO,CAAC;IACnC,CAAC,0BAA0B,EAAE,OAAO,CAAC;IACrC,CAAC,2BAA2B,EAAE,OAAO,CAAC;IACtC,CAAC,uBAAuB,EAAE,OAAO,CAAC;IAClC,CAAC,sBAAsB,EAAE,OAAO,CAAC;IACjC,CAAC,mBAAmB,EAAE,OAAO,CAAC;IAC9B,CAAC,0BAA0B,EAAE,OAAO,CAAC;IACrC,CAAC,iBAAiB,EAAE,OAAO,CAAC;IAC5B,CAAC,sBAAsB,EAAE,OAAO,CAAC;IACjC,CAAC,8BAA8B,EAAE,OAAO,CAAC;IACzC,CAAC,kBAAkB,EAAE,OAAO,CAAC;IAC7B,CAAC,yBAAyB,EAAE,OAAO,CAAC;IACpC,CAAC,uBAAuB,EAAE,OAAO,CAAC;IAClC,CAAC,8BAA8B,EAAE,OAAO,CAAC;IACzC,CAAC,cAAc,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,MAAM,kBAAkB,GAAQ,EAAE,CAAC;AASJ,mCAAK;AAPpC,MAAM,OAAO,GAA2D;IACtE,WAAW,EAAE,EAAE,OAAO,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;CACjD,CAAC;AAKoC,0BAAO;AAH7C,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5F,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,KAAM,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC"}
@@ -19,93 +19,110 @@
19
19
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
20
  */
21
21
  // https://jira.sonarsource.com/browse/RSPEC-3776
22
- var nodes_1 = require("../utils/nodes");
23
- var locations_1 = require("../utils/locations");
24
- var DEFAULT_THRESHOLD = 15;
25
- var rule = {
22
+ const nodes_1 = require("../utils/nodes");
23
+ const locations_1 = require("../utils/locations");
24
+ const DEFAULT_THRESHOLD = 15;
25
+ const rule = {
26
26
  meta: {
27
+ type: "suggestion",
27
28
  schema: [
28
29
  { type: "integer", minimum: 0 },
29
30
  {
30
31
  // internal parameter
31
- enum: ["sonar-runtime"],
32
+ enum: ["sonar-runtime", "metric"],
32
33
  },
33
34
  ],
34
35
  },
35
- create: function (context) {
36
- var threshold = context.options[0] !== undefined ? context.options[0] : DEFAULT_THRESHOLD;
36
+ create(context) {
37
+ const threshold = getThreshold();
38
+ const isFileComplexity = context.options.includes("metric");
39
+ /** Complexity of the file */
40
+ let fileComplexity = 0;
37
41
  /** Complexity of the current function if it is *not* considered nested to the first level function */
38
- var complexityIfNotNested = [];
42
+ let complexityIfNotNested = [];
39
43
  /** Complexity of the current function if it is considered nested to the first level function */
40
- var complexityIfNested = [];
44
+ let complexityIfNested = [];
41
45
  /** Current nesting level (number of enclosing control flow statements and functions) */
42
- var nesting = 0;
46
+ let nesting = 0;
43
47
  /** Indicator if the current top level function has a structural (generated by control flow statements) complexity */
44
- var topLevelHasStructuralComplexity = false;
48
+ let topLevelHasStructuralComplexity = false;
45
49
  /** Own (not including nested functions) complexity of the current top function */
46
- var topLevelOwnComplexity = [];
50
+ let topLevelOwnComplexity = [];
47
51
  /** Nodes that should increase nesting level */
48
- var nestingNodes = new Set();
52
+ const nestingNodes = new Set();
49
53
  /** Set of already considered (with already computed complexity) logical expressions */
50
- var consideredLogicalExpressions = new Set();
54
+ const consideredLogicalExpressions = new Set();
51
55
  /** Stack of enclosing functions */
52
- var enclosingFunctions = [];
53
- var secondLevelFunctions = [];
56
+ const enclosingFunctions = [];
57
+ let secondLevelFunctions = [];
54
58
  return {
55
- ":function": function (node) {
59
+ ":function": (node) => {
56
60
  onEnterFunction(node);
57
61
  },
58
- ":function:exit": function (node) {
62
+ ":function:exit"(node) {
59
63
  onLeaveFunction(node);
60
64
  },
61
- "*": function (node) {
65
+ "*"(node) {
62
66
  if (nestingNodes.has(node)) {
63
67
  nesting++;
64
68
  }
65
69
  },
66
- "*:exit": function (node) {
70
+ "*:exit"(node) {
67
71
  if (nestingNodes.has(node)) {
68
72
  nesting--;
69
73
  nestingNodes.delete(node);
70
74
  }
71
75
  },
72
- IfStatement: function (node) {
76
+ Program() {
77
+ fileComplexity = 0;
78
+ },
79
+ "Program:exit"(node) {
80
+ if (isFileComplexity) {
81
+ // as issues are the only communication channel of a rule
82
+ // we pass data as serialized json as an issue message
83
+ context.report({ node, message: fileComplexity.toString() });
84
+ }
85
+ },
86
+ IfStatement(node) {
73
87
  visitIfStatement(node);
74
88
  },
75
- ForStatement: function (node) {
89
+ ForStatement(node) {
76
90
  visitLoop(node);
77
91
  },
78
- ForInStatement: function (node) {
92
+ ForInStatement(node) {
79
93
  visitLoop(node);
80
94
  },
81
- ForOfStatement: function (node) {
95
+ ForOfStatement(node) {
82
96
  visitLoop(node);
83
97
  },
84
- DoWhileStatement: function (node) {
98
+ DoWhileStatement(node) {
85
99
  visitLoop(node);
86
100
  },
87
- WhileStatement: function (node) {
101
+ WhileStatement(node) {
88
102
  visitLoop(node);
89
103
  },
90
- SwitchStatement: function (node) {
104
+ SwitchStatement(node) {
91
105
  visitSwitchStatement(node);
92
106
  },
93
- ContinueStatement: function (node) {
107
+ ContinueStatement(node) {
94
108
  visitContinueOrBreakStatement(node);
95
109
  },
96
- BreakStatement: function (node) {
110
+ BreakStatement(node) {
97
111
  visitContinueOrBreakStatement(node);
98
112
  },
99
- CatchClause: function (node) {
113
+ CatchClause(node) {
100
114
  visitCatchClause(node);
101
115
  },
102
- LogicalExpression: function (node) {
116
+ LogicalExpression(node) {
103
117
  visitLogicalExpression(node);
104
118
  },
105
- ConditionalExpression: function (node) {
119
+ ConditionalExpression(node) {
106
120
  visitConditionalExpression(node);
107
121
  },
108
122
  };
123
+ function getThreshold() {
124
+ return context.options[0] !== undefined ? context.options[0] : DEFAULT_THRESHOLD;
125
+ }
109
126
  function onEnterFunction(node) {
110
127
  if (enclosingFunctions.length === 0) {
111
128
  // top level function
@@ -129,15 +146,15 @@ var rule = {
129
146
  if (enclosingFunctions.length === 0) {
130
147
  // top level function
131
148
  if (topLevelHasStructuralComplexity) {
132
- var totalComplexity_1 = topLevelOwnComplexity;
133
- secondLevelFunctions.forEach(function (secondLevelFunction) {
134
- totalComplexity_1 = totalComplexity_1.concat(secondLevelFunction.complexityIfNested);
149
+ let totalComplexity = topLevelOwnComplexity;
150
+ secondLevelFunctions.forEach(secondLevelFunction => {
151
+ totalComplexity = totalComplexity.concat(secondLevelFunction.complexityIfNested);
135
152
  });
136
- checkFunction(totalComplexity_1, locations_1.getMainFunctionTokenLocation(node, nodes_1.getParent(context), context));
153
+ checkFunction(totalComplexity, locations_1.getMainFunctionTokenLocation(node, nodes_1.getParent(context), context));
137
154
  }
138
155
  else {
139
156
  checkFunction(topLevelOwnComplexity, locations_1.getMainFunctionTokenLocation(node, nodes_1.getParent(context), context));
140
- secondLevelFunctions.forEach(function (secondLevelFunction) {
157
+ secondLevelFunctions.forEach(secondLevelFunction => {
141
158
  checkFunction(secondLevelFunction.complexityIfThisSecondaryIsTopLevel, locations_1.getMainFunctionTokenLocation(secondLevelFunction.node, secondLevelFunction.parent, context));
142
159
  });
143
160
  }
@@ -145,9 +162,9 @@ var rule = {
145
162
  else if (enclosingFunctions.length === 1) {
146
163
  // second level function
147
164
  secondLevelFunctions.push({
148
- node: node,
165
+ node,
149
166
  parent: nodes_1.getParent(context),
150
- complexityIfNested: complexityIfNested,
167
+ complexityIfNested,
151
168
  complexityIfThisSecondaryIsTopLevel: complexityIfNotNested,
152
169
  loc: locations_1.getMainFunctionTokenLocation(node, nodes_1.getParent(context), context),
153
170
  });
@@ -158,8 +175,8 @@ var rule = {
158
175
  }
159
176
  }
160
177
  function visitIfStatement(ifStatement) {
161
- var parent = nodes_1.getParent(context);
162
- var ifLoc = locations_1.getFirstToken(ifStatement, context).loc;
178
+ const parent = nodes_1.getParent(context);
179
+ const { loc: ifLoc } = locations_1.getFirstToken(ifStatement, context);
163
180
  // if the current `if` statement is `else if`, do not count it in structural complexity
164
181
  if (nodes_1.isIfStatement(parent) && parent.alternate === ifStatement) {
165
182
  addComplexity(ifLoc);
@@ -174,7 +191,7 @@ var rule = {
174
191
  // - add +1 complexity
175
192
  if (ifStatement.alternate && !nodes_1.isIfStatement(ifStatement.alternate)) {
176
193
  nestingNodes.add(ifStatement.alternate);
177
- var elseTokenLoc = locations_1.getFirstTokenAfter(ifStatement.consequent, context).loc;
194
+ const elseTokenLoc = locations_1.getFirstTokenAfter(ifStatement.consequent, context).loc;
178
195
  addComplexity(elseTokenLoc);
179
196
  }
180
197
  }
@@ -184,8 +201,7 @@ var rule = {
184
201
  }
185
202
  function visitSwitchStatement(switchStatement) {
186
203
  addStructuralComplexity(locations_1.getFirstToken(switchStatement, context).loc);
187
- for (var _i = 0, _a = switchStatement.cases; _i < _a.length; _i++) {
188
- var switchCase = _a[_i];
204
+ for (const switchCase of switchStatement.cases) {
189
205
  nestingNodes.add(switchCase);
190
206
  }
191
207
  }
@@ -199,19 +215,18 @@ var rule = {
199
215
  nestingNodes.add(catchClause.body);
200
216
  }
201
217
  function visitConditionalExpression(conditionalExpression) {
202
- var questionTokenLoc = locations_1.getFirstTokenAfter(conditionalExpression.test, context).loc;
218
+ const questionTokenLoc = locations_1.getFirstTokenAfter(conditionalExpression.test, context).loc;
203
219
  addStructuralComplexity(questionTokenLoc);
204
220
  nestingNodes.add(conditionalExpression.consequent);
205
221
  nestingNodes.add(conditionalExpression.alternate);
206
222
  }
207
223
  function visitLogicalExpression(logicalExpression) {
208
224
  if (!consideredLogicalExpressions.has(logicalExpression)) {
209
- var flattenedLogicalExpressions = flattenLogicalExpression(logicalExpression);
210
- var previous = void 0;
211
- for (var _i = 0, flattenedLogicalExpressions_1 = flattenedLogicalExpressions; _i < flattenedLogicalExpressions_1.length; _i++) {
212
- var current = flattenedLogicalExpressions_1[_i];
225
+ const flattenedLogicalExpressions = flattenLogicalExpression(logicalExpression);
226
+ let previous;
227
+ for (const current of flattenedLogicalExpressions) {
213
228
  if (!previous || previous.operator !== current.operator) {
214
- var operatorTokenLoc = locations_1.getFirstTokenAfter(logicalExpression.left, context).loc;
229
+ const operatorTokenLoc = locations_1.getFirstTokenAfter(logicalExpression.left, context).loc;
215
230
  addComplexity(operatorTokenLoc);
216
231
  }
217
232
  previous = current;
@@ -221,27 +236,35 @@ var rule = {
221
236
  function flattenLogicalExpression(node) {
222
237
  if (nodes_1.isLogicalExpression(node)) {
223
238
  consideredLogicalExpressions.add(node);
224
- return flattenLogicalExpression(node.left).concat([node], flattenLogicalExpression(node.right));
239
+ return [...flattenLogicalExpression(node.left), node, ...flattenLogicalExpression(node.right)];
225
240
  }
226
241
  return [];
227
242
  }
228
243
  function addStructuralComplexity(location) {
229
- var added = nesting + 1;
230
- var complexityPoint = { complexity: added, location: location };
231
- if (enclosingFunctions.length === 1) {
244
+ const added = nesting + 1;
245
+ const complexityPoint = { complexity: added, location };
246
+ if (enclosingFunctions.length === 0) {
247
+ // top level scope
248
+ fileComplexity += added;
249
+ }
250
+ else if (enclosingFunctions.length === 1) {
232
251
  // top level function
233
252
  topLevelHasStructuralComplexity = true;
234
253
  topLevelOwnComplexity.push(complexityPoint);
235
254
  }
236
255
  else {
237
256
  // second+ level function
238
- complexityIfNested.push({ complexity: added + 1, location: location });
257
+ complexityIfNested.push({ complexity: added + 1, location });
239
258
  complexityIfNotNested.push(complexityPoint);
240
259
  }
241
260
  }
242
261
  function addComplexity(location) {
243
- var complexityPoint = { complexity: 1, location: location };
244
- if (enclosingFunctions.length === 1) {
262
+ const complexityPoint = { complexity: 1, location };
263
+ if (enclosingFunctions.length === 0) {
264
+ // top level scope
265
+ fileComplexity += 1;
266
+ }
267
+ else if (enclosingFunctions.length === 1) {
245
268
  // top level function
246
269
  topLevelOwnComplexity.push(complexityPoint);
247
270
  }
@@ -251,18 +274,21 @@ var rule = {
251
274
  complexityIfNotNested.push(complexityPoint);
252
275
  }
253
276
  }
254
- function checkFunction(complexity, loc) {
255
- if (complexity === void 0) { complexity = []; }
256
- var complexityAmount = complexity.reduce(function (acc, cur) { return acc + cur.complexity; }, 0);
277
+ function checkFunction(complexity = [], loc) {
278
+ const complexityAmount = complexity.reduce((acc, cur) => acc + cur.complexity, 0);
279
+ fileComplexity += complexityAmount;
280
+ if (isFileComplexity) {
281
+ return;
282
+ }
257
283
  if (complexityAmount > threshold) {
258
- var secondaryLocations = complexity.map(function (complexityPoint) {
259
- var complexity = complexityPoint.complexity, location = complexityPoint.location;
260
- var message = complexity === 1 ? "+1" : "+" + complexity + " (incl. " + (complexity - 1) + " for nesting)";
284
+ const secondaryLocations = complexity.map(complexityPoint => {
285
+ const { complexity, location } = complexityPoint;
286
+ const message = complexity === 1 ? "+1" : `+${complexity} (incl. ${complexity - 1} for nesting)`;
261
287
  return locations_1.issueLocation(location, undefined, message);
262
288
  });
263
289
  locations_1.report(context, {
264
- message: "Refactor this function to reduce its Cognitive Complexity from " + complexityAmount + " to the " + threshold + " allowed.",
265
- loc: loc,
290
+ message: `Refactor this function to reduce its Cognitive Complexity from ${complexityAmount} to the ${threshold} allowed.`,
291
+ loc,
266
292
  }, secondaryLocations, complexityAmount - threshold);
267
293
  }
268
294
  }