Skip to content

Commit 81a48fe

Browse files
committed
- Support non-identifier keys
- Move main logic onto tryGetGlobalSymbols function
1 parent 7c0366e commit 81a48fe

10 files changed

+52
-66
lines changed

src/services/completions.ts

Lines changed: 32 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,6 @@ namespace ts.Completions {
153153
return stringCompletions;
154154
}
155155

156-
const objectTypeLiteralCompletions = getObjectTypeLiteralInTypeArgumentCompletions(sourceFile, position, contextToken, typeChecker, compilerOptions, log, preferences);
157-
if (objectTypeLiteralCompletions) {
158-
return objectTypeLiteralCompletions;
159-
}
160-
161156
if (contextToken && isBreakOrContinueStatement(contextToken.parent)
162157
&& (contextToken.kind === SyntaxKind.BreakKeyword || contextToken.kind === SyntaxKind.ContinueKeyword || contextToken.kind === SyntaxKind.Identifier)) {
163158
return getLabelCompletionAtPosition(contextToken.parent);
@@ -988,53 +983,6 @@ namespace ts.Completions {
988983
return !!symbol.declarations?.some(d => d.kind === SyntaxKind.SourceFile);
989984
}
990985

991-
function getObjectTypeLiteralInTypeArgumentCompletions(sourceFile: SourceFile, position: number, contextToken: Node | undefined, checker: TypeChecker, options: CompilerOptions, log: Log, preferences: UserPreferences): CompletionInfo | undefined{
992-
if (!contextToken) return undefined;
993-
994-
const typeLiteralNode = tryGetTypeLiteralNode(contextToken);
995-
if (!typeLiteralNode) return undefined;
996-
997-
const intersectionTypeNode = isIntersectionTypeNode(typeLiteralNode.parent) ? typeLiteralNode.parent : undefined;
998-
const containerTypeNode = intersectionTypeNode || typeLiteralNode;
999-
1000-
const containerExpectedType = tryGetTypeArgumentSubType(containerTypeNode, checker);
1001-
if (!containerExpectedType) return undefined;
1002-
1003-
const containerActualType = checker.getTypeFromTypeNode(containerTypeNode);
1004-
1005-
const members = getPropertiesForCompletion(containerExpectedType, checker);
1006-
const existingMembers = getPropertiesForCompletion(containerActualType, checker);
1007-
1008-
const existingMemberEscapedNames: Set<__String> = new Set();
1009-
forEach(existingMembers, s => existingMemberEscapedNames.add(s.escapedName));
1010-
1011-
const missingMembers = filter(members, s => !existingMemberEscapedNames.has(s.escapedName));
1012-
1013-
const location = getTouchingToken(sourceFile, position);
1014-
1015-
const entries: CompletionEntry[] = [];
1016-
getCompletionEntriesFromSymbols(
1017-
missingMembers,
1018-
entries,
1019-
/* contextToken */ undefined,
1020-
location,
1021-
sourceFile,
1022-
checker,
1023-
options.target!,
1024-
log,
1025-
CompletionKind.MemberLike,
1026-
preferences,
1027-
options
1028-
);
1029-
1030-
return {
1031-
isGlobalCompletion: false,
1032-
isMemberCompletion: true,
1033-
isNewIdentifierLocation: false,
1034-
entries
1035-
};
1036-
}
1037-
1038986
function getCompletionData(
1039987
program: Program,
1040988
log: (message: string) => void,
@@ -1561,7 +1509,8 @@ namespace ts.Completions {
15611509
}
15621510

15631511
function tryGetGlobalSymbols(): boolean {
1564-
const result: GlobalsSearch = tryGetObjectLikeCompletionSymbols()
1512+
const result: GlobalsSearch = tryGetObjectTypeLiteralInTypeArgumentCompletionSymbols()
1513+
|| tryGetObjectLikeCompletionSymbols()
15651514
|| tryGetImportCompletionSymbols()
15661515
|| tryGetImportOrExportClauseCompletionSymbols()
15671516
|| tryGetLocalNamedExportCompletionSymbols()
@@ -1963,6 +1912,32 @@ namespace ts.Completions {
19631912
position === contextToken.end && (!!contextToken.isUnterminated || isRegularExpressionLiteral(contextToken)));
19641913
}
19651914

1915+
function tryGetObjectTypeLiteralInTypeArgumentCompletionSymbols(): GlobalsSearch | undefined {
1916+
const typeLiteralNode = tryGetTypeLiteralNode(contextToken);
1917+
if (!typeLiteralNode) return GlobalsSearch.Continue;
1918+
1919+
const intersectionTypeNode = isIntersectionTypeNode(typeLiteralNode.parent) ? typeLiteralNode.parent : undefined;
1920+
const containerTypeNode = intersectionTypeNode || typeLiteralNode;
1921+
1922+
const containerExpectedType = getConstraintOfTypeArgumentProperty(containerTypeNode, typeChecker);
1923+
if (!containerExpectedType) return GlobalsSearch.Continue;
1924+
1925+
const containerActualType = typeChecker.getTypeFromTypeNode(containerTypeNode);
1926+
1927+
const members = getPropertiesForCompletion(containerExpectedType, typeChecker);
1928+
const existingMembers = getPropertiesForCompletion(containerActualType, typeChecker);
1929+
1930+
const existingMemberEscapedNames: Set<__String> = new Set();
1931+
existingMembers.forEach(s => existingMemberEscapedNames.add(s.escapedName));
1932+
1933+
symbols = filter(members, s => !existingMemberEscapedNames.has(s.escapedName));
1934+
1935+
completionKind = CompletionKind.ObjectPropertyDeclaration;
1936+
isNewIdentifierLocation = true;
1937+
1938+
return GlobalsSearch.Success;
1939+
}
1940+
19661941
/**
19671942
* Aggregates relevant symbols for completion in object literals and object binding patterns.
19681943
* Relevant symbols are stored in the captured 'symbols' variable.
@@ -2910,6 +2885,8 @@ namespace ts.Completions {
29102885
}
29112886

29122887
function tryGetTypeLiteralNode(node: Node): TypeLiteralNode | undefined {
2888+
if (!node) return undefined;
2889+
29132890
const parent = node.parent;
29142891

29152892
switch (node.kind) {
@@ -2930,14 +2907,14 @@ namespace ts.Completions {
29302907
return undefined;
29312908
}
29322909

2933-
function tryGetTypeArgumentSubType(node: Node, checker: TypeChecker): Type | undefined {
2910+
function getConstraintOfTypeArgumentProperty(node: Node, checker: TypeChecker): Type | undefined {
29342911
if (!node) return undefined;
29352912

29362913
if (isTypeNode(node) && isTypeReferenceType(node.parent)) {
29372914
return checker.getTypeArgumentConstraint(node);
29382915
}
29392916

2940-
const t = tryGetTypeArgumentSubType(node.parent, checker);
2917+
const t = getConstraintOfTypeArgumentProperty(node.parent, checker);
29412918
if (!t) return undefined;
29422919

29432920
switch (node.kind) {

tests/cases/fourslash/completionListInTypeLiteralInTypeParameter1.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
////interface Foo {
44
//// one: string;
55
//// two: number;
6+
//// 333: symbol;
7+
//// '4four': boolean;
8+
//// '5 five': object;
9+
//// number: string;
10+
//// Object: number;
611
////}
712
////
813
////interface Bar<T extends Foo> {
@@ -11,4 +16,8 @@
1116
////
1217
////var foobar: Bar<{/**/
1318

14-
verify.completions({ marker: "", exact: ["one", "two"] });
19+
verify.completions({
20+
marker: "",
21+
exact: ["one", "two", "\"333\"", "\"4four\"", "\"5 five\"", "number", "Object"],
22+
isNewIdentifierLocation: true
23+
});

tests/cases/fourslash/completionListInTypeLiteralInTypeParameter2.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111
////
1212
////var foobar: Bar<{ on/**/
1313

14-
verify.completions({ marker: "", exact: ["one", "two"] });
14+
verify.completions({ marker: "", exact: ["one", "two"], isNewIdentifierLocation: true });

tests/cases/fourslash/completionListInTypeLiteralInTypeParameter3.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111
////
1212
////var foobar: Bar<{ one: string, /**/
1313

14-
verify.completions({ marker: "", exact: "two" });
14+
verify.completions({ marker: "", exact: "two", isNewIdentifierLocation: true });

tests/cases/fourslash/completionListInTypeLiteralInTypeParameter4.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111
////
1212
////var foobar: Bar<{ one: string } & {/**/
1313

14-
verify.completions({ marker: "", exact: "two" });
14+
verify.completions({ marker: "", exact: "two", isNewIdentifierLocation: true });

tests/cases/fourslash/completionListInTypeLiteralInTypeParameter5.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111
////
1212
////var foobar: Bar<{ prop1: string } & {/**/
1313

14-
verify.completions({ marker: "", exact: ["one", "two"] });
14+
verify.completions({ marker: "", exact: ["one", "two"], isNewIdentifierLocation: true });

tests/cases/fourslash/completionListInTypeLiteralInTypeParameter6.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111
////
1212
////var foobar: Bar<{ one: string } | {/**/
1313

14-
verify.completions({ marker: "", exact: ["one", "two"] });
14+
verify.completions({ marker: "", exact: ["one", "two"], isNewIdentifierLocation: true });

tests/cases/fourslash/completionListInTypeLiteralInTypeParameter7.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414
////var foobar: Bar<{
1515
//// two: {/**/
1616

17-
verify.completions({ marker: "", exact: "three" });
17+
verify.completions({ marker: "", exact: "three", isNewIdentifierLocation: true });

tests/cases/fourslash/completionListInTypeLiteralInTypeParameter8.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
////}>;
2727

2828
verify.completions(
29-
{ marker: "4", exact: "four" },
30-
{ marker: "0", exact: [] },
31-
{ marker: "1", exact: "one" },
29+
{ marker: "4", exact: "four", isNewIdentifierLocation: true },
30+
{ marker: "0", exact: [], isNewIdentifierLocation: true },
31+
{ marker: "1", exact: "one", isNewIdentifierLocation: true },
3232
);
3333

tests/cases/fourslash/completionListInTypeLiteralInTypeParameter9.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@
2121
////}>;
2222

2323
verify.completions({ marker: "g", includes: ["Foo", "Bar", ...completion.globalTypes] });
24-
verify.completions({ marker: "4", exact: "four" });
24+
verify.completions({ marker: "4", exact: "four", isNewIdentifierLocation: true });
2525

0 commit comments

Comments
 (0)