Skip to content

Commit 4977bf4

Browse files
Merge pull request #19544 from uniqueiniquity/interfaceJsDoc
Insert JsDoc comment templates for additional nodes
2 parents d97335e + d2114e1 commit 4977bf4

18 files changed

+150
-131
lines changed

src/harness/harnessLanguageService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ namespace Harness.LanguageService {
495495
getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: ts.FormatCodeOptions): ts.TextChange[] {
496496
return unwrapJSONCallResult(this.shim.getFormattingEditsAfterKeystroke(fileName, position, key, JSON.stringify(options)));
497497
}
498-
getDocCommentTemplateAtPosition(fileName: string, position: number): ts.TextInsertion {
498+
getDocCommentTemplateAtPosition(fileName: string, position: number): ts.TextInsertion | undefined {
499499
return unwrapJSONCallResult(this.shim.getDocCommentTemplateAtPosition(fileName, position));
500500
}
501501
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean {

src/services/jsDoc.ts

Lines changed: 30 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* @internal */
22
namespace ts.JsDoc {
3+
const singleLineTemplate = { newText: "/** */", caretOffset: 3 };
34
const jsDocTagNames = [
45
"augments",
56
"author",
@@ -195,13 +196,9 @@ namespace ts.JsDoc {
195196
/**
196197
* Checks if position points to a valid position to add JSDoc comments, and if so,
197198
* returns the appropriate template. Otherwise returns an empty string.
198-
* Valid positions are
199-
* - outside of comments, statements, and expressions, and
200-
* - preceding a:
201-
* - function/constructor/method declaration
202-
* - class declarations
203-
* - variable statements
204-
* - namespace declarations
199+
* Invalid positions are
200+
* - within comments, strings (including template literals and regex), and JSXText
201+
* - within a token
205202
*
206203
* Hosts should ideally check that:
207204
* - The line is all whitespace up to 'position' before performing the insertion.
@@ -212,7 +209,8 @@ namespace ts.JsDoc {
212209
* @param position The (character-indexed) position in the file where the check should
213210
* be performed.
214211
*/
215-
export function getDocCommentTemplateAtPosition(newLine: string, sourceFile: SourceFile, position: number): TextInsertion {
212+
213+
export function getDocCommentTemplateAtPosition(newLine: string, sourceFile: SourceFile, position: number): TextInsertion | undefined {
216214
// Check if in a context where we don't want to perform any insertion
217215
if (isInString(sourceFile, position) || isInComment(sourceFile, position) || hasDocComment(sourceFile, position)) {
218216
return undefined;
@@ -226,35 +224,33 @@ namespace ts.JsDoc {
226224

227225
const commentOwnerInfo = getCommentOwnerInfo(tokenAtPos);
228226
if (!commentOwnerInfo) {
229-
return undefined;
227+
// if climbing the tree did not find a declaration with parameters, complete to a single line comment
228+
return singleLineTemplate;
230229
}
231230
const { commentOwner, parameters } = commentOwnerInfo;
232-
if (commentOwner.getStart() < position) {
231+
232+
if (commentOwner.kind === SyntaxKind.JsxText) {
233233
return undefined;
234234
}
235235

236+
if (commentOwner.getStart() < position || parameters.length === 0) {
237+
// if climbing the tree found a declaration with parameters but the request was made inside it
238+
// or if there are no parameters, complete to a single line comment
239+
return singleLineTemplate;
240+
}
241+
236242
const posLineAndChar = sourceFile.getLineAndCharacterOfPosition(position);
237243
const lineStart = sourceFile.getLineStarts()[posLineAndChar.line];
238244

239245
// replace non-whitespace characters in prefix with spaces.
240246
const indentationStr = sourceFile.text.substr(lineStart, posLineAndChar.character).replace(/\S/i, () => " ");
241247
const isJavaScriptFile = hasJavaScriptFileExtension(sourceFile.fileName);
242248

243-
let docParams = "";
244-
if (parameters) {
245-
for (let i = 0; i < parameters.length; i++) {
246-
const currentName = parameters[i].name;
247-
const paramName = currentName.kind === SyntaxKind.Identifier ?
248-
(<Identifier>currentName).escapedText :
249-
"param" + i;
250-
if (isJavaScriptFile) {
251-
docParams += `${indentationStr} * @param {any} ${paramName}${newLine}`;
252-
}
253-
else {
254-
docParams += `${indentationStr} * @param ${paramName}${newLine}`;
255-
}
256-
}
257-
}
249+
const docParams = parameters.map(({name}, i) => {
250+
const nameText = isIdentifier(name) ? name.text : `param${i}`;
251+
const type = isJavaScriptFile ? "{any} " : "";
252+
return `${indentationStr} * @param ${type}${nameText}${newLine}`;
253+
}).join("");
258254

259255
// A doc comment consists of the following
260256
// * The opening comment line
@@ -276,43 +272,30 @@ namespace ts.JsDoc {
276272

277273
interface CommentOwnerInfo {
278274
readonly commentOwner: Node;
279-
readonly parameters?: ReadonlyArray<ParameterDeclaration>;
275+
readonly parameters: ReadonlyArray<ParameterDeclaration>;
280276
}
281277
function getCommentOwnerInfo(tokenAtPos: Node): CommentOwnerInfo | undefined {
282-
// TODO: add support for:
283-
// - enums/enum members
284-
// - interfaces
285-
// - property declarations
286-
// - potentially property assignments
287278
for (let commentOwner = tokenAtPos; commentOwner; commentOwner = commentOwner.parent) {
288279
switch (commentOwner.kind) {
289280
case SyntaxKind.FunctionDeclaration:
290281
case SyntaxKind.MethodDeclaration:
291282
case SyntaxKind.Constructor:
292-
const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration;
283+
case SyntaxKind.MethodSignature:
284+
const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature;
293285
return { commentOwner, parameters };
294286

295-
case SyntaxKind.ClassDeclaration:
296-
return { commentOwner };
297-
298287
case SyntaxKind.VariableStatement: {
299288
const varStatement = <VariableStatement>commentOwner;
300289
const varDeclarations = varStatement.declarationList.declarations;
301290
const parameters = varDeclarations.length === 1 && varDeclarations[0].initializer
302291
? getParametersFromRightHandSideOfAssignment(varDeclarations[0].initializer)
303292
: undefined;
304-
return { commentOwner, parameters };
293+
return parameters ? { commentOwner, parameters } : undefined;
305294
}
306295

307296
case SyntaxKind.SourceFile:
308297
return undefined;
309298

310-
case SyntaxKind.ModuleDeclaration:
311-
// If in walking up the tree, we hit a a nested namespace declaration,
312-
// then we must be somewhere within a dotted namespace name; however we don't
313-
// want to give back a JSDoc template for the 'b' or 'c' in 'namespace a.b.c { }'.
314-
return commentOwner.parent.kind === SyntaxKind.ModuleDeclaration ? undefined : { commentOwner };
315-
316299
case SyntaxKind.BinaryExpression: {
317300
const be = commentOwner as BinaryExpression;
318301
if (getSpecialPropertyAssignmentKind(be) === ts.SpecialPropertyAssignmentKind.None) {
@@ -321,6 +304,11 @@ namespace ts.JsDoc {
321304
const parameters = isFunctionLike(be.right) ? be.right.parameters : emptyArray;
322305
return { commentOwner, parameters };
323306
}
307+
308+
case SyntaxKind.JsxText: {
309+
const parameters: ReadonlyArray<ParameterDeclaration> = emptyArray;
310+
return { commentOwner, parameters };
311+
}
324312
}
325313
}
326314
}

src/services/services.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1808,7 +1808,7 @@ namespace ts {
18081808
}
18091809
}
18101810

1811-
function getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion {
1811+
function getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion | undefined {
18121812
return JsDoc.getDocCommentTemplateAtPosition(getNewLineOrDefaultFromHost(host), syntaxTreeCache.getCurrentSourceFile(fileName), position);
18131813
}
18141814

tests/cases/fourslash/docCommentTemplateClassDecl01.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,5 @@
1111
//// }
1212
////}
1313

14-
verify.docCommentTemplateAt("decl", /*newTextOffset*/ 8,
15-
`/**
16-
*
17-
*/
18-
`);
14+
verify.docCommentTemplateAt("decl", /*newTextOffset*/ 3,
15+
"/** */");

tests/cases/fourslash/docCommentTemplateClassDeclMethods01.ts

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
/// <reference path='fourslash.ts' />
22

3-
const enum Indentation {
4-
Standard = 8,
5-
Indented = 12,
6-
}
3+
const singleLineOffset = 3;
4+
const multiLineOffset = 12;
75

86

97
////class C {
@@ -16,42 +14,38 @@ const enum Indentation {
1614
//// }
1715
////}
1816

19-
verify.docCommentTemplateAt("0", Indentation.Standard,
20-
`/**
21-
*
22-
*/`);
17+
verify.docCommentTemplateAt("0", singleLineOffset,
18+
"/** */");
2319

2420

25-
verify.docCommentTemplateAt("1", Indentation.Indented,
26-
`/**
27-
*
28-
*/`);
21+
verify.docCommentTemplateAt("1", singleLineOffset,
22+
"/** */");
2923

3024

31-
verify.docCommentTemplateAt("2", Indentation.Indented,
25+
verify.docCommentTemplateAt("2", multiLineOffset,
3226
`/**
3327
*
3428
* @param a
3529
*/
3630
`);
3731

38-
verify.docCommentTemplateAt("3", Indentation.Indented,
32+
verify.docCommentTemplateAt("3", multiLineOffset,
3933
`/**
4034
*
4135
* @param a
4236
* @param b
4337
*/
4438
`);
4539

46-
verify.docCommentTemplateAt("4", Indentation.Indented,
40+
verify.docCommentTemplateAt("4", multiLineOffset,
4741
`/**
4842
*
4943
* @param a
5044
* @param param1
5145
* @param param2
5246
*/`);
5347

54-
verify.docCommentTemplateAt("5", Indentation.Indented,
48+
verify.docCommentTemplateAt("5", multiLineOffset,
5549
`/**
5650
*
5751
* @param a

tests/cases/fourslash/docCommentTemplateClassDeclMethods02.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
/// <reference path='fourslash.ts' />
22

3-
const enum Indentation {
4-
Indented = 12,
5-
}
3+
const singleLineOffset = 3;
4+
const multiLineOffset = 12;
65

76
////class C {
87
//// /*0*/
@@ -13,12 +12,10 @@ const enum Indentation {
1312
//// [1 + 2 + 3 + Math.rand()](x: number, y: string, z = true) { }
1413
////}
1514

16-
verify.docCommentTemplateAt("0", Indentation.Indented,
17-
`/**
18-
*
19-
*/`);
15+
verify.docCommentTemplateAt("0", singleLineOffset,
16+
"/** */");
2017

21-
verify.docCommentTemplateAt("1", Indentation.Indented,
18+
verify.docCommentTemplateAt("1", multiLineOffset,
2219
`/**
2320
*
2421
* @param x

tests/cases/fourslash/docCommentTemplateEmptyFile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
// @Filename: emptyFile.ts
44
/////*0*/
55

6-
verify.noDocCommentTemplateAt("0");
6+
verify.docCommentTemplateAt("0", 3, "/** */");

tests/cases/fourslash/docCommentTemplateIndentation.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,8 @@
55
//// /*1*/
66
/////*0*/ function foo() { }
77

8-
const noIndentEmptyScaffolding = "/**\r\n * \r\n */";
9-
const oneIndentEmptyScaffolding = "/**\r\n * \r\n */";
10-
const twoIndentEmptyScaffolding = "/**\r\n * \r\n */";
11-
const noIndentOffset = 8;
12-
const oneIndentOffset = noIndentOffset + 4;
13-
const twoIndentOffset = oneIndentOffset + 4;
8+
const singleLineComment = "/** */";
149

15-
verify.docCommentTemplateAt("0", noIndentOffset, noIndentEmptyScaffolding);
16-
verify.docCommentTemplateAt("1", oneIndentOffset, oneIndentEmptyScaffolding);
17-
verify.docCommentTemplateAt("2", twoIndentOffset, twoIndentEmptyScaffolding);
10+
verify.docCommentTemplateAt("0", 3, singleLineComment);
11+
verify.docCommentTemplateAt("1", 3, singleLineComment);
12+
verify.docCommentTemplateAt("2", 3, singleLineComment);

tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
// @Filename: functionDecl.ts
44
////f/*0*/unction /*1*/foo/*2*/(/*3*/) /*4*/{ /*5*/}
55

6-
for (const marker of test.markers()) {
7-
verify.noDocCommentTemplateAt(marker);
8-
}
6+
verify.noDocCommentTemplateAt("0");
7+
8+
verify.docCommentTemplateAt("1", 3, "/** */");
9+
verify.docCommentTemplateAt("2", 3, "/** */");
10+
verify.docCommentTemplateAt("3", 3, "/** */");
11+
verify.docCommentTemplateAt("4", 3, "/** */");
12+
verify.docCommentTemplateAt("5", 3, "/** */");
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
/////*interfaceFoo*/
4+
////interface Foo {
5+
//// /*propertybar*/
6+
//// bar: any;
7+
////
8+
//// /*methodbaz*/
9+
//// baz(message: any): void;
10+
////
11+
//// /*methodUnit*/
12+
//// unit(): void;
13+
////}
14+
////
15+
/////*enumStatus*/
16+
////const enum Status {
17+
//// /*memberOpen*/
18+
//// Open,
19+
////
20+
//// /*memberClosed*/
21+
//// Closed
22+
////}
23+
////
24+
/////*aliasBar*/
25+
////type Bar = Foo & any;
26+
27+
verify.docCommentTemplateAt("interfaceFoo", /*expectedOffset*/ 3,
28+
"/** */");
29+
30+
verify.docCommentTemplateAt("propertybar", /*expectedOffset*/ 3,
31+
"/** */");
32+
33+
verify.docCommentTemplateAt("methodbaz", /*expectedOffset*/ 12,
34+
`/**
35+
*
36+
* @param message
37+
*/`);
38+
39+
verify.docCommentTemplateAt("methodUnit", /*expectedOffset*/ 3,
40+
"/** */");
41+
42+
verify.docCommentTemplateAt("enumStatus", /*expectedOffset*/ 3,
43+
"/** */");
44+
45+
verify.docCommentTemplateAt("memberOpen", /*expectedOffset*/ 3,
46+
"/** */");
47+
48+
verify.docCommentTemplateAt("memberClosed", /*expectedOffset*/ 3,
49+
"/** */");
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
//@Filename: file.tsx
4+
////
5+
//// var x = <div>
6+
//// /*0*/hello/*1*/
7+
//// /*2*/goodbye/*3*/
8+
//// </div>;
9+
10+
for (const marker in test.markers()) {
11+
verify.noDocCommentTemplateAt(marker);
12+
}

tests/cases/fourslash/docCommentTemplateNamespacesAndModules01.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,11 @@
1212
////module "ambientModule" {
1313
////}
1414

15-
verify.docCommentTemplateAt("namespaceN", /*indentation*/ 8,
16-
`/**
17-
*
18-
*/`);
15+
verify.docCommentTemplateAt("namespaceN", /*indentation*/ 3,
16+
"/** */");
1917

20-
verify.docCommentTemplateAt("namespaceM", /*indentation*/ 8,
21-
`/**
22-
*
23-
*/`);
18+
verify.docCommentTemplateAt("namespaceM", /*indentation*/ 3,
19+
"/** */");
2420

25-
verify.docCommentTemplateAt("namespaceM", /*indentation*/ 8,
26-
`/**
27-
*
28-
*/`);
21+
verify.docCommentTemplateAt("namespaceM", /*indentation*/ 3,
22+
"/** */");

0 commit comments

Comments
 (0)