├── .gitignore ├── package.json ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solhint-plugin-prettier", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "index.js", 6 | "keywords": [ 7 | "solhint", 8 | "prettier", 9 | "plugin", 10 | "solidity" 11 | ], 12 | "author": "", 13 | "license": "MIT", 14 | "dependencies": { 15 | "@prettier/sync": "^0.3.0", 16 | "prettier-linter-helpers": "^1.0.0" 17 | }, 18 | "devDependencies": { 19 | "prettier": "^3.0.0", 20 | "prettier-plugin-solidity": "^1.0.0" 21 | }, 22 | "peerDependencies": { 23 | "prettier": "^3.0.0", 24 | "prettier-plugin-solidity": "^1.0.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # solhint-plugin-prettier 2 | 3 | This [Solhint](https://github.com/solhint-community/solhint-community) plugin lets you check that 4 | your solidity files are correctly formatted according to the [solidity plugin 5 | for Prettier](https://github.com/prettier-solidity/prettier-plugin-solidity). 6 | Each difference with how prettier would format it is reported as an individual 7 | issue. 8 | 9 | ## Setup 10 | 11 | First install the necessary packages: 12 | 13 | ``` 14 | npm install --save-dev solhint-community solhint-plugin-prettier prettier prettier-plugin-solidity 15 | ``` 16 | 17 | Then add a `.solhint.json` configuration file: 18 | 19 | ```json 20 | { 21 | "plugins": ["prettier"], 22 | "rules": { 23 | "prettier/prettier": "error" 24 | } 25 | } 26 | ``` 27 | 28 | This rule will emit an error for each difference between your code and how prettier-solidity would format it. You can also set it to `warning` instead of `error` if you prefer that. 29 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { showInvisibles, generateDifferences } = require('prettier-linter-helpers') 2 | const { INSERT, DELETE, REPLACE } = generateDifferences 3 | 4 | const getLocFromIndex = (text, index) => { 5 | let line = 1 6 | let column = 0 7 | let i = 0 8 | while (i < index) { 9 | if (text[i] === '\n') { 10 | line++ 11 | column = 0 12 | } else { 13 | column++ 14 | } 15 | i++ 16 | } 17 | 18 | return { line, column } 19 | } 20 | 21 | class PrettierChecker { 22 | constructor(reporter, config, inputSrc, fileName) { 23 | this.prettier = null 24 | this.ruleId = 'prettier' 25 | this.reporter = reporter 26 | this.config = config 27 | this.inputSrc = inputSrc 28 | this.fileName = fileName 29 | } 30 | 31 | enterSourceUnit() { 32 | this.SourceUnit() 33 | } 34 | 35 | SourceUnit() { 36 | try { 37 | // Check for optional dependencies with the try catch 38 | // Prettier is expensive to load, so only load it if needed. 39 | if (!this.prettier) { 40 | this.prettier = require('@prettier/sync') 41 | } 42 | 43 | const filepath = this.fileName 44 | 45 | const prettierRcOptions = this.prettier.resolveConfig(filepath, { 46 | editorconfig: true 47 | }) 48 | 49 | const prettierOptions = Object.assign({}, prettierRcOptions, { 50 | filepath, 51 | plugins: ['prettier-plugin-solidity'] 52 | }) 53 | 54 | const formatted = this.prettier.format(this.inputSrc, prettierOptions) 55 | 56 | const differences = generateDifferences(this.inputSrc, formatted) 57 | 58 | differences.forEach(difference => { 59 | let loc = null 60 | switch (difference.operation) { 61 | case INSERT: 62 | loc = getLocFromIndex(this.inputSrc, difference.offset) 63 | this.errorAt(loc.line, loc.column, `Insert ${showInvisibles(difference.insertText)}`) 64 | break 65 | case DELETE: 66 | loc = getLocFromIndex(this.inputSrc, difference.offset) 67 | this.errorAt(loc.line, loc.column, `Delete ${showInvisibles(difference.deleteText)}`) 68 | break 69 | case REPLACE: 70 | loc = getLocFromIndex(this.inputSrc, difference.offset) 71 | this.errorAt( 72 | loc.line, 73 | loc.column, 74 | `Replace ${showInvisibles(difference.deleteText)} with ${showInvisibles( 75 | difference.insertText 76 | )}` 77 | ) 78 | break 79 | default: 80 | // A switch must have a default 81 | } 82 | }) 83 | } catch (e) { 84 | console.error(e) 85 | process.exit(1) 86 | } 87 | } 88 | 89 | errorAt(line, column, message) { 90 | this.reporter.errorAt(line, column, this.ruleId, message) 91 | } 92 | } 93 | 94 | module.exports = [PrettierChecker] 95 | --------------------------------------------------------------------------------