Skip to content

Commit 1574ae9

Browse files
authored
Merge pull request #1 from TimoBechtel/chore/upgrade-to-eslint-9
feat(eslint): upgrade to eslint 9
2 parents e929f38 + 2a0f4f9 commit 1574ae9

22 files changed

Lines changed: 495 additions & 632 deletions

README.md

Lines changed: 54 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Highly opinionated configuration files for typescript projects. Inspired by [@ve
1010
## Usage
1111

1212
```bash
13-
npm i -D @timobechtel/style prettier "eslint@^8.57.1" typescript
13+
npm i -D @timobechtel/style prettier "eslint@^9" typescript
1414
```
1515

1616
### Prettier
@@ -94,7 +94,6 @@ With expo make sure to add `"moduleResolution": "bundler"` to the `compilerOptio
9494

9595
</details>
9696

97-
9897
#### Or with React
9998

10099
```bash
@@ -117,80 +116,94 @@ curl -O https://raw.githubusercontent.com/TimoBechtel/style/refs/heads/main/temp
117116
### Eslint
118117

119118
```bash
120-
curl -O https://raw.githubusercontent.com/TimoBechtel/style/refs/heads/main/templates/eslint/core/.eslintrc.cjs
121-
```
122-
123-
#### Fix Parsing errors for config files
124-
125-
You may get a `Parsing error: <FILE> was not found by the project service.` for config files like .eslintrc.cjs when not included in the tsconfig.
126-
127-
To fix, either add to tsconfig or add them to the eslint config:
128-
129-
```diff
130-
//...
131-
parserOptions: {
132-
+ projectService: {
133-
+ allowDefaultProject: ['.eslintrc.cjs'],
134-
+ },
135-
//...
136-
},
137-
//...
119+
curl -O https://raw.githubusercontent.com/TimoBechtel/style/refs/heads/main/templates/eslint/core/eslint.config.js
138120
```
139121

122+
Note: If your project is not ESM (no `"type": "module"` in `package.json`), rename the file to `eslint.config.mjs`.
140123

141124
<details>
142125
<summary>Or manually</summary>
143126

144-
Copy the following to a `.eslintrc.cjs`:
127+
Copy the following to an `eslint.config.js`:
145128

146129
```js
147-
const { resolve } = require('node:path');
148-
149-
const project = resolve(process.cwd(), 'tsconfig.json');
150-
151-
module.exports = {
152-
root: true,
153-
extends: [require.resolve('@timobechtel/style/eslint/core.cjs')],
154-
parserOptions: {
155-
tsconfigRootDir: process.cwd(),
156-
},
157-
settings: {
158-
'import/resolver': {
159-
typescript: {
160-
project,
130+
import path from 'node:path';
131+
import { fileURLToPath } from 'node:url';
132+
import { defineConfig } from 'eslint/config';
133+
import styleCore from '@timobechtel/style/eslint/core.js';
134+
import { createTypeScriptImportResolver } from 'eslint-import-resolver-typescript';
135+
import { createNodeResolver } from 'eslint-plugin-import-x';
136+
137+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
138+
139+
export default defineConfig([
140+
...styleCore,
141+
{
142+
languageOptions: {
143+
parserOptions: {
144+
tsconfigRootDir: __dirname,
161145
},
162146
},
147+
settings: {
148+
'import-x/resolver-next': [
149+
createTypeScriptImportResolver({
150+
project: path.resolve(__dirname, 'tsconfig.json'),
151+
}),
152+
createNodeResolver(),
153+
],
154+
},
163155
},
164-
};
156+
]);
165157
```
166158
167159
</details>
168160
169161
#### React
170162
171163
```bash
172-
curl -O https://raw.githubusercontent.com/TimoBechtel/style/refs/heads/main/templates/eslint/react/.eslintrc.cjs
164+
curl -O https://raw.githubusercontent.com/TimoBechtel/style/refs/heads/main/templates/eslint/react/eslint.config.js
173165
```
174166
175167
<details>
176168
<summary>Or manually</summary>
177169
178-
Also add `require.resolve('@timobechtel/style/eslint/react.cjs')` to the `extends` array.
170+
Also spread `styleReact` from `@timobechtel/style/eslint/react.js`:
171+
172+
```js
173+
import styleCore from '@timobechtel/style/eslint/core.js';
174+
import styleReact from '@timobechtel/style/eslint/react.js';
175+
import { defineConfig } from 'eslint/config';
176+
177+
export default defineConfig([
178+
...styleCore,
179+
...styleReact,
180+
// ... your config
181+
]);
182+
```
179183
180184
Example config:
181-
<https://raw.githubusercontent.com/TimoBechtel/style/refs/heads/main/templates/eslint/react/.eslintrc.cjs>
185+
<https://raw.githubusercontent.com/TimoBechtel/style/refs/heads/main/templates/eslint/react/eslint.config.js>
182186
</details>
183187
188+
#### Migration from v1.x
189+
190+
If you're upgrading from v1.x, you'll need to:
191+
192+
1. Upgrade to ESLint v9+
193+
2. Replace `.eslintrc.cjs` with `eslint.config.js`
194+
3. Update imports to use `.js` extension (e.g., `@timobechtel/style/eslint/core.js`)
195+
4. Note: Import plugin rules now use `import-x/` prefix instead of `import/`
196+
184197
#### VSCode
185198
186-
Note: You should disable `source.organizeImports` in your VSCode config, as this collides with the `import/order` rule.
199+
Note: You should disable `source.organizeImports` in your VSCode config, as this collides with the `import-x/order` rule.
187200
188201
Add the following to your VSCode config, e.g. `.vscode/settings.json`
189202
190203
```json
191204
{
192205
"editor.codeActionsOnSave": {
193-
// use eslint import/order instead
206+
// use eslint import-x/order instead
194207
"source.sortImports": "never"
195208
}
196209
}

bun.lockb

27.2 KB
Binary file not shown.

eslint/core.cjs

Lines changed: 0 additions & 63 deletions
This file was deleted.

eslint/core.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import js from '@eslint/js';
2+
import timobechtelRulesPlugin from '@timobechtel/eslint-plugin-rules';
3+
import prettierConfig from 'eslint-config-prettier/flat';
4+
import { createTypeScriptImportResolver } from 'eslint-import-resolver-typescript';
5+
import { createNodeResolver, importX } from 'eslint-plugin-import-x';
6+
import unicornPlugin from 'eslint-plugin-unicorn';
7+
import { defineConfig } from 'eslint/config';
8+
import globals from 'globals';
9+
import tseslint from 'typescript-eslint';
10+
11+
import baseRules from './rules/base.js';
12+
import importRules from './rules/import.js';
13+
import typescriptRules from './rules/typescript.js';
14+
import unicornRules from './rules/unicorn.js';
15+
16+
const mergeRules = (configs) =>
17+
Object.assign({}, ...configs.map((config) => config?.rules ?? {}));
18+
19+
export default defineConfig([
20+
js.configs.recommended,
21+
importX.flatConfigs.recommended,
22+
importX.flatConfigs.typescript,
23+
timobechtelRulesPlugin.configs['flat/all'],
24+
25+
{
26+
languageOptions: {
27+
globals: {
28+
...globals.browser,
29+
...globals.node,
30+
...globals.es2021,
31+
},
32+
ecmaVersion: 2021,
33+
sourceType: 'module',
34+
},
35+
plugins: {
36+
unicorn: unicornPlugin,
37+
},
38+
rules: {
39+
...mergeRules(baseRules),
40+
...mergeRules(importRules),
41+
...mergeRules(unicornRules),
42+
},
43+
linterOptions: {
44+
reportUnusedDisableDirectives: true,
45+
},
46+
settings: {
47+
'import-x/resolver-next': [
48+
createTypeScriptImportResolver(),
49+
createNodeResolver(),
50+
],
51+
},
52+
},
53+
54+
...tseslint.configs.recommended,
55+
...tseslint.configs.recommendedTypeChecked,
56+
...tseslint.configs.strict,
57+
...tseslint.configs.strictTypeChecked,
58+
...tseslint.configs.stylistic,
59+
...tseslint.configs.stylisticTypeChecked,
60+
{
61+
languageOptions: {
62+
parserOptions: {
63+
projectService: true,
64+
},
65+
},
66+
},
67+
{
68+
files: ['**/*.js'],
69+
extends: [tseslint.configs.disableTypeChecked],
70+
},
71+
{
72+
files: ['**/*.ts', '**/*.tsx'],
73+
rules: {
74+
...mergeRules(typescriptRules),
75+
},
76+
},
77+
78+
{
79+
files: ['**/*.test.ts', '**/*.test.tsx', '**/*.spec.ts', '**/*.spec.tsx'],
80+
rules: {
81+
'@typescript-eslint/ban-ts-comment': 'off',
82+
},
83+
},
84+
85+
prettierConfig,
86+
]);

eslint/react.cjs

Lines changed: 0 additions & 21 deletions
This file was deleted.

eslint/react.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import prettierConfig from 'eslint-config-prettier/flat';
2+
import reactPlugin from 'eslint-plugin-react';
3+
import reactHooksPlugin from 'eslint-plugin-react-hooks';
4+
import { defineConfig } from 'eslint/config';
5+
import reactRules from './rules/react.js';
6+
7+
const mergeRules = (configs) =>
8+
Object.assign({}, ...configs.map((config) => config?.rules ?? {}));
9+
10+
export default defineConfig([
11+
reactPlugin.configs.flat.recommended,
12+
reactPlugin.configs.flat['jsx-runtime'],
13+
14+
{
15+
plugins: {
16+
react: reactPlugin,
17+
'react-hooks': reactHooksPlugin,
18+
},
19+
settings: {
20+
react: {
21+
version: 'detect',
22+
},
23+
linkComponents: ['Link'],
24+
},
25+
rules: {
26+
...reactHooksPlugin.configs.flat.recommended.rules,
27+
...mergeRules(reactRules),
28+
},
29+
},
30+
31+
prettierConfig,
32+
]);

0 commit comments

Comments
 (0)