Skip to content

Commit 14aa132

Browse files
authored
[Release-2.0] Fix 9632 Auto-completion for quoted property in object literal expression (#9745)
* wip * 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 * Add tests and baseline for object literal expression for arguments * Undo wip * Undo wip
1 parent 253253d commit 14aa132

5 files changed

+147
-6
lines changed

src/services/services.ts

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4206,6 +4206,7 @@ namespace ts {
42064206
kindModifiers: getSymbolModifiers(symbol),
42074207
sortText: "0",
42084208
};
4209+
42094210
}
42104211

42114212
function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[], location: Node, performCharacterChecks: boolean): Map<string> {
@@ -4234,22 +4235,58 @@ namespace ts {
42344235
return undefined;
42354236
}
42364237

4237-
const argumentInfo = SignatureHelp.getContainingArgumentInfo(node, position, sourceFile);
4238-
if (argumentInfo) {
4239-
// Get string literal completions from specialized signatures of the target
4240-
return getStringLiteralCompletionEntriesFromCallExpression(argumentInfo);
4238+
if (node.parent.kind === SyntaxKind.PropertyAssignment && node.parent.parent.kind === SyntaxKind.ObjectLiteralExpression) {
4239+
// Get quoted name of properties of the object literal expression
4240+
// i.e. interface ConfigFiles {
4241+
// 'jspm:dev': string
4242+
// }
4243+
// let files: ConfigFiles = {
4244+
// '/*completion position*/'
4245+
// }
4246+
//
4247+
// function foo(c: ConfigFiles) {}
4248+
// foo({
4249+
// '/*completion position*/'
4250+
// });
4251+
return getStringLiteralCompletionEntriesFromPropertyAssignment(<ObjectLiteralElement>node.parent);
42414252
}
42424253
else if (isElementAccessExpression(node.parent) && node.parent.argumentExpression === node) {
42434254
// Get all names of properties on the expression
4255+
// i.e. interface A {
4256+
// 'prop1': string
4257+
// }
4258+
// let a: A;
4259+
// a['/*completion position*/']
42444260
return getStringLiteralCompletionEntriesFromElementAccess(node.parent);
42454261
}
42464262
else {
4247-
// Otherwise, get the completions from the contextual type if one exists
4263+
const argumentInfo = SignatureHelp.getContainingArgumentInfo(node, position, sourceFile);
4264+
if (argumentInfo) {
4265+
// Get string literal completions from specialized signatures of the target
4266+
// i.e. declare function f(a: 'A');
4267+
// f("/*completion position*/")
4268+
return getStringLiteralCompletionEntriesFromCallExpression(argumentInfo, node);
4269+
}
4270+
4271+
// Get completion for string literal from string literal type
4272+
// i.e. var x: "hi" | "hello" = "/*completion position*/"
42484273
return getStringLiteralCompletionEntriesFromContextualType(<StringLiteral>node);
42494274
}
42504275
}
42514276

4252-
function getStringLiteralCompletionEntriesFromCallExpression(argumentInfo: SignatureHelp.ArgumentListInfo) {
4277+
function getStringLiteralCompletionEntriesFromPropertyAssignment(element: ObjectLiteralElement) {
4278+
const typeChecker = program.getTypeChecker();
4279+
const type = typeChecker.getContextualType((<ObjectLiteralExpression>element.parent));
4280+
const entries: CompletionEntry[] = [];
4281+
if (type) {
4282+
getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, element, /*performCharacterChecks*/false);
4283+
if (entries.length) {
4284+
return { isMemberCompletion: true, isNewIdentifierLocation: true, entries };
4285+
}
4286+
}
4287+
}
4288+
4289+
function getStringLiteralCompletionEntriesFromCallExpression(argumentInfo: SignatureHelp.ArgumentListInfo, location: Node) {
42534290
const typeChecker = program.getTypeChecker();
42544291
const candidates: Signature[] = [];
42554292
const entries: CompletionEntry[] = [];
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
//// export interface Configfiles {
4+
//// jspm: string;
5+
//// 'jspm:browser': string;
6+
//// 'jspm:dev': string;
7+
//// 'jspm:node': string;
8+
//// }
9+
10+
//// let files: Configfiles;
11+
//// files = {
12+
//// /*0*/: '',
13+
//// '/*1*/': ''
14+
//// }
15+
16+
goTo.marker('0');
17+
verify.completionListContains("jspm");
18+
verify.completionListAllowsNewIdentifier();
19+
verify.memberListCount(1);
20+
21+
goTo.marker('1');
22+
verify.completionListContains("jspm:dev");
23+
verify.completionListAllowsNewIdentifier();
24+
verify.memberListCount(4);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
//// export interface Config {
4+
//// files: ConfigFiles
5+
//// }
6+
7+
//// export interface ConfigFiles {
8+
//// jspm: string;
9+
//// 'jspm:browser': string;
10+
//// 'jspm:dev': string;
11+
//// 'jspm:node': string;
12+
//// }
13+
14+
//// let config: Config;
15+
//// config = {
16+
//// files: {
17+
//// /*0*/: '',
18+
//// '/*1*/': ''
19+
//// }
20+
//// }
21+
22+
goTo.marker('0');
23+
verify.completionListContains("jspm");
24+
verify.completionListAllowsNewIdentifier();
25+
verify.memberListCount(1);
26+
27+
goTo.marker('1');
28+
verify.completionListContains("jspm:dev");
29+
verify.completionListAllowsNewIdentifier();
30+
verify.memberListCount(4);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
//// let configFiles1: {
4+
//// jspm: string;
5+
//// 'jspm:browser': string;
6+
//// } = {
7+
//// /*0*/: "",
8+
//// }
9+
10+
//// let configFiles2: {
11+
//// jspm: string;
12+
//// 'jspm:browser': string;
13+
//// } = {
14+
//// jspm: "",
15+
//// '/*1*/': ""
16+
//// }
17+
18+
goTo.marker('0');
19+
verify.completionListContains("jspm");
20+
verify.completionListAllowsNewIdentifier();
21+
verify.memberListCount(1);
22+
23+
goTo.marker('1');
24+
verify.completionListContains("jspm:browser");
25+
verify.completionListAllowsNewIdentifier();
26+
verify.memberListCount(2);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
//// export interface ConfigFiles {
4+
//// jspm: string;
5+
//// 'jspm:browser': string;
6+
//// 'jspm:dev': string;
7+
//// 'jspm:node': string;
8+
//// }
9+
10+
//// function foo(c: ConfigFiles) {}
11+
//// foo({
12+
//// j/*0*/: "",
13+
//// "/*1*/": "",
14+
//// })
15+
16+
goTo.marker('0');
17+
verify.completionListContains("jspm");
18+
verify.completionListAllowsNewIdentifier();
19+
verify.memberListCount(1);
20+
21+
goTo.marker('1');
22+
verify.completionListContains("jspm:dev");
23+
verify.completionListAllowsNewIdentifier();
24+
verify.memberListCount(4);

0 commit comments

Comments
 (0)