@vue/language-service 3.1.7 → 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/data/template/fr.json +1 -1
- 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 +516 -483
- package/package.json +14 -14
- 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");
|
|
@@ -7,40 +40,31 @@ const language_core_1 = require("@vue/language-core");
|
|
|
7
40
|
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
|
-
const getFormatCodeSettings_js_1 = require("volar-service-typescript/lib/configs/getFormatCodeSettings.js");
|
|
11
|
-
const getUserPreferences_js_1 = require("volar-service-typescript/lib/configs/getUserPreferences.js");
|
|
12
43
|
const lspConverters_js_1 = require("volar-service-typescript/lib/utils/lspConverters.js");
|
|
13
|
-
const html = require("vscode-html-languageservice");
|
|
44
|
+
const html = __importStar(require("vscode-html-languageservice"));
|
|
14
45
|
const vscode_uri_1 = require("vscode-uri");
|
|
15
46
|
const data_1 = require("../data");
|
|
16
47
|
const htmlFormatter_1 = require("../htmlFormatter");
|
|
17
48
|
const nameCasing_1 = require("../nameCasing");
|
|
18
49
|
const utils_1 = require("../utils");
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
'Transition',
|
|
34
|
-
'TransitionGroup',
|
|
35
|
-
'KeepAlive',
|
|
36
|
-
'Suspense',
|
|
37
|
-
'Teleport',
|
|
38
|
-
]);
|
|
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}"';
|
|
39
64
|
let builtInData;
|
|
40
65
|
let modelData;
|
|
41
|
-
function create(ts, languageId,
|
|
42
|
-
let
|
|
43
|
-
let extraCustomData = [];
|
|
66
|
+
function create(ts, languageId, tsserver) {
|
|
67
|
+
let htmlData = [];
|
|
44
68
|
let modulePathCache;
|
|
45
69
|
const onDidChangeCustomDataListeners = new Set();
|
|
46
70
|
const onDidChangeCustomData = (listener) => {
|
|
@@ -51,62 +75,55 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
51
75
|
},
|
|
52
76
|
};
|
|
53
77
|
};
|
|
78
|
+
const getDocumentContext = context => ({
|
|
79
|
+
resolveReference(ref, base) {
|
|
80
|
+
let baseUri = vscode_uri_1.URI.parse(base);
|
|
81
|
+
const decoded = context.decodeEmbeddedDocumentUri(baseUri);
|
|
82
|
+
if (decoded) {
|
|
83
|
+
baseUri = decoded[0];
|
|
84
|
+
}
|
|
85
|
+
if (modulePathCache
|
|
86
|
+
&& baseUri.scheme === 'file'
|
|
87
|
+
&& !ref.startsWith('./')
|
|
88
|
+
&& !ref.startsWith('../')) {
|
|
89
|
+
const map = modulePathCache;
|
|
90
|
+
if (!map.has(ref)) {
|
|
91
|
+
const fileName = baseUri.fsPath.replace(/\\/g, '/');
|
|
92
|
+
const promise = tsserver.resolveModuleName(fileName, ref);
|
|
93
|
+
map.set(ref, promise);
|
|
94
|
+
if (promise instanceof Promise) {
|
|
95
|
+
promise.then(res => map.set(ref, res));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const cached = modulePathCache.get(ref);
|
|
99
|
+
if (cached instanceof Promise) {
|
|
100
|
+
throw cached;
|
|
101
|
+
}
|
|
102
|
+
if (cached) {
|
|
103
|
+
return cached;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return (0, volar_service_html_1.resolveReference)(ref, baseUri, context.env.workspaceFolders);
|
|
107
|
+
},
|
|
108
|
+
});
|
|
54
109
|
const baseService = languageId === 'jade'
|
|
55
110
|
? (0, volar_service_pug_1.create)({
|
|
56
111
|
useDefaultDataProvider: false,
|
|
112
|
+
getDocumentContext,
|
|
57
113
|
getCustomData() {
|
|
58
|
-
return
|
|
59
|
-
...customData,
|
|
60
|
-
...extraCustomData,
|
|
61
|
-
];
|
|
114
|
+
return htmlData;
|
|
62
115
|
},
|
|
63
116
|
onDidChangeCustomData,
|
|
64
117
|
})
|
|
65
118
|
: (0, volar_service_html_1.create)({
|
|
66
119
|
documentSelector: ['html', 'markdown'],
|
|
67
120
|
useDefaultDataProvider: false,
|
|
68
|
-
getDocumentContext
|
|
69
|
-
return {
|
|
70
|
-
resolveReference(ref, base) {
|
|
71
|
-
let baseUri = vscode_uri_1.URI.parse(base);
|
|
72
|
-
const decoded = context.decodeEmbeddedDocumentUri(baseUri);
|
|
73
|
-
if (decoded) {
|
|
74
|
-
baseUri = decoded[0];
|
|
75
|
-
}
|
|
76
|
-
if (modulePathCache
|
|
77
|
-
&& baseUri.scheme === 'file'
|
|
78
|
-
&& !ref.startsWith('./')
|
|
79
|
-
&& !ref.startsWith('../')) {
|
|
80
|
-
const map = modulePathCache;
|
|
81
|
-
if (!map.has(ref)) {
|
|
82
|
-
const fileName = baseUri.fsPath.replace(/\\/g, '/');
|
|
83
|
-
const promise = resolveModuleName(fileName, ref);
|
|
84
|
-
map.set(ref, promise);
|
|
85
|
-
if (promise instanceof Promise) {
|
|
86
|
-
promise.then(res => map.set(ref, res));
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
const cached = modulePathCache.get(ref);
|
|
90
|
-
if (cached instanceof Promise) {
|
|
91
|
-
throw cached;
|
|
92
|
-
}
|
|
93
|
-
if (cached) {
|
|
94
|
-
return cached;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return (0, volar_service_html_1.resolveReference)(ref, baseUri, context.env.workspaceFolders);
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
},
|
|
121
|
+
getDocumentContext,
|
|
101
122
|
getCustomData() {
|
|
102
|
-
return
|
|
103
|
-
...customData,
|
|
104
|
-
...extraCustomData,
|
|
105
|
-
];
|
|
123
|
+
return htmlData;
|
|
106
124
|
},
|
|
107
125
|
onDidChangeCustomData,
|
|
108
126
|
});
|
|
109
|
-
const htmlDataProvider = html.getDefaultHTMLDataProvider();
|
|
110
127
|
return {
|
|
111
128
|
name: `vue-template (${languageId})`,
|
|
112
129
|
capabilities: {
|
|
@@ -149,7 +166,7 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
149
166
|
const codegen = info && language_core_1.tsCodegen.get(info.root.sfc);
|
|
150
167
|
if (codegen) {
|
|
151
168
|
const componentNames = new Set([
|
|
152
|
-
...codegen.
|
|
169
|
+
...codegen.getImportedComponents(),
|
|
153
170
|
...codegen.getSetupExposed(),
|
|
154
171
|
]);
|
|
155
172
|
// copied from https://github.com/microsoft/vscode-html-languageservice/blob/10daf45dc16b4f4228987cf7cddf3a7dbbdc7570/src/beautify/beautify-html.js#L2746-L2761
|
|
@@ -184,66 +201,20 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
184
201
|
builtInData ??= (0, data_1.loadTemplateData)(context.env.locale ?? 'en');
|
|
185
202
|
modelData ??= (0, data_1.loadModelModifiersData)(context.env.locale ?? 'en');
|
|
186
203
|
// https://vuejs.org/api/built-in-directives.html#v-on
|
|
204
|
+
const vOnModifiers = extractDirectiveModifiers(builtInData.globalAttributes?.find(x => x.name === 'v-on'));
|
|
187
205
|
// https://vuejs.org/api/built-in-directives.html#v-bind
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
const vModelModifiers = {};
|
|
191
|
-
const vOn = builtInData.globalAttributes?.find(x => x.name === 'v-on');
|
|
192
|
-
const vBind = builtInData.globalAttributes?.find(x => x.name === 'v-bind');
|
|
193
|
-
const vModel = builtInData.globalAttributes?.find(x => x.name === 'v-model');
|
|
194
|
-
if (vOn) {
|
|
195
|
-
const markdown = typeof vOn.description === 'object'
|
|
196
|
-
? vOn.description.value
|
|
197
|
-
: vOn.description ?? '';
|
|
198
|
-
const modifiers = markdown
|
|
199
|
-
.split('\n- ')[4]
|
|
200
|
-
.split('\n').slice(2, -1);
|
|
201
|
-
for (let text of modifiers) {
|
|
202
|
-
text = text.slice(' - `.'.length);
|
|
203
|
-
const [name, desc] = text.split('` - ');
|
|
204
|
-
vOnModifiers[name] = desc;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
if (vBind) {
|
|
208
|
-
const markdown = typeof vBind.description === 'object'
|
|
209
|
-
? vBind.description.value
|
|
210
|
-
: vBind.description ?? '';
|
|
211
|
-
const modifiers = markdown
|
|
212
|
-
.split('\n- ')[4]
|
|
213
|
-
.split('\n').slice(2, -1);
|
|
214
|
-
for (let text of modifiers) {
|
|
215
|
-
text = text.slice(' - `.'.length);
|
|
216
|
-
const [name, desc] = text.split('` - ');
|
|
217
|
-
vBindModifiers[name] = desc;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
if (vModel) {
|
|
221
|
-
for (const modifier of modelData.globalAttributes ?? []) {
|
|
222
|
-
const description = typeof modifier.description === 'object'
|
|
223
|
-
? modifier.description.value
|
|
224
|
-
: modifier.description ?? '';
|
|
225
|
-
const references = modifier.references?.map(ref => `[${ref.name}](${ref.url})`).join(' | ');
|
|
226
|
-
vModelModifiers[modifier.name] = description + '\n\n' + references;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
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);
|
|
230
208
|
const transformedItems = new WeakSet();
|
|
231
|
-
|
|
232
|
-
|
|
209
|
+
const defaultHtmlTags = new Map();
|
|
210
|
+
for (const tag of html.getDefaultHTMLDataProvider().provideTags()) {
|
|
211
|
+
defaultHtmlTags.set(tag.name, tag);
|
|
212
|
+
}
|
|
233
213
|
let lastCompletionDocument;
|
|
234
214
|
return {
|
|
235
215
|
...baseServiceInstance,
|
|
236
216
|
dispose() {
|
|
237
217
|
baseServiceInstance.dispose?.();
|
|
238
|
-
disposable?.dispose();
|
|
239
|
-
},
|
|
240
|
-
provideDocumentFormattingEdits(document, range, options, ...rest) {
|
|
241
|
-
formattingOptions = options;
|
|
242
|
-
return baseServiceInstance.provideDocumentFormattingEdits?.(document, range, options, ...rest);
|
|
243
|
-
},
|
|
244
|
-
provideOnTypeFormattingEdits(document, position, key, options, ...rest) {
|
|
245
|
-
formattingOptions = options;
|
|
246
|
-
return baseServiceInstance.provideOnTypeFormattingEdits?.(document, position, key, options, ...rest);
|
|
247
218
|
},
|
|
248
219
|
async provideCompletionItems(document, position, completionContext, token) {
|
|
249
220
|
if (document.languageId !== languageId) {
|
|
@@ -253,21 +224,35 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
253
224
|
if (info?.code.id !== 'template') {
|
|
254
225
|
return;
|
|
255
226
|
}
|
|
256
|
-
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);
|
|
257
237
|
if (!htmlCompletion) {
|
|
258
238
|
return;
|
|
259
239
|
}
|
|
260
|
-
|
|
261
|
-
|
|
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
|
+
}
|
|
262
251
|
const offset = document.offsetAt(position);
|
|
263
252
|
const map = context.language.maps.get(info.code, info.script);
|
|
264
253
|
let spliced = false;
|
|
265
254
|
for (const [sourceOffset] of map.toSourceLocation(offset)) {
|
|
266
|
-
const
|
|
267
|
-
(0, getFormatCodeSettings_js_1.getFormatCodeSettings)(context, document, formattingOptions),
|
|
268
|
-
(0, getUserPreferences_js_1.getUserPreferences)(context, document),
|
|
269
|
-
]);
|
|
270
|
-
const autoImport = await getAutoImportSuggestions(info.root.fileName, sourceOffset, preferences, formatOptions);
|
|
255
|
+
const autoImport = await tsserver.getAutoImportSuggestions(info.root.fileName, sourceOffset);
|
|
271
256
|
if (!autoImport) {
|
|
272
257
|
continue;
|
|
273
258
|
}
|
|
@@ -296,118 +281,42 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
296
281
|
htmlCompletion.items.splice(autoImportPlaceholderIndex, 1);
|
|
297
282
|
}
|
|
298
283
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
328
|
-
if (prop.info?.deprecated) {
|
|
329
|
-
item.tags = [1];
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
else {
|
|
333
|
-
let name = item.label;
|
|
334
|
-
for (const str of ['v-bind:', ':']) {
|
|
335
|
-
if (name.startsWith(str) && name !== str) {
|
|
336
|
-
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
|
+
}
|
|
337
312
|
break;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
if (specialProps.has(name)) {
|
|
341
|
-
prop = {
|
|
342
|
-
name,
|
|
343
|
-
kind: 'prop',
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
const tokens = [];
|
|
348
|
-
if (prop) {
|
|
349
|
-
const { isEvent, propName } = getPropName(prop.name, prop.kind === 'event');
|
|
350
|
-
if (prop.kind === 'prop') {
|
|
351
|
-
if (!prop.isGlobal) {
|
|
352
|
-
item.kind = 5;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
else if (isEvent) {
|
|
356
|
-
item.kind = 23;
|
|
357
|
-
if (propName.startsWith('vue:')) {
|
|
358
|
-
tokens.push('\u0004');
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
if (!prop.isGlobal) {
|
|
362
|
-
tokens.push('\u0000');
|
|
363
|
-
if (item.label.startsWith(':')) {
|
|
364
|
-
tokens.push('\u0001');
|
|
365
|
-
}
|
|
366
|
-
else if (item.label.startsWith('@')) {
|
|
367
|
-
tokens.push('\u0002');
|
|
368
|
-
}
|
|
369
|
-
else if (item.label.startsWith('v-bind:')) {
|
|
370
|
-
tokens.push('\u0003');
|
|
371
|
-
}
|
|
372
|
-
else if (item.label.startsWith('v-model:')) {
|
|
373
|
-
tokens.push('\u0004');
|
|
374
|
-
}
|
|
375
|
-
else if (item.label.startsWith('v-on:')) {
|
|
376
|
-
tokens.push('\u0005');
|
|
377
|
-
}
|
|
378
|
-
else {
|
|
379
|
-
tokens.push('\u0000');
|
|
380
|
-
}
|
|
381
|
-
if (specialProps.has(propName)) {
|
|
382
|
-
tokens.push('\u0001');
|
|
383
|
-
}
|
|
384
|
-
else {
|
|
385
|
-
tokens.push('\u0000');
|
|
386
|
-
}
|
|
387
313
|
}
|
|
388
314
|
}
|
|
389
|
-
else if (item.label === 'v-if'
|
|
390
|
-
|| item.label === 'v-else-if'
|
|
391
|
-
|| item.label === 'v-else'
|
|
392
|
-
|| item.label === 'v-for') {
|
|
393
|
-
item.kind = 14;
|
|
394
|
-
tokens.push('\u0003');
|
|
395
|
-
}
|
|
396
|
-
else if (item.label.startsWith('v-')) {
|
|
397
|
-
item.kind = 3;
|
|
398
|
-
tokens.push('\u0002');
|
|
399
|
-
}
|
|
400
|
-
else {
|
|
401
|
-
tokens.push('\u0001');
|
|
402
|
-
}
|
|
403
|
-
item.sortText = tokens.join('') + (item.sortText ?? item.label);
|
|
404
|
-
if (item.label === 'v-for') {
|
|
405
|
-
item.textEdit.newText = item.label + '="${1:value} in ${2:source}"';
|
|
406
|
-
}
|
|
407
315
|
}
|
|
408
316
|
},
|
|
409
317
|
async resolveCompletionItem(item) {
|
|
410
|
-
|
|
318
|
+
const data = item.data;
|
|
319
|
+
if (data?.__vue__autoImport || data?.__vue__componentAutoImport) {
|
|
411
320
|
const embeddedUri = vscode_uri_1.URI.parse(lastCompletionDocument.uri);
|
|
412
321
|
const decoded = context.decodeEmbeddedDocumentUri(embeddedUri);
|
|
413
322
|
if (!decoded) {
|
|
@@ -417,11 +326,7 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
417
326
|
if (!sourceScript) {
|
|
418
327
|
return item;
|
|
419
328
|
}
|
|
420
|
-
const
|
|
421
|
-
(0, getFormatCodeSettings_js_1.getFormatCodeSettings)(context, lastCompletionDocument, formattingOptions),
|
|
422
|
-
(0, getUserPreferences_js_1.getUserPreferences)(context, lastCompletionDocument),
|
|
423
|
-
]);
|
|
424
|
-
const details = await resolveAutoImportCompletionEntry(item.data, preferences, formatOptions);
|
|
329
|
+
const details = await tsserver.resolveAutoImportCompletionEntry(data);
|
|
425
330
|
if (details) {
|
|
426
331
|
const virtualCode = sourceScript.generated.embeddedCodes.get(decoded[1]);
|
|
427
332
|
const sourceDocument = context.documents.get(sourceScript.id, sourceScript.languageId, sourceScript.snapshot);
|
|
@@ -439,7 +344,7 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
439
344
|
return item;
|
|
440
345
|
}
|
|
441
346
|
},
|
|
442
|
-
provideHover(document, position, token) {
|
|
347
|
+
async provideHover(document, position, token) {
|
|
443
348
|
if (document.languageId !== languageId) {
|
|
444
349
|
return;
|
|
445
350
|
}
|
|
@@ -447,12 +352,129 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
447
352
|
if (info?.code.id !== 'template') {
|
|
448
353
|
return;
|
|
449
354
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
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;
|
|
454
477
|
}
|
|
455
|
-
return baseServiceInstance.provideHover?.(document, position, token);
|
|
456
478
|
},
|
|
457
479
|
async provideDocumentLinks(document, token) {
|
|
458
480
|
modulePathCache = new Map();
|
|
@@ -473,10 +495,10 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
473
495
|
}
|
|
474
496
|
},
|
|
475
497
|
};
|
|
476
|
-
async function
|
|
498
|
+
async function runWithVueDataProvider(sourceDocumentUri, root, hint, mode, fn) {
|
|
477
499
|
// #4298: Precompute HTMLDocument before provideHtmlData to avoid parseHTMLDocument requesting component names from tsserver
|
|
478
500
|
await fn();
|
|
479
|
-
const { sync } = await provideHtmlData(sourceDocumentUri, root);
|
|
501
|
+
const { sync } = await provideHtmlData(sourceDocumentUri, root, hint, mode);
|
|
480
502
|
let lastSync = await sync();
|
|
481
503
|
let result = await fn();
|
|
482
504
|
while (lastSync.version !== (lastSync = await sync()).version) {
|
|
@@ -484,255 +506,195 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
484
506
|
}
|
|
485
507
|
return { result, ...lastSync };
|
|
486
508
|
}
|
|
487
|
-
async function provideHtmlData(sourceDocumentUri, root) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
if (specialTags.has(tag.name)) {
|
|
493
|
-
continue;
|
|
494
|
-
}
|
|
495
|
-
if (tagNameCasing === 0 /* TagNameCasing.Kebab */) {
|
|
496
|
-
tag.name = (0, language_core_1.hyphenateTag)(tag.name);
|
|
497
|
-
}
|
|
498
|
-
else {
|
|
499
|
-
tag.name = (0, shared_1.camelize)((0, shared_1.capitalize)(tag.name));
|
|
500
|
-
}
|
|
501
|
-
}
|
|
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
|
+
]);
|
|
502
514
|
let version = 0;
|
|
503
|
-
let target;
|
|
504
515
|
let components;
|
|
516
|
+
let elements;
|
|
517
|
+
let directives;
|
|
505
518
|
let values;
|
|
506
519
|
const tasks = [];
|
|
507
|
-
const
|
|
508
|
-
const propMap = new Map();
|
|
520
|
+
const tagDataMap = new Map();
|
|
509
521
|
updateExtraCustomData([
|
|
510
|
-
{
|
|
511
|
-
getId: () => htmlDataProvider.getId(),
|
|
512
|
-
isApplicable: () => true,
|
|
513
|
-
provideTags() {
|
|
514
|
-
target = 'tag';
|
|
515
|
-
return htmlDataProvider.provideTags()
|
|
516
|
-
.filter(tag => !specialTags.has(tag.name));
|
|
517
|
-
},
|
|
518
|
-
provideAttributes(tag) {
|
|
519
|
-
target = 'attribute';
|
|
520
|
-
const attrs = htmlDataProvider.provideAttributes(tag);
|
|
521
|
-
if (tag === 'slot') {
|
|
522
|
-
const nameAttr = attrs.find(attr => attr.name === 'name');
|
|
523
|
-
if (nameAttr) {
|
|
524
|
-
nameAttr.valueSet = 'slot';
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
return attrs;
|
|
528
|
-
},
|
|
529
|
-
provideValues(tag, attr) {
|
|
530
|
-
target = 'value';
|
|
531
|
-
return htmlDataProvider.provideValues(tag, attr);
|
|
532
|
-
},
|
|
533
|
-
},
|
|
534
|
-
html.newHTMLDataProvider('vue-template-built-in', builtInData),
|
|
535
522
|
{
|
|
536
523
|
getId: () => 'vue-template',
|
|
537
524
|
isApplicable: () => true,
|
|
538
525
|
provideTags: () => {
|
|
539
|
-
|
|
540
|
-
components = [];
|
|
541
|
-
tasks.push((async () => {
|
|
542
|
-
components = (await getComponentNames(root.fileName) ?? [])
|
|
543
|
-
.filter(name => !builtInComponents.has(name));
|
|
544
|
-
version++;
|
|
545
|
-
})());
|
|
546
|
-
}
|
|
526
|
+
const { components, elements } = getComponentsAndElements();
|
|
547
527
|
const codegen = language_core_1.tsCodegen.get(root.sfc);
|
|
548
528
|
const names = new Set();
|
|
549
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
|
+
}
|
|
550
536
|
for (const tag of components) {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
names.add(tag);
|
|
556
|
-
}
|
|
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);
|
|
557
541
|
}
|
|
558
542
|
if (codegen) {
|
|
559
543
|
for (const name of [
|
|
560
|
-
...codegen.
|
|
544
|
+
...codegen.getImportedComponents(),
|
|
561
545
|
...codegen.getSetupExposed(),
|
|
562
546
|
]) {
|
|
563
|
-
|
|
564
|
-
names.add((0, language_core_1.hyphenateTag)(name));
|
|
565
|
-
}
|
|
566
|
-
else {
|
|
567
|
-
names.add(name);
|
|
568
|
-
}
|
|
547
|
+
names.add(tagNameCasing === 0 /* TagNameCasing.Kebab */ ? (0, language_core_1.hyphenateTag)(name) : name);
|
|
569
548
|
}
|
|
570
549
|
}
|
|
550
|
+
const added = new Set(tags.map(t => t.name));
|
|
571
551
|
for (const name of names) {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
552
|
+
if (!added.has(name)) {
|
|
553
|
+
const defaultTag = defaultHtmlTags.get(name);
|
|
554
|
+
tags.push({
|
|
555
|
+
...defaultTag,
|
|
556
|
+
name,
|
|
557
|
+
attributes: [],
|
|
558
|
+
});
|
|
559
|
+
}
|
|
576
560
|
}
|
|
577
561
|
return tags;
|
|
578
562
|
},
|
|
579
563
|
provideAttributes: tag => {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
events: [],
|
|
586
|
-
directives: [],
|
|
587
|
-
};
|
|
588
|
-
tagMap.set(tag, tagInfo);
|
|
589
|
-
tasks.push((async () => {
|
|
590
|
-
tagMap.set(tag, {
|
|
591
|
-
attrs: await getElementAttrs(root.fileName, tag) ?? [],
|
|
592
|
-
propInfos: await getComponentProps(root.fileName, tag) ?? [],
|
|
593
|
-
events: await getComponentEvents(root.fileName, tag) ?? [],
|
|
594
|
-
directives: await getComponentDirectives(root.fileName) ?? [],
|
|
595
|
-
});
|
|
596
|
-
version++;
|
|
597
|
-
})());
|
|
598
|
-
}
|
|
599
|
-
const { attrs, propInfos, events, directives } = tagInfo;
|
|
600
|
-
for (let i = 0; i < propInfos.length; i++) {
|
|
601
|
-
const prop = propInfos[i];
|
|
602
|
-
if (prop.name.startsWith('ref_')) {
|
|
603
|
-
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') {
|
|
604
569
|
continue;
|
|
605
570
|
}
|
|
606
|
-
if (
|
|
607
|
-
|
|
608
|
-
|
|
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
|
+
});
|
|
609
590
|
}
|
|
610
591
|
}
|
|
611
|
-
const
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
...propInfos,
|
|
615
|
-
...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]),
|
|
616
595
|
]) {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
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),
|
|
634
612
|
});
|
|
635
613
|
}
|
|
636
614
|
}
|
|
637
615
|
else {
|
|
638
|
-
const
|
|
616
|
+
const labelName = attrNameCasing === 1 /* AttrNameCasing.Camel */ ? propName : (0, language_core_1.hyphenateAttr)(propName);
|
|
617
|
+
const propMeta2 = meta?.props.find(prop => {
|
|
639
618
|
const name = attrNameCasing === 1 /* AttrNameCasing.Camel */ ? prop.name : (0, language_core_1.hyphenateAttr)(prop.name);
|
|
640
|
-
return name ===
|
|
619
|
+
return name === labelName;
|
|
641
620
|
});
|
|
642
|
-
|
|
643
|
-
propName,
|
|
644
|
-
':' + propName,
|
|
645
|
-
'v-bind:' + propName,
|
|
646
|
-
]) {
|
|
621
|
+
if (!hint || hint === ':') {
|
|
647
622
|
attributes.push({
|
|
648
|
-
name,
|
|
649
|
-
|
|
623
|
+
name: V_BIND_SHORTHAND + labelName,
|
|
624
|
+
description: propMeta2 && createDescription(propMeta2),
|
|
650
625
|
});
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
626
|
+
}
|
|
627
|
+
if (!hint || hint === 'v') {
|
|
628
|
+
attributes.push({
|
|
629
|
+
name: DIRECTIVE_V_BIND + labelName,
|
|
630
|
+
description: propMeta2 && createDescription(propMeta2),
|
|
631
|
+
});
|
|
632
|
+
attributes.push({
|
|
633
|
+
name: labelName,
|
|
634
|
+
description: propMeta2 && createDescription(propMeta2),
|
|
656
635
|
});
|
|
657
636
|
}
|
|
658
637
|
}
|
|
659
638
|
}
|
|
660
|
-
for (const event of events) {
|
|
661
|
-
const eventName = attrNameCasing === 1 /* AttrNameCasing.Camel */ ? event : (0, language_core_1.hyphenateAttr)(event);
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
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),
|
|
670
651
|
});
|
|
671
652
|
}
|
|
672
653
|
}
|
|
673
654
|
for (const directive of directives) {
|
|
674
|
-
const name = (0, language_core_1.hyphenateAttr)(directive);
|
|
675
655
|
attributes.push({
|
|
676
|
-
name,
|
|
656
|
+
name: (0, language_core_1.hyphenateAttr)(directive),
|
|
677
657
|
});
|
|
678
658
|
}
|
|
679
|
-
const
|
|
680
|
-
|
|
681
|
-
...
|
|
682
|
-
...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]),
|
|
683
662
|
]) {
|
|
684
|
-
if (
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
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
|
+
});
|
|
691
671
|
}
|
|
692
672
|
}
|
|
693
|
-
|
|
694
|
-
const
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
});
|
|
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
|
+
}
|
|
705
684
|
}
|
|
706
685
|
}
|
|
707
686
|
return attributes;
|
|
708
687
|
},
|
|
709
688
|
provideValues: (tag, attr) => {
|
|
710
|
-
|
|
711
|
-
values = [];
|
|
712
|
-
tasks.push((async () => {
|
|
713
|
-
if (tag === 'slot' && attr === 'name') {
|
|
714
|
-
values = await getComponentSlots(root.fileName) ?? [];
|
|
715
|
-
}
|
|
716
|
-
version++;
|
|
717
|
-
})());
|
|
718
|
-
}
|
|
719
|
-
return values.map(value => ({
|
|
720
|
-
name: value,
|
|
721
|
-
}));
|
|
689
|
+
return getAttrValues(tag, attr).map(value => ({ name: value }));
|
|
722
690
|
},
|
|
723
691
|
},
|
|
724
692
|
{
|
|
725
693
|
getId: () => 'vue-auto-imports',
|
|
726
694
|
isApplicable: () => true,
|
|
727
|
-
provideTags() {
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
provideAttributes() {
|
|
731
|
-
return [];
|
|
732
|
-
},
|
|
733
|
-
provideValues() {
|
|
734
|
-
return [];
|
|
735
|
-
},
|
|
695
|
+
provideTags: () => [{ name: AUTO_IMPORT_PLACEHOLDER, attributes: [] }],
|
|
696
|
+
provideAttributes: () => [],
|
|
697
|
+
provideValues: () => [],
|
|
736
698
|
},
|
|
737
699
|
]);
|
|
738
700
|
return {
|
|
@@ -740,25 +702,96 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
740
702
|
await Promise.all(tasks);
|
|
741
703
|
return {
|
|
742
704
|
version,
|
|
743
|
-
target,
|
|
744
705
|
info: {
|
|
745
706
|
tagNameCasing,
|
|
746
707
|
components,
|
|
747
|
-
propMap,
|
|
748
708
|
},
|
|
749
709
|
};
|
|
750
710
|
},
|
|
751
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
|
+
}
|
|
752
785
|
}
|
|
753
|
-
function addDirectiveModifiers(
|
|
754
|
-
const replacement = getReplacement(
|
|
786
|
+
function addDirectiveModifiers(list, item, document) {
|
|
787
|
+
const replacement = getReplacement(item, document);
|
|
755
788
|
if (!replacement?.text.includes('.')) {
|
|
756
789
|
return;
|
|
757
790
|
}
|
|
758
791
|
const [text, ...modifiers] = replacement.text.split('.');
|
|
759
|
-
const isVOn = text.startsWith(
|
|
760
|
-
const isVBind = text.startsWith(
|
|
761
|
-
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';
|
|
762
795
|
const currentModifiers = isVOn
|
|
763
796
|
? vOnModifiers
|
|
764
797
|
: isVBind
|
|
@@ -788,55 +821,55 @@ function create(ts, languageId, { getComponentNames, getComponentProps, getCompo
|
|
|
788
821
|
},
|
|
789
822
|
kind: 20,
|
|
790
823
|
};
|
|
791
|
-
|
|
824
|
+
list.items.push(newItem);
|
|
792
825
|
}
|
|
793
826
|
}
|
|
794
|
-
async function initialize() {
|
|
795
|
-
customData = await getHtmlCustomData();
|
|
796
|
-
}
|
|
797
|
-
async function getHtmlCustomData() {
|
|
798
|
-
const customData = await context.env.getConfiguration?.('html.customData') ?? [];
|
|
799
|
-
const newData = [];
|
|
800
|
-
for (const customDataPath of customData) {
|
|
801
|
-
for (const workspaceFolder of context.env.workspaceFolders) {
|
|
802
|
-
const uri = vscode_uri_1.Utils.resolvePath(workspaceFolder, customDataPath);
|
|
803
|
-
const json = await context.env.fs?.readFile(uri);
|
|
804
|
-
if (json) {
|
|
805
|
-
try {
|
|
806
|
-
const data = JSON.parse(json);
|
|
807
|
-
newData.push(html.newHTMLDataProvider(customDataPath, data));
|
|
808
|
-
}
|
|
809
|
-
catch (error) {
|
|
810
|
-
console.error(error);
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
return newData;
|
|
816
|
-
}
|
|
817
827
|
},
|
|
818
828
|
};
|
|
819
|
-
function updateExtraCustomData(
|
|
820
|
-
|
|
829
|
+
function updateExtraCustomData(newData) {
|
|
830
|
+
htmlData = newData;
|
|
821
831
|
onDidChangeCustomDataListeners.forEach(l => l());
|
|
822
832
|
}
|
|
823
833
|
}
|
|
824
|
-
function getReplacement(
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
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
|
+
};
|
|
841
|
+
}
|
|
842
|
+
}
|
|
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;
|
|
833
858
|
}
|
|
859
|
+
return modifiers;
|
|
834
860
|
}
|
|
835
|
-
function
|
|
836
|
-
const
|
|
837
|
-
if (
|
|
838
|
-
return
|
|
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;
|
|
839
872
|
}
|
|
840
|
-
return
|
|
873
|
+
return modifiers;
|
|
841
874
|
}
|
|
842
875
|
//# sourceMappingURL=vue-template.js.map
|