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'
511import type {
612 OptionsFiles ,
713 OptionsOverrides ,
14+ OptionsTypeScriptParserOptions ,
815 OptionsTypeScriptWithTypes ,
916 TypedFlatConfigItem ,
1017} from '../types'
1118
12- // react refresh
13- const ReactRefreshAllowConstantExportPackages = [ 'vite' ]
14-
1519export async function react (
16- options : OptionsTypeScriptWithTypes & OptionsOverrides & OptionsFiles = { } ,
20+ options : OptionsTypeScriptParserOptions &
21+ OptionsTypeScriptWithTypes &
22+ OptionsOverrides &
23+ OptionsFiles = { } ,
1724) : 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
1932
2033 await ensurePackages ( [
2134 '@eslint-react/eslint-plugin' ,
2235 'eslint-plugin-react-hooks' ,
2336 'eslint-plugin-react-refresh' ,
2437 ] )
2538
26- const tsconfigPath = options ?. tsconfigPath
27- ? toArray ( options . tsconfigPath )
28- : undefined
2939 const isTypeAware = ! ! tsconfigPath
3040
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+ [
3347 interopDefault ( import ( '@eslint-react/eslint-plugin' ) ) ,
3448 interopDefault ( import ( 'eslint-plugin-react-hooks' ) ) ,
3549 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 ,
4151 )
4252
4353 const plugins = pluginReact . configs . all . plugins
@@ -57,12 +67,10 @@ export async function react(
5767 {
5868 files,
5969 languageOptions : {
60- parser : parserTs ,
6170 parserOptions : {
6271 ecmaFeatures : {
6372 jsx : true ,
6473 } ,
65- ...( isTypeAware ? { project : tsconfigPath } : { } ) ,
6674 } ,
6775 sourceType : 'module' ,
6876 } ,
@@ -117,25 +125,30 @@ export async function react(
117125
118126 // recommended rules from @eslint -react
119127 'react/ensure-forward-ref-using-ref' : 'warn' ,
128+ 'react/jsx-no-duplicate-props' : 'warn' ,
129+ 'react/jsx-uses-vars' : 'warn' ,
120130 'react/no-access-state-in-setstate' : 'error' ,
121131 'react/no-array-index-key' : 'warn' ,
122132 'react/no-children-count' : 'warn' ,
123133 'react/no-children-for-each' : 'warn' ,
124134 'react/no-children-map' : 'warn' ,
125135 'react/no-children-only' : 'warn' ,
126- 'react/no-children-prop' : 'warn' ,
127136 'react/no-children-to-array' : 'warn' ,
128137 'react/no-clone-element' : 'warn' ,
129138 'react/no-comment-textnodes' : 'warn' ,
130139 'react/no-component-will-mount' : 'error' ,
131140 'react/no-component-will-receive-props' : 'error' ,
132141 'react/no-component-will-update' : 'error' ,
142+ 'react/no-context-provider' : 'warn' ,
133143 'react/no-create-ref' : 'error' ,
144+ 'react/no-default-props' : 'error' ,
134145 'react/no-direct-mutation-state' : 'error' ,
135146 'react/no-duplicate-key' : 'error' ,
136- 'react/no-implicit-key' : 'error' ,
147+ 'react/no-forward-ref' : 'warn' ,
148+ 'react/no-implicit-key' : 'warn' ,
137149 'react/no-missing-key' : 'error' ,
138- 'react/no-nested-components' : 'warn' ,
150+ 'react/no-nested-components' : 'error' ,
151+ 'react/no-prop-types' : 'error' ,
139152 'react/no-redundant-should-component-update' : 'error' ,
140153 'react/no-set-state-in-component-did-mount' : 'warn' ,
141154 'react/no-set-state-in-component-did-update' : 'warn' ,
@@ -144,24 +157,29 @@ export async function react(
144157 'react/no-unsafe-component-will-mount' : 'warn' ,
145158 'react/no-unsafe-component-will-receive-props' : 'warn' ,
146159 '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 ' ,
149162 'react/no-unused-class-component-members' : 'warn' ,
150163 'react/no-unused-state' : 'warn' ,
151- 'react/no-useless-fragment' : 'warn' ,
152164 'react/prefer-destructuring-assignment' : 'warn' ,
153165 'react/prefer-shorthand-boolean' : 'warn' ,
154166 'react/prefer-shorthand-fragment' : 'warn' ,
155167
156- ...( isTypeAware
157- ? {
158- 'react/no-leaked-conditional-rendering' : 'warn' ,
159- }
160- : { } ) ,
161-
162168 // overrides
163169 ...overrides ,
164170 } ,
165171 } ,
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+ : [ ] ) ,
166184 ]
167185}
0 commit comments