Comparing version 4.0.0 to 4.1.1
function isFallbackFunction(node) { | ||
return isFunctionDefinition(node) && node.isFallback | ||
return isFunctionDefinition(node) && (node.isFallback || node.isReceiveEther) | ||
} | ||
@@ -4,0 +4,0 @@ |
@@ -11,2 +11,3 @@ # Eslint formatters | ||
- compact.js: eslint - Nicholas C. Zakas | ||
- sarif.js: [@microsoft/eslint-formatter-sarif](https://www.npmjs.com/package/@microsoft/eslint-formatter-sarif) | ||
@@ -44,3 +44,3 @@ const fs = require('fs') | ||
const tokens = parser.tokenize(inputStr, { loc: true }) | ||
const tokens = parser.tokenize(inputStr, { loc: true, range: true }) | ||
const reporter = new Reporter(tokens, config) | ||
@@ -47,0 +47,0 @@ const listener = new TreeListener(checkers(reporter, config, inputStr, tokens, fileName)) |
@@ -26,2 +26,7 @@ const BaseChecker = require('../base-checker') | ||
}, | ||
notes: [ | ||
{ | ||
note: 'Solhint allows this rule to automatically fix the code with `--fix` option', | ||
}, | ||
], | ||
}, | ||
@@ -28,0 +33,0 @@ |
@@ -25,2 +25,7 @@ const BaseChecker = require('../base-checker') | ||
}, | ||
notes: [ | ||
{ | ||
note: 'Solhint allows this rule to automatically fix the code with `--fix` option', | ||
}, | ||
], | ||
}, | ||
@@ -31,3 +36,3 @@ | ||
defaultSetup: 'warn', | ||
fixable: true, | ||
schema: null, | ||
@@ -44,8 +49,25 @@ } | ||
if (node.stateMutability !== 'payable') { | ||
this.warn(node, 'When fallback is not payable you will not be able to receive ether') | ||
this.warn( | ||
node, | ||
'Fallback should be external and payable to accept native currency', | ||
this.fixStatement(node) | ||
) | ||
} | ||
} | ||
} | ||
fixStatement(node) { | ||
const range = node.range | ||
const stringToPut = ' payable ' | ||
if (node.isReceiveEther) { | ||
range[0] += 9 | ||
} else { | ||
range[0] += 10 | ||
} | ||
return (fixer) => fixer.insertTextBeforeRange(range, stringToPut) | ||
} | ||
} | ||
module.exports = PayableFallbackChecker |
@@ -64,3 +64,3 @@ const BaseChecker = require('../base-checker') | ||
defaultSetup: [DEFAULT_SEVERITY, DEFAULT_QUOTES_TYPE], | ||
fixable: true, | ||
schema: { | ||
@@ -117,7 +117,29 @@ type: 'string', | ||
_error(ctx) { | ||
this.error(ctx, `Use ${this.quoteType} quotes for string literals`) | ||
_error(node) { | ||
this.error(node, `Use ${this.quoteType} quotes for string literals`, this.fixStatement(node)) | ||
} | ||
swapQuotes(inputString, quoteType) { | ||
// Define the opposite quote type | ||
const oppositeQuote = quoteType === "'" ? '"' : "'" | ||
// Regular expression to match either single or double quotes within the string | ||
const quoteRegex = new RegExp(`[${quoteType}${oppositeQuote}]`, 'g') | ||
// Replace each occurrence of the specified quote type with the opposite quote | ||
const resultString = inputString.replace(quoteRegex, (match) => | ||
match === quoteType ? oppositeQuote : quoteType | ||
) | ||
return resultString | ||
} | ||
fixStatement(node) { | ||
const stringToPut = this.swapQuotes(node.value, this.incorrectQuote) | ||
const range = node.range | ||
range[1] -= 1 | ||
return (fixer) => fixer.replaceTextRange(range, stringToPut) | ||
} | ||
} | ||
module.exports = QuotesChecker |
@@ -9,4 +9,12 @@ const BaseChecker = require('../base-checker') | ||
docs: { | ||
description: 'Contract name must be in CamelCase.', | ||
description: 'Contract, Structs and Enums should be in CamelCase.', | ||
category: 'Style Guide Rules', | ||
notes: [ | ||
{ | ||
note: 'Solhint allows this rule to automatically fix the code with `--fix` option', | ||
}, | ||
{ | ||
note: 'The FIX will only change first letter and remove underscores', | ||
}, | ||
], | ||
}, | ||
@@ -17,3 +25,3 @@ | ||
defaultSetup: 'warn', | ||
fixable: true, | ||
schema: null, | ||
@@ -28,24 +36,50 @@ } | ||
ContractDefinition(node) { | ||
this.validateName(node) | ||
this.validateName(node, 'contract') | ||
} | ||
EnumDefinition(node) { | ||
this.validateName(node) | ||
this.validateName(node, 'enum') | ||
} | ||
StructDefinition(node) { | ||
this.validateName(node) | ||
this.validateName(node, 'struct') | ||
} | ||
validateName(node) { | ||
validateName(node, type) { | ||
if (naming.isNotCamelCase(node.name)) { | ||
this._error(node) | ||
this._error(node, type) | ||
} | ||
} | ||
_error(node) { | ||
this.error(node, 'Contract name must be in CamelCase') | ||
fixStatement(node, type) { | ||
// Remove leading and trailing underscores | ||
let nameToPut = node.name.replace(/^[_]+|[_]+$/g, '') | ||
// Replace '-' with space and split the string into an array | ||
let words = nameToPut.replace(/-/g, ' ').split('_') | ||
// Capitalize the first letter of each word | ||
words = words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)) | ||
// Join the words back into a single string | ||
nameToPut = words.join('') | ||
const originalNameLength = node.name.length | ||
const typeLength = type.length | ||
const rangeStart = node.range[0] + typeLength + 1 | ||
const rangeEnd = node.range[0] + typeLength + originalNameLength | ||
return (fixer) => fixer.replaceTextRange([rangeStart, rangeEnd], nameToPut) | ||
} | ||
_error(node, type) { | ||
this.error( | ||
node, | ||
'Contract, Structs and Enums should be in CamelCase', | ||
this.fixStatement(node, type) | ||
) | ||
} | ||
} | ||
module.exports = ContractNameCamelcaseChecker |
@@ -11,2 +11,10 @@ const BaseChecker = require('../base-checker') | ||
category: 'Style Guide Rules', | ||
notes: [ | ||
{ | ||
note: 'Solhint allows this rule to automatically fix the code with `--fix` option', | ||
}, | ||
{ | ||
note: 'The FIX will only change first letter and remove underscores', | ||
}, | ||
], | ||
}, | ||
@@ -17,3 +25,3 @@ | ||
defaultSetup: 'warn', | ||
fixable: true, | ||
schema: null, | ||
@@ -27,5 +35,27 @@ } | ||
fixStatement(node) { | ||
// Remove leading and trailing underscores | ||
let nameToPut = node.name.replace(/^[_]+|[_]+$/g, '') | ||
// Replace '-' with space and split the string into an array | ||
let words = nameToPut.replace(/-/g, ' ').split('_') | ||
// Capitalize the first letter of each word | ||
words = words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)) | ||
// Join the words back into a single string | ||
nameToPut = words.join('') | ||
const originalNameLength = node.name.length | ||
const typeLength = 'event'.length | ||
const rangeStart = node.range[0] + typeLength + 1 | ||
const rangeEnd = node.range[0] + typeLength + originalNameLength | ||
return (fixer) => fixer.replaceTextRange([rangeStart, rangeEnd], nameToPut) | ||
} | ||
EventDefinition(node) { | ||
if (naming.isNotCamelCase(node.name)) { | ||
this.error(node, 'Event name must be in CamelCase') | ||
this.error(node, 'Event name must be in CamelCase', this.fixStatement(node)) | ||
} | ||
@@ -32,0 +62,0 @@ } |
@@ -70,3 +70,3 @@ const BaseChecker = require('../base-checker') | ||
{ | ||
note: 'This rule considers functions and variables in Libraries as well', | ||
note: 'This rule DO NOT considers functions and variables in Libraries', | ||
}, | ||
@@ -82,2 +82,5 @@ { | ||
}, | ||
{ | ||
note: 'Solhint allows this rule to automatically fix the code with `--fix` option', | ||
}, | ||
], | ||
@@ -108,22 +111,23 @@ }, | ||
// 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) { | ||
return | ||
if (!this.inLibrary) { | ||
if (!node.name) { | ||
return | ||
} | ||
const isPrivate = node.visibility === 'private' | ||
const isInternal = node.visibility === 'internal' || node.visibility === 'default' | ||
const shouldHaveLeadingUnderscore = isPrivate || isInternal | ||
this.validateName(node, shouldHaveLeadingUnderscore, 'function') | ||
} | ||
const isPrivate = node.visibility === 'private' | ||
const isInternal = node.visibility === 'internal' || node.visibility === 'default' | ||
// const shouldHaveLeadingUnderscore = isPrivate || (!this.inLibrary && isInternal) | ||
const shouldHaveLeadingUnderscore = isPrivate || isInternal | ||
this.validateName(node, shouldHaveLeadingUnderscore, 'function') | ||
} | ||
@@ -140,14 +144,16 @@ | ||
VariableDeclaration(node) { | ||
if (!this.inStateVariableDeclaration) { | ||
// if strict is enabled, non-state vars should not start with leading underscore | ||
if (this.isStrict) { | ||
this.validateName(node, false, 'variable') | ||
if (!this.inLibrary) { | ||
if (!this.inStateVariableDeclaration) { | ||
// if strict is enabled, non-state vars should not start with leading underscore | ||
if (this.isStrict) { | ||
this.validateName(node, false, 'variable') | ||
} | ||
return | ||
} | ||
return | ||
const isPrivate = node.visibility === 'private' | ||
const isInternal = node.visibility === 'internal' || node.visibility === 'default' | ||
const shouldHaveLeadingUnderscore = isPrivate || isInternal | ||
this.validateName(node, shouldHaveLeadingUnderscore, 'variable') | ||
} | ||
const isPrivate = node.visibility === 'private' | ||
const isInternal = node.visibility === 'internal' || node.visibility === 'default' | ||
const shouldHaveLeadingUnderscore = isPrivate || isInternal | ||
this.validateName(node, shouldHaveLeadingUnderscore, 'variable') | ||
} | ||
@@ -154,0 +160,0 @@ |
@@ -15,3 +15,3 @@ const BaseChecker = require('../base-checker') | ||
defaultSetup: 'warn', | ||
fixable: true, | ||
schema: null, | ||
@@ -25,9 +25,23 @@ } | ||
Identifier(node) { | ||
if (node.name === 'suicide') { | ||
this.error(node, 'Use "selfdestruct" instead of deprecated "suicide"') | ||
FunctionCall(node) { | ||
if (node.expression.type === 'Identifier' && node.expression.name === 'suicide') { | ||
this.error( | ||
node, | ||
'Use "selfdestruct" instead of deprecated "suicide"', | ||
this.fixStatement(node) | ||
) | ||
} | ||
} | ||
fixStatement(node) { | ||
let stringToPut = 'selfdestruct()' | ||
if (node.arguments.length > 0) { | ||
stringToPut = 'selfdestruct(' + node.arguments[0].name + ')' | ||
} | ||
return (fixer) => fixer.replaceTextRange(node.range, stringToPut) | ||
} | ||
} | ||
module.exports = AvoidSuicideChecker |
{ | ||
"name": "solhint", | ||
"version": "4.0.0", | ||
"version": "4.1.1", | ||
"description": "Solidity Code Linter", | ||
@@ -21,3 +21,3 @@ "main": "lib/index.js", | ||
"test:coverage": "npm run exec-tests", | ||
"test": "mocha --recursive", | ||
"test": "mocha --recursive --timeout 10000", | ||
"lint": "eslint .", | ||
@@ -24,0 +24,0 @@ "generate-rulesets": "node scripts/generate-rulesets.js && prettier --write conf/rulesets", |
<p align="center"> | ||
<img src="solhint.png"> | ||
<a href="https://protofire.io/projects/solhint" target="_blank"><img src="solhint.png"></a> | ||
</p> | ||
<p align="center"> | ||
By <a href="https://protofire.io/">Protofire</a> | ||
By <a href="https://protofire.io/" target="_blank">Protofire</a> | ||
</p> | ||
[![Join Discord](https://img.shields.io/badge/join-Discord-red)](https://discord.gg/4TYGq3zpjs) | ||
[![](https://img.shields.io/badge/Solhint%20Website-cyan)](https://protofire.io/projects/solhint) | ||
[![](https://img.shields.io/badge/Join%20Our%20Discord-magenta)](https://discord.gg/4TYGq3zpjs) | ||
[![Donate with Ethereum](https://img.shields.io/badge/Donate-ETH-blue)](https://etherscan.io/address/0xA81705c8C247C413a19A244938ae7f4A0393944e) | ||
@@ -17,4 +18,6 @@ [![NPM version](https://badge.fury.io/js/solhint.svg)](https://npmjs.org/package/solhint) | ||
provides both **Security** and **Style Guide** validations. | ||
<br> | ||
[VISIT OUR WEBSITE](https://protofire.io/projects/solhint)<br> | ||
[JOIN OUR DISCORD SERVER](https://discord.gg/4TYGq3zpjs) | ||
<br> | ||
## Installation | ||
@@ -61,3 +64,3 @@ | ||
-V, --version output the version number | ||
-f, --formatter [name] report formatter name (stylish, table, tap, unix, json, compact) | ||
-f, --formatter [name] report formatter name (stylish, table, tap, unix, json, compact, sarif) | ||
-w, --max-warnings [maxWarningsNumber] number of allowed warnings | ||
@@ -203,4 +206,7 @@ -c, --config [file_name] file to use as your .solhint.json | ||
## Docker | ||
### Solhint has an official Docker Image | ||
Go to docker folder and follow [this](docker/docker.md) instructions. | ||
## Documentation | ||
Related documentation you may find [here](https://protofire.github.io/solhint/). | ||
@@ -207,0 +213,0 @@ |
@@ -24,3 +24,3 @@ #!/usr/bin/env node | ||
'-f, --formatter [name]', | ||
'report formatter name (stylish, table, tap, unix, json, compact)' | ||
'report formatter name (stylish, table, tap, unix, json, compact, sarif)' | ||
) | ||
@@ -131,3 +131,2 @@ .option('-w, --max-warnings [maxWarningsNumber]', 'number of allowed warnings') | ||
// if (program.opts().fix || program.opts().fixShow) { | ||
if (program.opts().fix) { | ||
@@ -145,8 +144,2 @@ for (const report of reports) { | ||
if (fixed) { | ||
// // 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) => { | ||
@@ -157,8 +150,4 @@ if (report.fix !== null) { | ||
}) | ||
// } | ||
// fs.writeFileSync(report.filePath, output) | ||
try { | ||
fs.writeFileSync(report.filePath, output) | ||
// fs.writeFileSync('no-console/Foo1Modified.sol', output) | ||
} catch (error) { | ||
@@ -165,0 +154,0 @@ console.error('An error occurred while writing the file:', error) |
@@ -36,2 +36,13 @@ const { assertNoWarnings, assertErrorMessage, assertWarnsCount } = require('../../common/asserts') | ||
}) | ||
it('should raise for other fallback types when are not payable', () => { | ||
const code = contractWith('fallback() external {} receive() onlyOwner {}') | ||
const report = linter.processStr(code, { | ||
rules: { 'payable-fallback': 'warn' }, | ||
}) | ||
assertWarnsCount(report, 2) | ||
assertErrorMessage(report, 'payable') | ||
}) | ||
}) |
@@ -57,2 +57,3 @@ const assert = require('assert') | ||
"assembly { linkerSymbol('uint') }", | ||
"assembly { let hexString := '48656c6c6f2c2027576f726c64212722' }", | ||
] | ||
@@ -59,0 +60,0 @@ |
@@ -14,5 +14,2 @@ const assert = require('assert') | ||
contractWith('function foo() internal {}'), | ||
libraryWith('function foo() {}'), | ||
libraryWith('function foo() private {}'), | ||
libraryWith('function foo() internal {}'), | ||
@@ -24,4 +21,2 @@ // warn when public/external names start with _ | ||
contractWith('function _foo() external {}'), | ||
libraryWith('function _foo() public {}'), | ||
libraryWith('function _foo() external {}'), | ||
] | ||
@@ -33,4 +28,2 @@ | ||
contractWith('function foo() public returns (uint256 _bar) {}'), | ||
libraryWith('function _foo() returns (uint256 _bar) {}'), | ||
libraryWith('function _foo(uint _bar) private {}'), | ||
] | ||
@@ -37,0 +30,0 @@ |
const assert = require('assert') | ||
const linter = require('../../../lib/index') | ||
const funcWith = require('../../common/contract-builder').funcWith | ||
const contractWith = require('../../common/contract-builder').contractWith | ||
@@ -21,3 +22,3 @@ describe('Linter - avoid-suicide', () => { | ||
const ALMOST_DEPRECATION_ERRORS = ['suicides();'] | ||
const ALMOST_DEPRECATION_ERRORS = ['suicides();', 'selfdestruct();'] | ||
@@ -35,2 +36,12 @@ ALMOST_DEPRECATION_ERRORS.forEach((curText) => | ||
) | ||
it(`should not return error when doing for struct name suicide`, () => { | ||
const code = contractWith('struct AnotherNiceStruct { uint256 suicide; uint256 c; }') | ||
const report = linter.processStr(code, { | ||
rules: { 'avoid-suicide': 'error' }, | ||
}) | ||
assert.equal(report.errorCount, 0) | ||
}) | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
389796
209
11333
267
1