From 7b7e62ce72ec1d5116a40c430e71754a131a8380 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 25 Sep 2015 16:27:58 -0700 Subject: [PATCH 1/3] Modified/added tests. --- .../docCommentTemplateVariableStatements01.ts | 36 +++++--- .../docCommentTemplateVariableStatements03.ts | 90 +++++++++++++++++++ 2 files changed, 116 insertions(+), 10 deletions(-) create mode 100644 tests/cases/fourslash/docCommentTemplateVariableStatements03.ts diff --git a/tests/cases/fourslash/docCommentTemplateVariableStatements01.ts b/tests/cases/fourslash/docCommentTemplateVariableStatements01.ts index 6859d9aa1ec..b901919fa1f 100644 --- a/tests/cases/fourslash/docCommentTemplateVariableStatements01.ts +++ b/tests/cases/fourslash/docCommentTemplateVariableStatements01.ts @@ -28,27 +28,43 @@ function confirmNormalizedJsDoc(markerName: string, newTextOffset: number, templ ////const c = 30; //// /////*d*/ -////let d = function d(x, y, z) { -//// return +(x + y + z); +////let d = { +//// foo: 10, +//// bar: "20" ////}; //// /////*e*/ -////let e = class E { +////let e = function e(x, y, z) { +//// return +(x + y + z); +////}; +//// +/////*f*/ +////let f = class F { //// constructor(a, b, c) { //// this.a = a; //// this.b = b || (this.c = c); //// } ////} -//// -/////*f*/ -////let f = { -//// foo: 10, -//// bar: "20" -////}; -for (const varName of "abcdef".split("")) { +for (const varName of "abcd".split("")) { confirmNormalizedJsDoc(varName, /*newTextOffset*/ 8, ` /** * */`); } + +confirmNormalizedJsDoc("e", /*newTextOffset*/ 8, ` +/** + * + * @param x + * @param y + * @param z + */`); + +confirmNormalizedJsDoc("f", /*newTextOffset*/ 8, ` +/** + * + * @param a + * @param b + * @param c + */`); \ No newline at end of file diff --git a/tests/cases/fourslash/docCommentTemplateVariableStatements03.ts b/tests/cases/fourslash/docCommentTemplateVariableStatements03.ts new file mode 100644 index 00000000000..e473cb798b7 --- /dev/null +++ b/tests/cases/fourslash/docCommentTemplateVariableStatements03.ts @@ -0,0 +1,90 @@ +/// + +const CRLF = "\r\n"; +/** + * @returns the given value with '\n' normalized to '\r\n' and with no leading newline + */ +function useCRLFAndStripLeadingNewline(str: string): string { + str = str.replace(/\r?\n/g, CRLF); + if (str.indexOf(CRLF) === 0) { + str = str.slice(CRLF.length); + } + return str; +} + +function confirmNormalizedJsDoc(markerName: string, newTextOffset: number, template: string): void { + goTo.marker(markerName); + const normalized = useCRLFAndStripLeadingNewline(template); + verify.DocCommentTemplate(normalized, newTextOffset); +} + +/////*a*/ +////var a = x => x +//// +/////*b*/ +////let b = (x,y,z) => x + y + z; +//// +/////*c*/ +////const c = ((x => +x)) +//// +/////*d*/ +////let d = (function () { }) +//// +/////*e*/ +////let e = function e([a,b,c]) { +//// return "hello" +////}; +//// +/////*f*/ +////let f = class { +////} +//// +/////*g*/ +////const g = ((class G { +//// constructor(private x); +//// constructor(x,y,z); +//// constructor(x,y,z, ...okayThatsEnough) { +//// } +////})) + +confirmNormalizedJsDoc("a", /*newTextOffset*/ 8, ` +/** + * + * @param x + */`); + +confirmNormalizedJsDoc("b", /*newTextOffset*/ 8, ` +/** + * + * @param x + * @param y + * @param z + */`); + +confirmNormalizedJsDoc("c", /*newTextOffset*/ 8, ` +/** + * + * @param x + */`); + +confirmNormalizedJsDoc("d", /*newTextOffset*/ 8, ` +/** + * + */`); + +confirmNormalizedJsDoc("e", /*newTextOffset*/ 8, ` +/** + * + * @param param0 + */`); + +confirmNormalizedJsDoc("f", /*newTextOffset*/ 8, ` +/** + * + */`); + +confirmNormalizedJsDoc("g", /*newTextOffset*/ 8, ` +/** + * + * @param x + */`); \ No newline at end of file From 6bfc28f88399552e63f5df190de9191b4df1f71a Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 25 Sep 2015 16:30:26 -0700 Subject: [PATCH 2/3] Try to grab parameters for single-declaration variable statements. We only do this for a (parenthesized) function expression, arrow function, or class expression with a constructor. In the presence of a class expression, if there are multiple constructor declarations, the parameters are acquired from the first one. --- src/services/services.ts | 48 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/services/services.ts b/src/services/services.ts index 4326e57f93e..13f7d4c15e0 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -7059,7 +7059,7 @@ namespace ts { return undefined; } - let parameters = isFunctionLike(commentOwner) ? commentOwner.parameters : emptyArray; + let parameters = getParametersForJsDocOwningNode(commentOwner); let posLineAndChar = sourceFile.getLineAndCharacterOfPosition(position); let lineStart = sourceFile.getLineStarts()[posLineAndChar.line]; @@ -7096,6 +7096,52 @@ namespace ts { return { newText: result, caretOffset: preamble.length }; } + function getParametersForJsDocOwningNode(commentOwner: Node): ParameterDeclaration[] { + if (isFunctionLike(commentOwner)) { + return commentOwner.parameters; + } + + if (commentOwner.kind === SyntaxKind.VariableStatement) { + const varStatement = commentOwner; + const varDeclarations = varStatement.declarationList.declarations; + + if (varDeclarations.length === 1 && varDeclarations[0].initializer) { + return getParametersFromRightHandSideOfAssignment(varDeclarations[0].initializer); + } + } + + return emptyArray; + } + + /** + * Digs into an an initializer or RHS operand of an assignment operation + * to get the parameters from an apst 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): ParameterDeclaration[] { + while (rightHandSide.kind === SyntaxKind.ParenthesizedExpression) { + rightHandSide = (rightHandSide).expression; + } + + switch (rightHandSide.kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + return (rightHandSide).parameters; + case SyntaxKind.ClassExpression: + for (let member of (rightHandSide).members) { + if (member.kind === SyntaxKind.Constructor) { + return (member).parameters; + } + } + break; + } + + return emptyArray; + } + function getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[] { // Note: while getting todo comments seems like a syntactic operation, we actually // treat it as a semantic operation here. This is because we expect our host to call From 2692cde71209c3a8e8867af96abec6a0d30ae6e5 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 25 Sep 2015 17:10:58 -0700 Subject: [PATCH 3/3] :%s/apst/apt --- src/services/services.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/services.ts b/src/services/services.ts index 13f7d4c15e0..2bbf286a1f2 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -7115,7 +7115,7 @@ namespace ts { /** * Digs into an an initializer or RHS operand of an assignment operation - * to get the parameters from an apst signature corresponding to a + * 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