@@ -183,23 +183,37 @@ export function parseFromProgram(filePath: string, program: ts.Program) {
183
183
return ;
184
184
}
185
185
186
- programNode . body . push ( t . componentNode ( name , properties . map ( checkSymbol ) ) ) ;
186
+ programNode . body . push (
187
+ t . componentNode ( name , properties . map ( x => checkSymbol ( x , [ ( type as any ) . id ] ) ) ) ,
188
+ ) ;
187
189
}
188
190
189
- function checkSymbol ( symbol : ts . Symbol ) : t . PropTypeNode {
190
- const locations = symbol . getDeclarations ( ) ;
191
- if ( ! locations ) {
192
- console . error ( 'No types found' ) ;
193
- return t . propTypeNode ( symbol . getName ( ) , getDocumentation ( symbol ) , t . anyNode ( ) ) ;
191
+ function checkSymbol ( symbol : ts . Symbol , typeStack : number [ ] ) : t . PropTypeNode {
192
+ const declarations = symbol . getDeclarations ( ) ;
193
+
194
+ const type = declarations
195
+ ? // The proptypes aren't detailed enough that we need all the different combinations
196
+ // so we just pick the first and ignore the rest
197
+ checker . getTypeOfSymbolAtLocation ( symbol , declarations [ 0 ] )
198
+ : // The properties of Record<..., ...> don't have a declaration, but the symbol has a type property
199
+ ( ( symbol as any ) . type as ts . Type ) ;
200
+
201
+ if ( ! type ) {
202
+ throw new Error ( 'No types found' ) ;
194
203
}
195
204
196
- // The proptypes aren't detailed enough that we need all the different combinations
197
- // So we just pick the first and ignore the rest
198
- const type = checker . getTypeOfSymbolAtLocation ( symbol , locations [ 0 ] ) ;
199
- return t . propTypeNode ( symbol . getName ( ) , getDocumentation ( symbol ) , checkType ( type ) ) ;
205
+ return t . propTypeNode (
206
+ symbol . getName ( ) ,
207
+ getDocumentation ( symbol ) ,
208
+ // If the typeStack contains type.id we're dealing with a type that references itself.
209
+ // To prevent getting stuck in an infinite loop we just set it to an objectNode
210
+ typeStack . includes ( ( type as any ) . id )
211
+ ? t . objectNode ( )
212
+ : checkType ( type , [ ...typeStack , ( type as any ) . id ] ) ,
213
+ ) ;
200
214
}
201
215
202
- function checkType ( type : ts . Type ) : t . Node {
216
+ function checkType ( type : ts . Type , typeStack : number [ ] ) : t . Node {
203
217
{
204
218
const typeNode = type as any ;
205
219
@@ -220,11 +234,11 @@ export function parseFromProgram(filePath: string, program: ts.Program) {
220
234
if ( checker . isArrayType ( type ) ) {
221
235
// @ts -ignore - Private method
222
236
const arrayType : ts . Type = checker . getElementTypeOfArrayType ( type ) ;
223
- return t . arrayNode ( checkType ( arrayType ) ) ;
237
+ return t . arrayNode ( checkType ( arrayType , typeStack ) ) ;
224
238
}
225
239
226
240
if ( type . isUnion ( ) ) {
227
- return t . unionNode ( type . types . map ( checkType ) ) ;
241
+ return t . unionNode ( type . types . map ( x => checkType ( x , typeStack ) ) ) ;
228
242
}
229
243
230
244
if ( type . flags & ts . TypeFlags . String ) {
0 commit comments