Skip to content

Commit edd9485

Browse files
committed
objectLiteralCompletions fixes + make more stable
1 parent 7236174 commit edd9485

File tree

1 file changed

+25
-31
lines changed

1 file changed

+25
-31
lines changed

typescript/src/completions/objectLiteralCompletions.ts

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ export default (
1414
// plans to make it hihgly configurable! e.g. if user wants to make some subtype leading (e.g. from [] | {})
1515
if (ts.isIdentifier(node)) node = node.parent
1616
if (ts.isShorthandPropertyAssignment(node)) node = node.parent
17-
const addEntries: ts.CompletionEntry[] = []
18-
const completionIndexesToRemove: number[] = []
1917
entries = [...entries]
2018
if (ts.isObjectLiteralExpression(node)) {
2119
const typeChecker = languageService.getProgram()!.getTypeChecker()!
@@ -28,7 +26,18 @@ export default (
2826
const type = typeChecker.getTypeOfSymbolAtLocation(property, node)
2927
if (!type) continue
3028
if (isMethodCompletionCall(type, typeChecker)) {
31-
if (keepOriginal === 'remove') completionIndexesToRemove.push(entries.indexOf(entry))
29+
if (['above', 'remove'].includes(keepOriginal) && preferences.includeCompletionsWithObjectLiteralMethodSnippets) {
30+
const methodEntryIndex = entries.findIndex(e => e.name === entry.name && isObjectLiteralMethodSnippet(e))
31+
const methodEntry = entries[methodEntryIndex]
32+
if (methodEntry) {
33+
entries.splice(methodEntryIndex, 1)
34+
entries.splice(entries.indexOf(entry) + (keepOriginal === 'below' ? 1 : 0), keepOriginal === 'remove' ? 1 : 0, {
35+
...methodEntry,
36+
// let correctSorting.enable sort it
37+
sortText: entry.sortText,
38+
})
39+
}
40+
}
3241
continue
3342
}
3443
if (!enableMoreVariants) continue
@@ -40,13 +49,15 @@ export default (
4049
const completingStyleMap = [
4150
[getQuotedSnippet, isStringCompletion],
4251
[[`: [${insertObjectArrayInnerText}],$0`, `: [],`], isArrayCompletion],
43-
[[`: {${insertObjectArrayInnerText}},$0`, `: {}`], isObjectCompletion],
52+
[[`: {${insertObjectArrayInnerText}},$0`, `: {},`], isObjectCompletion],
4453
] as const
45-
const insertSnippetVariant = completingStyleMap.find(([, detector]) => detector(type, typeChecker))?.[0]
54+
const fallbackSnippet = c('objectLiteralCompletions.fallbackVariant') ? ([': $0,', ': ,'] as const) : undefined
55+
const insertSnippetVariant = completingStyleMap.find(([, detector]) => detector(type, typeChecker))?.[0] ?? fallbackSnippet
4656
if (!insertSnippetVariant) continue
4757
const [insertSnippetText, insertSnippetPreview] = typeof insertSnippetVariant === 'function' ? insertSnippetVariant() : insertSnippetVariant
4858
const insertText = entry.name + insertSnippetText
49-
addEntries.push({
59+
const index = entries.indexOf(entry)
60+
entries.splice(index + (keepOriginal === 'below' ? 1 : 0), keepOriginal === 'remove' ? 1 : 0, {
5061
...entry,
5162
// todo setting incompatible!!!
5263
sortText: entry.sortText,
@@ -56,48 +67,31 @@ export default (
5667
insertText,
5768
isSnippet: true,
5869
})
59-
if (keepOriginal === 'remove') entries.splice(entries.indexOf(entry), 1)
60-
}
61-
if ((keepOriginal === 'above' || keepOriginal === 'remove') && preferences.includeCompletionsWithObjectLiteralMethodSnippets) {
62-
const metMethodCompletions: string[] = []
63-
entries = entries.filter((entry, i) => {
64-
if (completionIndexesToRemove.includes(i)) return false
65-
66-
const { detail } = entry.labelDetails ?? {}
67-
if (detail?.startsWith('(') && detail.split('\n')[0]!.trimEnd().endsWith(')')) {
68-
addEntries.push(entry)
69-
metMethodCompletions.push(entry.name)
70-
return false
71-
}
72-
if (
73-
keepOriginal === 'remove' &&
74-
entry.kind === ts.ScriptElementKind.memberFunctionElement &&
75-
!detail &&
76-
metMethodCompletions.includes(entry.name)
77-
) {
78-
return false
79-
}
80-
return true
81-
})
8270
}
83-
return keepOriginal === 'above' ? [...addEntries, ...entries] : [...entries, ...addEntries]
71+
return entries
8472
}
8573
}
8674
}
8775

76+
const isObjectLiteralMethodSnippet = (entry: ts.CompletionEntry) => {
77+
const { detail } = entry.labelDetails ?? {}
78+
return detail?.startsWith('(') && detail.split('\n')[0]!.trimEnd().endsWith(')')
79+
}
80+
8881
const isMethodCompletionCall = (type: ts.Type, checker: ts.TypeChecker) => {
8982
if (checker.getSignaturesOfType(type, ts.SignatureKind.Call).length > 0) return true
9083
if (type.isUnion()) return type.types.some(type => isMethodCompletionCall(type, checker))
9184
}
9285

9386
const isStringCompletion = (type: ts.Type) => {
9487
if (type.flags & ts.TypeFlags.Undefined) return true
95-
if (type.isStringLiteral()) return true
88+
if (type.flags & ts.TypeFlags.StringLike) return true
9689
if (type.isUnion()) return type.types.every(type => isStringCompletion(type))
9790
return false
9891
}
9992

10093
const isArrayCompletion = (type: ts.Type, checker: ts.TypeChecker) => {
94+
if (type.flags & ts.TypeFlags.Any) return false
10195
if (type.flags & ts.TypeFlags.Undefined) return true
10296
if (checker['isArrayLikeType'](type)) return true
10397
if (type.isUnion()) return type.types.every(type => isArrayCompletion(type, checker))

0 commit comments

Comments
 (0)