@vue/language-service 3.0.2 → 3.0.4
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/index.d.ts +1 -12
- package/index.js +14 -15
- package/lib/plugins/css.js +9 -17
- package/lib/plugins/typescript-semantic-tokens.d.ts +2 -2
- package/lib/plugins/typescript-semantic-tokens.js +6 -14
- package/lib/plugins/utils.d.ts +8 -2
- package/lib/plugins/utils.js +39 -6
- package/lib/plugins/vue-autoinsert-dotvalue.d copy.d.ts +2 -0
- package/lib/plugins/vue-autoinsert-dotvalue.d copy.js +3 -0
- package/lib/plugins/vue-autoinsert-dotvalue.d.ts +2 -2
- package/lib/plugins/vue-autoinsert-dotvalue.js +15 -32
- package/lib/plugins/vue-compiler-dom-errors.js +17 -35
- package/lib/plugins/vue-component-semantic-tokens.d.ts +2 -2
- package/lib/plugins/vue-component-semantic-tokens.js +35 -49
- package/lib/plugins/vue-destructured-props-hints.d.ts +7 -0
- package/lib/plugins/vue-destructured-props-hints.js +220 -0
- package/lib/plugins/vue-document-drop.d.ts +2 -2
- package/lib/plugins/vue-document-drop.js +12 -26
- package/lib/plugins/vue-document-highlights.d.ts +1 -2
- package/lib/plugins/vue-document-highlights.js +6 -13
- package/lib/plugins/vue-extract-file.d.ts +2 -2
- package/lib/plugins/vue-extract-file.js +10 -25
- package/lib/plugins/vue-global-types-error.js +28 -14
- package/lib/plugins/vue-inlayhints.js +14 -15
- package/lib/plugins/vue-missing-props-hints.d.ts +2 -2
- package/lib/plugins/vue-missing-props-hints.js +7 -23
- package/lib/plugins/vue-scoped-class-links.d.ts +2 -0
- package/lib/plugins/vue-scoped-class-links.js +62 -0
- package/lib/plugins/vue-sfc.js +140 -143
- package/lib/plugins/vue-suggest-define-assignment.js +3 -13
- package/lib/plugins/vue-template-ref-links.d.ts +2 -0
- package/lib/plugins/vue-template-ref-links.js +57 -0
- package/lib/plugins/vue-template.d.ts +2 -2
- package/lib/plugins/vue-template.js +320 -353
- package/lib/plugins/vue-twoslash-queries.d.ts +2 -2
- package/lib/plugins/vue-twoslash-queries.js +6 -15
- package/package.json +7 -7
|
@@ -9,6 +9,7 @@ const html = require("vscode-html-languageservice");
|
|
|
9
9
|
const vscode_uri_1 = require("vscode-uri");
|
|
10
10
|
const nameCasing_1 = require("../nameCasing");
|
|
11
11
|
const data_1 = require("./data");
|
|
12
|
+
const utils_1 = require("./utils");
|
|
12
13
|
const specialTags = new Set([
|
|
13
14
|
'slot',
|
|
14
15
|
'component',
|
|
@@ -24,11 +25,9 @@ const specialProps = new Set([
|
|
|
24
25
|
]);
|
|
25
26
|
let builtInData;
|
|
26
27
|
let modelData;
|
|
27
|
-
function create(mode,
|
|
28
|
+
function create(mode, tsPluginClient) {
|
|
28
29
|
let customData = [];
|
|
29
30
|
let extraCustomData = [];
|
|
30
|
-
let lastCompletionComponentNames = new Set();
|
|
31
|
-
const cachedPropInfos = new Map();
|
|
32
31
|
const onDidChangeCustomDataListeners = new Set();
|
|
33
32
|
const onDidChangeCustomData = (listener) => {
|
|
34
33
|
onDidChangeCustomDataListeners.add(listener);
|
|
@@ -40,6 +39,7 @@ function create(mode, getTsPluginClient) {
|
|
|
40
39
|
};
|
|
41
40
|
const baseService = mode === 'pug'
|
|
42
41
|
? (0, volar_service_pug_1.create)({
|
|
42
|
+
useDefaultDataProvider: false,
|
|
43
43
|
getCustomData() {
|
|
44
44
|
return [
|
|
45
45
|
...customData,
|
|
@@ -50,6 +50,7 @@ function create(mode, getTsPluginClient) {
|
|
|
50
50
|
})
|
|
51
51
|
: (0, volar_service_html_1.create)({
|
|
52
52
|
documentSelector: ['html', 'markdown'],
|
|
53
|
+
useDefaultDataProvider: false,
|
|
53
54
|
getCustomData() {
|
|
54
55
|
return [
|
|
55
56
|
...customData,
|
|
@@ -58,6 +59,8 @@ function create(mode, getTsPluginClient) {
|
|
|
58
59
|
},
|
|
59
60
|
onDidChangeCustomData,
|
|
60
61
|
});
|
|
62
|
+
const htmlDataProvider = html.getDefaultHTMLDataProvider();
|
|
63
|
+
const languageId = mode === 'pug' ? 'jade' : 'html';
|
|
61
64
|
return {
|
|
62
65
|
name: `vue-template (${mode})`,
|
|
63
66
|
capabilities: {
|
|
@@ -71,7 +74,6 @@ function create(mode, getTsPluginClient) {
|
|
|
71
74
|
hoverProvider: true,
|
|
72
75
|
},
|
|
73
76
|
create(context) {
|
|
74
|
-
const tsPluginClient = getTsPluginClient?.(context);
|
|
75
77
|
const baseServiceInstance = baseService.create(context);
|
|
76
78
|
builtInData ??= (0, data_1.loadTemplateData)(context.env.locale ?? 'en');
|
|
77
79
|
modelData ??= (0, data_1.loadModelModifiersData)(context.env.locale ?? 'en');
|
|
@@ -84,7 +86,9 @@ function create(mode, getTsPluginClient) {
|
|
|
84
86
|
const vBind = builtInData.globalAttributes?.find(x => x.name === 'v-bind');
|
|
85
87
|
const vModel = builtInData.globalAttributes?.find(x => x.name === 'v-model');
|
|
86
88
|
if (vOn) {
|
|
87
|
-
const markdown =
|
|
89
|
+
const markdown = typeof vOn.description === 'object'
|
|
90
|
+
? vOn.description.value
|
|
91
|
+
: vOn.description ?? '';
|
|
88
92
|
const modifiers = markdown
|
|
89
93
|
.split('\n- ')[4]
|
|
90
94
|
.split('\n').slice(2, -1);
|
|
@@ -95,7 +99,9 @@ function create(mode, getTsPluginClient) {
|
|
|
95
99
|
}
|
|
96
100
|
}
|
|
97
101
|
if (vBind) {
|
|
98
|
-
const markdown =
|
|
102
|
+
const markdown = typeof vBind.description === 'object'
|
|
103
|
+
? vBind.description.value
|
|
104
|
+
: vBind.description ?? '';
|
|
99
105
|
const modifiers = markdown
|
|
100
106
|
.split('\n- ')[4]
|
|
101
107
|
.split('\n').slice(2, -1);
|
|
@@ -109,7 +115,7 @@ function create(mode, getTsPluginClient) {
|
|
|
109
115
|
for (const modifier of modelData.globalAttributes ?? []) {
|
|
110
116
|
const description = typeof modifier.description === 'object'
|
|
111
117
|
? modifier.description.value
|
|
112
|
-
: modifier.description;
|
|
118
|
+
: modifier.description ?? '';
|
|
113
119
|
const references = modifier.references?.map(ref => `[${ref.name}](${ref.url})`).join(' | ');
|
|
114
120
|
vModelModifiers[modifier.name] = description + '\n\n' + references;
|
|
115
121
|
}
|
|
@@ -123,94 +129,211 @@ function create(mode, getTsPluginClient) {
|
|
|
123
129
|
disposable?.dispose();
|
|
124
130
|
},
|
|
125
131
|
async provideCompletionItems(document, position, completionContext, token) {
|
|
126
|
-
|
|
132
|
+
const info = (0, utils_1.getEmbeddedInfo)(context, document, 'template', languageId);
|
|
133
|
+
if (!info) {
|
|
127
134
|
return;
|
|
128
135
|
}
|
|
129
|
-
|
|
136
|
+
const { sourceScript, root } = info;
|
|
137
|
+
const { result: completionList, target, info: { components, propMap, }, } = await runWithVueData(sourceScript.id, root, () => baseServiceInstance.provideCompletionItems(document, position, completionContext, token));
|
|
138
|
+
if (!completionList) {
|
|
130
139
|
return;
|
|
131
140
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
currentVersion = await sync();
|
|
143
|
-
}
|
|
144
|
-
let htmlComplete = await baseServiceInstance.provideCompletionItems?.(document, position, completionContext, token);
|
|
145
|
-
while (currentVersion !== (currentVersion = await sync?.())) {
|
|
146
|
-
htmlComplete = await baseServiceInstance.provideCompletionItems?.(document, position, completionContext, token);
|
|
141
|
+
switch (target) {
|
|
142
|
+
case 'tag': {
|
|
143
|
+
completionList.items.forEach(transformTag);
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
case 'attribute': {
|
|
147
|
+
addDirectiveModifiers(completionList, document);
|
|
148
|
+
completionList.items.forEach(transformAttribute);
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
147
151
|
}
|
|
148
|
-
|
|
149
|
-
|
|
152
|
+
updateExtraCustomData([]);
|
|
153
|
+
return completionList;
|
|
154
|
+
function transformTag(item) {
|
|
155
|
+
const tagName = (0, shared_1.capitalize)((0, shared_1.camelize)(item.label));
|
|
156
|
+
if (components?.includes(tagName)) {
|
|
157
|
+
item.kind = 6;
|
|
158
|
+
item.sortText = '\u0000' + (item.sortText ?? item.label);
|
|
159
|
+
}
|
|
150
160
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (
|
|
154
|
-
|
|
155
|
-
|
|
161
|
+
function transformAttribute(item) {
|
|
162
|
+
let prop = propMap.get(item.label);
|
|
163
|
+
if (prop) {
|
|
164
|
+
if (prop.info?.documentation) {
|
|
165
|
+
item.documentation = {
|
|
166
|
+
kind: 'markdown',
|
|
167
|
+
value: prop.info.documentation,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if (prop.info?.deprecated) {
|
|
171
|
+
item.tags = [1];
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
let name = item.label;
|
|
176
|
+
for (const str of ['v-bind:', ':']) {
|
|
177
|
+
if (name.startsWith(str) && name !== str) {
|
|
178
|
+
name = name.slice(str.length);
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (specialProps.has(name)) {
|
|
183
|
+
prop = {
|
|
184
|
+
name,
|
|
185
|
+
kind: 'prop',
|
|
186
|
+
isGlobal: true,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const tokens = [];
|
|
191
|
+
if (prop) {
|
|
192
|
+
const { isEvent, propName } = getPropName(prop.name, prop.kind === 'event');
|
|
193
|
+
if (prop.kind === 'prop') {
|
|
194
|
+
if (!prop.isGlobal || specialProps.has(propName)) {
|
|
195
|
+
item.kind = 5;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
else if (isEvent) {
|
|
199
|
+
item.kind = 23;
|
|
200
|
+
if (propName.startsWith('vue:')) {
|
|
201
|
+
tokens.push('\u0004');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (!prop.isGlobal || specialProps.has(propName)) {
|
|
205
|
+
tokens.push('\u0000');
|
|
206
|
+
if (item.label.startsWith(':')) {
|
|
207
|
+
tokens.push('\u0001');
|
|
208
|
+
}
|
|
209
|
+
else if (item.label.startsWith('@')) {
|
|
210
|
+
tokens.push('\u0002');
|
|
211
|
+
}
|
|
212
|
+
else if (item.label.startsWith('v-bind:')) {
|
|
213
|
+
tokens.push('\u0003');
|
|
214
|
+
}
|
|
215
|
+
else if (item.label.startsWith('v-model:')) {
|
|
216
|
+
tokens.push('\u0004');
|
|
217
|
+
}
|
|
218
|
+
else if (item.label.startsWith('v-on:')) {
|
|
219
|
+
tokens.push('\u0005');
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
tokens.push('\u0000');
|
|
223
|
+
}
|
|
224
|
+
if (specialProps.has(propName)) {
|
|
225
|
+
tokens.push('\u0001');
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
tokens.push('\u0000');
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
else if (item.label === 'v-if'
|
|
233
|
+
|| item.label === 'v-else-if'
|
|
234
|
+
|| item.label === 'v-else'
|
|
235
|
+
|| item.label === 'v-for') {
|
|
236
|
+
item.kind = 14;
|
|
237
|
+
tokens.push('\u0003');
|
|
238
|
+
}
|
|
239
|
+
else if (item.label.startsWith('v-')) {
|
|
240
|
+
item.kind = 3;
|
|
241
|
+
tokens.push('\u0002');
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
tokens.push('\u0001');
|
|
156
245
|
}
|
|
246
|
+
item.sortText = tokens.join('') + (item.sortText ?? item.label);
|
|
157
247
|
}
|
|
158
|
-
return htmlComplete;
|
|
159
248
|
},
|
|
160
249
|
provideHover(document, position, token) {
|
|
161
|
-
|
|
250
|
+
const info = (0, utils_1.getEmbeddedInfo)(context, document, 'template', languageId);
|
|
251
|
+
if (!info) {
|
|
162
252
|
return;
|
|
163
253
|
}
|
|
164
254
|
if (context.decodeEmbeddedDocumentUri(vscode_uri_1.URI.parse(document.uri))) {
|
|
165
|
-
updateExtraCustomData([
|
|
255
|
+
updateExtraCustomData([
|
|
256
|
+
htmlDataProvider,
|
|
257
|
+
]);
|
|
166
258
|
}
|
|
167
259
|
return baseServiceInstance.provideHover?.(document, position, token);
|
|
168
260
|
},
|
|
169
261
|
};
|
|
170
|
-
async function
|
|
262
|
+
async function runWithVueData(sourceDocumentUri, root, fn) {
|
|
263
|
+
// #4298: Precompute HTMLDocument before provideHtmlData to avoid parseHTMLDocument requesting component names from tsserver
|
|
264
|
+
await fn();
|
|
265
|
+
const { sync } = await provideHtmlData(sourceDocumentUri, root);
|
|
266
|
+
let lastSync = await sync();
|
|
267
|
+
let result = await fn();
|
|
268
|
+
while (lastSync.version !== (lastSync = await sync()).version) {
|
|
269
|
+
result = await fn();
|
|
270
|
+
}
|
|
271
|
+
return { result, ...lastSync };
|
|
272
|
+
}
|
|
273
|
+
async function provideHtmlData(sourceDocumentUri, root) {
|
|
171
274
|
await (initializing ??= initialize());
|
|
172
275
|
const casing = await (0, nameCasing_1.checkCasing)(context, sourceDocumentUri);
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
tag.name = (0, language_core_1.hyphenateTag)(tag.name);
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
tag.name = (0, shared_1.camelize)((0, shared_1.capitalize)(tag.name));
|
|
186
|
-
}
|
|
276
|
+
for (const tag of builtInData.tags ?? []) {
|
|
277
|
+
if (specialTags.has(tag.name)) {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
if (casing.tag === nameCasing_1.TagNameCasing.Kebab) {
|
|
281
|
+
tag.name = (0, language_core_1.hyphenateTag)(tag.name);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
tag.name = (0, shared_1.camelize)((0, shared_1.capitalize)(tag.name));
|
|
187
285
|
}
|
|
188
286
|
}
|
|
189
|
-
const promises = [];
|
|
190
|
-
const tagInfos = new Map();
|
|
191
287
|
let version = 0;
|
|
288
|
+
let target;
|
|
192
289
|
let components;
|
|
193
|
-
|
|
290
|
+
let values;
|
|
291
|
+
const tasks = [];
|
|
292
|
+
const tagMap = new Map();
|
|
293
|
+
const propMap = new Map();
|
|
194
294
|
updateExtraCustomData([
|
|
295
|
+
{
|
|
296
|
+
getId: () => htmlDataProvider.getId(),
|
|
297
|
+
isApplicable: () => true,
|
|
298
|
+
provideTags() {
|
|
299
|
+
target = 'tag';
|
|
300
|
+
return htmlDataProvider.provideTags()
|
|
301
|
+
.filter(tag => !specialTags.has(tag.name));
|
|
302
|
+
},
|
|
303
|
+
provideAttributes(tag) {
|
|
304
|
+
target = 'attribute';
|
|
305
|
+
const attrs = htmlDataProvider.provideAttributes(tag);
|
|
306
|
+
if (tag === 'slot') {
|
|
307
|
+
const nameAttr = attrs.find(attr => attr.name === 'name');
|
|
308
|
+
if (nameAttr) {
|
|
309
|
+
nameAttr.valueSet = 'slot';
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return attrs;
|
|
313
|
+
},
|
|
314
|
+
provideValues(tag, attr) {
|
|
315
|
+
target = 'value';
|
|
316
|
+
return htmlDataProvider.provideValues(tag, attr);
|
|
317
|
+
},
|
|
318
|
+
},
|
|
195
319
|
html.newHTMLDataProvider('vue-template-built-in', builtInData),
|
|
196
320
|
{
|
|
197
321
|
getId: () => 'vue-template',
|
|
198
322
|
isApplicable: () => true,
|
|
199
323
|
provideTags: () => {
|
|
200
324
|
if (!components) {
|
|
201
|
-
|
|
202
|
-
|
|
325
|
+
components = [];
|
|
326
|
+
tasks.push((async () => {
|
|
327
|
+
components = (await tsPluginClient?.getComponentNames(root.fileName) ?? [])
|
|
203
328
|
.filter(name => name !== 'Transition'
|
|
204
329
|
&& name !== 'TransitionGroup'
|
|
205
330
|
&& name !== 'KeepAlive'
|
|
206
331
|
&& name !== 'Suspense'
|
|
207
332
|
&& name !== 'Teleport');
|
|
208
|
-
lastCompletionComponentNames = new Set(components);
|
|
209
333
|
version++;
|
|
210
334
|
})());
|
|
211
|
-
return [];
|
|
212
335
|
}
|
|
213
|
-
const scriptSetupRanges = language_core_1.tsCodegen.get(
|
|
336
|
+
const scriptSetupRanges = language_core_1.tsCodegen.get(root.sfc)?.getScriptSetupRanges();
|
|
214
337
|
const names = new Set();
|
|
215
338
|
const tags = [];
|
|
216
339
|
for (const tag of components) {
|
|
@@ -222,7 +345,7 @@ function create(mode, getTsPluginClient) {
|
|
|
222
345
|
}
|
|
223
346
|
}
|
|
224
347
|
for (const binding of scriptSetupRanges?.bindings ?? []) {
|
|
225
|
-
const name =
|
|
348
|
+
const name = root.sfc.scriptSetup.content.slice(binding.range.start, binding.range.end);
|
|
226
349
|
if (casing.tag === nameCasing_1.TagNameCasing.Kebab) {
|
|
227
350
|
names.add((0, language_core_1.hyphenateTag)(name));
|
|
228
351
|
}
|
|
@@ -239,84 +362,98 @@ function create(mode, getTsPluginClient) {
|
|
|
239
362
|
return tags;
|
|
240
363
|
},
|
|
241
364
|
provideAttributes: tag => {
|
|
242
|
-
|
|
365
|
+
let tagInfo = tagMap.get(tag);
|
|
243
366
|
if (!tagInfo) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
367
|
+
tagInfo = {
|
|
368
|
+
attrs: [],
|
|
369
|
+
propInfos: [],
|
|
370
|
+
events: [],
|
|
371
|
+
directives: [],
|
|
372
|
+
};
|
|
373
|
+
tagMap.set(tag, tagInfo);
|
|
374
|
+
tasks.push((async () => {
|
|
375
|
+
tagMap.set(tag, {
|
|
376
|
+
attrs: await tsPluginClient?.getElementAttrs(root.fileName, tag) ?? [],
|
|
377
|
+
propInfos: await tsPluginClient?.getComponentProps(root.fileName, tag) ?? [],
|
|
378
|
+
events: await tsPluginClient?.getComponentEvents(root.fileName, tag) ?? [],
|
|
379
|
+
directives: await tsPluginClient?.getComponentDirectives(root.fileName) ?? [],
|
|
254
380
|
});
|
|
255
381
|
version++;
|
|
256
382
|
})());
|
|
257
|
-
return [];
|
|
258
383
|
}
|
|
259
384
|
const { attrs, propInfos, events, directives } = tagInfo;
|
|
260
|
-
for (
|
|
385
|
+
for (let i = 0; i < propInfos.length; i++) {
|
|
386
|
+
const prop = propInfos[i];
|
|
387
|
+
if (prop.name.startsWith('ref_')) {
|
|
388
|
+
propInfos.splice(i--, 1);
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
261
391
|
if ((0, language_core_1.hyphenateTag)(prop.name).startsWith('on-vnode-')) {
|
|
262
|
-
prop.name = 'onVue:' + prop.name
|
|
392
|
+
prop.name = 'onVue:' + prop.name['onVnode'.length].toLowerCase()
|
|
393
|
+
+ prop.name.slice('onVnodeX'.length);
|
|
263
394
|
}
|
|
264
395
|
}
|
|
265
396
|
const attributes = [];
|
|
266
|
-
const
|
|
397
|
+
const propNameSet = new Set(propInfos.map(prop => prop.name));
|
|
267
398
|
for (const prop of [
|
|
268
399
|
...propInfos,
|
|
269
400
|
...attrs.map(attr => ({ name: attr })),
|
|
270
401
|
]) {
|
|
271
|
-
const isGlobal = prop.isAttribute || !
|
|
272
|
-
const
|
|
273
|
-
const isEvent = (0, language_core_1.hyphenateAttr)(
|
|
402
|
+
const isGlobal = prop.isAttribute || !propNameSet.has(prop.name);
|
|
403
|
+
const propName = casing.attr === nameCasing_1.AttrNameCasing.Camel ? prop.name : (0, language_core_1.hyphenateAttr)(prop.name);
|
|
404
|
+
const isEvent = (0, language_core_1.hyphenateAttr)(propName).startsWith('on-');
|
|
274
405
|
if (isEvent) {
|
|
275
|
-
const
|
|
276
|
-
?
|
|
277
|
-
:
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
name
|
|
284
|
-
|
|
285
|
-
|
|
406
|
+
const eventName = casing.attr === nameCasing_1.AttrNameCasing.Camel
|
|
407
|
+
? propName['on'.length].toLowerCase() + propName.slice('onX'.length)
|
|
408
|
+
: propName.slice('on-'.length);
|
|
409
|
+
for (const name of [
|
|
410
|
+
'v-on:' + eventName,
|
|
411
|
+
'@' + eventName,
|
|
412
|
+
]) {
|
|
413
|
+
attributes.push({ name });
|
|
414
|
+
propMap.set(name, {
|
|
415
|
+
name: propName,
|
|
416
|
+
kind: 'event',
|
|
417
|
+
isGlobal,
|
|
418
|
+
info: prop,
|
|
419
|
+
});
|
|
420
|
+
}
|
|
286
421
|
}
|
|
287
422
|
else {
|
|
288
|
-
const propName = name;
|
|
289
423
|
const propInfo = propInfos.find(prop => {
|
|
290
424
|
const name = casing.attr === nameCasing_1.AttrNameCasing.Camel ? prop.name : (0, language_core_1.hyphenateAttr)(prop.name);
|
|
291
425
|
return name === propName;
|
|
292
426
|
});
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
427
|
+
for (const name of [
|
|
428
|
+
propName,
|
|
429
|
+
':' + propName,
|
|
430
|
+
'v-bind:' + propName,
|
|
431
|
+
]) {
|
|
432
|
+
attributes.push({
|
|
433
|
+
name,
|
|
434
|
+
valueSet: prop.values?.some(value => typeof value === 'string') ? '__deferred__' : undefined,
|
|
435
|
+
});
|
|
436
|
+
propMap.set(name, {
|
|
437
|
+
name: propName,
|
|
438
|
+
kind: 'prop',
|
|
439
|
+
isGlobal,
|
|
440
|
+
info: propInfo,
|
|
441
|
+
});
|
|
296
442
|
}
|
|
297
|
-
attributes.push({
|
|
298
|
-
name: propName,
|
|
299
|
-
description: propKey,
|
|
300
|
-
valueSet: prop.values?.some(value => typeof value === 'string') ? '__deferred__' : undefined,
|
|
301
|
-
}, {
|
|
302
|
-
name: ':' + propName,
|
|
303
|
-
description: propKey,
|
|
304
|
-
}, {
|
|
305
|
-
name: 'v-bind:' + propName,
|
|
306
|
-
description: propKey,
|
|
307
|
-
});
|
|
308
443
|
}
|
|
309
444
|
}
|
|
310
445
|
for (const event of events) {
|
|
311
|
-
const
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
name
|
|
318
|
-
|
|
319
|
-
|
|
446
|
+
const eventName = casing.attr === nameCasing_1.AttrNameCasing.Camel ? event : (0, language_core_1.hyphenateAttr)(event);
|
|
447
|
+
for (const name of [
|
|
448
|
+
'v-on:' + eventName,
|
|
449
|
+
'@' + eventName,
|
|
450
|
+
]) {
|
|
451
|
+
attributes.push({ name });
|
|
452
|
+
propMap.set(name, {
|
|
453
|
+
name: eventName,
|
|
454
|
+
kind: 'event',
|
|
455
|
+
});
|
|
456
|
+
}
|
|
320
457
|
}
|
|
321
458
|
for (const directive of directives) {
|
|
322
459
|
const name = (0, language_core_1.hyphenateAttr)(directive);
|
|
@@ -330,7 +467,7 @@ function create(mode, getTsPluginClient) {
|
|
|
330
467
|
...attrs.map(attr => ({ name: attr })),
|
|
331
468
|
]) {
|
|
332
469
|
if (prop.name.startsWith('onUpdate:')) {
|
|
333
|
-
const isGlobal = !
|
|
470
|
+
const isGlobal = !propNameSet.has(prop.name);
|
|
334
471
|
models.push([isGlobal, prop.name.slice('onUpdate:'.length)]);
|
|
335
472
|
}
|
|
336
473
|
}
|
|
@@ -341,224 +478,92 @@ function create(mode, getTsPluginClient) {
|
|
|
341
478
|
}
|
|
342
479
|
for (const [isGlobal, model] of models) {
|
|
343
480
|
const name = casing.attr === nameCasing_1.AttrNameCasing.Camel ? model : (0, language_core_1.hyphenateAttr)(model);
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
name
|
|
347
|
-
|
|
481
|
+
attributes.push({ name: 'v-model:' + name });
|
|
482
|
+
propMap.set('v-model:' + name, {
|
|
483
|
+
name,
|
|
484
|
+
kind: 'prop',
|
|
485
|
+
isGlobal,
|
|
348
486
|
});
|
|
349
487
|
if (model === 'modelValue') {
|
|
350
|
-
|
|
351
|
-
name
|
|
352
|
-
|
|
488
|
+
propMap.set('v-model', {
|
|
489
|
+
name,
|
|
490
|
+
kind: 'prop',
|
|
491
|
+
isGlobal,
|
|
353
492
|
});
|
|
354
493
|
}
|
|
355
494
|
}
|
|
356
495
|
return attributes;
|
|
357
496
|
},
|
|
358
|
-
provideValues: () =>
|
|
497
|
+
provideValues: (tag, attr) => {
|
|
498
|
+
if (!values) {
|
|
499
|
+
values = [];
|
|
500
|
+
tasks.push((async () => {
|
|
501
|
+
if (tag === 'slot' && attr === 'name') {
|
|
502
|
+
values = await tsPluginClient?.getComponentSlots(root.fileName) ?? [];
|
|
503
|
+
}
|
|
504
|
+
version++;
|
|
505
|
+
})());
|
|
506
|
+
}
|
|
507
|
+
return values.map(value => ({
|
|
508
|
+
name: value,
|
|
509
|
+
}));
|
|
510
|
+
},
|
|
359
511
|
},
|
|
360
512
|
]);
|
|
361
513
|
return {
|
|
362
514
|
async sync() {
|
|
363
|
-
await Promise.all(
|
|
364
|
-
return
|
|
515
|
+
await Promise.all(tasks);
|
|
516
|
+
return {
|
|
517
|
+
version,
|
|
518
|
+
target,
|
|
519
|
+
info: {
|
|
520
|
+
components,
|
|
521
|
+
propMap,
|
|
522
|
+
},
|
|
523
|
+
};
|
|
365
524
|
},
|
|
366
525
|
};
|
|
367
526
|
}
|
|
368
|
-
function
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
if (!replacement?.text.includes('.')) {
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
|
-
const [text, ...modifiers] = replacement.text.split('.');
|
|
376
|
-
const isVOn = text.startsWith('v-on:') || text.startsWith('@') && text.length > 1;
|
|
377
|
-
const isVBind = text.startsWith('v-bind:') || text.startsWith(':') && text.length > 1;
|
|
378
|
-
const isVModel = text.startsWith('v-model:') || text === 'v-model';
|
|
379
|
-
const currentModifiers = isVOn
|
|
380
|
-
? vOnModifiers
|
|
381
|
-
: isVBind
|
|
382
|
-
? vBindModifiers
|
|
383
|
-
: isVModel
|
|
384
|
-
? vModelModifiers
|
|
385
|
-
: undefined;
|
|
386
|
-
if (!currentModifiers) {
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
for (const modifier in currentModifiers) {
|
|
390
|
-
if (modifiers.includes(modifier)) {
|
|
391
|
-
continue;
|
|
392
|
-
}
|
|
393
|
-
const description = currentModifiers[modifier];
|
|
394
|
-
const insertText = text + modifiers.slice(0, -1).map(m => '.' + m).join('') + '.' + modifier;
|
|
395
|
-
const newItem = {
|
|
396
|
-
label: modifier,
|
|
397
|
-
filterText: insertText,
|
|
398
|
-
documentation: {
|
|
399
|
-
kind: 'markdown',
|
|
400
|
-
value: description,
|
|
401
|
-
},
|
|
402
|
-
textEdit: {
|
|
403
|
-
range: replacement.textEdit.range,
|
|
404
|
-
newText: insertText,
|
|
405
|
-
},
|
|
406
|
-
kind: 20,
|
|
407
|
-
};
|
|
408
|
-
completionList.items.push(newItem);
|
|
409
|
-
}
|
|
527
|
+
function addDirectiveModifiers(completionList, document) {
|
|
528
|
+
const replacement = getReplacement(completionList, document);
|
|
529
|
+
if (!replacement?.text.includes('.')) {
|
|
530
|
+
return;
|
|
410
531
|
}
|
|
411
|
-
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
532
|
+
const [text, ...modifiers] = replacement.text.split('.');
|
|
533
|
+
const isVOn = text.startsWith('v-on:') || text.startsWith('@') && text.length > 1;
|
|
534
|
+
const isVBind = text.startsWith('v-bind:') || text.startsWith(':') && text.length > 1;
|
|
535
|
+
const isVModel = text.startsWith('v-model:') || text === 'v-model';
|
|
536
|
+
const currentModifiers = isVOn
|
|
537
|
+
? vOnModifiers
|
|
538
|
+
: isVBind
|
|
539
|
+
? vBindModifiers
|
|
540
|
+
: isVModel
|
|
541
|
+
? vModelModifiers
|
|
542
|
+
: undefined;
|
|
543
|
+
if (!currentModifiers) {
|
|
544
|
+
return;
|
|
418
545
|
}
|
|
419
|
-
for (const
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
const name = parsedLabel.tag;
|
|
423
|
-
item.label = parsedLabel.leadingSlash ? '/' + name : name;
|
|
424
|
-
const text = parsedLabel.leadingSlash ? `/${name}>` : name;
|
|
425
|
-
if (item.textEdit) {
|
|
426
|
-
item.textEdit.newText = text;
|
|
427
|
-
}
|
|
428
|
-
if (item.insertText) {
|
|
429
|
-
item.insertText = text;
|
|
430
|
-
}
|
|
431
|
-
if (item.sortText) {
|
|
432
|
-
item.sortText = text;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
const itemKey = typeof item.documentation === 'string' ? item.documentation : item.documentation?.value;
|
|
436
|
-
let parsedItem = itemKey ? parseItemKey(itemKey) : undefined;
|
|
437
|
-
let propInfo;
|
|
438
|
-
if (parsedItem) {
|
|
439
|
-
const documentations = [];
|
|
440
|
-
propInfo = cachedPropInfos.get(parsedItem.prop);
|
|
441
|
-
if (propInfo?.commentMarkdown) {
|
|
442
|
-
documentations.push(propInfo.commentMarkdown);
|
|
443
|
-
}
|
|
444
|
-
let { isEvent, propName } = getPropName(parsedItem);
|
|
445
|
-
if (isEvent) {
|
|
446
|
-
// click -> onclick
|
|
447
|
-
propName = 'on' + propName;
|
|
448
|
-
}
|
|
449
|
-
if (htmlDocumentations.has(propName)) {
|
|
450
|
-
documentations.push(htmlDocumentations.get(propName));
|
|
451
|
-
}
|
|
452
|
-
if (documentations.length) {
|
|
453
|
-
item.documentation = {
|
|
454
|
-
kind: 'markdown',
|
|
455
|
-
value: documentations.join('\n\n'),
|
|
456
|
-
};
|
|
457
|
-
}
|
|
458
|
-
else {
|
|
459
|
-
item.documentation = undefined;
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
else {
|
|
463
|
-
let propName = item.label;
|
|
464
|
-
for (const str of ['v-bind:', ':']) {
|
|
465
|
-
if (propName.startsWith(str) && propName !== str) {
|
|
466
|
-
propName = propName.slice(str.length);
|
|
467
|
-
break;
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
// for special props without internal item key
|
|
471
|
-
if (specialProps.has(propName)) {
|
|
472
|
-
parsedItem = {
|
|
473
|
-
type: 'componentProp',
|
|
474
|
-
tag: '^',
|
|
475
|
-
prop: propName,
|
|
476
|
-
deprecated: false,
|
|
477
|
-
leadingSlash: false,
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
propInfo = cachedPropInfos.get(propName);
|
|
481
|
-
if (propInfo?.commentMarkdown) {
|
|
482
|
-
const originalDocumentation = typeof item.documentation === 'string'
|
|
483
|
-
? item.documentation
|
|
484
|
-
: item.documentation?.value;
|
|
485
|
-
item.documentation = {
|
|
486
|
-
kind: 'markdown',
|
|
487
|
-
value: [
|
|
488
|
-
propInfo.commentMarkdown,
|
|
489
|
-
originalDocumentation,
|
|
490
|
-
].filter(str => !!str).join('\n\n'),
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
if (propInfo?.deprecated) {
|
|
495
|
-
item.tags = [1];
|
|
496
|
-
}
|
|
497
|
-
const tokens = [];
|
|
498
|
-
if (item.kind === 10
|
|
499
|
-
&& lastCompletionComponentNames.has((0, language_core_1.hyphenateTag)(item.label))) {
|
|
500
|
-
item.kind = 6;
|
|
501
|
-
tokens.push('\u0000');
|
|
502
|
-
}
|
|
503
|
-
else if (parsedItem) {
|
|
504
|
-
const isComponent = parsedItem.tag !== '*';
|
|
505
|
-
const { isEvent, propName } = getPropName(parsedItem);
|
|
506
|
-
if (parsedItem.type === 'componentProp') {
|
|
507
|
-
if (isComponent || specialProps.has(propName)) {
|
|
508
|
-
item.kind = 5;
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
else if (isEvent) {
|
|
512
|
-
item.kind = 23;
|
|
513
|
-
if (propName.startsWith('vue:')) {
|
|
514
|
-
tokens.push('\u0004');
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
if (isComponent || specialProps.has(propName)) {
|
|
518
|
-
tokens.push('\u0000');
|
|
519
|
-
if (item.label.startsWith(':')) {
|
|
520
|
-
tokens.push('\u0001');
|
|
521
|
-
}
|
|
522
|
-
else if (item.label.startsWith('@')) {
|
|
523
|
-
tokens.push('\u0002');
|
|
524
|
-
}
|
|
525
|
-
else if (item.label.startsWith('v-bind:')) {
|
|
526
|
-
tokens.push('\u0003');
|
|
527
|
-
}
|
|
528
|
-
else if (item.label.startsWith('v-model:')) {
|
|
529
|
-
tokens.push('\u0004');
|
|
530
|
-
}
|
|
531
|
-
else if (item.label.startsWith('v-on:')) {
|
|
532
|
-
tokens.push('\u0005');
|
|
533
|
-
}
|
|
534
|
-
else {
|
|
535
|
-
tokens.push('\u0000');
|
|
536
|
-
}
|
|
537
|
-
if (specialProps.has(propName)) {
|
|
538
|
-
tokens.push('\u0001');
|
|
539
|
-
}
|
|
540
|
-
else {
|
|
541
|
-
tokens.push('\u0000');
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
else if (item.label === 'v-if'
|
|
546
|
-
|| item.label === 'v-else-if'
|
|
547
|
-
|| item.label === 'v-else'
|
|
548
|
-
|| item.label === 'v-for') {
|
|
549
|
-
item.kind = 14;
|
|
550
|
-
tokens.push('\u0003');
|
|
546
|
+
for (const modifier in currentModifiers) {
|
|
547
|
+
if (modifiers.includes(modifier)) {
|
|
548
|
+
continue;
|
|
551
549
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
550
|
+
const description = currentModifiers[modifier];
|
|
551
|
+
const insertText = text + modifiers.slice(0, -1).map(m => '.' + m).join('') + '.' + modifier;
|
|
552
|
+
const newItem = {
|
|
553
|
+
label: modifier,
|
|
554
|
+
filterText: insertText,
|
|
555
|
+
documentation: {
|
|
556
|
+
kind: 'markdown',
|
|
557
|
+
value: description,
|
|
558
|
+
},
|
|
559
|
+
textEdit: {
|
|
560
|
+
range: replacement.textEdit.range,
|
|
561
|
+
newText: insertText,
|
|
562
|
+
},
|
|
563
|
+
kind: 20,
|
|
564
|
+
};
|
|
565
|
+
completionList.items.push(newItem);
|
|
560
566
|
}
|
|
561
|
-
updateExtraCustomData([]);
|
|
562
567
|
}
|
|
563
568
|
async function initialize() {
|
|
564
569
|
customData = await getHtmlCustomData();
|
|
@@ -589,41 +594,6 @@ function create(mode, getTsPluginClient) {
|
|
|
589
594
|
extraCustomData = extraData;
|
|
590
595
|
onDidChangeCustomDataListeners.forEach(l => l());
|
|
591
596
|
}
|
|
592
|
-
function isSupportedDocument(document) {
|
|
593
|
-
if (mode === 'pug') {
|
|
594
|
-
return document.languageId === 'jade';
|
|
595
|
-
}
|
|
596
|
-
else {
|
|
597
|
-
return document.languageId === 'html';
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
function parseLabel(label) {
|
|
602
|
-
const leadingSlash = label.startsWith('/');
|
|
603
|
-
const name = label.slice(leadingSlash ? 1 : 0);
|
|
604
|
-
return {
|
|
605
|
-
name,
|
|
606
|
-
leadingSlash,
|
|
607
|
-
};
|
|
608
|
-
}
|
|
609
|
-
function generateItemKey(type, tag, prop, deprecated) {
|
|
610
|
-
return `__VLS_data=${type},${tag},${prop},${Number(deprecated)}`;
|
|
611
|
-
}
|
|
612
|
-
function isItemKey(key) {
|
|
613
|
-
return key.startsWith('__VLS_data=');
|
|
614
|
-
}
|
|
615
|
-
function parseItemKey(key) {
|
|
616
|
-
const { leadingSlash, name } = parseLabel(key);
|
|
617
|
-
if (isItemKey(name)) {
|
|
618
|
-
const strs = name.slice('__VLS_data='.length).split(',');
|
|
619
|
-
return {
|
|
620
|
-
type: strs[0],
|
|
621
|
-
tag: strs[1],
|
|
622
|
-
prop: strs[2],
|
|
623
|
-
deprecated: strs[3] === '1',
|
|
624
|
-
leadingSlash,
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
597
|
}
|
|
628
598
|
function getReplacement(list, doc) {
|
|
629
599
|
for (const item of list.items) {
|
|
@@ -636,14 +606,11 @@ function getReplacement(list, doc) {
|
|
|
636
606
|
}
|
|
637
607
|
}
|
|
638
608
|
}
|
|
639
|
-
function getPropName(
|
|
640
|
-
const name = (0, language_core_1.hyphenateAttr)(
|
|
609
|
+
function getPropName(prop, isEvent) {
|
|
610
|
+
const name = (0, language_core_1.hyphenateAttr)(prop);
|
|
641
611
|
if (name.startsWith('on-')) {
|
|
642
612
|
return { isEvent: true, propName: name.slice('on-'.length) };
|
|
643
613
|
}
|
|
644
|
-
|
|
645
|
-
return { isEvent: true, propName: name };
|
|
646
|
-
}
|
|
647
|
-
return { isEvent: false, propName: name };
|
|
614
|
+
return { isEvent, propName: name };
|
|
648
615
|
}
|
|
649
616
|
//# sourceMappingURL=vue-template.js.map
|