@@ -51,7 +51,7 @@ export function createProgram(files: string[], options: ts.CompilerOptions) {
5151export function parseFile (
5252 filePath : string ,
5353 options : ts . CompilerOptions ,
54- parserOptions : Partial < ParserOptions > = { }
54+ parserOptions : Partial < ParserOptions > = { } ,
5555) {
5656 const program = ts . createProgram ( [ filePath ] , options ) ;
5757 return parseFromProgram ( filePath , program , parserOptions ) ;
@@ -66,7 +66,7 @@ export function parseFile(
6666export function parseFromProgram (
6767 filePath : string ,
6868 program : ts . Program ,
69- parserOptions : Partial < ParserOptions > = { }
69+ parserOptions : Partial < ParserOptions > = { } ,
7070) {
7171 const { checkDeclarations = false } = parserOptions ;
7272
@@ -168,7 +168,7 @@ export function parseFromProgram(
168168 parsePropsType (
169169 variableNode . name . getText ( ) ,
170170 type . aliasTypeArguments [ 0 ] ,
171- node . getSourceFile ( )
171+ node . getSourceFile ( ) ,
172172 ) ;
173173 } else if ( checkDeclarations ) {
174174 parseFunctionComponent ( variableNode ) ;
@@ -216,7 +216,7 @@ export function parseFromProgram(
216216 parsePropsType (
217217 node . name . getText ( ) ,
218218 checker . getTypeAtLocation ( arg . typeArguments [ 0 ] ) ,
219- node . getSourceFile ( )
219+ node . getSourceFile ( ) ,
220220 ) ;
221221 }
222222 }
@@ -225,11 +225,15 @@ export function parseFromProgram(
225225 function isTypeJSXElementLike ( type : ts . Type ) : boolean {
226226 if ( type . isUnion ( ) ) {
227227 return type . types . every (
228- ( subType ) => subType . flags & ts . TypeFlags . Null || isTypeJSXElementLike ( subType )
228+ ( subType ) => subType . flags & ts . TypeFlags . Null || isTypeJSXElementLike ( subType ) ,
229229 ) ;
230230 } else if ( type . symbol ) {
231231 const name = checker . getFullyQualifiedName ( type . symbol ) ;
232- return name === 'global.JSX.Element' || name === 'React.ReactElement' ;
232+ return (
233+ name === 'global.JSX.Element' ||
234+ name === 'React.ReactElement' ||
235+ name === 'React.JSX.Element'
236+ ) ;
233237 }
234238
235239 return false ;
@@ -246,15 +250,15 @@ export function parseFromProgram(
246250 }
247251 const componentName = node . name . getText ( ) ;
248252
249- const type = checker . getTypeOfSymbolAtLocation ( symbol , symbol . valueDeclaration ) ;
253+ const type = checker . getTypeOfSymbolAtLocation ( symbol , symbol . valueDeclaration ! ) ;
250254 type . getCallSignatures ( ) . forEach ( ( signature ) => {
251255 if ( ! isTypeJSXElementLike ( signature . getReturnType ( ) ) ) {
252256 return ;
253257 }
254258
255259 const propsType = checker . getTypeOfSymbolAtLocation (
256260 signature . parameters [ 0 ] ,
257- signature . parameters [ 0 ] . valueDeclaration
261+ signature . parameters [ 0 ] . valueDeclaration ! ,
258262 ) ;
259263
260264 parsePropsType ( componentName , propsType , node . getSourceFile ( ) ) ;
@@ -282,7 +286,7 @@ export function parseFromProgram(
282286 currentTypeNode . jsDoc ,
283287 t . unionNode ( [ currentTypeNode . propType , typeNode . propType ] ) ,
284288 new Set ( Array . from ( currentTypeNode . filenames ) . concat ( Array . from ( typeNode . filenames ) ) ) ,
285- undefined
289+ undefined ,
286290 ) ;
287291 }
288292
@@ -311,8 +315,8 @@ export function parseFromProgram(
311315 }
312316 return propType ;
313317 } ) ,
314- node . getSourceFile ( ) . fileName
315- )
318+ node . getSourceFile ( ) . fileName ,
319+ ) ,
316320 ) ;
317321 }
318322
@@ -330,8 +334,8 @@ export function parseFromProgram(
330334 t . componentNode (
331335 name ,
332336 properties . map ( ( x ) => checkSymbol ( x , new Set ( [ ( type as any ) . id ] ) ) ) ,
333- propsFilename
334- )
337+ propsFilename ,
338+ ) ,
335339 ) ;
336340 }
337341
@@ -361,25 +365,25 @@ export function parseFromProgram(
361365 name === 'React.Component'
362366 ) {
363367 const elementNode = t . elementNode (
364- name === 'React.ReactElement' ? 'element' : 'elementType'
368+ name === 'React.ReactElement' ? 'element' : 'elementType' ,
365369 ) ;
366370
367371 return t . propTypeNode (
368372 symbol . getName ( ) ,
369373 getDocumentation ( symbol ) ,
370374 declaration . questionToken ? t . unionNode ( [ t . undefinedNode ( ) , elementNode ] ) : elementNode ,
371375 symbolFilenames ,
372- ( symbol as any ) . id
376+ ( symbol as any ) . id ,
373377 ) ;
374378 }
375379 }
376380
377381 const symbolType = declaration
378382 ? // The proptypes aren't detailed enough that we need all the different combinations
379- // so we just pick the first and ignore the rest
380- checker . getTypeOfSymbolAtLocation ( symbol , declaration )
383+ // so we just pick the first and ignore the rest
384+ checker . getTypeOfSymbolAtLocation ( symbol , declaration )
381385 : // The properties of Record<..., ...> don't have a declaration, but the symbol has a type property
382- ( ( symbol as any ) . type as ts . Type ) ;
386+ ( ( symbol as any ) . type as ts . Type ) ;
383387 // get `React.ElementType` from `C extends React.ElementType`
384388 const declaredType =
385389 declaration !== undefined ? checker . getTypeAtLocation ( declaration ) : undefined ;
@@ -415,7 +419,7 @@ export function parseFromProgram(
415419 getDocumentation ( symbol ) ,
416420 parsedType ,
417421 symbolFilenames ,
418- ( symbol as any ) . id
422+ ( symbol as any ) . id ,
419423 ) ;
420424 }
421425
@@ -433,6 +437,7 @@ export function parseFromProgram(
433437 const typeName = symbol ? checker . getFullyQualifiedName ( symbol ) : null ;
434438 switch ( typeName ) {
435439 case 'global.JSX.Element' :
440+ case 'React.JSX.Element' :
436441 case 'React.ReactElement' : {
437442 return t . elementNode ( 'element' ) ;
438443 }
@@ -486,7 +491,7 @@ export function parseFromProgram(
486491 if ( type . isLiteral ( ) ) {
487492 return t . literalNode (
488493 type . isStringLiteral ( ) ? `"${ type . value } "` : type . value ,
489- getDocumentation ( type . symbol )
494+ getDocumentation ( type . symbol ) ,
490495 ) ;
491496 }
492497 return t . literalNode ( checker . typeToString ( type ) ) ;
@@ -496,8 +501,20 @@ export function parseFromProgram(
496501 return t . literalNode ( 'null' ) ;
497502 }
498503
499- if ( type . getCallSignatures ( ) . length ) {
500- return t . functionNode ( ) ;
504+ if ( type . getCallSignatures ( ) . length === 1 ) {
505+ const signature = type . getCallSignatures ( ) [ 0 ] ;
506+ return t . functionNode (
507+ signature . parameters . map ( ( param ) =>
508+ t . parameterNode (
509+ param . name ,
510+ checker . getTypeOfSymbol ( param ) ?. getSymbol ( ) ?. name ?? 'unknown' ,
511+ ) ,
512+ ) ,
513+ // TODO: parse return type
514+ t . anyNode ( ) ,
515+ ) ;
516+ } else if ( type . getCallSignatures ( ) . length > 1 ) {
517+ return t . functionNode ( [ ] , t . anyNode ( ) ) ;
501518 }
502519
503520 // Object-like type
@@ -508,13 +525,13 @@ export function parseFromProgram(
508525 shouldResolveObject ( { name, propertyCount : properties . length , depth : typeStack . size } )
509526 ) {
510527 const filtered = properties . filter ( ( symbol ) =>
511- shouldInclude ( { name : symbol . getName ( ) , depth : typeStack . size + 1 } )
528+ shouldInclude ( { name : symbol . getName ( ) , depth : typeStack . size + 1 } ) ,
512529 ) ;
513530 if ( filtered . length > 0 ) {
514531 return t . interfaceNode (
515532 filtered . map ( ( x ) =>
516- checkSymbol ( x , new Set ( [ ...typeStack . values ( ) , ( type as any ) . id ] ) )
517- )
533+ checkSymbol ( x , new Set ( [ ...typeStack . values ( ) , ( type as any ) . id ] ) ) ,
534+ ) ,
518535 ) ;
519536 }
520537 }
@@ -532,7 +549,7 @@ export function parseFromProgram(
532549 }
533550
534551 console . warn (
535- `Unable to handle node of type "ts.TypeFlags.${ ts . TypeFlags [ type . flags ] } ", using any`
552+ `Unable to handle node of type "ts.TypeFlags.${ ts . TypeFlags [ type . flags ] } ", using any` ,
536553 ) ;
537554 return t . anyNode ( ) ;
538555 }
0 commit comments