feat(14248): add returns tag to JSDoc template (#42068)

This commit is contained in:
Oleksandr T 2021-01-08 03:57:23 +02:00 committed by GitHub
parent 0d284e6c26
commit 042bf4eb15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 116 additions and 46 deletions

View File

@ -269,34 +269,35 @@ namespace ts.JsDoc {
if (!commentOwnerInfo) {
return undefined;
}
const { commentOwner, parameters } = commentOwnerInfo;
const { commentOwner, parameters, hasReturn } = commentOwnerInfo;
if (commentOwner.getStart(sourceFile) < position) {
return undefined;
}
if (!parameters || parameters.length === 0) {
// if there are no parameters, just complete to a single line JSDoc comment
const singleLineResult = "/** */";
return { newText: singleLineResult, caretOffset: 3 };
}
const indentationStr = getIndentationStringAtPosition(sourceFile, position);
const isJavaScriptFile = hasJSFileExtension(sourceFile.fileName);
const tags =
(parameters ? parameterDocComments(parameters || [], isJavaScriptFile, indentationStr, newLine) : "") +
(hasReturn ? returnsDocComment(indentationStr, newLine) : "");
// A doc comment consists of the following
// * The opening comment line
// * the first line (without a param) for the object's untagged info (this is also where the caret ends up)
// * the '@param'-tagged lines
// * the '@returns'-tag
// * TODO: other tags.
// * the closing comment line
// * if the caret was directly in front of the object, then we add an extra line and indentation.
const preamble = "/**" + newLine + indentationStr + " * ";
const result =
preamble + newLine +
parameterDocComments(parameters, hasJSFileExtension(sourceFile.fileName), indentationStr, newLine) +
indentationStr + " */" +
(tokenStart === position ? newLine + indentationStr : "");
return { newText: result, caretOffset: preamble.length };
const openComment = "/**";
const closeComment = " */";
if (tags) {
const preamble = openComment + newLine + indentationStr + " * ";
const endLine = tokenStart === position ? newLine + indentationStr : "";
const result = preamble + newLine + tags + indentationStr + closeComment + endLine;
return { newText: result, caretOffset: preamble.length };
}
return { newText: openComment + closeComment, caretOffset: 3 };
}
function getIndentationStringAtPosition(sourceFile: SourceFile, position: number): string {
@ -315,9 +316,14 @@ namespace ts.JsDoc {
}).join("");
}
function returnsDocComment(indentationStr: string, newLine: string) {
return `${indentationStr} * @returns${newLine}`;
}
interface CommentOwnerInfo {
readonly commentOwner: Node;
readonly parameters?: readonly ParameterDeclaration[];
readonly hasReturn?: boolean;
}
function getCommentOwnerInfo(tokenAtPos: Node): CommentOwnerInfo | undefined {
return forEachAncestor(tokenAtPos, getCommentOwnerInfoWorker);
@ -330,8 +336,8 @@ namespace ts.JsDoc {
case SyntaxKind.Constructor:
case SyntaxKind.MethodSignature:
case SyntaxKind.ArrowFunction:
const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature;
return { commentOwner, parameters };
const host = commentOwner as ArrowFunction | FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature;
return { commentOwner, parameters: host.parameters, hasReturn: hasReturn(host) };
case SyntaxKind.PropertyAssignment:
return getCommentOwnerInfoWorker((commentOwner as PropertyAssignment).initializer);
@ -347,10 +353,12 @@ namespace ts.JsDoc {
case SyntaxKind.VariableStatement: {
const varStatement = <VariableStatement>commentOwner;
const varDeclarations = varStatement.declarationList.declarations;
const parameters = varDeclarations.length === 1 && varDeclarations[0].initializer
? getParametersFromRightHandSideOfAssignment(varDeclarations[0].initializer)
const host = varDeclarations.length === 1 && varDeclarations[0].initializer
? getRightHandSideOfAssignment(varDeclarations[0].initializer)
: undefined;
return { commentOwner, parameters };
return host
? { commentOwner, parameters: host.parameters, hasReturn: hasReturn(host) }
: { commentOwner };
}
case SyntaxKind.SourceFile:
@ -369,26 +377,24 @@ namespace ts.JsDoc {
if (getAssignmentDeclarationKind(be) === AssignmentDeclarationKind.None) {
return "quit";
}
const parameters = isFunctionLike(be.right) ? be.right.parameters : emptyArray;
return { commentOwner, parameters };
return isFunctionLike(be.right)
? { commentOwner, parameters: be.right.parameters, hasReturn: hasReturn(be.right) }
: { commentOwner };
}
case SyntaxKind.PropertyDeclaration:
const init = (commentOwner as PropertyDeclaration).initializer;
if (init && (isFunctionExpression(init) || isArrowFunction(init))) {
return { commentOwner, parameters: init.parameters };
return { commentOwner, parameters: init.parameters, hasReturn: hasReturn(init) };
}
}
}
/**
* Digs into an an initializer or RHS operand of an assignment operation
* to get the parameters of an apt signature corresponding to a
* function expression or a class expression.
*
* @param rightHandSide the expression which may contain an appropriate set of parameters
* @returns the parameters of a signature found on the RHS if one exists; otherwise 'emptyArray'.
*/
function getParametersFromRightHandSideOfAssignment(rightHandSide: Expression): readonly ParameterDeclaration[] {
function hasReturn(node: Node) {
return isArrowFunction(node) && isExpression(node.body)
|| isFunctionLikeDeclaration(node) && node.body && isBlock(node.body) && !!forEachReturnStatement(node.body, n => n);
}
function getRightHandSideOfAssignment(rightHandSide: Expression): FunctionExpression | ArrowFunction | ConstructorDeclaration | undefined {
while (rightHandSide.kind === SyntaxKind.ParenthesizedExpression) {
rightHandSide = (<ParenthesizedExpression>rightHandSide).expression;
}
@ -396,13 +402,9 @@ namespace ts.JsDoc {
switch (rightHandSide.kind) {
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
return (<FunctionExpression>rightHandSide).parameters;
case SyntaxKind.ClassExpression: {
const ctr = find((rightHandSide as ClassExpression).members, isConstructorDeclaration);
return ctr ? ctr.parameters : emptyArray;
}
return (<FunctionExpression>rightHandSide);
case SyntaxKind.ClassExpression:
return find((rightHandSide as ClassExpression).members, isConstructorDeclaration);
}
return emptyArray;
}
}

View File

@ -1,6 +1,5 @@
/// <reference path='fourslash.ts' />
const singleLineOffset = 3;
const multiLineOffset = 12;
////class C {
@ -12,8 +11,11 @@ const multiLineOffset = 12;
//// [1 + 2 + 3 + Math.rand()](x: number, y: string, z = true) { }
////}
verify.docCommentTemplateAt("0", singleLineOffset,
"/** */");
verify.docCommentTemplateAt("0", multiLineOffset,
`/**
*
* @returns
*/`);
verify.docCommentTemplateAt("1", multiLineOffset,
`/**

View File

@ -23,17 +23,18 @@ verify.docCommentTemplateAt("0", multiLineOffset,
`/**
*
* @param p0
* @returns
*/`);
verify.docCommentTemplateAt("1", multiLineOffset,
`/**
*
* @param p1
* @returns
*/`);
verify.docCommentTemplateAt("2", multiLineOffset,
`/**
*
* @param p2
* @param p3
* @returns
*/`);

View File

@ -1,6 +1,5 @@
/// <reference path='fourslash.ts' />
const singleLineOffset = 3;
const multiLineOffset = 12;
////var x = {
@ -19,7 +18,11 @@ const multiLineOffset = 12;
//// m2: (a: string, b: string) => {}
////}
verify.docCommentTemplateAt("0", singleLineOffset, "/** */");
verify.docCommentTemplateAt("0", multiLineOffset,
`/**
*
* @returns
*/`);
verify.docCommentTemplateAt("1", multiLineOffset,
`/**

View File

@ -0,0 +1,56 @@
/// <reference path='fourslash.ts' />
/////*0*/
////function f1() {}
/////*1*/
////function f2() {
//// return 1;
////}
/////*2*/
////const f3 = () => 1;
/////*3*/
////const f3 = () => {
//// return 1;
////}
////class Foo {
//// /*4*/
//// m1() {}
////
//// /*5*/
//// m2() {
//// return 1;
//// }
////}
verify.docCommentTemplateAt("0", 3, "/** */");
verify.docCommentTemplateAt("1", 8,
`/**
*
* @returns
*/`);
verify.docCommentTemplateAt("2", 8,
`/**
*
* @returns
*/`);
verify.docCommentTemplateAt("3", 8,
`/**
*
* @returns
*/`);
verify.docCommentTemplateAt("4", 3, "/** */");
verify.docCommentTemplateAt("5", 12,
`/**
*
* @returns
*/`);

View File

@ -39,6 +39,7 @@ verify.docCommentTemplateAt("e", /*newTextOffset*/ 8,
* @param x
* @param y
* @param z
* @returns
*/`);
verify.docCommentTemplateAt("f", /*newTextOffset*/ 8,

View File

@ -33,6 +33,7 @@ verify.docCommentTemplateAt("a", /*newTextOffset*/ 8,
`/**
*
* @param x
* @returns
*/`);
verify.docCommentTemplateAt("b", /*newTextOffset*/ 8,
@ -41,12 +42,14 @@ verify.docCommentTemplateAt("b", /*newTextOffset*/ 8,
* @param x
* @param y
* @param z
* @returns
*/`);
verify.docCommentTemplateAt("c", /*newTextOffset*/ 8,
`/**
*
* @param x
* @returns
*/`);
verify.docCommentTemplateAt("d", /*newTextOffset*/ 3,
@ -56,6 +59,7 @@ verify.docCommentTemplateAt("e", /*newTextOffset*/ 8,
`/**
*
* @param param0
* @returns
*/`);
verify.docCommentTemplateAt("f", /*newTextOffset*/ 3,

View File

@ -10,6 +10,7 @@ verify.docCommentTemplateAt("", /*newTextOffset*/ 8,
`/**
*
* @param p
* @returns
*/`);
verify.noDocCommentTemplateAt("1");