Skip to content

Commit 0f423c3

Browse files
committed
feat: New completions experience! Display default string completion at object literal (@default jsdoc support)
1 parent efeaed3 commit 0f423c3

File tree

3 files changed

+33
-2
lines changed

3 files changed

+33
-2
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { approveCast } from '../utils'
2+
3+
export default (entries: ts.CompletionEntry[], node: ts.Node, languageService: ts.LanguageService): ts.CompletionEntry[] | void => {
4+
if (entries.length && node) {
5+
if (ts.isStringLiteralLike(node) && approveCast(node.parent, ts.isPropertyAssignment) && ts.isObjectLiteralExpression(node.parent.parent)) {
6+
const typeChecker = languageService.getProgram()!.getTypeChecker()!
7+
const type = typeChecker.getContextualType(node.parent.parent)
8+
if (type) {
9+
const properties = type.getProperties()
10+
const propName = node.parent.name.getText()
11+
const completingPropName = properties.find(({ name }) => name === propName)
12+
const defaultValue = completingPropName?.getJsDocTags().find(({ name, text }) => name === 'default' && text?.length)?.text?.[0]?.text
13+
if (defaultValue) {
14+
const entryIndex = entries.findIndex(({ name, kind }) => name === defaultValue && kind === ts.ScriptElementKind.string)
15+
if (entryIndex === -1) return
16+
const entry = entries[entryIndex]!
17+
const newEntries = [...entries]
18+
newEntries.splice(entryIndex, 1, { ...entry, sortText: `z${entry.sortText}`, sourceDisplay: [{ kind: 'text', text: 'Default' }] })
19+
return newEntries
20+
}
21+
}
22+
}
23+
}
24+
}

typescript/src/completionsAtPosition.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ import { isGoodPositionBuiltinMethodCompletion } from './completions/isGoodPosit
1010
import improveJsxCompletions from './completions/jsxAttributes'
1111
import arrayMethods from './completions/arrayMethods'
1212
import prepareTextForEmmet from './specialCommands/prepareTextForEmmet'
13-
import objectLiteralHelpers from './completions/objectLiteralHelpers'
1413
import switchCaseExcludeCovered from './completions/switchCaseExcludeCovered'
1514
import additionalTypesSuggestions from './completions/additionalTypesSuggestions'
1615
import boostKeywordSuggestions from './completions/boostKeywordSuggestions'
1716
import boostTextSuggestions from './completions/boostNameSuggestions'
1817
import keywordsSpace from './completions/keywordsSpace'
1918
import jsdocDefault from './completions/jsdocDefault'
19+
import defaultHelpers from './completions/defaultHelpers'
2020

2121
export type PrevCompletionMap = Record<string, { originalName?: string; documentationOverride?: string | ts.SymbolDisplayPart[] }>
2222

@@ -142,14 +142,15 @@ export const getCompletionsAtPosition = (
142142
// ({ name }) => name === 'toExponential',
143143
// ({ name }) => name === 'toString',
144144
// )
145-
const indexToPatch = prior.entries.findIndex(({ name }) => name === 'toString')
145+
const indexToPatch = prior.entries.findIndex(({ name, kind }) => name === 'toString' && kind !== ts.ScriptElementKind.warning)
146146
if (indexToPatch !== -1) {
147147
prior.entries[indexToPatch]!.insertText = `${prior.entries[indexToPatch]!.insertText ?? prior.entries[indexToPatch]!.name}()`
148148
prior.entries[indexToPatch]!.kind = ts.ScriptElementKind.constElement
149149
// prior.entries[indexToPatch]!.isSnippet = true
150150
}
151151
}
152152

153+
if (node) prior.entries = defaultHelpers(prior.entries, node, languageService) ?? prior.entries
153154
const banAutoImportPackages = c('suggestions.banAutoImportPackages')
154155
if (banAutoImportPackages?.length)
155156
prior.entries = prior.entries.filter(entry => {

typescript/src/utils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,9 @@ const wordRangeAtPos = (text: string, position: number) => {
169169
}
170170
return text.slice(startPos + 1, endPos)
171171
}
172+
173+
export function approveCast<TOut extends TIn, TIn = any>(value: TIn | undefined, test: (value: TIn) => value is TOut): value is TOut
174+
export function approveCast<T>(value: T, test: (value: T) => boolean): T | undefined
175+
export function approveCast<T>(value: T, test: (value: T) => boolean): T | undefined {
176+
return value !== undefined && test(value) ? value : undefined
177+
}

0 commit comments

Comments
 (0)