Skip to content

Commit 2ebf844

Browse files
authored
Merge pull request #2357 from yoyo930021/fix-optional-chaining
Support optional deprecated when completion
2 parents 83c2e47 + 5166dc0 commit 2ebf844

File tree

5 files changed

+55
-6
lines changed

5 files changed

+55
-6
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- 🙌 Add command `Vetur: Restart VLS (Vue Language Server)`. Thanks to contribution from [@yoyo930021](https://github.com/yoyo930021). #2331.
1212
- 🙌 Fix no complete literal string union. Thanks to contribution from [@yoyo930021](https://github.com/yoyo930021). #2300 and #2353.
1313
- 🙌 Add --version command. Thanks to contribution from [@andrewisaburden](https://github.com/andrewisaburden). #2337.
14+
- 🙌 Complete with `?.` for optional properies in completion. Thanks to contribution from [@yoyo930021](https://github.com/yoyo930021). #2326 and #2357.
1415

1516
### 0.28.0 | 2020-09-23 | [VSIX](https://marketplace.visualstudio.com/_apis/public/gallery/publishers/octref/vsextensions/vetur/0.28.0/vspackage)
1617

server/src/modes/script/javascript.ts

+30-4
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ import {
2525
CodeAction,
2626
CodeActionKind,
2727
WorkspaceEdit,
28-
FoldingRangeKind
28+
FoldingRangeKind,
29+
CompletionItemTag
2930
} from 'vscode-languageserver-types';
3031
import { LanguageMode } from '../../embeddedSupport/languageModes';
3132
import { VueDocumentRegions, LanguageRange } from '../../embeddedSupport/embeddedSupport';
@@ -165,7 +166,7 @@ export async function getJavascriptMode(
165166
const range = entry.replacementSpan && convertRange(scriptDoc, entry.replacementSpan);
166167
const { label, detail } = calculateLabelAndDetailTextForPathImport(entry);
167168

168-
return {
169+
const item: CompletionItem = {
169170
uri: doc.uri,
170171
position,
171172
preselect: entry.isRecommended ? true : undefined,
@@ -174,7 +175,7 @@ export async function getJavascriptMode(
174175
filterText: getFilterText(entry.insertText),
175176
sortText: entry.sortText + index,
176177
kind: toCompletionItemKind(entry.kind),
177-
textEdit: range && TextEdit.replace(range, entry.name),
178+
textEdit: range && TextEdit.replace(range, entry.insertText || entry.name),
178179
insertText: entry.insertText,
179180
data: {
180181
// data used for resolving item details (see 'doResolve')
@@ -183,7 +184,22 @@ export async function getJavascriptMode(
183184
offset,
184185
source: entry.source
185186
}
186-
};
187+
} as CompletionItem;
188+
189+
if (entry.kindModifiers) {
190+
const kindModifiers = parseKindModifier(entry.kindModifiers ?? '');
191+
if (kindModifiers.optional) {
192+
item.label += '?';
193+
}
194+
if (kindModifiers.deprecated) {
195+
item.tags = [CompletionItemTag.Deprecated];
196+
}
197+
if (kindModifiers.color) {
198+
item.kind = CompletionItemKind.Color;
199+
}
200+
}
201+
202+
return item;
187203
})
188204
};
189205

@@ -804,6 +820,16 @@ function convertCodeAction(
804820
return textEdits;
805821
}
806822

823+
function parseKindModifier(kindModifiers: string) {
824+
const kinds = new Set(kindModifiers.split(/,|\s+/g));
825+
826+
return {
827+
optional: kinds.has('optional'),
828+
deprecated: kinds.has('deprecated'),
829+
color: kinds.has('color')
830+
};
831+
}
832+
807833
function convertTSDiagnosticCategoryToDiagnosticSeverity(c: ts.DiagnosticCategory) {
808834
switch (c) {
809835
case ts.DiagnosticCategory.Error:

test/lsp/features/completion/script.test.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ describe.only('Should autocomplete for <script>', () => {
66
const basicUri = getDocUri('completion/script/Basic.vue');
77
const hyphenUri = getDocUri('completion/script/Hyphen.vue');
88
const literalUri = getDocUri('completion/script/issue-2300.vue');
9+
const kindModifiersUri = getDocUri('completion/script/kindModifiers.vue');
910

1011
it('completes module names when importing', async () => {
1112
await testCompletion(basicUri, position(5, 8), ['lodash', 'vue', 'vuex']);
@@ -20,7 +21,7 @@ describe.only('Should autocomplete for <script>', () => {
2021
});
2122

2223
it('completes Vue default export methods', async () => {
23-
await testCompletion(basicUri, position(20, 4), ['data', 'props', 'mounted']);
24+
await testCompletion(basicUri, position(20, 4), ['data?', 'props?', 'mounted?']);
2425
});
2526

2627
it('completes hyphen properties in object', async () => {
@@ -29,5 +30,9 @@ describe.only('Should autocomplete for <script>', () => {
2930

3031
it('completes literal string', async () => {
3132
await testCompletion(literalUri, position(3, 6), ['black', 'blue']);
33+
})
34+
35+
it('completes optional properties in object', async () => {
36+
await testCompletion(kindModifiersUri, position(12, 8), [{ label: 'b?', insertTextValue: '?.b' }]);
3237
});
3338
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<script lang="ts">
2+
export const getData = () => {
3+
interface Data {
4+
a?: { b?: 1 }
5+
/** @deprecated no d */
6+
d: 2
7+
}
8+
9+
const res: Data = {
10+
d: 2
11+
}
12+
13+
res.a.
14+
}
15+
16+
getData()
17+
</script>

test/vue3/features/completion/basic.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ describe('Vue 3 integration test', () => {
1010
it('complete `setup`', async () => {
1111
await testCompletion(fileUri, position(6, 2), [
1212
{
13-
label: 'setup',
13+
label: 'setup?',
1414
kind: CompletionItemKind.Field
1515
}
1616
]);

0 commit comments

Comments
 (0)