1
1
import { isPackageExists } from 'local-pkg'
2
- import { ensurePackages , interopDefault } from '../utils'
3
- import type { OptionsFiles , OptionsHasTypeScript , OptionsOverrides , TypedFlatConfigItem } from '../types'
4
- import { GLOB_JSX , GLOB_TSX } from '../globs'
2
+ import { ensurePackages , interopDefault , toArray } from '../utils'
3
+ import type { OptionsFiles , OptionsOverrides , OptionsTypeScriptWithTypes , TypedFlatConfigItem } from '../types'
4
+ import { GLOB_TS , GLOB_TSX } from '../globs'
5
5
6
6
// react refresh
7
7
const ReactRefreshAllowConstantExportPackages = [
8
8
'vite' ,
9
9
]
10
10
11
11
export async function react (
12
- options : OptionsHasTypeScript & OptionsOverrides & OptionsFiles = { } ,
12
+ options : OptionsTypeScriptWithTypes & OptionsOverrides & OptionsFiles = { } ,
13
13
) : Promise < TypedFlatConfigItem [ ] > {
14
14
const {
15
- files = [ GLOB_JSX , GLOB_TSX ] ,
15
+ files = [ GLOB_TS , GLOB_TSX ] ,
16
16
overrides = { } ,
17
- typescript = true ,
18
17
} = options
19
18
20
19
await ensurePackages ( [
21
- 'eslint-plugin- react' ,
20
+ '@ eslint-react/eslint-plugin ' ,
22
21
'eslint-plugin-react-hooks' ,
23
22
'eslint-plugin-react-refresh' ,
24
23
] )
25
24
25
+ const tsconfigPath = options ?. tsconfigPath
26
+ ? toArray ( options . tsconfigPath )
27
+ : undefined
28
+ const isTypeAware = ! ! tsconfigPath
29
+
26
30
const [
27
31
pluginReact ,
28
32
pluginReactHooks ,
29
33
pluginReactRefresh ,
34
+ parserTs ,
30
35
] = await Promise . all ( [
31
- interopDefault ( import ( 'eslint-plugin- react' ) ) ,
36
+ interopDefault ( import ( '@ eslint-react/eslint-plugin ' ) ) ,
32
37
interopDefault ( import ( 'eslint-plugin-react-hooks' ) ) ,
33
38
interopDefault ( import ( 'eslint-plugin-react-refresh' ) ) ,
39
+ interopDefault ( import ( '@typescript-eslint/parser' ) ) ,
34
40
] as const )
35
41
36
42
const isAllowConstantExport = ReactRefreshAllowConstantExportPackages . some (
37
43
i => isPackageExists ( i ) ,
38
44
)
39
45
46
+ const plugins = pluginReact . configs . all . plugins
47
+
40
48
return [
41
49
{
42
50
name : 'antfu/react/setup' ,
43
51
plugins : {
44
- 'react' : pluginReact ,
52
+ 'react' : plugins [ '@eslint-react' ] ,
53
+ 'react-dom' : plugins [ '@eslint-react/dom' ] ,
45
54
'react-hooks' : pluginReactHooks ,
55
+ 'react-hooks-extra' : plugins [ '@eslint-react/hooks-extra' ] ,
56
+ 'react-naming-convention' : plugins [ '@eslint-react/naming-convention' ] ,
46
57
'react-refresh' : pluginReactRefresh ,
47
58
} ,
48
- settings : {
49
- react : {
50
- version : 'detect' ,
51
- } ,
52
- } ,
53
59
} ,
54
60
{
55
61
files,
56
62
languageOptions : {
63
+ parser : parserTs ,
57
64
parserOptions : {
58
65
ecmaFeatures : {
59
66
jsx : true ,
60
67
} ,
68
+ ...isTypeAware ? { project : tsconfigPath } : { } ,
61
69
} ,
70
+ sourceType : 'module' ,
62
71
} ,
63
72
name : 'antfu/react/rules' ,
64
73
rules : {
74
+ // recommended rules from @eslint -react/dom
75
+ 'react-dom/no-children-in-void-dom-elements' : 'warn' ,
76
+ 'react-dom/no-dangerously-set-innerhtml' : 'warn' ,
77
+ 'react-dom/no-dangerously-set-innerhtml-with-children' : 'error' ,
78
+ 'react-dom/no-find-dom-node' : 'error' ,
79
+ 'react-dom/no-missing-button-type' : 'warn' ,
80
+ 'react-dom/no-missing-iframe-sandbox' : 'warn' ,
81
+ 'react-dom/no-namespace' : 'error' ,
82
+ 'react-dom/no-render-return-value' : 'error' ,
83
+ 'react-dom/no-script-url' : 'warn' ,
84
+ 'react-dom/no-unsafe-iframe-sandbox' : 'warn' ,
85
+ 'react-dom/no-unsafe-target-blank' : 'warn' ,
86
+
65
87
// recommended rules react-hooks
66
88
'react-hooks/exhaustive-deps' : 'warn' ,
67
89
'react-hooks/rules-of-hooks' : 'error' ,
@@ -72,34 +94,47 @@ export async function react(
72
94
{ allowConstantExport : isAllowConstantExport } ,
73
95
] ,
74
96
75
- // recommended rules react
76
- 'react/display-name' : 'error' ,
77
- 'react/jsx-key' : 'error' ,
78
- 'react/jsx-no-comment-textnodes' : 'error' ,
79
- 'react/jsx-no-duplicate-props' : 'error' ,
80
- 'react/jsx-no-target-blank' : 'error' ,
81
- 'react/jsx-no-undef' : 'error' ,
82
- 'react/jsx-uses-react' : 'error' ,
83
- 'react/jsx-uses-vars' : 'error' ,
84
- 'react/no-children-prop' : 'error' ,
85
- 'react/no-danger-with-children' : 'error' ,
86
- 'react/no-deprecated' : 'error' ,
97
+ // recommended rules from @eslint -react
98
+ 'react/ensure-forward-ref-using-ref' : 'warn' ,
99
+ 'react/no-access-state-in-setstate' : 'error' ,
100
+ 'react/no-array-index-key' : 'warn' ,
101
+ 'react/no-children-count' : 'warn' ,
102
+ 'react/no-children-for-each' : 'warn' ,
103
+ 'react/no-children-map' : 'warn' ,
104
+ 'react/no-children-only' : 'warn' ,
105
+ 'react/no-children-prop' : 'warn' ,
106
+ 'react/no-children-to-array' : 'warn' ,
107
+ 'react/no-clone-element' : 'warn' ,
108
+ 'react/no-comment-textnodes' : 'warn' ,
109
+ 'react/no-component-will-mount' : 'error' ,
110
+ 'react/no-component-will-receive-props' : 'error' ,
111
+ 'react/no-component-will-update' : 'error' ,
112
+ 'react/no-create-ref' : 'error' ,
87
113
'react/no-direct-mutation-state' : 'error' ,
88
- 'react/no-find-dom-node' : 'error' ,
89
- 'react/no-is-mounted' : 'error' ,
90
- 'react/no-render-return-value' : 'error' ,
114
+ 'react/no-duplicate-key' : 'error' ,
115
+ 'react/no-implicit-key' : 'error' ,
116
+ 'react/no-missing-key' : 'error' ,
117
+ 'react/no-nested-components' : 'warn' ,
118
+ 'react/no-redundant-should-component-update' : 'error' ,
119
+ 'react/no-set-state-in-component-did-mount' : 'warn' ,
120
+ 'react/no-set-state-in-component-did-update' : 'warn' ,
121
+ 'react/no-set-state-in-component-will-update' : 'warn' ,
91
122
'react/no-string-refs' : 'error' ,
92
- 'react/no-unescaped-entities' : 'error' ,
93
- 'react/no-unknown-property' : 'error' ,
94
- 'react/no-unsafe' : 'off' ,
95
- 'react/prop-types' : 'error' ,
96
- 'react/react-in-jsx-scope' : 'off' ,
97
- 'react/require-render-return' : 'error' ,
123
+ 'react/no-unsafe-component-will-mount' : 'warn' ,
124
+ 'react/no-unsafe-component-will-receive-props' : 'warn' ,
125
+ 'react/no-unsafe-component-will-update' : 'warn' ,
126
+ 'react/no-unstable-context-value' : 'error' ,
127
+ 'react/no-unstable-default-props' : 'error' ,
128
+ 'react/no-unused-class-component-members' : 'warn' ,
129
+ 'react/no-unused-state' : 'warn' ,
130
+ 'react/no-useless-fragment' : 'warn' ,
131
+ 'react/prefer-destructuring-assignment' : 'warn' ,
132
+ 'react/prefer-shorthand-boolean' : 'warn' ,
133
+ 'react/prefer-shorthand-fragment' : 'warn' ,
98
134
99
- ...typescript
135
+ ...isTypeAware
100
136
? {
101
- 'react/jsx-no-undef' : 'off' ,
102
- 'react/prop-type' : 'off' ,
137
+ 'react/no-leaked-conditional-rendering' : 'warn' ,
103
138
}
104
139
: { } ,
105
140
0 commit comments