mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-07-01 21:34:46 -05:00
getStringLiteralCompletionEntries: switch on parent.type (#21169)
* getStringLiteralCompletionEntries: switch on parent.type * Use a 'default' case and reduce findPrecedingToken calls * fromType -> fromContextualType
This commit is contained in:
@@ -35,11 +35,14 @@ namespace ts.Completions {
|
||||
return entries && pathCompletionsInfo(entries);
|
||||
}
|
||||
|
||||
if (isInString(sourceFile, position)) {
|
||||
return getStringLiteralCompletionEntries(sourceFile, position, typeChecker, compilerOptions, host, log);
|
||||
const contextToken = findPrecedingToken(position, sourceFile);
|
||||
|
||||
if (isInString(sourceFile, position, contextToken)) {
|
||||
return !contextToken || !isStringLiteral(contextToken) && !isNoSubstitutionTemplateLiteral(contextToken)
|
||||
? undefined
|
||||
: getStringLiteralCompletionEntries(sourceFile, contextToken, position, typeChecker, compilerOptions, host, log);
|
||||
}
|
||||
|
||||
const contextToken = findPrecedingToken(position, sourceFile);
|
||||
if (contextToken && isBreakOrContinueStatement(contextToken.parent)
|
||||
&& (contextToken.kind === SyntaxKind.BreakKeyword || contextToken.kind === SyntaxKind.ContinueKeyword || contextToken.kind === SyntaxKind.Identifier)) {
|
||||
return getLabelCompletionAtPosition(contextToken.parent);
|
||||
@@ -261,70 +264,87 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionEntries(sourceFile: SourceFile, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost, log: Log): CompletionInfo | undefined {
|
||||
const node = findPrecedingToken(position, sourceFile);
|
||||
if (!node || !isStringLiteral(node) && !isNoSubstitutionTemplateLiteral(node)) {
|
||||
return undefined;
|
||||
}
|
||||
function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringLiteralLike, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost, log: Log): CompletionInfo | undefined {
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.LiteralType:
|
||||
switch (node.parent.parent.kind) {
|
||||
case SyntaxKind.TypeReference:
|
||||
// TODO: GH#21168
|
||||
return undefined;
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
// Get all apparent property names
|
||||
// i.e. interface Foo {
|
||||
// foo: string;
|
||||
// bar: string;
|
||||
// }
|
||||
// let x: Foo["/*completion position*/"]
|
||||
const type = typeChecker.getTypeFromTypeNode((node.parent.parent as IndexedAccessTypeNode).objectType);
|
||||
return getStringLiteralCompletionEntriesFromElementAccessOrIndexedAccess(node, sourceFile, type, typeChecker, compilerOptions.target, log);
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (node.parent.kind === SyntaxKind.PropertyAssignment &&
|
||||
node.parent.parent.kind === SyntaxKind.ObjectLiteralExpression &&
|
||||
(<PropertyAssignment>node.parent).name === node) {
|
||||
// Get quoted name of properties of the object literal expression
|
||||
// i.e. interface ConfigFiles {
|
||||
// 'jspm:dev': string
|
||||
// }
|
||||
// let files: ConfigFiles = {
|
||||
// '/*completion position*/'
|
||||
// }
|
||||
//
|
||||
// function foo(c: ConfigFiles) {}
|
||||
// foo({
|
||||
// '/*completion position*/'
|
||||
// });
|
||||
return getStringLiteralCompletionEntriesFromPropertyAssignment(<ObjectLiteralElement>node.parent, sourceFile, typeChecker, compilerOptions.target, log);
|
||||
}
|
||||
else if (isElementAccessExpression(node.parent) && node.parent.argumentExpression === node) {
|
||||
// Get all names of properties on the expression
|
||||
// i.e. interface A {
|
||||
// 'prop1': string
|
||||
// }
|
||||
// let a: A;
|
||||
// a['/*completion position*/']
|
||||
const type = typeChecker.getTypeAtLocation(node.parent.expression);
|
||||
return getStringLiteralCompletionEntriesFromElementAccessOrIndexedAccess(node, sourceFile, type, typeChecker, compilerOptions.target, log);
|
||||
}
|
||||
else if (node.parent.kind === SyntaxKind.ImportDeclaration || node.parent.kind === SyntaxKind.ExportDeclaration
|
||||
|| isRequireCall(node.parent, /*checkArgumentIsStringLiteral*/ false) || isImportCall(node.parent)
|
||||
|| isExpressionOfExternalModuleImportEqualsDeclaration(node)) {
|
||||
// Get all known external module names or complete a path to a module
|
||||
// i.e. import * as ns from "/*completion position*/";
|
||||
// var y = import("/*completion position*/");
|
||||
// import x = require("/*completion position*/");
|
||||
// var y = require("/*completion position*/");
|
||||
// export * from "/*completion position*/";
|
||||
const entries = PathCompletions.getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker);
|
||||
return pathCompletionsInfo(entries);
|
||||
}
|
||||
else if (isIndexedAccessTypeNode(node.parent.parent)) {
|
||||
// Get all apparent property names
|
||||
// i.e. interface Foo {
|
||||
// foo: string;
|
||||
// bar: string;
|
||||
// }
|
||||
// let x: Foo["/*completion position*/"]
|
||||
const type = typeChecker.getTypeFromTypeNode(node.parent.parent.objectType);
|
||||
return getStringLiteralCompletionEntriesFromElementAccessOrIndexedAccess(node, sourceFile, type, typeChecker, compilerOptions.target, log);
|
||||
}
|
||||
else {
|
||||
const argumentInfo = SignatureHelp.getImmediatelyContainingArgumentInfo(node, position, sourceFile);
|
||||
if (argumentInfo) {
|
||||
// Get string literal completions from specialized signatures of the target
|
||||
// i.e. declare function f(a: 'A');
|
||||
// f("/*completion position*/")
|
||||
return getStringLiteralCompletionEntriesFromCallExpression(argumentInfo, typeChecker);
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
if (node.parent.parent.kind === SyntaxKind.ObjectLiteralExpression &&
|
||||
(<PropertyAssignment>node.parent).name === node) {
|
||||
// Get quoted name of properties of the object literal expression
|
||||
// i.e. interface ConfigFiles {
|
||||
// 'jspm:dev': string
|
||||
// }
|
||||
// let files: ConfigFiles = {
|
||||
// '/*completion position*/'
|
||||
// }
|
||||
//
|
||||
// function foo(c: ConfigFiles) {}
|
||||
// foo({
|
||||
// '/*completion position*/'
|
||||
// });
|
||||
return getStringLiteralCompletionEntriesFromPropertyAssignment(<PropertyAssignment>node.parent, sourceFile, typeChecker, compilerOptions.target, log);
|
||||
}
|
||||
return fromContextualType();
|
||||
|
||||
case SyntaxKind.ElementAccessExpression: {
|
||||
const { expression, argumentExpression } = node.parent as ElementAccessExpression;
|
||||
if (node === argumentExpression) {
|
||||
// Get all names of properties on the expression
|
||||
// i.e. interface A {
|
||||
// 'prop1': string
|
||||
// }
|
||||
// let a: A;
|
||||
// a['/*completion position*/']
|
||||
const type = typeChecker.getTypeAtLocation(expression);
|
||||
return getStringLiteralCompletionEntriesFromElementAccessOrIndexedAccess(node, sourceFile, type, typeChecker, compilerOptions.target, log);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
if (!isRequireCall(node.parent, /*checkArgumentIsStringLiteral*/ false) && !isImportCall(node.parent)) {
|
||||
const argumentInfo = SignatureHelp.getImmediatelyContainingArgumentInfo(node, position, sourceFile);
|
||||
// Get string literal completions from specialized signatures of the target
|
||||
// i.e. declare function f(a: 'A');
|
||||
// f("/*completion position*/")
|
||||
return argumentInfo ? getStringLiteralCompletionEntriesFromCallExpression(argumentInfo, typeChecker) : fromContextualType();
|
||||
}
|
||||
// falls through
|
||||
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
case SyntaxKind.ExternalModuleReference:
|
||||
// Get all known external module names or complete a path to a module
|
||||
// i.e. import * as ns from "/*completion position*/";
|
||||
// var y = import("/*completion position*/");
|
||||
// import x = require("/*completion position*/");
|
||||
// var y = require("/*completion position*/");
|
||||
// export * from "/*completion position*/";
|
||||
return pathCompletionsInfo(PathCompletions.getStringLiteralCompletionsFromModuleNames(sourceFile, node as StringLiteral, compilerOptions, host, typeChecker));
|
||||
|
||||
default:
|
||||
return fromContextualType();
|
||||
}
|
||||
|
||||
function fromContextualType(): CompletionInfo {
|
||||
// Get completion for string literal from string literal type
|
||||
// i.e. var x: "hi" | "hello" = "/*completion position*/"
|
||||
return getStringLiteralCompletionEntriesFromType(getContextualTypeFromParent(node, typeChecker), typeChecker);
|
||||
|
||||
@@ -833,8 +833,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function isInString(sourceFile: SourceFile, position: number): boolean {
|
||||
const previousToken = findPrecedingToken(position, sourceFile);
|
||||
export function isInString(sourceFile: SourceFile, position: number, previousToken = findPrecedingToken(position, sourceFile)): boolean {
|
||||
if (previousToken && isStringTextContainingNode(previousToken)) {
|
||||
const start = previousToken.getStart();
|
||||
const end = previousToken.getEnd();
|
||||
|
||||
Reference in New Issue
Block a user