Repository: protofire/solhint
Pull request #518 (2023-10-27 18:02:37)

v4 20231027 develop to master


Patch:
diff --git a/.gitignore b/.gitignore
index 063bb15..8f52611 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,4 +9,5 @@ convertLib.sol
 antlr4.jar
 /docs/.sass-cache/
 _temp/
+*solhintReport*.*
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d93d717..96c84c9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,26 @@
+## [4.0] - 2023-10-01
+
+### Updated
+- Enhance explicit types sensitivity [#493](https://github.com/protofire/solhint/pull/493) (Thanks to [@vladyan18](https://github.com/vladyan18))
+- Docs on `private-vars-leading-underscore` rule to clarify its functionality
+- Changelog and docs for `no-empty-blocks` rule to clarify its functionality
+- Require package with full path [#515](https://github.com/protofire/solhint/pull/515) (Thanks to [@zouguangxian](@https://github.com/zouguangxian))
+
+### Added
+- Check for updates on Solhint version to keep users up to date. There's an option to disable this check (`--disc`) [#506](https://github.com/protofire/solhint/pull/506)
+- `fix` option now shows the report on screen [#509](https://github.com/protofire/solhint/pull/509)
+- `save` option to store report on disk with the standard or the specified format [#509](https://github.com/protofire/solhint/pull/509) 
+- Autofix for `explicit-types` rule [#504](https://github.com/protofire/solhint/pull/504)
+- Autofix for `no-console` rule [#513](https://github.com/protofire/solhint/pull/513)
+- Autofix for `private-vars-leading-underscore` rule [#511](https://github.com/protofire/solhint/pull/511)
+
+### Fixed
+- Generate docs script on Windows OS [#494](https://github.com/protofire/solhint/pull/494) (Thanks to [@vladyan18](https://github.com/vladyan18))
+- `one-contract-per-file` ignore interfaces [#514](https://github.com/protofire/solhint/pull/514) (Thanks to [@cruzdanilo](https://github.com/cruzdanilo))
+
+ 
+
+
 ## [3.6.2] - 2023-08-17
 ### Added
 - New Rule: `one-contract-per-file` - Enforces the use of ONE contract per file [#487](https://github.com/protofire/solhint/pull/487)
@@ -31,12 +54,17 @@ If not explicitly added, this rule will not be executed.
 ### SPECIAL ATTENTION
 - RULE: `compiler-version` default was updated from ^0.5.2 to ^0.8.0
 
+
+### Updated
+- Rule: `check-send-result` added config clarification in the new `Notes` section [#482](https://github.com/protofire/solhint/pull/482)
+- Rule: `compiler-version` default was updated from ^0.5.2 to ^0.8.0 [#483](https://github.com/protofire/solhint/pull/483)
+
 ### Added
 - New Rule: Enforces the use of Custom Errors over Require and Revert statements [#475](https://github.com/protofire/solhint/pull/475)
 - New Rule: Enforces the test_ prefix on a file for Foundry users [#476](https://github.com/protofire/solhint/pull/476)
 - New Rule: Enforces the naming of function return values [#478](https://github.com/protofire/solhint/pull/478)
 - `Notes` option on docs to add more information of each rule. See `foundry-test-functions`. [#476](https://github.com/protofire/solhint/pull/476)
-  
+
 ### Fixed
 - `func-named-parameters` - false positives on builtin functions [#472](https://github.com/protofire/solhint/pull/472)
 - `ordering` - treat initializer weight same as constructor [#474](https://github.com/protofire/solhint/pull/474)
@@ -44,15 +72,12 @@ If not explicitly added, this rule will not be executed.
 - `explicit-types` - default value is now taking into account when no value is specified in config [#481](https://github.com/protofire/solhint/pull/481)
 - `compiler-version` - default value is now taking into account when no value is specified in config [#483](https://github.com/protofire/solhint/pull/483)
 
-### Updates
-- Rule: `check-send-result` added config clarification in the new `Notes` section [#482](https://github.com/protofire/solhint/pull/482)
-- Rule: `compiler-version` default was updated from ^0.5.2 to ^0.8.0 [#483](https://github.com/protofire/solhint/pull/483)
 
 
 
 ## [3.5.1] - 2023-08-04
 ### Updated
-- Support `ignoreConstructors` option for `no-empty-blocks` [#418](https://github.com/protofire/solhint/pull/418)
+- Ignores empty constructors when inheriting a base contract [#418](https://github.com/protofire/solhint/pull/418)
 - Bump json5 from 2.1.3 to 2.2.3 [#376](https://github.com/protofire/solhint/pull/376)
 - Bump json-schema and jsprim [#370](https://github.com/protofire/solhint/pull/370)
 - Bump semver from 6.3.0 to 7.5.2 [#438](https://github.com/protofire/solhint/pull/438)
@@ -64,7 +89,6 @@ If not explicitly added, this rule will not be executed.
 - Removed runtime dependencies on load-rules [#462](https://github.com/protofire/solhint/pull/462)
 - Allowed $ symbol as part of naming [#465](https://github.com/protofire/solhint/issues/465)
 - Disabled `no-empty-blocks` rule for receive() function [#466](https://github.com/protofire/solhint/pull/466)
-
   
 ### Added
 - New Rule: No unused imports [#417](https://github.com/protofire/solhint/pull/417)
diff --git a/README.md b/README.md
index 0f010f6..27ffa79 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
   By <a href="https://protofire.io/">Protofire</a>
 </p>
 
+[![Join Discord](https://img.shields.io/badge/join-Discord-red)](https://discord.gg/4TYGq3zpjs)
 [![Donate with Ethereum](https://img.shields.io/badge/Donate-ETH-blue)](https://etherscan.io/address/0xA81705c8C247C413a19A244938ae7f4A0393944e)
 [![NPM version](https://badge.fury.io/js/solhint.svg)](https://npmjs.org/package/solhint)
 [![Coverage Status](https://coveralls.io/repos/github/protofire/solhint/badge.svg?branch=master)](
@@ -14,6 +15,7 @@ https://coveralls.io/github/protofire/solhint?branch=master)
 This is an open source project for linting [Solidity](http://solidity.readthedocs.io/en/develop/) code. This project
 provides both **Security** and **Style Guide** validations.
 
+[JOIN OUR DISCORD SERVER](https://discord.gg/4TYGq3zpjs)
 ## Installation
 
 You can install Solhint using **npm**:
@@ -60,8 +62,11 @@ Options:
   -c, --config [file_name]                file to use as your .solhint.json
   -q, --quiet                             report errors only - default: false
   --ignore-path [file_name]               file to use as your .solhintignore
-  --fix                                   automatically fix problems
+  --fix                                   automatically fix problems and show report
+  --noPrompt                              do not suggest to backup files when any `fix` option is selected
   --init                                  create configuration file for solhint
+  --disc                                  do not check for solhint updates
+  --save                                  save report to file on current folder
   -h, --help                              output usage information
 
 Commands:
@@ -69,8 +74,17 @@ 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
+### Notes
+- Solhint checks if there are newer versions. The `--disc`  option avoids that check.
+- `--save` option will create a file named as `YYYYMMDDHHMMSS_solhintReport.txt` on current folder with default or specified format 
+
+### Fix
+This option currently works on:
+- avoid-throw
+- avoid-sha3
+- no-console
+- explicit-types
+- private-vars-underscore
 <br><br>
 ## Configuration
 
diff --git a/docs/rules.md b/docs/rules.md
index 66d1265..64185cd 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -48,7 +48,7 @@ title:       "Rule Index of Solhint"
 | [modifier-name-mixedcase](./rules/naming/modifier-name-mixedcase.md)                 | Modifier name must be in mixedCase.                                                                           |              |             |
 | [named-parameters-mapping](./rules/naming/named-parameters-mapping.md)               | Solidity v0.8.18 introduced named parameters on the mappings definition.                                      |              |             |
 | [named-return-values](./rules/naming/named-return-values.md)                         | Enforce the return values of a function to be named                                                           |              |             |
-| [private-vars-leading-underscore](./rules/naming/private-vars-leading-underscore.md) | Private and internal names must start with a single underscore.                                               |              |             |
+| [private-vars-leading-underscore](./rules/naming/private-vars-leading-underscore.md) | Non-external functions and state variables should start with a single underscore. Others, shouldn't           |              |             |
 | [use-forbidden-name](./rules/naming/use-forbidden-name.md)                           | Avoid to use letters 'I', 'l', 'O' as identifiers.                                                            | $~~~~~~~~$✔️ |             |
 | [var-name-mixedcase](./rules/naming/var-name-mixedcase.md)                           | Variable name must be in mixedCase. (Does not check IMMUTABLES, use immutable-vars-naming)                    | $~~~~~~~~$✔️ |             |
 | [func-order](./rules/order/func-order.md)                                            | Function order is incorrect.                                                                                  |              | $~~~~~~~$✔️ |
diff --git a/docs/rules/best-practises/explicit-types.md b/docs/rules/best-practises/explicit-types.md
index 8448bc6..2a47276 100644
--- a/docs/rules/best-practises/explicit-types.md
+++ b/docs/rules/best-practises/explicit-types.md
@@ -32,6 +32,8 @@ This rule accepts an array of options:
 }
 ```
 
+### Notes
+- Solhint allows this rule to automatically fix the code with `--fix` option
 
 ## Examples
 ### 👍 Examples of **correct** code for this rule
@@ -48,6 +50,12 @@ uint256 public variableName
 uint public variableName
 ```
 
+#### If explicit is selected
+
+```solidity
+uint256 public variableName = uint256(5)
+```
+
 ### 👎 Examples of **incorrect** code for this rule
 
 #### If explicit is selected
@@ -62,6 +70,12 @@ uint public variableName
 uint256 public variableName
 ```
 
+#### At any setting
+
+```solidity
+uint public variableName = uint256(5)
+```
+
 ## Version
 This rule was introduced in [Solhint 3.5.1](https://github.com/protofire/solhint/tree/v3.5.1)
 
diff --git a/docs/rules/best-practises/no-empty-blocks.md b/docs/rules/best-practises/no-empty-blocks.md
index cbc7cae..d8a1875 100644
--- a/docs/rules/best-practises/no-empty-blocks.md
+++ b/docs/rules/best-practises/no-empty-blocks.md
@@ -26,6 +26,8 @@ This rule accepts a string option of rule severity. Must be one of "error", "war
 }
 ```
 
+### Notes
+- The rule ignores an empty constructor by default as long as base contracts are being inherited. See "Empty Constructor" example.
 
 ## Examples
 ### 👍 Examples of **correct** code for this rule
diff --git a/docs/rules/best-practises/one-contract-per-file.md b/docs/rules/best-practises/one-contract-per-file.md
index 564baca..9213535 100644
--- a/docs/rules/best-practises/one-contract-per-file.md
+++ b/docs/rules/best-practises/one-contract-per-file.md
@@ -31,7 +31,7 @@ This rule accepts a string option of rule severity. Must be one of "error", "war
 This rule does not have examples.
 
 ## Version
-This rule is introduced in the latest version.
+This rule was introduced in [Solhint 3.6.2](https://github.com/protofire/solhint/tree/v3.6.2)
 
 ## Resources
 - [Rule source](https://github.com/protofire/solhint/tree/master/lib/rules/best-practises/one-contract-per-file.js)
diff --git a/docs/rules/naming/private-vars-leading-underscore.md b/docs/rules/naming/private-vars-leading-underscore.md
index 9e0028c..bba9e89 100644
--- a/docs/rules/naming/private-vars-leading-underscore.md
+++ b/docs/rules/naming/private-vars-leading-underscore.md
@@ -9,15 +9,15 @@ title:       "private-vars-leading-underscore | Solhint"
 ![Default Severity Badge warn](https://img.shields.io/badge/Default%20Severity-warn-yellow)
 
 ## Description
-Private and internal names must start with a single underscore.
+Non-external functions and state variables should start with a single underscore. Others, shouldn't
 
 ## Options
 This rule accepts an array of options:
 
-| Index | Description                                                                                                                           | Default Value    |
-| ----- | ------------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
-| 0     | Rule severity. Must be one of "error", "warn", "off".                                                                                 | warn             |
-| 1     | A JSON object with a single property "strict" specifying if the rule should apply to non state variables. Default: { strict: false }. | {"strict":false} |
+| Index | Description                                                                                                                               | Default Value    |
+| ----- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
+| 0     | Rule severity. Must be one of "error", "warn", "off".                                                                                     | warn             |
+| 1     | A JSON object with a single property "strict" specifying if the rule should apply to ALL non state variables. Default: { strict: false }. | {"strict":false} |
 
 
 ### Example Config
@@ -29,9 +29,64 @@ This rule accepts an array of options:
 }
 ```
 
+### Notes
+- This rule considers functions and variables in Libraries as well
+- This rule skips external and public functions
+- This rule skips external and public state variables
+- See [here](https://docs.soliditylang.org/en/latest/style-guide.html#underscore-prefix-for-non-external-functions-and-variables) for further information
 
 ## Examples
-This rule does not have examples.
+### 👍 Examples of **correct** code for this rule
+
+#### Internal function with correct naming
+
+```solidity
+function _thisIsInternal() internal {}
+```
+
+#### Private function with correct naming
+
+```solidity
+function _thisIsPrivate() private {}
+```
+
+#### Internal state variable with correct naming
+
+```solidity
+uint256 internal _thisIsInternalVariable;
+```
+
+#### Internal state variable with correct naming (no visibility is considered internal)
+
+```solidity
+uint256 _thisIsInternalVariable;
+```
+
+### 👎 Examples of **incorrect** code for this rule
+
+#### Internal function with incorrect naming
+
+```solidity
+function thisIsInternal() internal {}
+```
+
+#### Private function with incorrect naming
+
+```solidity
+function thisIsPrivate() private {}
+```
+
+#### Internal state variable with incorrect naming
+
+```solidity
+uint256 internal thisIsInternalVariable;
+```
+
+#### Internal state variable with incorrect naming (no visibility is considered internal)
+
+```solidity
+uint256 thisIsInternalVariable;
+```
 
 ## Version
 This rule was introduced in [Solhint 3.0.0-rc.3](https://github.com/protofire/solhint/tree/v3.0.0-rc.3)
diff --git a/docs/rules/security/avoid-sha3.md b/docs/rules/security/avoid-sha3.md
index 1d6f963..7947a08 100644
--- a/docs/rules/security/avoid-sha3.md
+++ b/docs/rules/security/avoid-sha3.md
@@ -26,6 +26,8 @@ This rule accepts a string option of rule severity. Must be one of "error", "war
 }
 ```
 
+### Notes
+- Solhint allows this rule to automatically fix the code with `--fix` option
 
 ## Examples
 This rule does not have examples.
diff --git a/docs/rules/security/avoid-throw.md b/docs/rules/security/avoid-throw.md
index a9d90cc..5b12fcd 100644
--- a/docs/rules/security/avoid-throw.md
+++ b/docs/rules/security/avoid-throw.md
@@ -26,6 +26,8 @@ This rule accepts a string option of rule severity. Must be one of "error", "war
 }
 ```
 
+### Notes
+- Solhint allows this rule to automatically fix the code with `--fix` option
 
 ## Examples
 This rule does not have examples.
diff --git a/docs/writing-plugins.md b/docs/writing-plugins.md
index fe1fa11..457e777 100644
--- a/docs/writing-plugins.md
+++ b/docs/writing-plugins.md
@@ -24,6 +24,7 @@ class MyNewRule {
 
     ...
   }
+}
 ```
 
 This is enough for the rule to work but, of course, this will do nothing. Rules are implemented using a visitor pattern: you implement methods that are called when a node in the AST is entered or exited. For example, let's make a rule that forbids naming contracts `Foo`:
diff --git a/lib/config/config-file.js b/lib/config/config-file.js
index f101d8f..3ae3c1d 100644
--- a/lib/config/config-file.js
+++ b/lib/config/config-file.js
@@ -1,4 +1,5 @@
 const fs = require('fs')
+const path = require('path')
 const _ = require('lodash')
 const { cosmiconfigSync } = require('cosmiconfig')
 const { ConfigMissingError } = require('../common/errors')
@@ -64,8 +65,15 @@ const loadConfig = (configFile) => {
   return searchedFor.config || createEmptyConfig()
 }
 
-const configGetter = (path) =>
-  path.startsWith('solhint:') ? getSolhintCoreConfig(path) : require(`solhint-config-${path}`)
+const isAbsolute = path.isAbsolute
+const configGetter = (path) => {
+  if (isAbsolute(path)) {
+    return require(path)
+  }
+  return path.startsWith('solhint:')
+    ? getSolhintCoreConfig(path)
+    : require(`solhint-config-${path}`)
+}
 
 const applyExtends = (config, getter = configGetter) => {
   if (!config.extends) {
diff --git a/lib/rules/best-practises/explicit-types.js b/lib/rules/best-practises/explicit-types.js
index ebf7b60..3273b34 100644
--- a/lib/rules/best-practises/explicit-types.js
+++ b/lib/rules/best-practises/explicit-types.js
@@ -7,6 +7,7 @@ const ALL_TYPES = EXPLICIT_TYPES.concat(IMPLICIT_TYPES)
 const VALID_CONFIGURATION_OPTIONS = ['explicit', 'implicit']
 const DEFAULT_OPTION = 'explicit'
 const DEFAULT_SEVERITY = 'warn'
+let typesToSearch
 
 const ruleId = 'explicit-types'
 const meta = {
@@ -35,6 +36,10 @@ const meta = {
           description: 'If implicit is selected',
           code: 'uint public variableName',
         },
+        {
+          description: 'If explicit is selected',
+          code: 'uint256 public variableName = uint256(5)',
+        },
       ],
       bad: [
         {
@@ -45,13 +50,23 @@ const meta = {
           description: 'If implicit is selected',
           code: 'uint256 public variableName',
         },
+        {
+          description: 'At any setting',
+          code: 'uint public variableName = uint256(5)',
+        },
       ],
     },
+    notes: [
+      {
+        note: 'Solhint allows this rule to automatically fix the code with `--fix` option',
+      },
+    ],
   },
 
   isDefault: false,
   recommended: true,
   defaultSetup: [DEFAULT_SEVERITY, DEFAULT_OPTION],
+  fixable: true,
 
   schema: {
     type: 'string',
@@ -65,9 +80,29 @@ class ExplicitTypesChecker extends BaseChecker {
     this.configOption =
       (config && config.getStringFromArray(ruleId, DEFAULT_OPTION)) || DEFAULT_OPTION
     this.isExplicit = this.configOption === 'explicit'
+
+    // if explicit, it will search for implicit and viceversa
+    if (this.isExplicit) {
+      typesToSearch = IMPLICIT_TYPES
+    } else {
+      typesToSearch = EXPLICIT_TYPES
+    }
   }
 
   VariableDeclaration(node) {
+    this.validateInNode(node)
+  }
+
+  VariableDeclarationStatement(node) {
+    if (!node.initialValue) return
+    this.validateInNode(node.initialValue)
+  }
+
+  ExpressionStatement(node) {
+    this.validateInNode(node)
+  }
+
+  validateInNode(node) {
     if (!VALID_CONFIGURATION_OPTIONS.includes(this.configOption)) {
       this.error(node, 'Error: Config error on [explicit-types]. See explicit-types.md.')
       return
@@ -85,12 +120,7 @@ class ExplicitTypesChecker extends BaseChecker {
     // if defined variables are not to be checked (example address type), return
     if (varsToBeChecked && varsToBeChecked.length === 0) return
 
-    // if explicit, it will search for implicit and viceversa
-    if (this.isExplicit) {
-      this.validateVariables(IMPLICIT_TYPES, node, varsToBeChecked)
-    } else {
-      this.validateVariables(EXPLICIT_TYPES, node, varsToBeChecked)
-    }
+    this.validateVariables(typesToSearch, node, varsToBeChecked)
   }
 
   validateVariables(configType, node, varsToBeChecked) {
@@ -98,11 +128,24 @@ class ExplicitTypesChecker extends BaseChecker {
 
     if (errorVars && errorVars.length > 0) {
       for (const errorVar of errorVars) {
-        this.error(node, `Rule is set with ${this.configOption} type [var/s: ${errorVar}]`)
+        this.error(
+          node,
+          `Rule is set with ${this.configOption} type [var/s: ${errorVar}]`,
+          this.fixStatement(node, errorVar)
+        )
       }
     }
   }
 
+  fixStatement(typeNameNode, errorVar) {
+    const configFileIndex = typesToSearch.findIndex((arg) => arg === errorVar)
+    return (fixer) =>
+      fixer.replaceTextRange(
+        typeNameNode.typeName.range,
+        this.isExplicit ? EXPLICIT_TYPES[configFileIndex] : IMPLICIT_TYPES[configFileIndex]
+      )
+  }
+
   findNamesOfElementaryTypeName(jsonObject, typeToFind) {
     const names = []
 
diff --git a/lib/rules/best-practises/no-console.js b/lib/rules/best-practises/no-console.js
index e6b26af..c6156fb 100644
--- a/lib/rules/best-practises/no-console.js
+++ b/lib/rules/best-practises/no-console.js
@@ -28,6 +28,7 @@ const meta = {
   isDefault: true,
   recommended: true,
   defaultSetup: 'error',
+  fixable: true,
   schema: null,
 }
 
@@ -38,13 +39,13 @@ class NoConsoleLogChecker extends BaseChecker {
 
   ImportDirective(node) {
     if (this.isConsoleImport(node)) {
-      this.error(node, 'Unexpected import of console file')
+      this.error(node, 'Unexpected import of console file', this.fixStatement(node, 'import'))
     }
   }
 
   FunctionCall(node) {
     if (this.isConsoleLog(node)) {
-      this.error(node, 'Unexpected console statement')
+      this.error(node, 'Unexpected console statement', this.fixStatement(node, 'call'))
     }
   }
 
@@ -64,6 +65,18 @@ class NoConsoleLogChecker extends BaseChecker {
       node.path === 'forge-std/console2.sol'
     )
   }
+
+  fixStatement(node, type) {
+    const range = node.range
+    // to remove the ';'
+    if (type === 'call') range[1] += 1
+
+    // // to remove the ';' and the 'enter'
+    // if (type === 'call') range[1] += 2
+    // else range[1] += 1 // to remove the 'enter'
+
+    return (fixer) => fixer.removeRange(range)
+  }
 }
 
 module.exports = NoConsoleLogChecker
diff --git a/lib/rules/best-practises/no-empty-blocks.js b/lib/rules/best-practises/no-empty-blocks.js
index 2df7a23..a8c81bf 100644
--- a/lib/rules/best-practises/no-empty-blocks.js
+++ b/lib/rules/best-practises/no-empty-blocks.js
@@ -25,6 +25,11 @@ const meta = {
         },
       ],
     },
+    notes: [
+      {
+        note: 'The rule ignores an empty constructor by default as long as base contracts are being inherited. See "Empty Constructor" example.',
+      },
+    ],
   },
 
   isDefault: false,
diff --git a/lib/rules/best-practises/one-contract-per-file.js b/lib/rules/best-practises/one-contract-per-file.js
index 200ab77..51cdf00 100644
--- a/lib/rules/best-practises/one-contract-per-file.js
+++ b/lib/rules/best-practises/one-contract-per-file.js
@@ -33,7 +33,7 @@ class OneContractPerFileChecker extends BaseChecker {
 
   SourceUnit(node) {
     const contractDefinitionCount = node.children.reduce((count, child) => {
-      if (child.type === 'ContractDefinition') {
+      if (child.type === 'ContractDefinition' && child.kind !== 'interface') {
         return count + 1
       }
       return count
diff --git a/lib/rules/naming/private-vars-leading-underscore.js b/lib/rules/naming/private-vars-leading-underscore.js
index dc41872..bcbfdff 100644
--- a/lib/rules/naming/private-vars-leading-underscore.js
+++ b/lib/rules/naming/private-vars-leading-underscore.js
@@ -11,7 +11,8 @@ const meta = {
   type: 'naming',
 
   docs: {
-    description: 'Private and internal names must start with a single underscore.',
+    description:
+      "Non-external functions and state variables should start with a single underscore. Others, shouldn't",
     category: 'Style Guide Rules',
     options: [
       {
@@ -20,15 +21,70 @@ const meta = {
       },
       {
         description:
-          'A JSON object with a single property "strict" specifying if the rule should apply to non state variables. Default: { strict: false }.',
+          'A JSON object with a single property "strict" specifying if the rule should apply to ALL non state variables. Default: { strict: false }.',
         default: JSON.stringify(DEFAULT_OPTION),
       },
     ],
+    examples: {
+      good: [
+        {
+          description: 'Internal function with correct naming',
+          code: 'function _thisIsInternal() internal {}',
+        },
+        {
+          description: 'Private function with correct naming',
+          code: 'function _thisIsPrivate() private {}',
+        },
+        {
+          description: 'Internal state variable with correct naming',
+          code: 'uint256 internal _thisIsInternalVariable;',
+        },
+        {
+          description:
+            'Internal state variable with correct naming (no visibility is considered internal)',
+          code: 'uint256 _thisIsInternalVariable;',
+        },
+      ],
+      bad: [
+        {
+          description: 'Internal function with incorrect naming',
+          code: 'function thisIsInternal() internal {}',
+        },
+        {
+          description: 'Private function with incorrect naming',
+          code: 'function thisIsPrivate() private {}',
+        },
+        {
+          description: 'Internal state variable with incorrect naming',
+          code: 'uint256 internal thisIsInternalVariable;',
+        },
+        {
+          description:
+            'Internal state variable with incorrect naming (no visibility is considered internal)',
+          code: 'uint256 thisIsInternalVariable;',
+        },
+      ],
+    },
+    notes: [
+      {
+        note: 'This rule considers functions and variables in Libraries as well',
+      },
+      {
+        note: 'This rule skips external and public functions',
+      },
+      {
+        note: 'This rule skips external and public state variables',
+      },
+      {
+        note: 'See [here](https://docs.soliditylang.org/en/latest/style-guide.html#underscore-prefix-for-non-external-functions-and-variables) for further information',
+      },
+    ],
   },
 
   isDefault: false,
   recommended: false,
   defaultSetup: [DEFAULT_SEVERITY, DEFAULT_OPTION],
+  fixable: true,
 
   schema: {
     type: 'object',
@@ -47,15 +103,15 @@ class PrivateVarsLeadingUnderscoreChecker extends BaseChecker {
     this.isStrict = config && config.getObjectPropertyBoolean(ruleId, 'strict', DEFAULT_STRICTNESS)
   }
 
-  ContractDefinition(node) {
-    if (node.kind === 'library') {
-      this.inLibrary = true
-    }
-  }
+  // ContractDefinition(node) {
+  //   if (node.kind === 'library') {
+  //     this.inLibrary = true
+  //   }
+  // }
 
-  'ContractDefinition:exit'() {
-    this.inLibrary = false
-  }
+  // 'ContractDefinition:exit'() {
+  //   this.inLibrary = false
+  // }
 
   FunctionDefinition(node) {
     if (!node.name) {
@@ -63,9 +119,10 @@ class PrivateVarsLeadingUnderscoreChecker extends BaseChecker {
     }
 
     const isPrivate = node.visibility === 'private'
-    const isInternal = node.visibility === 'internal'
-    const shouldHaveLeadingUnderscore = isPrivate || (!this.inLibrary && isInternal)
-    this.validateName(node, shouldHaveLeadingUnderscore)
+    const isInternal = node.visibility === 'internal' || node.visibility === 'default'
+    // const shouldHaveLeadingUnderscore = isPrivate || (!this.inLibrary && isInternal)
+    const shouldHaveLeadingUnderscore = isPrivate || isInternal
+    this.validateName(node, shouldHaveLeadingUnderscore, 'function')
   }
 
   StateVariableDeclaration() {
@@ -80,7 +137,7 @@ class PrivateVarsLeadingUnderscoreChecker extends BaseChecker {
     if (!this.inStateVariableDeclaration) {
       // if strict is enabled, non-state vars should not start with leading underscore
       if (this.isStrict) {
-        this.validateName(node, false)
+        this.validateName(node, false, 'variable')
       }
       return
     }
@@ -88,25 +145,43 @@ class PrivateVarsLeadingUnderscoreChecker extends BaseChecker {
     const isPrivate = node.visibility === 'private'
     const isInternal = node.visibility === 'internal' || node.visibility === 'default'
     const shouldHaveLeadingUnderscore = isPrivate || isInternal
-    this.validateName(node, shouldHaveLeadingUnderscore)
+    this.validateName(node, shouldHaveLeadingUnderscore, 'variable')
   }
 
-  validateName(node, shouldHaveLeadingUnderscore) {
+  validateName(node, shouldHaveLeadingUnderscore, type) {
     if (node.name === null) {
       return
     }
 
     if (naming.hasLeadingUnderscore(node.name) !== shouldHaveLeadingUnderscore) {
-      this._error(node, node.name, shouldHaveLeadingUnderscore)
+      this._error(node, node.name, shouldHaveLeadingUnderscore, type)
     }
   }
 
-  _error(node, name, shouldHaveLeadingUnderscore) {
+  _error(node, name, shouldHaveLeadingUnderscore, type) {
     this.error(
       node,
-      `'${name}' ${shouldHaveLeadingUnderscore ? 'should' : 'should not'} start with _`
+      `'${name}' ${shouldHaveLeadingUnderscore ? 'should' : 'should not'} start with _`,
+      this.fixStatement(node, shouldHaveLeadingUnderscore, type)
     )
   }
+
+  fixStatement(node, shouldHaveLeadingUnderscore, type) {
+    let range
+
+    if (type === 'function') {
+      range = node.range
+      range[0] += 8
+    } else {
+      range = node.identifier.range
+      range[0] -= 1
+    }
+
+    return (fixer) =>
+      shouldHaveLeadingUnderscore
+        ? fixer.insertTextBeforeRange(range, ' _')
+        : fixer.removeRange([range[0] + 1, range[0] + 1])
+  }
 }
 
 module.exports = PrivateVarsLeadingUnderscoreChecker
diff --git a/lib/rules/security/avoid-sha3.js b/lib/rules/security/avoid-sha3.js
index 048679a..a8d5c0b 100644
--- a/lib/rules/security/avoid-sha3.js
+++ b/lib/rules/security/avoid-sha3.js
@@ -7,6 +7,11 @@ const meta = {
   docs: {
     description: `Use "keccak256" instead of deprecated "sha3".`,
     category: 'Security Rules',
+    notes: [
+      {
+        note: 'Solhint allows this rule to automatically fix the code with `--fix` option',
+      },
+    ],
   },
 
   isDefault: false,
diff --git a/lib/rules/security/avoid-throw.js b/lib/rules/security/avoid-throw.js
index 30a942a..72a9f4f 100644
--- a/lib/rules/security/avoid-throw.js
+++ b/lib/rules/security/avoid-throw.js
@@ -7,6 +7,11 @@ const meta = {
   docs: {
     description: `"throw" is deprecated, avoid to use it.`,
     category: 'Security Rules',
+    notes: [
+      {
+        note: 'Solhint allows this rule to automatically fix the code with `--fix` option',
+      },
+    ],
   },
 
   isDefault: false,
diff --git a/package-lock.json b/package-lock.json
index c5d4d4e..633ddb0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "solhint",
-  "version": "3.5.1",
+  "version": "3.6.3",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "solhint",
-      "version": "3.5.1",
+      "version": "3.6.3",
       "license": "MIT",
       "dependencies": {
         "@solidity-parser/parser": "^0.16.0",
@@ -20,6 +20,7 @@
         "glob": "^8.0.3",
         "ignore": "^5.2.4",
         "js-yaml": "^4.1.0",
+        "latest-version": "^7.0.0",
         "lodash": "^4.17.21",
         "pluralize": "^8.0.0",
         "semver": "^7.5.2",
@@ -699,6 +700,49 @@
         "node": ">= 8"
       }
     },
+    "node_modules/@pnpm/config.env-replace": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz",
+      "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==",
+      "engines": {
+        "node": ">=12.22.0"
+      }
+    },
+    "node_modules/@pnpm/network.ca-file": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz",
+      "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==",
+      "dependencies": {
+        "graceful-fs": "4.2.10"
+      },
+      "engines": {
+        "node": ">=12.22.0"
+      }
+    },
+    "node_modules/@pnpm/npm-conf": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz",
+      "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==",
+      "dependencies": {
+        "@pnpm/config.env-replace": "^1.1.0",
+        "@pnpm/network.ca-file": "^1.0.1",
+        "config-chain": "^1.1.11"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@sindresorhus/is": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz",
+      "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==",
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/is?sponsor=1"
+      }
+    },
     "node_modules/@solidity-parser/parser": {
       "version": "0.16.0",
       "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.0.tgz",
@@ -707,6 +751,22 @@
         "antlr4ts": "^0.5.0-alpha.4"
       }
     },
+    "node_modules/@szmarczak/http-timer": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz",
+      "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==",
+      "dependencies": {
+        "defer-to-connect": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=14.16"
+      }
+    },
+    "node_modules/@types/http-cache-semantics": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz",
+      "integrity": "sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw=="
+    },
     "node_modules/@types/json5": {
       "version": "0.0.29",
       "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@@ -1052,6 +1112,31 @@
         "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
       }
     },
+    "node_modules/cacheable-lookup": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz",
+      "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==",
+      "engines": {
+        "node": ">=14.16"
+      }
+    },
+    "node_modules/cacheable-request": {
+      "version": "10.2.14",
+      "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz",
+      "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==",
+      "dependencies": {
+        "@types/http-cache-semantics": "^4.0.2",
+        "get-stream": "^6.0.1",
+        "http-cache-semantics": "^4.1.1",
+        "keyv": "^4.5.3",
+        "mimic-response": "^4.0.0",
+        "normalize-url": "^8.0.0",
+        "responselike": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=14.16"
+      }
+    },
     "node_modules/caching-transform": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
@@ -1241,6 +1326,15 @@
       "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
       "dev": true
     },
+    "node_modules/config-chain": {
+      "version": "1.1.13",
+      "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
+      "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
+      "dependencies": {
+        "ini": "^1.3.4",
+        "proto-list": "~1.2.1"
+      }
+    },
     "node_modules/confusing-browser-globals": {
       "version": "1.0.11",
       "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz",
@@ -1366,6 +1460,39 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/decompress-response": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+      "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+      "dependencies": {
+        "mimic-response": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/decompress-response/node_modules/mimic-response": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+      "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/deep-extend": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
     "node_modules/deep-is": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -1387,6 +1514,14 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/defer-to-connect": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
+      "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/define-properties": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
@@ -2100,6 +2235,14 @@
         "node": ">= 0.12"
       }
     },
+    "node_modules/form-data-encoder": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz",
+      "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==",
+      "engines": {
+        "node": ">= 14.17"
+      }
+    },
     "node_modules/fromentries": {
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz",
@@ -2213,6 +2356,17 @@
         "node": ">=8.0.0"
       }
     },
+    "node_modules/get-stream": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+      "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+      "engines": {
+        "node": ">=10"
+      },
+      "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",
@@ -2329,11 +2483,34 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/got": {
+      "version": "12.6.1",
+      "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz",
+      "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==",
+      "dependencies": {
+        "@sindresorhus/is": "^5.2.0",
+        "@szmarczak/http-timer": "^5.0.1",
+        "cacheable-lookup": "^7.0.0",
+        "cacheable-request": "^10.2.8",
+        "decompress-response": "^6.0.0",
+        "form-data-encoder": "^2.1.2",
+        "get-stream": "^6.0.1",
+        "http2-wrapper": "^2.1.10",
+        "lowercase-keys": "^3.0.0",
+        "p-cancelable": "^3.0.0",
+        "responselike": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/got?sponsor=1"
+      }
+    },
     "node_modules/graceful-fs": {
       "version": "4.2.10",
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
-      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
-      "dev": true
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
     },
     "node_modules/grapheme-splitter": {
       "version": "1.0.4",
@@ -2484,6 +2661,11 @@
       "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
       "dev": true
     },
+    "node_modules/http-cache-semantics": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+      "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
+    },
     "node_modules/http-signature": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
@@ -2499,6 +2681,18 @@
         "npm": ">=1.3.7"
       }
     },
+    "node_modules/http2-wrapper": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz",
+      "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==",
+      "dependencies": {
+        "quick-lru": "^5.1.1",
+        "resolve-alpn": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=10.19.0"
+      }
+    },
     "node_modules/husky": {
       "version": "8.0.3",
       "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz",
@@ -2569,6 +2763,11 @@
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
       "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
     },
+    "node_modules/ini": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
+    },
     "node_modules/internal-slot": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz",
@@ -3107,6 +3306,11 @@
         "node": ">=4"
       }
     },
+    "node_modules/json-buffer": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
+    },
     "node_modules/json-parse-even-better-errors": {
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
@@ -3162,6 +3366,28 @@
         "node": ">=0.6.0"
       }
     },
+    "node_modules/keyv": {
+      "version": "4.5.4",
+      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+      "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+      "dependencies": {
+        "json-buffer": "3.0.1"
+      }
+    },
+    "node_modules/latest-version": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz",
+      "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==",
+      "dependencies": {
+        "package-json": "^8.1.0"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/lcov-parse": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz",
@@ -3251,6 +3477,17 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/lowercase-keys": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
+      "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==",
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/lru-cache": {
       "version": "5.1.1",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -3318,6 +3555,17 @@
         "node": ">= 0.6"
       }
     },
+    "node_modules/mimic-response": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz",
+      "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==",
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/minimatch": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -3334,7 +3582,6 @@
       "version": "1.2.7",
       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
       "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
-      "dev": true,
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
@@ -3513,6 +3760,17 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/normalize-url": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz",
+      "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==",
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/nyc": {
       "version": "15.1.0",
       "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
@@ -3818,6 +4076,14 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/p-cancelable": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz",
+      "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==",
+      "engines": {
+        "node": ">=12.20"
+      }
+    },
     "node_modules/p-limit": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -3884,6 +4150,23 @@
         "node": ">=8"
       }
     },
+    "node_modules/package-json": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz",
+      "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==",
+      "dependencies": {
+        "got": "^12.1.0",
+        "registry-auth-token": "^5.0.1",
+        "registry-url": "^6.0.0",
+        "semver": "^7.3.7"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/parent-module": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -4097,6 +4380,11 @@
         "node": ">=8"
       }
     },
+    "node_modules/proto-list": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
+      "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="
+    },
     "node_modules/psl": {
       "version": "1.9.0",
       "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@@ -4140,6 +4428,17 @@
         }
       ]
     },
+    "node_modules/quick-lru": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+      "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/randombytes": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -4149,6 +4448,28 @@
         "safe-buffer": "^5.1.0"
       }
     },
+    "node_modules/rc": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+      "dependencies": {
+        "deep-extend": "^0.6.0",
+        "ini": "~1.3.0",
+        "minimist": "^1.2.0",
+        "strip-json-comments": "~2.0.1"
+      },
+      "bin": {
+        "rc": "cli.js"
+      }
+    },
+    "node_modules/rc/node_modules/strip-json-comments": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/readdirp": {
       "version": "3.6.0",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -4202,6 +4523,31 @@
         "url": "https://github.com/sponsors/mysticatea"
       }
     },
+    "node_modules/registry-auth-token": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz",
+      "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==",
+      "dependencies": {
+        "@pnpm/npm-conf": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/registry-url": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz",
+      "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==",
+      "dependencies": {
+        "rc": "1.2.8"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/release-zalgo": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
@@ -4305,6 +4651,11 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/resolve-alpn": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
+      "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="
+    },
     "node_modules/resolve-from": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -4313,6 +4664,20 @@
         "node": ">=4"
       }
     },
+    "node_modules/responselike": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz",
+      "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==",
+      "dependencies": {
+        "lowercase-keys": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/reusify": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -5703,6 +6068,34 @@
         "fastq": "^1.6.0"
       }
     },
+    "@pnpm/config.env-replace": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz",
+      "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w=="
+    },
+    "@pnpm/network.ca-file": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz",
+      "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==",
+      "requires": {
+        "graceful-fs": "4.2.10"
+      }
+    },
+    "@pnpm/npm-conf": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz",
+      "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==",
+      "requires": {
+        "@pnpm/config.env-replace": "^1.1.0",
+        "@pnpm/network.ca-file": "^1.0.1",
+        "config-chain": "^1.1.11"
+      }
+    },
+    "@sindresorhus/is": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz",
+      "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g=="
+    },
     "@solidity-parser/parser": {
       "version": "0.16.0",
       "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.0.tgz",
@@ -5711,6 +6104,19 @@
         "antlr4ts": "^0.5.0-alpha.4"
       }
     },
+    "@szmarczak/http-timer": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz",
+      "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==",
+      "requires": {
+        "defer-to-connect": "^2.0.1"
+      }
+    },
+    "@types/http-cache-semantics": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz",
+      "integrity": "sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw=="
+    },
     "@types/json5": {
       "version": "0.0.29",
       "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@@ -5965,6 +6371,25 @@
         "update-browserslist-db": "^1.0.9"
       }
     },
+    "cacheable-lookup": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz",
+      "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w=="
+    },
+    "cacheable-request": {
+      "version": "10.2.14",
+      "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz",
+      "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==",
+      "requires": {
+        "@types/http-cache-semantics": "^4.0.2",
+        "get-stream": "^6.0.1",
+        "http-cache-semantics": "^4.1.1",
+        "keyv": "^4.5.3",
+        "mimic-response": "^4.0.0",
+        "normalize-url": "^8.0.0",
+        "responselike": "^3.0.0"
+      }
+    },
     "caching-transform": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
@@ -6102,6 +6527,15 @@
       "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
       "dev": true
     },
+    "config-chain": {
+      "version": "1.1.13",
+      "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
+      "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
+      "requires": {
+        "ini": "^1.3.4",
+        "proto-list": "~1.2.1"
+      }
+    },
     "confusing-browser-globals": {
       "version": "1.0.11",
       "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz",
@@ -6200,6 +6634,26 @@
       "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
       "dev": true
     },
+    "decompress-response": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+      "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+      "requires": {
+        "mimic-response": "^3.1.0"
+      },
+      "dependencies": {
+        "mimic-response": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+          "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="
+        }
+      }
+    },
+    "deep-extend": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+    },
     "deep-is": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -6215,6 +6669,11 @@
         "strip-bom": "^4.0.0"
       }
     },
+    "defer-to-connect": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
+      "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg=="
+    },
     "define-properties": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
@@ -6764,6 +7223,11 @@
         "mime-types": "^2.1.12"
       }
     },
+    "form-data-encoder": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz",
+      "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw=="
+    },
     "fromentries": {
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz",
@@ -6835,6 +7299,11 @@
       "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
       "dev": true
     },
+    "get-stream": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+      "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="
+    },
     "get-symbol-description": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
@@ -6920,11 +7389,28 @@
         "get-intrinsic": "^1.1.3"
       }
     },
+    "got": {
+      "version": "12.6.1",
+      "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz",
+      "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==",
+      "requires": {
+        "@sindresorhus/is": "^5.2.0",
+        "@szmarczak/http-timer": "^5.0.1",
+        "cacheable-lookup": "^7.0.0",
+        "cacheable-request": "^10.2.8",
+        "decompress-response": "^6.0.0",
+        "form-data-encoder": "^2.1.2",
+        "get-stream": "^6.0.1",
+        "http2-wrapper": "^2.1.10",
+        "lowercase-keys": "^3.0.0",
+        "p-cancelable": "^3.0.0",
+        "responselike": "^3.0.0"
+      }
+    },
     "graceful-fs": {
       "version": "4.2.10",
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
-      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
-      "dev": true
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
     },
     "grapheme-splitter": {
       "version": "1.0.4",
@@ -7028,6 +7514,11 @@
       "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
       "dev": true
     },
+    "http-cache-semantics": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+      "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
+    },
     "http-signature": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
@@ -7039,6 +7530,15 @@
         "sshpk": "^1.7.0"
       }
     },
+    "http2-wrapper": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz",
+      "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==",
+      "requires": {
+        "quick-lru": "^5.1.1",
+        "resolve-alpn": "^1.2.0"
+      }
+    },
     "husky": {
       "version": "8.0.3",
       "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz",
@@ -7085,6 +7585,11 @@
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
       "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
     },
+    "ini": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
+    },
     "internal-slot": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz",
@@ -7459,6 +7964,11 @@
       "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
       "dev": true
     },
+    "json-buffer": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
+    },
     "json-parse-even-better-errors": {
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
@@ -7505,6 +8015,22 @@
         "verror": "1.10.0"
       }
     },
+    "keyv": {
+      "version": "4.5.4",
+      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+      "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+      "requires": {
+        "json-buffer": "3.0.1"
+      }
+    },
+    "latest-version": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz",
+      "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==",
+      "requires": {
+        "package-json": "^8.1.0"
+      }
+    },
     "lcov-parse": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz",
@@ -7573,6 +8099,11 @@
         "is-unicode-supported": "^0.1.0"
       }
     },
+    "lowercase-keys": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
+      "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ=="
+    },
     "lru-cache": {
       "version": "5.1.1",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -7623,6 +8154,11 @@
         "mime-db": "1.52.0"
       }
     },
+    "mimic-response": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz",
+      "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg=="
+    },
     "minimatch": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -7635,8 +8171,7 @@
     "minimist": {
       "version": "1.2.7",
       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
-      "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
-      "dev": true
+      "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g=="
     },
     "mocha": {
       "version": "10.2.0",
@@ -7774,6 +8309,11 @@
       "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
       "dev": true
     },
+    "normalize-url": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz",
+      "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw=="
+    },
     "nyc": {
       "version": "15.1.0",
       "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
@@ -8009,6 +8549,11 @@
         "word-wrap": "^1.2.3"
       }
     },
+    "p-cancelable": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz",
+      "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw=="
+    },
     "p-limit": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -8054,6 +8599,17 @@
         "release-zalgo": "^1.0.0"
       }
     },
+    "package-json": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz",
+      "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==",
+      "requires": {
+        "got": "^12.1.0",
+        "registry-auth-token": "^5.0.1",
+        "registry-url": "^6.0.0",
+        "semver": "^7.3.7"
+      }
+    },
     "parent-module": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -8203,6 +8759,11 @@
         "fromentries": "^1.2.0"
       }
     },
+    "proto-list": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
+      "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="
+    },
     "psl": {
       "version": "1.9.0",
       "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@@ -8226,6 +8787,11 @@
       "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
       "dev": true
     },
+    "quick-lru": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+      "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="
+    },
     "randombytes": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -8235,6 +8801,24 @@
         "safe-buffer": "^5.1.0"
       }
     },
+    "rc": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+      "requires": {
+        "deep-extend": "^0.6.0",
+        "ini": "~1.3.0",
+        "minimist": "^1.2.0",
+        "strip-json-comments": "~2.0.1"
+      },
+      "dependencies": {
+        "strip-json-comments": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+          "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="
+        }
+      }
+    },
     "readdirp": {
       "version": "3.6.0",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -8270,6 +8854,22 @@
       "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
       "dev": true
     },
+    "registry-auth-token": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz",
+      "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==",
+      "requires": {
+        "@pnpm/npm-conf": "^2.1.0"
+      }
+    },
+    "registry-url": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz",
+      "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==",
+      "requires": {
+        "rc": "1.2.8"
+      }
+    },
     "release-zalgo": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
@@ -8349,11 +8949,24 @@
         "supports-preserve-symlinks-flag": "^1.0.0"
       }
     },
+    "resolve-alpn": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
+      "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="
+    },
     "resolve-from": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
       "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
     },
+    "responselike": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz",
+      "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==",
+      "requires": {
+        "lowercase-keys": "^3.0.0"
+      }
+    },
     "reusify": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
diff --git a/package.json b/package.json
index a0d0b55..79a21f8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "solhint",
-  "version": "3.6.2",
+  "version": "4.0.0",
   "description": "Solidity Code Linter",
   "main": "lib/index.js",
   "keywords": [
@@ -35,6 +35,7 @@
     "/solhint.js"
   ],
   "author": "Ilya Drabenia <ilya.drobenya@gmail.com>",
+  "contributors": ["Diego Bale <diego.bale@protofire.io>"],
   "license": "MIT",
   "dependencies": {
     "@solidity-parser/parser": "^0.16.0",
@@ -48,6 +49,7 @@
     "glob": "^8.0.3",
     "ignore": "^5.2.4",
     "js-yaml": "^4.1.0",
+    "latest-version": "^7.0.0",
     "lodash": "^4.17.21",
     "pluralize": "^8.0.0",
     "semver": "^7.5.2",
diff --git a/scripts/generate-rule-docs.js b/scripts/generate-rule-docs.js
index c170bb7..8b2c995 100755
--- a/scripts/generate-rule-docs.js
+++ b/scripts/generate-rule-docs.js
@@ -191,23 +191,26 @@ function linkToVersion(version) {
 }
 
 function linkToSource(rule) {
-  const link = rule.file.replace(path.resolve(path.join(__dirname, '..')), '')
+  const link = localPathToUri(rule.file)
   return `https://github.com/protofire/solhint/tree/master${link}`
 }
 
 function linkToDocumentSource(rule) {
-  const link = rule.file
-    .replace(path.resolve(path.join(__dirname, '..')), '')
+  const link = localPathToUri(rule.file)
     .replace('lib/rules', 'docs/rules')
     .replace(/\.js$/, '.md')
   return `https://github.com/protofire/solhint/tree/master${link}`
 }
 
 function linkToTestCase(rule) {
-  const link = rule.file.replace(path.resolve(path.join(__dirname, '..', 'lib', 'rules')), '')
+  const link = localPathToUri(rule.file).replace('lib/rules/', '')
   return `https://github.com/protofire/solhint/tree/master/test/rules${link}`
 }
 
+function localPathToUri(file) {
+  return file.replace(path.resolve(path.join(__dirname, '..')), '').split(path.sep).join('/')
+}
+
 function loadExamples(rule) {
   if (!rule.meta.docs.examples) {
     return 'This rule does not have examples.'
diff --git a/solhint.js b/solhint.js
index f1d6400..520a6e5 100644
--- a/solhint.js
+++ b/solhint.js
@@ -1,9 +1,9 @@
 #!/usr/bin/env node
-
 const program = require('commander')
 const _ = require('lodash')
 const fs = require('fs')
 const process = require('process')
+const readline = require('readline')
 
 const linter = require('./lib/index')
 const { loadConfig } = require('./lib/config/config-file')
@@ -27,8 +27,12 @@ function init() {
     .option('-c, --config [file_name]', 'file to use as your .solhint.json')
     .option('-q, --quiet', 'report errors only - default: false')
     .option('--ignore-path [file_name]', 'file to use as your .solhintignore')
-    .option('--fix', 'automatically fix problems')
+    .option('--fix', 'automatically fix problems. Skips fixes in report')
+    // .option('--fixShow', 'automatically fix problems. Show fixes in report')
+    .option('--noPrompt', 'do not suggest to backup files when any `fix` option is selected')
     .option('--init', 'create configuration file for solhint')
+    .option('--disc', 'do not check for solhint updates')
+    .option('--save', 'save report to file on current folder')
     .description('Linter for Solidity programming language')
     .action(execMainAction)
 
@@ -53,10 +57,60 @@ function init() {
   if (process.argv.length <= 2) {
     program.help()
   }
+
   program.parse(process.argv)
 }
 
+function askUserToContinue(callback) {
+  const rl = readline.createInterface({
+    input: process.stdin,
+    output: process.stdout,
+  })
+
+  rl.question(
+    '\nFIX option detected. Solhint will modify your files whenever it finds a fix for a rule error. Please BACKUP your contracts first. \nContinue ? (y/n) ',
+    (answer) => {
+      // Close the readline interface.
+      rl.close()
+
+      // Normalize and pass the user's answer to the callback function.
+      const normalizedAnswer = answer.trim().toLowerCase()
+      callback(normalizedAnswer)
+    }
+  )
+}
+
 function execMainAction() {
+  // if ((program.opts().fix || program.opts().fixShow) && !program.opts().noPrompt) {
+  if (program.opts().fix && !program.opts().noPrompt) {
+    askUserToContinue((userAnswer) => {
+      if (userAnswer !== 'y') {
+        console.log('\nProcess terminated by user')
+        process.exit(0)
+      } else {
+        // User agreed, continue with the operation.
+        continueExecution()
+      }
+    })
+  } else {
+    // No need for user input, continue with the operation.
+    continueExecution()
+  }
+
+  function continueExecution() {
+    if (program.opts().disc) {
+      executeMainActionLogic()
+    } else {
+      // Call checkForUpdate and wait for it to complete using .then()
+      checkForUpdate().then(() => {
+        // This block runs after checkForUpdate is complete
+        executeMainActionLogic()
+      })
+    }
+  }
+}
+
+function executeMainActionLogic() {
   if (program.opts().init) {
     writeSampleConfigFile()
   }
@@ -73,6 +127,7 @@ function execMainAction() {
   const reportLists = program.args.filter(_.isString).map(processPath)
   const reports = _.flatten(reportLists)
 
+  // if (program.opts().fix || program.opts().fixShow) {
   if (program.opts().fix) {
     for (const report of reports) {
       const inputSrc = fs.readFileSync(report.filePath).toString()
@@ -85,8 +140,26 @@ function execMainAction() {
 
       const { fixed, output } = applyFixes(fixes, inputSrc)
       if (fixed) {
-        report.reports = report.reports.filter((x) => !x.fix)
-        fs.writeFileSync(report.filePath, output)
+        // // skip or not the report when fixed
+        // // This was filtering fixed rules so status code was not 1
+        // if (program.opts().fix) {
+        //   report.reports = report.reports.filter((x) => !x.fix)
+        // } else {
+        // console.log('report.reports :>> ', report.reports)
+        report.reports.forEach((report) => {
+          if (report.fix !== null) {
+            report.message = `[FIXED] - ${report.message}`
+          }
+        })
+        // }
+
+        // fs.writeFileSync(report.filePath, output)
+        try {
+          fs.writeFileSync(report.filePath, output)
+          // fs.writeFileSync('no-console/Foo1Modified.sol', output)
+        } catch (error) {
+          console.error('An error occurred while writing the file:', error)
+        }
       }
     }
   }
@@ -216,12 +289,40 @@ function printReports(reports, formatter) {
     }
   }
 
-  console.log(formatter(reports), finalMessage || '')
+  const fullReport = formatter(reports) + (finalMessage || '')
+  console.log(fullReport)
+
+  if (program.opts().save) {
+    writeStringToFile(fullReport)
+  }
 
   if (exitWithOne) process.exit(1)
   return reports
 }
 
+function writeStringToFile(data) {
+  const now = new Date()
+  const year = now.getFullYear()
+  const month = String(now.getMonth() + 1).padStart(2, '0') // Months are zero-based
+  const day = String(now.getDate()).padStart(2, '0')
+  const hour = String(now.getHours()).padStart(2, '0')
+  const minute = String(now.getMinutes()).padStart(2, '0')
+  const second = String(now.getSeconds()).padStart(2, '0')
+
+  const fileName = `${year}${month}${day}${hour}${minute}${second}_solhintReport.txt`
+
+  // Remove ANSI escape codes from the data
+  // eslint-disable-next-line no-control-regex
+  const cleanedData = data.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, '')
+
+  try {
+    fs.writeFileSync(fileName, cleanedData, 'utf-8') // Specify the encoding (UTF-16)
+    // console.log('File written successfully:', fileName)
+  } catch (err) {
+    console.error('Error writing to file:', err)
+  }
+}
+
 function getFormatter(formatter) {
   const formatterName = formatter || 'stylish'
   try {
@@ -235,12 +336,20 @@ function getFormatter(formatter) {
 }
 
 function listRules() {
-  if (process.argv.length !== 3) {
+  const args = process.argv.slice(2)
+  let configPath = '.solhint.json'
+  const configFileIndex = args.findIndex((arg) => arg === '-c' || arg === '--config')
+  if (configFileIndex !== -1) {
+    configPath = args[configFileIndex + 1]
+    if (!configPath || configPath.startsWith('-')) {
+      console.error('Error: Invalid configuration file path after -c or --config flag.')
+      process.exit(1)
+    }
+  } else if (args.length !== 1) {
     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)
@@ -271,4 +380,27 @@ function exitWithCode(reports) {
   process.exit(errorsCount > 0 ? 1 : 0)
 }
 
+function checkForUpdate() {
+  // eslint-disable-next-line import/no-extraneous-dependencies
+  return import('latest-version')
+    .then((latestVersionModule) => {
+      const latestVersion = latestVersionModule.default
+      const currentVersion = require('./package.json').version
+
+      return latestVersion('solhint')
+        .then((latest) => {
+          if (currentVersion < latest) {
+            console.log('A new version of Solhint is available:', latest)
+            console.log('Please consider updating your Solhint package.')
+          }
+        })
+        .catch((error) => {
+          console.error('Error checking for updates:', error.message)
+        })
+    })
+    .catch((error) => {
+      console.error('Error importing latest-version:', error.message)
+    })
+}
+
 init()


Test patch:
diff --git a/e2e/06-formatters/helpers/helpers.js b/e2e/06-formatters/helpers/helpers.js
index 85d43c6..8376310 100644
--- a/e2e/06-formatters/helpers/helpers.js
+++ b/e2e/06-formatters/helpers/helpers.js
@@ -32,7 +32,6 @@ const foo1Output = [
     severity: 'Warning',
     message: "'TEST2' should start with _",
     ruleId: 'private-vars-leading-underscore',
-    fix: null,
     filePath: 'contracts/Foo.sol',
   },
   {
diff --git a/e2e/08-autofix/commands/.solhint.json b/e2e/08-autofix/commands/.solhint.json
new file mode 100644
index 0000000..7bd7c6a
--- /dev/null
+++ b/e2e/08-autofix/commands/.solhint.json
@@ -0,0 +1,5 @@
+{
+  "rules": {
+    "explicit-types": ["error", "explicit"]
+  }
+}
diff --git a/e2e/08-autofix/commands/Foo1.sol b/e2e/08-autofix/commands/Foo1.sol
new file mode 100644
index 0000000..78bcaec
--- /dev/null
+++ b/e2e/08-autofix/commands/Foo1.sol
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.4;
+
+import {ERC20Burnable} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol';
+
+contract Foo1 is ERC20Burnable {
+    uint public hola;
+    uint public hola2;
+    int public constant hola3 = 2;
+    ufixed hola4;
+    fixed internal hola5;
+
+    constructor() ERC20('MyToken', 'MTK') {}
+
+    // solhint-disable no-empty-blocks
+    function payableTrue() public payable {}
+
+    // solhint-disable no-empty-blocks
+    function payableFalse() public {}
+
+    function zarasa() {}
+}
diff --git a/e2e/08-autofix/commands/Foo1AfterFix.sol b/e2e/08-autofix/commands/Foo1AfterFix.sol
new file mode 100644
index 0000000..ca900d6
--- /dev/null
+++ b/e2e/08-autofix/commands/Foo1AfterFix.sol
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.4;
+
+import {ERC20Burnable} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol';
+
+contract Foo1 is ERC20Burnable {
+    uint256 public hola;
+    uint256 public hola2;
+    int256 public constant hola3 = 2;
+    ufixed128x18 hola4;
+    fixed128x18 internal hola5;
+
+    constructor() ERC20('MyToken', 'MTK') {}
+
+    // solhint-disable no-empty-blocks
+    function payableTrue() public payable {}
+
+    // solhint-disable no-empty-blocks
+    function payableFalse() public {}
+
+    function zarasa() {}
+}
diff --git a/e2e/08-autofix/commands/Foo1BeforeFix.sol b/e2e/08-autofix/commands/Foo1BeforeFix.sol
new file mode 100644
index 0000000..78bcaec
--- /dev/null
+++ b/e2e/08-autofix/commands/Foo1BeforeFix.sol
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.4;
+
+import {ERC20Burnable} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol';
+
+contract Foo1 is ERC20Burnable {
+    uint public hola;
+    uint public hola2;
+    int public constant hola3 = 2;
+    ufixed hola4;
+    fixed internal hola5;
+
+    constructor() ERC20('MyToken', 'MTK') {}
+
+    // solhint-disable no-empty-blocks
+    function payableTrue() public payable {}
+
+    // solhint-disable no-empty-blocks
+    function payableFalse() public {}
+
+    function zarasa() {}
+}
diff --git a/e2e/08-autofix/explicit-types/.solhint.json b/e2e/08-autofix/explicit-types/.solhint.json
new file mode 100644
index 0000000..7bd7c6a
--- /dev/null
+++ b/e2e/08-autofix/explicit-types/.solhint.json
@@ -0,0 +1,5 @@
+{
+  "rules": {
+    "explicit-types": ["error", "explicit"]
+  }
+}
diff --git a/e2e/08-autofix/explicit-types/Foo1.sol b/e2e/08-autofix/explicit-types/Foo1.sol
new file mode 100644
index 0000000..78bcaec
--- /dev/null
+++ b/e2e/08-autofix/explicit-types/Foo1.sol
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.4;
+
+import {ERC20Burnable} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol';
+
+contract Foo1 is ERC20Burnable {
+    uint public hola;
+    uint public hola2;
+    int public constant hola3 = 2;
+    ufixed hola4;
+    fixed internal hola5;
+
+    constructor() ERC20('MyToken', 'MTK') {}
+
+    // solhint-disable no-empty-blocks
+    function payableTrue() public payable {}
+
+    // solhint-disable no-empty-blocks
+    function payableFalse() public {}
+
+    function zarasa() {}
+}
diff --git a/e2e/08-autofix/explicit-types/Foo1AfterFix.sol b/e2e/08-autofix/explicit-types/Foo1AfterFix.sol
new file mode 100644
index 0000000..ca900d6
--- /dev/null
+++ b/e2e/08-autofix/explicit-types/Foo1AfterFix.sol
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.4;
+
+import {ERC20Burnable} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol';
+
+contract Foo1 is ERC20Burnable {
+    uint256 public hola;
+    uint256 public hola2;
+    int256 public constant hola3 = 2;
+    ufixed128x18 hola4;
+    fixed128x18 internal hola5;
+
+    constructor() ERC20('MyToken', 'MTK') {}
+
+    // solhint-disable no-empty-blocks
+    function payableTrue() public payable {}
+
+    // solhint-disable no-empty-blocks
+    function payableFalse() public {}
+
+    function zarasa() {}
+}
diff --git a/e2e/08-autofix/explicit-types/Foo1BeforeFix.sol b/e2e/08-autofix/explicit-types/Foo1BeforeFix.sol
new file mode 100644
index 0000000..78bcaec
--- /dev/null
+++ b/e2e/08-autofix/explicit-types/Foo1BeforeFix.sol
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.4;
+
+import {ERC20Burnable} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol';
+
+contract Foo1 is ERC20Burnable {
+    uint public hola;
+    uint public hola2;
+    int public constant hola3 = 2;
+    ufixed hola4;
+    fixed internal hola5;
+
+    constructor() ERC20('MyToken', 'MTK') {}
+
+    // solhint-disable no-empty-blocks
+    function payableTrue() public payable {}
+
+    // solhint-disable no-empty-blocks
+    function payableFalse() public {}
+
+    function zarasa() {}
+}
diff --git a/e2e/08-autofix/no-console/.solhint.json b/e2e/08-autofix/no-console/.solhint.json
new file mode 100644
index 0000000..2ff50f9
--- /dev/null
+++ b/e2e/08-autofix/no-console/.solhint.json
@@ -0,0 +1,5 @@
+{
+  "rules": {
+    "no-console": "error"
+  }
+}
diff --git a/e2e/08-autofix/no-console/Foo1.sol b/e2e/08-autofix/no-console/Foo1.sol
new file mode 100644
index 0000000..93b6d39
--- /dev/null
+++ b/e2e/08-autofix/no-console/Foo1.sol
@@ -0,0 +1,37 @@
+pragma solidity 0.8.0;
+
+import 'hardhat/console.sol';
+import 'forge-std/console.sol';
+import 'forge-std/console2.sol';
+import 'forge-std/xxxxx.sol';
+
+contract Foo1 {
+    Console[] public consoleTest;
+    Console[] public console;
+
+    struct Console {
+        uint256 one;
+        uint256 two;
+    }
+
+    function a() public {
+        console.log('test');
+        // comment
+        console.logString('test logString');
+        uint256 declaration;
+        console.logBytes12('test logBytes12');
+    }
+
+    function b() public {
+        console2.log('test console 2');
+        // comment
+        console.logString('test logString');
+        uint256 declaration;
+        console.logBytes12('test');
+    }
+
+    function c() external {
+        consoleTest.push(0, 0);
+        console.push = (1, 1);
+    }
+}
diff --git a/e2e/08-autofix/no-console/Foo1AfterFix.sol b/e2e/08-autofix/no-console/Foo1AfterFix.sol
new file mode 100644
index 0000000..2207537
--- /dev/null
+++ b/e2e/08-autofix/no-console/Foo1AfterFix.sol
@@ -0,0 +1,37 @@
+pragma solidity 0.8.0;
+
+
+
+
+import 'forge-std/xxxxx.sol';
+
+contract Foo1 {
+    Console[] public consoleTest;
+    Console[] public console;
+
+    struct Console {
+        uint256 one;
+        uint256 two;
+    }
+
+    function a() public {
+        
+        // comment
+        
+        uint256 declaration;
+        
+    }
+
+    function b() public {
+        
+        // comment
+        
+        uint256 declaration;
+        
+    }
+
+    function c() external {
+        consoleTest.push(0, 0);
+        console.push = (1, 1);
+    }
+}
diff --git a/e2e/08-autofix/no-console/Foo1BeforeFix.sol b/e2e/08-autofix/no-console/Foo1BeforeFix.sol
new file mode 100644
index 0000000..93b6d39
--- /dev/null
+++ b/e2e/08-autofix/no-console/Foo1BeforeFix.sol
@@ -0,0 +1,37 @@
+pragma solidity 0.8.0;
+
+import 'hardhat/console.sol';
+import 'forge-std/console.sol';
+import 'forge-std/console2.sol';
+import 'forge-std/xxxxx.sol';
+
+contract Foo1 {
+    Console[] public consoleTest;
+    Console[] public console;
+
+    struct Console {
+        uint256 one;
+        uint256 two;
+    }
+
+    function a() public {
+        console.log('test');
+        // comment
+        console.logString('test logString');
+        uint256 declaration;
+        console.logBytes12('test logBytes12');
+    }
+
+    function b() public {
+        console2.log('test console 2');
+        // comment
+        console.logString('test logString');
+        uint256 declaration;
+        console.logBytes12('test');
+    }
+
+    function c() external {
+        consoleTest.push(0, 0);
+        console.push = (1, 1);
+    }
+}
diff --git a/e2e/08-autofix/private-vars-underscore/.solhint.json b/e2e/08-autofix/private-vars-underscore/.solhint.json
new file mode 100644
index 0000000..47ff676
--- /dev/null
+++ b/e2e/08-autofix/private-vars-underscore/.solhint.json
@@ -0,0 +1,5 @@
+{
+  "rules": {
+    "private-vars-leading-underscore": ["error",{"strict":false}]
+  }
+}
diff --git a/e2e/08-autofix/private-vars-underscore/Foo1.sol b/e2e/08-autofix/private-vars-underscore/Foo1.sol
new file mode 100644
index 0000000..f8a0751
--- /dev/null
+++ b/e2e/08-autofix/private-vars-underscore/Foo1.sol
@@ -0,0 +1,83 @@
+pragma solidity 0.8.0;
+
+library libraryName {
+    uint256 internal lzarasa1;
+    uint256 internal lzarasa2 = 2;
+    uint256 internal _lzarasa3;
+    uint256 private lzarasa4;
+    uint256 private lzarasa5 = 5;
+    uint256 private _lzarasa6;
+
+    uint256 public _lzarasa7;
+    uint256 public _lzarasa8 = 8;
+    uint256 public lzarasa9;
+
+    function fofo1() public {}
+    function _fofo2() public {}
+    function _fofo3() internal {}
+    function fofo4() internal {}
+}
+
+contract Foo1 {
+    uint256 internal zarasa1;
+    uint256 internal zarasa2 = 2;
+    uint256 internal _zarasa3;
+    uint256 private zarasa4;
+    uint256 private zarasa5 = 5;
+    uint256 private _zarasa6;
+
+    uint256 public _zarasa7;
+    uint256 public _zarasa8 = 8;
+    uint256 public zarasa9;
+
+    address payable internal constant zarasa10 = '0x0';
+    address public constant _zarasa11 = '0x0';
+    uint256 public immutable _zarasa12 = 2;
+    uint256 _zarasa13;
+    uint256 zarasa14;
+
+    mapping(address => uint256) internal zarMapping1;
+    mapping(address => uint256) public _zarMapping2;
+    mapping(address => uint256) internal _zarMapping3;
+    mapping(address => uint256) public zarMapping4;
+
+    function fooA(uint bar) internal payable onlyOwner returns (uint256 barA) {
+        uint256 zarasaFunc;
+    }
+
+    function fooB(uint bar) private onlyOwner returns (uint256 _barB) {
+        uint256 zarasaFunc;
+    }
+
+    function fooC(uint bar) private onlyOwner returns (uint256 _barC) {
+        uint256 zarasaFunc;
+    }
+
+    function fooD(uint bar) external onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function fooE(uint bar) public onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function fooF(uint bar) onlyOwner returns (uint256 _barF) {
+        uint256 zarasaFunc;
+    }
+
+    function fooG(uint bar) onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function _fooH(uint bar) external onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function _fooI(uint bar) public onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function _fooJ(uint bar) onlyOwner returns (uint256 barJ) {
+        uint256 zarasaFunc;
+    }
+}
diff --git a/e2e/08-autofix/private-vars-underscore/Foo1AfterFix.sol b/e2e/08-autofix/private-vars-underscore/Foo1AfterFix.sol
new file mode 100644
index 0000000..87b80ad
--- /dev/null
+++ b/e2e/08-autofix/private-vars-underscore/Foo1AfterFix.sol
@@ -0,0 +1,83 @@
+pragma solidity 0.8.0;
+
+library libraryName {
+    uint256 internal _lzarasa1;
+    uint256 internal _lzarasa2 = 2;
+    uint256 internal _lzarasa3;
+    uint256 private _lzarasa4;
+    uint256 private _lzarasa5 = 5;
+    uint256 private _lzarasa6;
+
+    uint256 public lzarasa7;
+    uint256 public lzarasa8 = 8;
+    uint256 public lzarasa9;
+
+    function fofo1() public {}
+    function fofo2() public {}
+    function _fofo3() internal {}
+    function _fofo4() internal {}
+}
+
+contract Foo1 {
+    uint256 internal _zarasa1;
+    uint256 internal _zarasa2 = 2;
+    uint256 internal _zarasa3;
+    uint256 private _zarasa4;
+    uint256 private _zarasa5 = 5;
+    uint256 private _zarasa6;
+
+    uint256 public zarasa7;
+    uint256 public zarasa8 = 8;
+    uint256 public zarasa9;
+
+    address payable internal constant _zarasa10 = '0x0';
+    address public constant zarasa11 = '0x0';
+    uint256 public immutable zarasa12 = 2;
+    uint256 _zarasa13;
+    uint256 _zarasa14;
+
+    mapping(address => uint256) internal _zarMapping1;
+    mapping(address => uint256) public zarMapping2;
+    mapping(address => uint256) internal _zarMapping3;
+    mapping(address => uint256) public zarMapping4;
+
+    function _fooA(uint bar) internal payable onlyOwner returns (uint256 barA) {
+        uint256 zarasaFunc;
+    }
+
+    function _fooB(uint bar) private onlyOwner returns (uint256 _barB) {
+        uint256 zarasaFunc;
+    }
+
+    function _fooC(uint bar) private onlyOwner returns (uint256 _barC) {
+        uint256 zarasaFunc;
+    }
+
+    function fooD(uint bar) external onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function fooE(uint bar) public onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function _fooF(uint bar) onlyOwner returns (uint256 _barF) {
+        uint256 zarasaFunc;
+    }
+
+    function _fooG(uint bar) onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function fooH(uint bar) external onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function fooI(uint bar) public onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function _fooJ(uint bar) onlyOwner returns (uint256 barJ) {
+        uint256 zarasaFunc;
+    }
+}
diff --git a/e2e/08-autofix/private-vars-underscore/Foo1BeforeFix.sol b/e2e/08-autofix/private-vars-underscore/Foo1BeforeFix.sol
new file mode 100644
index 0000000..f8a0751
--- /dev/null
+++ b/e2e/08-autofix/private-vars-underscore/Foo1BeforeFix.sol
@@ -0,0 +1,83 @@
+pragma solidity 0.8.0;
+
+library libraryName {
+    uint256 internal lzarasa1;
+    uint256 internal lzarasa2 = 2;
+    uint256 internal _lzarasa3;
+    uint256 private lzarasa4;
+    uint256 private lzarasa5 = 5;
+    uint256 private _lzarasa6;
+
+    uint256 public _lzarasa7;
+    uint256 public _lzarasa8 = 8;
+    uint256 public lzarasa9;
+
+    function fofo1() public {}
+    function _fofo2() public {}
+    function _fofo3() internal {}
+    function fofo4() internal {}
+}
+
+contract Foo1 {
+    uint256 internal zarasa1;
+    uint256 internal zarasa2 = 2;
+    uint256 internal _zarasa3;
+    uint256 private zarasa4;
+    uint256 private zarasa5 = 5;
+    uint256 private _zarasa6;
+
+    uint256 public _zarasa7;
+    uint256 public _zarasa8 = 8;
+    uint256 public zarasa9;
+
+    address payable internal constant zarasa10 = '0x0';
+    address public constant _zarasa11 = '0x0';
+    uint256 public immutable _zarasa12 = 2;
+    uint256 _zarasa13;
+    uint256 zarasa14;
+
+    mapping(address => uint256) internal zarMapping1;
+    mapping(address => uint256) public _zarMapping2;
+    mapping(address => uint256) internal _zarMapping3;
+    mapping(address => uint256) public zarMapping4;
+
+    function fooA(uint bar) internal payable onlyOwner returns (uint256 barA) {
+        uint256 zarasaFunc;
+    }
+
+    function fooB(uint bar) private onlyOwner returns (uint256 _barB) {
+        uint256 zarasaFunc;
+    }
+
+    function fooC(uint bar) private onlyOwner returns (uint256 _barC) {
+        uint256 zarasaFunc;
+    }
+
+    function fooD(uint bar) external onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function fooE(uint bar) public onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function fooF(uint bar) onlyOwner returns (uint256 _barF) {
+        uint256 zarasaFunc;
+    }
+
+    function fooG(uint bar) onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function _fooH(uint bar) external onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function _fooI(uint bar) public onlyOwner {
+        uint256 zarasaFunc;
+    }
+
+    function _fooJ(uint bar) onlyOwner returns (uint256 barJ) {
+        uint256 zarasaFunc;
+    }
+}
diff --git a/e2e/autofix-test.js b/e2e/autofix-test.js
new file mode 100644
index 0000000..1f11d18
--- /dev/null
+++ b/e2e/autofix-test.js
@@ -0,0 +1,276 @@
+const chai = require('chai')
+const { expect } = chai
+const fs = require('fs-extra')
+const os = require('os')
+const path = require('path')
+const shell = require('shelljs')
+const spawnSync = require('spawn-sync')
+
+const E2E = true
+
+let params
+let currentConfig
+let currentFile
+let beforeFixFile
+let afterFixFile
+
+function retrieveParams(subpath) {
+  if (E2E) {
+    return { command: 'solhint', param1: '', path: '', subpath }
+  } else {
+    return { command: 'node', param1: 'solhint', path: 'e2e/08-autofix/', subpath }
+  }
+}
+
+function compareTextFiles(file1Path, file2Path) {
+  const file1Content = fs.readFileSync(file1Path, 'utf-8')
+  const file2Content = fs.readFileSync(file2Path, 'utf-8')
+
+  return file1Content === file2Content
+}
+
+function copyFile(sourcePath, destinationPath) {
+  shell.cp(sourcePath, destinationPath)
+}
+
+function useFixture(dir) {
+  beforeEach(`switch to ${dir}`, function () {
+    const fixturePath = path.join(__dirname, dir)
+
+    const tmpDirContainer = os.tmpdir()
+    this.testDirPath = path.join(tmpDirContainer, `solhint-tests-${dir}`)
+
+    fs.ensureDirSync(this.testDirPath)
+    fs.emptyDirSync(this.testDirPath)
+
+    fs.copySync(fixturePath, this.testDirPath)
+
+    shell.cd(this.testDirPath)
+  })
+}
+
+describe('e2e', function () {
+  let result = false
+
+  describe('autofix tests', () => {
+    if (E2E) {
+      useFixture('08-autofix')
+    }
+
+    describe('autofix command line options', () => {
+      before(function () {
+        params = retrieveParams('commands/')
+        currentConfig = `${params.path}${params.subpath}.solhint.json`
+        currentFile = `${params.path}${params.subpath}Foo1.sol`
+        beforeFixFile = `${params.path}${params.subpath}Foo1BeforeFix.sol`
+        afterFixFile = `${params.path}${params.subpath}Foo1AfterFix.sol`
+      })
+
+      describe('--fix without noPrompt', () => {
+        after(function () {
+          if (!E2E) {
+            copyFile(beforeFixFile, currentFile)
+          }
+        })
+
+        it('should terminate with --fix and user choose NOT to continue', () => {
+          const solhintProcess = spawnSync(
+            `${params.command}`,
+            [`${params.param1}`, '-c', currentConfig, currentFile, '--fix', '--disc'],
+            {
+              input: 'n\n', // Provide 'n' as input
+              shell: true,
+            }
+          )
+
+          expect(solhintProcess.status).to.equal(0)
+          expect(solhintProcess.stdout.toString().includes('Process terminated by user'))
+        })
+
+        it('should compare Foo1 file with template beforeFix file and they should match 1a', () => {
+          result = compareTextFiles(currentFile, beforeFixFile)
+          expect(result).to.be.true
+        })
+
+        it('should fix with --fix and user choose YES to continue', () => {
+          const solhintProcess = spawnSync(
+            `${params.command}`,
+            [`${params.param1}`, '-c', currentConfig, currentFile, '--fix', '--disc'],
+            {
+              input: 'y\n', // Provide 'y' as input
+              shell: true,
+            }
+          )
+
+          expect(solhintProcess.status).to.equal(1)
+          expect(solhintProcess.stdout.toString().includes('5 problems (5 errors, 0 warnings)'))
+        })
+      })
+      it('should check FOO1 does not change after test 1a', () => {
+        result = compareTextFiles(currentFile, beforeFixFile)
+        expect(result).to.be.true
+      })
+
+      describe('--fix with noPrompt', () => {
+        after(function () {
+          if (!E2E) {
+            copyFile(beforeFixFile, currentFile)
+          }
+        })
+
+        it('should compare Foo1 file with template beforeFix file and they should match 1b', () => {
+          result = compareTextFiles(currentFile, beforeFixFile)
+          expect(result).to.be.true
+        })
+
+        it('should fix file when noPrompt 1b', () => {
+          const { code, stdout } = shell.exec(
+            `${params.command} ${params.param1} -c ${currentConfig} ${currentFile} --fix --disc --noPrompt`
+          )
+
+          expect(code).to.equal(1)
+
+          const reportLines = stdout.split('\n')
+          const finalLine = '5 problems (5 errors, 0 warnings)'
+          expect(reportLines[reportLines.length - 3]).to.contain(finalLine)
+
+          result = compareTextFiles(currentFile, afterFixFile)
+          expect(result).to.be.true
+        })
+      })
+
+      it('should check FOO1 does not change after test 1b', () => {
+        result = compareTextFiles(currentFile, beforeFixFile)
+        expect(result).to.be.true
+      })
+    })
+
+    describe('autofix rule: explicit-types', () => {
+      before(function () {
+        params = retrieveParams('explicit-types/')
+        currentConfig = `${params.path}${params.subpath}.solhint.json`
+        currentFile = `${params.path}${params.subpath}Foo1.sol`
+        beforeFixFile = `${params.path}${params.subpath}Foo1BeforeFix.sol`
+        afterFixFile = `${params.path}${params.subpath}Foo1AfterFix.sol`
+      })
+      describe('--fix with noPrompt', () => {
+        after(function () {
+          if (!E2E) {
+            copyFile(beforeFixFile, currentFile)
+          }
+        })
+
+        it('should compare Foo1 file with template BEFORE FIX file and they should match 2', () => {
+          result = compareTextFiles(currentFile, beforeFixFile)
+          expect(result).to.be.true
+        })
+
+        it('should compare Foo1 file with template AFTER FIX file and they should match 2', () => {
+          const { code, stdout } = shell.exec(
+            `${params.command} ${params.param1} -c ${currentConfig} ${currentFile} --fix --disc --noPrompt`
+          )
+
+          expect(code).to.equal(1)
+
+          const reportLines = stdout.split('\n')
+          const finalLine = '5 problems (5 errors, 0 warnings)'
+          expect(reportLines[reportLines.length - 3]).to.contain(finalLine)
+
+          result = compareTextFiles(currentFile, afterFixFile)
+          expect(result).to.be.true
+        })
+      })
+
+      it('should check FOO1 does not change after test 2', () => {
+        result = compareTextFiles(currentFile, beforeFixFile)
+        expect(result).to.be.true
+      })
+    })
+
+    describe('autofix rule: no-console', () => {
+      before(function () {
+        params = retrieveParams('no-console/')
+        currentConfig = `${params.path}${params.subpath}.solhint.json`
+        currentFile = `${params.path}${params.subpath}Foo1.sol`
+        beforeFixFile = `${params.path}${params.subpath}Foo1BeforeFix.sol`
+        afterFixFile = `${params.path}${params.subpath}Foo1AfterFix.sol`
+      })
+      describe('--fix with noPrompt', () => {
+        after(function () {
+          if (!E2E) {
+            copyFile(beforeFixFile, currentFile)
+          }
+        })
+
+        it('should compare Foo1 file with template BEFORE FIX file and they should match 3', () => {
+          result = compareTextFiles(currentFile, beforeFixFile)
+          expect(result).to.be.true
+        })
+
+        it('should compare Foo1 file with template AFTER FIX file and they should match 3', () => {
+          const { code, stdout } = shell.exec(
+            `${params.command} ${params.param1} -c ${currentConfig} ${currentFile} --fix --disc --noPrompt`
+          )
+
+          expect(code).to.equal(1)
+
+          const reportLines = stdout.split('\n')
+          const finalLine = '9 problems (9 errors, 0 warnings)'
+          expect(reportLines[reportLines.length - 3]).to.contain(finalLine)
+
+          result = compareTextFiles(currentFile, afterFixFile)
+          expect(result).to.be.true
+        })
+      })
+
+      it('should check FOO1 does not change after test 3', () => {
+        result = compareTextFiles(currentFile, beforeFixFile)
+        expect(result).to.be.true
+      })
+    })
+
+    describe('autofix rule: private-vars-leading-underscore', () => {
+      before(function () {
+        params = retrieveParams('private-vars-underscore/')
+        currentConfig = `${params.path}${params.subpath}.solhint.json`
+        currentFile = `${params.path}${params.subpath}Foo1.sol`
+        beforeFixFile = `${params.path}${params.subpath}Foo1BeforeFix.sol`
+        afterFixFile = `${params.path}${params.subpath}Foo1AfterFix.sol`
+      })
+      describe('--fix with noPrompt', () => {
+        after(function () {
+          if (!E2E) {
+            copyFile(beforeFixFile, currentFile)
+          }
+        })
+
+        it('should compare Foo1 file with template BEFORE FIX file and they should match 4', () => {
+          result = compareTextFiles(currentFile, beforeFixFile)
+          expect(result).to.be.true
+        })
+
+        it('should compare Foo1 file with template AFTER FIX file and they should match 4', () => {
+          const { code, stdout } = shell.exec(
+            `${params.command} ${params.param1} -c ${currentConfig} ${currentFile} --fix --disc --noPrompt`
+          )
+
+          expect(code).to.equal(1)
+
+          const reportLines = stdout.split('\n')
+          const finalLine = '27 problems (27 errors, 0 warnings)'
+          expect(reportLines[reportLines.length - 3]).to.contain(finalLine)
+
+          result = compareTextFiles(currentFile, afterFixFile)
+          expect(result).to.be.true
+        })
+      })
+      it('should check FOO1 does not change after test 4', () => {
+        result = compareTextFiles(currentFile, beforeFixFile)
+        expect(result).to.be.true
+      })
+    })
+  })
+})
+
+// FALTA LA COMPARACION DEL FIX CON EL TEMPLATE FIX
+// FALTA LA PRUEBA DEL STORE TO FILE
diff --git a/e2e/formatters-test.js b/e2e/formatters-test.js
index 07f60a5..668c19d 100644
--- a/e2e/formatters-test.js
+++ b/e2e/formatters-test.js
@@ -63,7 +63,7 @@ describe('e2e', function () {
         }
         expect(code).to.equal(0)
 
-        const finalLine = '3 problem/s (3 warning/s) '
+        const finalLine = '3 problem/s (3 warning/s)'
         expect(reportLines[reportLines.length - 2]).to.equal(finalLine)
       })
       it('should make the output report with unix formatter for Foo and Foo2 and Foo3', () => {
@@ -112,7 +112,7 @@ describe('e2e', function () {
         expect(strExpected).to.equal(strOutput)
         expect(code).to.equal(0)
       })
-      it('should make the output report with unix formatter for Foo and Foo2 and Foo3', () => {
+      it('should make the output report with json formatter for Foo and Foo2 and Foo3', () => {
         const { code, stdout } = shell.exec(
           `solhint ${PATH}contracts/Foo.sol ${PATH}contracts/Foo2.sol ${PATH}contracts/Foo3.sol -f ${formatterType}`
         )
@@ -157,7 +157,7 @@ describe('e2e', function () {
         }
         expect(code).to.equal(0)
 
-        const finalLine = '3 problem/s (3 warning/s) '
+        const finalLine = '3 problem/s (3 warning/s)'
         expect(reportLines[reportLines.length - 2]).to.equal(finalLine)
       })
       it('should make the output report with compact formatter for Foo and Foo2 and Foo3', () => {
diff --git a/e2e/package.json b/e2e/package.json
index 3f81707..282f9ed 100644
--- a/e2e/package.json
+++ b/e2e/package.json
@@ -4,7 +4,7 @@
   "description": "E2E tests for solhint",
   "main": "index.js",
   "scripts": {
-    "test": "mocha test.js formatters-test.js"    
+    "test": "mocha test.js formatters-test.js autofix-test.js"
   },
   "author": "",
   "license": "MIT",
@@ -14,6 +14,7 @@
     "fs-extra": "^11.1.0",
     "get-stream": "^6.0.0",
     "mocha": "^10.2.0",
-    "shelljs": "^0.8.5"
+    "shelljs": "^0.8.5",
+    "spawn-sync": "^2.0.0"
   }
 }
diff --git a/test/fixtures/best-practises/explicit-types.js b/test/fixtures/best-practises/explicit-types.js
index b63c483..925b879 100644
--- a/test/fixtures/best-practises/explicit-types.js
+++ b/test/fixtures/best-practises/explicit-types.js
@@ -119,6 +119,12 @@ const VAR_DECLARATIONS = {
     errorsExplicit: 1,
   },
 
+  fixedArrayCastInDeclaration: {
+    code: 'uint[] public arr = [uint(1),2,3];',
+    errorsImplicit: 0,
+    errorsExplicit: 2,
+  },
+
   fixedArrayOfArrays: {
     code: 'uint256[] public arr = [[1,2,3]];',
     errorsImplicit: 1,
@@ -130,6 +136,42 @@ const VAR_DECLARATIONS = {
     errorsImplicit: 1,
     errorsExplicit: 1,
   },
+
+  castInStateVariableDeclaration: {
+    code: 'uint256 public varUint256 = uint256(1); uint public varUint = uint(1);',
+    errorsImplicit: 2,
+    errorsExplicit: 2,
+  },
+
+  castInsideFunctionAtDeclarationUint256: {
+    code: 'function withUint256() external { uint256 varUint256 = uint256(1); }',
+    errorsImplicit: 2,
+    errorsExplicit: 0,
+  },
+
+  castInsideFunctionAtDeclarationUint: {
+    code: 'function withUint() external { uint varUint = uint(1); }',
+    errorsImplicit: 0,
+    errorsExplicit: 2,
+  },
+
+  castInsideFunctionUint: {
+    code: 'function withUint() external { uint varUint; varUint = uint(1);}',
+    errorsImplicit: 0,
+    errorsExplicit: 2,
+  },
+
+  castInsideFunctionUint256: {
+    code: 'function withUint256() external { uint256 varUint; varUint = uint256(1);}',
+    errorsImplicit: 2,
+    errorsExplicit: 0,
+  },
+
+  castInsideModifier: {
+    code: 'modifier withUint256() { _; uint256 varUint; varUint = uint256(1);}',
+    errorsImplicit: 2,
+    errorsExplicit: 0,
+  },
 }
 
 module.exports = VAR_DECLARATIONS
diff --git a/test/fixtures/best-practises/one-contract-per-file.js b/test/fixtures/best-practises/one-contract-per-file.js
index afc7492..6926837 100644
--- a/test/fixtures/best-practises/one-contract-per-file.js
+++ b/test/fixtures/best-practises/one-contract-per-file.js
@@ -33,4 +33,40 @@ const THREE_CONTRACTS = `
         uint256 public constant TESTC = "testC";
     }
     `
-module.exports = { ONE_CONTRACT, TWO_CONTRACTS, THREE_CONTRACTS }
+
+const TWO_LIBRARIES = `
+    pragma solidity 0.8.0;
+    
+    library A { }
+
+    library B { }
+    `
+
+const ONE_CONTRACT_WITH_INTERFACES = `
+    pragma solidity 0.8.0;
+    
+    contract A { }
+
+    interface B { }
+
+    interface C { }
+    `
+
+const ONE_LIBRARY_WITH_INTERFACES = `
+    pragma solidity 0.8.0;
+    
+    library A { }
+
+    interface B { }
+
+    interface C { }
+    `
+
+module.exports = {
+  ONE_CONTRACT,
+  TWO_CONTRACTS,
+  THREE_CONTRACTS,
+  TWO_LIBRARIES,
+  ONE_CONTRACT_WITH_INTERFACES,
+  ONE_LIBRARY_WITH_INTERFACES,
+}
diff --git a/test/rules/best-practises/no-console.js b/test/rules/best-practises/no-console.js
index 6b67b2e..2ac75dc 100644
--- a/test/rules/best-practises/no-console.js
+++ b/test/rules/best-practises/no-console.js
@@ -35,7 +35,7 @@ describe('Linter - no-console', () => {
 
   it('should raise console.logBytes12() is not allowed', () => {
     const code = funcWith(`
-      console.logString('test');
+      console.logBytes12('test');
     `)
 
     const report = linter.processStr(code, {
diff --git a/test/rules/best-practises/one-contract-per-file.js b/test/rules/best-practises/one-contract-per-file.js
index 54b5876..86dc782 100644
--- a/test/rules/best-practises/one-contract-per-file.js
+++ b/test/rules/best-practises/one-contract-per-file.js
@@ -13,6 +13,26 @@ describe('Linter - one-contract-per-file', () => {
     assertNoWarnings(report)
   })
 
+  it('should not raise error for ONE contract and multiple interfaces in the same file', () => {
+    const code = contracts.ONE_CONTRACT_WITH_INTERFACES
+
+    const report = linter.processStr(code, {
+      rules: { 'one-contract-per-file': 'error' },
+    })
+
+    assertNoWarnings(report)
+  })
+
+  it('should not raise error for ONE library and multiple interfaces in the same file', () => {
+    const code = contracts.ONE_LIBRARY_WITH_INTERFACES
+
+    const report = linter.processStr(code, {
+      rules: { 'one-contract-per-file': 'error' },
+    })
+
+    assertNoWarnings(report)
+  })
+
   it('should raise error for TWO contracts in same file', () => {
     const code = contracts.TWO_CONTRACTS
 
@@ -34,4 +54,15 @@ describe('Linter - one-contract-per-file', () => {
     assertErrorCount(report, 1)
     assertErrorMessage(report, 'Found more than One contract per file. 3 contracts found!')
   })
+
+  it('should raise error for TWO libraries in same file', () => {
+    const code = contracts.TWO_LIBRARIES
+
+    const report = linter.processStr(code, {
+      rules: { 'one-contract-per-file': 'error' },
+    })
+
+    assertErrorCount(report, 1)
+    assertErrorMessage(report, 'Found more than One contract per file. 2 contracts found!')
+  })
 })
diff --git a/test/rules/naming/private-vars-leading-underscore.js b/test/rules/naming/private-vars-leading-underscore.js
index 5a8d0e5..dbf02a2 100644
--- a/test/rules/naming/private-vars-leading-underscore.js
+++ b/test/rules/naming/private-vars-leading-underscore.js
@@ -4,60 +4,66 @@ const { contractWith, libraryWith } = require('../../common/contract-builder')
 
 describe('Linter - private-vars-leading-underscore', () => {
   const SHOULD_WARN_CASES = [
-    // warn when private/internal names don't start with _
+    // warn when private/internal/default names don't start with _
     contractWith('uint foo;'),
     contractWith('uint private foo;'),
     contractWith('uint internal foo;'),
+    contractWith('function foo() {}'),
     contractWith('function foo() private {}'),
     contractWith('function foo() internal {}'),
+    libraryWith('function foo() {}'),
     libraryWith('function foo() private {}'),
+    libraryWith('function foo() internal {}'),
 
-    // warn when public/external/default names start with _
+    // warn when public/external names start with _
     contractWith('uint public _foo;'),
-    contractWith('function _foo() {}'),
+    contractWith('uint external _foo;'),
     contractWith('function _foo() public {}'),
     contractWith('function _foo() external {}'),
-    libraryWith('function _foo() {}'),
     libraryWith('function _foo() public {}'),
-    libraryWith('function _foo() internal {}'),
+    libraryWith('function _foo() external {}'),
   ]
+
   const SHOULD_WARN_STRICT_CASES = [
-    contractWith('function foo() { uint _bar; }'),
-    contractWith('function foo(uint _bar) {}'),
-    contractWith('function foo() returns (uint256 _bar) {}'),
-    libraryWith('function foo() returns (uint256 _bar) {}'),
-    libraryWith('function foo(uint _bar) {}'),
+    contractWith('function _foo() internal { uint _bar; }'),
+    contractWith('function foo(uint _bar) external {}'),
+    contractWith('function foo() public returns (uint256 _bar) {}'),
+    libraryWith('function _foo() returns (uint256 _bar) {}'),
+    libraryWith('function _foo(uint _bar) private {}'),
   ]
+
   const SHOULD_NOT_WARN_CASES = [
-    // don't warn when private/internal names start with _
+    // don't warn when private/internal/default names start with _
     contractWith('uint _foo;'),
     contractWith('uint private _foo;'),
     contractWith('uint internal _foo;'),
+    contractWith('function _foo() {}'),
     contractWith('function _foo() private {}'),
     contractWith('function _foo() internal {}'),
+    libraryWith('function _foo() {}'),
+    libraryWith('function _foo() internal {}'),
     libraryWith('function _foo() private {}'),
 
-    // don't warn when public/external/default names don't start with _
+    // don't warn when public/external names don't start with _
     contractWith('uint public foo;'),
-    contractWith('function foo() {}'),
+    contractWith('uint public foo = 2;'),
     contractWith('function foo() public {}'),
     contractWith('function foo() external {}'),
-    libraryWith('function foo() {}'),
     libraryWith('function foo() public {}'),
-    libraryWith('function foo() internal {}'),
+    libraryWith('function foo() external {}'),
 
     // don't warn for constructors
     contractWith('constructor() public {}'),
 
     // other names (variables, parameters, returns) shouldn't be affected by this rule
-    contractWith('function foo(uint bar) {}'),
-    contractWith('function foo() { uint bar; }'),
-    contractWith('function foo() returns (uint256) {}'),
-    contractWith('function foo() returns (uint256 bar) {}'),
-    libraryWith('function foo(uint bar) {}'),
-    libraryWith('function foo() { uint bar; }'),
-    libraryWith('function foo() returns (uint256) {}'),
-    libraryWith('function foo() returns (uint256 bar) {}'),
+    contractWith('function foo(uint bar) external {}'),
+    contractWith('function foo() public { uint bar; }'),
+    contractWith('function _foo() returns (uint256) {}'),
+    contractWith('function _foo() returns (uint256 bar) {}'),
+    libraryWith('function foo(uint bar) external {}'),
+    libraryWith('function foo() public { uint bar; }'),
+    libraryWith('function _foo() returns (uint256) {}'),
+    libraryWith('function _foo() internal returns (uint256 bar) {}'),
   ]
 
   SHOULD_WARN_CASES.forEach((code, index) => {
@@ -71,7 +77,7 @@ describe('Linter - private-vars-leading-underscore', () => {
   })
 
   SHOULD_WARN_STRICT_CASES.concat(SHOULD_NOT_WARN_CASES).forEach((code, index) => {
-    it(`should not emit a warning (strict) (${index})`, () => {
+    it(`should not emit a warning (not strict) (${index})`, () => {
       const report = linter.processStr(code, {
         rules: { 'private-vars-leading-underscore': 'error' },
       })
@@ -91,7 +97,7 @@ describe('Linter - private-vars-leading-underscore', () => {
   })
 
   SHOULD_WARN_STRICT_CASES.forEach((code, index) => {
-    it(`should not emit a warning (strict) (${index})`, () => {
+    it(`should emit a warning (strict) (${index})`, () => {
       const report = linter.processStr(code, {
         rules: { 'private-vars-leading-underscore': ['error', { strict: true }] },
       })