@vue/language-service 3.1.8 → 3.2.1
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.js +0 -2
- package/lib/data.js +0 -17
- package/lib/plugins/vue-extract-file.d.ts +1 -1
- package/lib/plugins/vue-extract-file.js +7 -8
- package/lib/plugins/vue-missing-props-hints.d.ts +1 -1
- package/lib/plugins/vue-missing-props-hints.js +42 -10
- package/lib/plugins/vue-sfc.js +34 -1
- package/lib/plugins/vue-template.d.ts +1 -1
- package/lib/plugins/vue-template.js +491 -430
- package/package.json +7 -7
- package/lib/plugins/vue-global-types-error.d.ts +0 -2
- package/lib/plugins/vue-global-types-error.js +0 -53
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.create = create;
|
|
4
37
|
const language_service_1 = require("@volar/language-service");
|
|
@@ -8,37 +41,30 @@ const shared_1 = require("@vue/shared");
|
|
|
8
41
|
const volar_service_html_1 = require("volar-service-html");
|
|
9
42
|
const volar_service_pug_1 = require("volar-service-pug");
|
|
10
43
|
const lspConverters_js_1 = require("volar-service-typescript/lib/utils/lspConverters.js");
|
|
11
|
-
const html = require("vscode-html-languageservice");
|
|
44
|
+
const html = __importStar(require("vscode-html-languageservice"));
|
|
12
45
|
const vscode_uri_1 = require("vscode-uri");
|
|
13
46
|
const data_1 = require("../data");
|
|
14
47
|
const htmlFormatter_1 = require("../htmlFormatter");
|
|
15
48
|
const nameCasing_1 = require("../nameCasing");
|
|
16
49
|
const utils_1 = require("../utils");
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
'Transition',
|
|
32
|
-
'TransitionGroup',
|
|
33
|
-
'KeepAlive',
|
|
34
|
-
'Suspense',
|
|
35
|
-
'Teleport',
|
|
36
|
-
]);
|
|
50
|
+
const EVENT_PROP_REGEX = /^on[A-Z]/;
|
|
51
|
+
// String constants
|
|
52
|
+
const AUTO_IMPORT_PLACEHOLDER = 'AutoImportsPlaceholder';
|
|
53
|
+
const UPDATE_EVENT_PREFIX = 'update:';
|
|
54
|
+
const UPDATE_PROP_PREFIX = 'onUpdate:';
|
|
55
|
+
// Directive prefixes
|
|
56
|
+
const DIRECTIVE_V_ON = 'v-on:';
|
|
57
|
+
const DIRECTIVE_V_BIND = 'v-bind:';
|
|
58
|
+
const DIRECTIVE_V_MODEL = 'v-model:';
|
|
59
|
+
const V_ON_SHORTHAND = '@';
|
|
60
|
+
const V_BIND_SHORTHAND = ':';
|
|
61
|
+
const DIRECTIVE_V_FOR_NAME = 'v-for';
|
|
62
|
+
// Templates
|
|
63
|
+
const V_FOR_SNIPPET = '="${1:value} in ${2:source}"';
|
|
37
64
|
let builtInData;
|
|
38
65
|
let modelData;
|
|
39
|
-
function create(ts, languageId,
|
|
40
|
-
let
|
|
41
|
-
let extraCustomData = [];
|
|
66
|
+
function create(ts, languageId, tsserver) {
|
|
67
|
+
let htmlData = [];
|
|
42
68
|
let modulePathCache;
|
|
43
69
|
const onDidChangeCustomDataListeners = new Set();
|
|
44
70
|
const onDidChangeCustomData = (listener) => {
|
|
@@ -63,7 +89,7 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
63
89
|
const map = modulePathCache;
|
|
64
90
|
if (!map.has(ref)) {
|
|
65
91
|
const fileName = baseUri.fsPath.replace(/\\/g, '/');
|
|
66
|
-
const promise = resolveModuleName(fileName, ref);
|
|
92
|
+
const promise = tsserver.resolveModuleName(fileName, ref);
|
|
67
93
|
map.set(ref, promise);
|
|
68
94
|
if (promise instanceof Promise) {
|
|
69
95
|
promise.then(res => map.set(ref, res));
|
|
@@ -85,10 +111,7 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
85
111
|
useDefaultDataProvider: false,
|
|
86
112
|
getDocumentContext,
|
|
87
113
|
getCustomData() {
|
|
88
|
-
return
|
|
89
|
-
...customData,
|
|
90
|
-
...extraCustomData,
|
|
91
|
-
];
|
|
114
|
+
return htmlData;
|
|
92
115
|
},
|
|
93
116
|
onDidChangeCustomData,
|
|
94
117
|
})
|
|
@@ -97,14 +120,10 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
97
120
|
useDefaultDataProvider: false,
|
|
98
121
|
getDocumentContext,
|
|
99
122
|
getCustomData() {
|
|
100
|
-
return
|
|
101
|
-
...customData,
|
|
102
|
-
...extraCustomData,
|
|
103
|
-
];
|
|
123
|
+
return htmlData;
|
|
104
124
|
},
|
|
105
125
|
onDidChangeCustomData,
|
|
106
126
|
});
|
|
107
|
-
const htmlDataProvider = html.getDefaultHTMLDataProvider();
|
|
108
127
|
return {
|
|
109
128
|
name: `vue-template (${languageId})`,
|
|
110
129
|
capabilities: {
|
|
@@ -147,7 +166,7 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
147
166
|
const codegen = info && language_core_1.tsCodegen.get(info.root.sfc);
|
|
148
167
|
if (codegen) {
|
|
149
168
|
const componentNames = new Set([
|
|
150
|
-
...codegen.
|
|
169
|
+
...codegen.getImportedComponents(),
|
|
151
170
|
...codegen.getSetupExposed(),
|
|
152
171
|
]);
|
|
153
172
|
// copied from https://github.com/microsoft/vscode-html-languageservice/blob/10daf45dc16b4f4228987cf7cddf3a7dbbdc7570/src/beautify/beautify-html.js#L2746-L2761
|
|
@@ -182,57 +201,20 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
182
201
|
builtInData ??= (0, data_1.loadTemplateData)(context.env.locale ?? 'en');
|
|
183
202
|
modelData ??= (0, data_1.loadModelModifiersData)(context.env.locale ?? 'en');
|
|
184
203
|
// https://vuejs.org/api/built-in-directives.html#v-on
|
|
204
|
+
const vOnModifiers = extractDirectiveModifiers(builtInData.globalAttributes?.find(x => x.name === 'v-on'));
|
|
185
205
|
// https://vuejs.org/api/built-in-directives.html#v-bind
|
|
186
|
-
const
|
|
187
|
-
const
|
|
188
|
-
const vModelModifiers = {};
|
|
189
|
-
const vOn = builtInData.globalAttributes?.find(x => x.name === 'v-on');
|
|
190
|
-
const vBind = builtInData.globalAttributes?.find(x => x.name === 'v-bind');
|
|
191
|
-
const vModel = builtInData.globalAttributes?.find(x => x.name === 'v-model');
|
|
192
|
-
if (vOn) {
|
|
193
|
-
const markdown = typeof vOn.description === 'object'
|
|
194
|
-
? vOn.description.value
|
|
195
|
-
: vOn.description ?? '';
|
|
196
|
-
const modifiers = markdown
|
|
197
|
-
.split('\n- ')[4]
|
|
198
|
-
.split('\n').slice(2, -1);
|
|
199
|
-
for (let text of modifiers) {
|
|
200
|
-
text = text.slice(' - `.'.length);
|
|
201
|
-
const [name, desc] = text.split('` - ');
|
|
202
|
-
vOnModifiers[name] = desc;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
if (vBind) {
|
|
206
|
-
const markdown = typeof vBind.description === 'object'
|
|
207
|
-
? vBind.description.value
|
|
208
|
-
: vBind.description ?? '';
|
|
209
|
-
const modifiers = markdown
|
|
210
|
-
.split('\n- ')[4]
|
|
211
|
-
.split('\n').slice(2, -1);
|
|
212
|
-
for (let text of modifiers) {
|
|
213
|
-
text = text.slice(' - `.'.length);
|
|
214
|
-
const [name, desc] = text.split('` - ');
|
|
215
|
-
vBindModifiers[name] = desc;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
if (vModel) {
|
|
219
|
-
for (const modifier of modelData.globalAttributes ?? []) {
|
|
220
|
-
const description = typeof modifier.description === 'object'
|
|
221
|
-
? modifier.description.value
|
|
222
|
-
: modifier.description ?? '';
|
|
223
|
-
const references = modifier.references?.map(ref => `[${ref.name}](${ref.url})`).join(' | ');
|
|
224
|
-
vModelModifiers[modifier.name] = description + '\n\n' + references;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
const disposable = context.env.onDidChangeConfiguration?.(() => initializing = undefined);
|
|
206
|
+
const vBindModifiers = extractDirectiveModifiers(builtInData.globalAttributes?.find(x => x.name === 'v-bind'));
|
|
207
|
+
const vModelModifiers = extractModelModifiers(modelData.globalAttributes);
|
|
228
208
|
const transformedItems = new WeakSet();
|
|
229
|
-
|
|
209
|
+
const defaultHtmlTags = new Map();
|
|
210
|
+
for (const tag of html.getDefaultHTMLDataProvider().provideTags()) {
|
|
211
|
+
defaultHtmlTags.set(tag.name, tag);
|
|
212
|
+
}
|
|
230
213
|
let lastCompletionDocument;
|
|
231
214
|
return {
|
|
232
215
|
...baseServiceInstance,
|
|
233
216
|
dispose() {
|
|
234
217
|
baseServiceInstance.dispose?.();
|
|
235
|
-
disposable?.dispose();
|
|
236
218
|
},
|
|
237
219
|
async provideCompletionItems(document, position, completionContext, token) {
|
|
238
220
|
if (document.languageId !== languageId) {
|
|
@@ -242,17 +224,29 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
242
224
|
if (info?.code.id !== 'template') {
|
|
243
225
|
return;
|
|
244
226
|
}
|
|
245
|
-
const
|
|
227
|
+
const prevText = document.getText({ start: { line: 0, character: 0 }, end: position });
|
|
228
|
+
const hint = prevText.match(/(\S)[\S]*$/)?.[1];
|
|
229
|
+
const { result: htmlCompletion, info: { tagNameCasing, components, }, } = await runWithVueDataProvider(info.script.id, info.root, hint, 'completion', () => baseServiceInstance.provideCompletionItems(document, position, completionContext, token));
|
|
230
|
+
const componentSet = new Set(components);
|
|
246
231
|
if (!htmlCompletion) {
|
|
247
232
|
return;
|
|
248
233
|
}
|
|
249
|
-
|
|
250
|
-
|
|
234
|
+
if (!hint) {
|
|
235
|
+
htmlCompletion.isIncomplete = true;
|
|
236
|
+
}
|
|
237
|
+
await resolveAutoImportPlaceholder(htmlCompletion, info);
|
|
238
|
+
resolveComponentItemKinds(htmlCompletion);
|
|
239
|
+
return htmlCompletion;
|
|
240
|
+
async function resolveAutoImportPlaceholder(htmlCompletion, info) {
|
|
241
|
+
const autoImportPlaceholderIndex = htmlCompletion.items.findIndex(item => item.label === AUTO_IMPORT_PLACEHOLDER);
|
|
242
|
+
if (autoImportPlaceholderIndex === -1) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
251
245
|
const offset = document.offsetAt(position);
|
|
252
246
|
const map = context.language.maps.get(info.code, info.script);
|
|
253
247
|
let spliced = false;
|
|
254
248
|
for (const [sourceOffset] of map.toSourceLocation(offset)) {
|
|
255
|
-
const autoImport = await getAutoImportSuggestions(info.root.fileName, sourceOffset);
|
|
249
|
+
const autoImport = await tsserver.getAutoImportSuggestions(info.root.fileName, sourceOffset);
|
|
256
250
|
if (!autoImport) {
|
|
257
251
|
continue;
|
|
258
252
|
}
|
|
@@ -281,118 +275,42 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
281
275
|
htmlCompletion.items.splice(autoImportPlaceholderIndex, 1);
|
|
282
276
|
}
|
|
283
277
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
}
|
|
313
|
-
if (prop.info?.deprecated) {
|
|
314
|
-
item.tags = [1];
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
let name = item.label;
|
|
319
|
-
for (const str of ['v-bind:', ':']) {
|
|
320
|
-
if (name.startsWith(str) && name !== str) {
|
|
321
|
-
name = name.slice(str.length);
|
|
278
|
+
function resolveComponentItemKinds(htmlCompletion) {
|
|
279
|
+
for (const item of htmlCompletion.items) {
|
|
280
|
+
switch (item.kind) {
|
|
281
|
+
case 10:
|
|
282
|
+
if (componentSet.has(item.label)
|
|
283
|
+
|| componentSet.has((0, shared_1.capitalize)((0, shared_1.camelize)(item.label)))) {
|
|
284
|
+
item.kind = 6;
|
|
285
|
+
}
|
|
286
|
+
break;
|
|
287
|
+
case 12:
|
|
288
|
+
addDirectiveModifiers(htmlCompletion, item, document);
|
|
289
|
+
if (typeof item.documentation === 'object' && item.documentation.value.includes('*@deprecated*')) {
|
|
290
|
+
item.tags = [1];
|
|
291
|
+
}
|
|
292
|
+
if (item.label.startsWith(DIRECTIVE_V_ON) || item.label.startsWith(V_ON_SHORTHAND)) {
|
|
293
|
+
item.kind = 23;
|
|
294
|
+
}
|
|
295
|
+
else if (item.label.startsWith(DIRECTIVE_V_BIND)
|
|
296
|
+
|| item.label.startsWith(V_BIND_SHORTHAND)
|
|
297
|
+
|| item.label.startsWith(DIRECTIVE_V_MODEL)) {
|
|
298
|
+
item.kind = 5;
|
|
299
|
+
}
|
|
300
|
+
else if (item.label.startsWith('v-')) {
|
|
301
|
+
item.kind = 14;
|
|
302
|
+
}
|
|
303
|
+
if (item.label === DIRECTIVE_V_FOR_NAME) {
|
|
304
|
+
item.textEdit.newText = item.label + V_FOR_SNIPPET;
|
|
305
|
+
}
|
|
322
306
|
break;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
if (specialProps.has(name)) {
|
|
326
|
-
prop = {
|
|
327
|
-
name,
|
|
328
|
-
kind: 'prop',
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
const tokens = [];
|
|
333
|
-
if (prop) {
|
|
334
|
-
const { isEvent, propName } = getPropName(prop.name, prop.kind === 'event');
|
|
335
|
-
if (prop.kind === 'prop') {
|
|
336
|
-
if (!prop.isGlobal) {
|
|
337
|
-
item.kind = 5;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
else if (isEvent) {
|
|
341
|
-
item.kind = 23;
|
|
342
|
-
if (propName.startsWith('vue:')) {
|
|
343
|
-
tokens.push('\u0004');
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
if (!prop.isGlobal) {
|
|
347
|
-
tokens.push('\u0000');
|
|
348
|
-
if (item.label.startsWith(':')) {
|
|
349
|
-
tokens.push('\u0001');
|
|
350
|
-
}
|
|
351
|
-
else if (item.label.startsWith('@')) {
|
|
352
|
-
tokens.push('\u0002');
|
|
353
|
-
}
|
|
354
|
-
else if (item.label.startsWith('v-bind:')) {
|
|
355
|
-
tokens.push('\u0003');
|
|
356
|
-
}
|
|
357
|
-
else if (item.label.startsWith('v-model:')) {
|
|
358
|
-
tokens.push('\u0004');
|
|
359
|
-
}
|
|
360
|
-
else if (item.label.startsWith('v-on:')) {
|
|
361
|
-
tokens.push('\u0005');
|
|
362
|
-
}
|
|
363
|
-
else {
|
|
364
|
-
tokens.push('\u0000');
|
|
365
|
-
}
|
|
366
|
-
if (specialProps.has(propName)) {
|
|
367
|
-
tokens.push('\u0001');
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
tokens.push('\u0000');
|
|
371
|
-
}
|
|
372
307
|
}
|
|
373
308
|
}
|
|
374
|
-
else if (item.label === 'v-if'
|
|
375
|
-
|| item.label === 'v-else-if'
|
|
376
|
-
|| item.label === 'v-else'
|
|
377
|
-
|| item.label === 'v-for') {
|
|
378
|
-
item.kind = 14;
|
|
379
|
-
tokens.push('\u0003');
|
|
380
|
-
}
|
|
381
|
-
else if (item.label.startsWith('v-')) {
|
|
382
|
-
item.kind = 3;
|
|
383
|
-
tokens.push('\u0002');
|
|
384
|
-
}
|
|
385
|
-
else {
|
|
386
|
-
tokens.push('\u0001');
|
|
387
|
-
}
|
|
388
|
-
item.sortText = tokens.join('') + (item.sortText ?? item.label);
|
|
389
|
-
if (item.label === 'v-for') {
|
|
390
|
-
item.textEdit.newText = item.label + '="${1:value} in ${2:source}"';
|
|
391
|
-
}
|
|
392
309
|
}
|
|
393
310
|
},
|
|
394
311
|
async resolveCompletionItem(item) {
|
|
395
|
-
|
|
312
|
+
const data = item.data;
|
|
313
|
+
if (data?.__vue__autoImport || data?.__vue__componentAutoImport) {
|
|
396
314
|
const embeddedUri = vscode_uri_1.URI.parse(lastCompletionDocument.uri);
|
|
397
315
|
const decoded = context.decodeEmbeddedDocumentUri(embeddedUri);
|
|
398
316
|
if (!decoded) {
|
|
@@ -402,7 +320,7 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
402
320
|
if (!sourceScript) {
|
|
403
321
|
return item;
|
|
404
322
|
}
|
|
405
|
-
const details = await resolveAutoImportCompletionEntry(
|
|
323
|
+
const details = await tsserver.resolveAutoImportCompletionEntry(data);
|
|
406
324
|
if (details) {
|
|
407
325
|
const virtualCode = sourceScript.generated.embeddedCodes.get(decoded[1]);
|
|
408
326
|
const sourceDocument = context.documents.get(sourceScript.id, sourceScript.languageId, sourceScript.snapshot);
|
|
@@ -420,7 +338,7 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
420
338
|
return item;
|
|
421
339
|
}
|
|
422
340
|
},
|
|
423
|
-
provideHover(document, position, token) {
|
|
341
|
+
async provideHover(document, position, token) {
|
|
424
342
|
if (document.languageId !== languageId) {
|
|
425
343
|
return;
|
|
426
344
|
}
|
|
@@ -428,12 +346,129 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
428
346
|
if (info?.code.id !== 'template') {
|
|
429
347
|
return;
|
|
430
348
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
349
|
+
let { result: htmlHover, } = await runWithVueDataProvider(info.script.id, info.root, undefined, 'hover', () => baseServiceInstance.provideHover(document, position, token));
|
|
350
|
+
const templateAst = info.root.sfc.template?.ast;
|
|
351
|
+
const enabledRichMessage = await context.env.getConfiguration?.('vue.hover.rich');
|
|
352
|
+
if (!templateAst || !enabledRichMessage || (htmlHover && hasContents(htmlHover.contents))) {
|
|
353
|
+
return htmlHover;
|
|
354
|
+
}
|
|
355
|
+
for (const element of (0, language_core_1.forEachElementNode)(templateAst)) {
|
|
356
|
+
const tagStart = element.loc.start.offset + element.loc.source.indexOf(element.tag);
|
|
357
|
+
const tagEnd = tagStart + element.tag.length;
|
|
358
|
+
const offset = document.offsetAt(position);
|
|
359
|
+
if (offset >= tagStart && offset <= tagEnd) {
|
|
360
|
+
const meta = await tsserver.getComponentMeta(info.root.fileName, element.tag);
|
|
361
|
+
const props = meta?.props.filter(p => !p.global);
|
|
362
|
+
const modelProps = new Set();
|
|
363
|
+
let tableContents = [];
|
|
364
|
+
for (const event of meta?.events ?? []) {
|
|
365
|
+
if (event.name.startsWith(UPDATE_EVENT_PREFIX)) {
|
|
366
|
+
const modelName = event.name.slice(UPDATE_EVENT_PREFIX.length);
|
|
367
|
+
const modelProp = props?.find(p => p.name === modelName);
|
|
368
|
+
if (modelProp) {
|
|
369
|
+
modelProps.add(modelProp);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
for (const prop of props ?? []) {
|
|
374
|
+
if (prop.name.startsWith(UPDATE_PROP_PREFIX)) {
|
|
375
|
+
const modelName = prop.name.slice(UPDATE_PROP_PREFIX.length);
|
|
376
|
+
const modelProp = props?.find(p => p.name === modelName);
|
|
377
|
+
if (modelProp) {
|
|
378
|
+
modelProps.add(modelProp);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (props?.length) {
|
|
383
|
+
let table = `<tr><th align="left">Prop</th><th align="left">Description</th><th align="left">Default</th></tr>\n`;
|
|
384
|
+
for (const p of props) {
|
|
385
|
+
table += `<tr>
|
|
386
|
+
<td>${printName(p, modelProps.has(p))}</td>
|
|
387
|
+
<td>${printDescription(p)}</td>
|
|
388
|
+
<td>${p.default ? `<code>${p.default}</code>` : ''}</td>
|
|
389
|
+
</tr>\n`;
|
|
390
|
+
}
|
|
391
|
+
tableContents.push(table);
|
|
392
|
+
}
|
|
393
|
+
if (meta?.events?.length) {
|
|
394
|
+
let table = `<tr><th align="left">Event</th><th align="left">Description</th><th></th></tr>\n`;
|
|
395
|
+
for (const e of meta.events) {
|
|
396
|
+
table += `<tr>
|
|
397
|
+
<td>${printName(e)}</td>
|
|
398
|
+
<td colspan="2">${printDescription(e)}</td>
|
|
399
|
+
</tr>\n`;
|
|
400
|
+
}
|
|
401
|
+
tableContents.push(table);
|
|
402
|
+
}
|
|
403
|
+
if (meta?.slots?.length) {
|
|
404
|
+
let table = `<tr><th align="left">Slot</th><th align="left">Description</th><th></th></tr>\n`;
|
|
405
|
+
for (const s of meta.slots) {
|
|
406
|
+
table += `<tr>
|
|
407
|
+
<td>${printName(s)}</td>
|
|
408
|
+
<td colspan="2">${printDescription(s)}</td>
|
|
409
|
+
</tr>\n`;
|
|
410
|
+
}
|
|
411
|
+
tableContents.push(table);
|
|
412
|
+
}
|
|
413
|
+
if (meta?.exposed.length) {
|
|
414
|
+
let table = `<tr><th align="left">Exposed</th><th align="left">Description</th><th></th></tr>\n`;
|
|
415
|
+
for (const e of meta.exposed) {
|
|
416
|
+
table += `<tr>
|
|
417
|
+
<td>${printName(e)}</td>
|
|
418
|
+
<td colspan="2">${printDescription(e)}</td>
|
|
419
|
+
</tr>\n`;
|
|
420
|
+
}
|
|
421
|
+
tableContents.push(table);
|
|
422
|
+
}
|
|
423
|
+
htmlHover ??= {
|
|
424
|
+
range: {
|
|
425
|
+
start: document.positionAt(tagStart),
|
|
426
|
+
end: document.positionAt(tagEnd),
|
|
427
|
+
},
|
|
428
|
+
contents: '',
|
|
429
|
+
};
|
|
430
|
+
// 2px height per <tr>
|
|
431
|
+
const tableGap = `<tr></tr>`.repeat(4);
|
|
432
|
+
htmlHover.contents = {
|
|
433
|
+
kind: 'markdown',
|
|
434
|
+
value: tableContents
|
|
435
|
+
? `<table>\n${tableContents.join(`\n${tableGap}\n`)}\n</table>`
|
|
436
|
+
: `No type information available.`,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return htmlHover;
|
|
441
|
+
function printName(meta, model) {
|
|
442
|
+
let name = meta.name;
|
|
443
|
+
if (meta.tags.some(tag => tag.name === 'deprecated')) {
|
|
444
|
+
name = `<del>${name}</del>`;
|
|
445
|
+
}
|
|
446
|
+
if (meta.required) {
|
|
447
|
+
name += ' <sup><em>required</em></sup>';
|
|
448
|
+
}
|
|
449
|
+
if (model) {
|
|
450
|
+
name += ' <sup><em>model</em></sup>';
|
|
451
|
+
}
|
|
452
|
+
return name;
|
|
453
|
+
}
|
|
454
|
+
function printDescription(meta) {
|
|
455
|
+
let desc = `<code>${meta.type}</code>`;
|
|
456
|
+
if (meta.description) {
|
|
457
|
+
// blank line for terminate HTML to support markdown
|
|
458
|
+
// see: https://github.github.com/gfm/#example-118
|
|
459
|
+
desc = `\n\n${meta.description}<br>${desc}`;
|
|
460
|
+
}
|
|
461
|
+
return desc;
|
|
462
|
+
}
|
|
463
|
+
function hasContents(contents) {
|
|
464
|
+
if (typeof contents === 'string') {
|
|
465
|
+
return !!contents;
|
|
466
|
+
}
|
|
467
|
+
if (Array.isArray(contents)) {
|
|
468
|
+
return contents.some(hasContents);
|
|
469
|
+
}
|
|
470
|
+
return !!contents.value;
|
|
435
471
|
}
|
|
436
|
-
return baseServiceInstance.provideHover?.(document, position, token);
|
|
437
472
|
},
|
|
438
473
|
async provideDocumentLinks(document, token) {
|
|
439
474
|
modulePathCache = new Map();
|
|
@@ -454,10 +489,10 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
454
489
|
}
|
|
455
490
|
},
|
|
456
491
|
};
|
|
457
|
-
async function
|
|
492
|
+
async function runWithVueDataProvider(sourceDocumentUri, root, hint, mode, fn) {
|
|
458
493
|
// #4298: Precompute HTMLDocument before provideHtmlData to avoid parseHTMLDocument requesting component names from tsserver
|
|
459
494
|
await fn();
|
|
460
|
-
const { sync } = await provideHtmlData(sourceDocumentUri, root);
|
|
495
|
+
const { sync } = await provideHtmlData(sourceDocumentUri, root, hint, mode);
|
|
461
496
|
let lastSync = await sync();
|
|
462
497
|
let result = await fn();
|
|
463
498
|
while (lastSync.version !== (lastSync = await sync()).version) {
|
|
@@ -465,255 +500,210 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
465
500
|
}
|
|
466
501
|
return { result, ...lastSync };
|
|
467
502
|
}
|
|
468
|
-
async function provideHtmlData(sourceDocumentUri, root) {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
if (specialTags.has(tag.name)) {
|
|
474
|
-
continue;
|
|
475
|
-
}
|
|
476
|
-
if (tagNameCasing === 0 /* TagNameCasing.Kebab */) {
|
|
477
|
-
tag.name = (0, language_core_1.hyphenateTag)(tag.name);
|
|
478
|
-
}
|
|
479
|
-
else {
|
|
480
|
-
tag.name = (0, shared_1.camelize)((0, shared_1.capitalize)(tag.name));
|
|
481
|
-
}
|
|
482
|
-
}
|
|
503
|
+
async function provideHtmlData(sourceDocumentUri, root, hint, mode) {
|
|
504
|
+
const [tagNameCasing, attrNameCasing] = await Promise.all([
|
|
505
|
+
(0, nameCasing_1.getTagNameCasing)(context, sourceDocumentUri),
|
|
506
|
+
(0, nameCasing_1.getAttrNameCasing)(context, sourceDocumentUri),
|
|
507
|
+
]);
|
|
483
508
|
let version = 0;
|
|
484
|
-
let target;
|
|
485
509
|
let components;
|
|
510
|
+
let elements;
|
|
511
|
+
let directives;
|
|
486
512
|
let values;
|
|
487
513
|
const tasks = [];
|
|
488
|
-
const
|
|
489
|
-
const propMap = new Map();
|
|
514
|
+
const tagDataMap = new Map();
|
|
490
515
|
updateExtraCustomData([
|
|
491
|
-
{
|
|
492
|
-
getId: () => htmlDataProvider.getId(),
|
|
493
|
-
isApplicable: () => true,
|
|
494
|
-
provideTags() {
|
|
495
|
-
target = 'tag';
|
|
496
|
-
return htmlDataProvider.provideTags()
|
|
497
|
-
.filter(tag => !specialTags.has(tag.name));
|
|
498
|
-
},
|
|
499
|
-
provideAttributes(tag) {
|
|
500
|
-
target = 'attribute';
|
|
501
|
-
const attrs = htmlDataProvider.provideAttributes(tag);
|
|
502
|
-
if (tag === 'slot') {
|
|
503
|
-
const nameAttr = attrs.find(attr => attr.name === 'name');
|
|
504
|
-
if (nameAttr) {
|
|
505
|
-
nameAttr.valueSet = 'slot';
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
return attrs;
|
|
509
|
-
},
|
|
510
|
-
provideValues(tag, attr) {
|
|
511
|
-
target = 'value';
|
|
512
|
-
return htmlDataProvider.provideValues(tag, attr);
|
|
513
|
-
},
|
|
514
|
-
},
|
|
515
|
-
html.newHTMLDataProvider('vue-template-built-in', builtInData),
|
|
516
516
|
{
|
|
517
517
|
getId: () => 'vue-template',
|
|
518
518
|
isApplicable: () => true,
|
|
519
519
|
provideTags: () => {
|
|
520
|
-
|
|
521
|
-
components = [];
|
|
522
|
-
tasks.push((async () => {
|
|
523
|
-
components = (await getComponentNames(root.fileName) ?? [])
|
|
524
|
-
.filter(name => !builtInComponents.has(name));
|
|
525
|
-
version++;
|
|
526
|
-
})());
|
|
527
|
-
}
|
|
520
|
+
const { components, elements } = getComponentsAndElements();
|
|
528
521
|
const codegen = language_core_1.tsCodegen.get(root.sfc);
|
|
529
522
|
const names = new Set();
|
|
530
523
|
const tags = [];
|
|
524
|
+
for (const tag of builtInData?.tags ?? []) {
|
|
525
|
+
tags.push({
|
|
526
|
+
...tag,
|
|
527
|
+
name: tagNameCasing === 0 /* TagNameCasing.Kebab */ ? (0, language_core_1.hyphenateTag)(tag.name) : tag.name,
|
|
528
|
+
});
|
|
529
|
+
}
|
|
531
530
|
for (const tag of components) {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
names.add(tag);
|
|
537
|
-
}
|
|
531
|
+
names.add(tagNameCasing === 0 /* TagNameCasing.Kebab */ ? (0, language_core_1.hyphenateTag)(tag) : tag);
|
|
532
|
+
}
|
|
533
|
+
for (const tag of elements) {
|
|
534
|
+
names.add(tag);
|
|
538
535
|
}
|
|
539
536
|
if (codegen) {
|
|
540
537
|
for (const name of [
|
|
541
|
-
...codegen.
|
|
538
|
+
...codegen.getImportedComponents(),
|
|
542
539
|
...codegen.getSetupExposed(),
|
|
543
540
|
]) {
|
|
544
|
-
|
|
545
|
-
names.add((0, language_core_1.hyphenateTag)(name));
|
|
546
|
-
}
|
|
547
|
-
else {
|
|
548
|
-
names.add(name);
|
|
549
|
-
}
|
|
541
|
+
names.add(tagNameCasing === 0 /* TagNameCasing.Kebab */ ? (0, language_core_1.hyphenateTag)(name) : name);
|
|
550
542
|
}
|
|
551
543
|
}
|
|
544
|
+
const added = new Set(tags.map(t => t.name));
|
|
552
545
|
for (const name of names) {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
546
|
+
if (!added.has(name)) {
|
|
547
|
+
const defaultTag = defaultHtmlTags.get(name);
|
|
548
|
+
tags.push({
|
|
549
|
+
...defaultTag,
|
|
550
|
+
name,
|
|
551
|
+
attributes: [],
|
|
552
|
+
});
|
|
553
|
+
}
|
|
557
554
|
}
|
|
558
555
|
return tags;
|
|
559
556
|
},
|
|
560
557
|
provideAttributes: tag => {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
attrs: await getElementAttrs(root.fileName, tag) ?? [],
|
|
573
|
-
propInfos: await getComponentProps(root.fileName, tag) ?? [],
|
|
574
|
-
events: await getComponentEvents(root.fileName, tag) ?? [],
|
|
575
|
-
directives: await getComponentDirectives(root.fileName) ?? [],
|
|
576
|
-
});
|
|
577
|
-
version++;
|
|
578
|
-
})());
|
|
558
|
+
const directives = getDirectives();
|
|
559
|
+
const { attrs, meta } = getTagData(tag);
|
|
560
|
+
const attributes = [];
|
|
561
|
+
let addPlainAttrs = false;
|
|
562
|
+
let addVBinds = false;
|
|
563
|
+
let addVBindShorthands = false;
|
|
564
|
+
let addVOns = false;
|
|
565
|
+
let addVOnShorthands = false;
|
|
566
|
+
if (!hint) {
|
|
567
|
+
addVBindShorthands = true;
|
|
568
|
+
addVOnShorthands = true;
|
|
579
569
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
570
|
+
else if (hint === ':') {
|
|
571
|
+
addVBindShorthands = true;
|
|
572
|
+
}
|
|
573
|
+
else if (hint === '@') {
|
|
574
|
+
addVOnShorthands = true;
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
addPlainAttrs = true;
|
|
578
|
+
addVBinds = true;
|
|
579
|
+
addVOns = true;
|
|
580
|
+
addVBindShorthands = true;
|
|
581
|
+
addVOnShorthands = true;
|
|
582
|
+
}
|
|
583
|
+
for (const attr of builtInData?.globalAttributes ?? []) {
|
|
584
|
+
if (attr.name === 'is' && tag.toLowerCase() !== 'component') {
|
|
585
|
+
continue;
|
|
586
|
+
}
|
|
587
|
+
if (attr.name === 'ref' || attr.name.startsWith('v-')) {
|
|
588
|
+
attributes.push(attr);
|
|
585
589
|
continue;
|
|
586
590
|
}
|
|
587
|
-
if (
|
|
588
|
-
|
|
589
|
-
|
|
591
|
+
if (addPlainAttrs) {
|
|
592
|
+
attributes.push({ ...attr, name: attr.name });
|
|
593
|
+
}
|
|
594
|
+
if (addVBindShorthands) {
|
|
595
|
+
attributes.push({ ...attr, name: V_BIND_SHORTHAND + attr.name });
|
|
596
|
+
}
|
|
597
|
+
if (addVBinds) {
|
|
598
|
+
attributes.push({ ...attr, name: DIRECTIVE_V_BIND + attr.name });
|
|
590
599
|
}
|
|
591
600
|
}
|
|
592
|
-
const
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
...propInfos,
|
|
596
|
-
...attrs.map(attr => ({ name: attr })),
|
|
601
|
+
for (const [propName, propMeta] of [
|
|
602
|
+
...meta?.props.map(prop => [prop.name, prop]) ?? [],
|
|
603
|
+
...attrs.map(attr => [attr.name, undefined]),
|
|
597
604
|
]) {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
info: prop,
|
|
605
|
+
if (propName.match(EVENT_PROP_REGEX)) {
|
|
606
|
+
let labelName = propName.slice(2);
|
|
607
|
+
labelName = labelName.charAt(0).toLowerCase() + labelName.slice(1);
|
|
608
|
+
if (attrNameCasing === 0 /* AttrNameCasing.Kebab */) {
|
|
609
|
+
labelName = (0, language_core_1.hyphenateAttr)(labelName);
|
|
610
|
+
}
|
|
611
|
+
if (addVOnShorthands) {
|
|
612
|
+
attributes.push({
|
|
613
|
+
name: V_ON_SHORTHAND + labelName,
|
|
614
|
+
description: propMeta && createDescription(propMeta),
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
if (addVOns) {
|
|
618
|
+
attributes.push({
|
|
619
|
+
name: DIRECTIVE_V_ON + labelName,
|
|
620
|
+
description: propMeta && createDescription(propMeta),
|
|
615
621
|
});
|
|
616
622
|
}
|
|
617
623
|
}
|
|
618
624
|
else {
|
|
619
|
-
const
|
|
625
|
+
const labelName = attrNameCasing === 1 /* AttrNameCasing.Camel */ ? propName : (0, language_core_1.hyphenateAttr)(propName);
|
|
626
|
+
const propMeta2 = meta?.props.find(prop => {
|
|
620
627
|
const name = attrNameCasing === 1 /* AttrNameCasing.Camel */ ? prop.name : (0, language_core_1.hyphenateAttr)(prop.name);
|
|
621
|
-
return name ===
|
|
628
|
+
return name === labelName;
|
|
622
629
|
});
|
|
623
|
-
|
|
624
|
-
propName,
|
|
625
|
-
':' + propName,
|
|
626
|
-
'v-bind:' + propName,
|
|
627
|
-
]) {
|
|
630
|
+
if (addPlainAttrs) {
|
|
628
631
|
attributes.push({
|
|
629
|
-
name,
|
|
630
|
-
|
|
632
|
+
name: labelName,
|
|
633
|
+
description: propMeta2 && createDescription(propMeta2),
|
|
631
634
|
});
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
635
|
+
}
|
|
636
|
+
if (addVBindShorthands) {
|
|
637
|
+
attributes.push({
|
|
638
|
+
name: V_BIND_SHORTHAND + labelName,
|
|
639
|
+
description: propMeta2 && createDescription(propMeta2),
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
if (addVBinds) {
|
|
643
|
+
attributes.push({
|
|
644
|
+
name: DIRECTIVE_V_BIND + labelName,
|
|
645
|
+
description: propMeta2 && createDescription(propMeta2),
|
|
637
646
|
});
|
|
638
647
|
}
|
|
639
648
|
}
|
|
640
649
|
}
|
|
641
|
-
for (const event of events) {
|
|
642
|
-
const eventName = attrNameCasing === 1 /* AttrNameCasing.Camel */ ? event : (0, language_core_1.hyphenateAttr)(event);
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
650
|
+
for (const event of meta?.events ?? []) {
|
|
651
|
+
const eventName = attrNameCasing === 1 /* AttrNameCasing.Camel */ ? event.name : (0, language_core_1.hyphenateAttr)(event.name);
|
|
652
|
+
if (addVOnShorthands) {
|
|
653
|
+
attributes.push({
|
|
654
|
+
name: V_ON_SHORTHAND + eventName,
|
|
655
|
+
description: event && createDescription(event),
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
if (addVOns) {
|
|
659
|
+
attributes.push({
|
|
660
|
+
name: DIRECTIVE_V_ON + eventName,
|
|
661
|
+
description: event && createDescription(event),
|
|
651
662
|
});
|
|
652
663
|
}
|
|
653
664
|
}
|
|
654
665
|
for (const directive of directives) {
|
|
655
|
-
const name = (0, language_core_1.hyphenateAttr)(directive);
|
|
656
666
|
attributes.push({
|
|
657
|
-
name,
|
|
667
|
+
name: (0, language_core_1.hyphenateAttr)(directive),
|
|
658
668
|
});
|
|
659
669
|
}
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
...
|
|
663
|
-
...attrs.map(attr => ({ name: attr })),
|
|
670
|
+
for (const [propName, propMeta] of [
|
|
671
|
+
...meta?.props.map(prop => [prop.name, prop]) ?? [],
|
|
672
|
+
...attrs.map(attr => [attr.name, undefined]),
|
|
664
673
|
]) {
|
|
665
|
-
if (
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
674
|
+
if (propName.startsWith(UPDATE_PROP_PREFIX)) {
|
|
675
|
+
const model = propName.slice(UPDATE_PROP_PREFIX.length);
|
|
676
|
+
const label = DIRECTIVE_V_MODEL
|
|
677
|
+
+ (attrNameCasing === 1 /* AttrNameCasing.Camel */ ? model : (0, language_core_1.hyphenateAttr)(model));
|
|
678
|
+
attributes.push({
|
|
679
|
+
name: label,
|
|
680
|
+
description: propMeta && createDescription(propMeta),
|
|
681
|
+
});
|
|
672
682
|
}
|
|
673
683
|
}
|
|
674
|
-
for (const
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
propMap.set('v-model', {
|
|
683
|
-
name,
|
|
684
|
-
kind: 'prop',
|
|
684
|
+
for (const event of meta?.events ?? []) {
|
|
685
|
+
if (event.name.startsWith(UPDATE_EVENT_PREFIX)) {
|
|
686
|
+
const model = event.name.slice(UPDATE_EVENT_PREFIX.length);
|
|
687
|
+
const label = DIRECTIVE_V_MODEL
|
|
688
|
+
+ (attrNameCasing === 1 /* AttrNameCasing.Camel */ ? model : (0, language_core_1.hyphenateAttr)(model));
|
|
689
|
+
attributes.push({
|
|
690
|
+
name: label,
|
|
691
|
+
description: createDescription(event),
|
|
685
692
|
});
|
|
686
693
|
}
|
|
687
694
|
}
|
|
688
695
|
return attributes;
|
|
689
696
|
},
|
|
690
697
|
provideValues: (tag, attr) => {
|
|
691
|
-
|
|
692
|
-
values = [];
|
|
693
|
-
tasks.push((async () => {
|
|
694
|
-
if (tag === 'slot' && attr === 'name') {
|
|
695
|
-
values = await getComponentSlots(root.fileName) ?? [];
|
|
696
|
-
}
|
|
697
|
-
version++;
|
|
698
|
-
})());
|
|
699
|
-
}
|
|
700
|
-
return values.map(value => ({
|
|
701
|
-
name: value,
|
|
702
|
-
}));
|
|
698
|
+
return getAttrValues(tag, attr).map(value => ({ name: value }));
|
|
703
699
|
},
|
|
704
700
|
},
|
|
705
701
|
{
|
|
706
702
|
getId: () => 'vue-auto-imports',
|
|
707
703
|
isApplicable: () => true,
|
|
708
|
-
provideTags() {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
provideAttributes() {
|
|
712
|
-
return [];
|
|
713
|
-
},
|
|
714
|
-
provideValues() {
|
|
715
|
-
return [];
|
|
716
|
-
},
|
|
704
|
+
provideTags: () => [{ name: AUTO_IMPORT_PLACEHOLDER, attributes: [] }],
|
|
705
|
+
provideAttributes: () => [],
|
|
706
|
+
provideValues: () => [],
|
|
717
707
|
},
|
|
718
708
|
]);
|
|
719
709
|
return {
|
|
@@ -721,25 +711,96 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
721
711
|
await Promise.all(tasks);
|
|
722
712
|
return {
|
|
723
713
|
version,
|
|
724
|
-
target,
|
|
725
714
|
info: {
|
|
726
715
|
tagNameCasing,
|
|
727
716
|
components,
|
|
728
|
-
propMap,
|
|
729
717
|
},
|
|
730
718
|
};
|
|
731
719
|
},
|
|
732
720
|
};
|
|
721
|
+
function createDescription(meta) {
|
|
722
|
+
if (mode === 'hover') {
|
|
723
|
+
// dedupe from TS hover
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
let description = meta?.description ?? '';
|
|
727
|
+
for (const tag of meta.tags) {
|
|
728
|
+
description += `\n\n*@${tag.name}* ${tag.text ?? ''}`;
|
|
729
|
+
}
|
|
730
|
+
if (!description) {
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
return {
|
|
734
|
+
kind: 'markdown',
|
|
735
|
+
value: description,
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
function getAttrValues(tag, attr) {
|
|
739
|
+
if (!values) {
|
|
740
|
+
values = [];
|
|
741
|
+
tasks.push((async () => {
|
|
742
|
+
if (tag === 'slot' && attr === 'name') {
|
|
743
|
+
values = await tsserver.getComponentSlots(root.fileName) ?? [];
|
|
744
|
+
}
|
|
745
|
+
version++;
|
|
746
|
+
})());
|
|
747
|
+
}
|
|
748
|
+
return values;
|
|
749
|
+
}
|
|
750
|
+
function getTagData(tag) {
|
|
751
|
+
let data = tagDataMap.get(tag);
|
|
752
|
+
if (!data) {
|
|
753
|
+
data = { attrs: [], meta: undefined };
|
|
754
|
+
tagDataMap.set(tag, data);
|
|
755
|
+
tasks.push((async () => {
|
|
756
|
+
tagDataMap.set(tag, {
|
|
757
|
+
attrs: await tsserver.getElementAttrs(root.fileName, tag) ?? [],
|
|
758
|
+
meta: await tsserver.getComponentMeta(root.fileName, tag),
|
|
759
|
+
});
|
|
760
|
+
version++;
|
|
761
|
+
})());
|
|
762
|
+
}
|
|
763
|
+
return data;
|
|
764
|
+
}
|
|
765
|
+
function getDirectives() {
|
|
766
|
+
if (!directives) {
|
|
767
|
+
directives = [];
|
|
768
|
+
tasks.push((async () => {
|
|
769
|
+
directives = await tsserver.getComponentDirectives(root.fileName) ?? [];
|
|
770
|
+
version++;
|
|
771
|
+
})());
|
|
772
|
+
}
|
|
773
|
+
return directives;
|
|
774
|
+
}
|
|
775
|
+
function getComponentsAndElements() {
|
|
776
|
+
if (!components || !elements) {
|
|
777
|
+
components = [];
|
|
778
|
+
elements = [];
|
|
779
|
+
tasks.push((async () => {
|
|
780
|
+
const res = await Promise.all([
|
|
781
|
+
tsserver.getComponentNames(root.fileName),
|
|
782
|
+
tsserver.getElementNames(root.fileName),
|
|
783
|
+
]);
|
|
784
|
+
components = res[0] ?? [];
|
|
785
|
+
elements = res[1] ?? [];
|
|
786
|
+
version++;
|
|
787
|
+
})());
|
|
788
|
+
}
|
|
789
|
+
return {
|
|
790
|
+
components,
|
|
791
|
+
elements,
|
|
792
|
+
};
|
|
793
|
+
}
|
|
733
794
|
}
|
|
734
|
-
function addDirectiveModifiers(
|
|
735
|
-
const replacement = getReplacement(
|
|
795
|
+
function addDirectiveModifiers(list, item, document) {
|
|
796
|
+
const replacement = getReplacement(item, document);
|
|
736
797
|
if (!replacement?.text.includes('.')) {
|
|
737
798
|
return;
|
|
738
799
|
}
|
|
739
800
|
const [text, ...modifiers] = replacement.text.split('.');
|
|
740
|
-
const isVOn = text.startsWith(
|
|
741
|
-
const isVBind = text.startsWith(
|
|
742
|
-
const isVModel = text.startsWith(
|
|
801
|
+
const isVOn = text.startsWith(DIRECTIVE_V_ON) || text.startsWith(V_ON_SHORTHAND) && text.length > 1;
|
|
802
|
+
const isVBind = text.startsWith(DIRECTIVE_V_BIND) || text.startsWith(V_BIND_SHORTHAND) && text.length > 1;
|
|
803
|
+
const isVModel = text.startsWith(DIRECTIVE_V_MODEL) || text === 'v-model';
|
|
743
804
|
const currentModifiers = isVOn
|
|
744
805
|
? vOnModifiers
|
|
745
806
|
: isVBind
|
|
@@ -769,55 +830,55 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
769
830
|
},
|
|
770
831
|
kind: 20,
|
|
771
832
|
};
|
|
772
|
-
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
async function initialize() {
|
|
776
|
-
customData = await getHtmlCustomData();
|
|
777
|
-
}
|
|
778
|
-
async function getHtmlCustomData() {
|
|
779
|
-
const customData = await context.env.getConfiguration?.('html.customData') ?? [];
|
|
780
|
-
const newData = [];
|
|
781
|
-
for (const customDataPath of customData) {
|
|
782
|
-
for (const workspaceFolder of context.env.workspaceFolders) {
|
|
783
|
-
const uri = vscode_uri_1.Utils.resolvePath(workspaceFolder, customDataPath);
|
|
784
|
-
const json = await context.env.fs?.readFile(uri);
|
|
785
|
-
if (json) {
|
|
786
|
-
try {
|
|
787
|
-
const data = JSON.parse(json);
|
|
788
|
-
newData.push(html.newHTMLDataProvider(customDataPath, data));
|
|
789
|
-
}
|
|
790
|
-
catch (error) {
|
|
791
|
-
console.error(error);
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
}
|
|
833
|
+
list.items.push(newItem);
|
|
795
834
|
}
|
|
796
|
-
return newData;
|
|
797
835
|
}
|
|
798
836
|
},
|
|
799
837
|
};
|
|
800
|
-
function updateExtraCustomData(
|
|
801
|
-
|
|
838
|
+
function updateExtraCustomData(newData) {
|
|
839
|
+
htmlData = newData;
|
|
802
840
|
onDidChangeCustomDataListeners.forEach(l => l());
|
|
803
841
|
}
|
|
804
842
|
}
|
|
805
|
-
function getReplacement(
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
};
|
|
813
|
-
}
|
|
843
|
+
function getReplacement(item, doc) {
|
|
844
|
+
if (item.textEdit && 'range' in item.textEdit) {
|
|
845
|
+
return {
|
|
846
|
+
item: item,
|
|
847
|
+
textEdit: item.textEdit,
|
|
848
|
+
text: doc.getText(item.textEdit.range),
|
|
849
|
+
};
|
|
814
850
|
}
|
|
815
851
|
}
|
|
816
|
-
function
|
|
817
|
-
const
|
|
818
|
-
if (
|
|
819
|
-
return
|
|
852
|
+
function extractDirectiveModifiers(directive) {
|
|
853
|
+
const modifiers = {};
|
|
854
|
+
if (!directive) {
|
|
855
|
+
return modifiers;
|
|
856
|
+
}
|
|
857
|
+
const markdown = typeof directive.description === 'object'
|
|
858
|
+
? directive.description.value
|
|
859
|
+
: directive.description ?? '';
|
|
860
|
+
const modifierLines = markdown
|
|
861
|
+
.split('\n- ')[4]
|
|
862
|
+
?.split('\n').slice(2, -1) ?? [];
|
|
863
|
+
for (let text of modifierLines) {
|
|
864
|
+
text = text.slice(' - `.'.length);
|
|
865
|
+
const [name, desc] = text.split('` - ');
|
|
866
|
+
modifiers[name] = desc;
|
|
867
|
+
}
|
|
868
|
+
return modifiers;
|
|
869
|
+
}
|
|
870
|
+
function extractModelModifiers(attributes) {
|
|
871
|
+
const modifiers = {};
|
|
872
|
+
if (!attributes) {
|
|
873
|
+
return modifiers;
|
|
874
|
+
}
|
|
875
|
+
for (const modifier of attributes) {
|
|
876
|
+
const description = typeof modifier.description === 'object'
|
|
877
|
+
? modifier.description.value
|
|
878
|
+
: modifier.description ?? '';
|
|
879
|
+
const references = modifier.references?.map(ref => `[${ref.name}](${ref.url})`).join(' | ');
|
|
880
|
+
modifiers[modifier.name] = description + '\n\n' + references;
|
|
820
881
|
}
|
|
821
|
-
return
|
|
882
|
+
return modifiers;
|
|
822
883
|
}
|
|
823
884
|
//# sourceMappingURL=vue-template.js.map
|