@vue/language-service 3.1.8 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +484 -432
- 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,35 @@ 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(/\bv[\S]*$/)
|
|
229
|
+
? 'v'
|
|
230
|
+
: prevText.match(/[:][\S]*$/)
|
|
231
|
+
? ':'
|
|
232
|
+
: prevText.match(/[@][\S]*$/)
|
|
233
|
+
? '@'
|
|
234
|
+
: undefined;
|
|
235
|
+
const { result: htmlCompletion, info: { tagNameCasing, components, }, } = await runWithVueDataProvider(info.script.id, info.root, hint, 'completion', () => baseServiceInstance.provideCompletionItems(document, position, completionContext, token));
|
|
236
|
+
const componentSet = new Set(components);
|
|
246
237
|
if (!htmlCompletion) {
|
|
247
238
|
return;
|
|
248
239
|
}
|
|
249
|
-
|
|
250
|
-
|
|
240
|
+
if (!prevText.match(/[\S]+$/)) {
|
|
241
|
+
htmlCompletion.isIncomplete = true;
|
|
242
|
+
}
|
|
243
|
+
await resolveAutoImportPlaceholder(htmlCompletion, info);
|
|
244
|
+
resolveComponentItemKinds(htmlCompletion);
|
|
245
|
+
return htmlCompletion;
|
|
246
|
+
async function resolveAutoImportPlaceholder(htmlCompletion, info) {
|
|
247
|
+
const autoImportPlaceholderIndex = htmlCompletion.items.findIndex(item => item.label === AUTO_IMPORT_PLACEHOLDER);
|
|
248
|
+
if (autoImportPlaceholderIndex === -1) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
251
|
const offset = document.offsetAt(position);
|
|
252
252
|
const map = context.language.maps.get(info.code, info.script);
|
|
253
253
|
let spliced = false;
|
|
254
254
|
for (const [sourceOffset] of map.toSourceLocation(offset)) {
|
|
255
|
-
const autoImport = await getAutoImportSuggestions(info.root.fileName, sourceOffset);
|
|
255
|
+
const autoImport = await tsserver.getAutoImportSuggestions(info.root.fileName, sourceOffset);
|
|
256
256
|
if (!autoImport) {
|
|
257
257
|
continue;
|
|
258
258
|
}
|
|
@@ -281,118 +281,42 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
281
281
|
htmlCompletion.items.splice(autoImportPlaceholderIndex, 1);
|
|
282
282
|
}
|
|
283
283
|
}
|
|
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);
|
|
284
|
+
function resolveComponentItemKinds(htmlCompletion) {
|
|
285
|
+
for (const item of htmlCompletion.items) {
|
|
286
|
+
switch (item.kind) {
|
|
287
|
+
case 10:
|
|
288
|
+
if (componentSet.has(item.label)
|
|
289
|
+
|| componentSet.has((0, shared_1.capitalize)((0, shared_1.camelize)(item.label)))) {
|
|
290
|
+
item.kind = 6;
|
|
291
|
+
}
|
|
292
|
+
break;
|
|
293
|
+
case 12:
|
|
294
|
+
addDirectiveModifiers(htmlCompletion, item, document);
|
|
295
|
+
if (typeof item.documentation === 'object' && item.documentation.value.includes('*@deprecated*')) {
|
|
296
|
+
item.tags = [1];
|
|
297
|
+
}
|
|
298
|
+
if (item.label.startsWith(DIRECTIVE_V_ON) || item.label.startsWith(V_ON_SHORTHAND)) {
|
|
299
|
+
item.kind = 23;
|
|
300
|
+
}
|
|
301
|
+
else if (item.label.startsWith(DIRECTIVE_V_BIND)
|
|
302
|
+
|| item.label.startsWith(V_BIND_SHORTHAND)
|
|
303
|
+
|| item.label.startsWith(DIRECTIVE_V_MODEL)) {
|
|
304
|
+
item.kind = 5;
|
|
305
|
+
}
|
|
306
|
+
else if (item.label.startsWith('v-')) {
|
|
307
|
+
item.kind = 14;
|
|
308
|
+
}
|
|
309
|
+
if (item.label === DIRECTIVE_V_FOR_NAME) {
|
|
310
|
+
item.textEdit.newText = item.label + V_FOR_SNIPPET;
|
|
311
|
+
}
|
|
322
312
|
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
313
|
}
|
|
373
314
|
}
|
|
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
315
|
}
|
|
393
316
|
},
|
|
394
317
|
async resolveCompletionItem(item) {
|
|
395
|
-
|
|
318
|
+
const data = item.data;
|
|
319
|
+
if (data?.__vue__autoImport || data?.__vue__componentAutoImport) {
|
|
396
320
|
const embeddedUri = vscode_uri_1.URI.parse(lastCompletionDocument.uri);
|
|
397
321
|
const decoded = context.decodeEmbeddedDocumentUri(embeddedUri);
|
|
398
322
|
if (!decoded) {
|
|
@@ -402,7 +326,7 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
402
326
|
if (!sourceScript) {
|
|
403
327
|
return item;
|
|
404
328
|
}
|
|
405
|
-
const details = await resolveAutoImportCompletionEntry(
|
|
329
|
+
const details = await tsserver.resolveAutoImportCompletionEntry(data);
|
|
406
330
|
if (details) {
|
|
407
331
|
const virtualCode = sourceScript.generated.embeddedCodes.get(decoded[1]);
|
|
408
332
|
const sourceDocument = context.documents.get(sourceScript.id, sourceScript.languageId, sourceScript.snapshot);
|
|
@@ -420,7 +344,7 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
420
344
|
return item;
|
|
421
345
|
}
|
|
422
346
|
},
|
|
423
|
-
provideHover(document, position, token) {
|
|
347
|
+
async provideHover(document, position, token) {
|
|
424
348
|
if (document.languageId !== languageId) {
|
|
425
349
|
return;
|
|
426
350
|
}
|
|
@@ -428,12 +352,129 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
428
352
|
if (info?.code.id !== 'template') {
|
|
429
353
|
return;
|
|
430
354
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
355
|
+
let { result: htmlHover, } = await runWithVueDataProvider(info.script.id, info.root, undefined, 'hover', () => baseServiceInstance.provideHover(document, position, token));
|
|
356
|
+
const templateAst = info.root.sfc.template?.ast;
|
|
357
|
+
const enabledRichMessage = await context.env.getConfiguration?.('vue.hover.rich');
|
|
358
|
+
if (!templateAst || !enabledRichMessage || (htmlHover && hasContents(htmlHover.contents))) {
|
|
359
|
+
return htmlHover;
|
|
360
|
+
}
|
|
361
|
+
for (const element of (0, language_core_1.forEachElementNode)(templateAst)) {
|
|
362
|
+
const tagStart = element.loc.start.offset + element.loc.source.indexOf(element.tag);
|
|
363
|
+
const tagEnd = tagStart + element.tag.length;
|
|
364
|
+
const offset = document.offsetAt(position);
|
|
365
|
+
if (offset >= tagStart && offset <= tagEnd) {
|
|
366
|
+
const meta = await tsserver.getComponentMeta(info.root.fileName, element.tag);
|
|
367
|
+
const props = meta?.props.filter(p => !p.global);
|
|
368
|
+
const modelProps = new Set();
|
|
369
|
+
let tableContents = [];
|
|
370
|
+
for (const event of meta?.events ?? []) {
|
|
371
|
+
if (event.name.startsWith(UPDATE_EVENT_PREFIX)) {
|
|
372
|
+
const modelName = event.name.slice(UPDATE_EVENT_PREFIX.length);
|
|
373
|
+
const modelProp = props?.find(p => p.name === modelName);
|
|
374
|
+
if (modelProp) {
|
|
375
|
+
modelProps.add(modelProp);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
for (const prop of props ?? []) {
|
|
380
|
+
if (prop.name.startsWith(UPDATE_PROP_PREFIX)) {
|
|
381
|
+
const modelName = prop.name.slice(UPDATE_PROP_PREFIX.length);
|
|
382
|
+
const modelProp = props?.find(p => p.name === modelName);
|
|
383
|
+
if (modelProp) {
|
|
384
|
+
modelProps.add(modelProp);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
if (props?.length) {
|
|
389
|
+
let table = `<tr><th align="left">Prop</th><th align="left">Description</th><th align="left">Default</th></tr>\n`;
|
|
390
|
+
for (const p of props) {
|
|
391
|
+
table += `<tr>
|
|
392
|
+
<td>${printName(p, modelProps.has(p))}</td>
|
|
393
|
+
<td>${printDescription(p)}</td>
|
|
394
|
+
<td>${p.default ? `<code>${p.default}</code>` : ''}</td>
|
|
395
|
+
</tr>\n`;
|
|
396
|
+
}
|
|
397
|
+
tableContents.push(table);
|
|
398
|
+
}
|
|
399
|
+
if (meta?.events?.length) {
|
|
400
|
+
let table = `<tr><th align="left">Event</th><th align="left">Description</th><th></th></tr>\n`;
|
|
401
|
+
for (const e of meta.events) {
|
|
402
|
+
table += `<tr>
|
|
403
|
+
<td>${printName(e)}</td>
|
|
404
|
+
<td colspan="2">${printDescription(e)}</td>
|
|
405
|
+
</tr>\n`;
|
|
406
|
+
}
|
|
407
|
+
tableContents.push(table);
|
|
408
|
+
}
|
|
409
|
+
if (meta?.slots?.length) {
|
|
410
|
+
let table = `<tr><th align="left">Slot</th><th align="left">Description</th><th></th></tr>\n`;
|
|
411
|
+
for (const s of meta.slots) {
|
|
412
|
+
table += `<tr>
|
|
413
|
+
<td>${printName(s)}</td>
|
|
414
|
+
<td colspan="2">${printDescription(s)}</td>
|
|
415
|
+
</tr>\n`;
|
|
416
|
+
}
|
|
417
|
+
tableContents.push(table);
|
|
418
|
+
}
|
|
419
|
+
if (meta?.exposed.length) {
|
|
420
|
+
let table = `<tr><th align="left">Exposed</th><th align="left">Description</th><th></th></tr>\n`;
|
|
421
|
+
for (const e of meta.exposed) {
|
|
422
|
+
table += `<tr>
|
|
423
|
+
<td>${printName(e)}</td>
|
|
424
|
+
<td colspan="2">${printDescription(e)}</td>
|
|
425
|
+
</tr>\n`;
|
|
426
|
+
}
|
|
427
|
+
tableContents.push(table);
|
|
428
|
+
}
|
|
429
|
+
htmlHover ??= {
|
|
430
|
+
range: {
|
|
431
|
+
start: document.positionAt(tagStart),
|
|
432
|
+
end: document.positionAt(tagEnd),
|
|
433
|
+
},
|
|
434
|
+
contents: '',
|
|
435
|
+
};
|
|
436
|
+
// 2px height per <tr>
|
|
437
|
+
const tableGap = `<tr></tr>`.repeat(4);
|
|
438
|
+
htmlHover.contents = {
|
|
439
|
+
kind: 'markdown',
|
|
440
|
+
value: tableContents
|
|
441
|
+
? `<table>\n${tableContents.join(`\n${tableGap}\n`)}\n</table>`
|
|
442
|
+
: `No type information available.`,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return htmlHover;
|
|
447
|
+
function printName(meta, model) {
|
|
448
|
+
let name = meta.name;
|
|
449
|
+
if (meta.tags.some(tag => tag.name === 'deprecated')) {
|
|
450
|
+
name = `<del>${name}</del>`;
|
|
451
|
+
}
|
|
452
|
+
if (meta.required) {
|
|
453
|
+
name += ' <sup><em>required</em></sup>';
|
|
454
|
+
}
|
|
455
|
+
if (model) {
|
|
456
|
+
name += ' <sup><em>model</em></sup>';
|
|
457
|
+
}
|
|
458
|
+
return name;
|
|
459
|
+
}
|
|
460
|
+
function printDescription(meta) {
|
|
461
|
+
let desc = `<code>${meta.type}</code>`;
|
|
462
|
+
if (meta.description) {
|
|
463
|
+
// blank line for terminate HTML to support markdown
|
|
464
|
+
// see: https://github.github.com/gfm/#example-118
|
|
465
|
+
desc = `\n\n${meta.description}<br>${desc}`;
|
|
466
|
+
}
|
|
467
|
+
return desc;
|
|
468
|
+
}
|
|
469
|
+
function hasContents(contents) {
|
|
470
|
+
if (typeof contents === 'string') {
|
|
471
|
+
return !!contents;
|
|
472
|
+
}
|
|
473
|
+
if (Array.isArray(contents)) {
|
|
474
|
+
return contents.some(hasContents);
|
|
475
|
+
}
|
|
476
|
+
return !!contents.value;
|
|
435
477
|
}
|
|
436
|
-
return baseServiceInstance.provideHover?.(document, position, token);
|
|
437
478
|
},
|
|
438
479
|
async provideDocumentLinks(document, token) {
|
|
439
480
|
modulePathCache = new Map();
|
|
@@ -454,10 +495,10 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
454
495
|
}
|
|
455
496
|
},
|
|
456
497
|
};
|
|
457
|
-
async function
|
|
498
|
+
async function runWithVueDataProvider(sourceDocumentUri, root, hint, mode, fn) {
|
|
458
499
|
// #4298: Precompute HTMLDocument before provideHtmlData to avoid parseHTMLDocument requesting component names from tsserver
|
|
459
500
|
await fn();
|
|
460
|
-
const { sync } = await provideHtmlData(sourceDocumentUri, root);
|
|
501
|
+
const { sync } = await provideHtmlData(sourceDocumentUri, root, hint, mode);
|
|
461
502
|
let lastSync = await sync();
|
|
462
503
|
let result = await fn();
|
|
463
504
|
while (lastSync.version !== (lastSync = await sync()).version) {
|
|
@@ -465,255 +506,195 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
465
506
|
}
|
|
466
507
|
return { result, ...lastSync };
|
|
467
508
|
}
|
|
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
|
-
}
|
|
509
|
+
async function provideHtmlData(sourceDocumentUri, root, hint, mode) {
|
|
510
|
+
const [tagNameCasing, attrNameCasing] = await Promise.all([
|
|
511
|
+
(0, nameCasing_1.getTagNameCasing)(context, sourceDocumentUri),
|
|
512
|
+
(0, nameCasing_1.getAttrNameCasing)(context, sourceDocumentUri),
|
|
513
|
+
]);
|
|
483
514
|
let version = 0;
|
|
484
|
-
let target;
|
|
485
515
|
let components;
|
|
516
|
+
let elements;
|
|
517
|
+
let directives;
|
|
486
518
|
let values;
|
|
487
519
|
const tasks = [];
|
|
488
|
-
const
|
|
489
|
-
const propMap = new Map();
|
|
520
|
+
const tagDataMap = new Map();
|
|
490
521
|
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
522
|
{
|
|
517
523
|
getId: () => 'vue-template',
|
|
518
524
|
isApplicable: () => true,
|
|
519
525
|
provideTags: () => {
|
|
520
|
-
|
|
521
|
-
components = [];
|
|
522
|
-
tasks.push((async () => {
|
|
523
|
-
components = (await getComponentNames(root.fileName) ?? [])
|
|
524
|
-
.filter(name => !builtInComponents.has(name));
|
|
525
|
-
version++;
|
|
526
|
-
})());
|
|
527
|
-
}
|
|
526
|
+
const { components, elements } = getComponentsAndElements();
|
|
528
527
|
const codegen = language_core_1.tsCodegen.get(root.sfc);
|
|
529
528
|
const names = new Set();
|
|
530
529
|
const tags = [];
|
|
530
|
+
for (const tag of builtInData?.tags ?? []) {
|
|
531
|
+
tags.push({
|
|
532
|
+
...tag,
|
|
533
|
+
name: tagNameCasing === 0 /* TagNameCasing.Kebab */ ? (0, language_core_1.hyphenateTag)(tag.name) : tag.name,
|
|
534
|
+
});
|
|
535
|
+
}
|
|
531
536
|
for (const tag of components) {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
names.add(tag);
|
|
537
|
-
}
|
|
537
|
+
names.add(tagNameCasing === 0 /* TagNameCasing.Kebab */ ? (0, language_core_1.hyphenateTag)(tag) : tag);
|
|
538
|
+
}
|
|
539
|
+
for (const tag of elements) {
|
|
540
|
+
names.add(tag);
|
|
538
541
|
}
|
|
539
542
|
if (codegen) {
|
|
540
543
|
for (const name of [
|
|
541
|
-
...codegen.
|
|
544
|
+
...codegen.getImportedComponents(),
|
|
542
545
|
...codegen.getSetupExposed(),
|
|
543
546
|
]) {
|
|
544
|
-
|
|
545
|
-
names.add((0, language_core_1.hyphenateTag)(name));
|
|
546
|
-
}
|
|
547
|
-
else {
|
|
548
|
-
names.add(name);
|
|
549
|
-
}
|
|
547
|
+
names.add(tagNameCasing === 0 /* TagNameCasing.Kebab */ ? (0, language_core_1.hyphenateTag)(name) : name);
|
|
550
548
|
}
|
|
551
549
|
}
|
|
550
|
+
const added = new Set(tags.map(t => t.name));
|
|
552
551
|
for (const name of names) {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
552
|
+
if (!added.has(name)) {
|
|
553
|
+
const defaultTag = defaultHtmlTags.get(name);
|
|
554
|
+
tags.push({
|
|
555
|
+
...defaultTag,
|
|
556
|
+
name,
|
|
557
|
+
attributes: [],
|
|
558
|
+
});
|
|
559
|
+
}
|
|
557
560
|
}
|
|
558
561
|
return tags;
|
|
559
562
|
},
|
|
560
563
|
provideAttributes: tag => {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
events: [],
|
|
567
|
-
directives: [],
|
|
568
|
-
};
|
|
569
|
-
tagMap.set(tag, tagInfo);
|
|
570
|
-
tasks.push((async () => {
|
|
571
|
-
tagMap.set(tag, {
|
|
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
|
-
})());
|
|
579
|
-
}
|
|
580
|
-
const { attrs, propInfos, events, directives } = tagInfo;
|
|
581
|
-
for (let i = 0; i < propInfos.length; i++) {
|
|
582
|
-
const prop = propInfos[i];
|
|
583
|
-
if (prop.name.startsWith('ref_')) {
|
|
584
|
-
propInfos.splice(i--, 1);
|
|
564
|
+
const directives = getDirectives();
|
|
565
|
+
const { attrs, meta } = getTagData(tag);
|
|
566
|
+
const attributes = [];
|
|
567
|
+
for (const attr of builtInData?.globalAttributes ?? []) {
|
|
568
|
+
if (attr.name === 'is' && tag.toLowerCase() !== 'component') {
|
|
585
569
|
continue;
|
|
586
570
|
}
|
|
587
|
-
if (
|
|
588
|
-
|
|
589
|
-
|
|
571
|
+
if (attr.name === 'ref' || attr.name.startsWith('v-')) {
|
|
572
|
+
attributes.push(attr);
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
if (!hint || hint === ':') {
|
|
576
|
+
attributes.push({
|
|
577
|
+
...attr,
|
|
578
|
+
name: V_BIND_SHORTHAND + attr.name,
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
if (!hint || hint === 'v') {
|
|
582
|
+
attributes.push({
|
|
583
|
+
...attr,
|
|
584
|
+
name: DIRECTIVE_V_BIND + attr.name,
|
|
585
|
+
});
|
|
586
|
+
attributes.push({
|
|
587
|
+
...attr,
|
|
588
|
+
name: attr.name,
|
|
589
|
+
});
|
|
590
590
|
}
|
|
591
591
|
}
|
|
592
|
-
const
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
...propInfos,
|
|
596
|
-
...attrs.map(attr => ({ name: attr })),
|
|
592
|
+
for (const [propName, propMeta] of [
|
|
593
|
+
...meta?.props.map(prop => [prop.name, prop]) ?? [],
|
|
594
|
+
...attrs.map(attr => [attr.name, undefined]),
|
|
597
595
|
]) {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
info: prop,
|
|
596
|
+
if (propName.match(EVENT_PROP_REGEX)) {
|
|
597
|
+
let labelName = propName.slice(2);
|
|
598
|
+
labelName = labelName.charAt(0).toLowerCase() + labelName.slice(1);
|
|
599
|
+
if (attrNameCasing === 0 /* AttrNameCasing.Kebab */) {
|
|
600
|
+
labelName = (0, language_core_1.hyphenateAttr)(labelName);
|
|
601
|
+
}
|
|
602
|
+
if (!hint || hint === '@') {
|
|
603
|
+
attributes.push({
|
|
604
|
+
name: V_ON_SHORTHAND + labelName,
|
|
605
|
+
description: propMeta && createDescription(propMeta),
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
if (!hint || hint === 'v') {
|
|
609
|
+
attributes.push({
|
|
610
|
+
name: DIRECTIVE_V_ON + labelName,
|
|
611
|
+
description: propMeta && createDescription(propMeta),
|
|
615
612
|
});
|
|
616
613
|
}
|
|
617
614
|
}
|
|
618
615
|
else {
|
|
619
|
-
const
|
|
616
|
+
const labelName = attrNameCasing === 1 /* AttrNameCasing.Camel */ ? propName : (0, language_core_1.hyphenateAttr)(propName);
|
|
617
|
+
const propMeta2 = meta?.props.find(prop => {
|
|
620
618
|
const name = attrNameCasing === 1 /* AttrNameCasing.Camel */ ? prop.name : (0, language_core_1.hyphenateAttr)(prop.name);
|
|
621
|
-
return name ===
|
|
619
|
+
return name === labelName;
|
|
622
620
|
});
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
621
|
+
if (!hint || hint === ':') {
|
|
622
|
+
attributes.push({
|
|
623
|
+
name: V_BIND_SHORTHAND + labelName,
|
|
624
|
+
description: propMeta2 && createDescription(propMeta2),
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
if (!hint || hint === 'v') {
|
|
628
628
|
attributes.push({
|
|
629
|
-
name,
|
|
630
|
-
|
|
629
|
+
name: DIRECTIVE_V_BIND + labelName,
|
|
630
|
+
description: propMeta2 && createDescription(propMeta2),
|
|
631
631
|
});
|
|
632
|
-
|
|
633
|
-
name:
|
|
634
|
-
|
|
635
|
-
isGlobal,
|
|
636
|
-
info: propInfo,
|
|
632
|
+
attributes.push({
|
|
633
|
+
name: labelName,
|
|
634
|
+
description: propMeta2 && createDescription(propMeta2),
|
|
637
635
|
});
|
|
638
636
|
}
|
|
639
637
|
}
|
|
640
638
|
}
|
|
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
|
-
|
|
639
|
+
for (const event of meta?.events ?? []) {
|
|
640
|
+
const eventName = attrNameCasing === 1 /* AttrNameCasing.Camel */ ? event.name : (0, language_core_1.hyphenateAttr)(event.name);
|
|
641
|
+
if (!hint || hint === '@') {
|
|
642
|
+
attributes.push({
|
|
643
|
+
name: V_ON_SHORTHAND + eventName,
|
|
644
|
+
description: event && createDescription(event),
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
if (!hint || hint === 'v') {
|
|
648
|
+
attributes.push({
|
|
649
|
+
name: DIRECTIVE_V_ON + eventName,
|
|
650
|
+
description: event && createDescription(event),
|
|
651
651
|
});
|
|
652
652
|
}
|
|
653
653
|
}
|
|
654
654
|
for (const directive of directives) {
|
|
655
|
-
const name = (0, language_core_1.hyphenateAttr)(directive);
|
|
656
655
|
attributes.push({
|
|
657
|
-
name,
|
|
656
|
+
name: (0, language_core_1.hyphenateAttr)(directive),
|
|
658
657
|
});
|
|
659
658
|
}
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
...
|
|
663
|
-
...attrs.map(attr => ({ name: attr })),
|
|
659
|
+
for (const [propName, propMeta] of [
|
|
660
|
+
...meta?.props.map(prop => [prop.name, prop]) ?? [],
|
|
661
|
+
...attrs.map(attr => [attr.name, undefined]),
|
|
664
662
|
]) {
|
|
665
|
-
if (
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
663
|
+
if (propName.startsWith(UPDATE_PROP_PREFIX)) {
|
|
664
|
+
const model = propName.slice(UPDATE_PROP_PREFIX.length);
|
|
665
|
+
const label = DIRECTIVE_V_MODEL
|
|
666
|
+
+ (attrNameCasing === 1 /* AttrNameCasing.Camel */ ? model : (0, language_core_1.hyphenateAttr)(model));
|
|
667
|
+
attributes.push({
|
|
668
|
+
name: label,
|
|
669
|
+
description: propMeta && createDescription(propMeta),
|
|
670
|
+
});
|
|
672
671
|
}
|
|
673
672
|
}
|
|
674
|
-
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
});
|
|
673
|
+
if (!hint || hint === 'v') {
|
|
674
|
+
for (const event of meta?.events ?? []) {
|
|
675
|
+
if (event.name.startsWith(UPDATE_EVENT_PREFIX)) {
|
|
676
|
+
const model = event.name.slice(UPDATE_EVENT_PREFIX.length);
|
|
677
|
+
const label = DIRECTIVE_V_MODEL
|
|
678
|
+
+ (attrNameCasing === 1 /* AttrNameCasing.Camel */ ? model : (0, language_core_1.hyphenateAttr)(model));
|
|
679
|
+
attributes.push({
|
|
680
|
+
name: label,
|
|
681
|
+
description: createDescription(event),
|
|
682
|
+
});
|
|
683
|
+
}
|
|
686
684
|
}
|
|
687
685
|
}
|
|
688
686
|
return attributes;
|
|
689
687
|
},
|
|
690
688
|
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
|
-
}));
|
|
689
|
+
return getAttrValues(tag, attr).map(value => ({ name: value }));
|
|
703
690
|
},
|
|
704
691
|
},
|
|
705
692
|
{
|
|
706
693
|
getId: () => 'vue-auto-imports',
|
|
707
694
|
isApplicable: () => true,
|
|
708
|
-
provideTags() {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
provideAttributes() {
|
|
712
|
-
return [];
|
|
713
|
-
},
|
|
714
|
-
provideValues() {
|
|
715
|
-
return [];
|
|
716
|
-
},
|
|
695
|
+
provideTags: () => [{ name: AUTO_IMPORT_PLACEHOLDER, attributes: [] }],
|
|
696
|
+
provideAttributes: () => [],
|
|
697
|
+
provideValues: () => [],
|
|
717
698
|
},
|
|
718
699
|
]);
|
|
719
700
|
return {
|
|
@@ -721,25 +702,96 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
721
702
|
await Promise.all(tasks);
|
|
722
703
|
return {
|
|
723
704
|
version,
|
|
724
|
-
target,
|
|
725
705
|
info: {
|
|
726
706
|
tagNameCasing,
|
|
727
707
|
components,
|
|
728
|
-
propMap,
|
|
729
708
|
},
|
|
730
709
|
};
|
|
731
710
|
},
|
|
732
711
|
};
|
|
712
|
+
function createDescription(meta) {
|
|
713
|
+
if (mode === 'hover') {
|
|
714
|
+
// dedupe from TS hover
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
let description = meta?.description ?? '';
|
|
718
|
+
for (const tag of meta.tags) {
|
|
719
|
+
description += `\n\n*@${tag.name}* ${tag.text ?? ''}`;
|
|
720
|
+
}
|
|
721
|
+
if (!description) {
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
return {
|
|
725
|
+
kind: 'markdown',
|
|
726
|
+
value: description,
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
function getAttrValues(tag, attr) {
|
|
730
|
+
if (!values) {
|
|
731
|
+
values = [];
|
|
732
|
+
tasks.push((async () => {
|
|
733
|
+
if (tag === 'slot' && attr === 'name') {
|
|
734
|
+
values = await tsserver.getComponentSlots(root.fileName) ?? [];
|
|
735
|
+
}
|
|
736
|
+
version++;
|
|
737
|
+
})());
|
|
738
|
+
}
|
|
739
|
+
return values;
|
|
740
|
+
}
|
|
741
|
+
function getTagData(tag) {
|
|
742
|
+
let data = tagDataMap.get(tag);
|
|
743
|
+
if (!data) {
|
|
744
|
+
data = { attrs: [], meta: undefined };
|
|
745
|
+
tagDataMap.set(tag, data);
|
|
746
|
+
tasks.push((async () => {
|
|
747
|
+
tagDataMap.set(tag, {
|
|
748
|
+
attrs: await tsserver.getElementAttrs(root.fileName, tag) ?? [],
|
|
749
|
+
meta: await tsserver.getComponentMeta(root.fileName, tag),
|
|
750
|
+
});
|
|
751
|
+
version++;
|
|
752
|
+
})());
|
|
753
|
+
}
|
|
754
|
+
return data;
|
|
755
|
+
}
|
|
756
|
+
function getDirectives() {
|
|
757
|
+
if (!directives) {
|
|
758
|
+
directives = [];
|
|
759
|
+
tasks.push((async () => {
|
|
760
|
+
directives = await tsserver.getComponentDirectives(root.fileName) ?? [];
|
|
761
|
+
version++;
|
|
762
|
+
})());
|
|
763
|
+
}
|
|
764
|
+
return directives;
|
|
765
|
+
}
|
|
766
|
+
function getComponentsAndElements() {
|
|
767
|
+
if (!components || !elements) {
|
|
768
|
+
components = [];
|
|
769
|
+
elements = [];
|
|
770
|
+
tasks.push((async () => {
|
|
771
|
+
const res = await Promise.all([
|
|
772
|
+
tsserver.getComponentNames(root.fileName),
|
|
773
|
+
tsserver.getElementNames(root.fileName),
|
|
774
|
+
]);
|
|
775
|
+
components = res[0] ?? [];
|
|
776
|
+
elements = res[1] ?? [];
|
|
777
|
+
version++;
|
|
778
|
+
})());
|
|
779
|
+
}
|
|
780
|
+
return {
|
|
781
|
+
components,
|
|
782
|
+
elements,
|
|
783
|
+
};
|
|
784
|
+
}
|
|
733
785
|
}
|
|
734
|
-
function addDirectiveModifiers(
|
|
735
|
-
const replacement = getReplacement(
|
|
786
|
+
function addDirectiveModifiers(list, item, document) {
|
|
787
|
+
const replacement = getReplacement(item, document);
|
|
736
788
|
if (!replacement?.text.includes('.')) {
|
|
737
789
|
return;
|
|
738
790
|
}
|
|
739
791
|
const [text, ...modifiers] = replacement.text.split('.');
|
|
740
|
-
const isVOn = text.startsWith(
|
|
741
|
-
const isVBind = text.startsWith(
|
|
742
|
-
const isVModel = text.startsWith(
|
|
792
|
+
const isVOn = text.startsWith(DIRECTIVE_V_ON) || text.startsWith(V_ON_SHORTHAND) && text.length > 1;
|
|
793
|
+
const isVBind = text.startsWith(DIRECTIVE_V_BIND) || text.startsWith(V_BIND_SHORTHAND) && text.length > 1;
|
|
794
|
+
const isVModel = text.startsWith(DIRECTIVE_V_MODEL) || text === 'v-model';
|
|
743
795
|
const currentModifiers = isVOn
|
|
744
796
|
? vOnModifiers
|
|
745
797
|
: isVBind
|
|
@@ -769,55 +821,55 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
769
821
|
},
|
|
770
822
|
kind: 20,
|
|
771
823
|
};
|
|
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
|
-
}
|
|
824
|
+
list.items.push(newItem);
|
|
795
825
|
}
|
|
796
|
-
return newData;
|
|
797
826
|
}
|
|
798
827
|
},
|
|
799
828
|
};
|
|
800
|
-
function updateExtraCustomData(
|
|
801
|
-
|
|
829
|
+
function updateExtraCustomData(newData) {
|
|
830
|
+
htmlData = newData;
|
|
802
831
|
onDidChangeCustomDataListeners.forEach(l => l());
|
|
803
832
|
}
|
|
804
833
|
}
|
|
805
|
-
function getReplacement(
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
};
|
|
813
|
-
}
|
|
834
|
+
function getReplacement(item, doc) {
|
|
835
|
+
if (item.textEdit && 'range' in item.textEdit) {
|
|
836
|
+
return {
|
|
837
|
+
item: item,
|
|
838
|
+
textEdit: item.textEdit,
|
|
839
|
+
text: doc.getText(item.textEdit.range),
|
|
840
|
+
};
|
|
814
841
|
}
|
|
815
842
|
}
|
|
816
|
-
function
|
|
817
|
-
const
|
|
818
|
-
if (
|
|
819
|
-
return
|
|
843
|
+
function extractDirectiveModifiers(directive) {
|
|
844
|
+
const modifiers = {};
|
|
845
|
+
if (!directive) {
|
|
846
|
+
return modifiers;
|
|
847
|
+
}
|
|
848
|
+
const markdown = typeof directive.description === 'object'
|
|
849
|
+
? directive.description.value
|
|
850
|
+
: directive.description ?? '';
|
|
851
|
+
const modifierLines = markdown
|
|
852
|
+
.split('\n- ')[4]
|
|
853
|
+
?.split('\n').slice(2, -1) ?? [];
|
|
854
|
+
for (let text of modifierLines) {
|
|
855
|
+
text = text.slice(' - `.'.length);
|
|
856
|
+
const [name, desc] = text.split('` - ');
|
|
857
|
+
modifiers[name] = desc;
|
|
858
|
+
}
|
|
859
|
+
return modifiers;
|
|
860
|
+
}
|
|
861
|
+
function extractModelModifiers(attributes) {
|
|
862
|
+
const modifiers = {};
|
|
863
|
+
if (!attributes) {
|
|
864
|
+
return modifiers;
|
|
865
|
+
}
|
|
866
|
+
for (const modifier of attributes) {
|
|
867
|
+
const description = typeof modifier.description === 'object'
|
|
868
|
+
? modifier.description.value
|
|
869
|
+
: modifier.description ?? '';
|
|
870
|
+
const references = modifier.references?.map(ref => `[${ref.name}](${ref.url})`).join(' | ');
|
|
871
|
+
modifiers[modifier.name] = description + '\n\n' + references;
|
|
820
872
|
}
|
|
821
|
-
return
|
|
873
|
+
return modifiers;
|
|
822
874
|
}
|
|
823
875
|
//# sourceMappingURL=vue-template.js.map
|