Skip to content

Commit

Permalink
Add prettier as pre-commit hook, clean up CI
Browse files Browse the repository at this point in the history
  • Loading branch information
vdiez committed Nov 22, 2023
1 parent 732e2ad commit b8bf961
Show file tree
Hide file tree
Showing 38 changed files with 781 additions and 1,403 deletions.
37 changes: 27 additions & 10 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ env:

SONAR_TOKEN: VAULT[development/kv/data/sonarcloud data.token]
ARTIFACTORY_URL: https://repox.jfrog.io/
ARTIFACTORY_DEPLOY_ACCESS_TOKEN : VAULT[development/artifactory/token/${CIRRUS_REPO_OWNER}-${CIRRUS_REPO_NAME}-qa-deployer access_token]
ARTIFACTORY_PROMOTE_ACCESS_TOKEN : VAULT[development/artifactory/token/${CIRRUS_REPO_OWNER}-${CIRRUS_REPO_NAME}-promoter access_token]
ARTIFACTORY_DEPLOY_ACCESS_TOKEN: VAULT[development/artifactory/token/${CIRRUS_REPO_OWNER}-${CIRRUS_REPO_NAME}-qa-deployer access_token]
ARTIFACTORY_PROMOTE_ACCESS_TOKEN: VAULT[development/artifactory/token/${CIRRUS_REPO_OWNER}-${CIRRUS_REPO_NAME}-promoter access_token]
# Use bash (instead of sh on linux or cmd.exe on windows)
CIRRUS_SHELL: bash

Expand All @@ -26,6 +26,29 @@ container_definition: &CONTAINER_DEFINITION

build_task:
<<: *ONLY_SONARSOURCE_QA
eks_container:
<<: *CONTAINER_DEFINITION
docker_arguments:
CIRRUS_AWS_ACCOUNT: ${CIRRUS_AWS_ACCOUNT}
cpu: 3
memory: 8G
env:
SONARSOURCE_QA: true
node_version_script:
- node --version
script:
- if [ -n "${CIRRUS_BASE_BRANCH}" ]; then git fetch origin "${CIRRUS_BASE_BRANCH}"; fi
- jfrog config add repox --url $ARTIFACTORY_URL --access-token $ARTIFACTORY_DEPLOY_ACCESS_TOKEN
- jfrog rt npm-config --repo-resolve npm --repo-deploy sonarsource-npm-public-qa
- jfrog rt npm-ci
- npm run check-format
- npm run build
- ./scripts/test-ci.sh
- ./scripts/analyze_and_publish.sh

qa_task:

Check warning on line 49 in .cirrus.yml

View check run for this annotation

Cirrus CI / Build Parsing Results

.cirrus.yml#L49

task "qa" depends on task "build", but their only_if conditions are different

Check warning on line 49 in .cirrus.yml

View check run for this annotation

Cirrus CI / Build Parsing Results

.cirrus.yml#L49

task "qa" depends on task "build", but their only_if conditions are different

Check warning on line 49 in .cirrus.yml

View check run for this annotation

Cirrus CI / Build Parsing Results

.cirrus.yml#L49

task "qa" depends on task "build", but their only_if conditions are different

Check warning on line 49 in .cirrus.yml

View check run for this annotation

Cirrus CI / Build Parsing Results

.cirrus.yml#L49

task "qa" depends on task "build", but their only_if conditions are different

Check warning on line 49 in .cirrus.yml

View check run for this annotation

Cirrus CI / Build Parsing Results

.cirrus.yml#L49

task "qa" depends on task "build", but their only_if conditions are different

Check warning on line 49 in .cirrus.yml

View check run for this annotation

Cirrus CI / Build Parsing Results

.cirrus.yml#L49

task "qa" depends on task "build", but their only_if conditions are different
depends_on:
- build
eks_container:
matrix:
- docker_arguments:
Expand All @@ -41,7 +64,6 @@ build_task:
cpu: 3
memory: 8G
env:
CIRRUS_CLONE_DEPTH: 10
SONARSOURCE_QA: true
node_version_script:
- node --version
Expand All @@ -50,13 +72,8 @@ build_task:
- jfrog rt npm-config --repo-resolve npm --repo-deploy sonarsource-npm-public-qa
- git submodule update --init --depth 1 -r
- jfrog rt npm-ci
- npm run typecheck
- npm run build
- ./scripts/test-ci.sh
- npm run check-format
- npm run lint
- npm run ruling
- ./scripts/analyze_and_publish.sh

ws_scan_task:

Check warning on line 78 in .cirrus.yml

View check run for this annotation

Cirrus CI / Build Parsing Results

.cirrus.yml#L78

task "ws_scan" depends on task "build", but their only_if conditions are different

Check warning on line 78 in .cirrus.yml

View check run for this annotation

Cirrus CI / Build Parsing Results

.cirrus.yml#L78

task "ws_scan" depends on task "build", but their only_if conditions are different
depends_on:
Expand All @@ -75,7 +92,7 @@ ws_scan_task:
folder: ${CIRRUS_WORKING_DIR}/.m2/repository
whitesource_script:
- ./scripts/run_ws_scan.sh
allow_failures: "true"
allow_failures: 'true'
always:
ws_artifacts:
path: "whitesource/**/*"
path: 'whitesource/**/*'
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run precommit
3 changes: 2 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
.idea/
.vscode/
.github/
.husky

coverage/
docs/
Expand All @@ -20,13 +21,13 @@ tests/
.gitattributes
.gitmodules
.npmignore
.prettierignore
.travis.yml
.eslintrc.js
.editorconfig
sonar-project.properties
test-report.xml
tsconfig.json
tsconfig-src.json
.cirrus/
.cirrus.yml
.jfrog/
Expand Down
6 changes: 6 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.github
.jfrog
coverage
lib
javascript-test-sources
docs
85 changes: 43 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,43 @@ SonarJS rules for ESLint to help developers produce [Clean Code](https://www.son

Rules in this category aim to find places in code that have a high chance of being bugs, i.e. don't work as intended.

* All branches in a conditional structure should not have exactly the same implementation ([`no-all-duplicated-branches`])
* Collection elements should not be replaced unconditionally ([`no-element-overwrite`])
* Empty collections should not be accessed or iterated ([`no-empty-collection`])
* Function calls should not pass extra arguments ([`no-extra-arguments`])
* Related "if/else if" statements should not have the same condition ([`no-identical-conditions`])
* Identical expressions should not be used on both sides of a binary operator ([`no-identical-expressions`])
* Return values from functions without side effects should not be ignored ([`no-ignored-return`]) (*uses-types*)
* Loops with at most one iteration should be refactored ([`no-one-iteration-loop`])
* The output of functions that don't return anything should not be used ([`no-use-of-empty-return-value`])
* Non-existent operators '=+', '=-' and '=!' should not be used ([`non-existent-operator`]) (:wrench: *fixable*)
- All branches in a conditional structure should not have exactly the same implementation ([`no-all-duplicated-branches`])
- Collection elements should not be replaced unconditionally ([`no-element-overwrite`])
- Empty collections should not be accessed or iterated ([`no-empty-collection`])
- Function calls should not pass extra arguments ([`no-extra-arguments`])
- Related "if/else if" statements should not have the same condition ([`no-identical-conditions`])
- Identical expressions should not be used on both sides of a binary operator ([`no-identical-expressions`])
- Return values from functions without side effects should not be ignored ([`no-ignored-return`]) (_uses-types_)
- Loops with at most one iteration should be refactored ([`no-one-iteration-loop`])
- The output of functions that don't return anything should not be used ([`no-use-of-empty-return-value`])
- Non-existent operators '=+', '=-' and '=!' should not be used ([`non-existent-operator`]) (:wrench: _fixable_)

### Code Smell Detection :pig:

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 patterns.

* Cognitive Complexity of functions should not be too high ([`cognitive-complexity`])
* "if ... else if" constructs should end with "else" clauses ([`elseif-without-else`]) (*disabled*)
* "switch" statements should not have too many "case" clauses ([`max-switch-cases`])
* Collapsible "if" statements should be merged ([`no-collapsible-if`])
* Collection sizes and array length comparisons should make sense ([`no-collection-size-mischeck`]) (:wrench: *fixable*, *uses-types*)
* String literals should not be duplicated ([`no-duplicate-string`])
* Two branches in a conditional structure should not have exactly the same implementation ([`no-duplicated-branches`])
* Boolean expressions should not be gratuitous ([`no-gratuitous-expressions`])
* Functions should not have identical implementations ([`no-identical-functions`])
* Boolean checks should not be inverted ([`no-inverted-boolean-check`]) (:wrench: *fixable*, *disabled*)
* "switch" statements should not be nested ([`no-nested-switch`])
* Template literals should not be nested ([`no-nested-template-literals`])
* Boolean literals should not be redundant ([`no-redundant-boolean`])
* Jump statements should not be redundant ([`no-redundant-jump`]) (:wrench: *fixable*)
* Conditionals should start on new lines ([`no-same-line-conditional`]) (:wrench: *fixable*)
* "switch" statements should have at least 3 "case" clauses ([`no-small-switch`])
* Collection and array contents should be used ([`no-unused-collection`])
* "catch" clauses should do more than rethrow ([`no-useless-catch`])
* Local variables should not be declared and then immediately returned or thrown ([`prefer-immediate-return`]) (:wrench: *fixable*)
* Object literal syntax should be used ([`prefer-object-literal`])
* Return of boolean expressions should not be wrapped into an "if-then-else" statement ([`prefer-single-boolean-return`]) (:wrench: *fixable*)
* A "while" loop should be used instead of a "for" loop ([`prefer-while`]) (:wrench: *fixable*)
- Cognitive Complexity of functions should not be too high ([`cognitive-complexity`])
- "if ... else if" constructs should end with "else" clauses ([`elseif-without-else`]) (_disabled_)
- "switch" statements should not have too many "case" clauses ([`max-switch-cases`])
- Collapsible "if" statements should be merged ([`no-collapsible-if`])
- Collection sizes and array length comparisons should make sense ([`no-collection-size-mischeck`]) (:wrench: _fixable_, _uses-types_)
- String literals should not be duplicated ([`no-duplicate-string`])
- Two branches in a conditional structure should not have exactly the same implementation ([`no-duplicated-branches`])
- Boolean expressions should not be gratuitous ([`no-gratuitous-expressions`])
- Functions should not have identical implementations ([`no-identical-functions`])
- Boolean checks should not be inverted ([`no-inverted-boolean-check`]) (:wrench: _fixable_, _disabled_)
- "switch" statements should not be nested ([`no-nested-switch`])
- Template literals should not be nested ([`no-nested-template-literals`])
- Boolean literals should not be redundant ([`no-redundant-boolean`])
- Jump statements should not be redundant ([`no-redundant-jump`]) (:wrench: _fixable_)
- Conditionals should start on new lines ([`no-same-line-conditional`]) (:wrench: _fixable_)
- "switch" statements should have at least 3 "case" clauses ([`no-small-switch`])
- Collection and array contents should be used ([`no-unused-collection`])
- "catch" clauses should do more than rethrow ([`no-useless-catch`])
- Local variables should not be declared and then immediately returned or thrown ([`prefer-immediate-return`]) (:wrench: _fixable_)
- Object literal syntax should be used ([`prefer-object-literal`])
- Return of boolean expressions should not be wrapped into an "if-then-else" statement ([`prefer-single-boolean-return`]) (:wrench: _fixable_)
- A "while" loop should be used instead of a "for" loop ([`prefer-while`]) (:wrench: _fixable_)

[`cognitive-complexity`]: ./docs/rules/cognitive-complexity.md
[`elseif-without-else`]: ./docs/rules/elseif-without-else.md
Expand Down Expand Up @@ -81,36 +81,36 @@ Code Smells, or maintainability issues, are raised for places of code which migh

## Prerequisites

* Node.js (>=14.x).
* ESLint 5.x, 6.x, 7.x or 8.x (peer dependency for the plugin).
- Node.js (>=14.x).
- ESLint 5.x, 6.x, 7.x or 8.x (peer dependency for the plugin).

## Usage

* If you don't have ESLint yet configured for your project, follow [these instructions](https://github.com/eslint/eslint#installation-and-usage).
* Install `eslint-plugin-sonarjs` using `npm` (or `yarn`) for your project or globally:
- If you don't have ESLint yet configured for your project, follow [these instructions](https://github.com/eslint/eslint#installation-and-usage).
- Install `eslint-plugin-sonarjs` using `npm` (or `yarn`) for your project or globally:

```sh
npm install eslint-plugin-sonarjs --save-dev # install for your project
npm install eslint-plugin-sonarjs -g # or install globally
```

* Add `eslint-plugin-sonarjs` to the `plugins` option of your `.eslintrc`:
- Add `eslint-plugin-sonarjs` to the `plugins` option of your `.eslintrc`:

```json
{
"plugins": ["sonarjs"]
}
```

* Add `plugin:sonarjs/recommended` to the `extends` option to enable all recommended rules:
- Add `plugin:sonarjs/recommended` to the `extends` option to enable all recommended rules:

```json
{
"extends": ["plugin:sonarjs/recommended"]
}
```

* or enable only some rules manually:
- or enable only some rules manually:

```javascript
{
Expand All @@ -121,15 +121,16 @@ npm install eslint-plugin-sonarjs -g # or install globally
}
}
```
* 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.

- 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.

## Available Configurations

This plugin provides only a `recommended` configuration. Almost all rules are activated in this profile with a few exceptions (check the `disabled` tag in the rules list). The `recommended` configuration activates rules with `error` severity.
This plugin provides only a `recommended` configuration. Almost all rules are activated in this profile with a few exceptions (check the `disabled` tag in the rules list). The `recommended` configuration activates rules with `error` severity.

## ESLint and Sonar

This plugin exposes to ESLint users a subset of JS/TS rules from Sonar-* products (aka [SonarJS](https://github.com/SonarSource/SonarJS)). We extracted the rules that are not available in ESLint core or other ESLint plugins to be beneficial for the ESLint community.
This plugin exposes to ESLint users a subset of JS/TS rules from Sonar-\* products (aka [SonarJS](https://github.com/SonarSource/SonarJS)). We extracted the rules that are not available in ESLint core or other ESLint plugins to be beneficial for the ESLint community.

If you are a [SonarQube](https://www.sonarqube.org) or [SonarCloud](https://sonarcloud.io) user, to lint your code locally, we suggest using [SonarLint](https://www.sonarlint.org) IDE extension (available for VSCode, JetBrains IDEs and Eclipse). You can connect SonarLint to your SonarQube/SonarCloud project to synchronize rules configuration, issue statuses, etc.

Expand Down
12 changes: 6 additions & 6 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ Report bugs and suggest improvements. If something doesn't work well for you or

## Create New Rule

* Create a new file for the rule implementation in `src/rules`. File name should be lowercased, words must be separated by dashes (`-`).
* Create a test file `<rule name>.test.ts` in `test/rules`.
* Add the rule to `src/index.ts`.
* In folder `docs/rules` create a rule documentation file `<rule name>.md`
* In `README.md` add a reference to this documentation file.
* Run [Ruling](#ruling) test.
- Create a new file for the rule implementation in `src/rules`. File name should be lowercased, words must be separated by dashes (`-`).
- Create a test file `<rule name>.test.ts` in `test/rules`.
- Add the rule to `src/index.ts`.
- In folder `docs/rules` create a rule documentation file `<rule name>.md`
- In `README.md` add a reference to this documentation file.
- Run [Ruling](#ruling) test.

## Testing

Expand Down
6 changes: 3 additions & 3 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
## Releasing npm package

* [Create a Jira release ticket](https://jira.sonarsource.com/projects/REL) like [this one](https://sonarsource.atlassian.net/browse/REL-2313)
* [Publish a new GitHub release](https://github.com/SonarSource/eslint-plugin-sonarjs/releases/new)
* [Bump the package version for the next development iteration](https://github.com/SonarSource/eslint-plugin-sonarjs/pull/418/files)
- [Create a Jira release ticket](https://jira.sonarsource.com/projects/REL) like [this one](https://sonarsource.atlassian.net/browse/REL-2313)
- [Publish a new GitHub release](https://github.com/SonarSource/eslint-plugin-sonarjs/releases/new)
- [Bump the package version for the next development iteration](https://github.com/SonarSource/eslint-plugin-sonarjs/pull/418/files)
2 changes: 1 addition & 1 deletion docs/rules/cognitive-complexity.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Cognitive Complexity is a measure of how hard the control flow of a function is

## See

* [Cognitive Complexity](http://redirect.sonarsource.com/doc/cognitive-complexity.html)
- [Cognitive Complexity](http://redirect.sonarsource.com/doc/cognitive-complexity.html)

## Configuration

Expand Down
3 changes: 2 additions & 1 deletion docs/rules/elseif-without-else.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ if (x == 0) {
doSomethingElse();
}
```

## Compliant Solution

```javascript
Expand All @@ -23,7 +24,7 @@ if (x == 0) {
} else if (x == 1) {
doSomethingElse();
} else {
throw "Unexpected value for x";
throw 'Unexpected value for x';
}
```

Expand Down
20 changes: 14 additions & 6 deletions docs/rules/no-collection-size-mischeck.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
# no-collection-size-mischeck

:wrench: *fixable*
:wrench: _fixable_

The size of a collection and the length of an array are always greater than or equal to zero. So testing that a size or length is greater than or equal to zero doesn't make sense, since the result is always `true`. Similarly testing that it is less than zero will always return `false`. Perhaps the intent was to check the non-emptiness of the collection or array instead.

## Noncompliant Code Example

```javascript
if (someSet.size >= 0) {...} // Noncompliant
if (someSet.size >= 0) { // Noncompliant
//...
}

if (someMap.size < 0) {...} // Noncompliant
if (someMap.size < 0) { // Noncompliant
//...
}

const result = someArray.length >= 0; // Noncompliant
const result = someArray.length >= 0; // Noncompliant
```

## Compliant Solution

```javascript
if (someSet.size > 0) {...}
if (someSet.size > 0) {
//...
}

if (someMap.size == 0) {...}
if (someMap.size == 0) {
//...
}

const result = someArray.length > 0;
```
Expand Down
5 changes: 4 additions & 1 deletion docs/rules/no-duplicate-string.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# no-duplicate-string

Duplicated string literals make the process of refactoring error-prone, since you must be sure to update all occurrences.
On the other hand, constants can be referenced from many places, but only need to be updated in a single place.

## Exceptions
To prevent generating some false-positives, literals having less than 10 characters are excluded as well as literals matching /^\w*$/. String literals inside import/export statements are also ignored. The same goes for statement-like string literals, e.g. `'use strict';`

To prevent generating some false-positives, literals having less than 10 characters are excluded as well as literals matching /^\w\*$/. String literals inside import/export statements are also ignored. The same goes for statement-like string literals, e.g. `'use strict';`

## Configuration

Expand All @@ -23,3 +25,4 @@ Comma-separated list of strings that must be ignored. Default is `"application/j
"no-duplicate-string": "error",
"no-duplicate-string": ["error", { "ignoreStrings": "foo,bar,baz" }]
}
```
3 changes: 1 addition & 2 deletions docs/rules/no-duplicated-branches.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ if (a >= 0 && a < 10) {
doTheThing();
} else if (a >= 10 && a < 20) {
doTheOtherThing();
} else if (a >= 20 && a < 50) {
// Noncompliant; duplicates first condition
} else if (a >= 20 && a < 50) { // Noncompliant; duplicates first condition
doFirstThing();
doTheThing();
} else {
Expand Down
8 changes: 4 additions & 4 deletions docs/rules/no-element-overwrite.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ It is highly suspicious when a value is saved for a key or index and then uncond
## Noncompliant Code Example

```javascript
fruits[1] = "banana";
fruits[1] = "apple"; // Noncompliant - value on index 1 is overwritten
fruits[1] = 'banana';
fruits[1] = 'apple'; // Noncompliant - value on index 1 is overwritten

myMap.set("key", 1);
myMap.set("key", 2); // Noncompliant - value for key "key" is replaced
myMap.set('key', 1);
myMap.set('key', 2); // Noncompliant - value for key "key" is replaced

mySet.add(1);
mySet.add(1); // Noncompliant - element is already in the set
Expand Down
4 changes: 2 additions & 2 deletions docs/rules/no-empty-collection.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ When a collection is empty it makes no sense to access or iterate it. Doing so a
```javascript
let strings = [];

if (strings.includes("foo")) {} // Noncompliant
if (strings.includes('foo')) {} // Noncompliant

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

strings.forEach(str => doSomething(str)); // Noncompliant
```

0 comments on commit b8bf961

Please sign in to comment.