Repository: protofire/solhint
Pull request #455 (2023-07-19 13:43:18)

I161 add e2e to test max warnings


Patch:
diff --git a/README.md b/README.md
index 507c31e..6d8e70e 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/lib/rules/best-practises/reason-string.js b/lib/rules/best-practises/reason-string.js
index f535b90..33b44a2 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/package-lock.json b/package-lock.json
index 450008b..5b28b89 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 4865ef1..76bbf50 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 225aa94..6d6cf18 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
@@ -40,6 +42,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()
   }
@@ -52,7 +59,6 @@ function execMainAction() {
   }
 
   let formatterFn
-
   try {
     // to check if is a valid formatter before execute linter
     formatterFn = getFormatter(program.opts().formatter)
@@ -63,9 +69,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) {
@@ -92,37 +95,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() {
@@ -139,8 +136,6 @@ function writeSampleConfigFile() {
   } else {
     console.log('Configuration file already exists')
   }
-
-  process.exit(0)
 }
 
 const readIgnore = _.memoize(() => {
@@ -165,7 +160,6 @@ const readIgnore = _.memoize(() => {
 
 const readConfig = _.memoize(() => {
   let config = {}
-
   try {
     config = loadConfig(program.opts().config)
   } catch (e) {
@@ -190,8 +184,38 @@ 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) {
-  console.log(formatter(reports))
+  const warnings = areWarningsExceeded(reports)
+  let finalMessage = ''
+  let exitWithOne = false
+  if (
+    program.opts().maxWarnings &&
+    reports &&
+    reports.length > 0 &&
+    warnings.warningsNumberExceeded
+  ) {
+    if (!reports[0].errorCount) {
+      finalMessage = `Solhint found more warnings than the maximum specified (maximum: ${
+        program.opts().maxWarnings
+      }, found: ${warnings.warningsCount})`
+      exitWithOne = true
+    } else {
+      finalMessage =
+        'Error/s found on rules! [max-warnings] param is ignored. Fixing errors enables max-warnings'
+    }
+  }
+
+  console.log(formatter(reports), finalMessage || '')
+
+  if (exitWithOne) process.exit(1)
   return reports
 }
 
@@ -207,9 +231,40 @@ function getFormatter(formatter) {
   }
 }
 
+function listRules() {
+  if (process.argv.length !== 3) {
+    console.log('Error!! no additional parameters after list-rules command')
+    process.exit(1)
+  }
+
+  const configPath = '.solhint.json'
+  if (!fs.existsSync(configPath)) {
+    console.log('Error!! Configuration does not exists')
+    process.exit(1)
+  } else {
+    const config = readConfig()
+    console.log('\nConfiguration File: \n', config)
+
+    const reportLists = linter.processPath(configPath, config)
+    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])
+    })
+  }
+}
+
 function exitWithCode(reports) {
   const errorsCount = reports.reduce((acc, i) => acc + i.errorCount, 0)
-
   process.exit(errorsCount > 0 ? 1 : 0)
 }
 


Test patch:
diff --git a/.github/workflows/E2E.yml b/.github/workflows/E2E.yml
index 0a8e311..60d1e06 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 82b44da..c04448e 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 0000000..3b8ee84
--- /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 0000000..659755d
--- /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 0000000..e29d2dc
--- /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 b4b9399..5a38dd7 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/test/rules/best-practises/reason-string.js b/test/rules/best-practises/reason-string.js
index c7f0cfd..30546d7 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`
+    )
+  })
 })