solhint
Version:
Solidity Code Linter
178 lines (146 loc) • 4.75 kB
JavaScript
const program = require('commander')
const _ = require('lodash')
const fs = require('fs')
const process = require('process')
const linter = require('./lib/index')
function init() {
program.version('1.1.10')
program
.usage('[options] <file> [...other_files]')
.option('-f, --formatter [name]', 'report formatter name (stylish, table, tap, unix)')
.option(
'-w, --max-warnings [maxWarningsNumber]',
'number of warnings to trigger nonzero exit code'
)
.option('-q, --quiet', 'report errors only - default: false')
.option('--ignore-path [file_name]', 'file to use as your .solhintignore')
.description('Linter for Solidity programming language')
.action(execMainAction)
program
.command('stdin')
.description('linting of source code data provided to STDIN')
.option('--filename [file_name]', 'name of file received using STDIN')
.action(processStdin)
program
.command('init-config')
.description('create in current directory configuration file for solhint')
.action(writeSampleConfigFile)
program.parse(process.argv)
if (program.args.length < 1) {
program.help()
}
}
function execMainAction() {
let formatterFn
try {
// to check if is a valid formatter before execute linter
formatterFn = getFormatter(program.formatter)
} catch (ex) {
console.error(ex.message)
process.exit(1)
}
const reportLists = program.args.filter(_.isString).map(processPath)
const reports = _.flatten(reportLists)
const warningsNumberExceeded =
program.maxWarnings >= 0 && reports[0].warningCount >= program.maxWarnings
if (program.quiet) {
// filter the list of reports, to set errors only.
reports[0].reports = reports[0].reports.filter(i => i.severity === 2)
}
if (printReports(reports, formatterFn)) {
if (program.maxWarnings && !reports[0].errorCount && warningsNumberExceeded) {
console.log(
'Solhint found more warnings than the maximum specified (maximum: %s)',
program.maxWarnings
)
process.exit(1)
}
}
exitWithCode(reports)
}
function processStdin(options) {
const STDIN_FILE = 0
const stdinBuffer = fs.readFileSync(STDIN_FILE)
const report = processStr(stdinBuffer.toString())
report.file = options.filename || 'stdin'
printReports([report])
}
function writeSampleConfigFile() {
const configPath = '.solhint.json'
const sampleConfig = [
'{ ',
' "extends": "default", ',
' "rules": { ',
' "indent": ["error", 4], ',
' "quotes": ["error", "double"], ',
' "max-line-length": ["error", 120] ',
' } ',
'} '
]
if (!fs.existsSync(configPath)) {
fs.writeFileSync(configPath, sampleConfig.join('\n'))
console.log('Configuration file created!')
} else {
console.log('Configuration file already exists')
}
}
const readIgnore = _.memoize(() => {
let ignoreFile = '.solhintignore'
try {
if (program.ignorePath) {
ignoreFile = program.ignorePath
}
return fs
.readFileSync(ignoreFile)
.toString()
.split('\n')
.map(i => i.trim())
} catch (e) {
if (program.ignorePath && e.code === 'ENOENT') {
console.error(`\nERROR: ${ignoreFile} is not a valid path.`)
}
return []
}
})
const readConfig = _.memoize(() => {
let config = {}
try {
const configStr = fs.readFileSync('.solhint.json').toString()
config = JSON.parse(configStr)
} catch (e) {
if (e instanceof SyntaxError) {
console.log('ERROR: Configuration file [.solhint.json] is not a valid JSON!\n')
process.exit(0)
}
}
const configExcludeFiles = _.flatten(config.excludedFiles)
config.excludedFiles = _.concat(configExcludeFiles, readIgnore())
return config
})
function processStr(input) {
return linter.processStr(input, readConfig())
}
function processPath(path) {
return linter.processPath(path, readConfig())
}
function printReports(reports, formatter) {
console.log(formatter(reports))
return reports
}
function getFormatter(formatter) {
const formatterName = formatter || 'stylish'
try {
return require(`eslint/lib/formatters/${formatterName}`)
} catch (ex) {
ex.message = `\nThere was a problem loading formatter option: ${program.formatter} \nError: ${
ex.message
}`
throw ex
}
}
function exitWithCode(reports) {
const errorsCount = reports.reduce((acc, i) => acc + i.errorCount, 0)
process.exit(errorsCount > 0 ? 1 : 0)
}
init()