@@ -269,34 +269,35 @@ namespace ts.JsDoc {
269269 if ( ! commentOwnerInfo ) {
270270 return undefined ;
271271 }
272- const { commentOwner, parameters } = commentOwnerInfo ;
272+
273+ const { commentOwner, parameters, hasReturn } = commentOwnerInfo ;
273274 if ( commentOwner . getStart ( sourceFile ) < position ) {
274275 return undefined ;
275276 }
276277
277- if ( ! parameters || parameters . length === 0 ) {
278- // if there are no parameters, just complete to a single line JSDoc comment
279- const singleLineResult = "/** */" ;
280- return { newText : singleLineResult , caretOffset : 3 } ;
281- }
282-
283278 const indentationStr = getIndentationStringAtPosition ( sourceFile , position ) ;
279+ const isJavaScriptFile = hasJSFileExtension ( sourceFile . fileName ) ;
280+ const tags =
281+ ( parameters ? parameterDocComments ( parameters || [ ] , isJavaScriptFile , indentationStr , newLine ) : "" ) +
282+ ( hasReturn ? returnsDocComment ( indentationStr , newLine ) : "" ) ;
284283
285284 // A doc comment consists of the following
286285 // * The opening comment line
287286 // * the first line (without a param) for the object's untagged info (this is also where the caret ends up)
288287 // * the '@param'-tagged lines
288+ // * the '@returns'-tag
289289 // * TODO: other tags.
290290 // * the closing comment line
291291 // * if the caret was directly in front of the object, then we add an extra line and indentation.
292- const preamble = "/**" + newLine + indentationStr + " * " ;
293- const result =
294- preamble + newLine +
295- parameterDocComments ( parameters , hasJSFileExtension ( sourceFile . fileName ) , indentationStr , newLine ) +
296- indentationStr + " */" +
297- ( tokenStart === position ? newLine + indentationStr : "" ) ;
298-
299- return { newText : result , caretOffset : preamble . length } ;
292+ const openComment = "/**" ;
293+ const closeComment = " */" ;
294+ if ( tags ) {
295+ const preamble = openComment + newLine + indentationStr + " * " ;
296+ const endLine = tokenStart === position ? newLine + indentationStr : "" ;
297+ const result = preamble + newLine + tags + indentationStr + closeComment + endLine ;
298+ return { newText : result , caretOffset : preamble . length } ;
299+ }
300+ return { newText : openComment + closeComment , caretOffset : 3 } ;
300301 }
301302
302303 function getIndentationStringAtPosition ( sourceFile : SourceFile , position : number ) : string {
@@ -315,9 +316,14 @@ namespace ts.JsDoc {
315316 } ) . join ( "" ) ;
316317 }
317318
319+ function returnsDocComment ( indentationStr : string , newLine : string ) {
320+ return `${ indentationStr } * @returns${ newLine } ` ;
321+ }
322+
318323 interface CommentOwnerInfo {
319324 readonly commentOwner : Node ;
320325 readonly parameters ?: readonly ParameterDeclaration [ ] ;
326+ readonly hasReturn ?: boolean ;
321327 }
322328 function getCommentOwnerInfo ( tokenAtPos : Node ) : CommentOwnerInfo | undefined {
323329 return forEachAncestor ( tokenAtPos , getCommentOwnerInfoWorker ) ;
@@ -330,8 +336,8 @@ namespace ts.JsDoc {
330336 case SyntaxKind . Constructor :
331337 case SyntaxKind . MethodSignature :
332338 case SyntaxKind . ArrowFunction :
333- const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature ;
334- return { commentOwner, parameters } ;
339+ const host = commentOwner as ArrowFunction | FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature ;
340+ return { commentOwner, parameters : host . parameters , hasReturn : hasReturn ( host ) } ;
335341
336342 case SyntaxKind . PropertyAssignment :
337343 return getCommentOwnerInfoWorker ( ( commentOwner as PropertyAssignment ) . initializer ) ;
@@ -347,10 +353,12 @@ namespace ts.JsDoc {
347353 case SyntaxKind . VariableStatement : {
348354 const varStatement = < VariableStatement > commentOwner ;
349355 const varDeclarations = varStatement . declarationList . declarations ;
350- const parameters = varDeclarations . length === 1 && varDeclarations [ 0 ] . initializer
351- ? getParametersFromRightHandSideOfAssignment ( varDeclarations [ 0 ] . initializer )
356+ const host = varDeclarations . length === 1 && varDeclarations [ 0 ] . initializer
357+ ? getRightHandSideOfAssignment ( varDeclarations [ 0 ] . initializer )
352358 : undefined ;
353- return { commentOwner, parameters } ;
359+ return host
360+ ? { commentOwner, parameters : host . parameters , hasReturn : hasReturn ( host ) }
361+ : { commentOwner } ;
354362 }
355363
356364 case SyntaxKind . SourceFile :
@@ -369,40 +377,34 @@ namespace ts.JsDoc {
369377 if ( getAssignmentDeclarationKind ( be ) === AssignmentDeclarationKind . None ) {
370378 return "quit" ;
371379 }
372- const parameters = isFunctionLike ( be . right ) ? be . right . parameters : emptyArray ;
373- return { commentOwner, parameters } ;
380+ return isFunctionLike ( be . right )
381+ ? { commentOwner, parameters : be . right . parameters , hasReturn : hasReturn ( be . right ) }
382+ : { commentOwner } ;
374383 }
375384 case SyntaxKind . PropertyDeclaration :
376385 const init = ( commentOwner as PropertyDeclaration ) . initializer ;
377386 if ( init && ( isFunctionExpression ( init ) || isArrowFunction ( init ) ) ) {
378- return { commentOwner, parameters : init . parameters } ;
387+ return { commentOwner, parameters : init . parameters , hasReturn : hasReturn ( init ) } ;
379388 }
380389 }
381390 }
382391
383- /**
384- * Digs into an an initializer or RHS operand of an assignment operation
385- * to get the parameters of an apt signature corresponding to a
386- * function expression or a class expression.
387- *
388- * @param rightHandSide the expression which may contain an appropriate set of parameters
389- * @returns the parameters of a signature found on the RHS if one exists; otherwise 'emptyArray'.
390- */
391- function getParametersFromRightHandSideOfAssignment ( rightHandSide : Expression ) : readonly ParameterDeclaration [ ] {
392+ function hasReturn ( node : Node ) {
393+ return isArrowFunction ( node ) && isExpression ( node . body )
394+ || isFunctionLikeDeclaration ( node ) && node . body && isBlock ( node . body ) && ! ! forEachReturnStatement ( node . body , n => n ) ;
395+ }
396+
397+ function getRightHandSideOfAssignment ( rightHandSide : Expression ) : FunctionExpression | ArrowFunction | ConstructorDeclaration | undefined {
392398 while ( rightHandSide . kind === SyntaxKind . ParenthesizedExpression ) {
393399 rightHandSide = ( < ParenthesizedExpression > rightHandSide ) . expression ;
394400 }
395401
396402 switch ( rightHandSide . kind ) {
397403 case SyntaxKind . FunctionExpression :
398404 case SyntaxKind . ArrowFunction :
399- return ( < FunctionExpression > rightHandSide ) . parameters ;
400- case SyntaxKind . ClassExpression : {
401- const ctr = find ( ( rightHandSide as ClassExpression ) . members , isConstructorDeclaration ) ;
402- return ctr ? ctr . parameters : emptyArray ;
403- }
405+ return ( < FunctionExpression > rightHandSide ) ;
406+ case SyntaxKind . ClassExpression :
407+ return find ( ( rightHandSide as ClassExpression ) . members , isConstructorDeclaration ) ;
404408 }
405-
406- return emptyArray ;
407409 }
408410}
0 commit comments