@@ -269,34 +269,35 @@ namespace ts.JsDoc {
269
269
if ( ! commentOwnerInfo ) {
270
270
return undefined ;
271
271
}
272
- const { commentOwner, parameters } = commentOwnerInfo ;
272
+
273
+ const { commentOwner, parameters, hasReturn } = commentOwnerInfo ;
273
274
if ( commentOwner . getStart ( sourceFile ) < position ) {
274
275
return undefined ;
275
276
}
276
277
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
-
283
278
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 ) : "" ) ;
284
283
285
284
// A doc comment consists of the following
286
285
// * The opening comment line
287
286
// * the first line (without a param) for the object's untagged info (this is also where the caret ends up)
288
287
// * the '@param'-tagged lines
288
+ // * the '@returns'-tag
289
289
// * TODO: other tags.
290
290
// * the closing comment line
291
291
// * 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 } ;
300
301
}
301
302
302
303
function getIndentationStringAtPosition ( sourceFile : SourceFile , position : number ) : string {
@@ -315,9 +316,14 @@ namespace ts.JsDoc {
315
316
} ) . join ( "" ) ;
316
317
}
317
318
319
+ function returnsDocComment ( indentationStr : string , newLine : string ) {
320
+ return `${ indentationStr } * @returns${ newLine } ` ;
321
+ }
322
+
318
323
interface CommentOwnerInfo {
319
324
readonly commentOwner : Node ;
320
325
readonly parameters ?: readonly ParameterDeclaration [ ] ;
326
+ readonly hasReturn ?: boolean ;
321
327
}
322
328
function getCommentOwnerInfo ( tokenAtPos : Node ) : CommentOwnerInfo | undefined {
323
329
return forEachAncestor ( tokenAtPos , getCommentOwnerInfoWorker ) ;
@@ -330,8 +336,8 @@ namespace ts.JsDoc {
330
336
case SyntaxKind . Constructor :
331
337
case SyntaxKind . MethodSignature :
332
338
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 ) } ;
335
341
336
342
case SyntaxKind . PropertyAssignment :
337
343
return getCommentOwnerInfoWorker ( ( commentOwner as PropertyAssignment ) . initializer ) ;
@@ -347,10 +353,12 @@ namespace ts.JsDoc {
347
353
case SyntaxKind . VariableStatement : {
348
354
const varStatement = < VariableStatement > commentOwner ;
349
355
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 )
352
358
: undefined ;
353
- return { commentOwner, parameters } ;
359
+ return host
360
+ ? { commentOwner, parameters : host . parameters , hasReturn : hasReturn ( host ) }
361
+ : { commentOwner } ;
354
362
}
355
363
356
364
case SyntaxKind . SourceFile :
@@ -369,40 +377,34 @@ namespace ts.JsDoc {
369
377
if ( getAssignmentDeclarationKind ( be ) === AssignmentDeclarationKind . None ) {
370
378
return "quit" ;
371
379
}
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 } ;
374
383
}
375
384
case SyntaxKind . PropertyDeclaration :
376
385
const init = ( commentOwner as PropertyDeclaration ) . initializer ;
377
386
if ( init && ( isFunctionExpression ( init ) || isArrowFunction ( init ) ) ) {
378
- return { commentOwner, parameters : init . parameters } ;
387
+ return { commentOwner, parameters : init . parameters , hasReturn : hasReturn ( init ) } ;
379
388
}
380
389
}
381
390
}
382
391
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 {
392
398
while ( rightHandSide . kind === SyntaxKind . ParenthesizedExpression ) {
393
399
rightHandSide = ( < ParenthesizedExpression > rightHandSide ) . expression ;
394
400
}
395
401
396
402
switch ( rightHandSide . kind ) {
397
403
case SyntaxKind . FunctionExpression :
398
404
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 ) ;
404
408
}
405
-
406
- return emptyArray ;
407
409
}
408
410
}
0 commit comments