From 827c88b89c787965dcc4e402f4e1e22be243cdca Mon Sep 17 00:00:00 2001 From: dbale-altoros Date: Mon, 10 Jul 2023 17:59:07 -0300 Subject: [PATCH 1/4] add: info on reason-string maxLength chars --- lib/rules/best-practises/reason-string.js | 11 ++++++++--- test/rules/best-practises/reason-string.js | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/lib/rules/best-practises/reason-string.js b/lib/rules/best-practises/reason-string.js index f535b909..33b44a2f 100644 --- a/lib/rules/best-practises/reason-string.js +++ b/lib/rules/best-practises/reason-string.js @@ -82,7 +82,12 @@ class ReasonStringChecker extends BaseChecker { // If has reason message and is too long, throw an error const reason = _.last(functionParameters).value if (reason.length > this.maxCharactersLong) { - this._errorMessageIsTooLong(node, functionName) + const infoMessage = reason.length + .toString() + .concat(' counted / ') + .concat(this.maxCharactersLong.toString()) + .concat(' allowed') + this._errorMessageIsTooLong(node, functionName, infoMessage) } } } @@ -103,8 +108,8 @@ class ReasonStringChecker extends BaseChecker { this.error(node, `Provide an error message for ${key}`) } - _errorMessageIsTooLong(node, key) { - this.error(node, `Error message for ${key} is too long`) + _errorMessageIsTooLong(node, key, infoMessage) { + this.error(node, `Error message for ${key} is too long: ${infoMessage}`) } } diff --git a/test/rules/best-practises/reason-string.js b/test/rules/best-practises/reason-string.js index c7f0cfd7..30546d7b 100644 --- a/test/rules/best-practises/reason-string.js +++ b/test/rules/best-practises/reason-string.js @@ -101,4 +101,25 @@ describe('Linter - reason-string', () => { assertNoWarnings(report) assertNoErrors(report) }) + + it('should raise reason string maxLength error with added data', () => { + const qtyChars = 'Roles: account already has role'.length + const maxLength = 5 + + const code = funcWith(`require(!has(role, account), "Roles: account already has role"); + role.bearer[account] = true;role.bearer[account] = true; + `) + + const report = linter.processStr(code, { + rules: { 'reason-string': ['warn', { maxLength: 5 }] }, + }) + + assert.ok(report.warningCount > 0) + assertWarnsCount(report, 1) + + assert.equal( + report.reports[0].message, + `Error message for require is too long: ${qtyChars} counted / ${maxLength} allowed` + ) + }) }) From 9d20960393350756becc84229f4b49c21734e5b9 Mon Sep 17 00:00:00 2001 From: dbale-altoros Date: Tue, 11 Jul 2023 12:34:40 -0300 Subject: [PATCH 2/4] add: list-rules command --- README.md | 1 + solhint.js | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/README.md b/README.md index 507c31e8..6d8e70e3 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ Options: Commands: stdin [options] linting of source code data provided to STDIN + list-rules display covered rules of current .solhint.json ``` ### Note The `--fix` option currently works only on "avoid-throw" and "avoid-sha3" rules diff --git a/solhint.js b/solhint.js index 225aa94c..30c150e5 100644 --- a/solhint.js +++ b/solhint.js @@ -40,6 +40,11 @@ function init() { .description('create configuration file for solhint') .action(writeSampleConfigFile) + program + .command('list-rules', null, { noHelp: false }) + .description('display covered rules of current .solhint.json') + .action(listRules) + if (process.argv.length <= 2) { program.help() } @@ -63,6 +68,7 @@ function execMainAction() { const reportLists = program.args.filter(_.isString).map(processPath) const reports = _.flatten(reportLists) + const warningsCount = reports.reduce((acc, i) => acc + i.warningCount, 0) const warningsNumberExceeded = program.opts().maxWarnings >= 0 && warningsCount > program.opts().maxWarnings @@ -207,6 +213,35 @@ function getFormatter(formatter) { } } +function listRules() { + const configPath = '.solhint.json' + if (!fs.existsSync(configPath)) { + console.log('Error!! Configuration does not exists') + process.exit(0) + } else { + const config = readConfig() + console.log('\nConfiguration File: \n', config) + + const reportLists = linter.processPath(configPath, readConfig()) + const rulesObject = reportLists[0].config + + console.log('\nRules: \n') + const orderedRules = Object.keys(rulesObject) + .sort() + .reduce((obj, key) => { + obj[key] = rulesObject[key] + return obj + }, {}) + + // eslint-disable-next-line func-names + Object.keys(orderedRules).forEach(function (key) { + console.log('- ', key, ': ', orderedRules[key]) + }) + } + + process.exit(0) +} + function exitWithCode(reports) { const errorsCount = reports.reduce((acc, i) => acc + i.errorCount, 0) From ff2695dbe9d586136f0e829e148592f61524fa16 Mon Sep 17 00:00:00 2001 From: dbale-altoros Date: Fri, 14 Jul 2023 13:31:50 -0300 Subject: [PATCH 3/4] add to stdin formatter support --- solhint.js | 87 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 29 deletions(-) diff --git a/solhint.js b/solhint.js index 30c150e5..f3e09d15 100644 --- a/solhint.js +++ b/solhint.js @@ -30,9 +30,11 @@ function init() { .action(execMainAction) program - .command('stdin') - .description('linting of source code data provided to STDIN') + .command('stdin', null, { noHelp: false }) .option('--filename [file_name]', 'name of file received using STDIN') + .description( + 'linting of source code data provided to STDIN\nEx: echo "contract Foo { function f1()external view returns(uint256) {} }" | solhint stdin\nEx: solhint stdin --filename "./pathToFilename" -f table' + ) .action(processStdin) program @@ -69,10 +71,6 @@ function execMainAction() { const reportLists = program.args.filter(_.isString).map(processPath) const reports = _.flatten(reportLists) - const warningsCount = reports.reduce((acc, i) => acc + i.warningCount, 0) - const warningsNumberExceeded = - program.opts().maxWarnings >= 0 && warningsCount > program.opts().maxWarnings - if (program.opts().fix) { for (const report of reports) { const inputSrc = fs.readFileSync(report.filePath).toString() @@ -98,37 +96,31 @@ function execMainAction() { }) } - if (printReports(reports, formatterFn)) { - if ( - program.opts().maxWarnings && - reports && - reports.length > 0 && - !reports[0].errorCount && - warningsNumberExceeded - ) { - console.log( - 'Solhint found more warnings than the maximum specified (maximum: %s, found: %s)', - program.opts().maxWarnings, - warningsCount - ) - process.exit(1) - } - } + printReports(reports, formatterFn) exitWithCode(reports) } function processStdin(options) { - const STDIN_FILE = 0 + const STDIN_FILE = options.filename || 0 const stdinBuffer = fs.readFileSync(STDIN_FILE) - const report = processStr(stdinBuffer.toString()) report.file = options.filename || 'stdin' - const formatterFn = getFormatter() - printReports([report], formatterFn) + let formatterFn + try { + // to check if is a valid formatter before execute linter + formatterFn = getFormatter(program.opts().formatter) + } catch (ex) { + console.error(ex.message) + process.exit(1) + } + + const reports = [report] + + printReports(reports, formatterFn) - exitWithCode([report]) + exitWithCode(reports) } function writeSampleConfigFile() { @@ -171,7 +163,6 @@ const readIgnore = _.memoize(() => { const readConfig = _.memoize(() => { let config = {} - try { config = loadConfig(program.opts().config) } catch (e) { @@ -196,8 +187,41 @@ function processPath(path) { return linter.processPath(path, readConfig()) } +function areWarningsExceeded(reports) { + const warningsCount = reports.reduce((acc, i) => acc + i.warningCount, 0) + const warningsNumberExceeded = + program.opts().maxWarnings >= 0 && warningsCount > program.opts().maxWarnings + + return { warningsNumberExceeded, warningsCount } +} + function printReports(reports, formatter) { + const warnings = areWarningsExceeded(reports) + console.log(formatter(reports)) + + if ( + program.opts().maxWarnings && + reports && + reports.length > 0 && + warnings.warningsNumberExceeded + ) { + if (!reports[0].errorCount) { + console.log( + 'Solhint found more warnings than the maximum specified (maximum: %s, found: %s)', + program.opts().maxWarnings, + warnings.warningsCount + ) + } else { + console.log( + 'Error/s found on rules! [max-warnings] rule ignored. Fixing errors enables max-warnings', + program.opts().maxWarnings, + warnings.warningsCount + ) + } + process.exit(1) + } + return reports } @@ -214,6 +238,11 @@ function getFormatter(formatter) { } function listRules() { + if (process.argv.length !== 3) { + console.log('Error!! no additional parameters after list-rules command') + process.exit(0) + } + const configPath = '.solhint.json' if (!fs.existsSync(configPath)) { console.log('Error!! Configuration does not exists') @@ -222,7 +251,7 @@ function listRules() { const config = readConfig() console.log('\nConfiguration File: \n', config) - const reportLists = linter.processPath(configPath, readConfig()) + const reportLists = linter.processPath(configPath, config) const rulesObject = reportLists[0].config console.log('\nRules: \n') From 5daedc9611e3622a9b6afbbff2619a05a0b16e5c Mon Sep 17 00:00:00 2001 From: dbale-altoros Date: Wed, 19 Jul 2023 10:42:26 -0300 Subject: [PATCH 4/4] add e2e tests to --max-warnings --- .github/workflows/E2E.yml | 31 +++- .github/workflows/TESTS.yml | 2 +- e2e/05-max-warnings/.solhint.json | 3 + e2e/05-max-warnings/contracts/Foo.sol | 11 ++ e2e/05-max-warnings/contracts/Foo2.sol | 15 ++ e2e/test.js | 72 ++++++--- package-lock.json | 216 ++++++++++++++++++++++--- package.json | 4 +- solhint.js | 35 ++-- 9 files changed, 313 insertions(+), 76 deletions(-) create mode 100644 e2e/05-max-warnings/.solhint.json create mode 100644 e2e/05-max-warnings/contracts/Foo.sol create mode 100644 e2e/05-max-warnings/contracts/Foo2.sol diff --git a/.github/workflows/E2E.yml b/.github/workflows/E2E.yml index 0a8e3118..60d1e063 100644 --- a/.github/workflows/E2E.yml +++ b/.github/workflows/E2E.yml @@ -14,7 +14,7 @@ jobs: name: Test on Linux with Node ${{ matrix.node }} strategy: matrix: - node: [14, 16, 18] + node: [16, 18, 20] steps: - uses: actions/checkout@v3 @@ -36,15 +36,21 @@ jobs: - name: Global Installation run: npm i -g solhint*tgz + + - name: Check solhint version + run: solhint --version - name: Run E2E Tests run: cd e2e && npm install && npm test e2e_windows: runs-on: windows-latest - name: Run linter and E2E Tests on Windows + name: Test on Windows steps: + - name: Enable Debugging + run: | + echo "::debug::Debugging enabled" - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: @@ -53,8 +59,23 @@ jobs: - name: Install dependencies run: npm install --include=dev - - name: Install solhint - run: npm i -g solhint + - name: Run linter + run: npm run lint + + - name: Generate Docs + run: npm run docs + + - name: Pack + run: npm pack + + - name: Global Installation + run: npm i -g @(Get-ChildItem -Filter *.tgz) + + - name: Check solhint version + run: solhint --version + + - name: List directory contents + run: dir - name: Run linter run: npm run lint @@ -64,7 +85,7 @@ jobs: e2e_macos: runs-on: macos-latest - name: Run linter and E2E Tests on MacOS + name: Test on MacOS steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/TESTS.yml b/.github/workflows/TESTS.yml index 82b44da7..c04448ec 100644 --- a/.github/workflows/TESTS.yml +++ b/.github/workflows/TESTS.yml @@ -16,7 +16,7 @@ jobs: name: Run linter and tests on Linux strategy: matrix: - node-version: [14, 16, 18] + node-version: [16, 18, 20] steps: - uses: actions/checkout@v3 diff --git a/e2e/05-max-warnings/.solhint.json b/e2e/05-max-warnings/.solhint.json new file mode 100644 index 00000000..3b8ee84a --- /dev/null +++ b/e2e/05-max-warnings/.solhint.json @@ -0,0 +1,3 @@ +{ + "extends": "solhint:all" +} diff --git a/e2e/05-max-warnings/contracts/Foo.sol b/e2e/05-max-warnings/contracts/Foo.sol new file mode 100644 index 00000000..659755d7 --- /dev/null +++ b/e2e/05-max-warnings/contracts/Foo.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.5.8; + +contract Foo { + uint256 public constant test1 = 1; + uint256 TEST2; + + constructor() { + + } +} diff --git a/e2e/05-max-warnings/contracts/Foo2.sol b/e2e/05-max-warnings/contracts/Foo2.sol new file mode 100644 index 00000000..e29d2dc2 --- /dev/null +++ b/e2e/05-max-warnings/contracts/Foo2.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0; + +contract Foo { + uint256 public constant test1 = 1; + uint256 TEST2; + + constructor() {} + + function TEST() {} + + modifier ZAR_tok() {} + + uint256 SOSO; +} diff --git a/e2e/test.js b/e2e/test.js index b4b93998..5a38dd76 100644 --- a/e2e/test.js +++ b/e2e/test.js @@ -1,7 +1,3 @@ -/* eslint-disable func-names */ -/* eslint-disable prefer-arrow-callback */ -/* eslint-disable no-unused-expressions */ - const { expect } = require('chai') const cp = require('child_process') const fs = require('fs-extra') @@ -11,7 +7,7 @@ const path = require('path') const shell = require('shelljs') function useFixture(dir) { - beforeEach(`switch to ${dir}`, function() { + beforeEach(`switch to ${dir}`, function () { const fixturePath = path.join(__dirname, dir) const tmpDirContainer = os.tmpdir() @@ -26,17 +22,17 @@ function useFixture(dir) { }) } -describe('e2e', function() { - describe('no config', function() { +describe('e2e', function () { + describe('no config', function () { useFixture('01-no-config') - it('should fail', function() { + it('should fail', function () { const { code } = shell.exec('solhint Foo.sol') expect(code).to.equal(1) }) - it('should create an initial config with --init', function() { + it('should create an initial config with --init', function () { const { code } = shell.exec('solhint --init') expect(code).to.equal(0) @@ -46,55 +42,51 @@ describe('e2e', function() { expect(fs.existsSync(solhintConfigPath)).to.be.true }) - it('should print usage if called without arguments', function() { + it('should print usage if called without arguments', function () { const { code, stdout } = shell.exec('solhint') expect(code).to.equal(0) - expect(stdout).to.include('Usage: solhint [options]') expect(stdout).to.include('Linter for Solidity programming language') expect(stdout).to.include('linting of source code data provided to STDIN') }) }) - describe('empty-config', function() { + describe('empty-config', function () { useFixture('02-empty-solhint-json') - it('should print nothing', function() { + it('should print nothing', function () { const { code, stdout } = shell.exec('solhint Foo.sol') expect(code).to.equal(0) - expect(stdout.trim()).to.equal('') }) - it('should show warning when using --init', function() { + it('should show warning when using --init', function () { const { code, stdout } = shell.exec('solhint --init') expect(code).to.equal(0) - expect(stdout.trim()).to.equal('Configuration file already exists') }) }) - describe('no-empty-blocks', function() { + describe('no-empty-blocks', function () { useFixture('03-no-empty-blocks') - it('should exit with 1', function() { + it('should exit with 1', function () { const { code, stdout } = shell.exec('solhint Foo.sol') expect(code).to.equal(1) - expect(stdout.trim()).to.contain('Code contains empty blocks') }) - it('should work with stdin', async function() { + it('should work with stdin', async function () { const child = cp.exec('solhint stdin') const stdoutPromise = getStream(child.stdout) - const codePromise = new Promise(resolve => { - child.on('close', code => { + const codePromise = new Promise((resolve) => { + child.on('close', (code) => { resolve(code) }) }) @@ -112,13 +104,45 @@ describe('e2e', function() { }) }) - describe('.sol on path', function() { + describe('.sol on path', function () { useFixture('04-dotSol-on-path') - it('should handle directory names that end with .sol', function() { + it('should handle directory names that end with .sol', function () { const { code } = shell.exec('solhint contracts/**/*.sol') + expect(code).to.equal(0) + }) + }) + + describe('--max-warnings parameter tests', function () { + // Foo contract has 6 warnings + // Foo2 contract has 1 error and 14 warnings + useFixture('05-max-warnings') + const warningExceededMsg = 'Solhint found more warnings than the maximum specified' + const errorFound = + 'Error/s found on rules! [max-warnings] param is ignored. Fixing errors enables max-warnings' + it('should not display [warnings exceeded] for max 7 warnings', function () { + const { code, stdout } = shell.exec('solhint contracts/Foo.sol --max-warnings 7') expect(code).to.equal(0) + expect(stdout.trim()).to.not.contain(warningExceededMsg) + }) + + it('should display [warnings exceeded] for max 3 warnings and exit error 1', function () { + const { code, stdout, } = shell.exec('solhint contracts/Foo.sol --max-warnings 3') + expect(code).to.equal(1) + expect(stdout.trim()).to.contain(warningExceededMsg) + }) + + it('should return error for Compiler version rule, ignoring 3 --max-warnings', function () { + const { code, stdout } = shell.exec('solhint contracts/Foo2.sol --max-warnings 3') + expect(code).to.equal(1) + expect(stdout.trim()).to.contain(errorFound) + }) + + it('should return error for Compiler version rule. No message for max-warnings', function () { + const { code, stdout } = shell.exec('solhint contracts/Foo2.sol --max-warnings 27') + expect(code).to.equal(1) + expect(stdout.trim()).to.not.contain(errorFound) }) }) }) diff --git a/package-lock.json b/package-lock.json index 450008be..5b28b891 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,8 @@ "chalk": "^4.1.2", "commander": "^10.0.0", "cosmiconfig": "^8.0.0", + "cross-spawn": "^7.0.3", + "execa": "^4.1.0", "fast-diff": "^1.2.0", "glob": "^8.0.3", "ignore": "^5.2.4", @@ -1317,7 +1319,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -1453,6 +1454,14 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1924,6 +1933,28 @@ "node": ">=0.10.0" } }, + "node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -2212,6 +2243,20 @@ "node": ">=8.0.0" } }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -2498,6 +2543,14 @@ "npm": ">=1.3.7" } }, + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "engines": { + "node": ">=8.12.0" + } + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -2836,7 +2889,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, "engines": { "node": ">=8" }, @@ -2935,8 +2987,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/isstream": { "version": "0.1.2", @@ -3281,6 +3332,11 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -3302,6 +3358,14 @@ "node": ">= 0.6" } }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3497,6 +3561,17 @@ "node": ">=0.10.0" } }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/nyc": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", @@ -3785,6 +3860,20 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -3918,7 +4007,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -4087,6 +4175,15 @@ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", @@ -4454,7 +4551,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -4466,7 +4562,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -4525,8 +4620,7 @@ "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/slice-ansi": { "version": "4.0.0", @@ -4662,6 +4756,14 @@ "node": ">=8" } }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -4992,7 +5094,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -6153,7 +6254,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -6251,6 +6351,14 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -6609,6 +6717,22 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -6819,6 +6943,14 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, "get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -7023,6 +7155,11 @@ "sshpk": "^1.7.0" } }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==" + }, "ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -7252,8 +7389,7 @@ "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" }, "is-string": { "version": "1.0.7", @@ -7316,8 +7452,7 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "isstream": { "version": "0.1.2", @@ -7586,6 +7721,11 @@ "repeat-string": "^1.0.0" } }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -7601,6 +7741,11 @@ "mime-db": "1.52.0" } }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -7752,6 +7897,14 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, "nyc": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", @@ -7973,6 +8126,14 @@ "wrappy": "1" } }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -8066,8 +8227,7 @@ "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, "path-parse": { "version": "1.0.7", @@ -8187,6 +8347,15 @@ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "punycode": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", @@ -8437,7 +8606,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "requires": { "shebang-regex": "^3.0.0" } @@ -8445,8 +8613,7 @@ "shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" }, "shelljs": { "version": "0.8.5", @@ -8489,8 +8656,7 @@ "signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "slice-ansi": { "version": "4.0.0", @@ -8591,6 +8757,11 @@ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -8841,7 +9012,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "requires": { "isexe": "^2.0.0" } diff --git a/package.json b/package.json index 4865ef1b..76bbf50c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "solhint", - "version": "3.4.1", + "version": "3.4.2", "description": "Solidity Code Linter", "main": "lib/index.js", "keywords": [ @@ -41,6 +41,8 @@ "chalk": "^4.1.2", "commander": "^10.0.0", "cosmiconfig": "^8.0.0", + "cross-spawn": "^7.0.3", + "execa": "^4.1.0", "fast-diff": "^1.2.0", "glob": "^8.0.3", "ignore": "^5.2.4", diff --git a/solhint.js b/solhint.js index f3e09d15..6d6cf188 100644 --- a/solhint.js +++ b/solhint.js @@ -59,7 +59,6 @@ function execMainAction() { } let formatterFn - try { // to check if is a valid formatter before execute linter formatterFn = getFormatter(program.opts().formatter) @@ -137,8 +136,6 @@ function writeSampleConfigFile() { } else { console.log('Configuration file already exists') } - - process.exit(0) } const readIgnore = _.memoize(() => { @@ -197,9 +194,8 @@ function areWarningsExceeded(reports) { function printReports(reports, formatter) { const warnings = areWarningsExceeded(reports) - - console.log(formatter(reports)) - + let finalMessage = '' + let exitWithOne = false if ( program.opts().maxWarnings && reports && @@ -207,21 +203,19 @@ function printReports(reports, formatter) { warnings.warningsNumberExceeded ) { if (!reports[0].errorCount) { - console.log( - 'Solhint found more warnings than the maximum specified (maximum: %s, found: %s)', - program.opts().maxWarnings, - warnings.warningsCount - ) + finalMessage = `Solhint found more warnings than the maximum specified (maximum: ${ + program.opts().maxWarnings + }, found: ${warnings.warningsCount})` + exitWithOne = true } else { - console.log( - 'Error/s found on rules! [max-warnings] rule ignored. Fixing errors enables max-warnings', - program.opts().maxWarnings, - warnings.warningsCount - ) + finalMessage = + 'Error/s found on rules! [max-warnings] param is ignored. Fixing errors enables max-warnings' } - process.exit(1) } + console.log(formatter(reports), finalMessage || '') + + if (exitWithOne) process.exit(1) return reports } @@ -240,13 +234,13 @@ function getFormatter(formatter) { function listRules() { if (process.argv.length !== 3) { console.log('Error!! no additional parameters after list-rules command') - process.exit(0) + process.exit(1) } const configPath = '.solhint.json' if (!fs.existsSync(configPath)) { console.log('Error!! Configuration does not exists') - process.exit(0) + process.exit(1) } else { const config = readConfig() console.log('\nConfiguration File: \n', config) @@ -267,13 +261,10 @@ function listRules() { console.log('- ', key, ': ', orderedRules[key]) }) } - - process.exit(0) } function exitWithCode(reports) { const errorsCount = reports.reduce((acc, i) => acc + i.errorCount, 0) - process.exit(errorsCount > 0 ? 1 : 0) }