@vue/language-service 2.1.8 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/data/language-blocks/cs.json +29 -930
- package/data/language-blocks/en.json +28 -929
- package/data/language-blocks/fr.json +28 -929
- package/data/language-blocks/it.json +28 -929
- package/data/language-blocks/ja.json +28 -929
- package/data/language-blocks/ko.json +28 -929
- package/data/language-blocks/pt.json +28 -929
- package/data/language-blocks/ru.json +28 -929
- package/data/language-blocks/zh-cn.json +30 -931
- package/data/language-blocks/zh-hk.json +28 -929
- package/data/locale.json +54 -0
- package/data/model-modifiers/cs.json +6 -165
- package/data/model-modifiers/en.json +6 -165
- package/data/model-modifiers/fr.json +6 -165
- package/data/model-modifiers/it.json +6 -165
- package/data/model-modifiers/ja.json +6 -165
- package/data/model-modifiers/ko.json +6 -165
- package/data/model-modifiers/pt.json +6 -165
- package/data/model-modifiers/ru.json +6 -165
- package/data/model-modifiers/zh-cn.json +6 -165
- package/data/model-modifiers/zh-hk.json +6 -165
- package/data/template/cs.json +59 -1429
- package/data/template/en.json +52 -1422
- package/data/template/fr.json +55 -1425
- package/data/template/it.json +44 -1422
- package/data/template/ja.json +53 -1423
- package/data/template/ko.json +44 -1422
- package/data/template/pt.json +44 -1422
- package/data/template/ru.json +52 -1422
- package/data/template/zh-cn.json +53 -1423
- package/data/template/zh-hk.json +44 -1422
- package/index.d.ts +2 -2
- package/index.js +3 -1
- package/lib/ideFeatures/nameCasing.js +14 -16
- package/lib/plugins/data.js +47 -20
- package/lib/plugins/vue-autoinsert-dotvalue.d.ts +1 -0
- package/lib/plugins/vue-autoinsert-dotvalue.js +5 -3
- package/lib/plugins/vue-autoinsert-space.js +1 -1
- package/lib/plugins/vue-complete-define-assignment.d.ts +2 -0
- package/lib/plugins/vue-complete-define-assignment.js +83 -0
- package/lib/plugins/vue-directive-comments.js +10 -8
- package/lib/plugins/vue-document-drop.js +15 -12
- package/lib/plugins/vue-document-links.js +45 -39
- package/lib/plugins/vue-extract-file.js +19 -10
- package/lib/plugins/vue-inlayhints.d.ts +1 -1
- package/lib/plugins/vue-inlayhints.js +65 -56
- package/lib/plugins/vue-sfc.js +29 -27
- package/lib/plugins/vue-template.js +194 -162
- package/lib/plugins/vue-twoslash-queries.js +9 -4
- package/package.json +9 -9
- package/scripts/update-html-data.js +74 -70
|
@@ -11,8 +11,19 @@ const vscode_uri_1 = require("vscode-uri");
|
|
|
11
11
|
const nameCasing_1 = require("../ideFeatures/nameCasing");
|
|
12
12
|
const types_1 = require("../types");
|
|
13
13
|
const data_1 = require("./data");
|
|
14
|
-
const specialTags = new Set([
|
|
15
|
-
|
|
14
|
+
const specialTags = new Set([
|
|
15
|
+
'slot',
|
|
16
|
+
'component',
|
|
17
|
+
'template',
|
|
18
|
+
]);
|
|
19
|
+
const specialProps = new Set([
|
|
20
|
+
'class',
|
|
21
|
+
'data-allow-mismatch',
|
|
22
|
+
'is',
|
|
23
|
+
'key',
|
|
24
|
+
'ref',
|
|
25
|
+
'style',
|
|
26
|
+
]);
|
|
16
27
|
let builtInData;
|
|
17
28
|
let modelData;
|
|
18
29
|
function create(mode, ts, getTsPluginClient) {
|
|
@@ -79,8 +90,8 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
79
90
|
modelData ??= (0, data_1.loadModelModifiersData)(context.env.locale ?? 'en');
|
|
80
91
|
// https://vuejs.org/api/built-in-directives.html#v-on
|
|
81
92
|
// https://vuejs.org/api/built-in-directives.html#v-bind
|
|
82
|
-
const
|
|
83
|
-
const
|
|
93
|
+
const vOnModifiers = {};
|
|
94
|
+
const vBindModifiers = {};
|
|
84
95
|
const vOn = builtInData.globalAttributes?.find(x => x.name === 'v-on');
|
|
85
96
|
const vBind = builtInData.globalAttributes?.find(x => x.name === 'v-bind');
|
|
86
97
|
if (vOn) {
|
|
@@ -89,9 +100,9 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
89
100
|
.split('\n- ')[4]
|
|
90
101
|
.split('\n').slice(2, -1);
|
|
91
102
|
for (let text of modifiers) {
|
|
92
|
-
text = text.
|
|
93
|
-
const [name,
|
|
94
|
-
|
|
103
|
+
text = text.slice(' - `.'.length);
|
|
104
|
+
const [name, desc] = text.split('` - ');
|
|
105
|
+
vOnModifiers[name] = desc;
|
|
95
106
|
}
|
|
96
107
|
}
|
|
97
108
|
if (vBind) {
|
|
@@ -100,9 +111,9 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
100
111
|
.split('\n- ')[4]
|
|
101
112
|
.split('\n').slice(2, -1);
|
|
102
113
|
for (let text of modifiers) {
|
|
103
|
-
text = text.
|
|
104
|
-
const [name,
|
|
105
|
-
|
|
114
|
+
text = text.slice(' - `.'.length);
|
|
115
|
+
const [name, desc] = text.split('` - ');
|
|
116
|
+
vBindModifiers[name] = desc;
|
|
106
117
|
}
|
|
107
118
|
}
|
|
108
119
|
const disposable = context.env.onDidChangeConfiguration?.(() => initializing = undefined);
|
|
@@ -123,12 +134,14 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
123
134
|
const vueCompilerOptions = context.project.vue.compilerOptions;
|
|
124
135
|
let sync;
|
|
125
136
|
let currentVersion;
|
|
126
|
-
const
|
|
137
|
+
const uri = vscode_uri_1.URI.parse(document.uri);
|
|
138
|
+
const decoded = context.decodeEmbeddedDocumentUri(uri);
|
|
127
139
|
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
128
|
-
|
|
140
|
+
const root = sourceScript?.generated?.root;
|
|
141
|
+
if (root instanceof language_core_1.VueVirtualCode) {
|
|
129
142
|
// #4298: Precompute HTMLDocument before provideHtmlData to avoid parseHTMLDocument requesting component names from tsserver
|
|
130
143
|
baseServiceInstance.provideCompletionItems?.(document, position, completionContext, token);
|
|
131
|
-
sync = (await provideHtmlData(vueCompilerOptions, sourceScript.id,
|
|
144
|
+
sync = (await provideHtmlData(vueCompilerOptions, sourceScript.id, root)).sync;
|
|
132
145
|
currentVersion = await sync();
|
|
133
146
|
}
|
|
134
147
|
let htmlComplete = await baseServiceInstance.provideCompletionItems?.(document, position, completionContext, token);
|
|
@@ -159,7 +172,6 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
159
172
|
if (!enabled) {
|
|
160
173
|
return;
|
|
161
174
|
}
|
|
162
|
-
const result = [];
|
|
163
175
|
const uri = vscode_uri_1.URI.parse(document.uri);
|
|
164
176
|
const decoded = context.decodeEmbeddedDocumentUri(uri);
|
|
165
177
|
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
@@ -167,88 +179,98 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
167
179
|
if (!virtualCode) {
|
|
168
180
|
return;
|
|
169
181
|
}
|
|
170
|
-
const
|
|
182
|
+
const root = sourceScript?.generated?.root;
|
|
183
|
+
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
171
186
|
const scanner = getScanner(baseServiceInstance, document);
|
|
172
|
-
if (
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
187
|
+
if (!scanner) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const result = [];
|
|
191
|
+
// visualize missing required props
|
|
192
|
+
const casing = await (0, nameCasing_1.getNameCasing)(context, decoded[0]);
|
|
193
|
+
const components = await tsPluginClient?.getComponentNames(root.fileName) ?? [];
|
|
194
|
+
const componentProps = {};
|
|
195
|
+
let token;
|
|
196
|
+
let current;
|
|
197
|
+
while ((token = scanner.scan()) !== html.TokenType.EOS) {
|
|
198
|
+
if (token === html.TokenType.StartTag) {
|
|
199
|
+
const tagName = scanner.getTokenText();
|
|
200
|
+
const checkTag = tagName.includes('.')
|
|
201
|
+
? tagName
|
|
202
|
+
: components.find(component => component === tagName || (0, language_core_1.hyphenateTag)(component) === tagName);
|
|
203
|
+
if (checkTag) {
|
|
204
|
+
componentProps[checkTag] ??= (await tsPluginClient?.getComponentProps(root.fileName, checkTag) ?? [])
|
|
205
|
+
.filter(prop => prop.required)
|
|
206
|
+
.map(prop => prop.name);
|
|
207
|
+
current = {
|
|
208
|
+
unburnedRequiredProps: [...componentProps[checkTag]],
|
|
209
|
+
labelOffset: scanner.getTokenOffset() + scanner.getTokenLength(),
|
|
210
|
+
insertOffset: scanner.getTokenOffset() + scanner.getTokenLength(),
|
|
211
|
+
};
|
|
193
212
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
213
|
+
}
|
|
214
|
+
else if (token === html.TokenType.AttributeName) {
|
|
215
|
+
if (current) {
|
|
216
|
+
let attrText = scanner.getTokenText();
|
|
217
|
+
if (attrText === 'v-bind') {
|
|
218
|
+
current.unburnedRequiredProps = [];
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
// remove modifiers
|
|
222
|
+
if (attrText.includes('.')) {
|
|
223
|
+
attrText = attrText.split('.')[0];
|
|
199
224
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
attrText = attrText.split('.')[0];
|
|
204
|
-
}
|
|
205
|
-
// normalize
|
|
206
|
-
if (attrText.startsWith('v-bind:')) {
|
|
207
|
-
attrText = attrText.substring('v-bind:'.length);
|
|
208
|
-
}
|
|
209
|
-
else if (attrText.startsWith(':')) {
|
|
210
|
-
attrText = attrText.substring(':'.length);
|
|
211
|
-
}
|
|
212
|
-
else if (attrText.startsWith('v-model:')) {
|
|
213
|
-
attrText = attrText.substring('v-model:'.length);
|
|
214
|
-
}
|
|
215
|
-
else if (attrText === 'v-model') {
|
|
216
|
-
attrText = vueCompilerOptions.target >= 3 ? 'modelValue' : 'value'; // TODO: support for experimentalModelPropName?
|
|
217
|
-
}
|
|
218
|
-
else if (attrText.startsWith('@')) {
|
|
219
|
-
attrText = 'on-' + (0, language_core_1.hyphenateAttr)(attrText.substring('@'.length));
|
|
220
|
-
}
|
|
221
|
-
current.unburnedRequiredProps = current.unburnedRequiredProps.filter(propName => {
|
|
222
|
-
return attrText !== propName
|
|
223
|
-
&& attrText !== (0, language_core_1.hyphenateAttr)(propName);
|
|
224
|
-
});
|
|
225
|
+
// normalize
|
|
226
|
+
if (attrText.startsWith('v-bind:')) {
|
|
227
|
+
attrText = attrText.slice('v-bind:'.length);
|
|
225
228
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
result.push({
|
|
232
|
-
label: `${requiredProp}!`,
|
|
233
|
-
paddingLeft: true,
|
|
234
|
-
position: document.positionAt(current.labelOffset),
|
|
235
|
-
kind: 2,
|
|
236
|
-
textEdits: [{
|
|
237
|
-
range: {
|
|
238
|
-
start: document.positionAt(current.insertOffset),
|
|
239
|
-
end: document.positionAt(current.insertOffset),
|
|
240
|
-
},
|
|
241
|
-
newText: ` :${casing.attr === types_1.AttrNameCasing.Kebab ? (0, language_core_1.hyphenateAttr)(requiredProp) : requiredProp}=`,
|
|
242
|
-
}],
|
|
243
|
-
});
|
|
229
|
+
else if (attrText.startsWith(':')) {
|
|
230
|
+
attrText = attrText.slice(':'.length);
|
|
231
|
+
}
|
|
232
|
+
else if (attrText.startsWith('v-model:')) {
|
|
233
|
+
attrText = attrText.slice('v-model:'.length);
|
|
244
234
|
}
|
|
245
|
-
|
|
235
|
+
else if (attrText === 'v-model') {
|
|
236
|
+
attrText = vueCompilerOptions.target >= 3 ? 'modelValue' : 'value'; // TODO: support for experimentalModelPropName?
|
|
237
|
+
}
|
|
238
|
+
else if (attrText.startsWith('v-on:')) {
|
|
239
|
+
attrText = 'on-' + (0, language_core_1.hyphenateAttr)(attrText.slice('v-on:'.length));
|
|
240
|
+
}
|
|
241
|
+
else if (attrText.startsWith('@')) {
|
|
242
|
+
attrText = 'on-' + (0, language_core_1.hyphenateAttr)(attrText.slice('@'.length));
|
|
243
|
+
}
|
|
244
|
+
current.unburnedRequiredProps = current.unburnedRequiredProps.filter(propName => {
|
|
245
|
+
return attrText !== propName
|
|
246
|
+
&& attrText !== (0, language_core_1.hyphenateAttr)(propName);
|
|
247
|
+
});
|
|
246
248
|
}
|
|
247
249
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
250
|
+
}
|
|
251
|
+
else if (token === html.TokenType.StartTagSelfClose || token === html.TokenType.StartTagClose) {
|
|
252
|
+
if (current) {
|
|
253
|
+
for (const requiredProp of current.unburnedRequiredProps) {
|
|
254
|
+
result.push({
|
|
255
|
+
label: `${requiredProp}!`,
|
|
256
|
+
paddingLeft: true,
|
|
257
|
+
position: document.positionAt(current.labelOffset),
|
|
258
|
+
kind: 2,
|
|
259
|
+
textEdits: [{
|
|
260
|
+
range: {
|
|
261
|
+
start: document.positionAt(current.insertOffset),
|
|
262
|
+
end: document.positionAt(current.insertOffset),
|
|
263
|
+
},
|
|
264
|
+
newText: ` :${casing.attr === types_1.AttrNameCasing.Kebab ? (0, language_core_1.hyphenateAttr)(requiredProp) : requiredProp}=`,
|
|
265
|
+
}],
|
|
266
|
+
});
|
|
251
267
|
}
|
|
268
|
+
current = undefined;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (token === html.TokenType.AttributeName || token === html.TokenType.AttributeValue) {
|
|
272
|
+
if (current) {
|
|
273
|
+
current.insertOffset = scanner.getTokenOffset() + scanner.getTokenLength();
|
|
252
274
|
}
|
|
253
275
|
}
|
|
254
276
|
}
|
|
@@ -267,7 +289,6 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
267
289
|
if (!isSupportedDocument(document)) {
|
|
268
290
|
return;
|
|
269
291
|
}
|
|
270
|
-
const originalResult = await baseServiceInstance.provideDiagnostics?.(document, token);
|
|
271
292
|
const uri = vscode_uri_1.URI.parse(document.uri);
|
|
272
293
|
const decoded = context.decodeEmbeddedDocumentUri(uri);
|
|
273
294
|
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
@@ -275,12 +296,13 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
275
296
|
if (!virtualCode) {
|
|
276
297
|
return;
|
|
277
298
|
}
|
|
278
|
-
const
|
|
279
|
-
if (!(
|
|
299
|
+
const root = sourceScript?.generated?.root;
|
|
300
|
+
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
280
301
|
return;
|
|
281
302
|
}
|
|
303
|
+
const originalResult = await baseServiceInstance.provideDiagnostics?.(document, token);
|
|
282
304
|
const templateErrors = [];
|
|
283
|
-
const { template } =
|
|
305
|
+
const { template } = root._sfc;
|
|
284
306
|
if (template) {
|
|
285
307
|
for (const error of template.errors) {
|
|
286
308
|
onCompilerError(error, 1);
|
|
@@ -323,20 +345,23 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
323
345
|
if (!languageService) {
|
|
324
346
|
return;
|
|
325
347
|
}
|
|
326
|
-
const
|
|
348
|
+
const uri = vscode_uri_1.URI.parse(document.uri);
|
|
349
|
+
const decoded = context.decodeEmbeddedDocumentUri(uri);
|
|
327
350
|
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
351
|
+
const root = sourceScript?.generated?.root;
|
|
352
|
+
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const { template } = root._sfc;
|
|
356
|
+
if (!template) {
|
|
357
|
+
return;
|
|
332
358
|
}
|
|
333
|
-
const { template } = sourceScript.generated.root._sfc;
|
|
334
359
|
const spans = common_1.getComponentSpans.call({
|
|
335
360
|
files: context.language.scripts,
|
|
336
361
|
languageService,
|
|
337
362
|
typescript: ts,
|
|
338
363
|
vueOptions: vueCompilerOptions,
|
|
339
|
-
},
|
|
364
|
+
}, root, template, {
|
|
340
365
|
start: document.offsetAt(range.start),
|
|
341
366
|
length: document.offsetAt(range.end) - document.offsetAt(range.start),
|
|
342
367
|
});
|
|
@@ -362,7 +387,7 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
362
387
|
continue;
|
|
363
388
|
}
|
|
364
389
|
if (specialTags.has(tag.name)) {
|
|
365
|
-
tag.name =
|
|
390
|
+
tag.name = generateItemKey('specialTag', tag.name, '');
|
|
366
391
|
}
|
|
367
392
|
else if (casing.tag === types_1.TagNameCasing.Kebab) {
|
|
368
393
|
tag.name = (0, language_core_1.hyphenateTag)(tag.name);
|
|
@@ -411,7 +436,7 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
411
436
|
}
|
|
412
437
|
}
|
|
413
438
|
for (const binding of scriptSetupRanges?.bindings ?? []) {
|
|
414
|
-
const name = vueCode._sfc.scriptSetup.content.
|
|
439
|
+
const name = vueCode._sfc.scriptSetup.content.slice(binding.range.start, binding.range.end);
|
|
415
440
|
if (casing.tag === types_1.TagNameCasing.Kebab) {
|
|
416
441
|
names.add((0, language_core_1.hyphenateTag)(name));
|
|
417
442
|
}
|
|
@@ -444,7 +469,9 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
444
469
|
return [];
|
|
445
470
|
}
|
|
446
471
|
const { attrs, propsInfo, events } = tagInfo;
|
|
447
|
-
const props = propsInfo.map(prop => prop.name)
|
|
472
|
+
const props = propsInfo.map(prop => (0, language_core_1.hyphenateTag)(prop.name).startsWith('on-vnode-')
|
|
473
|
+
? 'onVue:' + prop.name.slice('onVnode'.length)
|
|
474
|
+
: prop.name);
|
|
448
475
|
const attributes = [];
|
|
449
476
|
const _tsCodegen = language_core_1.tsCodegen.get(vueCode._sfc);
|
|
450
477
|
if (_tsCodegen) {
|
|
@@ -456,8 +483,8 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
456
483
|
return [];
|
|
457
484
|
}
|
|
458
485
|
let ctxVars = [
|
|
459
|
-
..._tsCodegen.scriptRanges.get()?.bindings.map(
|
|
460
|
-
..._tsCodegen.scriptSetupRanges.get()?.bindings.map(
|
|
486
|
+
..._tsCodegen.scriptRanges.get()?.bindings.map(({ range }) => vueCode._sfc.script.content.slice(range.start, range.end)) ?? [],
|
|
487
|
+
..._tsCodegen.scriptSetupRanges.get()?.bindings.map(({ range }) => vueCode._sfc.scriptSetup.content.slice(range.start, range.end)) ?? [],
|
|
461
488
|
...templateContextProps,
|
|
462
489
|
];
|
|
463
490
|
ctxVars = [...new Set(ctxVars)];
|
|
@@ -477,7 +504,7 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
477
504
|
const propNameBase = name.startsWith('on-')
|
|
478
505
|
? name.slice('on-'.length)
|
|
479
506
|
: (name['on'.length].toLowerCase() + name.slice('onX'.length));
|
|
480
|
-
const propKey =
|
|
507
|
+
const propKey = generateItemKey('componentEvent', isGlobal ? '*' : tag, propNameBase);
|
|
481
508
|
attributes.push({
|
|
482
509
|
name: 'v-on:' + propNameBase,
|
|
483
510
|
description: propKey,
|
|
@@ -488,7 +515,7 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
488
515
|
}
|
|
489
516
|
else {
|
|
490
517
|
const propName = name;
|
|
491
|
-
const propKey =
|
|
518
|
+
const propKey = generateItemKey('componentProp', isGlobal ? '*' : tag, propName);
|
|
492
519
|
const propDescription = propsInfo.find(prop => {
|
|
493
520
|
const name = casing.attr === types_1.AttrNameCasing.Camel ? prop.name : (0, language_core_1.hyphenateAttr)(prop.name);
|
|
494
521
|
return name === propName;
|
|
@@ -510,7 +537,7 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
510
537
|
}
|
|
511
538
|
for (const event of events) {
|
|
512
539
|
const name = casing.attr === types_1.AttrNameCasing.Camel ? event : (0, language_core_1.hyphenateAttr)(event);
|
|
513
|
-
const propKey =
|
|
540
|
+
const propKey = generateItemKey('componentEvent', tag, name);
|
|
514
541
|
attributes.push({
|
|
515
542
|
name: 'v-on:' + name,
|
|
516
543
|
description: propKey,
|
|
@@ -523,17 +550,17 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
523
550
|
for (const prop of [...props, ...attrs]) {
|
|
524
551
|
if (prop.startsWith('onUpdate:')) {
|
|
525
552
|
const isGlobal = !propsSet.has(prop);
|
|
526
|
-
models.push([isGlobal, prop.
|
|
553
|
+
models.push([isGlobal, prop.slice('onUpdate:'.length)]);
|
|
527
554
|
}
|
|
528
555
|
}
|
|
529
556
|
for (const event of events) {
|
|
530
557
|
if (event.startsWith('update:')) {
|
|
531
|
-
models.push([false, event.
|
|
558
|
+
models.push([false, event.slice('update:'.length)]);
|
|
532
559
|
}
|
|
533
560
|
}
|
|
534
561
|
for (const [isGlobal, model] of models) {
|
|
535
562
|
const name = casing.attr === types_1.AttrNameCasing.Camel ? model : (0, language_core_1.hyphenateAttr)(model);
|
|
536
|
-
const propKey =
|
|
563
|
+
const propKey = generateItemKey('componentProp', isGlobal ? '*' : tag, name);
|
|
537
564
|
attributes.push({
|
|
538
565
|
name: 'v-model:' + name,
|
|
539
566
|
description: propKey,
|
|
@@ -558,30 +585,35 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
558
585
|
};
|
|
559
586
|
}
|
|
560
587
|
function afterHtmlCompletion(completionList, document) {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
588
|
+
do {
|
|
589
|
+
const replacement = getReplacement(completionList, document);
|
|
590
|
+
if (!replacement) {
|
|
591
|
+
break;
|
|
592
|
+
}
|
|
566
593
|
const hasModifier = replacement.text.includes('.');
|
|
567
|
-
|
|
568
|
-
|
|
594
|
+
if (!hasModifier) {
|
|
595
|
+
break;
|
|
596
|
+
}
|
|
597
|
+
const [text, ...modifiers] = replacement.text.split('.');
|
|
598
|
+
const isVOn = text.startsWith('v-on:') || text.startsWith('@') && text.length > 1;
|
|
599
|
+
const isVBind = text.startsWith('v-bind:') || text.startsWith(':') && text.length > 1;
|
|
600
|
+
const isVModel = text.startsWith('v-model:') || text === 'v-model';
|
|
601
|
+
const validModifiers = isVOn ? vOnModifiers
|
|
602
|
+
: isVBind ? vBindModifiers
|
|
569
603
|
: undefined;
|
|
570
|
-
|
|
571
|
-
const textWithoutModifier = replacement.text.split('.')[0];
|
|
572
|
-
if (validModifiers && hasModifier) {
|
|
604
|
+
if (validModifiers) {
|
|
573
605
|
for (const modifier in validModifiers) {
|
|
574
606
|
if (modifiers.includes(modifier)) {
|
|
575
607
|
continue;
|
|
576
608
|
}
|
|
577
|
-
const
|
|
578
|
-
const insertText =
|
|
609
|
+
const description = validModifiers[modifier];
|
|
610
|
+
const insertText = text + modifiers.slice(0, -1).map(m => '.' + m).join('') + '.' + modifier;
|
|
579
611
|
const newItem = {
|
|
580
612
|
label: modifier,
|
|
581
613
|
filterText: insertText,
|
|
582
614
|
documentation: {
|
|
583
615
|
kind: 'markdown',
|
|
584
|
-
value:
|
|
616
|
+
value: description,
|
|
585
617
|
},
|
|
586
618
|
textEdit: {
|
|
587
619
|
range: replacement.textEdit.range,
|
|
@@ -592,12 +624,12 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
592
624
|
completionList.items.push(newItem);
|
|
593
625
|
}
|
|
594
626
|
}
|
|
595
|
-
else if (
|
|
627
|
+
else if (isVModel) {
|
|
596
628
|
for (const modifier of modelData.globalAttributes ?? []) {
|
|
597
629
|
if (modifiers.includes(modifier.name)) {
|
|
598
630
|
continue;
|
|
599
631
|
}
|
|
600
|
-
const insertText =
|
|
632
|
+
const insertText = text + modifiers.slice(0, -1).map(m => '.' + m).join('') + '.' + modifier.name;
|
|
601
633
|
const newItem = {
|
|
602
634
|
label: modifier.name,
|
|
603
635
|
filterText: insertText,
|
|
@@ -615,7 +647,7 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
615
647
|
completionList.items.push(newItem);
|
|
616
648
|
}
|
|
617
649
|
}
|
|
618
|
-
}
|
|
650
|
+
} while (0);
|
|
619
651
|
completionList.items = completionList.items.filter(item => !specialTags.has(parseLabel(item.label).name));
|
|
620
652
|
const htmlDocumentations = new Map();
|
|
621
653
|
for (const item of completionList.items) {
|
|
@@ -625,29 +657,30 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
625
657
|
}
|
|
626
658
|
}
|
|
627
659
|
for (const item of completionList.items) {
|
|
628
|
-
const
|
|
629
|
-
if (
|
|
630
|
-
const name =
|
|
631
|
-
item.label =
|
|
660
|
+
const parsedLabelKey = parseItemKey(item.label);
|
|
661
|
+
if (parsedLabelKey) {
|
|
662
|
+
const name = parsedLabelKey.tag;
|
|
663
|
+
item.label = parsedLabelKey.leadingSlash ? '/' + name : name;
|
|
664
|
+
const text = parsedLabelKey.leadingSlash ? `/${name}>` : name;
|
|
632
665
|
if (item.textEdit) {
|
|
633
|
-
item.textEdit.newText =
|
|
666
|
+
item.textEdit.newText = text;
|
|
634
667
|
}
|
|
635
668
|
;
|
|
636
669
|
if (item.insertText) {
|
|
637
|
-
item.insertText =
|
|
670
|
+
item.insertText = text;
|
|
638
671
|
}
|
|
639
672
|
if (item.sortText) {
|
|
640
|
-
item.sortText =
|
|
673
|
+
item.sortText = text;
|
|
641
674
|
}
|
|
642
675
|
}
|
|
643
676
|
const itemKeyStr = typeof item.documentation === 'string' ? item.documentation : item.documentation?.value;
|
|
644
|
-
let
|
|
645
|
-
if (
|
|
677
|
+
let parsedItemKey = itemKeyStr ? parseItemKey(itemKeyStr) : undefined;
|
|
678
|
+
if (parsedItemKey) {
|
|
646
679
|
const documentations = [];
|
|
647
|
-
if (tsDocumentations.has(
|
|
648
|
-
documentations.push(tsDocumentations.get(
|
|
680
|
+
if (tsDocumentations.has(parsedItemKey.prop)) {
|
|
681
|
+
documentations.push(tsDocumentations.get(parsedItemKey.prop));
|
|
649
682
|
}
|
|
650
|
-
let { isEvent, propName } = getPropName(
|
|
683
|
+
let { isEvent, propName } = getPropName(parsedItemKey);
|
|
651
684
|
if (isEvent) {
|
|
652
685
|
// click -> onclick
|
|
653
686
|
propName = 'on' + propName;
|
|
@@ -667,14 +700,15 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
667
700
|
}
|
|
668
701
|
else {
|
|
669
702
|
let propName = item.label;
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
703
|
+
for (const str of ['v-bind:', ':']) {
|
|
704
|
+
if (propName.startsWith(str) && propName !== str) {
|
|
705
|
+
propName = propName.slice(str.length);
|
|
706
|
+
break;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
// for special props without internal item key
|
|
710
|
+
if (specialProps.has(propName)) {
|
|
711
|
+
parsedItemKey = {
|
|
678
712
|
type: 'componentProp',
|
|
679
713
|
tag: '^',
|
|
680
714
|
prop: propName,
|
|
@@ -693,27 +727,26 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
693
727
|
}
|
|
694
728
|
}
|
|
695
729
|
const tokens = [];
|
|
696
|
-
if (item.kind === 10
|
|
730
|
+
if (item.kind === 10
|
|
731
|
+
&& lastCompletionComponentNames.has((0, language_core_1.hyphenateTag)(item.label))) {
|
|
697
732
|
item.kind = 6;
|
|
698
733
|
tokens.push('\u0000');
|
|
699
734
|
}
|
|
700
|
-
else if (
|
|
701
|
-
const isComponent =
|
|
702
|
-
const { isEvent, propName } = getPropName(
|
|
703
|
-
if (
|
|
735
|
+
else if (parsedItemKey) {
|
|
736
|
+
const isComponent = parsedItemKey.tag !== '*';
|
|
737
|
+
const { isEvent, propName } = getPropName(parsedItemKey);
|
|
738
|
+
if (parsedItemKey.type === 'componentProp') {
|
|
704
739
|
if (isComponent || specialProps.has(propName)) {
|
|
705
740
|
item.kind = 5;
|
|
706
741
|
}
|
|
707
742
|
}
|
|
708
743
|
else if (isEvent) {
|
|
709
744
|
item.kind = 23;
|
|
710
|
-
if (propName.startsWith('
|
|
745
|
+
if (propName.startsWith('vue:')) {
|
|
711
746
|
tokens.push('\u0004');
|
|
712
747
|
}
|
|
713
748
|
}
|
|
714
|
-
if (isComponent
|
|
715
|
-
|| (isComponent && isEvent)
|
|
716
|
-
|| specialProps.has(propName)) {
|
|
749
|
+
if (isComponent || specialProps.has(propName)) {
|
|
717
750
|
tokens.push('\u0000');
|
|
718
751
|
if (item.label.startsWith(':')) {
|
|
719
752
|
tokens.push('\u0001');
|
|
@@ -724,9 +757,12 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
724
757
|
else if (item.label.startsWith('v-bind:')) {
|
|
725
758
|
tokens.push('\u0003');
|
|
726
759
|
}
|
|
727
|
-
else if (item.label.startsWith('v-
|
|
760
|
+
else if (item.label.startsWith('v-model:')) {
|
|
728
761
|
tokens.push('\u0004');
|
|
729
762
|
}
|
|
763
|
+
else if (item.label.startsWith('v-on:')) {
|
|
764
|
+
tokens.push('\u0005');
|
|
765
|
+
}
|
|
730
766
|
else {
|
|
731
767
|
tokens.push('\u0000');
|
|
732
768
|
}
|
|
@@ -738,10 +774,6 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
738
774
|
}
|
|
739
775
|
}
|
|
740
776
|
}
|
|
741
|
-
else if (specialProps.has(item.label)) {
|
|
742
|
-
item.kind = 5;
|
|
743
|
-
tokens.push('\u0000', '\u0000', '\u0001');
|
|
744
|
-
}
|
|
745
777
|
else if (item.label === 'v-if'
|
|
746
778
|
|| item.label === 'v-else-if'
|
|
747
779
|
|| item.label === 'v-else'
|
|
@@ -818,13 +850,13 @@ function parseLabel(label) {
|
|
|
818
850
|
leadingSlash
|
|
819
851
|
};
|
|
820
852
|
}
|
|
821
|
-
function
|
|
853
|
+
function generateItemKey(type, tag, prop) {
|
|
822
854
|
return '__VLS_data=' + type + ',' + tag + ',' + prop;
|
|
823
855
|
}
|
|
824
856
|
function isItemKey(key) {
|
|
825
857
|
return key.startsWith('__VLS_data=');
|
|
826
858
|
}
|
|
827
|
-
function
|
|
859
|
+
function parseItemKey(key) {
|
|
828
860
|
const { leadingSlash, name } = parseLabel(key);
|
|
829
861
|
if (isItemKey(name)) {
|
|
830
862
|
const strs = name.slice('__VLS_data='.length).split(',');
|