Skip to content

Commit 632345f

Browse files
authored
chore: Upgrade to eslint 9 with flat config (#4579)
1 parent 1709cce commit 632345f

17 files changed

+7196
-4559
lines changed

.eslintrc.json

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

.github/workflows/lint.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,12 @@ jobs:
2929
- name: Install npm dependencies
3030
run: npm ci
3131

32+
- name: Install website npm dependencies
33+
run: npm ci
34+
working-directory: website
35+
36+
- name: Build Cheerio
37+
run: npm run build
38+
3239
- name: Run lint
3340
run: npm run lint

eslint.config.js

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
import eslintJs from '@eslint/js';
2+
import { defineConfig } from 'eslint/config';
3+
import globals from 'globals';
4+
import { includeIgnoreFile } from '@eslint/compat'; // Added for .gitignore
5+
import { fileURLToPath } from 'node:url'; // Added for .gitignore path
6+
import eslintPluginJsdoc from 'eslint-plugin-jsdoc';
7+
import eslintPluginN from 'eslint-plugin-n';
8+
import eslintPluginUnicorn from 'eslint-plugin-unicorn';
9+
import tseslint from 'typescript-eslint';
10+
import eslintPluginVitest from '@vitest/eslint-plugin';
11+
import eslintConfigPrettier from 'eslint-config-prettier';
12+
13+
const gitignorePath = fileURLToPath(new URL('.gitignore', import.meta.url));
14+
15+
export default defineConfig(
16+
includeIgnoreFile(gitignorePath), // Handle .gitignore patterns
17+
18+
// 0. Global linter options
19+
{
20+
linterOptions: {
21+
reportUnusedDisableDirectives: true, // Enable reporting of unused disable directives
22+
},
23+
},
24+
25+
// 1. Base configurations for all relevant files
26+
eslintJs.configs.recommended, // Basic ESLint recommended rules
27+
28+
{
29+
// JSDoc configuration
30+
plugins: { jsdoc: eslintPluginJsdoc },
31+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
32+
rules: {
33+
...eslintPluginJsdoc.configs.recommended.rules,
34+
'jsdoc/require-jsdoc': 0,
35+
'jsdoc/tag-lines': [2, 'any', { startLines: 1 }],
36+
'jsdoc/require-param-type': 0,
37+
'jsdoc/require-returns-type': 0,
38+
'jsdoc/no-types': 2,
39+
'jsdoc/require-returns-check': 0, // Was in TS override, better here
40+
},
41+
settings: {
42+
jsdoc: {
43+
mode: 'typescript',
44+
tagNamePreference: { category: 'category' },
45+
},
46+
},
47+
},
48+
49+
{
50+
// Node plugin configuration
51+
plugins: { n: eslintPluginN },
52+
rules: {
53+
...eslintPluginN.configs.recommended.rules,
54+
'n/file-extension-in-import': [2, 'always'],
55+
'n/no-missing-import': 0,
56+
},
57+
},
58+
59+
{
60+
// Unicorn plugin configuration
61+
plugins: { unicorn: eslintPluginUnicorn },
62+
rules: {
63+
...eslintPluginUnicorn.configs.recommended.rules,
64+
'unicorn/no-null': 0,
65+
'unicorn/prevent-abbreviations': 0,
66+
'unicorn/prefer-code-point': 0,
67+
'unicorn/no-for-loop': 0,
68+
'unicorn/no-array-callback-reference': 0,
69+
'unicorn/prefer-spread': 0,
70+
'unicorn/no-useless-undefined': 0,
71+
'unicorn/no-array-reduce': 0,
72+
'unicorn/prefer-array-find': 0,
73+
'unicorn/prefer-module': 0,
74+
'unicorn/prefer-at': 0,
75+
'unicorn/prefer-string-replace-all': 0,
76+
'unicorn/prefer-switch': [2, { emptyDefaultCase: 'do-nothing-comment' }],
77+
},
78+
},
79+
80+
// 2. Global custom rules and language options
81+
{
82+
languageOptions: {
83+
globals: globals.node,
84+
parserOptions: {
85+
projectService: {
86+
allowDefaultProject: ['*.js'],
87+
},
88+
tsconfigRootDir: import.meta.dirname, // eslint-disable-line n/no-unsupported-features/node-builtins
89+
},
90+
},
91+
rules: {
92+
'array-callback-return': [2, { allowImplicit: true }],
93+
'no-lonely-if': 2,
94+
'no-proto': 2,
95+
eqeqeq: [2, 'smart'],
96+
'no-caller': 2,
97+
'dot-notation': 2,
98+
'no-var': 2,
99+
'prefer-const': 2,
100+
'prefer-arrow-callback': [2, { allowNamedFunctions: true }],
101+
'arrow-body-style': [2, 'as-needed'],
102+
'object-shorthand': 2,
103+
'prefer-template': 2,
104+
'one-var': [2, 'never'],
105+
'prefer-destructuring': [2, { object: true }],
106+
'capitalized-comments': 2,
107+
'multiline-comment-style': [2, 'starred-block'],
108+
'spaced-comment': 2,
109+
yoda: [2, 'never'],
110+
curly: [2, 'multi-line'],
111+
'no-else-return': [2, { allowElseIf: false }],
112+
'no-unused-expressions': 2,
113+
'no-useless-call': 2,
114+
'no-use-before-define': [2, 'nofunc'],
115+
'no-constant-binary-expression': 2,
116+
'no-void': 2,
117+
},
118+
},
119+
120+
// 3. TypeScript specific configurations
121+
tseslint.configs.recommendedTypeChecked,
122+
tseslint.configs.stylisticTypeChecked,
123+
{
124+
// Custom overrides and settings for TypeScript files
125+
files: ['**/*.ts', '**/*.mts', '**/*.cts'], // Ensure this block specifically targets TS files
126+
rules: {
127+
// Override base ESLint rules for TS
128+
'dot-notation': 0,
129+
'no-use-before-define': 0,
130+
// "curly" is already defined globally with [2, "multi-line"]
131+
132+
// Rule from original TS override related to Node features
133+
'n/no-unsupported-features/es-syntax': 0,
134+
135+
// Original TypeScript specific rules
136+
'@typescript-eslint/prefer-for-of': 0,
137+
'@typescript-eslint/member-ordering': 0,
138+
'@typescript-eslint/explicit-function-return-type': 0,
139+
'@typescript-eslint/no-unused-vars': [
140+
'error',
141+
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
142+
],
143+
'@typescript-eslint/no-use-before-define': [
144+
2,
145+
{
146+
functions: false,
147+
classes: true,
148+
variables: true,
149+
enums: true,
150+
typedefs: true,
151+
},
152+
],
153+
'@typescript-eslint/consistent-type-definitions': [2, 'interface'],
154+
'@typescript-eslint/prefer-function-type': 2,
155+
'@typescript-eslint/no-unnecessary-type-arguments': 2,
156+
'@typescript-eslint/prefer-string-starts-ends-with': 2,
157+
'@typescript-eslint/prefer-readonly': 2,
158+
'@typescript-eslint/prefer-includes': 2,
159+
'@typescript-eslint/switch-exhaustiveness-check': 2,
160+
'@typescript-eslint/prefer-nullish-coalescing': 2,
161+
'@typescript-eslint/no-non-null-assertion': 1,
162+
'@typescript-eslint/consistent-type-imports': 2,
163+
'@typescript-eslint/no-explicit-any': 1, // TODO
164+
},
165+
},
166+
167+
// 4. Vitest specific configuration (for *.spec.ts files)
168+
{
169+
files: ['**/*.spec.ts'],
170+
plugins: { vitest: eslintPluginVitest },
171+
languageOptions: {
172+
globals: {
173+
...globals.vitest, // Add Vitest globals
174+
},
175+
},
176+
rules: {
177+
// Assuming "recommended" is the flat config equivalent for "legacy-recommended"
178+
...eslintPluginVitest.configs.recommended.rules,
179+
'n/no-unpublished-import': 0, // Allow importing devDependencies
180+
'@typescript-eslint/no-explicit-any': 0, // Allow `any` in tests
181+
'@typescript-eslint/no-non-null-assertion': 0, // Allow `!` assertions in tests
182+
},
183+
},
184+
185+
// 5. Prettier - must be the last configuration to override styling rules
186+
eslintConfigPrettier,
187+
);

0 commit comments

Comments
 (0)