Skip to content

Commit 179d423

Browse files
committed
Merge pull request microsoft#9010 from Microsoft/merge-jsdoc-of-assignment-and-function-expression
Merge JSDoc of assignments from function expressions
2 parents 404650d + 1fe6626 commit 179d423

6 files changed

Lines changed: 190 additions & 149 deletions

File tree

src/compiler/utilities.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -603,9 +603,11 @@ namespace ts {
603603
}
604604

605605
export function getJsDocCommentsFromText(node: Node, text: string) {
606-
const commentRanges = (node.kind === SyntaxKind.Parameter || node.kind === SyntaxKind.TypeParameter) ?
607-
concatenate(getTrailingCommentRanges(text, node.pos),
608-
getLeadingCommentRanges(text, node.pos)) :
606+
const commentRanges = (node.kind === SyntaxKind.Parameter ||
607+
node.kind === SyntaxKind.TypeParameter ||
608+
node.kind === SyntaxKind.FunctionExpression ||
609+
node.kind === SyntaxKind.ArrowFunction) ?
610+
concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) :
609611
getLeadingCommentRangesOfNodeFromText(node, text);
610612
return filter(commentRanges, isJsDocComment);
611613

src/services/services.ts

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -406,37 +406,56 @@ namespace ts {
406406
const sourceFileOfDeclaration = getSourceFileOfNode(declaration);
407407
// If it is parameter - try and get the jsDoc comment with @param tag from function declaration's jsDoc comments
408408
if (canUseParsedParamTagComments && declaration.kind === SyntaxKind.Parameter) {
409-
ts.forEach(getJsDocCommentTextRange(declaration.parent, sourceFileOfDeclaration), jsDocCommentTextRange => {
410-
const cleanedParamJsDocComment = getCleanedParamJsDocComment(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration);
411-
if (cleanedParamJsDocComment) {
412-
addRange(jsDocCommentParts, cleanedParamJsDocComment);
413-
}
414-
});
409+
if ((declaration.parent.kind === SyntaxKind.FunctionExpression || declaration.parent.kind === SyntaxKind.ArrowFunction) &&
410+
declaration.parent.parent.kind === SyntaxKind.VariableDeclaration) {
411+
addCommentParts(declaration.parent.parent.parent, sourceFileOfDeclaration, getCleanedParamJsDocComment);
412+
}
413+
addCommentParts(declaration.parent, sourceFileOfDeclaration, getCleanedParamJsDocComment);
415414
}
416415

417416
// If this is left side of dotted module declaration, there is no doc comments associated with this node
418417
if (declaration.kind === SyntaxKind.ModuleDeclaration && (<ModuleDeclaration>declaration).body.kind === SyntaxKind.ModuleDeclaration) {
419418
return;
420419
}
421420

421+
if ((declaration.kind === SyntaxKind.FunctionExpression || declaration.kind === SyntaxKind.ArrowFunction) &&
422+
declaration.parent.kind === SyntaxKind.VariableDeclaration) {
423+
addCommentParts(declaration.parent.parent, sourceFileOfDeclaration, getCleanedJsDocComment);
424+
}
425+
422426
// If this is dotted module name, get the doc comments from the parent
423427
while (declaration.kind === SyntaxKind.ModuleDeclaration && declaration.parent.kind === SyntaxKind.ModuleDeclaration) {
424428
declaration = <ModuleDeclaration>declaration.parent;
425429
}
430+
addCommentParts(declaration.kind === SyntaxKind.VariableDeclaration ? declaration.parent.parent : declaration,
431+
sourceFileOfDeclaration,
432+
getCleanedJsDocComment);
426433

427-
// Get the cleaned js doc comment text from the declaration
428-
ts.forEach(getJsDocCommentTextRange(
429-
declaration.kind === SyntaxKind.VariableDeclaration ? declaration.parent.parent : declaration, sourceFileOfDeclaration), jsDocCommentTextRange => {
430-
const cleanedJsDocComment = getCleanedJsDocComment(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration);
431-
if (cleanedJsDocComment) {
432-
addRange(jsDocCommentParts, cleanedJsDocComment);
433-
}
434-
});
434+
if (declaration.kind === SyntaxKind.VariableDeclaration) {
435+
const init = (declaration as VariableDeclaration).initializer;
436+
if (init && (init.kind === SyntaxKind.FunctionExpression || init.kind === SyntaxKind.ArrowFunction)) {
437+
// Get the cleaned js doc comment text from the initializer
438+
addCommentParts(init, sourceFileOfDeclaration, getCleanedJsDocComment);
439+
}
440+
}
435441
}
436442
});
437443

438444
return jsDocCommentParts;
439445

446+
function addCommentParts(commented: Node,
447+
sourceFileOfDeclaration: SourceFile,
448+
getCommentPart: (pos: number, end: number, file: SourceFile) => SymbolDisplayPart[]): void {
449+
const ranges = getJsDocCommentTextRange(commented, sourceFileOfDeclaration);
450+
// Get the cleaned js doc comment text from the declaration
451+
ts.forEach(ranges, jsDocCommentTextRange => {
452+
const cleanedComment = getCommentPart(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration);
453+
if (cleanedComment) {
454+
addRange(jsDocCommentParts, cleanedComment);
455+
}
456+
});
457+
}
458+
440459
function getJsDocCommentTextRange(node: Node, sourceFile: SourceFile): TextRange[] {
441460
return ts.map(getJsDocComments(node, sourceFile),
442461
jsDocComment => {

tests/cases/fourslash/commentsFunction.ts

Lines changed: 0 additions & 131 deletions
This file was deleted.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
/////** This comment should appear for foo*/
4+
////function f/*1*/oo() {
5+
////}
6+
////f/*2*/oo/*3*/(/*4*/);
7+
/////** This is comment for function signature*/
8+
////function fo/*5*/oWithParameters(/** this is comment about a*/a: string,
9+
//// /** this is comment for b*/
10+
//// b: number) {
11+
//// var /*6*/d = /*7*/a;
12+
////}
13+
////fooWithParam/*8*/eters/*9*/(/*10*/"a",/*11*/10);
14+
15+
// ambient declaration
16+
/////**
17+
////* Does something
18+
////* @param a a string
19+
////*/
20+
////declare function fn(a: string);
21+
////fn(/*12*/"hello");
22+
23+
goTo.marker('1');
24+
verify.quickInfoIs("function foo(): void", "This comment should appear for foo");
25+
26+
goTo.marker('2');
27+
verify.quickInfoIs("function foo(): void", "This comment should appear for foo");
28+
29+
goTo.marker('3');
30+
verify.completionListContains('foo', 'function foo(): void', 'This comment should appear for foo');
31+
32+
goTo.marker('4');
33+
verify.currentSignatureHelpDocCommentIs("This comment should appear for foo");
34+
35+
goTo.marker('5');
36+
verify.quickInfoIs("function fooWithParameters(a: string, b: number): void", "This is comment for function signature");
37+
38+
goTo.marker('6');
39+
verify.quickInfoIs('(local var) d: string', '');
40+
41+
goTo.marker('7');
42+
verify.completionListContains('a', '(parameter) a: string', 'this is comment about a');
43+
verify.completionListContains('b', '(parameter) b: number', 'this is comment for b');
44+
45+
goTo.marker('8');
46+
verify.quickInfoIs("function fooWithParameters(a: string, b: number): void", "This is comment for function signature");
47+
48+
goTo.marker('9');
49+
verify.completionListContains('fooWithParameters', 'function fooWithParameters(a: string, b: number): void', 'This is comment for function signature');
50+
51+
goTo.marker('10');
52+
verify.currentSignatureHelpDocCommentIs("This is comment for function signature");
53+
verify.currentParameterHelpArgumentDocCommentIs("this is comment about a");
54+
55+
goTo.marker('11');
56+
verify.currentSignatureHelpDocCommentIs("This is comment for function signature");
57+
verify.currentParameterHelpArgumentDocCommentIs("this is comment for b");
58+
59+
goTo.marker('12');
60+
verify.currentSignatureHelpDocCommentIs("Does something");
61+
verify.currentParameterHelpArgumentDocCommentIs("a string");
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// test arrow doc comments
4+
/////** lamdaFoo var comment*/
5+
////var lamb/*1*/daFoo = /** this is lambda comment*/ (/**param a*/a: number, /**param b*/b: number) => /*2*/a + b;
6+
////var lambddaN/*3*/oVarComment = /** this is lambda multiplication*/ (/**param a*/a: number, /**param b*/b: number) => a * b;
7+
/////*4*/lambdaFoo(/*5*/10, /*6*/20);
8+
9+
// test nested arrow doc comments
10+
////function /*7*/anotherFunc(a: number) {
11+
//// /** documentation
12+
//// @param b {string} inner parameter */
13+
//// var /*8*/lambdaVar = /** inner docs */(/*9*/b: string) => {
14+
//// var /*10*/localVar = "Hello ";
15+
//// return /*11*/localVar + /*12*/b;
16+
//// }
17+
//// return lamb/*13*/daVar("World") + a;
18+
////}
19+
20+
// test function expression doc comments
21+
/////**
22+
//// * On variable
23+
//// * @param s the first parameter!
24+
//// * @returns the parameter's length
25+
//// */
26+
////var assi/*14*/gned = /**
27+
//// * Summary on expression
28+
//// * @param s param on expression
29+
//// * @returns return on expression
30+
//// */function(/** On parameter */s: string) {
31+
//// return /*15*/s.length;
32+
////}
33+
////assig/*16*/ned/*17*/(/*18*/"hey");
34+
35+
36+
37+
goTo.marker('1');
38+
verify.quickInfoIs("var lambdaFoo: (a: number, b: number) => number", "lamdaFoo var comment\nthis is lambda comment");
39+
40+
goTo.marker('2');
41+
verify.completionListContains('a', '(parameter) a: number', 'param a');
42+
verify.completionListContains('b', '(parameter) b: number', 'param b');
43+
44+
goTo.marker('3');
45+
// pick up doccomments from the lambda itself
46+
verify.quickInfoIs("var lambddaNoVarComment: (a: number, b: number) => number", "this is lambda multiplication");
47+
48+
goTo.marker('4');
49+
verify.completionListContains('lambdaFoo', 'var lambdaFoo: (a: number, b: number) => number', 'lamdaFoo var comment\nthis is lambda comment');
50+
verify.completionListContains('lambddaNoVarComment', 'var lambddaNoVarComment: (a: number, b: number) => number', 'this is lambda multiplication');
51+
52+
goTo.marker('5');
53+
verify.currentParameterHelpArgumentDocCommentIs("param a");
54+
55+
goTo.marker('6');
56+
verify.currentParameterHelpArgumentDocCommentIs("param b");
57+
58+
59+
60+
61+
goTo.marker('7');
62+
// no documentation from nested lambda
63+
verify.quickInfoIs('function anotherFunc(a: number): string', '');
64+
goTo.marker('8');
65+
verify.quickInfoIs('(local var) lambdaVar: (b: string) => string', 'documentation\ninner docs ');
66+
goTo.marker('9');
67+
verify.quickInfoIs('(parameter) b: string', '{string} inner parameter ');
68+
goTo.marker('10');
69+
verify.quickInfoIs('(local var) localVar: string', '');
70+
goTo.marker('11');
71+
verify.quickInfoIs('(local var) localVar: string', '');
72+
goTo.marker('12');
73+
verify.quickInfoIs('(parameter) b: string', '{string} inner parameter ');
74+
goTo.marker('13');
75+
verify.quickInfoIs('(local var) lambdaVar: (b: string) => string', 'documentation\ninner docs ');
76+
77+
goTo.marker('14');
78+
verify.quickInfoIs("var assigned: (s: string) => number", "On variable\n@returns the parameter's length\nSummary on expression\n@returns return on expression");
79+
goTo.marker('15');
80+
verify.completionListContains('s', '(parameter) s: string', "the first parameter!\nparam on expression\nOn parameter ");
81+
goTo.marker('16');
82+
verify.quickInfoIs("var assigned: (s: string) => number", "On variable\n@returns the parameter's length\nSummary on expression\n@returns return on expression");
83+
goTo.marker('17');
84+
verify.completionListContains("assigned", "var assigned: (s: string) => number", "On variable\n@returns the parameter's length\nSummary on expression\n@returns return on expression");
85+
goTo.marker('18');
86+
verify.currentSignatureHelpDocCommentIs("On variable\n@returns the parameter's length\nSummary on expression\n@returns return on expression");
87+
verify.currentParameterHelpArgumentDocCommentIs("the first parameter!\nparam on expression\nOn parameter ");
88+

tests/cases/fourslash/getJavaScriptQuickInfo7.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@
1717
//// x - /**/a1()
1818

1919
goTo.marker();
20-
verify.quickInfoExists();
20+
verify.quickInfoExists();
21+
verify.quickInfoIs('function a1(p: any): number',
22+
'This is a very cool function that is very nice.\n@returns something');

0 commit comments

Comments
 (0)