Port PR 9745 to master (#9881)

* Add completion for quote property name in object literal expression

* Add fourslash tests for completion of quoted property in object literal expression

* Handle object-literal expression as an argument

Undo wip

Undo wip

Conflicts:
	src/services/services.ts

* Add tests and baseline for object literal expression for arguments
This commit is contained in:
Yui 2016-07-22 07:15:12 -07:00 committed by GitHub
parent f24341f719
commit bd25c130ca
5 changed files with 147 additions and 6 deletions

View File

@ -4296,6 +4296,7 @@ namespace ts {
kindModifiers: getSymbolModifiers(symbol),
sortText: "0",
};
}
function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[], location: Node, performCharacterChecks: boolean): Map<string> {
@ -4324,22 +4325,58 @@ namespace ts {
return undefined;
}
const argumentInfo = SignatureHelp.getContainingArgumentInfo(node, position, sourceFile);
if (argumentInfo) {
// Get string literal completions from specialized signatures of the target
return getStringLiteralCompletionEntriesFromCallExpression(argumentInfo);
if (node.parent.kind === SyntaxKind.PropertyAssignment && node.parent.parent.kind === SyntaxKind.ObjectLiteralExpression) {
// 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);
}
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*/']
return getStringLiteralCompletionEntriesFromElementAccess(node.parent);
}
else {
// Otherwise, get the completions from the contextual type if one exists
const argumentInfo = SignatureHelp.getContainingArgumentInfo(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, node);
}
// Get completion for string literal from string literal type
// i.e. var x: "hi" | "hello" = "/*completion position*/"
return getStringLiteralCompletionEntriesFromContextualType(<StringLiteral>node);
}
}
function getStringLiteralCompletionEntriesFromCallExpression(argumentInfo: SignatureHelp.ArgumentListInfo) {
function getStringLiteralCompletionEntriesFromPropertyAssignment(element: ObjectLiteralElement) {
const typeChecker = program.getTypeChecker();
const type = typeChecker.getContextualType((<ObjectLiteralExpression>element.parent));
const entries: CompletionEntry[] = [];
if (type) {
getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, element, /*performCharacterChecks*/false);
if (entries.length) {
return { isMemberCompletion: true, isNewIdentifierLocation: true, entries };
}
}
}
function getStringLiteralCompletionEntriesFromCallExpression(argumentInfo: SignatureHelp.ArgumentListInfo, location: Node) {
const typeChecker = program.getTypeChecker();
const candidates: Signature[] = [];
const entries: CompletionEntry[] = [];

View File

@ -0,0 +1,24 @@
/// <reference path='fourslash.ts'/>
//// export interface Configfiles {
//// jspm: string;
//// 'jspm:browser': string;
//// 'jspm:dev': string;
//// 'jspm:node': string;
//// }
//// let files: Configfiles;
//// files = {
//// /*0*/: '',
//// '/*1*/': ''
//// }
goTo.marker('0');
verify.completionListContains("jspm");
verify.completionListAllowsNewIdentifier();
verify.memberListCount(1);
goTo.marker('1');
verify.completionListContains("jspm:dev");
verify.completionListAllowsNewIdentifier();
verify.memberListCount(4);

View File

@ -0,0 +1,30 @@
/// <reference path='fourslash.ts'/>
//// export interface Config {
//// files: ConfigFiles
//// }
//// export interface ConfigFiles {
//// jspm: string;
//// 'jspm:browser': string;
//// 'jspm:dev': string;
//// 'jspm:node': string;
//// }
//// let config: Config;
//// config = {
//// files: {
//// /*0*/: '',
//// '/*1*/': ''
//// }
//// }
goTo.marker('0');
verify.completionListContains("jspm");
verify.completionListAllowsNewIdentifier();
verify.memberListCount(1);
goTo.marker('1');
verify.completionListContains("jspm:dev");
verify.completionListAllowsNewIdentifier();
verify.memberListCount(4);

View File

@ -0,0 +1,26 @@
/// <reference path='fourslash.ts'/>
//// let configFiles1: {
//// jspm: string;
//// 'jspm:browser': string;
//// } = {
//// /*0*/: "",
//// }
//// let configFiles2: {
//// jspm: string;
//// 'jspm:browser': string;
//// } = {
//// jspm: "",
//// '/*1*/': ""
//// }
goTo.marker('0');
verify.completionListContains("jspm");
verify.completionListAllowsNewIdentifier();
verify.memberListCount(1);
goTo.marker('1');
verify.completionListContains("jspm:browser");
verify.completionListAllowsNewIdentifier();
verify.memberListCount(2);

View File

@ -0,0 +1,24 @@
/// <reference path='fourslash.ts'/>
//// export interface ConfigFiles {
//// jspm: string;
//// 'jspm:browser': string;
//// 'jspm:dev': string;
//// 'jspm:node': string;
//// }
//// function foo(c: ConfigFiles) {}
//// foo({
//// j/*0*/: "",
//// "/*1*/": "",
//// })
goTo.marker('0');
verify.completionListContains("jspm");
verify.completionListAllowsNewIdentifier();
verify.memberListCount(1);
goTo.marker('1');
verify.completionListContains("jspm:dev");
verify.completionListAllowsNewIdentifier();
verify.memberListCount(4);