|
1 | | -import { GetConfig } from '../types' |
2 | 1 | import { getFullTypeChecker, isTs5 } from '../utils' |
3 | 2 | import { sharedCompletionContext } from './sharedContext' |
4 | 3 |
|
5 | | -export default ( |
6 | | - entries: ts.CompletionEntry[], |
7 | | - node: ts.Node, |
8 | | - languageService: ts.LanguageService, |
9 | | - preferences: ts.UserPreferences, |
10 | | - c: GetConfig, |
11 | | -): ts.CompletionEntry[] | void => { |
12 | | - const { position } = sharedCompletionContext |
| 4 | +export default (prior: ts.CompletionInfo): ts.CompletionEntry[] | void => { |
| 5 | + const { entries, isMemberCompletion } = prior |
| 6 | + let { position, c, node, languageService, preferences } = sharedCompletionContext |
| 7 | + if (!node || entries.length === 0 || !isMemberCompletion) return |
13 | 8 |
|
14 | | - if (entries.length > 0 && node) { |
15 | | - const enableMoreVariants = c('objectLiteralCompletions.moreVariants') |
16 | | - const keepOriginal = c('objectLiteralCompletions.keepOriginal') |
17 | | - if (!preferences.includeCompletionsWithObjectLiteralMethodSnippets && !enableMoreVariants) return |
18 | | - // plans to make it hihgly configurable! e.g. if user wants to make some subtype leading (e.g. from [] | {}) |
19 | | - if (ts.isIdentifier(node)) node = node.parent |
20 | | - if (ts.isShorthandPropertyAssignment(node)) node = node.parent |
21 | | - const nextChar = node.getSourceFile().getFullText()[position] |
22 | | - if (!ts.isObjectLiteralExpression(node) || nextChar === ':') return |
| 9 | + const enableMoreVariants = c('objectLiteralCompletions.moreVariants') |
| 10 | + const keepOriginal = c('objectLiteralCompletions.keepOriginal') |
| 11 | + if (!preferences.includeCompletionsWithObjectLiteralMethodSnippets && !enableMoreVariants) return |
| 12 | + // plans to make it hihgly configurable! e.g. if user wants to make some subtype leading (e.g. from [] | {}) |
| 13 | + if (ts.isIdentifier(node)) node = node.parent |
| 14 | + if (ts.isShorthandPropertyAssignment(node)) node = node.parent |
| 15 | + const nextChar = node.getSourceFile().getFullText()[position] |
| 16 | + if (!ts.isObjectLiteralExpression(node) || nextChar === ':') return |
23 | 17 |
|
24 | | - entries = [...entries] |
25 | | - const typeChecker = languageService.getProgram()!.getTypeChecker()! |
26 | | - const objType = typeChecker.getContextualType(node) |
27 | | - let oldProperties: ts.Symbol[] | undefined |
| 18 | + const typeChecker = languageService.getProgram()!.getTypeChecker()! |
| 19 | + const objType = typeChecker.getContextualType(node) |
| 20 | + let oldProperties: ts.Symbol[] | undefined |
| 21 | + if (!isTs5()) { |
| 22 | + if (!objType) return |
| 23 | + oldProperties = getAllPropertiesOfType(objType, typeChecker) |
| 24 | + } |
| 25 | + // eslint-disable-next-line unicorn/no-useless-spread |
| 26 | + for (const entry of [...entries]) { |
| 27 | + let type: ts.Type | undefined |
28 | 28 | if (!isTs5()) { |
29 | | - if (!objType) return |
30 | | - oldProperties = getAllPropertiesOfType(objType, typeChecker) |
| 29 | + const property = oldProperties!.find(property => property.name === entry.name) |
| 30 | + if (!property) continue |
| 31 | + type = typeChecker.getTypeOfSymbolAtLocation(property, node) |
| 32 | + } else if (entry.symbol) { |
| 33 | + type = typeChecker.getTypeOfSymbol(entry.symbol) |
31 | 34 | } |
32 | | - for (const entry of entries) { |
33 | | - let type: ts.Type | undefined |
34 | | - if (!isTs5()) { |
35 | | - const property = oldProperties!.find(property => property.name === entry.name) |
36 | | - if (!property) continue |
37 | | - type = typeChecker.getTypeOfSymbolAtLocation(property, node) |
38 | | - } else if (entry.symbol) { |
39 | | - type = typeChecker.getTypeOfSymbol(entry.symbol) |
40 | | - } |
41 | | - if (!type) continue |
42 | | - if (isFunctionType(type, typeChecker)) { |
43 | | - if (['above', 'remove'].includes(keepOriginal) && preferences.includeCompletionsWithObjectLiteralMethodSnippets) { |
44 | | - const methodEntryIndex = entries.findIndex(e => e.name === entry.name && isObjectLiteralMethodSnippet(e)) |
45 | | - const methodEntry = entries[methodEntryIndex] |
46 | | - if (methodEntry) { |
47 | | - entries.splice(methodEntryIndex, 1) |
48 | | - entries.splice(entries.indexOf(entry) + (keepOriginal === 'before' ? 1 : 0), keepOriginal === 'remove' ? 1 : 0, { |
49 | | - ...methodEntry, |
50 | | - // let correctSorting.enable sort it |
51 | | - sortText: entry.sortText, |
52 | | - }) |
53 | | - } |
| 35 | + if (!type) continue |
| 36 | + if (isFunctionType(type, typeChecker)) { |
| 37 | + if (['above', 'remove'].includes(keepOriginal) && preferences.includeCompletionsWithObjectLiteralMethodSnippets) { |
| 38 | + const methodEntryIndex = entries.findIndex(e => e.name === entry.name && isObjectLiteralMethodSnippet(e)) |
| 39 | + const methodEntry = entries[methodEntryIndex] |
| 40 | + if (methodEntry) { |
| 41 | + entries.splice(methodEntryIndex, 1) |
| 42 | + entries.splice(entries.indexOf(entry) + (keepOriginal === 'before' ? 1 : 0), keepOriginal === 'remove' ? 1 : 0, { |
| 43 | + ...methodEntry, |
| 44 | + // let correctSorting.enable sort it |
| 45 | + sortText: entry.sortText, |
| 46 | + }) |
54 | 47 | } |
55 | | - continue |
56 | | - } |
57 | | - if (!enableMoreVariants) continue |
58 | | - const getQuotedSnippet = (): [string, string] => { |
59 | | - const quote = tsFull.getQuoteFromPreference(tsFull.getQuotePreference(node.getSourceFile() as any, preferences)) |
60 | | - return [`: ${quote}$1${quote},$0`, `: ${quote}${quote},`] |
61 | 48 | } |
62 | | - const insertObjectArrayInnerText = c('objectLiteralCompletions.insertNewLine') ? '\n\t$1\n' : '$1' |
63 | | - const booleanCompletion = getBooleanCompletion(type, typeChecker) |
64 | | - const completingStyleMap = [ |
65 | | - [getQuotedSnippet, isStringCompletion], |
66 | | - [[`: ${booleanCompletion?.[0] ?? ''},`, `: ${booleanCompletion?.[0] ?? ''}`], () => booleanCompletion?.length === 1], |
67 | | - [[': ${1|true,false|},$0', `: true/false,`], () => booleanCompletion?.length === 2], |
68 | | - [[`: [${insertObjectArrayInnerText}],$0`, `: [],`], isArrayCompletion], |
69 | | - [[`: {${insertObjectArrayInnerText}},$0`, `: {},`], isObjectCompletion], |
70 | | - ] as const |
71 | | - const fallbackSnippet = c('objectLiteralCompletions.fallbackVariant') ? ([': $0,', ': ,'] as const) : undefined |
72 | | - const insertSnippetVariant = completingStyleMap.find(([, detector]) => detector(type!, typeChecker))?.[0] ?? fallbackSnippet |
73 | | - if (!insertSnippetVariant) continue |
74 | | - const [insertSnippetText, insertSnippetPreview] = typeof insertSnippetVariant === 'function' ? insertSnippetVariant() : insertSnippetVariant |
75 | | - const insertText = entry.name + insertSnippetText |
76 | | - const index = entries.indexOf(entry) |
77 | | - entries.splice(index + (keepOriginal === 'before' ? 1 : 0), keepOriginal === 'remove' ? 1 : 0, { |
78 | | - ...entry, |
79 | | - // todo setting incompatible!!! |
80 | | - sortText: entry.sortText, |
81 | | - labelDetails: { |
82 | | - detail: insertSnippetPreview, |
83 | | - }, |
84 | | - insertText, |
85 | | - isSnippet: true, |
86 | | - }) |
| 49 | + continue |
87 | 50 | } |
88 | | - return entries |
| 51 | + if (!enableMoreVariants) continue |
| 52 | + const getQuotedSnippet = (): [string, string] => { |
| 53 | + const quote = tsFull.getQuoteFromPreference(tsFull.getQuotePreference(node!.getSourceFile() as any, preferences)) |
| 54 | + return [`: ${quote}$1${quote},$0`, `: ${quote}${quote},`] |
| 55 | + } |
| 56 | + const insertObjectArrayInnerText = c('objectLiteralCompletions.insertNewLine') ? '\n\t$1\n' : '$1' |
| 57 | + const booleanCompletion = getBooleanCompletion(type, typeChecker) |
| 58 | + const completingStyleMap = [ |
| 59 | + [getQuotedSnippet, isStringCompletion], |
| 60 | + [[`: ${booleanCompletion?.[0] ?? ''},`, `: ${booleanCompletion?.[0] ?? ''}`], () => booleanCompletion?.length === 1], |
| 61 | + [[': ${1|true,false|},$0', `: true/false,`], () => booleanCompletion?.length === 2], |
| 62 | + [[`: [${insertObjectArrayInnerText}],$0`, `: [],`], isArrayCompletion], |
| 63 | + [[`: {${insertObjectArrayInnerText}},$0`, `: {},`], isObjectCompletion], |
| 64 | + ] as const |
| 65 | + const fallbackSnippet = c('objectLiteralCompletions.fallbackVariant') ? ([': $0,', ': ,'] as const) : undefined |
| 66 | + const insertSnippetVariant = completingStyleMap.find(([, detector]) => detector(type!, typeChecker))?.[0] ?? fallbackSnippet |
| 67 | + if (!insertSnippetVariant) continue |
| 68 | + const [insertSnippetText, insertSnippetPreview] = typeof insertSnippetVariant === 'function' ? insertSnippetVariant() : insertSnippetVariant |
| 69 | + const insertText = entry.name + insertSnippetText |
| 70 | + const index = entries.indexOf(entry) |
| 71 | + entries.splice(index + (keepOriginal === 'before' ? 1 : 0), keepOriginal === 'remove' ? 1 : 0, { |
| 72 | + ...entry, |
| 73 | + // todo setting incompatible!!! |
| 74 | + sortText: entry.sortText, |
| 75 | + labelDetails: { |
| 76 | + detail: insertSnippetPreview, |
| 77 | + }, |
| 78 | + insertText, |
| 79 | + isSnippet: true, |
| 80 | + }) |
89 | 81 | } |
| 82 | + return entries |
90 | 83 | } |
91 | 84 |
|
92 | 85 | const isObjectLiteralMethodSnippet = (entry: ts.CompletionEntry) => { |
|
0 commit comments