@wistia/oxlint-config 0.3.5 → 0.4.1
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/README.md +67 -71
- package/configs/react.mjs +1 -0
- package/configs/typescript.mjs +4 -0
- package/package.json +17 -13
- package/rules/react.mjs +377 -0
package/README.md
CHANGED
|
@@ -23,11 +23,10 @@ Create an `oxlint.config.ts` in your project root:
|
|
|
23
23
|
|
|
24
24
|
```ts
|
|
25
25
|
import { defineConfig } from 'oxlint';
|
|
26
|
-
import {
|
|
26
|
+
import { typescriptConfig, reactConfig } from '@wistia/oxlint-config';
|
|
27
27
|
|
|
28
28
|
export default defineConfig({
|
|
29
|
-
|
|
30
|
-
rules: typescriptRules.rules,
|
|
29
|
+
extends: [typescriptConfig, reactConfig],
|
|
31
30
|
});
|
|
32
31
|
```
|
|
33
32
|
|
|
@@ -35,106 +34,102 @@ export default defineConfig({
|
|
|
35
34
|
|
|
36
35
|
```ts
|
|
37
36
|
import { defineConfig } from 'oxlint';
|
|
38
|
-
import {
|
|
37
|
+
import { javascriptConfig } from '@wistia/oxlint-config';
|
|
39
38
|
|
|
40
39
|
export default defineConfig({
|
|
41
|
-
|
|
42
|
-
rules: {
|
|
43
|
-
...baseRules.rules,
|
|
44
|
-
...importRules.rules,
|
|
45
|
-
...promiseRules.rules,
|
|
46
|
-
},
|
|
40
|
+
extends: [javascriptConfig],
|
|
47
41
|
});
|
|
48
42
|
```
|
|
49
43
|
|
|
50
|
-
## Available
|
|
51
|
-
|
|
52
|
-
### Base rules
|
|
53
|
-
|
|
54
|
-
| Export | Description |
|
|
55
|
-
| ----------------- | ------------------------------------------------------------------------ |
|
|
56
|
-
| `baseRules` | Core ESLint rules (correctness + suggestions) |
|
|
57
|
-
| `importRules` | Import/export validation (native + eslint-plugin-import-x via jsPlugins) |
|
|
58
|
-
| `promiseRules` | Promise handling rules |
|
|
59
|
-
| `typescriptRules` | TypeScript-specific rules (disables superseded base rules) |
|
|
44
|
+
## Available configs
|
|
60
45
|
|
|
61
|
-
###
|
|
46
|
+
### Base configs
|
|
62
47
|
|
|
63
|
-
| Export
|
|
64
|
-
|
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `nodeRules` | Node.js rules (native + eslint-plugin-n via jsPlugins) |
|
|
68
|
-
| `vitestRules` | Vitest testing rules (see note below) |
|
|
69
|
-
| `playwrightRules` | Playwright E2E testing rules (via jsPlugins) |
|
|
70
|
-
| `storybookRules` | Storybook story conventions (via jsPlugins) |
|
|
71
|
-
| `testingLibraryRules` | Testing Library + jest-dom rules (via jsPlugins) |
|
|
72
|
-
| `styledComponentsRules` | Styled Components accessibility rules (via jsPlugins) |
|
|
73
|
-
| `filenamesRules` | Filename convention rules (via jsPlugins) |
|
|
74
|
-
| `barrelFilesRules` | Barrel file rules (via jsPlugins) |
|
|
48
|
+
| Export | Description |
|
|
49
|
+
| ------------------ | ----------------------------------------------------------------------------- |
|
|
50
|
+
| `javascriptConfig` | Base config for any JS project (base + import + promise + barrel-files rules) |
|
|
51
|
+
| `typescriptConfig` | TypeScript projects (includes all JavaScript rules + TypeScript rules) |
|
|
75
52
|
|
|
76
|
-
|
|
53
|
+
### Feature configs
|
|
77
54
|
|
|
78
|
-
|
|
55
|
+
Feature configs wrap their rules in `overrides` with default file patterns, so they scope correctly when extended at the top level.
|
|
79
56
|
|
|
80
|
-
|
|
57
|
+
| Export | Default file patterns | Description |
|
|
58
|
+
| ------------------------ | ----------------------------------------- | ------------------------------------- |
|
|
59
|
+
| `reactConfig` | all files (global) | React component + accessibility rules |
|
|
60
|
+
| `styledComponentsConfig` | all files (global) | Styled Components accessibility rules |
|
|
61
|
+
| `vitestConfig` | `**/*.{test,spec,vitest}.{ts,tsx,js,jsx}` | Vitest testing rules |
|
|
62
|
+
| `testingLibraryConfig` | `**/*.{test,spec,vitest}.{ts,tsx,js,jsx}` | Testing Library + jest-dom rules |
|
|
63
|
+
| `storybookConfig` | `**/*.stories.{ts,tsx,js,jsx}` | Storybook story conventions |
|
|
64
|
+
| `nodeConfig` | `**/*.{mts,mjs,cjs}` | Node.js-specific rules |
|
|
65
|
+
| `playwrightConfig` | `**/*.spec.{ts,tsx,js}`, `**/e2e/**/*.ts` | Playwright E2E testing rules |
|
|
81
66
|
|
|
82
|
-
|
|
67
|
+
**Composing configs:**
|
|
83
68
|
|
|
84
69
|
```ts
|
|
85
70
|
import { defineConfig } from 'oxlint';
|
|
86
71
|
import {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
72
|
+
typescriptConfig,
|
|
73
|
+
reactConfig,
|
|
74
|
+
styledComponentsConfig,
|
|
75
|
+
vitestConfig,
|
|
76
|
+
testingLibraryConfig,
|
|
77
|
+
storybookConfig,
|
|
78
|
+
nodeConfig,
|
|
93
79
|
} from '@wistia/oxlint-config';
|
|
94
80
|
|
|
95
81
|
export default defineConfig({
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
82
|
+
extends: [
|
|
83
|
+
typescriptConfig,
|
|
84
|
+
reactConfig,
|
|
85
|
+
styledComponentsConfig,
|
|
86
|
+
vitestConfig,
|
|
87
|
+
testingLibraryConfig,
|
|
88
|
+
storybookConfig,
|
|
89
|
+
nodeConfig,
|
|
102
90
|
],
|
|
103
|
-
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Overriding rules
|
|
95
|
+
|
|
96
|
+
Add a `rules` section — your rules take precedence over the shared configs:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
export default defineConfig({
|
|
100
|
+
extends: [typescriptConfig, reactConfig],
|
|
104
101
|
rules: {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
...typescriptRules.rules,
|
|
108
|
-
...reactRules.rules,
|
|
109
|
-
...reactA11yRules.rules,
|
|
102
|
+
'typescript/no-explicit-any': 'off',
|
|
103
|
+
'react/no-clone-element': 'off',
|
|
110
104
|
},
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
File-specific overrides use `overrides`. Note that `extends` is not supported inside `overrides` — use rule imports for those:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { defineConfig } from 'oxlint';
|
|
112
|
+
import { typescriptConfig, vitestRules } from '@wistia/oxlint-config';
|
|
113
|
+
|
|
114
|
+
export default defineConfig({
|
|
115
|
+
extends: [typescriptConfig],
|
|
111
116
|
overrides: [
|
|
112
117
|
{
|
|
113
|
-
files: ['**/*.test.ts', '**/*.
|
|
118
|
+
files: ['**/*.test.ts', '**/*.vitest.ts'],
|
|
114
119
|
plugins: vitestRules.plugins,
|
|
115
120
|
jsPlugins: vitestRules.jsPlugins,
|
|
116
|
-
rules:
|
|
121
|
+
rules: {
|
|
122
|
+
...vitestRules.rules,
|
|
123
|
+
// project-specific overrides
|
|
124
|
+
'jest/expect-expect': ['error', { assertFunctionNames: ['expect', 'expectValid'] }],
|
|
125
|
+
},
|
|
117
126
|
},
|
|
118
127
|
],
|
|
119
128
|
});
|
|
120
129
|
```
|
|
121
130
|
|
|
122
|
-
## Overriding rules
|
|
123
|
-
|
|
124
|
-
Add overrides after the spread -- your rules take precedence:
|
|
125
|
-
|
|
126
|
-
```ts
|
|
127
|
-
rules: {
|
|
128
|
-
...typescriptRules.rules,
|
|
129
|
-
// override
|
|
130
|
-
'typescript/no-explicit-any': 'off',
|
|
131
|
-
},
|
|
132
|
-
```
|
|
133
|
-
|
|
134
131
|
## Running oxlint
|
|
135
132
|
|
|
136
|
-
Add a script to your `package.json`:
|
|
137
|
-
|
|
138
133
|
```json
|
|
139
134
|
{
|
|
140
135
|
"scripts": {
|
|
@@ -150,6 +145,7 @@ Add a script to your `package.json`:
|
|
|
150
145
|
3. Person/team adding new rules handles upgrading consumers and fixing violations
|
|
151
146
|
4. Rules should always be set to `error`, never `warn`
|
|
152
147
|
5. Add short description of rule and link to rule documentation in code comments
|
|
148
|
+
6. Never delete a rule — set it to `off` with a comment explaining why
|
|
153
149
|
|
|
154
150
|
## ESLint parity
|
|
155
151
|
|
package/configs/react.mjs
CHANGED
package/configs/typescript.mjs
CHANGED
|
@@ -6,6 +6,10 @@ import { typescriptRules } from '../rules/typescript.mjs';
|
|
|
6
6
|
import { barrelFilesRules } from '../rules/barrel-files.mjs';
|
|
7
7
|
|
|
8
8
|
export default defineConfig({
|
|
9
|
+
options: {
|
|
10
|
+
typeAware: true,
|
|
11
|
+
typeCheck: true,
|
|
12
|
+
},
|
|
9
13
|
plugins: [
|
|
10
14
|
...baseRules.plugins,
|
|
11
15
|
...importRules.plugins,
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wistia/oxlint-config",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Wistia's Oxlint configurations",
|
|
5
|
-
"packageManager": "yarn@4.
|
|
5
|
+
"packageManager": "yarn@4.14.1",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
8
8
|
"configs",
|
|
@@ -34,29 +34,33 @@
|
|
|
34
34
|
"validate": "vitest run test/validate-configs.test.mjs"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"oxlint": ">= 1.0.0"
|
|
37
|
+
"oxlint": ">= 1.0.0",
|
|
38
|
+
"oxlint-tsgolint": ">= 1.0.0"
|
|
38
39
|
},
|
|
39
40
|
"dependencies": {
|
|
40
|
-
"@
|
|
41
|
+
"@eslint-react/eslint-plugin": "^4.2.3",
|
|
42
|
+
"@vitest/eslint-plugin": "^1.6.16",
|
|
41
43
|
"eslint-plugin-barrel-files": "^3.0.1",
|
|
42
44
|
"eslint-plugin-import-x": "^4.16.2",
|
|
43
45
|
"eslint-plugin-jest-dom": "^5.5.0",
|
|
44
46
|
"eslint-plugin-n": "^17.24.0",
|
|
45
47
|
"eslint-plugin-no-only-tests": "^3.3.0",
|
|
46
|
-
"eslint-plugin-playwright": "^2.10.
|
|
47
|
-
"eslint-plugin-storybook": "^10.3.
|
|
48
|
+
"eslint-plugin-playwright": "^2.10.2",
|
|
49
|
+
"eslint-plugin-storybook": "^10.3.5",
|
|
48
50
|
"eslint-plugin-styled-components": "^0.0.0",
|
|
49
51
|
"eslint-plugin-styled-components-a11y": "^2.2.1",
|
|
50
|
-
"eslint-plugin-testing-library": "^7.16.2"
|
|
52
|
+
"eslint-plugin-testing-library": "^7.16.2",
|
|
53
|
+
"typescript": "^6.0.2"
|
|
51
54
|
},
|
|
52
55
|
"devDependencies": {
|
|
53
56
|
"@changesets/changelog-github": "^0.6.0",
|
|
54
|
-
"@changesets/cli": "^2.
|
|
55
|
-
"eslint": "^10.2.
|
|
56
|
-
"oxfmt": "^0.
|
|
57
|
-
"oxlint": "^1.
|
|
58
|
-
"
|
|
59
|
-
"
|
|
57
|
+
"@changesets/cli": "^2.31.0",
|
|
58
|
+
"eslint": "^10.2.1",
|
|
59
|
+
"oxfmt": "^0.46.0",
|
|
60
|
+
"oxlint": "^1.61.0",
|
|
61
|
+
"oxlint-tsgolint": "^0.21.1",
|
|
62
|
+
"storybook": "^10.3.5",
|
|
63
|
+
"vitest": "^4.1.5"
|
|
60
64
|
},
|
|
61
65
|
"engines": {
|
|
62
66
|
"node": "^20.19.0 || ^22.13.0 || >=24 || >=26"
|
package/rules/react.mjs
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
// Native oxlint react rules + @eslint-react/eslint-plugin via jsPlugins for rules
|
|
2
|
+
// without native equivalents.
|
|
1
3
|
export const reactRules = {
|
|
2
4
|
plugins: ['react'],
|
|
5
|
+
jsPlugins: [{ name: '@eslint-react', specifier: '@eslint-react/eslint-plugin' }],
|
|
3
6
|
rules: {
|
|
4
7
|
// -- React Core --
|
|
5
8
|
|
|
@@ -232,5 +235,379 @@ export const reactRules = {
|
|
|
232
235
|
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-handler-names.md
|
|
233
236
|
// decision: stylistic choice best left for formatter
|
|
234
237
|
'react/jsx-handler-names': 'off',
|
|
238
|
+
|
|
239
|
+
// -- Rules via jsPlugins (@eslint-react/eslint-plugin) --
|
|
240
|
+
// These rules have no native oxlint equivalent.
|
|
241
|
+
|
|
242
|
+
// --- Core React rules ---
|
|
243
|
+
|
|
244
|
+
// Validates higher order functions defining nested components or hooks
|
|
245
|
+
// https://eslint-react.xyz/docs/rules/component-hook-factories
|
|
246
|
+
'@eslint-react/component-hook-factories': 'error',
|
|
247
|
+
|
|
248
|
+
// Validates usage of Error Boundaries instead of try/catch for child errors
|
|
249
|
+
// https://eslint-react.xyz/docs/rules/error-boundaries
|
|
250
|
+
'@eslint-react/error-boundaries': 'error',
|
|
251
|
+
|
|
252
|
+
// Verify the list of the dependencies for Hooks like useEffect and similar
|
|
253
|
+
// https://eslint-react.xyz/docs/rules/exhaustive-deps
|
|
254
|
+
'@eslint-react/exhaustive-deps': 'error',
|
|
255
|
+
|
|
256
|
+
// Validates against mutating props, state, and other immutable values
|
|
257
|
+
// https://eslint-react.xyz/docs/rules/immutability
|
|
258
|
+
'@eslint-react/immutability': 'error',
|
|
259
|
+
|
|
260
|
+
// Prevent accidental JS comments from being injected into JSX as text
|
|
261
|
+
// https://eslint-react.xyz/docs/rules/jsx-no-comment-textnodes
|
|
262
|
+
'@eslint-react/jsx-no-comment-textnodes': 'error',
|
|
263
|
+
|
|
264
|
+
// Prevents unintentional '$' sign before expression in JSX
|
|
265
|
+
// https://eslint-react.xyz/docs/rules/jsx-no-leaked-dollar
|
|
266
|
+
'@eslint-react/jsx-no-leaked-dollar': 'error',
|
|
267
|
+
|
|
268
|
+
// Enforce key prop comes before spread to avoid overriding
|
|
269
|
+
// https://eslint-react.xyz/docs/rules/jsx-no-key-after-spread
|
|
270
|
+
'@eslint-react/jsx-no-key-after-spread': 'error',
|
|
271
|
+
|
|
272
|
+
// Prevent passing of children as props
|
|
273
|
+
// https://eslint-react.xyz/docs/rules/jsx-no-children-prop
|
|
274
|
+
'@eslint-react/jsx-no-children-prop': 'error',
|
|
275
|
+
|
|
276
|
+
// Prevent children prop used alongside children in JSX
|
|
277
|
+
// https://eslint-react.xyz/docs/rules/jsx-no-children-prop-with-children
|
|
278
|
+
'@eslint-react/jsx-no-children-prop-with-children': 'error',
|
|
279
|
+
|
|
280
|
+
// Disallow unnecessary fragments
|
|
281
|
+
// https://eslint-react.xyz/docs/rules/jsx-no-useless-fragment
|
|
282
|
+
'@eslint-react/jsx-no-useless-fragment': 'error',
|
|
283
|
+
|
|
284
|
+
// Prevent leaked semicolons in JSX
|
|
285
|
+
// https://eslint-react.xyz/docs/rules/jsx-no-leaked-semicolon
|
|
286
|
+
'@eslint-react/jsx-no-leaked-semicolon': 'error',
|
|
287
|
+
|
|
288
|
+
// Disallow namespace in JSX
|
|
289
|
+
// https://eslint-react.xyz/docs/rules/jsx-no-namespace
|
|
290
|
+
'@eslint-react/jsx-no-namespace': 'error',
|
|
291
|
+
|
|
292
|
+
// Prevent using this.state within a this.setState
|
|
293
|
+
// https://eslint-react.xyz/docs/rules/no-access-state-in-setstate
|
|
294
|
+
'@eslint-react/no-access-state-in-setstate': 'error',
|
|
295
|
+
|
|
296
|
+
// Prevent usage of Array index in keys
|
|
297
|
+
// https://eslint-react.xyz/docs/rules/no-array-index-key
|
|
298
|
+
'@eslint-react/no-array-index-key': 'error',
|
|
299
|
+
|
|
300
|
+
// Disallow usage of Children.count
|
|
301
|
+
// https://eslint-react.xyz/docs/rules/no-children-count
|
|
302
|
+
'@eslint-react/no-children-count': 'error',
|
|
303
|
+
|
|
304
|
+
// Disallow usage of Children.forEach
|
|
305
|
+
// https://eslint-react.xyz/docs/rules/no-children-for-each
|
|
306
|
+
'@eslint-react/no-children-for-each': 'error',
|
|
307
|
+
|
|
308
|
+
// Disallow usage of Children.map
|
|
309
|
+
// https://eslint-react.xyz/docs/rules/no-children-map
|
|
310
|
+
'@eslint-react/no-children-map': 'error',
|
|
311
|
+
|
|
312
|
+
// Disallow usage of Children.only
|
|
313
|
+
// https://eslint-react.xyz/docs/rules/no-children-only
|
|
314
|
+
'@eslint-react/no-children-only': 'error',
|
|
315
|
+
|
|
316
|
+
// Disallow usage of Children.toArray
|
|
317
|
+
// https://eslint-react.xyz/docs/rules/no-children-to-array
|
|
318
|
+
'@eslint-react/no-children-to-array': 'error',
|
|
319
|
+
|
|
320
|
+
// Disallow class components (except for error boundaries)
|
|
321
|
+
// https://eslint-react.xyz/docs/rules/no-class-component
|
|
322
|
+
'@eslint-react/no-class-component': 'error',
|
|
323
|
+
|
|
324
|
+
// Disallow usage of cloneElement
|
|
325
|
+
// https://eslint-react.xyz/docs/rules/no-clone-element
|
|
326
|
+
'@eslint-react/no-clone-element': 'error',
|
|
327
|
+
|
|
328
|
+
// Disallow usage of componentWillMount
|
|
329
|
+
// https://eslint-react.xyz/docs/rules/no-component-will-mount
|
|
330
|
+
'@eslint-react/no-component-will-mount': 'error',
|
|
331
|
+
|
|
332
|
+
// Disallow usage of componentWillReceiveProps
|
|
333
|
+
// https://eslint-react.xyz/docs/rules/no-component-will-receive-props
|
|
334
|
+
'@eslint-react/no-component-will-receive-props': 'error',
|
|
335
|
+
|
|
336
|
+
// Disallow usage of componentWillUpdate
|
|
337
|
+
// https://eslint-react.xyz/docs/rules/no-component-will-update
|
|
338
|
+
'@eslint-react/no-component-will-update': 'error',
|
|
339
|
+
|
|
340
|
+
// Disallow usage of legacy Context.Provider (React 19+)
|
|
341
|
+
// https://eslint-react.xyz/docs/rules/no-context-provider
|
|
342
|
+
'@eslint-react/no-context-provider': 'error',
|
|
343
|
+
|
|
344
|
+
// Disallow usage of createRef (prefer useRef)
|
|
345
|
+
// https://eslint-react.xyz/docs/rules/no-create-ref
|
|
346
|
+
'@eslint-react/no-create-ref': 'error',
|
|
347
|
+
|
|
348
|
+
// Prevent direct mutation of this.state
|
|
349
|
+
// https://eslint-react.xyz/docs/rules/no-direct-mutation-state
|
|
350
|
+
'@eslint-react/no-direct-mutation-state': 'error',
|
|
351
|
+
|
|
352
|
+
// Disallow duplicate keys in JSX arrays
|
|
353
|
+
// https://eslint-react.xyz/docs/rules/no-duplicate-key
|
|
354
|
+
'@eslint-react/no-duplicate-key': 'error',
|
|
355
|
+
|
|
356
|
+
// Disallow usage of forwardRef (React 19+ passes ref as prop)
|
|
357
|
+
// https://eslint-react.xyz/docs/rules/no-forward-ref
|
|
358
|
+
'@eslint-react/no-forward-ref': 'error',
|
|
359
|
+
|
|
360
|
+
// Prevent implicitly passing the children prop
|
|
361
|
+
// https://eslint-react.xyz/docs/rules/no-implicit-children
|
|
362
|
+
'@eslint-react/no-implicit-children': 'error',
|
|
363
|
+
|
|
364
|
+
// Prevent implicitly passing the key prop
|
|
365
|
+
// https://eslint-react.xyz/docs/rules/no-implicit-key
|
|
366
|
+
'@eslint-react/no-implicit-key': 'error',
|
|
367
|
+
|
|
368
|
+
// Prevent implicitly passing the ref prop
|
|
369
|
+
// https://eslint-react.xyz/docs/rules/no-implicit-ref
|
|
370
|
+
'@eslint-react/no-implicit-ref': 'error',
|
|
371
|
+
|
|
372
|
+
// Prevent problematic leaked values from being rendered
|
|
373
|
+
// https://eslint-react.xyz/docs/rules/no-leaked-conditional-rendering
|
|
374
|
+
'@eslint-react/no-leaked-conditional-rendering': 'error',
|
|
375
|
+
|
|
376
|
+
// Enforce that components have a displayName for DevTools
|
|
377
|
+
// https://eslint-react.xyz/docs/rules/no-missing-component-display-name
|
|
378
|
+
'@eslint-react/no-missing-component-display-name': 'off',
|
|
379
|
+
|
|
380
|
+
// Enforce that contexts have a displayName for DevTools
|
|
381
|
+
// https://eslint-react.xyz/docs/rules/no-missing-context-display-name
|
|
382
|
+
'@eslint-react/no-missing-context-display-name': 'off',
|
|
383
|
+
|
|
384
|
+
// Enforce that every JSX element in a list has a key prop
|
|
385
|
+
// https://eslint-react.xyz/docs/rules/no-missing-key
|
|
386
|
+
'@eslint-react/no-missing-key': 'error',
|
|
387
|
+
|
|
388
|
+
// Disallow misusing captureOwnerStack
|
|
389
|
+
// https://eslint-react.xyz/docs/rules/no-misused-capture-owner-stack
|
|
390
|
+
'@eslint-react/no-misused-capture-owner-stack': 'error',
|
|
391
|
+
|
|
392
|
+
// Prevent creating unstable components inside components
|
|
393
|
+
// https://eslint-react.xyz/docs/rules/no-nested-component-definitions
|
|
394
|
+
'@eslint-react/no-nested-component-definitions': 'error',
|
|
395
|
+
|
|
396
|
+
// Prevent creating lazy components inside components
|
|
397
|
+
// https://eslint-react.xyz/docs/rules/no-nested-lazy-component-declarations
|
|
398
|
+
'@eslint-react/no-nested-lazy-component-declarations': 'error',
|
|
399
|
+
|
|
400
|
+
// Prevent usage of shouldComponentUpdate when extending React.PureComponent
|
|
401
|
+
// https://eslint-react.xyz/docs/rules/no-redundant-should-component-update
|
|
402
|
+
'@eslint-react/no-redundant-should-component-update': 'error',
|
|
403
|
+
|
|
404
|
+
// Prevent usage of setState in componentDidMount
|
|
405
|
+
// https://eslint-react.xyz/docs/rules/no-set-state-in-component-did-mount
|
|
406
|
+
'@eslint-react/no-set-state-in-component-did-mount': 'error',
|
|
407
|
+
|
|
408
|
+
// Prevent usage of setState in componentDidUpdate
|
|
409
|
+
// https://eslint-react.xyz/docs/rules/no-set-state-in-component-did-update
|
|
410
|
+
'@eslint-react/no-set-state-in-component-did-update': 'error',
|
|
411
|
+
|
|
412
|
+
// Prevent usage of setState in componentWillUpdate
|
|
413
|
+
// https://eslint-react.xyz/docs/rules/no-set-state-in-component-will-update
|
|
414
|
+
'@eslint-react/no-set-state-in-component-will-update': 'error',
|
|
415
|
+
|
|
416
|
+
// Disallow unnecessary useCallback hooks
|
|
417
|
+
// https://eslint-react.xyz/docs/rules/no-unnecessary-use-callback
|
|
418
|
+
'@eslint-react/no-unnecessary-use-callback': 'error',
|
|
419
|
+
|
|
420
|
+
// Disallow unnecessary useMemo hooks
|
|
421
|
+
// https://eslint-react.xyz/docs/rules/no-unnecessary-use-memo
|
|
422
|
+
'@eslint-react/no-unnecessary-use-memo': 'error',
|
|
423
|
+
|
|
424
|
+
// Disallow unnecessary "use" prefix on custom hooks
|
|
425
|
+
// https://eslint-react.xyz/docs/rules/no-unnecessary-use-prefix
|
|
426
|
+
'@eslint-react/no-unnecessary-use-prefix': 'error',
|
|
427
|
+
|
|
428
|
+
// Disallow usage of UNSAFE_componentWillMount
|
|
429
|
+
// https://eslint-react.xyz/docs/rules/no-unsafe-component-will-mount
|
|
430
|
+
'@eslint-react/no-unsafe-component-will-mount': 'error',
|
|
431
|
+
|
|
432
|
+
// Disallow usage of UNSAFE_componentWillReceiveProps
|
|
433
|
+
// https://eslint-react.xyz/docs/rules/no-unsafe-component-will-receive-props
|
|
434
|
+
'@eslint-react/no-unsafe-component-will-receive-props': 'error',
|
|
435
|
+
|
|
436
|
+
// Disallow usage of UNSAFE_componentWillUpdate
|
|
437
|
+
// https://eslint-react.xyz/docs/rules/no-unsafe-component-will-update
|
|
438
|
+
'@eslint-react/no-unsafe-component-will-update': 'error',
|
|
439
|
+
|
|
440
|
+
// Prevent non-stable values used as context values
|
|
441
|
+
// https://eslint-react.xyz/docs/rules/no-unstable-context-value
|
|
442
|
+
'@eslint-react/no-unstable-context-value': 'error',
|
|
443
|
+
|
|
444
|
+
// Disallow referential-type variables as default props
|
|
445
|
+
// https://eslint-react.xyz/docs/rules/no-unstable-default-props
|
|
446
|
+
'@eslint-react/no-unstable-default-props': 'error',
|
|
447
|
+
|
|
448
|
+
// Prevent declaring unused methods of component class
|
|
449
|
+
// https://eslint-react.xyz/docs/rules/no-unused-class-component-members
|
|
450
|
+
'@eslint-react/no-unused-class-component-members': 'error',
|
|
451
|
+
|
|
452
|
+
// Warn about component props that are defined but never used
|
|
453
|
+
// https://eslint-react.xyz/docs/rules/no-unused-props
|
|
454
|
+
'@eslint-react/no-unused-props': 'error',
|
|
455
|
+
|
|
456
|
+
// Prevent unused state values
|
|
457
|
+
// https://eslint-react.xyz/docs/rules/no-unused-state
|
|
458
|
+
'@eslint-react/no-unused-state': 'error',
|
|
459
|
+
|
|
460
|
+
// Prefer using use() over useContext() (React 19+)
|
|
461
|
+
// https://eslint-react.xyz/docs/rules/no-use-context
|
|
462
|
+
'@eslint-react/no-use-context': 'error',
|
|
463
|
+
|
|
464
|
+
// Enforce consistent usage of destructuring assignment of props, state, and context
|
|
465
|
+
// decision: best left up to the implementer
|
|
466
|
+
// https://eslint-react.xyz/docs/rules/prefer-destructuring-assignment
|
|
467
|
+
'@eslint-react/prefer-destructuring-assignment': 'off',
|
|
468
|
+
|
|
469
|
+
// Enforce importing React via a namespace import
|
|
470
|
+
// https://eslint-react.xyz/docs/rules/prefer-namespace-import
|
|
471
|
+
'@eslint-react/prefer-namespace-import': 'off',
|
|
472
|
+
|
|
473
|
+
// Validates that components/hooks are pure
|
|
474
|
+
// https://eslint-react.xyz/docs/rules/purity
|
|
475
|
+
'@eslint-react/purity': 'error',
|
|
476
|
+
|
|
477
|
+
// Validates correct usage of refs, not reading/writing during render
|
|
478
|
+
// https://eslint-react.xyz/docs/rules/refs
|
|
479
|
+
'@eslint-react/refs': 'error',
|
|
480
|
+
|
|
481
|
+
// Enforce Rules of Hooks
|
|
482
|
+
// https://eslint-react.xyz/docs/rules/rules-of-hooks
|
|
483
|
+
'@eslint-react/rules-of-hooks': 'error',
|
|
484
|
+
|
|
485
|
+
// Validates against calling setState synchronously in an effect
|
|
486
|
+
// https://eslint-react.xyz/docs/rules/set-state-in-effect
|
|
487
|
+
'@eslint-react/set-state-in-effect': 'error',
|
|
488
|
+
|
|
489
|
+
// Validates against setting state during render
|
|
490
|
+
// https://eslint-react.xyz/docs/rules/set-state-in-render
|
|
491
|
+
'@eslint-react/set-state-in-render': 'error',
|
|
492
|
+
|
|
493
|
+
// Validates against syntax that React does not support
|
|
494
|
+
// https://eslint-react.xyz/docs/rules/unsupported-syntax
|
|
495
|
+
'@eslint-react/unsupported-syntax': 'error',
|
|
496
|
+
|
|
497
|
+
// Validates usage of useMemo with a return value
|
|
498
|
+
// https://eslint-react.xyz/docs/rules/use-memo
|
|
499
|
+
'@eslint-react/use-memo': 'error',
|
|
500
|
+
|
|
501
|
+
// Ensure destructuring and symmetric naming of useState hook value and setter
|
|
502
|
+
// https://eslint-react.xyz/docs/rules/use-state
|
|
503
|
+
'@eslint-react/use-state': 'error',
|
|
504
|
+
|
|
505
|
+
// --- React DOM rules ---
|
|
506
|
+
|
|
507
|
+
// Warn on usage of dangerouslySetInnerHTML
|
|
508
|
+
// https://eslint-react.xyz/docs/rules/dom-no-dangerously-set-innerhtml
|
|
509
|
+
'@eslint-react/dom-no-dangerously-set-innerhtml': 'error',
|
|
510
|
+
|
|
511
|
+
// Prevent problem with children and dangerouslySetInnerHTML
|
|
512
|
+
// https://eslint-react.xyz/docs/rules/dom-no-dangerously-set-innerhtml-with-children
|
|
513
|
+
'@eslint-react/dom-no-dangerously-set-innerhtml-with-children': 'error',
|
|
514
|
+
|
|
515
|
+
// Warn against using findDOMNode()
|
|
516
|
+
// https://eslint-react.xyz/docs/rules/dom-no-find-dom-node
|
|
517
|
+
'@eslint-react/dom-no-find-dom-node': 'error',
|
|
518
|
+
|
|
519
|
+
// Disallow usage of flushSync
|
|
520
|
+
// https://eslint-react.xyz/docs/rules/dom-no-flush-sync
|
|
521
|
+
'@eslint-react/dom-no-flush-sync': 'error',
|
|
522
|
+
|
|
523
|
+
// Disallow usage of ReactDOM.hydrate (use hydrateRoot instead)
|
|
524
|
+
// https://eslint-react.xyz/docs/rules/dom-no-hydrate
|
|
525
|
+
'@eslint-react/dom-no-hydrate': 'error',
|
|
526
|
+
|
|
527
|
+
// Enforce that buttons have an explicit type attribute
|
|
528
|
+
// https://eslint-react.xyz/docs/rules/dom-no-missing-button-type
|
|
529
|
+
'@eslint-react/dom-no-missing-button-type': 'error',
|
|
530
|
+
|
|
531
|
+
// Enforce sandbox attribute on iframe elements
|
|
532
|
+
// https://eslint-react.xyz/docs/rules/dom-no-missing-iframe-sandbox
|
|
533
|
+
'@eslint-react/dom-no-missing-iframe-sandbox': 'error',
|
|
534
|
+
|
|
535
|
+
// Disallow usage of ReactDOM.render (use createRoot instead)
|
|
536
|
+
// https://eslint-react.xyz/docs/rules/dom-no-render
|
|
537
|
+
'@eslint-react/dom-no-render': 'error',
|
|
538
|
+
|
|
539
|
+
// Disallow using ReactDOM.render return value
|
|
540
|
+
// https://eslint-react.xyz/docs/rules/dom-no-render-return-value
|
|
541
|
+
'@eslint-react/dom-no-render-return-value': 'error',
|
|
542
|
+
|
|
543
|
+
// Prevent usage of javascript: URLs
|
|
544
|
+
// https://eslint-react.xyz/docs/rules/dom-no-script-url
|
|
545
|
+
'@eslint-react/dom-no-script-url': 'error',
|
|
546
|
+
|
|
547
|
+
// Require style prop value be an object
|
|
548
|
+
// https://eslint-react.xyz/docs/rules/dom-no-string-style-prop
|
|
549
|
+
'@eslint-react/dom-no-string-style-prop': 'error',
|
|
550
|
+
|
|
551
|
+
// Prevent usage of unknown DOM property
|
|
552
|
+
// https://eslint-react.xyz/docs/rules/dom-no-unknown-property
|
|
553
|
+
'@eslint-react/dom-no-unknown-property': 'error',
|
|
554
|
+
|
|
555
|
+
// Enforce safe iframe sandbox attribute values
|
|
556
|
+
// https://eslint-react.xyz/docs/rules/dom-no-unsafe-iframe-sandbox
|
|
557
|
+
'@eslint-react/dom-no-unsafe-iframe-sandbox': 'error',
|
|
558
|
+
|
|
559
|
+
// Disallow target="_blank" without rel="noreferrer"
|
|
560
|
+
// https://eslint-react.xyz/docs/rules/dom-no-unsafe-target-blank
|
|
561
|
+
'@eslint-react/dom-no-unsafe-target-blank': 'error',
|
|
562
|
+
|
|
563
|
+
// Disallow usage of deprecated useFormState (use useActionState instead)
|
|
564
|
+
// https://eslint-react.xyz/docs/rules/dom-no-use-form-state
|
|
565
|
+
'@eslint-react/dom-no-use-form-state': 'error',
|
|
566
|
+
|
|
567
|
+
// Prevent void DOM elements from receiving children
|
|
568
|
+
// https://eslint-react.xyz/docs/rules/dom-no-void-elements-with-children
|
|
569
|
+
'@eslint-react/dom-no-void-elements-with-children': 'error',
|
|
570
|
+
|
|
571
|
+
// Enforce importing React DOM via a namespace import
|
|
572
|
+
// https://eslint-react.xyz/docs/rules/dom-prefer-namespace-import
|
|
573
|
+
'@eslint-react/dom-prefer-namespace-import': 'off',
|
|
574
|
+
|
|
575
|
+
// --- RSC rules ---
|
|
576
|
+
|
|
577
|
+
// Enforce correct function definition for React Server Components
|
|
578
|
+
// https://eslint-react.xyz/docs/rules/rsc-function-definition
|
|
579
|
+
'@eslint-react/rsc-function-definition': 'error',
|
|
580
|
+
|
|
581
|
+
// --- Naming convention rules ---
|
|
582
|
+
|
|
583
|
+
// Enforce consistent naming for React context
|
|
584
|
+
// https://eslint-react.xyz/docs/rules/naming-convention-context-name
|
|
585
|
+
'@eslint-react/naming-convention-context-name': 'error',
|
|
586
|
+
|
|
587
|
+
// Enforce consistent naming for React component identifiers
|
|
588
|
+
// https://eslint-react.xyz/docs/rules/naming-convention-id-name
|
|
589
|
+
'@eslint-react/naming-convention-id-name': 'error',
|
|
590
|
+
|
|
591
|
+
// Enforce consistent naming for refs
|
|
592
|
+
// https://eslint-react.xyz/docs/rules/naming-convention-ref-name
|
|
593
|
+
'@eslint-react/naming-convention-ref-name': 'error',
|
|
594
|
+
|
|
595
|
+
// --- Web API rules ---
|
|
596
|
+
|
|
597
|
+
// Prevent leaked event listeners
|
|
598
|
+
// https://eslint-react.xyz/docs/rules/web-api-no-leaked-event-listener
|
|
599
|
+
'@eslint-react/web-api-no-leaked-event-listener': 'error',
|
|
600
|
+
|
|
601
|
+
// Prevent leaked setInterval calls
|
|
602
|
+
// https://eslint-react.xyz/docs/rules/web-api-no-leaked-interval
|
|
603
|
+
'@eslint-react/web-api-no-leaked-interval': 'error',
|
|
604
|
+
|
|
605
|
+
// Prevent leaked ResizeObserver instances
|
|
606
|
+
// https://eslint-react.xyz/docs/rules/web-api-no-leaked-resize-observer
|
|
607
|
+
'@eslint-react/web-api-no-leaked-resize-observer': 'error',
|
|
608
|
+
|
|
609
|
+
// Prevent leaked setTimeout calls
|
|
610
|
+
// https://eslint-react.xyz/docs/rules/web-api-no-leaked-timeout
|
|
611
|
+
'@eslint-react/web-api-no-leaked-timeout': 'error',
|
|
235
612
|
},
|
|
236
613
|
};
|