Merge pull request #14371 from Microsoft/master-fix14254

[Master] Fix 14254: Return JsDoc tagName when there is no "@" sign prefix
This commit is contained in:
Yui 2017-03-01 21:48:17 -08:00 committed by GitHub
commit 5abb8f3caa
4 changed files with 150 additions and 56 deletions

View File

@ -16,11 +16,16 @@ namespace ts.Completions {
return undefined;
}
const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isJsDocTagName } = completionData;
const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, requestJsDocTagName, requestJsDocTag } = completionData;
if (isJsDocTagName) {
if (requestJsDocTagName) {
// If the current position is a jsDoc tag name, only tag names should be provided for completion
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getAllJsDocCompletionEntries() };
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getJSDocTagNameCompletions() };
}
if (requestJsDocTag) {
// If the current position is a jsDoc tag, only tags should be provided for completion
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getJSDocTagCompletions() };
}
const entries: CompletionEntry[] = [];
@ -54,7 +59,7 @@ namespace ts.Completions {
}
// Add keywords if this is not a member completion list
if (!isMemberCompletion && !isJsDocTagName) {
if (!isMemberCompletion && !requestJsDocTag && !requestJsDocTagName) {
addRange(entries, keywordCompletions);
}
@ -814,7 +819,10 @@ namespace ts.Completions {
function getCompletionData(typeChecker: TypeChecker, log: (message: string) => void, sourceFile: SourceFile, position: number) {
const isJavaScriptFile = isSourceFileJavaScript(sourceFile);
let isJsDocTagName = false;
// JsDoc tag-name is just the name of the JSDoc tagname (exclude "@")
let requestJsDocTagName = false;
// JsDoc tag includes both "@" and tag-name
let requestJsDocTag = false;
let start = timestamp();
const currentToken = getTokenAtPosition(sourceFile, position);
@ -826,10 +834,32 @@ namespace ts.Completions {
log("getCompletionData: Is inside comment: " + (timestamp() - start));
if (insideComment) {
// The current position is next to the '@' sign, when no tag name being provided yet.
// Provide a full list of tag names
if (hasDocComment(sourceFile, position) && sourceFile.text.charCodeAt(position - 1) === CharacterCodes.at) {
isJsDocTagName = true;
if (hasDocComment(sourceFile, position)) {
// The current position is next to the '@' sign, when no tag name being provided yet.
// Provide a full list of tag names
if (sourceFile.text.charCodeAt(position - 1) === CharacterCodes.at) {
requestJsDocTagName = true;
}
else {
// When completion is requested without "@", we will have check to make sure that
// there are no comments prefix the request position. We will only allow "*" and space.
// e.g
// /** |c| /*
//
// /**
// |c|
// */
//
// /**
// * |c|
// */
//
// /**
// * |c|
// */
const lineStart = getLineStartPositionForPosition(position, sourceFile);
requestJsDocTag = !(sourceFile.text.substring(lineStart, position).match(/[^\*|\s|(/\*\*)]/));
}
}
// Completion should work inside certain JsDoc tags. For example:
@ -839,7 +869,7 @@ namespace ts.Completions {
const tag = getJsDocTagAtPosition(sourceFile, position);
if (tag) {
if (tag.tagName.pos <= position && position <= tag.tagName.end) {
isJsDocTagName = true;
requestJsDocTagName = true;
}
switch (tag.kind) {
@ -854,8 +884,8 @@ namespace ts.Completions {
}
}
if (isJsDocTagName) {
return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, isJsDocTagName };
if (requestJsDocTagName || requestJsDocTag) {
return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, requestJsDocTagName, requestJsDocTag };
}
if (!insideJsDocTagExpression) {
@ -983,7 +1013,7 @@ namespace ts.Completions {
log("getCompletionData: Semantic work: " + (timestamp() - semanticStart));
return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), isJsDocTagName };
return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), requestJsDocTagName, requestJsDocTag };
function getTypeScriptMemberSymbols(): void {
// Right of dot member completion list

View File

@ -42,7 +42,8 @@ namespace ts.JsDoc {
"prop",
"version"
];
let jsDocCompletionEntries: CompletionEntry[];
let jsDocTagNameCompletionEntries: CompletionEntry[];
let jsDocTagCompletionEntries: CompletionEntry[];
export function getJsDocCommentsFromDeclarations(declarations: Declaration[]) {
// Only collect doc comments from duplicate declarations once:
@ -88,8 +89,8 @@ namespace ts.JsDoc {
return undefined;
}
export function getAllJsDocCompletionEntries(): CompletionEntry[] {
return jsDocCompletionEntries || (jsDocCompletionEntries = ts.map(jsDocTagNames, tagName => {
export function getJSDocTagNameCompletions(): CompletionEntry[] {
return jsDocTagNameCompletionEntries || (jsDocTagNameCompletionEntries = ts.map(jsDocTagNames, tagName => {
return {
name: tagName,
kind: ScriptElementKind.keyword,
@ -99,6 +100,17 @@ namespace ts.JsDoc {
}));
}
export function getJSDocTagCompletions(): CompletionEntry[] {
return jsDocTagCompletionEntries || (jsDocTagCompletionEntries = ts.map(jsDocTagNames, tagName => {
return {
name: `@${tagName}`,
kind: ScriptElementKind.keyword,
kindModifiers: "",
sortText: "0"
}
}));
}
/**
* Checks if position points to a valid position to add JSDoc comments, and if so,
* returns the appropriate template. Otherwise returns an empty string.

View File

@ -2,29 +2,57 @@
// @allowJs: true
// @Filename: Foo.js
/////** @/*1*/ */
////var v1;
//// /** @/*1*/ */
//// var v1;
////
/////** @p/*2*/ */
////var v2;
//// /** @p/*2*/ */
//// var v2;
////
/////** @param /*3*/ */
////var v3;
//// /** @param /*3*/ */
//// var v3;
////
/////** @param { n/*4*/ } bar */
////var v4;
//// /** @param { n/*4*/ } bar */
//// var v4;
////
/////** @type { n/*5*/ } */
////var v5;
//// /** @type { n/*5*/ } */
//// var v5;
////
////// @/*6*/
////var v6;
//// // @/*6*/
//// var v6;
////
////// @pa/*7*/
////var v7;
//// // @pa/*7*/
//// var v7;
////
/////** @return { n/*8*/ } */
////var v8;
//// /** @return { n/*8*/ } */
//// var v8;
////
//// /** /*9*/ */
////
//// /**
//// /*10*/
//// */
////
//// /**
//// * /*11*/
//// */
////
//// /**
//// /*12*/
//// */
////
//// /**
//// * /*13*/
//// */
////
//// /**
//// * some comment /*14*/
//// */
////
//// /**
//// * @param /*15*/
//// */
////
//// /** @param /*16*/ */
goTo.marker('1');
verify.completionListContains("constructor");
@ -55,3 +83,31 @@ verify.completionListIsEmpty();
goTo.marker('8');
verify.completionListContains('number');
goTo.marker('9');
verify.completionListCount(40);
verify.completionListContains("@argument");
goTo.marker('10');
verify.completionListCount(40);
verify.completionListContains("@returns");
goTo.marker('11');
verify.completionListCount(40);
verify.completionListContains("@argument");
goTo.marker('12');
verify.completionListCount(40);
verify.completionListContains("@constructor");
goTo.marker('13');
verify.completionListCount(40);
verify.completionListContains("@param");
goTo.marker('14');
verify.completionListIsEmpty();
goTo.marker('15');
verify.completionListIsEmpty();
goTo.marker('16');
verify.completionListIsEmpty();

View File

@ -1,28 +1,24 @@
/// <reference path='fourslash.ts' />
////var v1 = '';
////" /*openString1*/
////var v2 = '';
////"/*openString2*/
////var v3 = '';
////" bar./*openString3*/
////var v4 = '';
////// bar./*inComment1*/
////var v6 = '';
////// /*inComment2*/
////var v7 = '';
/////** /*inComment3*/
////var v8 = '';
/////** /*inComment4*/ **/
////var v9 = '';
/////* /*inComment5*/
////var v11 = '';
//// // /*inComment6*/
////var v12 = '';
////type htm/*inTypeAlias*/
///
////// /*inComment7*/
////foo;
////var v10 = /reg/*inRegExp1*/ex/;
//// var v1 = '';
//// " /*openString1*/
//// var v2 = '';
//// "/*openString2*/
//// var v3 = '';
//// " bar./*openString3*/
//// var v4 = '';
//// // bar./*inComment1*/
//// var v6 = '';
//// // /*inComment2*/
//// var v7 = '';
//// /* /*inComment3*/
//// var v11 = '';
//// // /*inComment4*/
//// var v12 = '';
//// type htm/*inTypeAlias*/
////
//// // /*inComment5*/
//// foo;
//// var v10 = /reg/*inRegExp1*/ex/;
goTo.eachMarker(() => verify.completionListIsEmpty());