@@ -49,7 +49,7 @@ const namedTypes = {
49
49
} ;
50
50
51
51
function getFlowTypeWithRequirements ( path : NodePath ) : FlowTypeDescriptor {
52
- const type = getFlowType ( path ) ;
52
+ const type = getFlowTypeWithResolvedTypes ( path ) ;
53
53
54
54
type . required = ! path . parentPath . node . optional ;
55
55
@@ -80,7 +80,7 @@ function handleKeysHelper(path: NodePath) {
80
80
function handleArrayTypeAnnotation ( path : NodePath ) {
81
81
return {
82
82
name : 'Array' ,
83
- elements : [ getFlowType ( path . get ( 'elementType' ) ) ] ,
83
+ elements : [ getFlowTypeWithResolvedTypes ( path . get ( 'elementType' ) ) ] ,
84
84
raw : printValue ( path ) ,
85
85
} ;
86
86
}
@@ -102,13 +102,13 @@ function handleGenericTypeAnnotation(path: NodePath) {
102
102
103
103
type = {
104
104
...type ,
105
- elements : params . map ( param => getFlowType ( param ) ) ,
105
+ elements : params . map ( param => getFlowTypeWithResolvedTypes ( param ) ) ,
106
106
raw : printValue ( path ) ,
107
107
} ;
108
108
} else {
109
109
let resolvedPath = resolveToValue ( path . get ( 'id' ) ) ;
110
110
if ( resolvedPath && resolvedPath . node . right ) {
111
- type = getFlowType ( resolvedPath . get ( 'right' ) ) ;
111
+ type = getFlowTypeWithResolvedTypes ( resolvedPath . get ( 'right' ) ) ;
112
112
}
113
113
}
114
114
@@ -124,12 +124,12 @@ function handleObjectTypeAnnotation(path: NodePath) {
124
124
} ;
125
125
126
126
path . get ( 'callProperties' ) . each ( param => {
127
- type . signature . constructor = getFlowType ( param . get ( 'value' ) ) ;
127
+ type . signature . constructor = getFlowTypeWithResolvedTypes ( param . get ( 'value' ) ) ;
128
128
} ) ;
129
129
130
130
path . get ( 'indexers' ) . each ( param => {
131
131
type . signature . properties . push ( {
132
- key : getFlowType ( param . get ( 'key' ) ) ,
132
+ key : getFlowTypeWithResolvedTypes ( param . get ( 'key' ) ) ,
133
133
value : getFlowTypeWithRequirements ( param . get ( 'value' ) ) ,
134
134
} ) ;
135
135
} ) ;
@@ -148,15 +148,15 @@ function handleUnionTypeAnnotation(path: NodePath) {
148
148
return {
149
149
name : 'union' ,
150
150
raw : printValue ( path ) ,
151
- elements : path . get ( 'types' ) . map ( subType => getFlowType ( subType ) ) ,
151
+ elements : path . get ( 'types' ) . map ( subType => getFlowTypeWithResolvedTypes ( subType ) ) ,
152
152
} ;
153
153
}
154
154
155
155
function handleIntersectionTypeAnnotation ( path : NodePath ) {
156
156
return {
157
157
name : 'intersection' ,
158
158
raw : printValue ( path ) ,
159
- elements : path . get ( 'types' ) . map ( subType => getFlowType ( subType ) ) ,
159
+ elements : path . get ( 'types' ) . map ( subType => getFlowTypeWithResolvedTypes ( subType ) ) ,
160
160
} ;
161
161
}
162
162
@@ -165,7 +165,7 @@ function handleNullableTypeAnnotation(path: NodePath) {
165
165
166
166
if ( ! typeAnnotation ) return null ;
167
167
168
- const type = getFlowType ( typeAnnotation ) ;
168
+ const type = getFlowTypeWithResolvedTypes ( typeAnnotation ) ;
169
169
type . nullable = true ;
170
170
171
171
return type ;
@@ -178,7 +178,7 @@ function handleFunctionTypeAnnotation(path: NodePath) {
178
178
raw : printValue ( path ) ,
179
179
signature : {
180
180
arguments : [ ] ,
181
- return : getFlowType ( path . get ( 'returnType' ) ) ,
181
+ return : getFlowTypeWithResolvedTypes ( path . get ( 'returnType' ) ) ,
182
182
} ,
183
183
} ;
184
184
@@ -188,7 +188,7 @@ function handleFunctionTypeAnnotation(path: NodePath) {
188
188
189
189
type . signature . arguments . push ( {
190
190
name : param . node . name ? param . node . name . name : '' ,
191
- type : getFlowType ( typeAnnotation ) ,
191
+ type : getFlowTypeWithResolvedTypes ( typeAnnotation ) ,
192
192
} ) ;
193
193
} ) ;
194
194
@@ -199,14 +199,14 @@ function handleTupleTypeAnnotation(path: NodePath) {
199
199
const type = { name : 'tuple' , raw : printValue ( path ) , elements : [ ] } ;
200
200
201
201
path . get ( 'types' ) . each ( param => {
202
- type . elements . push ( getFlowType ( param ) ) ;
202
+ type . elements . push ( getFlowTypeWithResolvedTypes ( param ) ) ;
203
203
} ) ;
204
204
205
205
return type ;
206
206
}
207
207
208
208
function handleTypeofTypeAnnotation ( path : NodePath ) {
209
- return getFlowType ( path . get ( 'argument' ) ) ;
209
+ return getFlowTypeWithResolvedTypes ( path . get ( 'argument' ) ) ;
210
210
}
211
211
212
212
function handleQualifiedTypeIdentifier ( path : NodePath ) {
@@ -215,17 +215,28 @@ function handleQualifiedTypeIdentifier(path: NodePath) {
215
215
return { name : `React${ path . node . id . name } ` , raw : printValue ( path ) } ;
216
216
}
217
217
218
- /**
219
- * Tries to identify the flow type by inspecting the path for known
220
- * flow type names. This method doesn't check whether the found type is actually
221
- * existing. It simply assumes that a match is always valid.
222
- *
223
- * If there is no match, "unknown" is returned.
224
- */
225
- export default function getFlowType ( path : NodePath ) : FlowTypeDescriptor {
218
+ let visitedTypes = { } ;
219
+
220
+ function getFlowTypeWithResolvedTypes ( path : NodePath ) : FlowTypeDescriptor {
226
221
const node = path . node ;
227
222
let type : ?FlowTypeDescriptor ;
228
223
224
+ const isTypeAlias = types . TypeAlias . check ( path . parentPath . node ) ;
225
+ // When we see a typealias mark it as visited so that the next
226
+ // call of this function does not run into an endless loop
227
+ if ( isTypeAlias ) {
228
+ if ( visitedTypes [ path . parentPath . node . id . name ] === true ) {
229
+ // if we are currently visiting this node then just return the name
230
+ // as we are starting to endless loop
231
+ return { name : path . parentPath . node . id . name } ;
232
+ } else if ( typeof visitedTypes [ path . parentPath . node . id . name ] === 'object' ) {
233
+ // if we already resolved the type simple return it
234
+ return visitedTypes [ path . parentPath . node . id . name ] ;
235
+ }
236
+ // mark the type as visited
237
+ visitedTypes [ path . parentPath . node . id . name ] = true ;
238
+ }
239
+
229
240
if ( types . Type . check ( node ) ) {
230
241
if ( node . type in flowTypes ) {
231
242
type = { name : flowTypes [ node . type ] } ;
@@ -236,9 +247,26 @@ export default function getFlowType(path: NodePath): FlowTypeDescriptor {
236
247
}
237
248
}
238
249
250
+ if ( isTypeAlias ) {
251
+ // mark the type as unvisited so that further calls can resolve the type again
252
+ visitedTypes [ path . parentPath . node . id . name ] = type ;
253
+ }
254
+
239
255
if ( ! type ) {
240
256
type = { name : 'unknown' } ;
241
257
}
242
258
243
259
return type ;
244
260
}
261
+
262
+ /**
263
+ * Tries to identify the flow type by inspecting the path for known
264
+ * flow type names. This method doesn't check whether the found type is actually
265
+ * existing. It simply assumes that a match is always valid.
266
+ *
267
+ * If there is no match, "unknown" is returned.
268
+ */
269
+ export default function getFlowType ( path : NodePath ) : FlowTypeDescriptor {
270
+ visitedTypes = { } ;
271
+ return getFlowTypeWithResolvedTypes ( path ) ;
272
+ }
0 commit comments