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