Skip to content

Commit 0d46406

Browse files
authored
feat: add code linting and formatting packages (#953)
* feat: add eslint-graph-config packages Signed-off-by: Tomás Migone <[email protected]>
1 parent 7e0e6a7 commit 0d46406

15 files changed

+1151
-1457
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@ This repository is a Yarn workspaces monorepo containing the following packages:
3737
| Package | Latest version | Description |
3838
| --- | --- | --- |
3939
| [contracts](./packages/contracts) | [![npm version](https://badge.fury.io/js/@graphprotocol%2Fcontracts.svg)](https://badge.fury.io/js/@graphprotocol%2Fcontracts) | Contracts enabling the open and permissionless decentralized network known as The Graph protocol. |
40+
| [eslint-graph-config](./packages/eslint-graph-config) | [![npm version]()]() | Shared linting and formatting rules for TypeScript projects. |
4041
| [token-distribution](./packages/token-distribution) | - | Contracts managing token locks for network participants |
4142
| [sdk](./packages/sdk) | [![npm version](https://badge.fury.io/js/@graphprotocol%2Fsdk.svg)](https://badge.fury.io/js/@graphprotocol%2Fsdk) | TypeScript based SDK to interact with the protocol contracts |
43+
| [solhint-graph-config](./packages/eslint-graph-config) | [![npm version]()]() | Shared linting and formatting rules for Solidity projects. |
4244

4345

4446
## Development

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
"packageManager": "[email protected]",
99
"workspaces": [
1010
"packages/contracts",
11+
"packages/eslint-graph-config",
1112
"packages/sdk",
13+
"packages/solhint-graph-config",
1214
"packages/token-distribution"
1315
],
1416
"scripts": {
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
index.js
+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# eslint-graph-config
2+
3+
This repository contains shared linting and formatting rules for TypeScript projects.
4+
5+
## Installation
6+
7+
```bash
8+
yarn add --dev eslint eslint-graph-config
9+
```
10+
11+
For projects on this monorepo, you can use the following command to install the package:
12+
13+
```bash
14+
yarn add --dev eslint eslint-graph-config@workspace:^x.y.z
15+
```
16+
17+
To enable the rules, you need to create an `eslint.config.js` file in the root of your project with the following content:
18+
19+
```javascript
20+
const config = require('eslint-graph-config')
21+
module.exports = config.default
22+
```
23+
24+
**Recommended config for existing projects**
25+
The default configuration is quite strict specially with the usage of `any` and it's derivatives. For existing projects with a codebase that was developed with more lenient guidelines migrating to this configuration can be a bit overwhelming.
26+
27+
You can customize your `eslint.config.js` file to disable some rules and make the transition easier. For example, you can create a `eslint.config.js` file with the following content:
28+
29+
```javascript
30+
const config = require('eslint-graph-config')
31+
32+
module.exports = [
33+
...config.default,
34+
{
35+
rules: {
36+
'@typescript-eslint/no-unsafe-assignment': 'off',
37+
'@typescript-eslint/no-var-requires': 'off',
38+
'@typescript-eslint/no-unsafe-call': 'off',
39+
'@typescript-eslint/no-unsafe-member-access': 'off',
40+
'@typescript-eslint/no-unsafe-argument': 'off',
41+
},
42+
},
43+
]
44+
```
45+
46+
## Tooling
47+
48+
This package uses the following tools:
49+
- [ESLint](https://eslint.org/) as the base linting tool
50+
- [typescript-eslint](https://typescript-eslint.io/) for TypeScript support
51+
- [ESLint Stylistic](https://eslint.style/) as the formatting tool
52+
53+
**Why no prettier?**
54+
Instead of prettier we use ESLint Stylistic which is a set of ESLint rules focused on formatting and styling code. As opposed to prettier, ESLint Stylistic runs entirely within ESLint and does not require a separate tool to be run (e.g. `prettier`, `eslint-plugin-prettier` and `eslint-config-prettier`). Additionally it's supposed to be [more efficient](https://eslint.style/guide/why#linters-vs-formatters) and [less opinionated](https://antfu.me/posts/why-not-prettier).
55+
56+
## VSCode support
57+
58+
If you are using VSCode you can install the [ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) to get real-time linting and formatting support.
59+
60+
The following settings should be added to your `settings.json` file:
61+
```json
62+
{
63+
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
64+
"eslint.format.enable": true,
65+
"eslint.experimental.useFlatConfig": true,
66+
"eslint.workingDirectories": [{ "pattern": "./packages/*/" }]
67+
}
68+
```
69+
70+
Additionally you can configure the `Format document` keyboard shortcut to run `eslint --fix` on demand.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// This file only exists to enable linting on index.js
2+
const config = require('./index')
3+
4+
module.exports = [
5+
...config.default,
6+
{
7+
rules: {
8+
'@typescript-eslint/no-unsafe-assignment': 'off',
9+
'@typescript-eslint/no-var-requires': 'off',
10+
},
11+
},
12+
]

packages/eslint-graph-config/index.ts

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import eslint from '@eslint/js'
2+
import globals from 'globals'
3+
import noOnlyTests from 'eslint-plugin-no-only-tests'
4+
import noSecrets from 'eslint-plugin-no-secrets'
5+
import stylistic from '@stylistic/eslint-plugin'
6+
import tseslint from 'typescript-eslint'
7+
8+
export default [
9+
// Base eslint configuration
10+
eslint.configs.recommended,
11+
12+
// Enable linting with type information
13+
// https://typescript-eslint.io/getting-started/typed-linting
14+
...tseslint.configs.recommendedTypeChecked,
15+
16+
// Formatting and stylistic rules
17+
stylistic.configs['recommended-flat'],
18+
19+
// Custom config
20+
{
21+
languageOptions: {
22+
parserOptions: {
23+
project: ['../*/tsconfig.json', 'tsconfig.json'],
24+
tsconfigRootDir: __dirname,
25+
},
26+
globals: {
27+
...globals.node,
28+
},
29+
},
30+
plugins: {
31+
'no-only-tests': noOnlyTests,
32+
'no-secrets': noSecrets,
33+
},
34+
ignores: ['dist/*', 'node_modules/*', 'build/*'],
35+
rules: {
36+
'prefer-const': 'warn',
37+
'@typescript-eslint/no-inferrable-types': 'warn',
38+
'@typescript-eslint/no-empty-function': 'warn',
39+
'no-only-tests/no-only-tests': 'error',
40+
'no-secrets/no-secrets': 'error',
41+
'sort-imports': [
42+
'warn', {
43+
memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
44+
ignoreCase: true,
45+
allowSeparatedGroups: true,
46+
}],
47+
},
48+
},
49+
]
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "eslint-graph-config",
3+
"version": "0.0.1",
4+
"description": "Linting and formatting rules for The Graph's TypeScript projects",
5+
"main": "index.js",
6+
"author": "The Graph Team",
7+
"license": "GPL-2.0-or-later",
8+
"scripts": {
9+
"clean": "rm -rf index.js",
10+
"lint": "eslint '**/*.{js,ts}' --ignore-pattern index.js --fix",
11+
"build": "yarn clean && tsc"
12+
},
13+
"dependencies": {
14+
"@stylistic/eslint-plugin": "^1.6.2",
15+
"eslint": "^8.56.0",
16+
"eslint-plugin-no-only-tests": "^3.1.0",
17+
"eslint-plugin-no-secrets": "^0.8.9",
18+
"typescript-eslint": "^7.0.2"
19+
},
20+
"devDependencies": {
21+
"@types/eslint__js": "^8.42.3",
22+
"@types/node": "^20.11.19",
23+
"typescript": "^5.3.3"
24+
},
25+
"peerDependencies": {
26+
"eslint": "^8.56.0"
27+
}
28+
}
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2020",
4+
"module": "commonjs",
5+
"esModuleInterop": true,
6+
"forceConsistentCasingInFileNames": true,
7+
"strict": true,
8+
"skipLibCheck": true,
9+
"resolveJsonModule": true
10+
},
11+
"include": ["index.ts", "typings/**/*.d.ts", "eslint.config.js"]
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
declare module 'eslint-plugin-no-only-tests' {
2+
import { FlatConfig } from 'typescript-eslint'
3+
const plugin: FlatConfig.Plugin
4+
export default plugin
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
declare module 'eslint-plugin-no-secrets' {
2+
import { FlatConfig } from 'typescript-eslint'
3+
const plugin: FlatConfig.Plugin
4+
export default plugin
5+
}
+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# solhint-graph-config
2+
3+
This repository contains shared linting and formatting rules for Solidity projects.
4+
5+
## Code linting
6+
7+
### Installation
8+
9+
⚠️ Unfortunately there isn't a way to install peer dependencies using Yarn v4, so we need to install them manually.
10+
11+
12+
```bash
13+
# Install with peer packages
14+
yarn add --dev solhint solhint-graph-config
15+
16+
# For projects on this monorepo
17+
yarn add --dev solhint solhint-graph-config@workspace:^x.y.z
18+
```
19+
20+
### Configuration
21+
22+
Run `solhint` with `node_modules/solhint-graph-config/index.js` as the configuration file. We suggest creating an npm script to make it easier to run:
23+
24+
```json
25+
26+
{
27+
"scripts": {
28+
"lint": "solhint --fix contracts/**/*.sol --config node_modules/solhint-graph-config/index.js"
29+
}
30+
}
31+
32+
```
33+
34+
## Code formatting
35+
36+
### Installation
37+
38+
⚠️ Unfortunately there isn't a way to install peer dependencies using Yarn v4, so we need to install them manually.
39+
40+
41+
```bash
42+
# Install with peer packages
43+
yarn add --dev solhint-graph-config prettier prettier-plugin-solidity
44+
45+
# For projects on this monorepo
46+
yarn add --dev solhint-graph-config@workspace:^x.y.z prettier prettier-plugin-solidity
47+
```
48+
49+
50+
### Configuration: formatting
51+
52+
Create a configuration file for prettier at `prettier.config.js`:
53+
54+
```javascript
55+
const prettierGraphConfig = require('solhint-graph-config/prettier')
56+
module.exports = prettierGraphConfig
57+
```
58+
59+
Running `prettier` will automatically pick up the configuration file. We suggest creating an npm script to make it easier to run:
60+
61+
```json
62+
{
63+
"scripts": {
64+
"format": "prettier --write 'contracts/**/*.sol'"
65+
}
66+
}
67+
```
68+
69+
## Tooling
70+
71+
This package uses the following tools:
72+
- [solhint](https://protofire.github.io/solhint/) as the base linting tool
73+
- [prettier](https://prettier.io/) as the base formatting tool
74+
- [prettier-plugin-solidity](https://github.com/prettier-solidity/prettier-plugin-solidity) to format Solidity code
75+
76+
77+
## VSCode support
78+
79+
If you are using VSCode you can install the [Solidity extension by Nomic Foundation](https://marketplace.visualstudio.com/items?itemName=NomicFoundation.hardhat-solidity). Unfortunately there is currently no way of getting real-time linting output from solhint, but this extension will provide formatting support using our prettier config and will also provide inline code validation using solc compiler output.
80+
81+
For formatting, the following settings should be added to your `settings.json` file:
82+
```json
83+
"[solidity]": {
84+
"editor.defaultFormatter": "NomicFoundation.hardhat-solidity"
85+
},
86+
```
87+
88+
Additionally you can configure the `Format document` keyboard shortcut to run `prettier --write` on demand.
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module.exports = {
2+
extends: 'solhint:recommended',
3+
rules: {
4+
'func-visibility': ['warn', { ignoreConstructors: true }],
5+
'compiler-version': ['off'],
6+
'constructor-syntax': 'warn',
7+
'quotes': ['error', 'double'],
8+
'reason-string': ['off'],
9+
'not-rely-on-time': 'off',
10+
'no-empty-blocks': 'off',
11+
},
12+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"name": "solhint-graph-config",
3+
"version": "0.0.1",
4+
"description": "Linting and formatting rules for The Graph's Solidity projects",
5+
"main": "index.js",
6+
"author": "The Graph Team",
7+
"license": "GPL-2.0-or-later",
8+
"peerDependencies": {
9+
"prettier": "^3.2.5",
10+
"prettier-plugin-solidity": "^1.3.1",
11+
"solhint": "^4.1.1"
12+
}
13+
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module.exports = {
2+
"printWidth": 120,
3+
"useTabs": false,
4+
"bracketSpacing": true,
5+
"plugins": ["prettier-plugin-solidity"],
6+
"overrides": [
7+
{
8+
"files": "*.sol",
9+
"options": {
10+
"tabWidth": 4,
11+
"singleQuote": false,
12+
}
13+
}
14+
]
15+
}

0 commit comments

Comments
 (0)