@wistia/eslint-config 2.3.1 → 2.4.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 +6 -0
- package/package.json +4 -10
- package/src/configs/react.mjs +2 -13
- package/src/rules/react.mjs +197 -476
- package/test/__snapshots__/react.mjs.snap +287 -525
- package/src/rules/react-hooks.mjs +0 -72
package/src/rules/react.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
//
|
|
2
|
-
// see: https://
|
|
1
|
+
// @eslint-react rules
|
|
2
|
+
// see: https://beta.eslint-react.xyz/docs/rules
|
|
3
3
|
|
|
4
4
|
export default {
|
|
5
5
|
// Enforce that class methods utilize this
|
|
@@ -28,570 +28,291 @@ export default {
|
|
|
28
28
|
},
|
|
29
29
|
],
|
|
30
30
|
|
|
31
|
-
//
|
|
32
|
-
'react-compiler/react-compiler': 'error',
|
|
31
|
+
// --- Core React rules ---
|
|
33
32
|
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
'react/display-name': ['off', { ignoreTranspilerName: false }],
|
|
33
|
+
// Validates higher order functions defining nested components or hooks
|
|
34
|
+
'@eslint-react/component-hook-factories': 'error',
|
|
37
35
|
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
// decision: prop-types are deprecated in favor of TypeScript types
|
|
41
|
-
'react/forbid-prop-types': 'off',
|
|
36
|
+
// Validates usage of Error Boundaries instead of try/catch for child errors
|
|
37
|
+
'@eslint-react/error-boundaries': 'error',
|
|
42
38
|
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
'react/forbid-dom-props': ['off', { forbid: [] }],
|
|
39
|
+
// Verify the list of the dependencies for Hooks like useEffect and similar
|
|
40
|
+
'@eslint-react/exhaustive-deps': 'error',
|
|
46
41
|
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
'react/jsx-boolean-value': ['error', 'always'],
|
|
42
|
+
// Validates against mutating props, state, and other immutable values
|
|
43
|
+
'@eslint-react/immutability': 'error',
|
|
50
44
|
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
// decision: disabled because this is a formatter concern
|
|
54
|
-
'react/jsx-closing-bracket-location': 'off',
|
|
45
|
+
// Prevents unintentional '$' sign before expression in JSX
|
|
46
|
+
'@eslint-react/jsx-dollar': 'error',
|
|
55
47
|
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
// decision: disabled because this is a formatter concern
|
|
59
|
-
'react/jsx-closing-tag-location': 'off',
|
|
48
|
+
// Enforce key prop comes before spread to avoid overriding
|
|
49
|
+
'@eslint-react/jsx-key-before-spread': 'error',
|
|
60
50
|
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
// decision: disabled because this is a formatter concern
|
|
64
|
-
'react/jsx-curly-spacing': 'off',
|
|
51
|
+
// Prevent accidental JS comments from being injected into JSX as text
|
|
52
|
+
'@eslint-react/jsx-no-comment-textnodes': 'error',
|
|
65
53
|
|
|
66
|
-
// Enforce
|
|
67
|
-
//
|
|
68
|
-
'react/jsx-
|
|
69
|
-
'error',
|
|
70
|
-
{
|
|
71
|
-
eventHandlerPrefix: 'handle',
|
|
72
|
-
eventHandlerPropPrefix: 'on',
|
|
73
|
-
checkLocalVariables: true,
|
|
74
|
-
checkInlineFunction: false,
|
|
75
|
-
},
|
|
76
|
-
],
|
|
54
|
+
// Enforce explicit boolean prop syntax (e.g. disabled={true} instead of disabled)
|
|
55
|
+
// note: -1 means "never use shorthand" (equivalent to react/jsx-boolean-value: ['error', 'always'])
|
|
56
|
+
'@eslint-react/jsx-shorthand-boolean': ['error', -1],
|
|
77
57
|
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
'react/jsx-indent-props': 'off',
|
|
58
|
+
// Enforce shorthand fragment syntax (<> instead of <React.Fragment>)
|
|
59
|
+
// note: 1 means "always use shorthand" (equivalent to react/jsx-fragments: ['error', 'syntax'])
|
|
60
|
+
'@eslint-react/jsx-shorthand-fragment': ['error', 1],
|
|
82
61
|
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
'react/jsx-key': [
|
|
86
|
-
'error',
|
|
87
|
-
{ checkFragmentShorthand: true, checkKeyMustBeforeSpread: true, warnOnDuplicates: true },
|
|
88
|
-
],
|
|
62
|
+
// Prevent using this.state within a this.setState
|
|
63
|
+
'@eslint-react/no-access-state-in-setstate': 'error',
|
|
89
64
|
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
// decision: disabled because this is a formatter concern
|
|
93
|
-
'react/jsx-max-props-per-line': 'off',
|
|
65
|
+
// Prevent usage of Array index in keys
|
|
66
|
+
'@eslint-react/no-array-index-key': 'error',
|
|
94
67
|
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
'react/jsx-no-bind': [
|
|
98
|
-
'error',
|
|
99
|
-
{
|
|
100
|
-
ignoreRefs: true,
|
|
101
|
-
allowArrowFunctions: true,
|
|
102
|
-
allowFunctions: false,
|
|
103
|
-
allowBind: false,
|
|
104
|
-
ignoreDOMComponents: true,
|
|
105
|
-
},
|
|
106
|
-
],
|
|
68
|
+
// Disallow usage of Children.count
|
|
69
|
+
'@eslint-react/no-children-count': 'error',
|
|
107
70
|
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
'react/jsx-no-duplicate-props': ['error', { ignoreCase: true }],
|
|
71
|
+
// Disallow usage of Children.forEach
|
|
72
|
+
'@eslint-react/no-children-for-each': 'error',
|
|
111
73
|
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
'react/jsx-no-literals': ['off', { noStrings: true }],
|
|
74
|
+
// Disallow usage of Children.map
|
|
75
|
+
'@eslint-react/no-children-map': 'error',
|
|
115
76
|
|
|
116
|
-
// Disallow
|
|
117
|
-
|
|
118
|
-
'react/jsx-no-undef': 'error',
|
|
77
|
+
// Disallow usage of Children.only
|
|
78
|
+
'@eslint-react/no-children-only': 'error',
|
|
119
79
|
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
'react/jsx-pascal-case': [
|
|
123
|
-
'error',
|
|
124
|
-
{
|
|
125
|
-
allowAllCaps: true,
|
|
126
|
-
ignore: [],
|
|
127
|
-
},
|
|
128
|
-
],
|
|
80
|
+
// Prevent passing of children as props
|
|
81
|
+
'@eslint-react/no-children-prop': 'error',
|
|
129
82
|
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
// decision: prop-types are deprecated in favor of TypeScript types
|
|
133
|
-
'react/sort-prop-types': 'off',
|
|
83
|
+
// Disallow usage of Children.toArray
|
|
84
|
+
'@eslint-react/no-children-to-array': 'error',
|
|
134
85
|
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
'react/jsx-sort-prop-types': 'off',
|
|
86
|
+
// Disallow class components (except for error boundaries)
|
|
87
|
+
'@eslint-react/no-class-component': 'error',
|
|
138
88
|
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
'react/jsx-sort-props': [
|
|
142
|
-
'error',
|
|
143
|
-
{
|
|
144
|
-
ignoreCase: true,
|
|
145
|
-
callbacksLast: false,
|
|
146
|
-
shorthandFirst: false,
|
|
147
|
-
shorthandLast: false,
|
|
148
|
-
noSortAlphabetically: false,
|
|
149
|
-
reservedFirst: true,
|
|
150
|
-
},
|
|
151
|
-
],
|
|
89
|
+
// Disallow usage of cloneElement
|
|
90
|
+
'@eslint-react/no-clone-element': 'error',
|
|
152
91
|
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md
|
|
156
|
-
'react/jsx-uses-react': 'off',
|
|
92
|
+
// Disallow usage of componentWillMount
|
|
93
|
+
'@eslint-react/no-component-will-mount': 'error',
|
|
157
94
|
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
'react/jsx-uses-vars': 'error',
|
|
95
|
+
// Disallow usage of componentWillReceiveProps
|
|
96
|
+
'@eslint-react/no-component-will-receive-props': 'error',
|
|
161
97
|
|
|
162
|
-
//
|
|
163
|
-
|
|
164
|
-
'react/no-danger': 'error',
|
|
98
|
+
// Disallow usage of componentWillUpdate
|
|
99
|
+
'@eslint-react/no-component-will-update': 'error',
|
|
165
100
|
|
|
166
|
-
//
|
|
167
|
-
|
|
168
|
-
'react/no-deprecated': 'error',
|
|
101
|
+
// Disallow usage of legacy Context.Provider (React 19+)
|
|
102
|
+
'@eslint-react/no-context-provider': 'error',
|
|
169
103
|
|
|
170
|
-
//
|
|
171
|
-
|
|
172
|
-
// this is necessary for server-rendering
|
|
173
|
-
'react/no-did-mount-set-state': 'error',
|
|
104
|
+
// Disallow usage of createRef (prefer useRef)
|
|
105
|
+
'@eslint-react/no-create-ref': 'error',
|
|
174
106
|
|
|
175
|
-
// Prevent
|
|
176
|
-
|
|
177
|
-
'react/no-did-update-set-state': 'error',
|
|
107
|
+
// Prevent direct mutation of this.state
|
|
108
|
+
'@eslint-react/no-direct-mutation-state': 'error',
|
|
178
109
|
|
|
179
|
-
//
|
|
180
|
-
|
|
181
|
-
'react/no-will-update-set-state': 'error',
|
|
110
|
+
// Disallow duplicate keys in JSX arrays
|
|
111
|
+
'@eslint-react/no-duplicate-key': 'error',
|
|
182
112
|
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
'react/no-direct-mutation-state': 'off',
|
|
113
|
+
// Disallow usage of forwardRef (React 19+ passes ref as prop)
|
|
114
|
+
'@eslint-react/no-forward-ref': 'error',
|
|
186
115
|
|
|
187
|
-
// Prevent
|
|
188
|
-
|
|
189
|
-
'react/no-is-mounted': 'error',
|
|
116
|
+
// Prevent implicitly passing the children prop
|
|
117
|
+
'@eslint-react/no-implicit-children': 'error',
|
|
190
118
|
|
|
191
|
-
// Prevent
|
|
192
|
-
|
|
193
|
-
'react/no-multi-comp': 'off',
|
|
119
|
+
// Prevent implicitly passing the key prop
|
|
120
|
+
'@eslint-react/no-implicit-key': 'error',
|
|
194
121
|
|
|
195
|
-
// Prevent
|
|
196
|
-
|
|
197
|
-
'react/no-set-state': 'off',
|
|
122
|
+
// Prevent implicitly passing the ref prop
|
|
123
|
+
'@eslint-react/no-implicit-ref': 'error',
|
|
198
124
|
|
|
199
|
-
// Prevent
|
|
200
|
-
|
|
201
|
-
'react/no-string-refs': 'error',
|
|
125
|
+
// Prevent problematic leaked values from being rendered
|
|
126
|
+
'@eslint-react/no-leaked-conditional-rendering': 'error',
|
|
202
127
|
|
|
203
|
-
//
|
|
204
|
-
|
|
205
|
-
'react/no-unknown-property': 'error',
|
|
206
|
-
|
|
207
|
-
// Require ES6 class declarations over React.createClass
|
|
208
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md
|
|
209
|
-
'react/prefer-es6-class': ['error', 'always'],
|
|
210
|
-
|
|
211
|
-
// Require stateless functions when not using lifecycle methods, setState or ref
|
|
212
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md
|
|
213
|
-
'react/prefer-stateless-function': ['error', { ignorePureComponents: true }],
|
|
214
|
-
|
|
215
|
-
// Prevent missing props validation in a React component definition
|
|
216
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/prop-types.md
|
|
217
|
-
// decision: prop-types are deprecated in favor of TypeScript types
|
|
218
|
-
'react/prop-types': 'off',
|
|
219
|
-
|
|
220
|
-
// Prevent missing React when using JSX
|
|
221
|
-
// decision: no longer required with React 17 & babel `automatic` runtime
|
|
222
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md
|
|
223
|
-
'react/react-in-jsx-scope': 'off',
|
|
224
|
-
|
|
225
|
-
// Require render() methods to return something
|
|
226
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/require-render-return.md
|
|
227
|
-
'react/require-render-return': 'error',
|
|
228
|
-
|
|
229
|
-
// Prevent extra closing tags for components without children
|
|
230
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md
|
|
231
|
-
'react/self-closing-comp': 'error',
|
|
232
|
-
|
|
233
|
-
// Enforce component methods order
|
|
234
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/sort-comp.md
|
|
235
|
-
'react/sort-comp': [
|
|
236
|
-
'error',
|
|
237
|
-
{
|
|
238
|
-
order: [
|
|
239
|
-
'static-variables',
|
|
240
|
-
'static-methods',
|
|
241
|
-
'instance-variables',
|
|
242
|
-
'lifecycle',
|
|
243
|
-
'/^handle.+$/',
|
|
244
|
-
'/^on.+$/',
|
|
245
|
-
'getters',
|
|
246
|
-
'setters',
|
|
247
|
-
'/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/',
|
|
248
|
-
'instance-methods',
|
|
249
|
-
'everything-else',
|
|
250
|
-
'rendering',
|
|
251
|
-
],
|
|
252
|
-
groups: {
|
|
253
|
-
lifecycle: [
|
|
254
|
-
'displayName',
|
|
255
|
-
'propTypes',
|
|
256
|
-
'contextTypes',
|
|
257
|
-
'childContextTypes',
|
|
258
|
-
'mixins',
|
|
259
|
-
'statics',
|
|
260
|
-
'defaultProps',
|
|
261
|
-
'constructor',
|
|
262
|
-
'getDefaultProps',
|
|
263
|
-
'getInitialState',
|
|
264
|
-
'state',
|
|
265
|
-
'getChildContext',
|
|
266
|
-
'getDerivedStateFromProps',
|
|
267
|
-
'componentWillMount',
|
|
268
|
-
'UNSAFE_componentWillMount',
|
|
269
|
-
'componentDidMount',
|
|
270
|
-
'componentWillReceiveProps',
|
|
271
|
-
'UNSAFE_componentWillReceiveProps',
|
|
272
|
-
'shouldComponentUpdate',
|
|
273
|
-
'componentWillUpdate',
|
|
274
|
-
'UNSAFE_componentWillUpdate',
|
|
275
|
-
'getSnapshotBeforeUpdate',
|
|
276
|
-
'componentDidUpdate',
|
|
277
|
-
'componentDidCatch',
|
|
278
|
-
'componentWillUnmount',
|
|
279
|
-
],
|
|
280
|
-
rendering: ['/^render.+$/', 'render'],
|
|
281
|
-
},
|
|
282
|
-
},
|
|
283
|
-
],
|
|
128
|
+
// Enforce that components have a displayName for DevTools
|
|
129
|
+
'@eslint-react/no-missing-component-display-name': 'off',
|
|
284
130
|
|
|
285
|
-
// Enforce
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
131
|
+
// Enforce that contexts have a displayName for DevTools
|
|
132
|
+
'@eslint-react/no-missing-context-display-name': 'off',
|
|
133
|
+
|
|
134
|
+
// Enforce that every JSX element in a list has a key prop
|
|
135
|
+
'@eslint-react/no-missing-key': 'error',
|
|
136
|
+
|
|
137
|
+
// Disallow misusing captureOwnerStack
|
|
138
|
+
'@eslint-react/no-misused-capture-owner-stack': 'error',
|
|
139
|
+
|
|
140
|
+
// Prevent creating unstable components inside components
|
|
141
|
+
'@eslint-react/no-nested-component-definitions': 'error',
|
|
293
142
|
|
|
294
|
-
// Prevent
|
|
295
|
-
|
|
296
|
-
// decision: disabled because this is a formatter concern
|
|
297
|
-
'react/jsx-wrap-multilines': 'off',
|
|
143
|
+
// Prevent creating lazy components inside components
|
|
144
|
+
'@eslint-react/no-nested-lazy-component-declarations': 'error',
|
|
298
145
|
|
|
299
|
-
//
|
|
300
|
-
|
|
301
|
-
// decision: disabled because this is a formatter concern
|
|
302
|
-
'react/jsx-first-prop-new-line': 'off',
|
|
146
|
+
// Prevent usage of shouldComponentUpdate when extending React.PureComponent
|
|
147
|
+
'@eslint-react/no-redundant-should-component-update': 'error',
|
|
303
148
|
|
|
304
|
-
//
|
|
305
|
-
|
|
306
|
-
// decision: disabled because this is a formatter concern
|
|
307
|
-
'react/jsx-equals-spacing': 'off',
|
|
149
|
+
// Prevent usage of setState in componentDidMount
|
|
150
|
+
'@eslint-react/no-set-state-in-component-did-mount': 'error',
|
|
308
151
|
|
|
309
|
-
//
|
|
310
|
-
|
|
311
|
-
// decision: disabled because this is a formatter concern
|
|
312
|
-
'react/jsx-indent': 'off',
|
|
152
|
+
// Prevent usage of setState in componentDidUpdate
|
|
153
|
+
'@eslint-react/no-set-state-in-component-did-update': 'error',
|
|
313
154
|
|
|
314
|
-
//
|
|
315
|
-
|
|
316
|
-
'react/jsx-no-target-blank': ['error', { enforceDynamicLinks: 'always' }],
|
|
155
|
+
// Prevent usage of setState in componentWillUpdate
|
|
156
|
+
'@eslint-react/no-set-state-in-component-will-update': 'error',
|
|
317
157
|
|
|
318
|
-
//
|
|
319
|
-
|
|
320
|
-
// decision: include typescript extensions to allow interop
|
|
321
|
-
'react/jsx-filename-extension': ['error', { extensions: ['.jsx', '.tsx'] }],
|
|
158
|
+
// Disallow unnecessary useCallback hooks
|
|
159
|
+
'@eslint-react/no-unnecessary-use-callback': 'error',
|
|
322
160
|
|
|
323
|
-
//
|
|
324
|
-
|
|
325
|
-
'react/jsx-no-comment-textnodes': 'error',
|
|
161
|
+
// Disallow unnecessary useMemo hooks
|
|
162
|
+
'@eslint-react/no-unnecessary-use-memo': 'error',
|
|
326
163
|
|
|
327
|
-
//
|
|
328
|
-
|
|
329
|
-
'react/no-render-return-value': 'error',
|
|
164
|
+
// Disallow unnecessary "use" prefix on custom hooks
|
|
165
|
+
'@eslint-react/no-unnecessary-use-prefix': 'error',
|
|
330
166
|
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
'react/require-optimization': ['off', { allowDecorators: [] }],
|
|
167
|
+
// Disallow usage of UNSAFE_componentWillMount
|
|
168
|
+
'@eslint-react/no-unsafe-component-will-mount': 'error',
|
|
334
169
|
|
|
335
|
-
//
|
|
336
|
-
|
|
337
|
-
'react/no-find-dom-node': 'error',
|
|
170
|
+
// Disallow usage of UNSAFE_componentWillReceiveProps
|
|
171
|
+
'@eslint-react/no-unsafe-component-will-receive-props': 'error',
|
|
338
172
|
|
|
339
|
-
//
|
|
340
|
-
|
|
341
|
-
'react/forbid-component-props': ['off', { forbid: [] }],
|
|
173
|
+
// Disallow usage of UNSAFE_componentWillUpdate
|
|
174
|
+
'@eslint-react/no-unsafe-component-will-update': 'error',
|
|
342
175
|
|
|
343
|
-
//
|
|
344
|
-
|
|
345
|
-
'react/forbid-elements': ['off', { forbid: [] }],
|
|
176
|
+
// Prevent non-stable values used as context values
|
|
177
|
+
'@eslint-react/no-unstable-context-value': 'error',
|
|
346
178
|
|
|
347
|
-
//
|
|
348
|
-
|
|
349
|
-
'react/no-danger-with-children': 'error',
|
|
179
|
+
// Disallow referential-type variables as default props
|
|
180
|
+
'@eslint-react/no-unstable-default-props': 'error',
|
|
350
181
|
|
|
351
|
-
// Prevent unused
|
|
352
|
-
|
|
353
|
-
// decision: prop-types are deprecated in favor of TypeScript types
|
|
354
|
-
'react/no-unused-prop-types': 'off',
|
|
182
|
+
// Prevent declaring unused methods of component class
|
|
183
|
+
'@eslint-react/no-unused-class-component-members': 'error',
|
|
355
184
|
|
|
356
|
-
//
|
|
357
|
-
|
|
358
|
-
'react/style-prop-object': 'error',
|
|
185
|
+
// Warn about component props that are defined but never used
|
|
186
|
+
'@eslint-react/no-unused-props': 'error',
|
|
359
187
|
|
|
360
|
-
// Prevent
|
|
361
|
-
|
|
362
|
-
'react/no-unescaped-entities': 'error',
|
|
188
|
+
// Prevent unused state values
|
|
189
|
+
'@eslint-react/no-unused-state': 'error',
|
|
363
190
|
|
|
364
|
-
//
|
|
365
|
-
|
|
366
|
-
'react/no-children-prop': 'error',
|
|
191
|
+
// Prefer using use() over useContext() (React 19+)
|
|
192
|
+
'@eslint-react/no-use-context': 'error',
|
|
367
193
|
|
|
368
|
-
//
|
|
369
|
-
|
|
370
|
-
// decision: disabled because this is a formatter concern
|
|
371
|
-
'react/jsx-tag-spacing': 'off',
|
|
194
|
+
// Disallow unnecessary fragments
|
|
195
|
+
'@eslint-react/no-useless-fragment': 'error',
|
|
372
196
|
|
|
373
|
-
// Enforce
|
|
374
|
-
|
|
375
|
-
// decision: this rule is deprecated. It was replaced by react/jsx-tag-spacing.
|
|
376
|
-
// 'react/jsx-space-before-closing': 'off',
|
|
197
|
+
// Enforce consistent usage of destructuring assignment of props, state, and context
|
|
198
|
+
'@eslint-react/prefer-destructuring-assignment': 'off',
|
|
377
199
|
|
|
378
|
-
//
|
|
379
|
-
|
|
380
|
-
'react/no-array-index-key': 'error',
|
|
200
|
+
// Enforce importing React via a namespace import
|
|
201
|
+
'@eslint-react/prefer-namespace-import': 'off',
|
|
381
202
|
|
|
382
|
-
//
|
|
383
|
-
|
|
384
|
-
// decision: default prop types shouldn't be necessary for optional parameters as they can just default to undefined
|
|
385
|
-
'react/require-default-props': 'off',
|
|
203
|
+
// Validates that components/hooks are pure
|
|
204
|
+
'@eslint-react/purity': 'error',
|
|
386
205
|
|
|
387
|
-
//
|
|
388
|
-
|
|
389
|
-
// decision: prop-types are deprecated in favor of TypeScript types
|
|
390
|
-
'react/forbid-foreign-prop-types': 'off',
|
|
206
|
+
// Validates correct usage of refs, not reading/writing during render
|
|
207
|
+
'@eslint-react/refs': 'error',
|
|
391
208
|
|
|
392
|
-
//
|
|
393
|
-
|
|
394
|
-
'react/void-dom-elements-no-children': 'error',
|
|
209
|
+
// Enforce Rules of Hooks
|
|
210
|
+
'@eslint-react/rules-of-hooks': 'error',
|
|
395
211
|
|
|
396
|
-
//
|
|
397
|
-
|
|
398
|
-
// decision: prop-types are deprecated in favor of TypeScript types
|
|
399
|
-
'react/default-props-match-prop-types': 'off',
|
|
212
|
+
// Validates against calling setState synchronously in an effect
|
|
213
|
+
'@eslint-react/set-state-in-effect': 'error',
|
|
400
214
|
|
|
401
|
-
//
|
|
402
|
-
|
|
403
|
-
'react/no-redundant-should-component-update': 'error',
|
|
215
|
+
// Validates against setting state during render
|
|
216
|
+
'@eslint-react/set-state-in-render': 'error',
|
|
404
217
|
|
|
405
|
-
//
|
|
406
|
-
|
|
407
|
-
'react/no-unused-state': 'error',
|
|
218
|
+
// Enforces the Rules of Props (unstable)
|
|
219
|
+
'@eslint-react/unstable-rules-of-props': 'error',
|
|
408
220
|
|
|
409
|
-
// Enforces
|
|
410
|
-
|
|
411
|
-
'react/boolean-prop-naming': [
|
|
412
|
-
'off',
|
|
413
|
-
{
|
|
414
|
-
propTypeNames: ['bool', 'mutuallyExclusiveTrueProps'],
|
|
415
|
-
rule: '^(is|has)[A-Z]([A-Za-z0-9]?)+',
|
|
416
|
-
message: '',
|
|
417
|
-
},
|
|
418
|
-
],
|
|
221
|
+
// Enforces the Rules of State (unstable)
|
|
222
|
+
'@eslint-react/unstable-rules-of-state': 'error',
|
|
419
223
|
|
|
420
|
-
//
|
|
421
|
-
|
|
422
|
-
'react/no-typos': 'error',
|
|
224
|
+
// Validates against syntax that React does not support
|
|
225
|
+
'@eslint-react/unsupported-syntax': 'error',
|
|
423
226
|
|
|
424
|
-
//
|
|
425
|
-
|
|
426
|
-
'react/jsx-curly-brace-presence': ['error', { props: 'never', children: 'never' }],
|
|
227
|
+
// Validates usage of useMemo with a return value
|
|
228
|
+
'@eslint-react/use-memo': 'error',
|
|
427
229
|
|
|
428
|
-
//
|
|
429
|
-
|
|
430
|
-
// decision: disabled because this is a formatter concern
|
|
431
|
-
'react/jsx-one-expression-per-line': 'off',
|
|
230
|
+
// Ensure destructuring and symmetric naming of useState hook value and setter
|
|
231
|
+
'@eslint-react/use-state': 'error',
|
|
432
232
|
|
|
433
|
-
//
|
|
434
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/destructuring-assignment.md
|
|
435
|
-
// decision: it's acceptable to mix these even at the expense of consistency
|
|
436
|
-
'react/destructuring-assignment': ['off', 'always'],
|
|
233
|
+
// --- React DOM rules ---
|
|
437
234
|
|
|
438
|
-
//
|
|
439
|
-
|
|
440
|
-
'react/no-access-state-in-setstate': 'error',
|
|
235
|
+
// Warn on usage of dangerouslySetInnerHTML
|
|
236
|
+
'@eslint-react/dom/no-dangerously-set-innerhtml': 'error',
|
|
441
237
|
|
|
442
|
-
// Prevent
|
|
443
|
-
|
|
444
|
-
'react/button-has-type': [
|
|
445
|
-
'error',
|
|
446
|
-
{
|
|
447
|
-
button: true,
|
|
448
|
-
submit: true,
|
|
449
|
-
reset: false,
|
|
450
|
-
},
|
|
451
|
-
],
|
|
238
|
+
// Prevent problem with children and dangerouslySetInnerHTML
|
|
239
|
+
'@eslint-react/dom/no-dangerously-set-innerhtml-with-children': 'error',
|
|
452
240
|
|
|
453
|
-
//
|
|
454
|
-
'react/
|
|
241
|
+
// Warn against using findDOMNode()
|
|
242
|
+
'@eslint-react/dom/no-find-dom-node': 'error',
|
|
455
243
|
|
|
456
|
-
//
|
|
457
|
-
|
|
458
|
-
'react/no-this-in-sfc': 'error',
|
|
244
|
+
// Disallow usage of flushSync
|
|
245
|
+
'@eslint-react/dom/no-flush-sync': 'error',
|
|
459
246
|
|
|
460
|
-
//
|
|
461
|
-
|
|
462
|
-
'react/jsx-max-depth': 'off',
|
|
247
|
+
// Disallow usage of ReactDOM.hydrate (use hydrateRoot instead)
|
|
248
|
+
'@eslint-react/dom/no-hydrate': 'error',
|
|
463
249
|
|
|
464
|
-
//
|
|
465
|
-
|
|
466
|
-
'react/jsx-props-no-multi-spaces': 'off',
|
|
250
|
+
// Enforce that buttons have an explicit type attribute
|
|
251
|
+
'@eslint-react/dom/no-missing-button-type': 'error',
|
|
467
252
|
|
|
468
|
-
//
|
|
469
|
-
|
|
470
|
-
'react/no-unsafe': 'off',
|
|
253
|
+
// Enforce sandbox attribute on iframe elements
|
|
254
|
+
'@eslint-react/dom/no-missing-iframe-sandbox': 'error',
|
|
471
255
|
|
|
472
|
-
// Enforce
|
|
473
|
-
|
|
474
|
-
'react/jsx-fragments': ['error', 'syntax'],
|
|
256
|
+
// Enforce that namespaces are not used in React elements
|
|
257
|
+
'@eslint-react/dom/no-namespace': 'error',
|
|
475
258
|
|
|
476
|
-
//
|
|
477
|
-
|
|
478
|
-
// decision: disabled because this is a formatter concern
|
|
479
|
-
'react/jsx-curly-newline': 'off',
|
|
259
|
+
// Disallow usage of ReactDOM.render (use createRoot instead)
|
|
260
|
+
'@eslint-react/dom/no-render': 'error',
|
|
480
261
|
|
|
481
|
-
//
|
|
482
|
-
|
|
483
|
-
'react/state-in-constructor': ['error', 'never'],
|
|
262
|
+
// Disallow using ReactDOM.render return value
|
|
263
|
+
'@eslint-react/dom/no-render-return-value': 'error',
|
|
484
264
|
|
|
485
|
-
//
|
|
486
|
-
|
|
487
|
-
'react/static-property-placement': ['error', 'static public field'],
|
|
265
|
+
// Prevent usage of javascript: URLs
|
|
266
|
+
'@eslint-react/dom/no-script-url': 'error',
|
|
488
267
|
|
|
489
|
-
//
|
|
490
|
-
|
|
491
|
-
// decision: because we have type safety in TypeScript, this rule isn't necessary as we will see
|
|
492
|
-
// TS errors for prop spreading against mismatched (prop)type declarations
|
|
493
|
-
'react/jsx-props-no-spreading': 'off',
|
|
268
|
+
// Require style prop value be an object
|
|
269
|
+
'@eslint-react/dom/no-string-style-prop': 'error',
|
|
494
270
|
|
|
495
|
-
//
|
|
496
|
-
|
|
497
|
-
'react/prefer-read-only-props': 'off',
|
|
271
|
+
// Prevent usage of unknown DOM property
|
|
272
|
+
'@eslint-react/dom/no-unknown-property': 'error',
|
|
498
273
|
|
|
499
|
-
//
|
|
500
|
-
|
|
501
|
-
'react/jsx-no-script-url': [
|
|
502
|
-
'error',
|
|
503
|
-
[
|
|
504
|
-
{
|
|
505
|
-
name: 'Link',
|
|
506
|
-
props: ['to'],
|
|
507
|
-
},
|
|
508
|
-
],
|
|
509
|
-
],
|
|
274
|
+
// Enforce safe iframe sandbox attribute values
|
|
275
|
+
'@eslint-react/dom/no-unsafe-iframe-sandbox': 'error',
|
|
510
276
|
|
|
511
|
-
// Disallow
|
|
512
|
-
|
|
513
|
-
'react/jsx-no-useless-fragment': 'error',
|
|
277
|
+
// Disallow target="_blank" without rel="noreferrer"
|
|
278
|
+
'@eslint-react/dom/no-unsafe-target-blank': 'error',
|
|
514
279
|
|
|
515
|
-
//
|
|
516
|
-
|
|
517
|
-
'react/no-adjacent-inline-elements': 'error',
|
|
280
|
+
// Disallow usage of deprecated useFormState (use useActionState instead)
|
|
281
|
+
'@eslint-react/dom/no-use-form-state': 'error',
|
|
518
282
|
|
|
519
|
-
//
|
|
520
|
-
|
|
521
|
-
'react/function-component-definition': [
|
|
522
|
-
'error',
|
|
523
|
-
{
|
|
524
|
-
namedComponents: 'arrow-function',
|
|
525
|
-
unnamedComponents: 'arrow-function',
|
|
526
|
-
},
|
|
527
|
-
],
|
|
283
|
+
// Prevent void DOM elements from receiving children
|
|
284
|
+
'@eslint-react/dom/no-void-elements-with-children': 'error',
|
|
528
285
|
|
|
529
|
-
// Enforce
|
|
530
|
-
|
|
531
|
-
// decision: disabled because this is a formatter concern
|
|
532
|
-
'react/jsx-newline': 'off',
|
|
286
|
+
// Enforce importing React DOM via a namespace import
|
|
287
|
+
'@eslint-react/dom/prefer-namespace-import': 'off',
|
|
533
288
|
|
|
534
|
-
//
|
|
535
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-constructed-context-values.md
|
|
536
|
-
'react/jsx-no-constructed-context-values': 'error',
|
|
289
|
+
// --- RSC rules ---
|
|
537
290
|
|
|
538
|
-
//
|
|
539
|
-
|
|
540
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unstable-nested-components.md
|
|
541
|
-
'react/no-unstable-nested-components': ['error', { allowAsProps: true }],
|
|
291
|
+
// Enforce correct function definition for React Server Components
|
|
292
|
+
'@eslint-react/rsc/function-definition': 'error',
|
|
542
293
|
|
|
543
|
-
//
|
|
544
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-namespace.md
|
|
545
|
-
'react/no-namespace': 'error',
|
|
294
|
+
// --- Naming convention rules ---
|
|
546
295
|
|
|
547
|
-
//
|
|
548
|
-
|
|
549
|
-
'react/prefer-exact-props': 'error',
|
|
296
|
+
// Enforce consistent naming for React context
|
|
297
|
+
'@eslint-react/naming-convention/context-name': 'error',
|
|
550
298
|
|
|
551
|
-
//
|
|
552
|
-
|
|
553
|
-
'react/no-arrow-function-lifecycle': 'error',
|
|
299
|
+
// Enforce consistent naming for React component identifiers
|
|
300
|
+
'@eslint-react/naming-convention/id-name': 'error',
|
|
554
301
|
|
|
555
|
-
//
|
|
556
|
-
|
|
557
|
-
'react/no-invalid-html-attribute': 'error',
|
|
302
|
+
// Enforce consistent naming for refs
|
|
303
|
+
'@eslint-react/naming-convention/ref-name': 'error',
|
|
558
304
|
|
|
559
|
-
//
|
|
560
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unused-class-component-methods.md
|
|
561
|
-
'react/no-unused-class-component-methods': 'error',
|
|
305
|
+
// --- Web API rules ---
|
|
562
306
|
|
|
563
|
-
//
|
|
564
|
-
|
|
565
|
-
'react/hook-use-state': 'error',
|
|
307
|
+
// Prevent leaked event listeners
|
|
308
|
+
'@eslint-react/web-api/no-leaked-event-listener': 'error',
|
|
566
309
|
|
|
567
|
-
//
|
|
568
|
-
|
|
569
|
-
'react/iframe-missing-sandbox': 'error',
|
|
310
|
+
// Prevent leaked setInterval calls
|
|
311
|
+
'@eslint-react/web-api/no-leaked-interval': 'error',
|
|
570
312
|
|
|
571
|
-
// Prevent
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/checked-requires-onchange-or-readonly.md
|
|
577
|
-
'react/checked-requires-onchange-or-readonly': 'error',
|
|
578
|
-
|
|
579
|
-
// Disallow usage of referential-type variables as default param in functional component
|
|
580
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-object-type-as-default-prop.md
|
|
581
|
-
// decision: there's an edge case issue this could prevent but it's not common enough to warrant the rule
|
|
582
|
-
'react/no-object-type-as-default-prop': 'off',
|
|
583
|
-
|
|
584
|
-
// Some developers prefer to sort defaultProps declarations alphabetically to be able to find necessary declarations easier at a later time.
|
|
585
|
-
// Others feel that it adds complexity and becomes a burden to maintain.
|
|
586
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-sort-default-props.md
|
|
587
|
-
// decision: this rule is deprecated. It was replaced by `react/sort-default-props`
|
|
588
|
-
// 'react/jsx-sort-default-props': 'off',
|
|
589
|
-
|
|
590
|
-
// Require all forwardRef components include a ref parameter
|
|
591
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/forward-ref-uses-ref.md
|
|
592
|
-
'react/forward-ref-uses-ref': 'error',
|
|
593
|
-
|
|
594
|
-
// Disallow JSX prop spreading the same identifier multiple times
|
|
595
|
-
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-props-no-spread-multi.md
|
|
596
|
-
'react/jsx-props-no-spread-multi': 'error',
|
|
313
|
+
// Prevent leaked ResizeObserver instances
|
|
314
|
+
'@eslint-react/web-api/no-leaked-resize-observer': 'error',
|
|
315
|
+
|
|
316
|
+
// Prevent leaked setTimeout calls
|
|
317
|
+
'@eslint-react/web-api/no-leaked-timeout': 'error',
|
|
597
318
|
};
|