Skip to content

Commit 5abb8f3

Browse files
authored
Merge pull request microsoft#14371 from Microsoft/master-fix14254
[Master] Fix 14254: Return JsDoc tagName when there is no "@" sign prefix
2 parents e9fd831 + da51f39 commit 5abb8f3

File tree

4 files changed

+150
-56
lines changed

4 files changed

+150
-56
lines changed

src/services/completions.ts

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,16 @@ namespace ts.Completions {
1616
return undefined;
1717
}
1818

19-
const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isJsDocTagName } = completionData;
19+
const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, requestJsDocTagName, requestJsDocTag } = completionData;
2020

21-
if (isJsDocTagName) {
21+
if (requestJsDocTagName) {
2222
// If the current position is a jsDoc tag name, only tag names should be provided for completion
23-
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getAllJsDocCompletionEntries() };
23+
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getJSDocTagNameCompletions() };
24+
}
25+
26+
if (requestJsDocTag) {
27+
// If the current position is a jsDoc tag, only tags should be provided for completion
28+
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getJSDocTagCompletions() };
2429
}
2530

2631
const entries: CompletionEntry[] = [];
@@ -54,7 +59,7 @@ namespace ts.Completions {
5459
}
5560

5661
// Add keywords if this is not a member completion list
57-
if (!isMemberCompletion && !isJsDocTagName) {
62+
if (!isMemberCompletion && !requestJsDocTag && !requestJsDocTagName) {
5863
addRange(entries, keywordCompletions);
5964
}
6065

@@ -814,7 +819,10 @@ namespace ts.Completions {
814819
function getCompletionData(typeChecker: TypeChecker, log: (message: string) => void, sourceFile: SourceFile, position: number) {
815820
const isJavaScriptFile = isSourceFileJavaScript(sourceFile);
816821

817-
let isJsDocTagName = false;
822+
// JsDoc tag-name is just the name of the JSDoc tagname (exclude "@")
823+
let requestJsDocTagName = false;
824+
// JsDoc tag includes both "@" and tag-name
825+
let requestJsDocTag = false;
818826

819827
let start = timestamp();
820828
const currentToken = getTokenAtPosition(sourceFile, position);
@@ -826,10 +834,32 @@ namespace ts.Completions {
826834
log("getCompletionData: Is inside comment: " + (timestamp() - start));
827835

828836
if (insideComment) {
829-
// The current position is next to the '@' sign, when no tag name being provided yet.
830-
// Provide a full list of tag names
831-
if (hasDocComment(sourceFile, position) && sourceFile.text.charCodeAt(position - 1) === CharacterCodes.at) {
832-
isJsDocTagName = true;
837+
if (hasDocComment(sourceFile, position)) {
838+
// The current position is next to the '@' sign, when no tag name being provided yet.
839+
// Provide a full list of tag names
840+
if (sourceFile.text.charCodeAt(position - 1) === CharacterCodes.at) {
841+
requestJsDocTagName = true;
842+
}
843+
else {
844+
// When completion is requested without "@", we will have check to make sure that
845+
// there are no comments prefix the request position. We will only allow "*" and space.
846+
// e.g
847+
// /** |c| /*
848+
//
849+
// /**
850+
// |c|
851+
// */
852+
//
853+
// /**
854+
// * |c|
855+
// */
856+
//
857+
// /**
858+
// * |c|
859+
// */
860+
const lineStart = getLineStartPositionForPosition(position, sourceFile);
861+
requestJsDocTag = !(sourceFile.text.substring(lineStart, position).match(/[^\*|\s|(/\*\*)]/));
862+
}
833863
}
834864

835865
// Completion should work inside certain JsDoc tags. For example:
@@ -839,7 +869,7 @@ namespace ts.Completions {
839869
const tag = getJsDocTagAtPosition(sourceFile, position);
840870
if (tag) {
841871
if (tag.tagName.pos <= position && position <= tag.tagName.end) {
842-
isJsDocTagName = true;
872+
requestJsDocTagName = true;
843873
}
844874

845875
switch (tag.kind) {
@@ -854,8 +884,8 @@ namespace ts.Completions {
854884
}
855885
}
856886

857-
if (isJsDocTagName) {
858-
return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, isJsDocTagName };
887+
if (requestJsDocTagName || requestJsDocTag) {
888+
return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, requestJsDocTagName, requestJsDocTag };
859889
}
860890

861891
if (!insideJsDocTagExpression) {
@@ -983,7 +1013,7 @@ namespace ts.Completions {
9831013

9841014
log("getCompletionData: Semantic work: " + (timestamp() - semanticStart));
9851015

986-
return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), isJsDocTagName };
1016+
return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), requestJsDocTagName, requestJsDocTag };
9871017

9881018
function getTypeScriptMemberSymbols(): void {
9891019
// Right of dot member completion list

src/services/jsDoc.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ namespace ts.JsDoc {
4242
"prop",
4343
"version"
4444
];
45-
let jsDocCompletionEntries: CompletionEntry[];
45+
let jsDocTagNameCompletionEntries: CompletionEntry[];
46+
let jsDocTagCompletionEntries: CompletionEntry[];
4647

4748
export function getJsDocCommentsFromDeclarations(declarations: Declaration[]) {
4849
// Only collect doc comments from duplicate declarations once:
@@ -88,8 +89,8 @@ namespace ts.JsDoc {
8889
return undefined;
8990
}
9091

91-
export function getAllJsDocCompletionEntries(): CompletionEntry[] {
92-
return jsDocCompletionEntries || (jsDocCompletionEntries = ts.map(jsDocTagNames, tagName => {
92+
export function getJSDocTagNameCompletions(): CompletionEntry[] {
93+
return jsDocTagNameCompletionEntries || (jsDocTagNameCompletionEntries = ts.map(jsDocTagNames, tagName => {
9394
return {
9495
name: tagName,
9596
kind: ScriptElementKind.keyword,
@@ -99,6 +100,17 @@ namespace ts.JsDoc {
99100
}));
100101
}
101102

103+
export function getJSDocTagCompletions(): CompletionEntry[] {
104+
return jsDocTagCompletionEntries || (jsDocTagCompletionEntries = ts.map(jsDocTagNames, tagName => {
105+
return {
106+
name: `@${tagName}`,
107+
kind: ScriptElementKind.keyword,
108+
kindModifiers: "",
109+
sortText: "0"
110+
}
111+
}));
112+
}
113+
102114
/**
103115
* Checks if position points to a valid position to add JSDoc comments, and if so,
104116
* returns the appropriate template. Otherwise returns an empty string.

tests/cases/fourslash/completionInJsDoc.ts

Lines changed: 72 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,57 @@
22

33
// @allowJs: true
44
// @Filename: Foo.js
5-
/////** @/*1*/ */
6-
////var v1;
5+
//// /** @/*1*/ */
6+
//// var v1;
77
////
8-
/////** @p/*2*/ */
9-
////var v2;
8+
//// /** @p/*2*/ */
9+
//// var v2;
1010
////
11-
/////** @param /*3*/ */
12-
////var v3;
11+
//// /** @param /*3*/ */
12+
//// var v3;
1313
////
14-
/////** @param { n/*4*/ } bar */
15-
////var v4;
14+
//// /** @param { n/*4*/ } bar */
15+
//// var v4;
1616
////
17-
/////** @type { n/*5*/ } */
18-
////var v5;
17+
//// /** @type { n/*5*/ } */
18+
//// var v5;
1919
////
20-
////// @/*6*/
21-
////var v6;
20+
//// // @/*6*/
21+
//// var v6;
2222
////
23-
////// @pa/*7*/
24-
////var v7;
23+
//// // @pa/*7*/
24+
//// var v7;
2525
////
26-
/////** @return { n/*8*/ } */
27-
////var v8;
26+
//// /** @return { n/*8*/ } */
27+
//// var v8;
28+
////
29+
//// /** /*9*/ */
30+
////
31+
//// /**
32+
//// /*10*/
33+
//// */
34+
////
35+
//// /**
36+
//// * /*11*/
37+
//// */
38+
////
39+
//// /**
40+
//// /*12*/
41+
//// */
42+
////
43+
//// /**
44+
//// * /*13*/
45+
//// */
46+
////
47+
//// /**
48+
//// * some comment /*14*/
49+
//// */
50+
////
51+
//// /**
52+
//// * @param /*15*/
53+
//// */
54+
////
55+
//// /** @param /*16*/ */
2856

2957
goTo.marker('1');
3058
verify.completionListContains("constructor");
@@ -55,3 +83,31 @@ verify.completionListIsEmpty();
5583
goTo.marker('8');
5684
verify.completionListContains('number');
5785

86+
goTo.marker('9');
87+
verify.completionListCount(40);
88+
verify.completionListContains("@argument");
89+
90+
goTo.marker('10');
91+
verify.completionListCount(40);
92+
verify.completionListContains("@returns");
93+
94+
goTo.marker('11');
95+
verify.completionListCount(40);
96+
verify.completionListContains("@argument");
97+
98+
goTo.marker('12');
99+
verify.completionListCount(40);
100+
verify.completionListContains("@constructor");
101+
102+
goTo.marker('13');
103+
verify.completionListCount(40);
104+
verify.completionListContains("@param");
105+
106+
goTo.marker('14');
107+
verify.completionListIsEmpty();
108+
109+
goTo.marker('15');
110+
verify.completionListIsEmpty();
111+
112+
goTo.marker('16');
113+
verify.completionListIsEmpty();
Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,24 @@
11
/// <reference path='fourslash.ts' />
22

3-
////var v1 = '';
4-
////" /*openString1*/
5-
////var v2 = '';
6-
////"/*openString2*/
7-
////var v3 = '';
8-
////" bar./*openString3*/
9-
////var v4 = '';
10-
////// bar./*inComment1*/
11-
////var v6 = '';
12-
////// /*inComment2*/
13-
////var v7 = '';
14-
/////** /*inComment3*/
15-
////var v8 = '';
16-
/////** /*inComment4*/ **/
17-
////var v9 = '';
18-
/////* /*inComment5*/
19-
////var v11 = '';
20-
//// // /*inComment6*/
21-
////var v12 = '';
22-
////type htm/*inTypeAlias*/
23-
///
24-
////// /*inComment7*/
25-
////foo;
26-
////var v10 = /reg/*inRegExp1*/ex/;
3+
//// var v1 = '';
4+
//// " /*openString1*/
5+
//// var v2 = '';
6+
//// "/*openString2*/
7+
//// var v3 = '';
8+
//// " bar./*openString3*/
9+
//// var v4 = '';
10+
//// // bar./*inComment1*/
11+
//// var v6 = '';
12+
//// // /*inComment2*/
13+
//// var v7 = '';
14+
//// /* /*inComment3*/
15+
//// var v11 = '';
16+
//// // /*inComment4*/
17+
//// var v12 = '';
18+
//// type htm/*inTypeAlias*/
19+
////
20+
//// // /*inComment5*/
21+
//// foo;
22+
//// var v10 = /reg/*inRegExp1*/ex/;
2723

2824
goTo.eachMarker(() => verify.completionListIsEmpty());

0 commit comments

Comments
 (0)