Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Tests

on:
pull_request:
push:
branches:
- master

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run tests
run: pnpm test

- name: Security
run: pnpm audit
95 changes: 87 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import oneInchEslintConfig from "@1inch/eslint-config";
export default oneInchEslintConfig
```

Remove .eslintignore and use special section in `eslint.config.mjs` for it. Root 1inch eslint config already have this ignores rules.
Remove `.eslintrc.js` / `.eslintrc.json` and `.eslintignore` — ESLint 9 flat config replaces them.

Use `eslint.config.mjs` for ignores and custom rules:
```javascript
import oneInchEslintConfig from "@1inch/eslint-config";

Expand All @@ -30,23 +32,24 @@ export default [
"**/node_modules",
"**/.github",
"**/.idea",
"**/.eslintrc-tmp.js",
"**/dist",
"**/*.json",
"**/*.yml",
"**/*.html",
"**/graph.serviceuser.postgres.repository.service.ts",
"**/migrations",
],
},
{
plugins: {
// ...
},
settings: {
// ...
"import-x/resolver": {
typescript: {}
}
},
}];
rules: {
// your custom rules here
}
}
];
```

Add prettier file `.prettierrc.js`:
Expand All @@ -60,3 +63,79 @@ module.exports = {
semi: false
}
```

## Migration from v3

### Breaking changes

1. **ESLint flat config only** — delete `.eslintrc.js` / `.eslintrc.json` and `.eslintignore`, create `eslint.config.mjs` instead

2. **`eslint-plugin-import` replaced by `eslint-plugin-import-x`** — all `import/` rule prefixes and settings changed to `import-x/`:

| Before (v3) | After (v4) |
|---|---|
| `plugins: ['import']` | not needed (included in config) |
| `settings: { 'import/resolver': { typescript: {} } }` | `settings: { 'import-x/resolver': { typescript: {} } }` |
| `rules: { 'import/order': ... }` | `rules: { 'import-x/order': ... }` |

3. **Removed packages** — uninstall these, they are no longer needed:
```shell
pnpm remove \
@typescript-eslint/eslint-plugin \
@typescript-eslint/parser \
eslint-plugin-import \
eslint-config-standard \
eslint-plugin-n \
eslint-plugin-promise \
@eslint/compat \
@eslint/eslintrc
```

4. **New packages** — install these instead:
```shell
pnpm install --save-dev \
eslint@10 \
@eslint/js@10 \
typescript-eslint@8 \
eslint-plugin-import-x@4 \
eslint-import-resolver-typescript@4 \
eslint-config-prettier@10 \
eslint-plugin-unused-imports@4 \
@stylistic/eslint-plugin@5 \
globals@17
```

### Example migration

Before (`.eslintrc.js`):
```js
module.exports = {
extends: ['@1inch'],
plugins: ['import'],
settings: {
'import/resolver': {
typescript: {}
}
},
rules: {
}
}
```

After (`eslint.config.mjs`):
```javascript
import oneInchEslintConfig from "@1inch/eslint-config";

export default [
...oneInchEslintConfig,
{
settings: {
"import-x/resolver": {
typescript: {}
}
},
rules: {
}
}
];
```
61 changes: 22 additions & 39 deletions index.mjs
Original file line number Diff line number Diff line change
@@ -1,25 +1,13 @@
import { fixupConfigRules, fixupPluginRules } from "@eslint/compat";
import typescriptEslint from "@typescript-eslint/eslint-plugin";
import unusedImports from "eslint-plugin-unused-imports";
import _import from "eslint-plugin-import";
import globals from "globals";
import tsParser from "@typescript-eslint/parser";
import path from "node:path";
import { fileURLToPath } from "node:url";
import js from "@eslint/js";
import { FlatCompat } from "@eslint/eslintrc";
import eslintConfigPrettier from "eslint-config-prettier";
import eslint from '@eslint/js'
import tseslint from 'typescript-eslint'
import importX from 'eslint-plugin-import-x'
import unusedImports from 'eslint-plugin-unused-imports'
import prettierPlugin from 'eslint-plugin-prettier'
import eslintConfigPrettier from 'eslint-config-prettier'
import stylistic from '@stylistic/eslint-plugin'
import globals from 'globals'

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all
});

export default [{
export default tseslint.config({
ignores: [
"**/*.mock.ts",
"**/node_modules",
Expand All @@ -33,38 +21,33 @@ export default [{
"**/graph.serviceuser.postgres.repository.service.ts",
"**/migrations",
],
}, ...fixupConfigRules(compat.extends(
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
)), {
},
eslint.configs.recommended,
...tseslint.configs.recommended,
importX.flatConfigs.recommended,
importX.flatConfigs.typescript,
{
plugins: {
"@typescript-eslint": fixupPluginRules(typescriptEslint),
"unused-imports": unusedImports,
import: fixupPluginRules(_import),
'@stylistic': stylistic
"prettier": prettierPlugin,
"@stylistic": stylistic,
},

languageOptions: {
globals: {
...globals.node,
},

parser: tsParser,
},

settings: {
"import/resolver": {
"import-x/resolver": {
typescript: {},
},
},


rules: {
"import/namespace": "off",
"import/default": "off",
"import-x/namespace": "off",
"import-x/default": "off",
"@typescript-eslint/member-ordering": "error",
"lines-between-class-members": "error",

Expand Down Expand Up @@ -116,11 +99,11 @@ export default [{
"@typescript-eslint/explicit-function-return-type": "error",
"@typescript-eslint/no-non-null-assertion": "off",

"import/order": ["error", {
"import-x/order": ["error", {
groups: ["external", "builtin", "internal", "sibling", "parent", "index"],
}],
"prettier/prettier": ["error", { "semi": false }],
'@stylistic/comma-dangle': ['error', 'never'],
"@stylistic/comma-dangle": ["error", "never"],
},
}, {
files: ["src/**/*.test.ts", "src/**/*.integration-test.ts", "src/**/*.spec.ts"],
Expand All @@ -134,4 +117,4 @@ export default [{
},
},
eslintConfigPrettier
];
)
66 changes: 66 additions & 0 deletions index.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { describe, it, expect } from 'vitest'
import { ESLint } from 'eslint'
import config from './index.mjs'

function createLinter() {
return new ESLint({
overrideConfigFile: true,
overrideConfig: config
})
}

async function lintText(code, filePath = 'src/test.ts') {
const linter = createLinter()
const results = await linter.lintText(code, { filePath })

return results[0].messages
}

function hasRule(messages, ruleId) {
return messages.some((m) => m.ruleId === ruleId)
}

describe('@1inch/eslint-config', () => {
it('exports a valid config array', () => {
expect(Array.isArray(config)).toBe(true)
expect(config.length).toBeGreaterThan(0)
})

it('catches console.log (no-console)', async () => {
const messages = await lintText('console.log("hello")\n')
expect(hasRule(messages, 'no-console')).toBe(true)
})

it('catches missing return type (@typescript-eslint/explicit-function-return-type)', async () => {
const messages = await lintText('export function foo() { return 1 }\n')
expect(hasRule(messages, '@typescript-eslint/explicit-function-return-type')).toBe(true)
})

it('catches unused imports (unused-imports/no-unused-imports)', async () => {
const code = 'import { readFile } from "fs"\nexport const x: number = 1\n'
const messages = await lintText(code)
expect(hasRule(messages, 'unused-imports/no-unused-imports')).toBe(true)
})

it('catches formatting issues via prettier (prettier/prettier)', async () => {
const code = 'export const arr: number[] = [1, 2, 3,]\n'
const messages = await lintText(code)
expect(hasRule(messages, 'prettier/prettier')).toBe(true)
})

it('allows valid code without errors for key rules', async () => {
const code = `export function add(a: number, b: number): number {
return a + b
}
`
const messages = await lintText(code)
const criticalRules = [
'no-console',
'@typescript-eslint/explicit-function-return-type',
'unused-imports/no-unused-imports'
]
for (const rule of criticalRules) {
expect(hasRule(messages, rule)).toBe(false)
}
})
})
Loading
Loading