Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add prettier support #72

Merged
merged 11 commits into from
Oct 10, 2018
Merged
18 changes: 18 additions & 0 deletions lib/common/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
getLocFromIndex(text, index) {
let line = 1
let column = 0
let i = 0
while (i < index) {
if (text[i] === '\n') {
line++
column = 0
} else {
column++
}
i++
}

return { line, column }
}
}
27 changes: 27 additions & 0 deletions lib/config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const _ = require('lodash')
const { RULES } = require('./constants')

module.exports = {
from(configVals) {
Expand All @@ -12,5 +13,31 @@ module.exports = {

getNumber(ruleName, defaultValue) {
return this.getNumberByPath(`rules["${ruleName}"][1]`, defaultValue)
},

getRulesDisabledByDefault() {
const { PRETTIER } = RULES
return [PRETTIER]
},

isRuleDisabledByDefault(ruleId) {
const rules = module.exports.getRulesDisabledByDefault()
return rules.includes(ruleId)
},

validateDisabledByDefault(rulesConfig, rulesToCheck) {
const rulesArrayOfObjects = []

for (const ruleToCheck of rulesToCheck) {
const { rule, instance } = ruleToCheck

const isConfigured = rulesConfig && rulesConfig[rule]
const isEnabledByDefault = !module.exports.isRuleDisabledByDefault(rule)

if (isConfigured || isEnabledByDefault) {
rulesArrayOfObjects.push(instance)
}
}
return rulesArrayOfObjects
}
}
6 changes: 6 additions & 0 deletions lib/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = Object.freeze({
RULES: {
PRETTIER: 'prettier/prettier',
QUOTES: 'quotes'
}
})
6 changes: 3 additions & 3 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const Reporter = require('./reporter')
const TreeListener = require('./tree-listener')
const checkers = require('./rules/index')

function processStr(inputStr, config = {}) {
function processStr(inputStr, config = {}, fileName = '') {
const chars = new antlr4.InputStream(inputStr)
const lexer = new SolidityLexer(chars)
const tokens = new antlr4.CommonTokenStream(lexer)
Expand All @@ -18,14 +18,14 @@ function processStr(inputStr, config = {}) {
const tree = parser.sourceUnit()
const reporter = new Reporter(tokens, config)

const listener = new TreeListener(checkers(reporter, config))
const listener = new TreeListener(checkers(reporter, config, inputStr, fileName))
antlr4.tree.ParseTreeWalker.DEFAULT.walk(listener, tree)

return reporter
}

function processFile(file, config) {
const report = processStr(fs.readFileSync(file).toString(), config)
const report = processStr(fs.readFileSync(file).toString(), config, file)
report.file = file

return report
Expand Down
4 changes: 4 additions & 0 deletions lib/rules/base-checker.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ class BaseChecker {
this.reporter.error(ctx, ruleId, message)
}

errorAt(line, column, ruleId, message) {
this.reporter.errorAt(line, column, ruleId, message)
}

warn(ctx, ruleId, message) {
this.reporter.warn(ctx, ruleId, message)
}
Expand Down
6 changes: 3 additions & 3 deletions lib/rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ const order = require('./order/index')
const align = require('./align/index')
const bestPractises = require('./best-practises/index')
const deprecations = require('./deprecations/index')
const QuotesChecker = require('./quotes')
const miscellaneous = require('./miscellaneous/index')
const configObject = require('./../config')

module.exports = function checkers(reporter, configVals) {
module.exports = function checkers(reporter, configVals, inputSrc, fileName) {
const config = configObject.from(configVals)

return [
Expand All @@ -17,6 +17,6 @@ module.exports = function checkers(reporter, configVals) {
...align(reporter, config),
...deprecations(reporter, config),
...bestPractises(reporter, config),
new QuotesChecker(reporter, config)
...miscellaneous(reporter, config, inputSrc, fileName)
]
}
20 changes: 20 additions & 0 deletions lib/rules/miscellaneous/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const Prettier = require('./prettier')
const QuotesChecker = require('./quotes')
const { RULES } = require('../../constants')

module.exports = function checkers(reporter, config, inputSrc, fileName) {
const { rules, validateDisabledByDefault } = config

const rulesToCheck = [
{
rule: RULES.QUOTES,
instance: new QuotesChecker(reporter, config)
},
{
rule: RULES.PRETTIER,
instance: new Prettier(reporter, config, inputSrc, fileName)
}
]

return validateDisabledByDefault(rules, rulesToCheck)
}
71 changes: 71 additions & 0 deletions lib/rules/miscellaneous/prettier.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
const { showInvisibles, generateDifferences } = require('prettier-linter-helpers')
const { getLocFromIndex } = require('../../common/utils')
const BaseChecker = require('../base-checker')
const { RULES } = require('../../constants')

const { INSERT, DELETE, REPLACE } = generateDifferences

class Prettier extends BaseChecker {
constructor(reporter, config, inputSrc, fileName) {
super(reporter)
this.inputSrc = inputSrc
this.fileName = fileName
}

enterSourceUnit(ctx) {
try {
// Check for optional dependencies with the try catch
// Prettier is expensive to load, so only load it if needed.
const prettier = require('prettier')

const formatted = prettier.format(this.inputSrc, {
filepath: this.fileName,
plugins: ['prettier-plugin-solidity']
})

const differences = generateDifferences(this.inputSrc, formatted)

differences.forEach(difference => {
let loc = null
switch (difference.operation) {
case INSERT:
loc = getLocFromIndex(this.inputSrc, difference.offset)
this.errorAt(
loc.line,
loc.column,
RULES.PRETTIER,
`Insert ${showInvisibles(difference.insertText)}`
)
break
case DELETE:
loc = getLocFromIndex(this.inputSrc, difference.offset)
this.errorAt(
loc.line,
loc.column,
RULES.PRETTIER,
`Delete ${showInvisibles(difference.deleteText)}`
)
break
case REPLACE:
loc = getLocFromIndex(this.inputSrc, difference.offset)
this.errorAt(
loc.line,
loc.column,
RULES.PRETTIER,
`Replace ${showInvisibles(difference.deleteText)} with ${showInvisibles(
difference.insertText
)}`
)
break
default:
// A switch must have a default
}
})
} catch (e) {
console.error(e)
process.exit(1)
}
}
}

module.exports = Prettier
5 changes: 3 additions & 2 deletions lib/rules/quotes.js → lib/rules/miscellaneous/quotes.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const BaseChecker = require('./base-checker')
const BaseChecker = require('../base-checker')
const { RULES } = require('../../constants')

class QuotesChecker extends BaseChecker {
constructor(reporter, config) {
Expand Down Expand Up @@ -40,7 +41,7 @@ class QuotesChecker extends BaseChecker {
}

_error(ctx) {
this.error(ctx, 'quotes', `Use ${this.quoteType} quotes for string literals`)
this.error(ctx, RULES.QUOTES, `Use ${this.quoteType} quotes for string literals`)
}
}

Expand Down
55 changes: 52 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@
"antlr4": "4.7.1",
"commander": "2.18.0",
"eslint": "^5.6.0",
"fast-diff": "^1.1.2",
"glob": "7.1.3",
"ignore": "^4.0.6",
"lodash": "^4.17.11"
"lodash": "^4.17.11",
"prettier-linter-helpers": "^1.0.0"
},
"devDependencies": {
"assert": "1.4.1",
Expand All @@ -44,7 +46,10 @@
"eslint-plugin-prettier": "^2.6.2",
"mocha": "^5.2.0",
"mocha-lcov-reporter": "1.3.0",
"nyc": "^13.0.1",
"prettier": "^1.14.3"
"nyc": "^13.0.1"
},
"optionalDependencies": {
"prettier": "^1.14.3",
"prettier-plugin-solidity": "^1.0.0-alpha.4"
}
}
19 changes: 18 additions & 1 deletion test/common/configs.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,21 @@ function noIndent() {
}
}

module.exports = { noIndent }
function prettier() {
return {
rules: {
'prettier/prettier': ['error'],
indent: false,
'no-empty-blocks': false,
'two-lines-top-level-separator': false,
'state-visibility': false,
'separate-by-one-line-in-contract': false,
'const-name-snakecase': false,
'func-visibility': false,
'compiler-fixed': false,
'contract-name-camelcase': false,
quotes: false
}
}
}
module.exports = { noIndent, prettier }
11 changes: 10 additions & 1 deletion test/common/contract-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,13 @@ function multiLine(...args) {
return args.join('\n')
}

module.exports = { contractWith, funcWith, multiLine }
function contractWithPrettier(code) {
return `pragma solidity 0.4.4;

contract A {
${code}
}
`
}

module.exports = { contractWith, funcWith, multiLine, contractWithPrettier }
Loading