@@ -8,46 +8,47 @@ import type {
8
8
JSCodeshift ,
9
9
TSTypeLiteral ,
10
10
TSTypeReference ,
11
- } from 'jscodeshift' ;
11
+ TSTypeParameterInstantiation ,
12
+ } from "jscodeshift" ;
12
13
13
14
// Props & { ref: React.RefObject<Ref>}
14
15
const buildPropsAndRefIntersectionTypeAnnotation = (
15
16
j : JSCodeshift ,
16
17
propType : TSTypeReference | TSTypeLiteral ,
17
- refType : TSTypeReference | TSTypeLiteral | null ,
18
+ refType : TSTypeReference | TSTypeLiteral | null
18
19
) =>
19
20
j . tsTypeAnnotation (
20
21
j . tsIntersectionType ( [
21
22
propType ,
22
23
j . tsTypeLiteral ( [
23
24
j . tsPropertySignature . from ( {
24
- key : j . identifier ( ' ref' ) ,
25
+ key : j . identifier ( " ref" ) ,
25
26
typeAnnotation : j . tsTypeAnnotation (
26
27
j . tsTypeReference . from ( {
27
28
typeName : j . tsQualifiedName (
28
- j . identifier ( ' React' ) ,
29
- j . identifier ( ' RefObject' ) ,
29
+ j . identifier ( " React" ) ,
30
+ j . identifier ( " RefObject" )
30
31
) ,
31
32
typeParameters : j . tsTypeParameterInstantiation ( [
32
33
refType === null ? j . tsUnknownKeyword ( ) : refType ,
33
34
] ) ,
34
- } ) ,
35
+ } )
35
36
) ,
36
37
} ) ,
37
38
] ) ,
38
- ] ) ,
39
+ ] )
39
40
) ;
40
41
41
42
// { ref: refName, ...propsName }
42
43
const buildRefAndPropsObjectPattern = (
43
44
j : JSCodeshift ,
44
45
refArgName : string ,
45
- propArgName : string ,
46
+ propArgName : string
46
47
) =>
47
48
j . objectPattern ( [
48
49
j . objectProperty . from ( {
49
50
shorthand : true ,
50
- key : j . identifier ( ' ref' ) ,
51
+ key : j . identifier ( " ref" ) ,
51
52
value : j . identifier ( refArgName ) ,
52
53
} ) ,
53
54
j . restProperty ( j . identifier ( propArgName ) ) ,
@@ -65,7 +66,7 @@ const getRefTypeFromRefArg = (j: JSCodeshift, refArg: Identifier) => {
65
66
66
67
const { right } = typeReference . typeName ;
67
68
68
- if ( ! j . Identifier . check ( right ) || right . name === ' forwardedRef' ) {
69
+ if ( ! j . Identifier . check ( right ) || right . name === " forwardedRef" ) {
69
70
return null ;
70
71
}
71
72
@@ -80,7 +81,7 @@ const getRefTypeFromRefArg = (j: JSCodeshift, refArg: Identifier) => {
80
81
81
82
const getForwardRefRenderFunction = (
82
83
j : JSCodeshift ,
83
- callExpression : CallExpression ,
84
+ callExpression : CallExpression
84
85
) : FunctionExpression | ArrowFunctionExpression | null => {
85
86
const [ renderFunction ] = callExpression . arguments ;
86
87
@@ -96,7 +97,7 @@ const getForwardRefRenderFunction = (
96
97
97
98
const isLiteralOrReference = (
98
99
j : JSCodeshift ,
99
- type : unknown ,
100
+ type : unknown
100
101
) : type is TSTypeReference | TSTypeLiteral => {
101
102
return j . TSTypeReference . check ( type ) || j . TSTypeLiteral . check ( type ) ;
102
103
} ;
@@ -113,14 +114,14 @@ export default function transform(file: FileInfo, api: API) {
113
114
114
115
root
115
116
. find ( j . ImportDeclaration , {
116
- source : { value : ' react' } ,
117
+ source : { value : " react" } ,
117
118
} )
118
119
. forEach ( ( path ) => {
119
120
path . value . specifiers ?. forEach ( ( specifier ) => {
120
121
// named import
121
122
if (
122
123
j . ImportSpecifier . check ( specifier ) &&
123
- specifier . imported . name === ' forwardRef'
124
+ specifier . imported . name === " forwardRef"
124
125
) {
125
126
reactForwardRefImportLocalName = specifier . local ?. name ?? null ;
126
127
}
@@ -152,7 +153,7 @@ export default function transform(file: FileInfo, api: API) {
152
153
j . Identifier . check ( callee . object ) &&
153
154
callee . object . name === reactDefaultImportName &&
154
155
j . Identifier . check ( callee . property ) &&
155
- callee . property . name === ' forwardRef'
156
+ callee . property . name === " forwardRef"
156
157
) {
157
158
return true ;
158
159
}
@@ -164,11 +165,11 @@ export default function transform(file: FileInfo, api: API) {
164
165
165
166
const renderFunction = getForwardRefRenderFunction (
166
167
j ,
167
- callExpressionPath . node ,
168
+ callExpressionPath . node
168
169
) ;
169
170
170
171
if ( renderFunction === null ) {
171
- console . warn ( ' Could not detect render function.' ) ;
172
+ console . warn ( " Could not detect render function." ) ;
172
173
173
174
return originalCallExpression ;
174
175
}
@@ -179,7 +180,7 @@ export default function transform(file: FileInfo, api: API) {
179
180
! j . Identifier . check ( refArg ) ||
180
181
! ( j . Identifier . check ( propsArg ) || j . ObjectPattern . check ( propsArg ) )
181
182
) {
182
- console . warn ( ' Could not detect ref or props arguments.' ) ;
183
+ console . warn ( " Could not detect ref or props arguments." ) ;
183
184
184
185
return originalCallExpression ;
185
186
}
@@ -196,9 +197,9 @@ export default function transform(file: FileInfo, api: API) {
196
197
propsArg . properties . unshift (
197
198
j . objectProperty . from ( {
198
199
shorthand : true ,
199
- key : j . identifier ( ' ref' ) ,
200
+ key : j . identifier ( " ref" ) ,
200
201
value : j . identifier ( refArgName ) ,
201
- } ) ,
202
+ } )
202
203
) ;
203
204
204
205
isDirty = true ;
@@ -209,7 +210,7 @@ export default function transform(file: FileInfo, api: API) {
209
210
renderFunction . params [ 0 ] = buildRefAndPropsObjectPattern (
210
211
j ,
211
212
refArg . name ,
212
- propsArg . name ,
213
+ propsArg . name
213
214
) ;
214
215
215
216
isDirty = true ;
@@ -222,13 +223,13 @@ export default function transform(file: FileInfo, api: API) {
222
223
if (
223
224
isLiteralOrReference ( j , propsArgTypeReference ) &&
224
225
renderFunction . params ?. [ 0 ] &&
225
- ' typeAnnotation' in renderFunction . params [ 0 ]
226
+ " typeAnnotation" in renderFunction . params [ 0 ]
226
227
) {
227
228
renderFunction . params [ 0 ] . typeAnnotation =
228
229
buildPropsAndRefIntersectionTypeAnnotation (
229
230
j ,
230
231
propsArgTypeReference ,
231
- refArgTypeReference ,
232
+ refArgTypeReference
232
233
) ;
233
234
isDirty = true ;
234
235
}
@@ -237,14 +238,18 @@ export default function transform(file: FileInfo, api: API) {
237
238
* Transform ts types: forwardRef type arguments are used
238
239
*/
239
240
240
- const typeParameters = callExpressionPath . node . typeParameters ;
241
+ const typeParameters = (
242
+ callExpressionPath . node as CallExpression & {
243
+ typeParameters ?: TSTypeParameterInstantiation ;
244
+ }
245
+ ) . typeParameters ;
241
246
242
247
// if typeParameters are used in forwardRef generic, reuse them to annotate props type
243
248
// forwardRef<Ref, Props>((props) => { ... }) ====> (props: Props & { ref: React.RefObject<Ref> }) => { ... }
244
249
if (
245
250
j . TSTypeParameterInstantiation . check ( typeParameters ) &&
246
251
renderFunction . params ?. [ 0 ] &&
247
- ' typeAnnotation' in renderFunction . params [ 0 ]
252
+ " typeAnnotation" in renderFunction . params [ 0 ]
248
253
) {
249
254
const [ refType , propType ] = typeParameters . params ;
250
255
@@ -269,20 +274,20 @@ export default function transform(file: FileInfo, api: API) {
269
274
root
270
275
. find ( j . ImportDeclaration , {
271
276
source : {
272
- value : ' react' ,
277
+ value : " react" ,
273
278
} ,
274
279
} )
275
280
. forEach ( ( importDeclarationPath ) => {
276
281
const { specifiers, importKind } = importDeclarationPath . node ;
277
282
278
- if ( importKind !== ' value' ) {
283
+ if ( importKind !== " value" ) {
279
284
return ;
280
285
}
281
286
282
287
const specifiersWithoutForwardRef =
283
288
specifiers ?. filter (
284
289
( s ) =>
285
- ! j . ImportSpecifier . check ( s ) || s . imported . name !== ' forwardRef' ,
290
+ ! j . ImportSpecifier . check ( s ) || s . imported . name !== " forwardRef"
286
291
) ?? [ ] ;
287
292
288
293
if ( specifiersWithoutForwardRef . length === 0 ) {
0 commit comments