|
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 |
| - const typeChecker = languageService.getProgram()!.getTypeChecker()! |
25 |
| - const objType = typeChecker.getContextualType(node) |
26 |
| - 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 |
27 | 28 | if (!isTs5()) {
|
28 |
| - if (!objType) return |
29 |
| - 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) |
30 | 34 | }
|
31 |
| - // eslint-disable-next-line unicorn/no-useless-spread |
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