@@ -35,16 +35,16 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
3535 if ( decl && ! decl . type ) {
3636 const annotate = getJSDocType ( decl ) ? annotateTypeFromJSDoc :
3737 getJSDocReturnType ( decl ) ? annotateReturnTypeFromJSDoc :
38- undefined ;
38+ undefined ;
3939 if ( annotate ) {
4040 return [ {
4141 name : annotate . name ,
4242 description : annotate . description ,
4343 actions : [
4444 {
45- description : annotate . description ,
46- name : actionName
47- }
45+ description : annotate . description ,
46+ name : actionName
47+ }
4848 ]
4949 } ] ;
5050 }
@@ -62,10 +62,9 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
6262 const sourceFile = context . file ;
6363 const token = getTokenAtPosition ( sourceFile , start , /*includeJsDocComment*/ false ) ;
6464 const decl = findAncestor ( token , isTypedNode ) ;
65- const jsdocType = getJSDocType ( decl ) ;
66- const jsdocReturn = getJSDocReturnType ( decl ) ;
67- if ( ! decl || ! jsdocType && ! jsdocReturn || decl . type ) {
68- Debug . fail ( `!decl || !jsdocType && !jsdocReturn || decl.type: !${ decl } || !${ jsdocType } && !{jsdocReturn} || ${ decl . type } ` ) ;
65+ const jsdocType = getJSDocReturnType ( decl ) || getJSDocType ( decl ) ;
66+ if ( ! decl || ! jsdocType || decl . type ) {
67+ Debug . fail ( `!decl || !jsdocType || decl.type: !${ decl } || !${ jsdocType } || ${ decl . type } ` ) ;
6968 return undefined ;
7069 }
7170
@@ -76,12 +75,12 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
7675 // other syntax changes
7776 const arrow = decl . parent as ArrowFunction ;
7877 const param = decl as ParameterDeclaration ;
79- const replacementParam = createParameter ( param . decorators , param . modifiers , param . dotDotDotToken , param . name , param . questionToken , jsdocType , param . initializer ) ;
78+ const replacementParam = createParameter ( param . decorators , param . modifiers , param . dotDotDotToken , param . name , param . questionToken , transformJSDocType ( jsdocType ) as TypeNode , param . initializer ) ;
8079 const replacement = createArrowFunction ( arrow . modifiers , arrow . typeParameters , [ replacementParam ] , arrow . type , arrow . equalsGreaterThanToken , arrow . body ) ;
8180 changeTracker . replaceRange ( sourceFile , { pos : arrow . getStart ( ) , end : arrow . end } , replacement ) ;
8281 }
8382 else {
84- changeTracker . replaceRange ( sourceFile , { pos : decl . getStart ( ) , end : decl . end } , replaceType ( decl , jsdocType , jsdocReturn ) ) ;
83+ changeTracker . replaceRange ( sourceFile , { pos : decl . getStart ( ) , end : decl . end } , replaceType ( decl , transformJSDocType ( jsdocType ) as TypeNode ) ) ;
8584 }
8685 return {
8786 edits : changeTracker . getChanges ( ) ,
@@ -98,7 +97,7 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
9897 node . kind === SyntaxKind . PropertyDeclaration ;
9998 }
10099
101- function replaceType ( decl : DeclarationWithType , jsdocType : TypeNode , jsdocReturn : TypeNode ) {
100+ function replaceType ( decl : DeclarationWithType , jsdocType : TypeNode ) {
102101 switch ( decl . kind ) {
103102 case SyntaxKind . VariableDeclaration :
104103 return createVariableDeclaration ( decl . name , jsdocType , decl . initializer ) ;
@@ -109,15 +108,15 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
109108 case SyntaxKind . PropertyDeclaration :
110109 return createProperty ( decl . decorators , decl . modifiers , decl . name , decl . questionToken , jsdocType , decl . initializer ) ;
111110 case SyntaxKind . FunctionDeclaration :
112- return createFunctionDeclaration ( decl . decorators , decl . modifiers , decl . asteriskToken , decl . name , decl . typeParameters , decl . parameters , jsdocReturn , decl . body ) ;
111+ return createFunctionDeclaration ( decl . decorators , decl . modifiers , decl . asteriskToken , decl . name , decl . typeParameters , decl . parameters , jsdocType , decl . body ) ;
113112 case SyntaxKind . FunctionExpression :
114- return createFunctionExpression ( decl . modifiers , decl . asteriskToken , decl . name , decl . typeParameters , decl . parameters , jsdocReturn , decl . body ) ;
113+ return createFunctionExpression ( decl . modifiers , decl . asteriskToken , decl . name , decl . typeParameters , decl . parameters , jsdocType , decl . body ) ;
115114 case SyntaxKind . ArrowFunction :
116- return createArrowFunction ( decl . modifiers , decl . typeParameters , decl . parameters , jsdocReturn , decl . equalsGreaterThanToken , decl . body ) ;
115+ return createArrowFunction ( decl . modifiers , decl . typeParameters , decl . parameters , jsdocType , decl . equalsGreaterThanToken , decl . body ) ;
117116 case SyntaxKind . MethodDeclaration :
118- return createMethod ( decl . decorators , decl . modifiers , decl . asteriskToken , decl . name , decl . questionToken , decl . typeParameters , decl . parameters , jsdocReturn , decl . body ) ;
117+ return createMethod ( decl . decorators , decl . modifiers , decl . asteriskToken , decl . name , decl . questionToken , decl . typeParameters , decl . parameters , jsdocType , decl . body ) ;
119118 case SyntaxKind . GetAccessor :
120- return createGetAccessor ( decl . decorators , decl . modifiers , decl . name , decl . parameters , jsdocReturn , decl . body ) ;
119+ return createGetAccessor ( decl . decorators , decl . modifiers , decl . name , decl . parameters , jsdocType , decl . body ) ;
121120 default :
122121 Debug . fail ( `Unexpected SyntaxKind: ${ decl . kind } ` ) ;
123122 return undefined ;
@@ -144,4 +143,82 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
144143 && ! parameter . initializer // parameter may not have an initializer
145144 && isIdentifier ( parameter . name ) ; // parameter name must be identifier
146145 }
146+
147+ function transformJSDocType ( node : Node ) : Node | undefined {
148+ if ( node === undefined ) {
149+ return undefined ;
150+ }
151+ switch ( node . kind ) {
152+ case SyntaxKind . JSDocAllType :
153+ case SyntaxKind . JSDocUnknownType :
154+ return createTypeReferenceNode ( "any" , emptyArray ) ;
155+ case SyntaxKind . JSDocOptionalType :
156+ return visitJSDocOptionalType ( node as JSDocOptionalType ) ;
157+ case SyntaxKind . JSDocNonNullableType :
158+ return transformJSDocType ( ( node as JSDocNonNullableType ) . type ) ;
159+ case SyntaxKind . JSDocNullableType :
160+ return visitJSDocNullableType ( node as JSDocNullableType ) ;
161+ case SyntaxKind . JSDocVariadicType :
162+ return visitJSDocVariadicType ( node as JSDocVariadicType ) ;
163+ case SyntaxKind . JSDocFunctionType :
164+ return visitJSDocFunctionType ( node as JSDocFunctionType ) ;
165+ case SyntaxKind . Parameter :
166+ return visitJSDocParameter ( node as ParameterDeclaration ) ;
167+ case SyntaxKind . TypeReference :
168+ return visitJSDocTypeReference ( node as TypeReferenceNode ) ;
169+ default :
170+ return visitEachChild ( node , transformJSDocType , /*context*/ undefined ) as TypeNode ;
171+ }
172+ }
173+
174+ function visitJSDocOptionalType ( node : JSDocOptionalType ) {
175+ return createUnionTypeNode ( [ visitNode ( node . type , transformJSDocType ) , createTypeReferenceNode ( "undefined" , emptyArray ) ] ) ;
176+ }
177+
178+ function visitJSDocNullableType ( node : JSDocNullableType ) {
179+ return createUnionTypeNode ( [ visitNode ( node . type , transformJSDocType ) , createTypeReferenceNode ( "null" , emptyArray ) ] ) ;
180+ }
181+
182+ function visitJSDocVariadicType ( node : JSDocVariadicType ) {
183+ return createArrayTypeNode ( visitNode ( node . type , transformJSDocType ) ) ;
184+ }
185+
186+ function visitJSDocFunctionType ( node : JSDocFunctionType ) {
187+ const parameters = node . parameters && node . parameters . map ( transformJSDocType ) ;
188+ return createFunctionTypeNode ( emptyArray , parameters as ParameterDeclaration [ ] , node . type ) ;
189+ }
190+
191+ function visitJSDocParameter ( node : ParameterDeclaration ) {
192+ const name = node . name || "arg" + node . parent . parameters . indexOf ( node ) ;
193+ return createParameter ( node . decorators , node . modifiers , node . dotDotDotToken , name , node . questionToken , node . type , node . initializer ) ;
194+ }
195+
196+ function visitJSDocTypeReference ( node : TypeReferenceNode ) {
197+ let name = node . typeName ;
198+ let args = node . typeArguments ;
199+ if ( isIdentifier ( node . typeName ) ) {
200+ let text = node . typeName . text ;
201+ switch ( node . typeName . text ) {
202+ case "String" :
203+ case "Boolean" :
204+ case "Object" :
205+ case "Number" :
206+ text = text . toLowerCase ( ) ;
207+ break ;
208+ case "array" :
209+ case "date" :
210+ case "promise" :
211+ text = text [ 0 ] . toUpperCase ( ) + text . slice ( 1 ) ;
212+ break ;
213+ }
214+ name = createIdentifier ( text ) ;
215+ if ( ( text === "Array" || text === "Promise" ) && ! node . typeArguments ) {
216+ args = createNodeArray ( [ createTypeReferenceNode ( "any" , emptyArray ) ] ) ;
217+ }
218+ else {
219+ args = visitNodes ( node . typeArguments , transformJSDocType ) ;
220+ }
221+ }
222+ return createTypeReferenceNode ( name , args ) ;
223+ }
147224}
0 commit comments