11import * as ts from 'typescript' ;
22import * as t from './types' ;
3- import { Documentation } from './types/documentation' ;
43
54/**
65 * Options that specify how the parser should act
@@ -167,8 +166,12 @@ export function parseFromProgram(
167166
168167 function visit ( node : ts . Node ) {
169168 // function x(props: type) { return <div/> }
170- if ( ts . isFunctionDeclaration ( node ) && node . name && node . parameters . length === 1 ) {
171- parseFunctionComponent ( node , node ) ;
169+ if ( ts . isFunctionDeclaration ( node ) && node . name ) {
170+ if ( node . name . getText ( ) . startsWith ( 'use' ) ) {
171+ parseHook ( node ) ;
172+ } else if ( node . parameters . length === 1 ) {
173+ parseFunctionComponent ( node , node ) ;
174+ }
172175 }
173176 // const x = ...
174177 else if ( ts . isVariableStatement ( node ) ) {
@@ -303,7 +306,7 @@ export function parseFromProgram(
303306 const props : Record < string , t . PropNode > = { } ;
304307 const usedPropsPerSignature : Set < String > [ ] = [ ] ;
305308 programNode . body = programNode . body . filter ( ( node ) => {
306- if ( node . name === componentName ) {
309+ if ( node . name === componentName && t . isComponentNode ( node ) ) {
307310 const usedProps : Set < string > = new Set ( ) ;
308311 // squash props
309312 node . props . forEach ( ( propNode ) => {
@@ -397,6 +400,49 @@ export function parseFromProgram(
397400 ) ;
398401 }
399402
403+ function parseHook ( node : ts . VariableDeclaration | ts . FunctionDeclaration ) {
404+ if ( ! node . name ) {
405+ return ;
406+ }
407+
408+ const symbol = checker . getSymbolAtLocation ( node . name ) ;
409+ if ( ! symbol ) {
410+ return ;
411+ }
412+ const hookName = node . name . getText ( ) ;
413+
414+ const type = checker . getTypeOfSymbolAtLocation ( symbol , symbol . valueDeclaration ! ) ;
415+ const typeStack = new Set < number > ( [ ( type as any ) . id ] ) ;
416+
417+ const checkedSignatures = type . getCallSignatures ( ) . map ( ( signature ) => {
418+ return {
419+ parameters : signature . parameters . map ( ( param ) =>
420+ t . parameterNode ( checkSymbol ( param , typeStack ) ) ,
421+ ) ,
422+
423+ returnValue : checkType ( signature . getReturnType ( ) , typeStack , hookName ) ,
424+ } ;
425+ } ) ;
426+
427+ if ( checkedSignatures . length === 0 ) {
428+ return ;
429+ }
430+
431+ if ( checkedSignatures . length === 1 ) {
432+ programNode . body . push (
433+ t . hookNode (
434+ hookName ,
435+ checkedSignatures [ 0 ] . parameters ,
436+ checkedSignatures [ 0 ] . returnValue ,
437+ getDocumentationFromNode ( node ) ,
438+ node . getSourceFile ( ) . fileName ,
439+ ) ,
440+ ) ;
441+ }
442+
443+ // TODO: handle multiple call signatures
444+ }
445+
400446 function checkSymbol (
401447 symbol : ts . Symbol ,
402448 typeStack : Set < number > ,
@@ -642,7 +688,7 @@ export function parseFromProgram(
642688 return t . simpleTypeNode ( 'any' ) ;
643689 }
644690
645- function getDocumentationFromSymbol ( symbol ?: ts . Symbol ) : Documentation | undefined {
691+ function getDocumentationFromSymbol ( symbol ?: ts . Symbol ) : t . Documentation | undefined {
646692 if ( ! symbol ) {
647693 return undefined ;
648694 }
@@ -656,7 +702,7 @@ export function parseFromProgram(
656702 return comment ? { description : comment } : undefined ;
657703 }
658704
659- function getDocumentationFromNode ( node : ts . Node ) : Documentation | undefined {
705+ function getDocumentationFromNode ( node : ts . Node ) : t . Documentation | undefined {
660706 const comments = ts . getJSDocCommentsAndTags ( node ) ;
661707 if ( comments && comments . length === 1 ) {
662708 const commentNode = comments [ 0 ] ;
@@ -681,7 +727,7 @@ function hasFlag(typeFlags: number, flag: number) {
681727 return ( typeFlags & flag ) === flag ;
682728}
683729
684- function getVisibilityFromJSDoc ( doc : ts . JSDoc ) : Documentation [ 'visibility' ] | undefined {
730+ function getVisibilityFromJSDoc ( doc : ts . JSDoc ) : t . Documentation [ 'visibility' ] | undefined {
685731 if ( doc . tags ?. some ( ( tag ) => tag . tagName . text === 'public' ) ) {
686732 return 'public' ;
687733 }
0 commit comments