From bd25c130caaa6c607e830f0f29784d1691308d87 Mon Sep 17 00:00:00 2001 From: Yui Date: Fri, 22 Jul 2016 07:15:12 -0700 Subject: [PATCH] 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 --- src/services/services.ts | 49 ++++++++++++++++--- ...nForQuotedPropertyInPropertyAssignment1.ts | 24 +++++++++ ...nForQuotedPropertyInPropertyAssignment2.ts | 30 ++++++++++++ ...nForQuotedPropertyInPropertyAssignment3.ts | 26 ++++++++++ ...nForQuotedPropertyInPropertyAssignment4.ts | 24 +++++++++ 5 files changed, 147 insertions(+), 6 deletions(-) create mode 100644 tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment1.ts create mode 100644 tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment2.ts create mode 100644 tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment3.ts create mode 100644 tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment4.ts diff --git a/src/services/services.ts b/src/services/services.ts index 3124c78bd15..3b8be487aba 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -4296,6 +4296,7 @@ namespace ts { kindModifiers: getSymbolModifiers(symbol), sortText: "0", }; + } function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[], location: Node, performCharacterChecks: boolean): Map { @@ -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(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(node); } } - function getStringLiteralCompletionEntriesFromCallExpression(argumentInfo: SignatureHelp.ArgumentListInfo) { + function getStringLiteralCompletionEntriesFromPropertyAssignment(element: ObjectLiteralElement) { + const typeChecker = program.getTypeChecker(); + const type = typeChecker.getContextualType((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[] = []; diff --git a/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment1.ts b/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment1.ts new file mode 100644 index 00000000000..7faebc1474b --- /dev/null +++ b/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment1.ts @@ -0,0 +1,24 @@ +/// + +//// 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); diff --git a/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment2.ts b/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment2.ts new file mode 100644 index 00000000000..4ba88e7dd2a --- /dev/null +++ b/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment2.ts @@ -0,0 +1,30 @@ +/// + +//// 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); diff --git a/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment3.ts b/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment3.ts new file mode 100644 index 00000000000..238606520e3 --- /dev/null +++ b/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment3.ts @@ -0,0 +1,26 @@ +/// + +//// 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); diff --git a/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment4.ts b/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment4.ts new file mode 100644 index 00000000000..9855bb8c502 --- /dev/null +++ b/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment4.ts @@ -0,0 +1,24 @@ +/// + +//// 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);