Add sortText depending scope of symbols

Fixes #15024
This commit is contained in:
Sheetal Nandi 2019-05-16 14:46:10 -07:00
parent 9052804576
commit 00cea41b65
93 changed files with 700 additions and 178 deletions

View File

@ -798,8 +798,8 @@ namespace FourSlash {
}
private verifyCompletionEntry(actual: ts.CompletionEntry, expected: FourSlashInterface.ExpectedCompletionEntry) {
const { insertText, replacementSpan, hasAction, isRecommended, kind, kindModifiers, text, documentation, tags, source, sourceDisplay } = typeof expected === "string"
? { insertText: undefined, replacementSpan: undefined, hasAction: undefined, isRecommended: undefined, kind: undefined, kindModifiers: undefined, text: undefined, documentation: undefined, tags: undefined, source: undefined, sourceDisplay: undefined }
const { insertText, replacementSpan, hasAction, isRecommended, kind, kindModifiers, text, documentation, tags, source, sourceDisplay, sortText } = typeof expected === "string"
? { insertText: undefined, replacementSpan: undefined, hasAction: undefined, isRecommended: undefined, kind: undefined, kindModifiers: undefined, text: undefined, documentation: undefined, tags: undefined, source: undefined, sourceDisplay: undefined, sortText: undefined }
: expected;
if (actual.insertText !== insertText) {
@ -825,6 +825,7 @@ namespace FourSlash {
assert.equal(actual.hasAction, hasAction);
assert.equal(actual.isRecommended, isRecommended);
assert.equal(actual.source, source);
assert.equal(actual.sortText, sortText || ts.Completions.SortText.LocationPriority, this.messageAtLastKnownMarker(`Actual entry: ${JSON.stringify(actual)}`));
if (text !== undefined) {
const actualDetails = this.getCompletionEntryDetails(actual.name, actual.source)!;
@ -4434,18 +4435,63 @@ namespace FourSlashInterface {
}
}
export namespace Completion {
const functionEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "function", kindModifiers: "declare" });
const varEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "var", kindModifiers: "declare" });
const moduleEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "module", kindModifiers: "declare" });
const keywordEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "keyword" });
const methodEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "method", kindModifiers: "declare" });
const propertyEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "property", kindModifiers: "declare" });
const interfaceEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "interface", kindModifiers: "declare" });
const typeEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "type", kindModifiers: "declare" });
export import SortText = ts.Completions.SortText;
const functionEntry = (name: string): ExpectedCompletionEntryObject => ({
name,
kind: "function",
kindModifiers: "declare",
sortText: SortText.GlobalsOrKeywords
});
const varEntry = (name: string): ExpectedCompletionEntryObject => ({
name,
kind: "var",
kindModifiers: "declare",
sortText: SortText.GlobalsOrKeywords
});
const moduleEntry = (name: string): ExpectedCompletionEntryObject => ({
name,
kind: "module",
kindModifiers: "declare",
sortText: SortText.GlobalsOrKeywords
});
const keywordEntry = (name: string): ExpectedCompletionEntryObject => ({
name,
kind: "keyword",
sortText: SortText.GlobalsOrKeywords
});
const methodEntry = (name: string): ExpectedCompletionEntryObject => ({
name,
kind: "method",
kindModifiers: "declare",
sortText: SortText.LocationPriority
});
const propertyEntry = (name: string): ExpectedCompletionEntryObject => ({
name,
kind: "property",
kindModifiers: "declare",
sortText: SortText.LocationPriority
});
const interfaceEntry = (name: string): ExpectedCompletionEntryObject => ({
name,
kind: "interface",
kindModifiers: "declare",
sortText: SortText.GlobalsOrKeywords
});
const typeEntry = (name: string): ExpectedCompletionEntryObject => ({
name,
kind: "type",
kindModifiers: "declare",
sortText: SortText.GlobalsOrKeywords
});
const res: ExpectedCompletionEntryObject[] = [];
for (let i = ts.SyntaxKind.FirstKeyword; i <= ts.SyntaxKind.LastKeyword; i++) {
res.push({ name: ts.Debug.assertDefined(ts.tokenToString(i)), kind: "keyword" });
res.push({
name: ts.Debug.assertDefined(ts.tokenToString(i)),
kind: "keyword",
sortText: SortText.GlobalsOrKeywords
});
}
export const keywordsWithUndefined: ReadonlyArray<ExpectedCompletionEntryObject> = res;
export const keywords: ReadonlyArray<ExpectedCompletionEntryObject> = keywordsWithUndefined.filter(k => k.name !== "undefined");
@ -4552,11 +4598,15 @@ namespace FourSlashInterface {
moduleEntry("Intl"),
];
export const globalThisEntry: ExpectedCompletionEntry = {
name: "globalThis",
kind: "module",
sortText: SortText.GlobalsOrKeywords
};
export const globalTypes = globalTypesPlus([]);
export function globalTypesPlus(plus: ReadonlyArray<ExpectedCompletionEntry>): ReadonlyArray<ExpectedCompletionEntry> {
return [
{ name: "globalThis", kind: "module" },
globalThisEntry,
...globalTypeDecls,
...plus,
...typeKeywords,
@ -4605,7 +4655,11 @@ namespace FourSlashInterface {
export const classElementInJsKeywords = getInJsKeywords(classElementKeywords);
export const constructorParameterKeywords: ReadonlyArray<ExpectedCompletionEntryObject> =
["private", "protected", "public", "readonly"].map((name): ExpectedCompletionEntryObject => ({ name, kind: "keyword" }));
["private", "protected", "public", "readonly"].map((name): ExpectedCompletionEntryObject => ({
name,
kind: "keyword",
sortText: SortText.GlobalsOrKeywords
}));
export const functionMembers: ReadonlyArray<ExpectedCompletionEntryObject> = [
methodEntry("apply"),
@ -4834,13 +4888,18 @@ namespace FourSlashInterface {
"await",
].map(keywordEntry);
export const undefinedVarEntry: ExpectedCompletionEntry = {
name: "undefined",
kind: "var",
sortText: SortText.GlobalsOrKeywords
};
// TODO: many of these are inappropriate to always provide
export const globalsInsideFunction = (plus: ReadonlyArray<ExpectedCompletionEntry>): ReadonlyArray<ExpectedCompletionEntry> => [
{ name: "arguments", kind: "local var" },
...plus,
{ name: "globalThis", kind: "module" },
globalThisEntry,
...globalsVars,
{ name: "undefined", kind: "var" },
undefinedVarEntry,
...globalKeywordsInsideFunction,
];
@ -4849,10 +4908,10 @@ namespace FourSlashInterface {
// TODO: many of these are inappropriate to always provide
export const globalsInJsInsideFunction = (plus: ReadonlyArray<ExpectedCompletionEntry>): ReadonlyArray<ExpectedCompletionEntry> => [
{ name: "arguments", kind: "local var" },
{ name: "globalThis", kind: "module" },
globalThisEntry,
...globalsVars,
...plus,
{ name: "undefined", kind: "var" },
undefinedVarEntry,
...globalInJsKeywordsInsideFunction,
];
@ -4990,34 +5049,34 @@ namespace FourSlashInterface {
})();
export const globals: ReadonlyArray<ExpectedCompletionEntryObject> = [
{ name: "globalThis", kind: "module" },
globalThisEntry,
...globalsVars,
{ name: "undefined", kind: "var" },
undefinedVarEntry,
...globalKeywords
];
export const globalsInJs: ReadonlyArray<ExpectedCompletionEntryObject> = [
{ name: "globalThis", kind: "module" },
globalThisEntry,
...globalsVars,
{ name: "undefined", kind: "var" },
undefinedVarEntry,
...globalInJsKeywords
];
export function globalsPlus(plus: ReadonlyArray<ExpectedCompletionEntry>): ReadonlyArray<ExpectedCompletionEntry> {
return [
{ name: "globalThis", kind: "module" },
globalThisEntry,
...globalsVars,
...plus,
{ name: "undefined", kind: "var" },
undefinedVarEntry,
...globalKeywords];
}
export function globalsInJsPlus(plus: ReadonlyArray<ExpectedCompletionEntry>): ReadonlyArray<ExpectedCompletionEntry> {
return [
{ name: "globalThis", kind: "module" },
globalThisEntry,
...globalsVars,
...plus,
{ name: "undefined", kind: "var" },
undefinedVarEntry,
...globalInJsKeywords];
}
}
@ -5050,6 +5109,7 @@ namespace FourSlashInterface {
readonly documentation?: string;
readonly sourceDisplay?: string;
readonly tags?: ReadonlyArray<ts.JSDocTagInfo>;
readonly sortText?: ts.Completions.SortText;
}
export interface VerifyCompletionsOptions {

View File

@ -1,5 +1,12 @@
/* @internal */
namespace ts.Completions {
export enum SortText {
LocationPriority = "0",
SuggestedClassMembers = "1",
GlobalsOrKeywords = "2",
AutoImportSuggestions = "3",
JavascriptIdentifiers = "4"
}
export type Log = (message: string) => void;
const enum SymbolOriginInfoKind { ThisType, SymbolMemberNoExport, SymbolMemberExport, Export }
@ -22,6 +29,8 @@ namespace ts.Completions {
*/
type SymbolOriginInfoMap = (SymbolOriginInfo | undefined)[];
type SymbolSortTextMap = (SortText | undefined)[];
const enum KeywordCompletionFilters {
None, // No keywords
All, // Every possible keyword (TODO: This is never appropriate)
@ -78,7 +87,21 @@ namespace ts.Completions {
}
function completionInfoFromData(sourceFile: SourceFile, typeChecker: TypeChecker, compilerOptions: CompilerOptions, log: Log, completionData: CompletionData, preferences: UserPreferences): CompletionInfo | undefined {
const { symbols, completionKind, isInSnippetScope, isNewIdentifierLocation, location, propertyAccessToConvert, keywordFilters, literals, symbolToOriginInfoMap, recommendedCompletion, isJsxInitializer, insideJsDocTagTypeExpression } = completionData;
const {
symbols,
completionKind,
isInSnippetScope,
isNewIdentifierLocation,
location,
propertyAccessToConvert,
keywordFilters,
literals,
symbolToOriginInfoMap,
recommendedCompletion,
isJsxInitializer,
insideJsDocTagTypeExpression,
symbolToSortTextMap,
} = completionData;
if (location && location.parent && isJsxClosingElement(location.parent)) {
// In the TypeScript JSX element, if such element is not defined. When users query for completion at closing tag,
@ -93,7 +116,7 @@ namespace ts.Completions {
name: tagName.getFullText(sourceFile) + (hasClosingAngleBracket ? "" : ">"),
kind: ScriptElementKind.classElement,
kindModifiers: undefined,
sortText: "0",
sortText: SortText.LocationPriority,
};
return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: false, entries: [entry] };
}
@ -101,7 +124,22 @@ namespace ts.Completions {
const entries: CompletionEntry[] = [];
if (isUncheckedFile(sourceFile, compilerOptions)) {
const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target!, log, completionKind, preferences, propertyAccessToConvert, isJsxInitializer, recommendedCompletion, symbolToOriginInfoMap);
const uniqueNames = getCompletionEntriesFromSymbols(
symbols,
entries,
location,
sourceFile,
typeChecker,
compilerOptions.target!,
log,
completionKind,
preferences,
propertyAccessToConvert,
isJsxInitializer,
recommendedCompletion,
symbolToOriginInfoMap,
symbolToSortTextMap
);
getJSCompletionEntries(sourceFile, location!.pos, uniqueNames, compilerOptions.target!, entries); // TODO: GH#18217
}
else {
@ -109,7 +147,22 @@ namespace ts.Completions {
return undefined;
}
getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target!, log, completionKind, preferences, propertyAccessToConvert, isJsxInitializer, recommendedCompletion, symbolToOriginInfoMap);
getCompletionEntriesFromSymbols(
symbols,
entries,
location,
sourceFile,
typeChecker,
compilerOptions.target!,
log,
completionKind,
preferences,
propertyAccessToConvert,
isJsxInitializer,
recommendedCompletion,
symbolToOriginInfoMap,
symbolToSortTextMap
);
}
if (keywordFilters !== KeywordCompletionFilters.None) {
@ -160,7 +213,7 @@ namespace ts.Completions {
name: realName,
kind: ScriptElementKind.warning,
kindModifiers: "",
sortText: "1"
sortText: SortText.JavascriptIdentifiers
});
}
});
@ -169,28 +222,23 @@ namespace ts.Completions {
const completionNameForLiteral = (literal: string | number | PseudoBigInt) =>
typeof literal === "object" ? pseudoBigIntToString(literal) + "n" : JSON.stringify(literal);
function createCompletionEntryForLiteral(literal: string | number | PseudoBigInt): CompletionEntry {
return { name: completionNameForLiteral(literal), kind: ScriptElementKind.string, kindModifiers: ScriptElementKindModifier.none, sortText: "0" };
return { name: completionNameForLiteral(literal), kind: ScriptElementKind.string, kindModifiers: ScriptElementKindModifier.none, sortText: SortText.LocationPriority };
}
function createCompletionEntry(
symbol: Symbol,
sortText: SortText,
location: Node | undefined,
sourceFile: SourceFile,
typeChecker: TypeChecker,
target: ScriptTarget,
kind: CompletionKind,
name: string,
needsConvertPropertyAccess: boolean,
origin: SymbolOriginInfo | undefined,
recommendedCompletion: Symbol | undefined,
propertyAccessToConvert: PropertyAccessExpression | undefined,
isJsxInitializer: IsJsxInitializer | undefined,
preferences: UserPreferences,
): CompletionEntry | undefined {
const info = getCompletionEntryDisplayNameForSymbol(symbol, target, origin, kind);
if (!info) {
return undefined;
}
const { name, needsConvertPropertyAccess } = info;
let insertText: string | undefined;
let replacementSpan: TextSpan | undefined;
if (origin && origin.kind === SymbolOriginInfoKind.ThisType) {
@ -230,7 +278,7 @@ namespace ts.Completions {
name,
kind: SymbolDisplay.getSymbolKind(typeChecker, symbol, location!), // TODO: GH#18217
kindModifiers: SymbolDisplay.getSymbolModifiers(symbol),
sortText: "0",
sortText,
source: getSourceFromOrigin(origin),
hasAction: trueOrUndefined(!!origin && originIsExport(origin)),
isRecommended: trueOrUndefined(isRecommendedCompletionMatch(symbol, recommendedCompletion, typeChecker)),
@ -266,6 +314,7 @@ namespace ts.Completions {
isJsxInitializer?: IsJsxInitializer,
recommendedCompletion?: Symbol,
symbolToOriginInfoMap?: SymbolOriginInfoMap,
symbolToSortTextMap?: SymbolSortTextMap,
): Map<true> {
const start = timestamp();
// Tracks unique names.
@ -275,13 +324,30 @@ namespace ts.Completions {
const uniques = createMap<true>();
for (const symbol of symbols) {
const origin = symbolToOriginInfoMap ? symbolToOriginInfoMap[getSymbolId(symbol)] : undefined;
const entry = createCompletionEntry(symbol, location, sourceFile, typeChecker, target, kind, origin, recommendedCompletion, propertyAccessToConvert, isJsxInitializer, preferences);
if (!entry) {
const info = getCompletionEntryDisplayNameForSymbol(symbol, target, origin, kind);
if (!info) {
continue;
}
const { name, needsConvertPropertyAccess } = info;
if (uniques.has(name)) {
continue;
}
const { name } = entry;
if (uniques.has(name)) {
const entry = createCompletionEntry(
symbol,
symbolToSortTextMap && symbolToSortTextMap[getSymbolId(symbol)] || SortText.LocationPriority,
location,
sourceFile,
typeChecker,
name,
needsConvertPropertyAccess,
origin,
recommendedCompletion,
propertyAccessToConvert,
isJsxInitializer,
preferences
);
if (!entry) {
continue;
}
@ -321,7 +387,7 @@ namespace ts.Completions {
name,
kindModifiers: ScriptElementKindModifier.none,
kind: ScriptElementKind.label,
sortText: "0"
sortText: SortText.LocationPriority
});
}
}
@ -358,7 +424,7 @@ namespace ts.Completions {
// We don't need to perform character checks here because we're only comparing the
// name against 'entryName' (which is known to be good), not building a new
// completion entry.
return firstDefined<Symbol, SymbolCompletion>(symbols, (symbol): SymbolCompletion | undefined => { // TODO: Shouldn't need return type annotation (GH#12632)
return firstDefined(symbols, (symbol): SymbolCompletion | undefined => {
const origin = symbolToOriginInfoMap[getSymbolId(symbol)];
const info = getCompletionEntryDisplayNameForSymbol(symbol, compilerOptions.target!, origin, completionKind);
return info && info.name === entryId.name && getSourceFromOrigin(origin) === entryId.source
@ -512,6 +578,7 @@ namespace ts.Completions {
readonly previousToken: Node | undefined;
readonly isJsxInitializer: IsJsxInitializer;
readonly insideJsDocTagTypeExpression: boolean;
readonly symbolToSortTextMap: SymbolSortTextMap;
}
type Request = { readonly kind: CompletionDataKind.JsDocTagName | CompletionDataKind.JsDocTag } | { readonly kind: CompletionDataKind.JsDocParameterName, tag: JSDocParameterTag };
@ -804,6 +871,7 @@ namespace ts.Completions {
let keywordFilters = KeywordCompletionFilters.None;
let symbols: Symbol[] = [];
const symbolToOriginInfoMap: SymbolOriginInfoMap = [];
const symbolToSortTextMap: SymbolSortTextMap = [];
if (isRightOfDot) {
getTypeScriptMemberSymbols();
@ -853,7 +921,8 @@ namespace ts.Completions {
recommendedCompletion,
previousToken,
isJsxInitializer,
insideJsDocTagTypeExpression
insideJsDocTagTypeExpression,
symbolToSortTextMap
};
type JSDocTagWithTypeExpression = JSDocParameterTag | JSDocPropertyTag | JSDocReturnTag | JSDocTypeTag | JSDocTypedefTag;
@ -1054,6 +1123,12 @@ namespace ts.Completions {
const symbolMeanings = (isTypeOnly ? SymbolFlags.None : SymbolFlags.Value) | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias;
symbols = Debug.assertEachDefined(typeChecker.getSymbolsInScope(scopeNode, symbolMeanings), "getSymbolsInScope() should all be defined");
for (const symbol of symbols) {
if (!typeChecker.isArgumentsSymbol(symbol) &&
!some(symbol.declarations, d => d.getSourceFile() === sourceFile)) {
symbolToSortTextMap[getSymbolId(symbol)] = SortText.GlobalsOrKeywords;
}
}
// Need to insert 'this.' before properties of `this` type, so only do that if `includeInsertTextCompletions`
if (preferences.includeCompletionsWithInsertText && scopeNode.kind !== SyntaxKind.SourceFile) {
@ -1062,6 +1137,7 @@ namespace ts.Completions {
for (const symbol of getPropertiesForCompletion(thisType, typeChecker)) {
symbolToOriginInfoMap[getSymbolId(symbol)] = { kind: SymbolOriginInfoKind.ThisType };
symbols.push(symbol);
symbolToSortTextMap[getSymbolId(symbol)] = SortText.SuggestedClassMembers;
}
}
}
@ -1195,6 +1271,7 @@ namespace ts.Completions {
// So in `declare namespace foo {} declare module "foo" { export = foo; }`, there will just be the global completion for `foo`.
some(resolvedModuleSymbol.declarations, d => !!d.getSourceFile().externalModuleIndicator)) {
symbols.push(resolvedModuleSymbol);
symbolToSortTextMap[getSymbolId(resolvedModuleSymbol)] = SortText.AutoImportSuggestions;
symbolToOriginInfoMap[getSymbolId(resolvedModuleSymbol)] = { kind: SymbolOriginInfoKind.Export, moduleSymbol, isDefaultExport: false };
}
@ -1220,6 +1297,7 @@ namespace ts.Completions {
const origin: SymbolOriginInfoExport = { kind: SymbolOriginInfoKind.Export, moduleSymbol, isDefaultExport };
if (detailsEntryId || stringContainsCharactersInOrder(getSymbolName(symbol, origin, target).toLowerCase(), tokenTextLowerCase)) {
symbols.push(symbol);
symbolToSortTextMap[getSymbolId(symbol)] = SortText.AutoImportSuggestions;
symbolToOriginInfoMap[getSymbolId(symbol)] = origin;
}
}
@ -1941,7 +2019,7 @@ namespace ts.Completions {
name: tokenToString(i)!,
kind: ScriptElementKind.keyword,
kindModifiers: ScriptElementKindModifier.none,
sortText: "0"
sortText: SortText.GlobalsOrKeywords
});
}
return res;

View File

@ -21,7 +21,17 @@ namespace ts.Completions.StringCompletions {
return convertPathCompletions(completion.paths);
case StringLiteralCompletionKind.Properties: {
const entries: CompletionEntry[] = [];
getCompletionEntriesFromSymbols(completion.symbols, entries, sourceFile, sourceFile, checker, ScriptTarget.ESNext, log, CompletionKind.String, preferences); // Target will not be used, so arbitrary
getCompletionEntriesFromSymbols(
completion.symbols,
entries,
sourceFile,
sourceFile,
checker,
ScriptTarget.ESNext,
log,
CompletionKind.String,
preferences
); // Target will not be used, so arbitrary
return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: completion.hasIndexSignature, entries };
}
case StringLiteralCompletionKind.Types: {
@ -60,7 +70,7 @@ namespace ts.Completions.StringCompletions {
const isGlobalCompletion = false; // We don't want the editor to offer any other completions, such as snippets, inside a comment.
const isNewIdentifierLocation = true; // The user may type in a path that doesn't yet exist, creating a "new identifier" with respect to the collection of identifiers the server is aware of.
const entries = pathCompletions.map(({ name, kind, span, extension }): CompletionEntry =>
({ name, kind, kindModifiers: kindModifiersFromExtension(extension), sortText: "0", replacementSpan: span }));
({ name, kind, kindModifiers: kindModifiersFromExtension(extension), sortText: SortText.LocationPriority, replacementSpan: span }));
return { isGlobalCompletion, isMemberCompletion: false, isNewIdentifierLocation, entries };
}
function kindModifiersFromExtension(extension: Extension | undefined): ScriptElementKindModifier {

View File

@ -36,7 +36,7 @@ namespace ts.projectSystem {
kindModifiers: ScriptElementKindModifier.exportedModifier,
name: "foo",
replacementSpan: undefined,
sortText: "0",
sortText: Completions.SortText.AutoImportSuggestions,
source: "/a",
};
assert.deepEqual<protocol.CompletionInfo | undefined>(response, {

View File

@ -7,7 +7,7 @@
verify.completions({
marker: "",
includes: [
{ name: "__foo", kind: "warning" },
{ name: "___foo", kind: "warning" },
{ name: "__foo", kind: "warning", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "___foo", kind: "warning", sortText: completion.SortText.JavascriptIdentifiers },
],
});

View File

@ -5,8 +5,8 @@
verify.completions({
marker: "",
exact: [
{ name: "globalThis", kind: "module" },
completion.globalThisEntry,
...completion.globalsVars,
{ name: "undefined", kind: "var" }
]
completion.undefinedVarEntry
].map(e => ({ ...e, sortText: completion.SortText.LocationPriority }))
});

View File

@ -130,9 +130,9 @@ verify.completions(
marker: "InsideMethod",
exact: [
"arguments",
"globalThis",
completion.globalThisEntry,
"B", "C", "D", "D1", "D2", "D3", "D4", "D5", "D6", "E", "F", "F2", "G", "G2", "H", "I", "J", "K", "L", "L2", "M", "N", "O",
"undefined",
completion.undefinedVarEntry,
...completion.insideMethodKeywords,
],
},
@ -146,7 +146,9 @@ verify.completions(
"classThatStartedWritingIdentifierAfterPrivateModifier",
"classThatStartedWritingIdentifierAfterPrivateStaticModifier",
],
exact: ["private", "protected", "public", "static", "abstract", "async", "constructor", "get", "readonly", "set"],
exact: ["private", "protected", "public", "static", "abstract", "async", "constructor", "get", "readonly", "set"].map(
name => ({ name, sortText: completion.SortText.GlobalsOrKeywords })
),
isNewIdentifierLocation: true,
},
{

View File

@ -12,9 +12,25 @@
////function foo() {
/////*insideFunction*/
////}
const warnings = [
{ name: "classA", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "Test7", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "foo", sortText: completion.SortText.JavascriptIdentifiers }
];
verify.completions(
{ marker: "global", exact: completion.globalsInJsPlus(["foo", "classA", "Test7"]) },
{ marker: "class", isNewIdentifierLocation: true, exact: ["classA", "Test7", "foo", ...completion.classElementInJsKeywords] },
{ marker: "constructorParameter", isNewIdentifierLocation: true, exact: ["classA", "Test7", "foo"] },
{
marker: "class",
isNewIdentifierLocation: true,
exact: [
...warnings,
...completion.classElementInJsKeywords
]
},
{
marker: "constructorParameter",
isNewIdentifierLocation: true,
exact: warnings
},
{ marker: "insideFunction", exact: completion.globalsInJsInsideFunction(["foo", "classA", "Test7"]) },
);
);

View File

@ -16,7 +16,9 @@
verify.completions(
{
marker: ["1", "2"],
includes: ["async", "await"],
includes: ["async", "await"].map(
name => ({ name, sortText: completion.SortText.GlobalsOrKeywords })
),
excludes: ["public", "private", "protected", "constructor", "readonly", "static", "abstract", "get", "set"],
},
{ marker: ["3", "4"], exact: completion.classElementKeywords, isNewIdentifierLocation: true },

View File

@ -5,4 +5,4 @@
/////** @type {function (new: string, string): string} */
////var f = function () { return new/**/; }
verify.completions({ marker: "", includes: "new" });
verify.completions({ marker: "", includes: { name: "new", sortText: completion.SortText.JavascriptIdentifiers } });

View File

@ -4,4 +4,4 @@
/////** @type {function (this: string, string): string} */
////var f = function (s) { return this/**/; }
verify.completions({ marker: "", includes: "this" });
verify.completions({ marker: "", includes: { name: "this", sortText: completion.SortText.JavascriptIdentifiers } });

View File

@ -57,7 +57,7 @@
verify.completions(
{ marker: ["1", "2"], includes: ["constructor", "param", "type", "method", "template"] },
{ marker: ["3", "15", "16"], exact: [] },
{ marker: ["4", "5", "8"], includes: "number" },
{ marker: ["4", "5", "8"], includes: { name: "number", sortText: completion.SortText.GlobalsOrKeywords } },
{ marker: ["6", "7", "14"], exact: undefined },
{ marker: ["9", "10", "11", "12", "13"], includes: ["@argument", "@returns"] },
);

View File

@ -5,5 +5,9 @@
verify.completions({
marker: "1",
// TODO: should not include 'default' keyword at an expression location
includes: ["d", "defaultIsAnInvalidParameterName", "default"]
includes: [
"d",
"defaultIsAnInvalidParameterName",
{ name: "default", sortText: completion.SortText.GlobalsOrKeywords }
]
});

View File

@ -7,6 +7,6 @@ verify.completions({
includes: [
"defaultIsAnInvalidParameterName",
// This should probably stop working in the future.
{ name: "default", text: "default", kind: "keyword" },
{ name: "default", text: "default", kind: "keyword", sortText: completion.SortText.GlobalsOrKeywords },
],
});

View File

@ -7,4 +7,8 @@
////
////declare function foo<TString, TNumber>(obj: I<TString, TNumber>): { /*1*/ }
verify.completions({ marker: "1", exact: "readonly", isNewIdentifierLocation: true });
verify.completions({
marker: "1",
exact: { name: "readonly", sortText: completion.SortText.GlobalsOrKeywords },
isNewIdentifierLocation: true
});

View File

@ -11,7 +11,9 @@ verify.completions(
{ marker: "0", includes: { name: "myClass", text: "(local class) myClass", kind: "local class" } },
{
marker: "1",
exact: ["private", "protected", "public", "static", "abstract", "async", "constructor", "get", "readonly", "set"],
exact: ["private", "protected", "public", "static", "abstract", "async", "constructor", "get", "readonly", "set"].map(
name => ({ name, sortText: completion.SortText.GlobalsOrKeywords })
),
isNewIdentifierLocation: true,
},
}
);

View File

@ -7,4 +7,8 @@
////
////declare function foo<TString, TNumber>(obj: I<TString, TNumber>): { /*1*/
verify.completions({ marker: "1", exact: "readonly", isNewIdentifierLocation: true });
verify.completions({
marker: "1",
exact: { name: "readonly", sortText: completion.SortText.GlobalsOrKeywords } ,
isNewIdentifierLocation: true
});

View File

@ -47,6 +47,6 @@ verify.completions(
{ marker: "10", exact: completion.classElementKeywords, isGlobalCompletion: false, isNewIdentifierLocation: true },
{ marker: "13", exact: globals, isGlobalCompletion: false },
{ marker: "15", exact: globals, isGlobalCompletion: true, isNewIdentifierLocation: true },
{ marker: "16", exact: [...x, "globalThis", ...completion.globalsVars, "undefined"], isGlobalCompletion: false },
{ marker: "16", exact: [...x, completion.globalThisEntry, ...completion.globalsVars, completion.undefinedVarEntry], isGlobalCompletion: false },
{ marker: "17", exact: completion.globalKeywordsPlusUndefined, isGlobalCompletion: false },
);

View File

@ -4,4 +4,11 @@
/////**/
verify.completions({ marker: "", exact: ["globalThis", "undefined", ...completion.statementKeywordsWithTypes] });
verify.completions({
marker: "",
exact: [
completion.globalThisEntry,
completion.undefinedVarEntry,
...completion.statementKeywordsWithTypes
]
});

View File

@ -16,7 +16,7 @@
////var zz = </*typeExpr2*/point>{ x: 4, y: 3 };
const values: ReadonlyArray<FourSlashInterface.ExpectedCompletionEntry> = [
"globalThis",
completion.globalThisEntry,
{ name: "m2", text: "namespace m2" }, // With no type side, allowed only in value
{ name: "m3", text: "namespace m3" },
{ name: "xx", text: "var xx: number" },
@ -24,12 +24,12 @@ const values: ReadonlyArray<FourSlashInterface.ExpectedCompletionEntry> = [
{ name: "yy", text: "var yy: point" },
{ name: "kk", text: "var kk: m3.point3" },
{ name: "zz", text: "var zz: point" },
"undefined",
completion.undefinedVarEntry,
...completion.statementKeywordsWithTypes,
];
const types: ReadonlyArray<FourSlashInterface.ExpectedCompletionEntry> = [
"globalThis",
completion.globalThisEntry,
{ name: "m", text: "namespace m" },
{ name: "m3", text: "namespace m3" },
{ name: "point", text: "interface point" },

View File

@ -263,9 +263,9 @@ verify.completions(
{ name: "shwvar", text: "var shwvar: string" },
{ name: "shwcls", text: "class shwcls" },
"tmp",
"globalThis",
completion.globalThisEntry,
...commonValues,
"undefined",
completion.undefinedVarEntry,
...completion.statementKeywordsWithTypes,
],
}, {
@ -273,7 +273,7 @@ verify.completions(
exact: [
{ name: "shwcls", text: "class shwcls" },
{ name: "shwint", text: "interface shwint" },
"globalThis",
completion.globalThisEntry,
...commonTypes,
...completion.typeKeywords,
]
@ -284,12 +284,12 @@ verify.completions(
"Mod1",
"iMod1",
"tmp",
"globalThis",
completion.globalThisEntry,
{ name: "shwfn", text: "function shwfn(): void" },
...commonValues,
{ name: "shwcls", text: "class shwcls" },
{ name: "shwvar", text: "var shwvar: number" },
"undefined",
completion.undefinedVarEntry,
...completion.statementKeywordsWithTypes,
],
},
@ -298,7 +298,7 @@ verify.completions(
exact: [
"Mod1",
"iMod1",
"globalThis",
completion.globalThisEntry,
...commonTypes,
{ name: "shwcls", text: "class shwcls" },
{ name: "shwint", text: "interface shwint" },

View File

@ -328,7 +328,7 @@ verifyGeneral('class', {
// from interface in mod1
verify.completions({
marker: "interface",
exact: "readonly",
exact: { name: "readonly", sortText: completion.SortText.GlobalsOrKeywords },
isNewIdentifierLocation: true,
});
@ -376,7 +376,14 @@ verifyGeneral('exportedClass', {
});
// from exported interface in mod1
verify.completions({ marker: "exportedInterface", exact: ["readonly"], isNewIdentifierLocation: true });
verify.completions({
marker: "exportedInterface",
exact: [{
name: "readonly",
sortText: completion.SortText.GlobalsOrKeywords
}],
isNewIdentifierLocation: true
});
// from exported namespace in mod1
verifyExportedNamespace('exportedNamespace');

View File

@ -256,7 +256,7 @@ verify.completions(
// from interface scope
{
marker: "interface",
exact: ["readonly"],
exact: [{ name: "readonly", sortText: completion.SortText.GlobalsOrKeywords }],
isNewIdentifierLocation: true,
}
);

View File

@ -5,4 +5,10 @@
//// var n: num/**/
////}
verify.completions({ marker: "", includes: "number" });
verify.completions({
marker: "",
includes: {
name: "number",
sortText: completion.SortText.GlobalsOrKeywords
}
});

View File

@ -18,5 +18,5 @@ verify.completions(
{ marker: ["a", "b"], exact: undefined, isNewIdentifierLocation: true },
{ marker: ["c", "d"], exact: ["baseMethod"], isNewIdentifierLocation: true },
{ marker: "e", exact: ["baseMethod"] },
{ marker: "f", includes: ["Number"] },
{ marker: "f", includes: [{ name: "Number", sortText: completion.SortText.GlobalsOrKeywords }] },
);

View File

@ -25,6 +25,7 @@ verify.completions({
kind: "const",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -21,6 +21,7 @@ verify.completions({
source: "/a",
sourceDisplay: "./a",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
{
name: "bar",
@ -28,6 +29,7 @@ verify.completions({
source: "/a",
sourceDisplay: "./a",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
],
preferences: {

View File

@ -33,9 +33,22 @@
////const a = import("./a"); // Does not make this an external module
////fo/*dts*/
verify.completions({ marker: ["b"], excludes: "foo", preferences: { includeCompletionsForModuleExports: true } });
verify.completions({
marker: ["b"],
excludes: "foo",
preferences: { includeCompletionsForModuleExports: true }
});
verify.completions({
marker: ["c", "ccheck", "cts", "d", "dcheck", "dts"],
includes: [{ name: "foo", source: "/node_modules/a/index", text: "const foo: 0", kind: "const", kindModifiers: "export,declare", hasAction: true, sourceDisplay: "a" }],
includes: [{
name: "foo",
source: "/node_modules/a/index",
text: "const foo: 0",
kind: "const",
kindModifiers: "export,declare",
hasAction: true,
sourceDisplay: "a",
sortText: completion.SortText.AutoImportSuggestions
}],
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -22,6 +22,7 @@ verify.completions({
kind: "const",
kindModifiers: "export,declare",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -18,6 +18,7 @@ verify.completions({
kind: "function",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -17,6 +17,7 @@ verify.completions({
kind: "function",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -17,6 +17,7 @@ verify.completions({
kind: "function",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -14,10 +14,26 @@
goTo.marker("0");
const preferences: FourSlashInterface.UserPreferences = { includeCompletionsForModuleExports: true };
verify.completions(
{ marker: "0", exact: ["globalThis", "undefined", ...completion.statementKeywordsWithTypes], preferences },
{
marker: "0",
exact: [
completion.globalThisEntry,
completion.undefinedVarEntry,
...completion.statementKeywordsWithTypes
],
preferences
},
{
marker: "1",
includes: { name: "fooBar", source: "/src/foo-bar", sourceDisplay: "./foo-bar", text: "(property) default: 0", kind: "property", hasAction: true },
includes: {
name: "fooBar",
source: "/src/foo-bar",
sourceDisplay: "./foo-bar",
text: "(property) default: 0",
kind: "property",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences,
},
);

View File

@ -18,6 +18,7 @@ verify.completions({
kind: "function",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -14,7 +14,15 @@
goTo.marker("");
verify.completions({
marker: "",
includes: { name: "foo", source: "/a", sourceDisplay: "./a", text: "(alias) const foo: 0\nexport default foo", kind: "alias", hasAction: true },
includes: {
name: "foo",
source: "/a",
sourceDisplay: "./a",
text: "(alias) const foo: 0\nexport default foo",
kind: "alias",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});
verify.applyCodeActionFromCompletion("", {

View File

@ -25,6 +25,7 @@ verify.completions({
kind: "class",
kindModifiers: "export,declare",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -17,12 +17,22 @@ const preferences: FourSlashInterface.UserPreferences = { includeCompletionsForM
verify.completions(
{
marker: "0",
includes: { name: "a", source: "/a", hasAction: true, },
includes: {
name: "a",
source: "/a",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences,
},
{
marker: "1",
includes: { name: "b", source: "/a", hasAction: true },
includes: {
name: "b",
source: "/a",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences,
}
);

View File

@ -18,7 +18,7 @@
verify.completions({
marker: "",
// Tester will assert that it is only included once
includes: [{ name: "foo", source: "a", hasAction: true }],
includes: [{ name: "foo", source: "a", hasAction: true, sortText: completion.SortText.AutoImportSuggestions }],
preferences: {
includeCompletionsForModuleExports: true,
}

View File

@ -12,9 +12,26 @@
goTo.marker("0");
const preferences: FourSlashInterface.UserPreferences = { includeCompletionsForModuleExports: true };
const exportEntry: FourSlashInterface.ExpectedCompletionEntryObject = { name: "fooBar", source: "/src/foo-bar", sourceDisplay: "./foo-bar", text: "(property) export=: 0", kind: "property", hasAction: true };
const exportEntry: FourSlashInterface.ExpectedCompletionEntryObject = {
name: "fooBar",
source: "/src/foo-bar",
sourceDisplay: "./foo-bar",
text: "(property) export=: 0",
kind: "property",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
};
verify.completions(
{ marker: "0", exact: ["globalThis", "undefined", exportEntry, ...completion.statementKeywordsWithTypes], preferences },
{
marker: "0",
exact: [
completion.globalThisEntry,
completion.undefinedVarEntry,
exportEntry,
...completion.statementKeywordsWithTypes
],
preferences
},
{ marker: "1", includes: exportEntry, preferences }
);
verify.applyCodeActionFromCompletion("0", {

View File

@ -21,6 +21,7 @@ verify.completions({
sourceDisplay: "./a",
text: "class C",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
{
name: "T",
@ -28,6 +29,7 @@ verify.completions({
sourceDisplay: "./a",
text: "type T = number",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
],
excludes: "x",

View File

@ -34,8 +34,17 @@ verify.completions(
{
marker: "unique",
exact: [
"globalThis", ...completion.globalsVars, "undefined",
{ name: "unique", source: "/a", sourceDisplay: "./a", text: "(alias) const unique: 0\nexport unique", hasAction: true },
completion.globalThisEntry,
...completion.globalsVars,
completion.undefinedVarEntry,
{
name: "unique",
source: "/a",
sourceDisplay: "./a",
text: "(alias) const unique: 0\nexport unique",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
...completion.globalKeywords.filter(e => e.name !== "unique"),
],
preferences,

View File

@ -17,7 +17,16 @@
verify.completions({
marker: "",
includes: ["bdf", "abcdef", "BDF"].map(name =>
({ name, source: "/a", text: `function ${name}(): void`, hasAction: true, kind: "function", kindModifiers: "export", sourceDisplay: "./a" })),
({
name,
source: "/a",
text: `function ${name}(): void`,
hasAction: true,
kind: "function",
kindModifiers: "export",
sourceDisplay: "./a",
sortText: completion.SortText.AutoImportSuggestions
})),
excludes: ["abcde", "dbf"],
preferences: { includeCompletionsForModuleExports: true },
})

View File

@ -20,9 +20,15 @@ goTo.marker("");
verify.completions({
marker: "",
exact: [
"globalThis",
{ name: "foo", text: "var foo: number", kind: "var", kindModifiers: "declare" },
"undefined",
completion.globalThisEntry,
{
name: "foo",
text: "var foo: number",
kind: "var",
kindModifiers: "declare",
sortText: completion.SortText.GlobalsOrKeywords
},
completion.undefinedVarEntry,
{
name: "foo",
source: "/a",
@ -31,6 +37,7 @@ verify.completions({
kind: "const",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
{
name: "foo",
@ -40,6 +47,7 @@ verify.completions({
kind: "const",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
...completion.statementKeywordsWithTypes,
],

View File

@ -18,6 +18,7 @@ verify.completions({
kind: "function",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -13,10 +13,23 @@
verify.completions({
marker: "",
exact: [
{ name: "Test2", text: "(alias) function Test2(): void\nimport Test2", kind: "alias" },
"globalThis",
"undefined",
{ name: "Test1", source: "/a", sourceDisplay: "./a", text: "function Test1(): void", kind: "function", kindModifiers: "export", hasAction: true },
{
name: "Test2",
text: "(alias) function Test2(): void\nimport Test2",
kind: "alias"
},
completion.globalThisEntry,
completion.undefinedVarEntry,
{
name: "Test1",
source: "/a",
sourceDisplay: "./a",
text: "function Test1(): void",
kind: "function",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
...completion.statementKeywordsWithTypes,
],
preferences: { includeCompletionsForModuleExports: true },

View File

@ -21,6 +21,7 @@ verify.completions({
kind: "const",
kindModifiers: "export,declare",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -26,6 +26,7 @@ verify.completions({
kind: "const",
kindModifiers: "export,declare",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -17,6 +17,7 @@ verify.completions({
kind: "function",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -26,6 +26,7 @@ for (const [marker, sourceDisplay] of [["0", "./src"], ["1", "./a"], ["2", "../a
kind: "const",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -22,8 +22,16 @@
verify.completions({
marker: "",
includes: [
"undefined",
{ name: "foo", source: "/a", sourceDisplay: "./a", text: "(alias) const foo: 0\nexport foo", kind: "alias", hasAction: true },
completion.undefinedVarEntry,
{
name: "foo",
source: "/a",
sourceDisplay: "./a",
text: "(alias) const foo: 0\nexport foo",
kind: "alias",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
...completion.statementKeywordsWithTypes,
],
preferences: { includeCompletionsForModuleExports: true },

View File

@ -19,9 +19,18 @@
verify.completions({
marker: "",
exact: [
"globalThis",
"undefined",
{ name: "foo", source: "/foo/lib/foo", sourceDisplay: "./foo", text: "const foo: 0", kind: "const", kindModifiers: "export", hasAction: true },
completion.globalThisEntry,
completion.undefinedVarEntry,
{
name: "foo",
source: "/foo/lib/foo",
sourceDisplay: "./foo",
text: "const foo: 0",
kind: "const",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
...completion.statementKeywordsWithTypes,
],
preferences: { includeCompletionsForModuleExports: true },

View File

@ -17,6 +17,7 @@ verify.completions({
kind: "function",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -15,9 +15,9 @@
verify.completions({
marker: "",
exact: [
"globalThis",
completion.globalThisEntry,
...completion.globalsVars,
"undefined",
completion.undefinedVarEntry,
{
name: "foo",
source: "/a/b/impl",
@ -26,6 +26,7 @@ verify.completions({
kind: "function",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
{
name: "foo",
@ -34,6 +35,7 @@ verify.completions({
text: "(alias) function foo(): void\nexport foo",
kind: "alias",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
...completion.globalKeywords,
],

View File

@ -15,8 +15,22 @@ goTo.marker("");
verify.completions({
marker: "",
includes: [
{ name: "x", source: "/a", sourceDisplay: "./a", text: "const x: 0", hasAction: true },
{ name: "y", source: "/index", sourceDisplay: ".", text: "(alias) const y: 0\nexport y", hasAction: true },
{
name: "x",
source: "/a",
sourceDisplay: "./a",
text: "const x: 0",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
{
name: "y",
source: "/index",
sourceDisplay: ".",
text: "(alias) const y: 0\nexport y",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
],
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -19,6 +19,7 @@ verify.completions({
kind: "const",
kindModifiers: "export",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -1,16 +1,24 @@
/// <reference path="fourslash.ts" />
// @noLib: true
// @Filename: /a.ts
////export const foo = 0;
// @Filename: /b.ts
////const foo = 1;
////fo/**/
verify.completions({
marker: "",
exact: ["globalThis", { name: "foo", text: "const foo: 1" }, "undefined", ...completion.statementKeywordsWithTypes],
preferences: { includeCompletionsForModuleExports: true },
});
/// <reference path="fourslash.ts" />
// @noLib: true
// @Filename: /a.ts
////export const foo = 0;
// @Filename: /b.ts
////const foo = 1;
////fo/**/
verify.completions({
marker: "",
exact: [
completion.globalThisEntry,
{
name: "foo",
text: "const foo: 1",
},
completion.undefinedVarEntry,
...completion.statementKeywordsWithTypes
],
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -12,7 +12,7 @@
verify.completions({
marker: "",
includes: { name: "Foo", source: "/a", hasAction: true },
includes: { name: "Foo", source: "/a", hasAction: true, sortText: completion.SortText.AutoImportSuggestions },
excludes: "Bar",
preferences: {
includeCompletionsForModuleExports: true,

View File

@ -13,4 +13,11 @@
////interface EndOfFile { f; /*e*/
verify.completions({ marker: test.markers(), exact: "readonly", isNewIdentifierLocation: true });
verify.completions({
marker: test.markers(),
exact: {
name: "readonly",
sortText: completion.SortText.GlobalsOrKeywords
},
isNewIdentifierLocation: true
});

View File

@ -4,4 +4,10 @@
// @Filename: /a.js
////const x = /** @type {{ s: string }} */ ({ /**/ });
verify.completions({ marker: "", exact: ["s", "x"] });
verify.completions({
marker: "",
exact: [
"s",
{ name: "x", sortText: completion.SortText.JavascriptIdentifiers }
]
});

View File

@ -9,8 +9,8 @@ verify.completions({
marker: "",
includes: [
{ name: "x", text: "(parameter) x: number", kind: "parameter", insertText: "{x}" },
{ name: "p", text: "(JSX attribute) p: number", kind: "JSX attribute", insertText: "{this.p}" },
{ name: "a b", text: '(JSX attribute) "a b": number', kind: "JSX attribute", insertText: '{this["a b"]}' },
{ name: "p", text: "(JSX attribute) p: number", kind: "JSX attribute", insertText: "{this.p}", sortText: completion.SortText.SuggestedClassMembers },
{ name: "a b", text: '(JSX attribute) "a b": number', kind: "JSX attribute", insertText: '{this["a b"]}', sortText: completion.SortText.SuggestedClassMembers },
],
preferences: {
includeInsertTextCompletions: true,

View File

@ -7,5 +7,5 @@
verify.completions(
{ marker: "a", exact: undefined },
{ marker: ["b", "c"], includes: "extends" },
{ marker: ["b", "c"], includes: { name: "extends", sortText: completion.SortText.GlobalsOrKeywords } },
);

View File

@ -28,6 +28,7 @@ const classEntry = (isConstructor: boolean): FourSlashInterface.ExpectedCompleti
text: isConstructor ? "constructor Cls(): Cls" : "class Cls",
hasAction: true,
isRecommended: true,
sortText: completion.SortText.AutoImportSuggestions
});
verify.completions(
{ marker: "b0", includes: classEntry(true), preferences },

View File

@ -38,6 +38,7 @@ verify.completions(
kindModifiers: "export",
hasAction: true,
isRecommended: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
},

View File

@ -14,15 +14,15 @@ verify.completions(
{
marker: "",
includes: [
{ name: "xyz", text: "(method) C.xyz(): any", kind: "method", insertText: "this.xyz" },
{ name: "foo bar", text: '(property) C["foo bar"]: number', kind: "property", insertText: 'this["foo bar"]' },
{ name: "xyz", text: "(method) C.xyz(): any", kind: "method", insertText: "this.xyz", sortText: completion.SortText.SuggestedClassMembers },
{ name: "foo bar", text: '(property) C["foo bar"]: number', kind: "property", insertText: 'this["foo bar"]', sortText: completion.SortText.SuggestedClassMembers },
],
isNewIdentifierLocation: true,
preferences,
},
{
marker: "f",
includes: { name: "x", text: "(property) x: number", kind: "property", insertText: "this.x" },
includes: { name: "x", text: "(property) x: number", kind: "property", insertText: "this.x", sortText: completion.SortText.SuggestedClassMembers },
preferences,
},
);

View File

@ -6,5 +6,5 @@
verify.completions({
marker: "",
exact: ["globalThis", "T", ...completion.typeKeywords],
exact: [completion.globalThisEntry, "T", ...completion.typeKeywords],
});

View File

@ -12,7 +12,7 @@ verify.completions({
marker: "1",
exact: [
{ name: "__property", text: "(property) MyObject.__property: number" },
"MyObject",
"instance",
{ name: "MyObject", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "instance", sortText: completion.SortText.JavascriptIdentifiers },
],
});

View File

@ -528,6 +528,7 @@ declare namespace FourSlashInterface {
readonly isRecommended?: boolean;
readonly kind?: string;
readonly kindModifiers?: string;
readonly sortText?: completion.SortText;
// details
readonly text?: string;
@ -650,6 +651,15 @@ declare var cancellation: FourSlashInterface.cancellation;
declare var classification: typeof FourSlashInterface.classification;
declare namespace completion {
type Entry = FourSlashInterface.ExpectedCompletionEntryObject;
export const enum SortText {
LocationPriority = "0",
SuggestedClassMembers = "1",
GlobalsOrKeywords = "2",
AutoImportSuggestions = "3",
JavascriptIdentifiers = "4"
}
export const globalThisEntry: Entry;
export const undefinedVarEntry: Entry;
export const globals: ReadonlyArray<Entry>;
export const globalsInJs: ReadonlyArray<Entry>;
export const globalKeywords: ReadonlyArray<Entry>;

View File

@ -26,5 +26,5 @@
verify.completions(
{ marker: "1", includes: { name: "charCodeAt", kind: "method", kindModifiers: "declare" } },
{ marker: ["2", "3", "4"], includes: { name: "toExponential", kind: "method", kindModifiers: "declare" } },
{ marker: "5", includes: { name: "test1", kind: "warning" } },
{ marker: "5", includes: { name: "test1", kind: "warning", sortText: completion.SortText.JavascriptIdentifiers } },
);

View File

@ -14,6 +14,21 @@
////file2Identifier2./*2*/
verify.completions(
{ marker: "1", includes: ["file2Identifier1", "file2Identifier2", "file1Identifier"], excludes: "FooProp" },
{ marker: "2", includes: ["file2Identifier1", "file2Identifier2"], excludes: ["file1Identifier", "FooProp"] },
)
{
marker: "1",
includes: [
"file2Identifier1",
"file2Identifier2",
{ name: "file1Identifier", sortText: completion.SortText.GlobalsOrKeywords }
],
excludes: "FooProp"
},
{
marker: "2",
includes: [
{ name: "file2Identifier1", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "file2Identifier2", sortText: completion.SortText.JavascriptIdentifiers }
],
excludes: ["file1Identifier", "FooProp"]
},
);

View File

@ -22,6 +22,16 @@
verify.completions(
{ marker: "1", includes: "toExponential" },
{ marker: "2", includes: "toLowerCase" },
{ marker: "3", exact: ["V", "ref1", "ref2", "require", "v", "x"] },
{
marker: "3",
exact: [
"V",
{ name: "ref1", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "ref2", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "require", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "v", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "x", sortText: completion.SortText.JavascriptIdentifiers }
]
},
{ marker: "4", includes: "toLowerCase" },
);

View File

@ -19,5 +19,12 @@
verify.completions({
marker: "",
exact: ["getName", "getNa", ...completion.functionMembersWithPrototype, "Person", "name", "age"],
exact: [
"getName",
"getNa",
...completion.functionMembersWithPrototype,
{ name: "Person", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "name", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "age", sortText: completion.SortText.JavascriptIdentifiers }
],
});

View File

@ -12,4 +12,4 @@
////
//// hello/**/
verify.completions({ includes: "helloWorld" });
verify.completions({ includes: { name: "helloWorld", sortText: completion.SortText.JavascriptIdentifiers } });

View File

@ -19,7 +19,7 @@ edit.insert('.');
verify.completions({
exact: [
...["n", "s", "b"].map(name => ({ name, kind: "property" })),
...["x", "require"].map(name => ({ name, kind: "warning" })),
...["x", "require"].map(name => ({ name, kind: "warning", sortText: completion.SortText.JavascriptIdentifiers })),
],
});
edit.insert('n.');

View File

@ -14,7 +14,18 @@
//// inst2.blah/*b*/;
goTo.marker('a');
verify.completions({ exact: ["property", "TestObj", "constructor", "instance", "class2", "prototype", "blah", "inst2"] });
verify.completions({
exact: [
"property",
{ name: "TestObj", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "constructor", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "instance", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "class2", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "prototype", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "blah", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "inst2", sortText: completion.SortText.JavascriptIdentifiers }
]
});
edit.backspace();
goTo.marker('b');

View File

@ -19,7 +19,15 @@
goTo.marker();
edit.insert('.');
verify.completions({ exact: ["bar", "thing", "union", "Foo", "x"] });
verify.completions({
exact: [
"bar",
"thing",
"union",
{ name: "Foo", sortText: completion.SortText.JavascriptIdentifiers },
{ name: "x", sortText: completion.SortText.JavascriptIdentifiers }
]
});
edit.insert('bar.');
verify.completions({ includes: ["substr"] });

View File

@ -27,7 +27,45 @@
//// /*5*/
verify.completions(
{ marker: "1", includes: ["x", "a", "b"], excludes: "y" },
{ marker: "2", includes: ["y", "a", "b"], excludes: "x" },
{ marker: ["3", "4", "5"], includes: ["a", "b"], excludes: ["x", "y"] },
{
marker: "1",
includes: [
"x",
{ name: "a", sortText: completion.SortText.GlobalsOrKeywords },
{ name: "b", sortText: completion.SortText.GlobalsOrKeywords }
], excludes: "y"
},
{
marker: "2",
includes: [
"y",
{ name: "a", sortText: completion.SortText.GlobalsOrKeywords },
{ name: "b", sortText: completion.SortText.GlobalsOrKeywords }
],
excludes: "x"
},
{
marker: "3",
includes: [
"a",
{ name: "b", sortText: completion.SortText.GlobalsOrKeywords }
],
excludes: ["x", "y"]
},
{
marker: "4",
includes: [
{ name: "a", sortText: completion.SortText.GlobalsOrKeywords },
"b"
],
excludes: ["x", "y"]
},
{
marker: ["5"],
includes: [
{ name: "a", sortText: completion.SortText.GlobalsOrKeywords },
{ name: "b", sortText: completion.SortText.GlobalsOrKeywords }
],
excludes: ["x", "y"]
},
);

View File

@ -19,7 +19,11 @@
goTo.file('consumer.js');
goTo.marker();
verify.completions({ marker: "", includes: "y", excludes: "invisible" });
verify.completions({
marker: "",
includes: { name: "y", sortText: completion.SortText.GlobalsOrKeywords },
excludes: "invisible"
});
edit.insert('x.');
verify.completions({ includes: { name: "a", kind: "property" } });

View File

@ -21,4 +21,8 @@
//// var x = require('myMod');
//// /**/;
verify.completions({ marker: "", includes: "y", excludes: "invisible" });
verify.completions({
marker: "",
includes: { name: "y", sortText: completion.SortText.GlobalsOrKeywords },
excludes: "invisible"
});

View File

@ -18,7 +18,7 @@ edit.insert('.');
verify.completions({
exact: [
...["n", "s", "b"].map(name => ({ name, kind: "property" })),
...["x", "require"].map(name => ({ name, kind: "warning" })),
...["x", "require"].map(name => ({ name, kind: "warning", sortText: completion.SortText.JavascriptIdentifiers })),
],
});
edit.insert('n.');

View File

@ -17,7 +17,11 @@
goTo.file('consumer.js');
goTo.marker();
verify.completions({ marker: "", includes: "y", excludes: "invisible" });
verify.completions({
marker: "",
includes: { name: "y", sortText: completion.SortText.GlobalsOrKeywords },
excludes: "invisible"
});
edit.insert('x.');
verify.completions({ includes: { name: "a", kind: "property" } });

View File

@ -31,4 +31,4 @@ verify.completions({ includes: { name: "toFixed", kind: "method", kindModifiers:
goTo.marker('3');
edit.insert('.');
// Make sure symbols don't leak out into the constructor
verify.completions({ includes: ["qua", "foo", "bar"].map(name => ({ name, kind: "warning" })) });
verify.completions({ includes: ["qua", "foo", "bar"].map(name => ({ name, kind: "warning", sortText: completion.SortText.JavascriptIdentifiers })) });

View File

@ -22,6 +22,10 @@ verify.completions({
{ name: "qua", kind: "property" },
{ name: "foo", kind: "method" },
{ name: "bar", kind: "method" },
...["myCtor", "x", "prototype"].map(name => ({ name, kind: "warning" })),
...["myCtor", "x", "prototype"].map(name => ({
name,
kind: "warning",
sortText: completion.SortText.JavascriptIdentifiers
})),
],
});

View File

@ -16,4 +16,7 @@ goTo.marker('1');
edit.insert('.');
// Check members of the function
verify.completions({ includes: ["foo", "bar", "qua"].map(name => ({ name, kind: "warning" })) });
verify.completions({
includes: ["foo", "bar", "qua"].map(
name => ({ name, kind: "warning", sortText: completion.SortText.JavascriptIdentifiers }))
});

View File

@ -9,4 +9,8 @@
//// import * as mod from "./mod"
//// mod./**/
verify.completions({ marker: "", exact: [{ name: "a", kind: "property" }, { name: "mod", kind: "warning" }] });
verify.completions({
marker: "", exact: [
{ name: "a", kind: "property" },
{ name: "mod", kind: "warning", sortText: completion.SortText.JavascriptIdentifiers }]
});

View File

@ -10,4 +10,10 @@
//// import mod from "./mod"
//// mod./**/
verify.completions({ marker: "", exact: [{ name: "a", kind: "property" }, { name: "mod", kind: "warning" }] });
verify.completions({
marker: "",
exact: [
{ name: "a", kind: "property" },
{ name: "mod", kind: "warning", sortText: completion.SortText.JavascriptIdentifiers }
]
});

View File

@ -29,7 +29,7 @@ const typeMembers: ReadonlyArray<FourSlashInterface.ExpectedCompletionEntryObjec
{ name: "O", kind: "module", kindModifiers: "export" },
];
function warnings(entries: ReadonlyArray<FourSlashInterface.ExpectedCompletionEntryObject>): ReadonlyArray<FourSlashInterface.ExpectedCompletionEntry> {
return entries.map(e => ({ ...e, kind: "warning", kindModifiers: undefined }));
return entries.map(e => ({ ...e, kind: "warning", kindModifiers: undefined, sortText: completion.SortText.JavascriptIdentifiers }));
}
verify.completions(

View File

@ -28,10 +28,10 @@ function getCompletions(nonWarnings: ReadonlyArray<string>): ReadonlyArray<FourS
{ name: "property1", kind: "property" },
{ name: "method3", kind: "method" },
{ name: "method4", kind: "method" },
{ name: "foo", kind: "warning" },
{ name: "foo", kind: "warning", sortText: completion.SortText.JavascriptIdentifiers },
];
for (const name of nonWarnings) ts.Debug.assert(withKinds.some(entry => entry.name === name));
return withKinds.map(entry => nonWarnings.includes(entry.name) ? entry : ({ name: entry.name, kind: "warning" }));
return withKinds.map(entry => nonWarnings.includes(entry.name) ? entry : ({ name: entry.name, kind: "warning", sortText: completion.SortText.JavascriptIdentifiers }));
}
verify.completions(

View File

@ -31,7 +31,7 @@
////Foo./*valueMemberOfFoo*/;
const warnings = (names: ReadonlyArray<string>): ReadonlyArray<FourSlashInterface.ExpectedCompletionEntry> =>
names.map(name => ({ name, kind: "warning" }));
names.map(name => ({ name, kind: "warning", sortText: completion.SortText.JavascriptIdentifiers }));
verify.completions(
{

View File

@ -32,6 +32,7 @@ goTo.eachMarker(() => {
kind: "const",
kindModifiers: "export,declare",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});
@ -45,6 +46,7 @@ goTo.eachMarker(() => {
kind: "const",
kindModifiers: "export,declare",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
},
preferences: { includeCompletionsForModuleExports: true },
});

View File

@ -17,5 +17,5 @@
verify.completions(
{ marker: ["1", "3"], includes: ["charAt", "toExponential"] },
{ marker: "2", includes: "age" },
{ marker: "2", includes: { name: "age", sortText: completion.SortText.JavascriptIdentifiers } },
);

View File

@ -18,4 +18,4 @@
for (var i = 1; i <= 10; i++) {
verify.completions({ marker: String(i), exact: undefined });
}
verify.completions({ marker: "end", includes: "null" });
verify.completions({ marker: "end", includes: { name: "null", sortText: completion.SortText.GlobalsOrKeywords } });

View File

@ -5,7 +5,20 @@
////[].map<numb/*b*/;
////1 < Infini/*c*/;
verify.completions(
{ marker: ["a", "b"], includes: "number", excludes: "SVGNumber" },
{ marker: "c", includes: "Infinity" },
verify.completions(
{
marker: ["a", "b"],
includes: {
name: "number",
sortText: completion.SortText.GlobalsOrKeywords
},
excludes: "SVGNumber"
},
{
marker: "c",
includes: {
name: "Infinity",
sortText: completion.SortText.GlobalsOrKeywords
}
},
);

View File

@ -3,4 +3,4 @@
//@Filename: file.tsx
//// var x = </**/;
verify.completions({ marker: "", exact: ["globalThis", ...completion.globalsVars, "x", "undefined"] });
verify.completions({ marker: "", exact: [completion.globalThisEntry, ...completion.globalsVars, "x", completion.undefinedVarEntry] });