parent
da48790dac
commit
f829f958a2
4 changed files with 314 additions and 4 deletions
|
@ -4555,6 +4555,9 @@ namespace FourSlashInterface {
|
|||
export const classElementKeywords: ReadonlyArray<ExpectedCompletionEntryObject> =
|
||||
["private", "protected", "public", "static", "abstract", "async", "constructor", "get", "readonly", "set"].map(keywordEntry);
|
||||
|
||||
export const classElementInJsKeywords: ReadonlyArray<ExpectedCompletionEntryObject> =
|
||||
["async", "constructor", "get", "set"].map(keywordEntry);
|
||||
|
||||
export const constructorParameterKeywords: ReadonlyArray<ExpectedCompletionEntryObject> =
|
||||
["private", "protected", "public", "readonly"].map((name): ExpectedCompletionEntryObject => ({ name, kind: "keyword" }));
|
||||
|
||||
|
@ -4692,6 +4695,59 @@ namespace FourSlashInterface {
|
|||
}
|
||||
});
|
||||
|
||||
export const statementInJsKeywords: ReadonlyArray<ExpectedCompletionEntryObject> = [
|
||||
"break",
|
||||
"case",
|
||||
"catch",
|
||||
"class",
|
||||
"const",
|
||||
"continue",
|
||||
"debugger",
|
||||
"default",
|
||||
"delete",
|
||||
"do",
|
||||
"else",
|
||||
"enum",
|
||||
"export",
|
||||
"extends",
|
||||
"false",
|
||||
"finally",
|
||||
"for",
|
||||
"function",
|
||||
"if",
|
||||
"import",
|
||||
"in",
|
||||
"instanceof",
|
||||
"new",
|
||||
"null",
|
||||
"return",
|
||||
"super",
|
||||
"switch",
|
||||
"this",
|
||||
"throw",
|
||||
"true",
|
||||
"try",
|
||||
"typeof",
|
||||
"var",
|
||||
"void",
|
||||
"while",
|
||||
"with",
|
||||
"implements",
|
||||
"interface",
|
||||
"let",
|
||||
"package",
|
||||
"yield",
|
||||
"as",
|
||||
"async",
|
||||
"await",
|
||||
"constructor",
|
||||
"get",
|
||||
"require",
|
||||
"set",
|
||||
"from",
|
||||
"of",
|
||||
].map(keywordEntry);
|
||||
|
||||
export const globalsVars: ReadonlyArray<ExpectedCompletionEntryObject> = [
|
||||
functionEntry("eval"),
|
||||
functionEntry("parseInt"),
|
||||
|
@ -4793,6 +4849,60 @@ namespace FourSlashInterface {
|
|||
...globalKeywordsInsideFunction,
|
||||
];
|
||||
|
||||
const globalInJsKeywordsInsideFunction: ReadonlyArray<ExpectedCompletionEntryObject> = [
|
||||
"break",
|
||||
"case",
|
||||
"catch",
|
||||
"class",
|
||||
"const",
|
||||
"continue",
|
||||
"debugger",
|
||||
"default",
|
||||
"delete",
|
||||
"do",
|
||||
"else",
|
||||
"export",
|
||||
"extends",
|
||||
"false",
|
||||
"finally",
|
||||
"for",
|
||||
"function",
|
||||
"if",
|
||||
"import",
|
||||
"in",
|
||||
"instanceof",
|
||||
"new",
|
||||
"null",
|
||||
"return",
|
||||
"super",
|
||||
"switch",
|
||||
"this",
|
||||
"throw",
|
||||
"true",
|
||||
"try",
|
||||
"typeof",
|
||||
"var",
|
||||
"void",
|
||||
"while",
|
||||
"with",
|
||||
"implements",
|
||||
"let",
|
||||
"package",
|
||||
"yield",
|
||||
"async",
|
||||
"await",
|
||||
].map(keywordEntry);
|
||||
|
||||
// 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" },
|
||||
...globalsVars,
|
||||
...plus,
|
||||
{ name: "undefined", kind: "var" },
|
||||
...globalInJsKeywordsInsideFunction,
|
||||
];
|
||||
|
||||
// TODO: many of these are inappropriate to always provide
|
||||
export const globalKeywords: ReadonlyArray<ExpectedCompletionEntryObject> = [
|
||||
"break",
|
||||
|
@ -4871,6 +4981,57 @@ namespace FourSlashInterface {
|
|||
"of",
|
||||
].map(keywordEntry);
|
||||
|
||||
export const globalInJsKeywords: ReadonlyArray<ExpectedCompletionEntryObject> = [
|
||||
"break",
|
||||
"case",
|
||||
"catch",
|
||||
"class",
|
||||
"const",
|
||||
"continue",
|
||||
"debugger",
|
||||
"default",
|
||||
"delete",
|
||||
"do",
|
||||
"else",
|
||||
"export",
|
||||
"extends",
|
||||
"false",
|
||||
"finally",
|
||||
"for",
|
||||
"function",
|
||||
"if",
|
||||
"import",
|
||||
"in",
|
||||
"instanceof",
|
||||
"new",
|
||||
"null",
|
||||
"return",
|
||||
"super",
|
||||
"switch",
|
||||
"this",
|
||||
"throw",
|
||||
"true",
|
||||
"try",
|
||||
"typeof",
|
||||
"var",
|
||||
"void",
|
||||
"while",
|
||||
"with",
|
||||
"implements",
|
||||
"let",
|
||||
"package",
|
||||
"yield",
|
||||
"as",
|
||||
"async",
|
||||
"await",
|
||||
"constructor",
|
||||
"get",
|
||||
"require",
|
||||
"set",
|
||||
"from",
|
||||
"of",
|
||||
].map(keywordEntry);
|
||||
|
||||
export const insideMethodKeywords: ReadonlyArray<ExpectedCompletionEntryObject> = [
|
||||
"break",
|
||||
"case",
|
||||
|
@ -4917,6 +5078,50 @@ namespace FourSlashInterface {
|
|||
"await",
|
||||
].map(keywordEntry);
|
||||
|
||||
export const insideMethodInJsKeywords: ReadonlyArray<ExpectedCompletionEntryObject> = [
|
||||
"break",
|
||||
"case",
|
||||
"catch",
|
||||
"class",
|
||||
"const",
|
||||
"continue",
|
||||
"debugger",
|
||||
"default",
|
||||
"delete",
|
||||
"do",
|
||||
"else",
|
||||
"export",
|
||||
"extends",
|
||||
"false",
|
||||
"finally",
|
||||
"for",
|
||||
"function",
|
||||
"if",
|
||||
"import",
|
||||
"in",
|
||||
"instanceof",
|
||||
"new",
|
||||
"null",
|
||||
"return",
|
||||
"super",
|
||||
"switch",
|
||||
"this",
|
||||
"throw",
|
||||
"true",
|
||||
"try",
|
||||
"typeof",
|
||||
"var",
|
||||
"void",
|
||||
"while",
|
||||
"with",
|
||||
"implements",
|
||||
"let",
|
||||
"package",
|
||||
"yield",
|
||||
"async",
|
||||
"await",
|
||||
].map(keywordEntry);
|
||||
|
||||
export const globalKeywordsPlusUndefined: ReadonlyArray<ExpectedCompletionEntryObject> = (() => {
|
||||
const i = ts.findIndex(globalKeywords, x => x.name === "unique");
|
||||
return [...globalKeywords.slice(0, i), keywordEntry("undefined"), ...globalKeywords.slice(i)];
|
||||
|
@ -4929,6 +5134,13 @@ namespace FourSlashInterface {
|
|||
...globalKeywords
|
||||
];
|
||||
|
||||
export const globalsInJs: ReadonlyArray<ExpectedCompletionEntryObject> = [
|
||||
{ name: "globalThis", kind: "module" },
|
||||
...globalsVars,
|
||||
{ name: "undefined", kind: "var" },
|
||||
...globalInJsKeywords
|
||||
];
|
||||
|
||||
export function globalsPlus(plus: ReadonlyArray<ExpectedCompletionEntry>): ReadonlyArray<ExpectedCompletionEntry> {
|
||||
return [
|
||||
{ name: "globalThis", kind: "module" },
|
||||
|
@ -4937,6 +5149,15 @@ namespace FourSlashInterface {
|
|||
{ name: "undefined", kind: "var" },
|
||||
...globalKeywords];
|
||||
}
|
||||
|
||||
export function globalsInJsPlus(plus: ReadonlyArray<ExpectedCompletionEntry>): ReadonlyArray<ExpectedCompletionEntry> {
|
||||
return [
|
||||
{ name: "globalThis", kind: "module" },
|
||||
...globalsVars,
|
||||
...plus,
|
||||
{ name: "undefined", kind: "var" },
|
||||
...globalInJsKeywords];
|
||||
}
|
||||
}
|
||||
|
||||
export interface ReferenceGroup {
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace ts.Completions {
|
|||
ConstructorParameterKeywords, // Keywords at constructor parameter
|
||||
FunctionLikeBodyKeywords, // Keywords at function like body
|
||||
TypeKeywords,
|
||||
Last = TypeKeywords
|
||||
}
|
||||
|
||||
const enum GlobalsSearch { Continue, Success, Fail }
|
||||
|
@ -77,7 +78,7 @@ 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 } = completionData;
|
||||
const { symbols, completionKind, isInSnippetScope, isNewIdentifierLocation, location, propertyAccessToConvert, keywordFilters, literals, symbolToOriginInfoMap, recommendedCompletion, isJsxInitializer, insideJsDocTagTypeExpression } = 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,
|
||||
|
@ -113,7 +114,7 @@ namespace ts.Completions {
|
|||
|
||||
if (keywordFilters !== KeywordCompletionFilters.None) {
|
||||
const entryNames = arrayToSet(entries, e => e.name);
|
||||
for (const keywordEntry of getKeywordCompletions(keywordFilters)) {
|
||||
for (const keywordEntry of getKeywordCompletions(keywordFilters, !insideJsDocTagTypeExpression && isSourceFileJS(sourceFile))) {
|
||||
if (!entryNames.has(keywordEntry.name)) {
|
||||
entries.push(keywordEntry);
|
||||
}
|
||||
|
@ -510,6 +511,7 @@ namespace ts.Completions {
|
|||
readonly recommendedCompletion: Symbol | undefined;
|
||||
readonly previousToken: Node | undefined;
|
||||
readonly isJsxInitializer: IsJsxInitializer;
|
||||
readonly insideJsDocTagTypeExpression: boolean;
|
||||
}
|
||||
type Request = { readonly kind: CompletionDataKind.JsDocTagName | CompletionDataKind.JsDocTag } | { readonly kind: CompletionDataKind.JsDocParameterName, tag: JSDocParameterTag };
|
||||
|
||||
|
@ -837,7 +839,22 @@ namespace ts.Completions {
|
|||
const literals = mapDefined(contextualType && (contextualType.isUnion() ? contextualType.types : [contextualType]), t => t.isLiteral() ? t.value : undefined);
|
||||
|
||||
const recommendedCompletion = previousToken && contextualType && getRecommendedCompletion(previousToken, contextualType, typeChecker);
|
||||
return { kind: CompletionDataKind.Data, symbols, completionKind, isInSnippetScope, propertyAccessToConvert, isNewIdentifierLocation, location, keywordFilters, literals, symbolToOriginInfoMap, recommendedCompletion, previousToken, isJsxInitializer };
|
||||
return {
|
||||
kind: CompletionDataKind.Data,
|
||||
symbols,
|
||||
completionKind,
|
||||
isInSnippetScope,
|
||||
propertyAccessToConvert,
|
||||
isNewIdentifierLocation,
|
||||
location,
|
||||
keywordFilters,
|
||||
literals,
|
||||
symbolToOriginInfoMap,
|
||||
recommendedCompletion,
|
||||
previousToken,
|
||||
isJsxInitializer,
|
||||
insideJsDocTagTypeExpression
|
||||
};
|
||||
|
||||
type JSDocTagWithTypeExpression = JSDocParameterTag | JSDocPropertyTag | JSDocReturnTag | JSDocTypeTag | JSDocTypedefTag;
|
||||
|
||||
|
@ -1927,7 +1944,18 @@ namespace ts.Completions {
|
|||
}
|
||||
return res;
|
||||
});
|
||||
function getKeywordCompletions(keywordFilter: KeywordCompletionFilters): ReadonlyArray<CompletionEntry> {
|
||||
|
||||
function getKeywordCompletions(keywordFilter: KeywordCompletionFilters, filterOutTsOnlyKeywords: boolean): ReadonlyArray<CompletionEntry> {
|
||||
if (!filterOutTsOnlyKeywords) return getTypescriptKeywordCompletions(keywordFilter);
|
||||
|
||||
const index = keywordFilter + KeywordCompletionFilters.Last + 1;
|
||||
return _keywordCompletions[index] ||
|
||||
(_keywordCompletions[index] = getTypescriptKeywordCompletions(keywordFilter)
|
||||
.filter(entry => !isTypeScriptOnlyKeyword(stringToToken(entry.name)!))
|
||||
);
|
||||
}
|
||||
|
||||
function getTypescriptKeywordCompletions(keywordFilter: KeywordCompletionFilters): ReadonlyArray<CompletionEntry> {
|
||||
return _keywordCompletions[keywordFilter] || (_keywordCompletions[keywordFilter] = allKeywordsCompletions().filter(entry => {
|
||||
const kind = stringToToken(entry.name)!;
|
||||
switch (keywordFilter) {
|
||||
|
@ -1952,6 +1980,40 @@ namespace ts.Completions {
|
|||
}));
|
||||
}
|
||||
|
||||
function isTypeScriptOnlyKeyword(kind: SyntaxKind) {
|
||||
switch (kind) {
|
||||
case SyntaxKind.AbstractKeyword:
|
||||
case SyntaxKind.AnyKeyword:
|
||||
case SyntaxKind.BigIntKeyword:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
case SyntaxKind.DeclareKeyword:
|
||||
case SyntaxKind.EnumKeyword:
|
||||
case SyntaxKind.GlobalKeyword:
|
||||
case SyntaxKind.InferKeyword:
|
||||
case SyntaxKind.InterfaceKeyword:
|
||||
case SyntaxKind.IsKeyword:
|
||||
case SyntaxKind.KeyOfKeyword:
|
||||
case SyntaxKind.ModuleKeyword:
|
||||
case SyntaxKind.NamespaceKeyword:
|
||||
case SyntaxKind.NeverKeyword:
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
case SyntaxKind.PrivateKeyword:
|
||||
case SyntaxKind.ProtectedKeyword:
|
||||
case SyntaxKind.PublicKeyword:
|
||||
case SyntaxKind.ReadonlyKeyword:
|
||||
case SyntaxKind.StaticKeyword:
|
||||
case SyntaxKind.StringKeyword:
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
case SyntaxKind.TypeKeyword:
|
||||
case SyntaxKind.UniqueKeyword:
|
||||
case SyntaxKind.UnknownKeyword:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isInterfaceOrTypeLiteralCompletionKeyword(kind: SyntaxKind): boolean {
|
||||
return kind === SyntaxKind.ReadonlyKeyword;
|
||||
}
|
||||
|
|
20
tests/cases/fourslash/completionEntryInJsFile.ts
Normal file
20
tests/cases/fourslash/completionEntryInJsFile.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
///<reference path="fourslash.ts" />
|
||||
|
||||
// @allowJs: true
|
||||
// @Filename: /Foo.js
|
||||
//// /*global*/
|
||||
////class classA {
|
||||
//// /*class*/
|
||||
////}
|
||||
////class Test7 {
|
||||
//// constructor(/*constructorParameter*/){}
|
||||
////}
|
||||
////function foo() {
|
||||
/////*insideFunction*/
|
||||
////}
|
||||
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: "insideFunction", exact: completion.globalsInJsInsideFunction(["foo", "classA", "Test7"]) },
|
||||
);
|
|
@ -650,22 +650,29 @@ declare var classification: typeof FourSlashInterface.classification;
|
|||
declare namespace completion {
|
||||
type Entry = FourSlashInterface.ExpectedCompletionEntryObject;
|
||||
export const globals: ReadonlyArray<Entry>;
|
||||
export const globalsInJs: ReadonlyArray<Entry>;
|
||||
export const globalKeywords: ReadonlyArray<Entry>;
|
||||
export const globalInJsKeywords: ReadonlyArray<Entry>;
|
||||
export const insideMethodKeywords: ReadonlyArray<Entry>;
|
||||
export const insideMethodInJsKeywords: ReadonlyArray<Entry>;
|
||||
export const globalKeywordsPlusUndefined: ReadonlyArray<Entry>;
|
||||
export const globalsVars: ReadonlyArray<Entry>;
|
||||
export function globalsInsideFunction(plus: ReadonlyArray<Entry>): ReadonlyArray<Entry>;
|
||||
export function globalsInJsInsideFunction(plus: ReadonlyArray<Entry>): ReadonlyArray<Entry>;
|
||||
export function globalsPlus(plus: ReadonlyArray<FourSlashInterface.ExpectedCompletionEntry>): ReadonlyArray<Entry>;
|
||||
export function globalsInJsPlus(plus: ReadonlyArray<FourSlashInterface.ExpectedCompletionEntry>): ReadonlyArray<Entry>;
|
||||
export const keywordsWithUndefined: ReadonlyArray<Entry>;
|
||||
export const keywords: ReadonlyArray<Entry>;
|
||||
export const typeKeywords: ReadonlyArray<Entry>;
|
||||
export const globalTypes: ReadonlyArray<Entry>;
|
||||
export function globalTypesPlus(plus: ReadonlyArray<FourSlashInterface.ExpectedCompletionEntry>): ReadonlyArray<Entry>;
|
||||
export const classElementKeywords: ReadonlyArray<Entry>;
|
||||
export const classElementInJsKeywords: ReadonlyArray<Entry>;
|
||||
export const constructorParameterKeywords: ReadonlyArray<Entry>;
|
||||
export const functionMembers: ReadonlyArray<Entry>;
|
||||
export const stringMembers: ReadonlyArray<Entry>;
|
||||
export const functionMembersWithPrototype: ReadonlyArray<Entry>;
|
||||
export const statementKeywordsWithTypes: ReadonlyArray<Entry>;
|
||||
export const statementKeywords: ReadonlyArray<Entry>;
|
||||
export const statementInJsKeywords: ReadonlyArray<Entry>;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue