1
- import { isPackageExists } from 'local-pkg'
2
- import { GLOB_SRC } from '../constants/glob'
3
- import { isUsingNext , isUsingRemix } from '../env'
4
- import { ensurePackages , interopDefault , toArray } from '../shared'
1
+ import {
2
+ GLOB_ASTRO_TS ,
3
+ GLOB_MARKDOWN ,
4
+ GLOB_SRC ,
5
+ GLOB_TS ,
6
+ GLOB_TSX ,
7
+ } from '../constants/glob'
8
+ import { isAllowConstantExport , isUsingNext , isUsingRemix } from '../env'
9
+
10
+ import { ensurePackages , interopDefault } from '../shared'
5
11
import type {
6
12
OptionsFiles ,
7
13
OptionsOverrides ,
14
+ OptionsTypeScriptParserOptions ,
8
15
OptionsTypeScriptWithTypes ,
9
16
TypedFlatConfigItem ,
10
17
} from '../types'
11
18
12
- // react refresh
13
- const ReactRefreshAllowConstantExportPackages = [ 'vite' ]
14
-
15
19
export async function react (
16
- options : OptionsTypeScriptWithTypes & OptionsOverrides & OptionsFiles = { } ,
20
+ options : OptionsTypeScriptParserOptions &
21
+ OptionsTypeScriptWithTypes &
22
+ OptionsOverrides &
23
+ OptionsFiles = { } ,
17
24
) : Promise < TypedFlatConfigItem [ ] > {
18
- const { files = [ GLOB_SRC ] , overrides = { } } = options
25
+ const {
26
+ files = [ GLOB_SRC ] ,
27
+ filesTypeAware = [ GLOB_TS , GLOB_TSX ] ,
28
+ ignoresTypeAware = [ `${ GLOB_MARKDOWN } /**` , GLOB_ASTRO_TS ] ,
29
+ overrides = { } ,
30
+ tsconfigPath,
31
+ } = options
19
32
20
33
await ensurePackages ( [
21
34
'@eslint-react/eslint-plugin' ,
22
35
'eslint-plugin-react-hooks' ,
23
36
'eslint-plugin-react-refresh' ,
24
37
] )
25
38
26
- const tsconfigPath = options ?. tsconfigPath
27
- ? toArray ( options . tsconfigPath )
28
- : undefined
29
39
const isTypeAware = ! ! tsconfigPath
30
40
31
- const [ pluginReact , pluginReactHooks , pluginReactRefresh , parserTs ] =
32
- await Promise . all ( [
41
+ const typeAwareRules : TypedFlatConfigItem [ 'rules' ] = {
42
+ 'react/no-leaked-conditional-rendering' : 'warn' ,
43
+ }
44
+
45
+ const [ pluginReact , pluginReactHooks , pluginReactRefresh ] = await Promise . all (
46
+ [
33
47
interopDefault ( import ( '@eslint-react/eslint-plugin' ) ) ,
34
48
interopDefault ( import ( 'eslint-plugin-react-hooks' ) ) ,
35
49
interopDefault ( import ( 'eslint-plugin-react-refresh' ) ) ,
36
- interopDefault ( import ( '@typescript-eslint/parser' ) ) ,
37
- ] as const )
38
-
39
- const isAllowConstantExport = ReactRefreshAllowConstantExportPackages . some (
40
- ( i ) => isPackageExists ( i ) ,
50
+ ] as const ,
41
51
)
42
52
43
53
const plugins = pluginReact . configs . all . plugins
@@ -57,12 +67,10 @@ export async function react(
57
67
{
58
68
files,
59
69
languageOptions : {
60
- parser : parserTs ,
61
70
parserOptions : {
62
71
ecmaFeatures : {
63
72
jsx : true ,
64
73
} ,
65
- ...( isTypeAware ? { project : tsconfigPath } : { } ) ,
66
74
} ,
67
75
sourceType : 'module' ,
68
76
} ,
@@ -117,25 +125,30 @@ export async function react(
117
125
118
126
// recommended rules from @eslint -react
119
127
'react/ensure-forward-ref-using-ref' : 'warn' ,
128
+ 'react/jsx-no-duplicate-props' : 'warn' ,
129
+ 'react/jsx-uses-vars' : 'warn' ,
120
130
'react/no-access-state-in-setstate' : 'error' ,
121
131
'react/no-array-index-key' : 'warn' ,
122
132
'react/no-children-count' : 'warn' ,
123
133
'react/no-children-for-each' : 'warn' ,
124
134
'react/no-children-map' : 'warn' ,
125
135
'react/no-children-only' : 'warn' ,
126
- 'react/no-children-prop' : 'warn' ,
127
136
'react/no-children-to-array' : 'warn' ,
128
137
'react/no-clone-element' : 'warn' ,
129
138
'react/no-comment-textnodes' : 'warn' ,
130
139
'react/no-component-will-mount' : 'error' ,
131
140
'react/no-component-will-receive-props' : 'error' ,
132
141
'react/no-component-will-update' : 'error' ,
142
+ 'react/no-context-provider' : 'warn' ,
133
143
'react/no-create-ref' : 'error' ,
144
+ 'react/no-default-props' : 'error' ,
134
145
'react/no-direct-mutation-state' : 'error' ,
135
146
'react/no-duplicate-key' : 'error' ,
136
- 'react/no-implicit-key' : 'error' ,
147
+ 'react/no-forward-ref' : 'warn' ,
148
+ 'react/no-implicit-key' : 'warn' ,
137
149
'react/no-missing-key' : 'error' ,
138
- 'react/no-nested-components' : 'warn' ,
150
+ 'react/no-nested-components' : 'error' ,
151
+ 'react/no-prop-types' : 'error' ,
139
152
'react/no-redundant-should-component-update' : 'error' ,
140
153
'react/no-set-state-in-component-did-mount' : 'warn' ,
141
154
'react/no-set-state-in-component-did-update' : 'warn' ,
@@ -144,24 +157,29 @@ export async function react(
144
157
'react/no-unsafe-component-will-mount' : 'warn' ,
145
158
'react/no-unsafe-component-will-receive-props' : 'warn' ,
146
159
'react/no-unsafe-component-will-update' : 'warn' ,
147
- 'react/no-unstable-context-value' : 'error ' ,
148
- 'react/no-unstable-default-props' : 'error ' ,
160
+ 'react/no-unstable-context-value' : 'warn ' ,
161
+ 'react/no-unstable-default-props' : 'warn ' ,
149
162
'react/no-unused-class-component-members' : 'warn' ,
150
163
'react/no-unused-state' : 'warn' ,
151
- 'react/no-useless-fragment' : 'warn' ,
152
164
'react/prefer-destructuring-assignment' : 'warn' ,
153
165
'react/prefer-shorthand-boolean' : 'warn' ,
154
166
'react/prefer-shorthand-fragment' : 'warn' ,
155
167
156
- ...( isTypeAware
157
- ? {
158
- 'react/no-leaked-conditional-rendering' : 'warn' ,
159
- }
160
- : { } ) ,
161
-
162
168
// overrides
163
169
...overrides ,
164
170
} ,
165
171
} ,
172
+ ...( isTypeAware
173
+ ? [
174
+ {
175
+ files : filesTypeAware ,
176
+ ignores : ignoresTypeAware ,
177
+ name : 'coderwyd/react/type-aware-rules' ,
178
+ rules : {
179
+ ...typeAwareRules ,
180
+ } ,
181
+ } ,
182
+ ]
183
+ : [ ] ) ,
166
184
]
167
185
}
0 commit comments