@mlaursen/eslint-config 12.0.6 → 12.0.7
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/dist/index.d.ts +296 -13
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +645 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +30 -20
- package/src/constants.ts +2 -2
- package/src/react.ts +2 -2
- package/dist/base.d.ts +0 -11
- package/dist/base.js +0 -51
- package/dist/constants.d.ts +0 -12
- package/dist/constants.js +0 -15
- package/dist/gitignore.d.ts +0 -23
- package/dist/gitignore.js +0 -26
- package/dist/index.js +0 -28
- package/dist/jsxA11y.d.ts +0 -11
- package/dist/jsxA11y.js +0 -37
- package/dist/mui.d.ts +0 -2
- package/dist/mui.js +0 -16
- package/dist/react.d.ts +0 -57
- package/dist/react.js +0 -82
- package/dist/recommended.d.ts +0 -18
- package/dist/recommended.js +0 -45
- package/dist/recommendedFrontend.d.ts +0 -18
- package/dist/recommendedFrontend.js +0 -46
- package/dist/scripts.d.ts +0 -11
- package/dist/scripts.js +0 -19
- package/dist/testing-library.d.ts +0 -35
- package/dist/testing-library.js +0 -57
- package/dist/testing.d.ts +0 -54
- package/dist/testing.js +0 -112
- package/dist/typescript.d.ts +0 -41
- package/dist/typescript.js +0 -161
- package/dist/unicorn.d.ts +0 -2
- package/dist/unicorn.js +0 -56
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,645 @@
|
|
|
1
|
+
import eslint from '@eslint/js';
|
|
2
|
+
import jsxA11yPlugin from 'eslint-plugin-jsx-a11y';
|
|
3
|
+
import reactPlugin from 'eslint-plugin-react';
|
|
4
|
+
import reactHooksPlugin from 'eslint-plugin-react-hooks';
|
|
5
|
+
import reactRefreshPlugin from 'eslint-plugin-react-refresh';
|
|
6
|
+
import vitestPlugin from '@vitest/eslint-plugin';
|
|
7
|
+
import jestPlugin from 'eslint-plugin-jest';
|
|
8
|
+
import jestDomPlugin from 'eslint-plugin-jest-dom';
|
|
9
|
+
import tseslint from 'typescript-eslint';
|
|
10
|
+
import eslintPluiginUnicorn from 'eslint-plugin-unicorn';
|
|
11
|
+
import testingLibraryPlugin from 'eslint-plugin-testing-library';
|
|
12
|
+
import { includeIgnoreFile } from '@eslint/compat';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
|
|
15
|
+
const DEV_WARNING_PROD_ERROR = process.env["NODE_ENV"] === "production" ? "error" : "warn";
|
|
16
|
+
/**
|
|
17
|
+
* This is a "temporary" workaround until autofixable rules can be disabled with
|
|
18
|
+
* a config option because of the "autofix + format(+ save)?" behavior. It
|
|
19
|
+
* should be something closer to `DEV_WARN_PROD_ERROR_AND_FIX`
|
|
20
|
+
*/ const DEV_OFF_PROD_ERROR = process.env["NODE_ENV"] === "production" ? "error" : "off";
|
|
21
|
+
const BASE_NAME = "@mlaursen/eslint-config";
|
|
22
|
+
const TS_FILES = [
|
|
23
|
+
"**/*.{ts,tsx,mts,mtsx}"
|
|
24
|
+
];
|
|
25
|
+
const TEST_FILES = [
|
|
26
|
+
"**/__tests__/**",
|
|
27
|
+
"**/*.{spec,test}.{ts,tsx,js,jsx}"
|
|
28
|
+
];
|
|
29
|
+
const JSX_FILES = [
|
|
30
|
+
"**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}"
|
|
31
|
+
];
|
|
32
|
+
const VITE_MAIN_FILES = [
|
|
33
|
+
"**/main.tsx"
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @example
|
|
38
|
+
* ```js
|
|
39
|
+
* import { configs } from "@mlaursen/eslint-config";
|
|
40
|
+
* import { defineConfig } from "eslint/config";
|
|
41
|
+
*
|
|
42
|
+
* export default defineConfig(configs.base);
|
|
43
|
+
* ```
|
|
44
|
+
*/ const base = [
|
|
45
|
+
eslint.configs.recommended,
|
|
46
|
+
{
|
|
47
|
+
name: `${BASE_NAME}/base`,
|
|
48
|
+
rules: {
|
|
49
|
+
// I use typescript instead
|
|
50
|
+
"no-undef": "off",
|
|
51
|
+
// You normally do not want `console.{whatever}` in prod but is fine for
|
|
52
|
+
// development in debugging
|
|
53
|
+
"no-console": DEV_WARNING_PROD_ERROR,
|
|
54
|
+
"no-var": "error",
|
|
55
|
+
"no-use-before-define": "warn",
|
|
56
|
+
// I want to enforce all statements to require curly braces even if it
|
|
57
|
+
// could be omitted for consistency
|
|
58
|
+
curly: "error",
|
|
59
|
+
// Since this is auto-fixable, I like `{ someproperty }` instead of
|
|
60
|
+
// `{ someproperty: someproperty }`
|
|
61
|
+
"object-shorthand": [
|
|
62
|
+
"error",
|
|
63
|
+
"always"
|
|
64
|
+
],
|
|
65
|
+
// This is about the same as `object-shorthand`. Only rename if it has to
|
|
66
|
+
// be renamed
|
|
67
|
+
"no-useless-rename": [
|
|
68
|
+
"error"
|
|
69
|
+
],
|
|
70
|
+
"no-eval": "error",
|
|
71
|
+
"no-alert": "error",
|
|
72
|
+
"no-lonely-if": "error",
|
|
73
|
+
"no-else-return": "error",
|
|
74
|
+
eqeqeq: "error",
|
|
75
|
+
// 100% stylistic, but do not allow `a = b = c = "whatever"` / `let a = whatever, b = whatever, c = whatever;`
|
|
76
|
+
// these should be different statements
|
|
77
|
+
"no-multi-assign": "error",
|
|
78
|
+
"no-sequences": "error",
|
|
79
|
+
// use template strings instead
|
|
80
|
+
"no-multi-str": "error",
|
|
81
|
+
// better to use new variables most of the time
|
|
82
|
+
"no-param-reassign": "error",
|
|
83
|
+
// i'd never hit these, but who trusts other people and AI?
|
|
84
|
+
"no-return-assign": "error",
|
|
85
|
+
"no-script-url": "error"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* import { configs } from "@mlaursen/eslint-config";
|
|
94
|
+
* import { defineConfig } from "eslint/config";
|
|
95
|
+
*
|
|
96
|
+
* export default defineConfig(configs.jsxA11y);
|
|
97
|
+
* ```
|
|
98
|
+
*/ const jsxA11y = [
|
|
99
|
+
{
|
|
100
|
+
name: `${BASE_NAME}/jsx-a11y`,
|
|
101
|
+
files: JSX_FILES,
|
|
102
|
+
...jsxA11yPlugin.flatConfigs.recommended,
|
|
103
|
+
rules: {
|
|
104
|
+
...jsxA11yPlugin.flatConfigs.recommended.rules,
|
|
105
|
+
// I **only** use autoFocus within dialogs which provide the correct
|
|
106
|
+
// context for screen readers.
|
|
107
|
+
"jsx-a11y/no-autofocus": "off"
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: `${BASE_NAME}/jsx-a11y/testing`,
|
|
112
|
+
files: TEST_FILES,
|
|
113
|
+
rules: {
|
|
114
|
+
"jsx-a11y/anchor-has-content": "off",
|
|
115
|
+
"jsx-a11y/click-events-have-key-events": "off",
|
|
116
|
+
"jsx-a11y/no-static-element-interactions": "off"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @example
|
|
123
|
+
* ```ts
|
|
124
|
+
* import { configs } from "@mlaursen/eslint-config";
|
|
125
|
+
* import { defineConfig } from "eslint/config";
|
|
126
|
+
*
|
|
127
|
+
* export default defineConfig(configs.react());
|
|
128
|
+
*
|
|
129
|
+
* // or with react compiler rules enabled
|
|
130
|
+
* export default defineConfig(configs.react(true));
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* Enables:
|
|
134
|
+
* - `eslint-plugin-react` with:
|
|
135
|
+
* - flat.recommended
|
|
136
|
+
* - flat['jsx-runtime']
|
|
137
|
+
* - `eslint-plugin-react-hooks` with:
|
|
138
|
+
* - recommended rules
|
|
139
|
+
* - compiler rules (if `true` is provided)
|
|
140
|
+
*/ const react = (options = {})=>{
|
|
141
|
+
const { reactRefresh, reactCompiler } = options;
|
|
142
|
+
return [
|
|
143
|
+
{
|
|
144
|
+
...reactPlugin.configs.flat["recommended"],
|
|
145
|
+
name: `${BASE_NAME}/react`,
|
|
146
|
+
files: JSX_FILES,
|
|
147
|
+
settings: {
|
|
148
|
+
react: {
|
|
149
|
+
version: "detect"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
rules: {
|
|
153
|
+
...reactPlugin.configs.flat["recommended"]?.rules,
|
|
154
|
+
...reactPlugin.configs.flat["jsx-runtime"]?.rules
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
...reactHooksPlugin.configs.flat.recommended,
|
|
159
|
+
name: `${BASE_NAME}/react-hooks`,
|
|
160
|
+
rules: {
|
|
161
|
+
...reactCompiler && reactHooksPlugin.configs.flat.recommended.rules,
|
|
162
|
+
"react-hooks/rules-of-hooks": "error",
|
|
163
|
+
"react-hooks/exhaustive-deps": [
|
|
164
|
+
"error",
|
|
165
|
+
{
|
|
166
|
+
additionalHooks: "(useIsomorphicLayoutEffect)"
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
...reactRefresh ? [
|
|
172
|
+
{
|
|
173
|
+
...reactRefreshPlugin.configs[reactRefresh],
|
|
174
|
+
name: `${BASE_NAME}/react-refresh`,
|
|
175
|
+
ignores: [
|
|
176
|
+
"**/test-utils*",
|
|
177
|
+
"**/test-utils/**"
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
] : []
|
|
181
|
+
];
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @example
|
|
186
|
+
* ```ts
|
|
187
|
+
* import { configs } from "@mlaursen/eslint-config";
|
|
188
|
+
* import { defineConfig } from "eslint/config";
|
|
189
|
+
*
|
|
190
|
+
* export default defineConfig(configs.scripts);
|
|
191
|
+
* ```
|
|
192
|
+
*/ const scripts = [
|
|
193
|
+
{
|
|
194
|
+
name: `${BASE_NAME}/scripts`,
|
|
195
|
+
files: [
|
|
196
|
+
"scripts/**"
|
|
197
|
+
],
|
|
198
|
+
rules: {
|
|
199
|
+
"no-console": "off"
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @example
|
|
206
|
+
* ```ts
|
|
207
|
+
* import { configs } from "@mlaursen/eslint-config";
|
|
208
|
+
* import { defineConfig } from "eslint/config";
|
|
209
|
+
*
|
|
210
|
+
* export default defineConfig(configs.vitest);
|
|
211
|
+
* ```
|
|
212
|
+
*/ const vitest = [
|
|
213
|
+
{
|
|
214
|
+
name: `${BASE_NAME}/vitest`,
|
|
215
|
+
files: TEST_FILES,
|
|
216
|
+
plugins: {
|
|
217
|
+
vitest: vitestPlugin
|
|
218
|
+
},
|
|
219
|
+
rules: {
|
|
220
|
+
...vitestPlugin.configs.recommended.rules,
|
|
221
|
+
"vitest/no-alias-methods": "error",
|
|
222
|
+
"vitest/no-focused-tests": DEV_OFF_PROD_ERROR,
|
|
223
|
+
"vitest/no-disabled-tests": DEV_OFF_PROD_ERROR,
|
|
224
|
+
"vitest/no-duplicate-hooks": "error",
|
|
225
|
+
"vitest/no-standalone-expect": "error",
|
|
226
|
+
"vitest/prefer-expect-resolves": "error",
|
|
227
|
+
"vitest/prefer-spy-on": "error",
|
|
228
|
+
"vitest/prefer-vi-mocked": "error"
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
];
|
|
232
|
+
/**
|
|
233
|
+
* @example
|
|
234
|
+
* ```ts
|
|
235
|
+
* import { configs } from "@mlaursen/eslint-config";
|
|
236
|
+
* import { defineConfig } from "eslint/config";
|
|
237
|
+
*
|
|
238
|
+
* export default defineConfig(configs.jest);
|
|
239
|
+
* ```
|
|
240
|
+
*/ const jest = [
|
|
241
|
+
{
|
|
242
|
+
name: `${BASE_NAME}/jest`,
|
|
243
|
+
files: TEST_FILES,
|
|
244
|
+
...jestPlugin.configs["flat/recommended"]
|
|
245
|
+
}
|
|
246
|
+
];
|
|
247
|
+
/**
|
|
248
|
+
* @example
|
|
249
|
+
* ```ts
|
|
250
|
+
* import { configs } from "@mlaursen/eslint-config";
|
|
251
|
+
* import { defineConfig } from "eslint/config";
|
|
252
|
+
*
|
|
253
|
+
* export default defineConfig([
|
|
254
|
+
* ...configs.jest,
|
|
255
|
+
* ...configs.jestDom,
|
|
256
|
+
* ]);
|
|
257
|
+
* ```
|
|
258
|
+
*/ const jestDom = [
|
|
259
|
+
{
|
|
260
|
+
name: `${BASE_NAME}/jest-dom`,
|
|
261
|
+
files: TEST_FILES,
|
|
262
|
+
...jestDomPlugin.configs["flat/recommended"]
|
|
263
|
+
}
|
|
264
|
+
];
|
|
265
|
+
/**
|
|
266
|
+
* @example
|
|
267
|
+
* ```ts
|
|
268
|
+
* import { configs } from "@mlaursen/eslint-config";
|
|
269
|
+
* import { defineConfig } from "eslint/config";
|
|
270
|
+
*
|
|
271
|
+
* export default defineConfig(configs.testing({ testFramework: "jest" }));
|
|
272
|
+
*
|
|
273
|
+
* // or
|
|
274
|
+
* export default defineConfig(configs.testing({ testFramework: "vitest" }));
|
|
275
|
+
* ```
|
|
276
|
+
*/ const testing = (options = {})=>{
|
|
277
|
+
const { testFramework = "vitest" } = options;
|
|
278
|
+
let config;
|
|
279
|
+
switch(testFramework){
|
|
280
|
+
case "jest":
|
|
281
|
+
config = jest;
|
|
282
|
+
break;
|
|
283
|
+
case "vitest":
|
|
284
|
+
config = vitest;
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
return [
|
|
288
|
+
...config,
|
|
289
|
+
...jestDom
|
|
290
|
+
];
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* @example
|
|
295
|
+
* ```ts
|
|
296
|
+
* import { configs, gitignore } from "@mlaursen/eslint-config";
|
|
297
|
+
* import { defineConfig } from "eslint/config";
|
|
298
|
+
*
|
|
299
|
+
* export default defineConfig([
|
|
300
|
+
* gitignore(import.meta.url),
|
|
301
|
+
* ...configs.typescript(),
|
|
302
|
+
* ]);
|
|
303
|
+
* ```
|
|
304
|
+
*/ const typescript = (options = {})=>{
|
|
305
|
+
const { tsconfigRootDir, strictTypeChecked } = options;
|
|
306
|
+
const configs = [
|
|
307
|
+
...base,
|
|
308
|
+
...tseslint.configs.strict,
|
|
309
|
+
{
|
|
310
|
+
name: `${BASE_NAME}/typescript`,
|
|
311
|
+
files: TS_FILES,
|
|
312
|
+
rules: {
|
|
313
|
+
// I normally do not want unified signatures since it helps improve type
|
|
314
|
+
// inference with function overloading
|
|
315
|
+
"@typescript-eslint/unified-signatures": "off",
|
|
316
|
+
// I prefer specifying when something is used only as a type
|
|
317
|
+
"@typescript-eslint/consistent-type-imports": [
|
|
318
|
+
"error",
|
|
319
|
+
{
|
|
320
|
+
fixStyle: "inline-type-imports"
|
|
321
|
+
}
|
|
322
|
+
],
|
|
323
|
+
// I prefer shorthand syntax
|
|
324
|
+
"@typescript-eslint/array-type": [
|
|
325
|
+
"error",
|
|
326
|
+
{
|
|
327
|
+
default: "array"
|
|
328
|
+
}
|
|
329
|
+
],
|
|
330
|
+
// I prefer using `interface` over `type = {}`
|
|
331
|
+
"@typescript-eslint/consistent-type-definitions": [
|
|
332
|
+
"error",
|
|
333
|
+
"interface"
|
|
334
|
+
],
|
|
335
|
+
// Allow expressions to work with react hooks. Annoying to have to
|
|
336
|
+
// typedef each arrow function in a `useEffect` or `useCallback` when
|
|
337
|
+
// it can be derived.
|
|
338
|
+
"@typescript-eslint/explicit-function-return-type": [
|
|
339
|
+
"error",
|
|
340
|
+
{
|
|
341
|
+
allowExpressions: true,
|
|
342
|
+
// allow FC definitions for React
|
|
343
|
+
allowTypedFunctionExpressions: true
|
|
344
|
+
}
|
|
345
|
+
],
|
|
346
|
+
"@typescript-eslint/no-unused-vars": [
|
|
347
|
+
"error",
|
|
348
|
+
{
|
|
349
|
+
argsIgnorePattern: "^_",
|
|
350
|
+
varsIgnorePattern: "^_"
|
|
351
|
+
}
|
|
352
|
+
],
|
|
353
|
+
"no-use-before-define": "off",
|
|
354
|
+
"@typescript-eslint/no-use-before-define": [
|
|
355
|
+
"warn",
|
|
356
|
+
{
|
|
357
|
+
ignoreTypeReferences: true
|
|
358
|
+
}
|
|
359
|
+
]
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
name: `${BASE_NAME}/typescript/tests`,
|
|
364
|
+
files: TEST_FILES,
|
|
365
|
+
rules: {
|
|
366
|
+
// allow tests to be less strict
|
|
367
|
+
"@typescript-eslint/ban-ts-comment": "off",
|
|
368
|
+
"@typescript-eslint/explicit-function-return-type": "off",
|
|
369
|
+
"@typescript-eslint/no-empty-function": "off",
|
|
370
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
371
|
+
"@typescript-eslint/no-object-literal-type-assertion": "off",
|
|
372
|
+
"@typescript-eslint/no-var-requires": "off"
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
name: `${BASE_NAME}/typescript/vite`,
|
|
377
|
+
files: VITE_MAIN_FILES,
|
|
378
|
+
rules: {
|
|
379
|
+
// allow `createRoot(document.getElementById("root")).render(...)` for
|
|
380
|
+
// `vite` without disabling eslint
|
|
381
|
+
"@typescript-eslint/no-non-null-assertion": "off"
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
];
|
|
385
|
+
if (tsconfigRootDir) {
|
|
386
|
+
configs.push({
|
|
387
|
+
name: `${BASE_NAME}/typescript-type-checking-language-options`,
|
|
388
|
+
languageOptions: {
|
|
389
|
+
parserOptions: {
|
|
390
|
+
projectService: strictTypeChecked,
|
|
391
|
+
tsconfigRootDir
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
if (strictTypeChecked) {
|
|
397
|
+
configs.push(...tseslint.configs.strictTypeCheckedOnly, {
|
|
398
|
+
name: `${BASE_NAME}/typescript-type-checking`,
|
|
399
|
+
files: TS_FILES,
|
|
400
|
+
rules: {
|
|
401
|
+
// I do not enable the `noUncheckedIndexedAccess` tsconfig option, so I
|
|
402
|
+
// still need to verify that stuff exists. There are other cases where I
|
|
403
|
+
// know it exists, so I can ignore those as well
|
|
404
|
+
"@typescript-eslint/no-unnecessary-condition": "off",
|
|
405
|
+
// I never use `this`
|
|
406
|
+
"@typescript-eslint/unbound-method": "off",
|
|
407
|
+
"@typescript-eslint/restrict-template-expressions": [
|
|
408
|
+
"error",
|
|
409
|
+
{
|
|
410
|
+
allowNumber: true
|
|
411
|
+
}
|
|
412
|
+
],
|
|
413
|
+
// I want to allow `onClick={async (event) => { ... }}`
|
|
414
|
+
"@typescript-eslint/no-misused-promises": [
|
|
415
|
+
"error",
|
|
416
|
+
{
|
|
417
|
+
checksVoidReturn: false
|
|
418
|
+
}
|
|
419
|
+
]
|
|
420
|
+
}
|
|
421
|
+
}, {
|
|
422
|
+
name: `${BASE_NAME}/typescript-type-checking/tests`,
|
|
423
|
+
files: TEST_FILES,
|
|
424
|
+
rules: {
|
|
425
|
+
// like base typescript, can be less strict in tests
|
|
426
|
+
"@typescript-eslint/no-unsafe-return": "off",
|
|
427
|
+
"@typescript-eslint/no-unsafe-assignment": "off",
|
|
428
|
+
"@typescript-eslint/restrict-template-expressions": "off"
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
return configs;
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
const unicorn = [
|
|
436
|
+
{
|
|
437
|
+
...eslintPluiginUnicorn.configs.recommended,
|
|
438
|
+
name: `${BASE_NAME}/unicorn`,
|
|
439
|
+
rules: {
|
|
440
|
+
...eslintPluiginUnicorn.configs.recommended.rules,
|
|
441
|
+
// this flags `dist` and `dest` which is annoying
|
|
442
|
+
"unicorn/prevent-abbreviations": "off",
|
|
443
|
+
// I do not like using the default exports from `node:path`, `node:fs`,
|
|
444
|
+
// etc
|
|
445
|
+
"unicorn/import-style": "off",
|
|
446
|
+
// I want PascalCase for React components/classes, camelCase for others.
|
|
447
|
+
// Don't care enough to enforce through a rule and don't think it's
|
|
448
|
+
// possible.
|
|
449
|
+
"unicorn/filename-case": "off",
|
|
450
|
+
// prettier instead
|
|
451
|
+
"unicorn/empty-brace-spaces": "off",
|
|
452
|
+
// I like `null`
|
|
453
|
+
"unicorn/no-null": "off",
|
|
454
|
+
// the description is incorrect since it attempts converting multi-line
|
|
455
|
+
// statements to ternary which is awful:
|
|
456
|
+
//
|
|
457
|
+
// > This rule enforces the use of ternary expressions over 'simple'
|
|
458
|
+
// > if-else statements, where 'simple' means the consequent and alternate
|
|
459
|
+
// > are each one line and have the same basic type and form.
|
|
460
|
+
"unicorn/prefer-ternary": "off",
|
|
461
|
+
// I don't care about adding braces to switch cases. I'd prefer
|
|
462
|
+
// `["error", "avoid"]` more though since it only adds them when needed.
|
|
463
|
+
"unicorn/switch-case-braces": "off"
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
name: `${BASE_NAME}/unicorn/vite`,
|
|
468
|
+
files: VITE_MAIN_FILES,
|
|
469
|
+
rules: {
|
|
470
|
+
// allow `createRoot(document.getElementById("root")).render(...)` for
|
|
471
|
+
// `vite` without disabling eslint
|
|
472
|
+
"unicorn/prefer-query-selector": "off"
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
name: `${BASE_NAME}/unicorn/testing`,
|
|
477
|
+
files: TEST_FILES,
|
|
478
|
+
rules: {
|
|
479
|
+
// allow functions to be scoped to tests
|
|
480
|
+
"unicorn/consistent-function-scoping": "off"
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
];
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* @example
|
|
487
|
+
* ```ts
|
|
488
|
+
* import { configs, gitignore } from "@mlaursen/eslint-config";
|
|
489
|
+
* import { defineConfig } from "eslint/config";
|
|
490
|
+
*
|
|
491
|
+
* export default defineConfig([
|
|
492
|
+
* gitignore(import.meta.url),
|
|
493
|
+
* ...configs.recommended(),
|
|
494
|
+
* ]);
|
|
495
|
+
* ```
|
|
496
|
+
*/ const recommended = (options = {})=>{
|
|
497
|
+
return [
|
|
498
|
+
...typescript(options),
|
|
499
|
+
...scripts,
|
|
500
|
+
...testing(options),
|
|
501
|
+
...unicorn
|
|
502
|
+
];
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
const mui = [
|
|
506
|
+
{
|
|
507
|
+
name: `${BASE_NAME}/material-ui`,
|
|
508
|
+
files: JSX_FILES,
|
|
509
|
+
rules: {
|
|
510
|
+
"no-restricted-imports": [
|
|
511
|
+
"error",
|
|
512
|
+
{
|
|
513
|
+
// https://mui.com/material-ui/guides/minimizing-bundle-size/#enforce-best-practices-with-eslint
|
|
514
|
+
patterns: [
|
|
515
|
+
{
|
|
516
|
+
regex: "^@mui/(?!(x-|utils))[^/]+$"
|
|
517
|
+
}
|
|
518
|
+
]
|
|
519
|
+
}
|
|
520
|
+
]
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
];
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* @example
|
|
527
|
+
* ```ts
|
|
528
|
+
* import { configs } from "@mlaursen/eslint-config";
|
|
529
|
+
* import { defineConfig } from "eslint/config";
|
|
530
|
+
*
|
|
531
|
+
* export default defineConfig([
|
|
532
|
+
* ...configs.react,
|
|
533
|
+
* ...configs.jest,
|
|
534
|
+
* ...configs.jestDom,
|
|
535
|
+
* ...configs.testingLibraryReact
|
|
536
|
+
* ]);
|
|
537
|
+
* ```
|
|
538
|
+
*
|
|
539
|
+
* NOTE: Only choose this or the {@link testingLibraryDom}. Do not use
|
|
540
|
+
* both.
|
|
541
|
+
*/ const testingLibraryReact = [
|
|
542
|
+
{
|
|
543
|
+
name: `${BASE_NAME}/testing-library/react`,
|
|
544
|
+
files: TEST_FILES,
|
|
545
|
+
...testingLibraryPlugin.configs["flat/react"],
|
|
546
|
+
rules: {
|
|
547
|
+
...testingLibraryPlugin.configs["flat/react"].rules,
|
|
548
|
+
// it can be useful to reassign screen.* queries without reusing to
|
|
549
|
+
// verify it still exists
|
|
550
|
+
"no-useless-assignment": "off"
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
];
|
|
554
|
+
/**
|
|
555
|
+
* @example
|
|
556
|
+
* ```ts
|
|
557
|
+
* import { configs, defineConfig } from "@mlaursen/eslint-config";
|
|
558
|
+
*
|
|
559
|
+
* export default defineConfig([
|
|
560
|
+
* ...configs.jest,
|
|
561
|
+
* ...configs.jestDom,
|
|
562
|
+
* ...configs.testingLibraryDom
|
|
563
|
+
* ]);
|
|
564
|
+
* ```
|
|
565
|
+
*
|
|
566
|
+
* NOTE: Only choose this or the {@link testingLibraryReact}. Do not use
|
|
567
|
+
* both.
|
|
568
|
+
*/ const testingLibraryDom = [
|
|
569
|
+
{
|
|
570
|
+
name: `${BASE_NAME}/testing-library/dom`,
|
|
571
|
+
files: TEST_FILES,
|
|
572
|
+
...testingLibraryPlugin.configs["flat/dom"],
|
|
573
|
+
rules: {
|
|
574
|
+
...testingLibraryPlugin.configs["flat/dom"].rules,
|
|
575
|
+
// it can be useful to reassign screen.* queries without reusing to
|
|
576
|
+
// verify it still exists
|
|
577
|
+
"no-useless-assignment": "off"
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
];
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* @example
|
|
584
|
+
* ```ts
|
|
585
|
+
* import { configs, gitignore } from "@mlaursen/eslint-config";
|
|
586
|
+
* import { defineConfig } from "eslint/config";
|
|
587
|
+
*
|
|
588
|
+
* export default defineConfig([
|
|
589
|
+
* gitignore(import.meta.url),
|
|
590
|
+
* ...configs.recommendedFrontend(),
|
|
591
|
+
* ]);
|
|
592
|
+
* ```
|
|
593
|
+
*/ const recommendedFrontend = (options = {})=>{
|
|
594
|
+
return [
|
|
595
|
+
...recommended(options),
|
|
596
|
+
...mui,
|
|
597
|
+
...react(options),
|
|
598
|
+
...jsxA11y,
|
|
599
|
+
...testingLibraryReact
|
|
600
|
+
];
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* @example
|
|
605
|
+
* ```ts
|
|
606
|
+
* import { configs, gitignore } from "@mlaursen/eslint-config";
|
|
607
|
+
* import { defineConfig } from "eslint/config";
|
|
608
|
+
*
|
|
609
|
+
* export default defineConfig([gitignore(import.meta.url), ...configs.typescript]);
|
|
610
|
+
* ```
|
|
611
|
+
*
|
|
612
|
+
* @example .gitignore in a different folder
|
|
613
|
+
* ```ts
|
|
614
|
+
* import { configs, gitignore } from "@mlaursen/eslint-config";
|
|
615
|
+
* import { defineConfig } from "eslint/config";
|
|
616
|
+
* import { join } from "node:path";
|
|
617
|
+
*
|
|
618
|
+
* export default defineConfig([
|
|
619
|
+
* gitignore(join(import.meta.url, "..", "..")),
|
|
620
|
+
* ...configs.typescript,
|
|
621
|
+
* ]);
|
|
622
|
+
* ```
|
|
623
|
+
*/ function gitignore(importMetaUrl) {
|
|
624
|
+
return includeIgnoreFile(fileURLToPath(new URL(".gitignore", importMetaUrl)));
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const configs = {
|
|
628
|
+
recommended,
|
|
629
|
+
recommendedFrontend,
|
|
630
|
+
base,
|
|
631
|
+
jest,
|
|
632
|
+
jestDom,
|
|
633
|
+
react,
|
|
634
|
+
typescript,
|
|
635
|
+
testingLibraryDom,
|
|
636
|
+
testingLibraryReact,
|
|
637
|
+
scripts,
|
|
638
|
+
jsxA11y,
|
|
639
|
+
testing,
|
|
640
|
+
vitest,
|
|
641
|
+
unicorn
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
export { BASE_NAME, DEV_OFF_PROD_ERROR, DEV_WARNING_PROD_ERROR, JSX_FILES, TEST_FILES, TS_FILES, VITE_MAIN_FILES, configs, gitignore };
|
|
645
|
+
//# sourceMappingURL=index.mjs.map
|