@foray1010/eslint-config 14.0.0 → 15.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +18 -20
- package/bases/base.mjs +78 -126
- package/bases/browser.mjs +11 -23
- package/bases/ignores.mjs +11 -14
- package/bases/node.mjs +8 -10
- package/bases/prettier.mjs +4 -5
- package/bases/react.mjs +10 -18
- package/index.mjs +19 -23
- package/package.json +3 -4
- package/utils/applyConfig.mjs +0 -72
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,23 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [15.0.0](https://github.com/foray1010/common-presets/compare/@foray1010/eslint-config@14.0.1...@foray1010/eslint-config@15.0.0) (2025-03-13)
|
|
7
|
+
|
|
8
|
+
### ⚠ BREAKING CHANGES
|
|
9
|
+
|
|
10
|
+
- drop applyConfig utils
|
|
11
|
+
- require eslint ^9.22.0
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
- migrate to eslint defineConfig utils ([faf0aa7](https://github.com/foray1010/common-presets/commit/faf0aa74048b2536e188a45b8371ebe416dcb851))
|
|
16
|
+
|
|
17
|
+
## [14.0.1](https://github.com/foray1010/common-presets/compare/@foray1010/eslint-config@14.0.0...@foray1010/eslint-config@14.0.1) (2025-03-11)
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
- **eslint-config:** drop eslint-plugin-functional ([fdc506c](https://github.com/foray1010/common-presets/commit/fdc506cf24792dfb55a2c39e7f96a49cd76044af))
|
|
22
|
+
|
|
6
23
|
## [14.0.0](https://github.com/foray1010/common-presets/compare/@foray1010/eslint-config@13.0.3...@foray1010/eslint-config@14.0.0) (2025-03-11)
|
|
7
24
|
|
|
8
25
|
### ⚠ BREAKING CHANGES
|
package/README.md
CHANGED
|
@@ -29,8 +29,9 @@ Z for looser rules
|
|
|
29
29
|
eslintIgnoresConfig,
|
|
30
30
|
eslintNodeConfig,
|
|
31
31
|
} from '@foray1010/eslint-config'
|
|
32
|
+
import { defineConfig } from 'eslint/config'
|
|
32
33
|
|
|
33
|
-
const config =
|
|
34
|
+
const config = defineConfig(eslintIgnoresConfig, eslintNodeConfig)
|
|
34
35
|
export default config
|
|
35
36
|
```
|
|
36
37
|
|
|
@@ -41,8 +42,9 @@ Z for looser rules
|
|
|
41
42
|
eslintIgnoresConfig,
|
|
42
43
|
eslintBrowserConfig,
|
|
43
44
|
} from '@foray1010/eslint-config'
|
|
45
|
+
import { defineConfig } from 'eslint/config'
|
|
44
46
|
|
|
45
|
-
const config =
|
|
47
|
+
const config = defineConfig(eslintIgnoresConfig, eslintBrowserConfig)
|
|
46
48
|
export default config
|
|
47
49
|
```
|
|
48
50
|
|
|
@@ -53,8 +55,9 @@ Z for looser rules
|
|
|
53
55
|
eslintIgnoresConfig,
|
|
54
56
|
eslintReactConfig,
|
|
55
57
|
} from '@foray1010/eslint-config'
|
|
58
|
+
import { defineConfig } from 'eslint/config'
|
|
56
59
|
|
|
57
|
-
const config =
|
|
60
|
+
const config = defineConfig(eslintIgnoresConfig, eslintReactConfig)
|
|
58
61
|
export default config
|
|
59
62
|
```
|
|
60
63
|
|
|
@@ -62,28 +65,23 @@ Z for looser rules
|
|
|
62
65
|
|
|
63
66
|
```js
|
|
64
67
|
import {
|
|
65
|
-
applyConfig,
|
|
66
68
|
eslintIgnoresConfig,
|
|
67
69
|
eslintNodeConfig,
|
|
68
70
|
eslintReactConfig,
|
|
69
71
|
} from '@foray1010/eslint-config'
|
|
72
|
+
import { defineConfig } from 'eslint/config'
|
|
70
73
|
|
|
71
|
-
const config =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
filePrefixes: ['src'],
|
|
83
|
-
},
|
|
84
|
-
eslintReactConfig,
|
|
85
|
-
),
|
|
86
|
-
]
|
|
74
|
+
const config = defineConfig(
|
|
75
|
+
eslintIgnoresConfig,
|
|
76
|
+
{
|
|
77
|
+
ignores: ['src/**'],
|
|
78
|
+
extends: [eslintNodeConfig],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
files: ['src/**'],
|
|
82
|
+
extends: [eslintReactConfig],
|
|
83
|
+
},
|
|
84
|
+
)
|
|
87
85
|
export default config
|
|
88
86
|
```
|
|
89
87
|
|
package/bases/base.mjs
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import js from '@eslint/js'
|
|
2
|
-
|
|
2
|
+
// eslint-disable-next-line import-x/extensions
|
|
3
|
+
import eslintPluginEslintCommentsConfigs from '@eslint-community/eslint-plugin-eslint-comments/configs'
|
|
3
4
|
import { hasDep, isESM } from '@foray1010/common-presets-utils'
|
|
5
|
+
// eslint-disable-next-line import-x/extensions, import-x/no-unresolved
|
|
6
|
+
import { defineConfig } from 'eslint/config'
|
|
4
7
|
import eslintPluginImportX from 'eslint-plugin-import-x'
|
|
5
8
|
import eslintPluginJest from 'eslint-plugin-jest'
|
|
6
9
|
import eslintPluginRegexp from 'eslint-plugin-regexp'
|
|
@@ -14,26 +17,20 @@ import {
|
|
|
14
17
|
typeScriptTestFileGlobs,
|
|
15
18
|
} from '../constants.mjs'
|
|
16
19
|
|
|
17
|
-
/** @typedef {import('../types/internal.d.ts').EslintConfig} EslintConfig */
|
|
18
|
-
|
|
19
|
-
/** @returns {Promise<EslintConfig>} */
|
|
20
20
|
async function generateTypeScriptConfig() {
|
|
21
21
|
// typescript plugins are depended on `typescript` package
|
|
22
|
-
if (!hasDep('typescript')) return
|
|
22
|
+
if (!hasDep('typescript')) return defineConfig({})
|
|
23
23
|
|
|
24
24
|
// eslint-disable-next-line import-x/no-unresolved
|
|
25
25
|
const tseslint = (await import('typescript-eslint')).default
|
|
26
|
-
// eslint-disable-next-line import-x/no-unresolved
|
|
27
|
-
const eslintPluginFunctional = (await import('eslint-plugin-functional'))
|
|
28
|
-
.default
|
|
29
26
|
|
|
30
|
-
return
|
|
31
|
-
|
|
32
|
-
...tseslint.config({
|
|
27
|
+
return defineConfig(
|
|
28
|
+
{
|
|
33
29
|
files: typeScriptFileGlobs,
|
|
34
30
|
extends: [
|
|
35
31
|
tseslint.configs.eslintRecommended,
|
|
36
|
-
|
|
32
|
+
tseslint.configs.recommendedTypeChecked,
|
|
33
|
+
eslintPluginImportX.configs['typescript'],
|
|
37
34
|
esmConfig,
|
|
38
35
|
],
|
|
39
36
|
languageOptions: {
|
|
@@ -45,16 +42,7 @@ async function generateTypeScriptConfig() {
|
|
|
45
42
|
project: ['./tsconfig*.json', './packages/*/tsconfig*.json'],
|
|
46
43
|
},
|
|
47
44
|
},
|
|
48
|
-
settings: {
|
|
49
|
-
'import-x/resolver': {
|
|
50
|
-
typescript: true,
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
plugins: {
|
|
54
|
-
functional: eslintPluginFunctional,
|
|
55
|
-
},
|
|
56
45
|
rules: {
|
|
57
|
-
...eslintPluginImportX.configs['typescript']?.rules,
|
|
58
46
|
// separate type exports which allow certain optimizations within compilers
|
|
59
47
|
'@typescript-eslint/consistent-type-exports': [
|
|
60
48
|
'error',
|
|
@@ -123,47 +111,6 @@ async function generateTypeScriptConfig() {
|
|
|
123
111
|
'@typescript-eslint/switch-exhaustiveness-check': 'error',
|
|
124
112
|
// ignore static function as those are not supposed to use `this`
|
|
125
113
|
'@typescript-eslint/unbound-method': ['error', { ignoreStatic: true }],
|
|
126
|
-
// use with functional/type-declaration-immutability
|
|
127
|
-
'functional/prefer-immutable-types': [
|
|
128
|
-
'error',
|
|
129
|
-
{
|
|
130
|
-
// as there is no native way to achieve `ReadonlyDeep` in TypeScript
|
|
131
|
-
enforcement: 'ReadonlyShallow',
|
|
132
|
-
// reduce the difficult to use this rule
|
|
133
|
-
ignoreInferredTypes: true,
|
|
134
|
-
// escape hatch without using eslint-disable
|
|
135
|
-
ignoreNamePattern: /Mutable$/u.source,
|
|
136
|
-
ignoreTypePattern: [
|
|
137
|
-
/^React\./u.source, // Some React types does not work with `Readonly`
|
|
138
|
-
],
|
|
139
|
-
},
|
|
140
|
-
],
|
|
141
|
-
// forbid unnecessary callback wrapper
|
|
142
|
-
'functional/prefer-tacit': 'error',
|
|
143
|
-
// use with functional/prefer-immutable-types
|
|
144
|
-
'functional/type-declaration-immutability': [
|
|
145
|
-
'error',
|
|
146
|
-
{
|
|
147
|
-
rules: [
|
|
148
|
-
{
|
|
149
|
-
identifiers: '.+',
|
|
150
|
-
immutability: 'ReadonlyShallow',
|
|
151
|
-
comparator: 'AtLeast',
|
|
152
|
-
// modified from https://github.com/eslint-functional/eslint-plugin-functional/blob/main/docs/rules/type-declaration-immutability.md#preset-overrides
|
|
153
|
-
fixer: [
|
|
154
|
-
{
|
|
155
|
-
pattern: /^(Array|Map|Set)<(.+)>$/u.source,
|
|
156
|
-
replace: /Readonly\$1<\$2>/u.source,
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
pattern: /^(.+)$/u.source,
|
|
160
|
-
replace: /Readonly<\$1>/u.source,
|
|
161
|
-
},
|
|
162
|
-
],
|
|
163
|
-
},
|
|
164
|
-
],
|
|
165
|
-
},
|
|
166
|
-
],
|
|
167
114
|
'no-restricted-syntax': [
|
|
168
115
|
'error',
|
|
169
116
|
{
|
|
@@ -183,8 +130,7 @@ async function generateTypeScriptConfig() {
|
|
|
183
130
|
// It is disabled in recommended config but re-enabled here to enforce a subset of global variables that supported by both node.js and browsers
|
|
184
131
|
'no-undef': 'error',
|
|
185
132
|
},
|
|
186
|
-
}
|
|
187
|
-
// @ts-expect-error As previous item's type is not correct, this item is affected too
|
|
133
|
+
},
|
|
188
134
|
{
|
|
189
135
|
files: typeScriptTestFileGlobs,
|
|
190
136
|
rules: {
|
|
@@ -196,11 +142,10 @@ async function generateTypeScriptConfig() {
|
|
|
196
142
|
'jest/unbound-method': ['error', { ignoreStatic: true }],
|
|
197
143
|
},
|
|
198
144
|
},
|
|
199
|
-
|
|
145
|
+
)
|
|
200
146
|
}
|
|
201
147
|
|
|
202
|
-
|
|
203
|
-
const cjsConfig = {
|
|
148
|
+
const cjsConfig = defineConfig({
|
|
204
149
|
languageOptions: {
|
|
205
150
|
globals: globals.commonjs,
|
|
206
151
|
sourceType: 'script',
|
|
@@ -209,10 +154,9 @@ const cjsConfig = {
|
|
|
209
154
|
// commonjs must use strict mode
|
|
210
155
|
strict: ['error', 'global'],
|
|
211
156
|
},
|
|
212
|
-
}
|
|
157
|
+
})
|
|
213
158
|
|
|
214
|
-
|
|
215
|
-
const esmConfig = {
|
|
159
|
+
const esmConfig = defineConfig({
|
|
216
160
|
languageOptions: {
|
|
217
161
|
sourceType: 'module',
|
|
218
162
|
},
|
|
@@ -225,16 +169,25 @@ const esmConfig = {
|
|
|
225
169
|
// auto sort import statements
|
|
226
170
|
'simple-import-sort/imports': 'error',
|
|
227
171
|
},
|
|
228
|
-
}
|
|
172
|
+
})
|
|
229
173
|
|
|
230
|
-
|
|
231
|
-
const baseConfig = [
|
|
174
|
+
const baseConfig = defineConfig(
|
|
232
175
|
js.configs.recommended,
|
|
233
|
-
eslintPluginRegexp.configs['flat/recommended'],
|
|
234
176
|
{
|
|
235
|
-
|
|
177
|
+
extends: [eslintPluginEslintCommentsConfigs['recommended']],
|
|
178
|
+
rules: {
|
|
179
|
+
// allow disable eslint rules for whole file without re-enable it in the end of the file
|
|
180
|
+
'@eslint-community/eslint-comments/disable-enable-pair': [
|
|
181
|
+
'error',
|
|
182
|
+
{ allowWholeFile: true },
|
|
183
|
+
],
|
|
184
|
+
// make sure every eslint-disable comments are in use
|
|
185
|
+
'@eslint-community/eslint-comments/no-unused-disable': 'error',
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
extends: [eslintPluginImportX.flatConfigs.recommended],
|
|
236
190
|
rules: {
|
|
237
|
-
...eslintPluginImportX.flatConfigs.recommended.rules,
|
|
238
191
|
// this rule doesn't support commonjs, some dependencies are using commonjs
|
|
239
192
|
'import-x/default': 'off',
|
|
240
193
|
// Does not work after upgrading to eslint-plugin-import-x v4, got this error message: `sourceType 'module' is not supported when ecmaVersion < 2015. Consider adding `{ ecmaVersion: 2015 }` to the parser options. (undefined:undefined)`
|
|
@@ -309,27 +262,17 @@ const baseConfig = [
|
|
|
309
262
|
},
|
|
310
263
|
},
|
|
311
264
|
{
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
languageOptions: {
|
|
317
|
-
ecmaVersion: 2023,
|
|
318
|
-
globals: {
|
|
319
|
-
...globals.es2023,
|
|
320
|
-
/* Not using `node` to explicitly import node.js only built-in modules, e.g.
|
|
321
|
-
* import { Buffer } from 'node:buffer'
|
|
322
|
-
* import process from 'node:process'
|
|
323
|
-
*/
|
|
324
|
-
...globals['shared-node-browser'],
|
|
325
|
-
},
|
|
265
|
+
extends: [eslintPluginRegexp.configs['flat/recommended']],
|
|
266
|
+
rules: {
|
|
267
|
+
// enable regexp strict mode (use `v` flag instead when it is widely supported)
|
|
268
|
+
'regexp/require-unicode-regexp': 'error',
|
|
326
269
|
},
|
|
270
|
+
},
|
|
271
|
+
{
|
|
327
272
|
plugins: {
|
|
328
|
-
'@eslint-community/eslint-comments': eslintPluginEslintComments,
|
|
329
273
|
unicorn: eslintPluginUnicorn,
|
|
330
274
|
},
|
|
331
275
|
rules: {
|
|
332
|
-
...eslintPluginEslintComments.configs['recommended']?.rules,
|
|
333
276
|
...Object.fromEntries(
|
|
334
277
|
Object.entries(
|
|
335
278
|
eslintPluginUnicorn.configs['flat/recommended']?.rules ?? {},
|
|
@@ -341,13 +284,40 @@ const baseConfig = [
|
|
|
341
284
|
)
|
|
342
285
|
}),
|
|
343
286
|
),
|
|
344
|
-
//
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
//
|
|
350
|
-
'
|
|
287
|
+
// use with `unicorn/throw-new-error`
|
|
288
|
+
// disallow builtins to be created without `new` operator, to be consistent with es6 class syntax
|
|
289
|
+
'unicorn/new-for-builtins': 'error',
|
|
290
|
+
// some legacy projects still use commonjs
|
|
291
|
+
'unicorn/prefer-module': 'off',
|
|
292
|
+
// `querySelector` is slower than `getElementById`
|
|
293
|
+
'unicorn/prefer-query-selector': 'off',
|
|
294
|
+
// `Array.from(iterable)` is more readable than `[...iterable]`
|
|
295
|
+
'unicorn/prefer-spread': 'off',
|
|
296
|
+
// sometimes it is less readable using ternary expressions
|
|
297
|
+
'unicorn/prefer-ternary': 'off',
|
|
298
|
+
// webpack support on `top level await` is still experimental, and some legacy projects still use commonjs
|
|
299
|
+
'unicorn/prefer-top-level-await': 'off',
|
|
300
|
+
// use with `unicorn/new-for-builtins`
|
|
301
|
+
'unicorn/throw-new-error': 'error',
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
linterOptions: {
|
|
306
|
+
reportUnusedDisableDirectives: 'error',
|
|
307
|
+
reportUnusedInlineConfigs: 'error',
|
|
308
|
+
},
|
|
309
|
+
languageOptions: {
|
|
310
|
+
ecmaVersion: 2023,
|
|
311
|
+
globals: {
|
|
312
|
+
...globals.es2023,
|
|
313
|
+
/* Not using `node` to explicitly import node.js only built-in modules, e.g.
|
|
314
|
+
* import { Buffer } from 'node:buffer'
|
|
315
|
+
* import process from 'node:process'
|
|
316
|
+
*/
|
|
317
|
+
...globals['shared-node-browser'],
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
rules: {
|
|
351
321
|
// always use named function for easier to debug via stack trace
|
|
352
322
|
'func-names': ['error', 'as-needed'],
|
|
353
323
|
// prefer explicitly convert type for readability
|
|
@@ -364,49 +334,31 @@ const baseConfig = [
|
|
|
364
334
|
destructuring: 'all',
|
|
365
335
|
},
|
|
366
336
|
],
|
|
367
|
-
// enable regexp strict mode (use `v` flag instead when it is widely supported)
|
|
368
|
-
'regexp/require-unicode-regexp': 'error',
|
|
369
|
-
// use with `unicorn/throw-new-error`
|
|
370
|
-
// disallow builtins to be created without `new` operator, to be consistent with es6 class syntax
|
|
371
|
-
'unicorn/new-for-builtins': 'error',
|
|
372
|
-
// some legacy projects still use commonjs
|
|
373
|
-
'unicorn/prefer-module': 'off',
|
|
374
|
-
// `querySelector` is slower than `getElementById`
|
|
375
|
-
'unicorn/prefer-query-selector': 'off',
|
|
376
|
-
// `Array.from(iterable)` is more readable than `[...iterable]`
|
|
377
|
-
'unicorn/prefer-spread': 'off',
|
|
378
|
-
// sometimes it is less readable using ternary expressions
|
|
379
|
-
'unicorn/prefer-ternary': 'off',
|
|
380
|
-
// webpack support on `top level await` is still experimental, and some legacy projects still use commonjs
|
|
381
|
-
'unicorn/prefer-top-level-await': 'off',
|
|
382
|
-
// use with `unicorn/new-for-builtins`
|
|
383
|
-
'unicorn/throw-new-error': 'error',
|
|
384
337
|
},
|
|
385
338
|
},
|
|
386
339
|
{
|
|
387
340
|
files: ['**/*.js'],
|
|
388
|
-
|
|
341
|
+
extends: [isESM() ? esmConfig : cjsConfig],
|
|
389
342
|
},
|
|
390
343
|
{
|
|
391
344
|
files: ['**/*.cjs'],
|
|
392
|
-
|
|
345
|
+
extends: [cjsConfig],
|
|
393
346
|
},
|
|
394
347
|
{
|
|
395
348
|
files: ['**/*.mjs'],
|
|
396
|
-
|
|
397
|
-
},
|
|
398
|
-
{
|
|
399
|
-
files: testFileGlobs,
|
|
400
|
-
...eslintPluginJest.configs['flat/recommended'],
|
|
401
|
-
...eslintPluginJest.configs['flat/style'],
|
|
349
|
+
extends: [esmConfig],
|
|
402
350
|
},
|
|
403
351
|
{
|
|
404
352
|
files: testFileGlobs,
|
|
353
|
+
extends: [
|
|
354
|
+
eslintPluginJest.configs['flat/recommended'],
|
|
355
|
+
eslintPluginJest.configs['flat/style'],
|
|
356
|
+
],
|
|
405
357
|
rules: {
|
|
406
358
|
// make sure lifecycle hooks on the top for readability
|
|
407
359
|
'jest/prefer-hooks-on-top': 'error',
|
|
408
360
|
},
|
|
409
361
|
},
|
|
410
|
-
|
|
411
|
-
|
|
362
|
+
await generateTypeScriptConfig(),
|
|
363
|
+
)
|
|
412
364
|
export default baseConfig
|
package/bases/browser.mjs
CHANGED
|
@@ -1,30 +1,26 @@
|
|
|
1
1
|
import { hasDep } from '@foray1010/common-presets-utils'
|
|
2
2
|
import restrictedGlobals from 'confusing-browser-globals'
|
|
3
|
+
// eslint-disable-next-line import-x/extensions, import-x/no-unresolved
|
|
4
|
+
import { defineConfig } from 'eslint/config'
|
|
3
5
|
import eslintPluginCompat from 'eslint-plugin-compat'
|
|
4
6
|
import eslintPluginTestingLibrary from 'eslint-plugin-testing-library'
|
|
5
7
|
import globals from 'globals'
|
|
6
8
|
|
|
7
9
|
import { testFileGlobs } from '../constants.mjs'
|
|
8
10
|
|
|
9
|
-
/** @typedef {import('../types/internal.d.ts').EslintConfig} EslintConfig */
|
|
10
|
-
|
|
11
|
-
/** @returns {Promise<EslintConfig>} */
|
|
12
11
|
async function generateJestDomConfig() {
|
|
13
12
|
// `eslint-plugin-jest-dom` depends on `@testing-library/dom` package
|
|
14
|
-
if (!hasDep('@testing-library/dom')) return
|
|
13
|
+
if (!hasDep('@testing-library/dom')) return defineConfig({})
|
|
15
14
|
|
|
16
15
|
const eslintPluginJestDom = (await import('eslint-plugin-jest-dom')).default
|
|
17
16
|
|
|
18
|
-
return
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
},
|
|
23
|
-
]
|
|
17
|
+
return defineConfig({
|
|
18
|
+
files: testFileGlobs,
|
|
19
|
+
extends: [eslintPluginJestDom.configs['flat/recommended']],
|
|
20
|
+
})
|
|
24
21
|
}
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
const browserConfig = [
|
|
23
|
+
const browserConfig = defineConfig(
|
|
28
24
|
{
|
|
29
25
|
languageOptions: {
|
|
30
26
|
globals: {
|
|
@@ -44,22 +40,14 @@ const browserConfig = [
|
|
|
44
40
|
'no-restricted-globals': ['error', ...restrictedGlobals],
|
|
45
41
|
},
|
|
46
42
|
},
|
|
47
|
-
|
|
48
|
-
{
|
|
49
|
-
files: testFileGlobs,
|
|
50
|
-
plugins: {
|
|
51
|
-
'testing-library': eslintPluginTestingLibrary,
|
|
52
|
-
},
|
|
53
|
-
rules: {
|
|
54
|
-
...eslintPluginTestingLibrary.configs['flat/dom']?.rules,
|
|
55
|
-
},
|
|
56
|
-
},
|
|
43
|
+
await generateJestDomConfig(),
|
|
57
44
|
{
|
|
58
45
|
files: testFileGlobs,
|
|
46
|
+
extends: [eslintPluginTestingLibrary.configs['flat/dom']],
|
|
59
47
|
rules: {
|
|
60
48
|
// allow to use nodejs modules in tests
|
|
61
49
|
'import-x/no-nodejs-modules': 'off',
|
|
62
50
|
},
|
|
63
51
|
},
|
|
64
|
-
|
|
52
|
+
)
|
|
65
53
|
export default browserConfig
|
package/bases/ignores.mjs
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
// eslint-disable-next-line import-x/extensions, import-x/no-unresolved
|
|
2
|
+
import { defineConfig, globalIgnores } from 'eslint/config'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
'**/node_modules/**',
|
|
13
|
-
],
|
|
14
|
-
},
|
|
15
|
-
]
|
|
4
|
+
const ignoresConfig = defineConfig(
|
|
5
|
+
globalIgnores([
|
|
6
|
+
'**/.yarn/**',
|
|
7
|
+
'**/build/**',
|
|
8
|
+
'**/coverage/**',
|
|
9
|
+
'**/dist/**',
|
|
10
|
+
'**/node_modules/**',
|
|
11
|
+
]),
|
|
12
|
+
)
|
|
16
13
|
export default ignoresConfig
|
package/bases/node.mjs
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import { isESM } from '@foray1010/common-presets-utils'
|
|
2
|
+
// eslint-disable-next-line import-x/extensions, import-x/no-unresolved
|
|
3
|
+
import { defineConfig } from 'eslint/config'
|
|
2
4
|
import eslintPluginN from 'eslint-plugin-n'
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/** @type {EslintConfig[number]} */
|
|
7
|
-
const cjsConfig = {
|
|
6
|
+
const cjsConfig = defineConfig({
|
|
8
7
|
languageOptions: {
|
|
9
8
|
globals: {
|
|
10
9
|
__dirname: 'readonly',
|
|
11
10
|
__filename: 'readonly',
|
|
12
11
|
},
|
|
13
12
|
},
|
|
14
|
-
}
|
|
13
|
+
})
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
const nodeConfig = [
|
|
15
|
+
const nodeConfig = defineConfig(
|
|
18
16
|
{
|
|
19
17
|
plugins: {
|
|
20
18
|
n: eslintPluginN,
|
|
@@ -67,12 +65,12 @@ const nodeConfig = [
|
|
|
67
65
|
: [
|
|
68
66
|
{
|
|
69
67
|
files: ['**/*.js'],
|
|
70
|
-
|
|
68
|
+
extends: [cjsConfig],
|
|
71
69
|
},
|
|
72
70
|
]),
|
|
73
71
|
{
|
|
74
72
|
files: ['**/*.{cjs,cts}'],
|
|
75
|
-
|
|
73
|
+
extends: [cjsConfig],
|
|
76
74
|
},
|
|
77
|
-
|
|
75
|
+
)
|
|
78
76
|
export default nodeConfig
|
package/bases/prettier.mjs
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
+
// eslint-disable-next-line import-x/extensions, import-x/no-unresolved
|
|
2
|
+
import { defineConfig } from 'eslint/config'
|
|
1
3
|
// eslint-disable-next-line import-x/extensions
|
|
2
4
|
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
|
|
3
5
|
|
|
4
|
-
/** @typedef {import('../types/internal.d.ts').EslintConfig} EslintConfig */
|
|
5
|
-
|
|
6
|
-
/** @type {EslintConfig} */
|
|
7
6
|
// should be placed at the end to override other configs
|
|
8
|
-
const prettierConfig =
|
|
7
|
+
const prettierConfig = defineConfig(
|
|
9
8
|
// This includes `eslint-config-prettier` as peer dependency
|
|
10
9
|
eslintPluginPrettierRecommended,
|
|
11
|
-
|
|
10
|
+
)
|
|
12
11
|
export default prettierConfig
|
package/bases/react.mjs
CHANGED
|
@@ -1,26 +1,24 @@
|
|
|
1
|
+
// eslint-disable-next-line import-x/extensions, import-x/no-unresolved
|
|
2
|
+
import { defineConfig } from 'eslint/config'
|
|
1
3
|
import eslintPluginReact from 'eslint-plugin-react'
|
|
2
4
|
import eslintPluginReactHooks from 'eslint-plugin-react-hooks'
|
|
3
5
|
import eslintPluginTestingLibrary from 'eslint-plugin-testing-library'
|
|
4
6
|
|
|
5
7
|
import { testFileGlobs } from '../constants.mjs'
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
/** @type {EslintConfig} */
|
|
10
|
-
const reactConfig = [
|
|
11
|
-
eslintPluginReact.configs.flat.recommended,
|
|
12
|
-
eslintPluginReact.configs.flat['jsx-runtime'],
|
|
9
|
+
const reactConfig = defineConfig(
|
|
13
10
|
{
|
|
14
11
|
settings: {
|
|
15
12
|
react: {
|
|
16
13
|
version: 'detect',
|
|
17
14
|
},
|
|
18
15
|
},
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
extends: [
|
|
17
|
+
eslintPluginReact.configs.flat.recommended,
|
|
18
|
+
eslintPluginReact.configs.flat['jsx-runtime'],
|
|
19
|
+
eslintPluginReactHooks.configs['recommended-latest'],
|
|
20
|
+
],
|
|
22
21
|
rules: {
|
|
23
|
-
...eslintPluginReactHooks.configs['recommended']?.rules,
|
|
24
22
|
// avoid unexpected form submits
|
|
25
23
|
'react/button-has-type': 'error',
|
|
26
24
|
'react/jsx-no-useless-fragment': [
|
|
@@ -61,13 +59,7 @@ const reactConfig = [
|
|
|
61
59
|
},
|
|
62
60
|
{
|
|
63
61
|
files: testFileGlobs,
|
|
64
|
-
|
|
65
|
-
// Do not use flat config directly as eslint v9 does not support duplicated plugins (already defined in browser.mjs)
|
|
66
|
-
...eslintPluginTestingLibrary.configs['flat/react']?.rules,
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
files: testFileGlobs,
|
|
62
|
+
extends: [eslintPluginTestingLibrary.configs['flat/react']],
|
|
71
63
|
rules: {
|
|
72
64
|
// avoid using unnecessary `await` as workaround for `not wrapped in act(...)` warnings
|
|
73
65
|
'testing-library/no-await-sync-events': [
|
|
@@ -82,5 +74,5 @@ const reactConfig = [
|
|
|
82
74
|
'testing-library/prefer-user-event': 'error',
|
|
83
75
|
},
|
|
84
76
|
},
|
|
85
|
-
|
|
77
|
+
)
|
|
86
78
|
export default reactConfig
|
package/index.mjs
CHANGED
|
@@ -1,33 +1,29 @@
|
|
|
1
|
+
// eslint-disable-next-line import-x/extensions, import-x/no-unresolved
|
|
2
|
+
import { defineConfig } from 'eslint/config'
|
|
3
|
+
|
|
1
4
|
import baseConfig from './bases/base.mjs'
|
|
2
5
|
import browserConfig from './bases/browser.mjs'
|
|
3
6
|
import nodeConfig from './bases/node.mjs'
|
|
4
7
|
import prettierConfig from './bases/prettier.mjs'
|
|
5
8
|
import reactConfig from './bases/react.mjs'
|
|
6
9
|
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export const eslintBrowserConfig = [
|
|
13
|
-
...baseConfig,
|
|
14
|
-
...browserConfig,
|
|
15
|
-
...prettierConfig,
|
|
16
|
-
]
|
|
10
|
+
export const eslintBrowserConfig = defineConfig(
|
|
11
|
+
baseConfig,
|
|
12
|
+
browserConfig,
|
|
13
|
+
prettierConfig,
|
|
14
|
+
)
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
]
|
|
16
|
+
export const eslintNodeConfig = defineConfig(
|
|
17
|
+
baseConfig,
|
|
18
|
+
nodeConfig,
|
|
19
|
+
prettierConfig,
|
|
20
|
+
)
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
]
|
|
22
|
+
export const eslintReactConfig = defineConfig(
|
|
23
|
+
baseConfig,
|
|
24
|
+
browserConfig,
|
|
25
|
+
reactConfig,
|
|
26
|
+
prettierConfig,
|
|
27
|
+
)
|
|
32
28
|
|
|
33
29
|
export { default as eslintIgnoresConfig } from './bases/ignores.mjs'
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@foray1010/eslint-config",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "15.0.0",
|
|
5
5
|
"homepage": "https://github.com/foray1010/common-presets/tree/master/packages/eslint-config#readme",
|
|
6
6
|
"bugs": "https://github.com/foray1010/common-presets/issues",
|
|
7
7
|
"repository": {
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"eslint-config-prettier": "^10.0.2",
|
|
28
28
|
"eslint-import-resolver-typescript": "^3.8.3",
|
|
29
29
|
"eslint-plugin-compat": "^6.0.2",
|
|
30
|
-
"eslint-plugin-functional": "^9.0.1",
|
|
31
30
|
"eslint-plugin-import-x": "^4.6.1",
|
|
32
31
|
"eslint-plugin-jest": "^28.11.0",
|
|
33
32
|
"eslint-plugin-jest-dom": "^5.5.0",
|
|
@@ -48,7 +47,7 @@
|
|
|
48
47
|
},
|
|
49
48
|
"peerDependencies": {
|
|
50
49
|
"@testing-library/dom": "^10.0.0",
|
|
51
|
-
"eslint": "^9.
|
|
50
|
+
"eslint": "^9.22.0",
|
|
52
51
|
"prettier": "^3.0.0",
|
|
53
52
|
"typescript": "^5.0.2"
|
|
54
53
|
},
|
|
@@ -66,5 +65,5 @@
|
|
|
66
65
|
"publishConfig": {
|
|
67
66
|
"access": "public"
|
|
68
67
|
},
|
|
69
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "321d60ec7b05e7c861bf019fb4c3f7b1410795e9"
|
|
70
69
|
}
|
package/utils/applyConfig.mjs
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
|
-
|
|
3
|
-
import { supportedFilesGlob } from '../constants.mjs'
|
|
4
|
-
|
|
5
|
-
/** @typedef {import('../types/internal.d.ts').EslintConfig} EslintConfig */
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Extend the flat configs with default files and ignores
|
|
9
|
-
* @param {{
|
|
10
|
-
* readonly filePrefixes: string | string[],
|
|
11
|
-
* readonly ignores?: string[] | undefined
|
|
12
|
-
* }} options
|
|
13
|
-
* @param {EslintConfig} eslintConfig
|
|
14
|
-
* @returns {EslintConfig}
|
|
15
|
-
*/
|
|
16
|
-
export function applyConfig(options, eslintConfig) {
|
|
17
|
-
const filePrefixes = [options.filePrefixes].flat()
|
|
18
|
-
if (filePrefixes.length === 0) {
|
|
19
|
-
throw new TypeError('filePrefixes must not be empty')
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Do not allow string such as "eslint:recommended" because it cannot be overridden by files/ignores
|
|
23
|
-
for (const config of eslintConfig) {
|
|
24
|
-
if (typeof config === 'string') {
|
|
25
|
-
throw new TypeError(
|
|
26
|
-
`Cannot extend ${config} with files/ignores, use \`@eslint/js\` instead`,
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (Object.keys(config).includes('ignores')) {
|
|
31
|
-
throw new TypeError('Do not use `ignores` in config')
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return eslintConfig.map((config) => {
|
|
36
|
-
const files = generateCombinations(filePrefixes, config.files)
|
|
37
|
-
return {
|
|
38
|
-
...config,
|
|
39
|
-
...(files ? { files } : {}),
|
|
40
|
-
...(options.ignores ? { ignores: options.ignores } : {}),
|
|
41
|
-
}
|
|
42
|
-
})
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* @param {string[]} prefixes
|
|
47
|
-
* @param {EslintConfig[number]['files']} originalGlobs
|
|
48
|
-
* @returns {string[] | undefined}
|
|
49
|
-
*/
|
|
50
|
-
function generateCombinations(prefixes, originalGlobs) {
|
|
51
|
-
if (!originalGlobs || originalGlobs.length === 0) {
|
|
52
|
-
return prefixes.map((prefix) => path.join(prefix, supportedFilesGlob))
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const verifiedOriginalGlobs = originalGlobs.filter(
|
|
56
|
-
/** @returns {originalGlob is string} */
|
|
57
|
-
(originalGlob) => typeof originalGlob === 'string',
|
|
58
|
-
)
|
|
59
|
-
if (originalGlobs.length !== verifiedOriginalGlobs.length) {
|
|
60
|
-
throw new TypeError(
|
|
61
|
-
`Do not support using non-string value in files/ignores`,
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return prefixes.flatMap((prefix) => {
|
|
66
|
-
return verifiedOriginalGlobs.flatMap((originalGlob) => {
|
|
67
|
-
const signRegexp = /^!/u
|
|
68
|
-
const sign = originalGlob.match(signRegexp)?.[0] ?? ''
|
|
69
|
-
return sign + path.join(prefix, originalGlob.replace(signRegexp, ''))
|
|
70
|
-
})
|
|
71
|
-
})
|
|
72
|
-
}
|