@vue/language-service 2.0.6 → 2.0.10
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/language-blocks/en.json +1 -1
- package/data/model-modifiers/ja.json +1 -1
- package/data/template/ja.json +1 -1
- package/index.d.ts +3 -2
- package/index.js +88 -23
- package/lib/ideFeatures/nameCasing.d.ts +2 -2
- package/lib/ideFeatures/nameCasing.js +23 -16
- package/lib/plugins/css.d.ts +2 -2
- package/lib/plugins/data.js +6 -3
- package/lib/plugins/vue-autoinsert-dotvalue.d.ts +5 -5
- package/lib/plugins/vue-autoinsert-dotvalue.js +37 -31
- package/lib/plugins/vue-autoinsert-parentheses.d.ts +2 -2
- package/lib/plugins/vue-autoinsert-parentheses.js +15 -6
- package/lib/plugins/vue-autoinsert-space.d.ts +2 -2
- package/lib/plugins/vue-autoinsert-space.js +7 -14
- package/lib/plugins/vue-codelens-references.d.ts +2 -2
- package/lib/plugins/vue-codelens-references.js +8 -4
- package/lib/plugins/vue-directive-comments.d.ts +2 -2
- package/lib/plugins/vue-directive-comments.js +4 -3
- package/lib/plugins/vue-document-drop.d.ts +2 -2
- package/lib/plugins/vue-document-drop.js +36 -14
- package/lib/plugins/vue-extract-file.d.ts +2 -2
- package/lib/plugins/vue-extract-file.js +32 -18
- package/lib/plugins/vue-sfc.d.ts +2 -2
- package/lib/plugins/vue-sfc.js +40 -35
- package/lib/plugins/vue-template.d.ts +3 -3
- package/lib/plugins/vue-template.js +86 -32
- package/lib/plugins/vue-toggle-v-bind-codeaction.d.ts +2 -2
- package/lib/plugins/vue-toggle-v-bind-codeaction.js +6 -3
- package/lib/plugins/vue-twoslash-queries.d.ts +2 -2
- package/lib/plugins/vue-twoslash-queries.js +9 -5
- package/lib/plugins/vue-visualize-hidden-callback-param.d.ts +2 -2
- package/lib/plugins/vue-visualize-hidden-callback-param.js +7 -4
- package/package.json +19 -19
|
@@ -6,45 +6,67 @@ const shared_1 = require("@vue/shared");
|
|
|
6
6
|
const path = require("path-browserify");
|
|
7
7
|
const vue_extract_file_1 = require("../plugins/vue-extract-file");
|
|
8
8
|
const types_1 = require("../types");
|
|
9
|
-
|
|
9
|
+
const getUserPreferences_1 = require("volar-service-typescript/lib/configs/getUserPreferences");
|
|
10
|
+
function create(ts, getTsPluginClient) {
|
|
10
11
|
return {
|
|
11
12
|
name: 'vue-document-drop',
|
|
12
13
|
create(context) {
|
|
13
14
|
let casing = types_1.TagNameCasing.Pascal; // TODO
|
|
15
|
+
const tsPluginClient = getTsPluginClient?.(context);
|
|
14
16
|
return {
|
|
15
17
|
async provideDocumentDropEdits(document, _position, dataTransfer) {
|
|
16
|
-
if (document.languageId !== 'html')
|
|
18
|
+
if (document.languageId !== 'html') {
|
|
17
19
|
return;
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
20
|
+
}
|
|
21
|
+
const decoded = context.decodeEmbeddedDocumentUri(document.uri);
|
|
22
|
+
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
23
|
+
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
|
|
24
|
+
const vueVirtualCode = sourceScript?.generated?.root;
|
|
25
|
+
if (!sourceScript || !virtualCode || !(vueVirtualCode instanceof language_core_1.VueGeneratedCode)) {
|
|
21
26
|
return;
|
|
27
|
+
}
|
|
22
28
|
let importUri;
|
|
23
29
|
for (const [mimeType, item] of dataTransfer) {
|
|
24
30
|
if (mimeType === 'text/uri-list') {
|
|
25
31
|
importUri = item.value;
|
|
26
32
|
}
|
|
27
33
|
}
|
|
28
|
-
if (!importUri?.endsWith('.vue'))
|
|
34
|
+
if (!importUri?.endsWith('.vue')) {
|
|
29
35
|
return;
|
|
36
|
+
}
|
|
30
37
|
let baseName = importUri.substring(importUri.lastIndexOf('/') + 1);
|
|
31
38
|
baseName = baseName.substring(0, baseName.lastIndexOf('.'));
|
|
32
39
|
const newName = (0, shared_1.capitalize)((0, shared_1.camelize)(baseName));
|
|
33
40
|
const { sfc } = vueVirtualCode;
|
|
34
41
|
const script = sfc.scriptSetup ?? sfc.script;
|
|
35
|
-
if (!script)
|
|
42
|
+
if (!script) {
|
|
36
43
|
return;
|
|
44
|
+
}
|
|
37
45
|
const additionalEdit = {};
|
|
38
46
|
const code = [...(0, language_core_1.forEachEmbeddedCode)(vueVirtualCode)].find(code => code.id === (sfc.scriptSetup ? 'scriptSetupFormat' : 'scriptFormat'));
|
|
39
47
|
const lastImportNode = (0, vue_extract_file_1.getLastImportNode)(ts, script.ast);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
const incomingFileName = context.env.typescript.uriToFileName(importUri);
|
|
49
|
+
let importPath;
|
|
50
|
+
const serviceScript = sourceScript.generated?.languagePlugin.typescript?.getServiceScript(vueVirtualCode);
|
|
51
|
+
if (tsPluginClient && serviceScript) {
|
|
52
|
+
const tsDocumentUri = context.encodeEmbeddedDocumentUri(sourceScript.id, serviceScript.code.id);
|
|
53
|
+
const tsDocument = context.documents.get(tsDocumentUri, serviceScript.code.languageId, serviceScript.code.snapshot);
|
|
54
|
+
const preferences = await (0, getUserPreferences_1.getUserPreferences)(context, tsDocument);
|
|
55
|
+
const importPathRequest = await tsPluginClient.getImportPathForFile(vueVirtualCode.fileName, incomingFileName, preferences);
|
|
56
|
+
if (importPathRequest) {
|
|
57
|
+
importPath = importPathRequest;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!importPath) {
|
|
61
|
+
importPath = path.relative(path.dirname(vueVirtualCode.fileName), incomingFileName)
|
|
62
|
+
|| importUri.substring(importUri.lastIndexOf('/') + 1);
|
|
63
|
+
if (!importPath.startsWith('./') && !importPath.startsWith('../')) {
|
|
64
|
+
importPath = './' + importPath;
|
|
65
|
+
}
|
|
44
66
|
}
|
|
45
67
|
additionalEdit.changes ??= {};
|
|
46
|
-
additionalEdit.changes[context.
|
|
47
|
-
additionalEdit.changes[context.
|
|
68
|
+
additionalEdit.changes[context.encodeEmbeddedDocumentUri(sourceScript.id, code.id)] = [];
|
|
69
|
+
additionalEdit.changes[context.encodeEmbeddedDocumentUri(sourceScript.id, code.id)].push({
|
|
48
70
|
range: lastImportNode ? {
|
|
49
71
|
start: script.ast.getLineAndCharacterOfPosition(lastImportNode.end),
|
|
50
72
|
end: script.ast.getLineAndCharacterOfPosition(lastImportNode.end),
|
|
@@ -58,7 +80,7 @@ function create(ts) {
|
|
|
58
80
|
if (sfc.script) {
|
|
59
81
|
const edit = (0, vue_extract_file_1.createAddComponentToOptionEdit)(ts, sfc.script.ast, newName);
|
|
60
82
|
if (edit) {
|
|
61
|
-
additionalEdit.changes[context.
|
|
83
|
+
additionalEdit.changes[context.encodeEmbeddedDocumentUri(sourceScript.id, code.id)].push({
|
|
62
84
|
range: {
|
|
63
85
|
start: document.positionAt(edit.range.start),
|
|
64
86
|
end: document.positionAt(edit.range.end),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ServiceContext, LanguageServicePlugin } from '@volar/language-service';
|
|
2
2
|
import type * as ts from 'typescript';
|
|
3
|
-
export declare function create(ts: typeof import('typescript'),
|
|
3
|
+
export declare function create(ts: typeof import('typescript'), getTsPluginClient?: (context: ServiceContext) => typeof import('@vue/typescript-plugin/lib/client') | undefined): LanguageServicePlugin;
|
|
4
4
|
export declare function getLastImportNode(ts: typeof import('typescript'), sourceFile: ts.SourceFile): ts.Node | undefined;
|
|
5
5
|
export declare function createAddComponentToOptionEdit(ts: typeof import('typescript'), ast: ts.SourceFile, componentName: string): {
|
|
6
6
|
range: import("@vue/language-core").TextRange;
|
|
@@ -3,10 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createAddComponentToOptionEdit = exports.getLastImportNode = exports.create = void 0;
|
|
4
4
|
const language_core_1 = require("@vue/language-core");
|
|
5
5
|
const unicodeReg = /\\u/g;
|
|
6
|
-
function create(ts,
|
|
6
|
+
function create(ts, getTsPluginClient) {
|
|
7
7
|
return {
|
|
8
8
|
name: 'vue-extract-file',
|
|
9
9
|
create(context) {
|
|
10
|
+
const tsPluginClient = getTsPluginClient?.(context);
|
|
10
11
|
return {
|
|
11
12
|
async provideCodeActions(document, range, _context) {
|
|
12
13
|
const startOffset = document.offsetAt(range.start);
|
|
@@ -14,16 +15,21 @@ function create(ts, tsPluginClient) {
|
|
|
14
15
|
if (startOffset === endOffset) {
|
|
15
16
|
return;
|
|
16
17
|
}
|
|
17
|
-
const
|
|
18
|
-
|
|
18
|
+
const decoded = context.decodeEmbeddedDocumentUri(document.uri);
|
|
19
|
+
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
20
|
+
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
|
|
21
|
+
if (!(sourceScript?.generated?.root instanceof language_core_1.VueGeneratedCode) || virtualCode?.id !== 'template') {
|
|
19
22
|
return;
|
|
20
|
-
|
|
23
|
+
}
|
|
24
|
+
const { sfc } = sourceScript.generated.root;
|
|
21
25
|
const script = sfc.scriptSetup ?? sfc.script;
|
|
22
|
-
if (!sfc.template || !script)
|
|
26
|
+
if (!sfc.template || !script) {
|
|
23
27
|
return;
|
|
28
|
+
}
|
|
24
29
|
const templateCodeRange = selectTemplateCode(startOffset, endOffset, sfc.template);
|
|
25
|
-
if (!templateCodeRange)
|
|
30
|
+
if (!templateCodeRange) {
|
|
26
31
|
return;
|
|
32
|
+
}
|
|
27
33
|
return [
|
|
28
34
|
{
|
|
29
35
|
title: 'Extract into new dumb component',
|
|
@@ -39,21 +45,27 @@ function create(ts, tsPluginClient) {
|
|
|
39
45
|
async resolveCodeAction(codeAction) {
|
|
40
46
|
const { uri, range, newName } = codeAction.data;
|
|
41
47
|
const [startOffset, endOffset] = range;
|
|
42
|
-
const
|
|
43
|
-
|
|
48
|
+
const decoded = context.decodeEmbeddedDocumentUri(uri);
|
|
49
|
+
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
50
|
+
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
|
|
51
|
+
if (!(sourceScript?.generated?.root instanceof language_core_1.VueGeneratedCode) || virtualCode?.id !== 'template') {
|
|
44
52
|
return codeAction;
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
const
|
|
53
|
+
}
|
|
54
|
+
const document = context.documents.get(uri, virtualCode.languageId, virtualCode.snapshot);
|
|
55
|
+
const sfcDocument = context.documents.get(sourceScript.id, sourceScript.languageId, sourceScript.snapshot);
|
|
56
|
+
const { sfc } = sourceScript.generated.root;
|
|
48
57
|
const script = sfc.scriptSetup ?? sfc.script;
|
|
49
|
-
if (!sfc.template || !script)
|
|
58
|
+
if (!sfc.template || !script) {
|
|
50
59
|
return codeAction;
|
|
60
|
+
}
|
|
51
61
|
const templateCodeRange = selectTemplateCode(startOffset, endOffset, sfc.template);
|
|
52
|
-
if (!templateCodeRange)
|
|
62
|
+
if (!templateCodeRange) {
|
|
53
63
|
return codeAction;
|
|
54
|
-
|
|
55
|
-
|
|
64
|
+
}
|
|
65
|
+
const toExtract = await tsPluginClient?.collectExtractProps(sourceScript.generated.root.fileName, templateCodeRange) ?? [];
|
|
66
|
+
if (!toExtract) {
|
|
56
67
|
return codeAction;
|
|
68
|
+
}
|
|
57
69
|
const templateInitialIndent = await context.env.getConfiguration('vue.format.template.initialIndent') ?? true;
|
|
58
70
|
const scriptInitialIndent = await context.env.getConfiguration('vue.format.script.initialIndent') ?? false;
|
|
59
71
|
const newUri = sfcDocument.uri.substring(0, sfcDocument.uri.lastIndexOf('/') + 1) + `${newName}.vue`;
|
|
@@ -114,7 +126,7 @@ function create(ts, tsPluginClient) {
|
|
|
114
126
|
// editing vue sfc
|
|
115
127
|
{
|
|
116
128
|
textDocument: {
|
|
117
|
-
uri:
|
|
129
|
+
uri: sourceScript.id,
|
|
118
130
|
version: null,
|
|
119
131
|
},
|
|
120
132
|
edits: sfcEdits,
|
|
@@ -200,8 +212,9 @@ function selectTemplateCode(startOffset, endOffset, templateBlock) {
|
|
|
200
212
|
}
|
|
201
213
|
}
|
|
202
214
|
function constructTag(name, attributes, initialIndent, content) {
|
|
203
|
-
if (initialIndent)
|
|
215
|
+
if (initialIndent) {
|
|
204
216
|
content = content.split('\n').map(line => `\t${line}`).join('\n');
|
|
217
|
+
}
|
|
205
218
|
const attributesString = attributes.length ? ` ${attributes.join(' ')}` : '';
|
|
206
219
|
return `<${name}${attributesString}>\n${content}\n</${name}>\n`;
|
|
207
220
|
}
|
|
@@ -220,8 +233,9 @@ function getLastImportNode(ts, sourceFile) {
|
|
|
220
233
|
exports.getLastImportNode = getLastImportNode;
|
|
221
234
|
function createAddComponentToOptionEdit(ts, ast, componentName) {
|
|
222
235
|
const exportDefault = language_core_1.scriptRanges.parseScriptRanges(ts, ast, false, true).exportDefault;
|
|
223
|
-
if (!exportDefault)
|
|
236
|
+
if (!exportDefault) {
|
|
224
237
|
return;
|
|
238
|
+
}
|
|
225
239
|
// https://github.com/microsoft/TypeScript/issues/36174
|
|
226
240
|
const printer = ts.createPrinter();
|
|
227
241
|
if (exportDefault.componentsOption && exportDefault.componentsOptionNode) {
|
package/lib/plugins/vue-sfc.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { LanguageServicePlugin } from '@volar/language-service';
|
|
2
2
|
import * as vue from '@vue/language-core';
|
|
3
3
|
import type { TextDocument } from 'vscode-languageserver-textdocument';
|
|
4
4
|
export interface Provide {
|
|
5
5
|
'vue/vueFile': (document: TextDocument) => vue.VueGeneratedCode | undefined;
|
|
6
6
|
}
|
|
7
|
-
export declare function create():
|
|
7
|
+
export declare function create(): LanguageServicePlugin;
|
package/lib/plugins/vue-sfc.js
CHANGED
|
@@ -12,34 +12,53 @@ function create() {
|
|
|
12
12
|
create(context) {
|
|
13
13
|
const htmlPlugin = (0, volar_service_html_1.create)({
|
|
14
14
|
documentSelector: ['vue'],
|
|
15
|
-
|
|
15
|
+
useDefaultDataProvider: false,
|
|
16
|
+
getCustomData(context) {
|
|
17
|
+
sfcDataProvider ??= html.newHTMLDataProvider('vue', (0, data_1.loadLanguageBlocks)(context.env.locale ?? 'en'));
|
|
18
|
+
return [sfcDataProvider];
|
|
19
|
+
},
|
|
20
|
+
async getFormattingOptions(document, options, context) {
|
|
21
|
+
return await worker(document, async (vueCode) => {
|
|
22
|
+
const formatSettings = await context.env.getConfiguration?.('html.format') ?? {};
|
|
23
|
+
const blockTypes = ['template', 'script', 'style'];
|
|
24
|
+
for (const customBlock of vueCode.sfc.customBlocks) {
|
|
25
|
+
blockTypes.push(customBlock.type);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
...options,
|
|
29
|
+
...formatSettings,
|
|
30
|
+
wrapAttributes: 'auto',
|
|
31
|
+
unformatted: '',
|
|
32
|
+
contentUnformatted: blockTypes.join(','),
|
|
33
|
+
endWithNewline: options.insertFinalNewline ? true
|
|
34
|
+
: options.trimFinalNewlines ? false
|
|
35
|
+
: document.getText().endsWith('\n'),
|
|
36
|
+
};
|
|
37
|
+
}) ?? {};
|
|
38
|
+
},
|
|
16
39
|
}).create(context);
|
|
17
|
-
const htmlLanguageService = htmlPlugin.provide['html/languageService']();
|
|
18
|
-
sfcDataProvider ??= html.newHTMLDataProvider('vue', (0, data_1.loadLanguageBlocks)(context.env.locale ?? 'en'));
|
|
19
|
-
htmlLanguageService.setDataProviders(false, [sfcDataProvider]);
|
|
20
40
|
return {
|
|
21
41
|
...htmlPlugin,
|
|
22
42
|
provide: {
|
|
23
43
|
'vue/vueFile': document => {
|
|
24
|
-
return worker(document,
|
|
44
|
+
return worker(document, vueFile => {
|
|
25
45
|
return vueFile;
|
|
26
46
|
});
|
|
27
47
|
},
|
|
28
48
|
},
|
|
29
|
-
async resolveEmbeddedCodeFormattingOptions(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (code.id === 'scriptFormat' || code.id === 'scriptSetupFormat') {
|
|
49
|
+
async resolveEmbeddedCodeFormattingOptions(sourceScript, virtualCode, options) {
|
|
50
|
+
if (sourceScript.generated?.root instanceof vue.VueGeneratedCode) {
|
|
51
|
+
if (virtualCode.id === 'scriptFormat' || virtualCode.id === 'scriptSetupFormat') {
|
|
33
52
|
if (await context.env.getConfiguration?.('vue.format.script.initialIndent') ?? false) {
|
|
34
53
|
options.initialIndentLevel++;
|
|
35
54
|
}
|
|
36
55
|
}
|
|
37
|
-
else if (
|
|
56
|
+
else if (virtualCode.id.startsWith('style_')) {
|
|
38
57
|
if (await context.env.getConfiguration?.('vue.format.style.initialIndent') ?? false) {
|
|
39
58
|
options.initialIndentLevel++;
|
|
40
59
|
}
|
|
41
60
|
}
|
|
42
|
-
else if (
|
|
61
|
+
else if (virtualCode.id === 'template') {
|
|
43
62
|
if (await context.env.getConfiguration?.('vue.format.template.initialIndent') ?? true) {
|
|
44
63
|
options.initialIndentLevel++;
|
|
45
64
|
}
|
|
@@ -49,7 +68,7 @@ function create() {
|
|
|
49
68
|
},
|
|
50
69
|
provideDocumentLinks: undefined,
|
|
51
70
|
provideDocumentSymbols(document) {
|
|
52
|
-
return worker(document,
|
|
71
|
+
return worker(document, vueSourceFile => {
|
|
53
72
|
const result = [];
|
|
54
73
|
const descriptor = vueSourceFile.sfc;
|
|
55
74
|
if (descriptor.template) {
|
|
@@ -96,10 +115,12 @@ function create() {
|
|
|
96
115
|
}
|
|
97
116
|
for (const style of descriptor.styles) {
|
|
98
117
|
let name = 'style';
|
|
99
|
-
if (style.scoped)
|
|
118
|
+
if (style.scoped) {
|
|
100
119
|
name += ' scoped';
|
|
101
|
-
|
|
120
|
+
}
|
|
121
|
+
if (style.module) {
|
|
102
122
|
name += ' module';
|
|
123
|
+
}
|
|
103
124
|
result.push({
|
|
104
125
|
name,
|
|
105
126
|
kind: 2,
|
|
@@ -130,29 +151,13 @@ function create() {
|
|
|
130
151
|
return result;
|
|
131
152
|
});
|
|
132
153
|
},
|
|
133
|
-
provideDocumentFormattingEdits(document, range, options) {
|
|
134
|
-
return worker(document, async (vueCode) => {
|
|
135
|
-
const formatSettings = await context.env.getConfiguration?.('html.format') ?? {};
|
|
136
|
-
const blockTypes = ['template', 'script', 'style'];
|
|
137
|
-
for (const customBlock of vueCode.sfc.customBlocks) {
|
|
138
|
-
blockTypes.push(customBlock.type);
|
|
139
|
-
}
|
|
140
|
-
return htmlLanguageService.format(document, range, {
|
|
141
|
-
...options,
|
|
142
|
-
...formatSettings,
|
|
143
|
-
unformatted: '',
|
|
144
|
-
contentUnformatted: blockTypes.join(','),
|
|
145
|
-
endWithNewline: options.insertFinalNewline ? true
|
|
146
|
-
: options.trimFinalNewlines ? false
|
|
147
|
-
: document.getText().endsWith('\n'),
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
},
|
|
151
154
|
};
|
|
152
155
|
function worker(document, callback) {
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
+
const decoded = context.decodeEmbeddedDocumentUri(document.uri);
|
|
157
|
+
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
158
|
+
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
|
|
159
|
+
if (virtualCode instanceof vue.VueGeneratedCode) {
|
|
160
|
+
return callback(virtualCode);
|
|
156
161
|
}
|
|
157
162
|
}
|
|
158
163
|
},
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { ServiceEnvironment } from '@volar/language-service';
|
|
2
|
-
import {
|
|
3
|
-
export declare function create(mode: 'html' | 'pug', ts: typeof import('typescript'), getVueOptions: (env: ServiceEnvironment) => VueCompilerOptions,
|
|
1
|
+
import type { ServiceContext, ServiceEnvironment } from '@volar/language-service';
|
|
2
|
+
import { LanguageServicePlugin, VueCompilerOptions } from '../types';
|
|
3
|
+
export declare function create(mode: 'html' | 'pug', ts: typeof import('typescript'), getVueOptions: (env: ServiceEnvironment) => VueCompilerOptions, getTsPluginClient?: (context: ServiceContext) => typeof import('@vue/typescript-plugin/lib/client') | undefined): LanguageServicePlugin;
|
|
@@ -10,9 +10,10 @@ const nameCasing_1 = require("../ideFeatures/nameCasing");
|
|
|
10
10
|
const types_1 = require("../types");
|
|
11
11
|
const data_1 = require("./data");
|
|
12
12
|
const vscode_uri_1 = require("vscode-uri");
|
|
13
|
+
const common_1 = require("@vue/typescript-plugin/lib/common");
|
|
13
14
|
let builtInData;
|
|
14
15
|
let modelData;
|
|
15
|
-
function create(mode, ts, getVueOptions,
|
|
16
|
+
function create(mode, ts, getVueOptions, getTsPluginClient) {
|
|
16
17
|
let customData = [];
|
|
17
18
|
let extraCustomData = [];
|
|
18
19
|
const onDidChangeCustomDataListeners = new Set();
|
|
@@ -41,6 +42,7 @@ function create(mode, ts, getVueOptions, tsPluginClient) {
|
|
|
41
42
|
'@', // vue event shorthand
|
|
42
43
|
],
|
|
43
44
|
create(context) {
|
|
45
|
+
const tsPluginClient = getTsPluginClient?.(context);
|
|
44
46
|
const baseServiceInstance = baseService.create(context);
|
|
45
47
|
const vueCompilerOptions = getVueOptions(context.env);
|
|
46
48
|
builtInData ??= (0, data_1.loadTemplateData)(context.env.locale ?? 'en');
|
|
@@ -82,38 +84,46 @@ function create(mode, ts, getVueOptions, tsPluginClient) {
|
|
|
82
84
|
disposable?.dispose();
|
|
83
85
|
},
|
|
84
86
|
async provideCompletionItems(document, position, completionContext, token) {
|
|
85
|
-
if (!isSupportedDocument(document))
|
|
87
|
+
if (!isSupportedDocument(document)) {
|
|
86
88
|
return;
|
|
89
|
+
}
|
|
87
90
|
let sync;
|
|
88
91
|
let currentVersion;
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
const decoded = context.decodeEmbeddedDocumentUri(document.uri);
|
|
93
|
+
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
94
|
+
if (sourceScript?.generated?.root instanceof language_core_1.VueGeneratedCode) {
|
|
95
|
+
sync = (await provideHtmlData(sourceScript.id, sourceScript.generated.root)).sync;
|
|
92
96
|
currentVersion = await sync();
|
|
93
97
|
}
|
|
94
98
|
let htmlComplete = await baseServiceInstance.provideCompletionItems?.(document, position, completionContext, token);
|
|
95
99
|
while (currentVersion !== (currentVersion = await sync?.())) {
|
|
96
100
|
htmlComplete = await baseServiceInstance.provideCompletionItems?.(document, position, completionContext, token);
|
|
97
101
|
}
|
|
98
|
-
if (!htmlComplete)
|
|
102
|
+
if (!htmlComplete) {
|
|
99
103
|
return;
|
|
100
|
-
|
|
101
|
-
|
|
104
|
+
}
|
|
105
|
+
if (sourceScript?.generated?.root instanceof language_core_1.VueGeneratedCode) {
|
|
106
|
+
await afterHtmlCompletion(htmlComplete, context.documents.get(sourceScript.id, sourceScript.languageId, sourceScript.snapshot), sourceScript.generated.root);
|
|
102
107
|
}
|
|
103
108
|
return htmlComplete;
|
|
104
109
|
},
|
|
105
110
|
async provideInlayHints(document) {
|
|
106
|
-
if (!isSupportedDocument(document))
|
|
111
|
+
if (!isSupportedDocument(document)) {
|
|
107
112
|
return;
|
|
113
|
+
}
|
|
108
114
|
const enabled = await context.env.getConfiguration?.('vue.inlayHints.missingProps') ?? false;
|
|
109
|
-
if (!enabled)
|
|
115
|
+
if (!enabled) {
|
|
110
116
|
return;
|
|
117
|
+
}
|
|
111
118
|
const result = [];
|
|
112
|
-
const
|
|
113
|
-
|
|
119
|
+
const decoded = context.decodeEmbeddedDocumentUri(document.uri);
|
|
120
|
+
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
121
|
+
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
|
|
122
|
+
if (!virtualCode) {
|
|
114
123
|
return;
|
|
124
|
+
}
|
|
115
125
|
for (const map of context.documents.getMaps(virtualCode)) {
|
|
116
|
-
const code = context.language.
|
|
126
|
+
const code = context.language.scripts.get(map.sourceDocument.uri)?.generated?.root;
|
|
117
127
|
const scanner = getScanner(baseServiceInstance, document);
|
|
118
128
|
if (code instanceof language_core_1.VueGeneratedCode && scanner) {
|
|
119
129
|
// visualize missing required props
|
|
@@ -203,23 +213,30 @@ function create(mode, ts, getVueOptions, tsPluginClient) {
|
|
|
203
213
|
return result;
|
|
204
214
|
},
|
|
205
215
|
provideHover(document, position, token) {
|
|
206
|
-
if (!isSupportedDocument(document))
|
|
216
|
+
if (!isSupportedDocument(document)) {
|
|
207
217
|
return;
|
|
208
|
-
|
|
218
|
+
}
|
|
219
|
+
if (context.decodeEmbeddedDocumentUri(document.uri)) {
|
|
209
220
|
updateExtraCustomData([]);
|
|
221
|
+
}
|
|
210
222
|
return baseServiceInstance.provideHover?.(document, position, token);
|
|
211
223
|
},
|
|
212
224
|
async provideDiagnostics(document, token) {
|
|
213
|
-
if (!isSupportedDocument(document))
|
|
225
|
+
if (!isSupportedDocument(document)) {
|
|
214
226
|
return;
|
|
227
|
+
}
|
|
215
228
|
const originalResult = await baseServiceInstance.provideDiagnostics?.(document, token);
|
|
216
|
-
const
|
|
217
|
-
|
|
229
|
+
const decoded = context.decodeEmbeddedDocumentUri(document.uri);
|
|
230
|
+
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
231
|
+
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
|
|
232
|
+
if (!virtualCode) {
|
|
218
233
|
return;
|
|
234
|
+
}
|
|
219
235
|
for (const map of context.documents.getMaps(virtualCode)) {
|
|
220
|
-
const code = context.language.
|
|
221
|
-
if (!(code instanceof language_core_1.VueGeneratedCode))
|
|
236
|
+
const code = context.language.scripts.get(map.sourceDocument.uri)?.generated?.root;
|
|
237
|
+
if (!(code instanceof language_core_1.VueGeneratedCode)) {
|
|
222
238
|
continue;
|
|
239
|
+
}
|
|
223
240
|
const templateErrors = [];
|
|
224
241
|
const { template } = code.sfc;
|
|
225
242
|
if (template) {
|
|
@@ -253,18 +270,58 @@ function create(mode, ts, getVueOptions, tsPluginClient) {
|
|
|
253
270
|
];
|
|
254
271
|
}
|
|
255
272
|
},
|
|
273
|
+
provideDocumentSemanticTokens(document, range, legend) {
|
|
274
|
+
if (!isSupportedDocument(document)) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const languageService = context.inject('typescript/languageService');
|
|
278
|
+
if (!languageService) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const decoded = context.decodeEmbeddedDocumentUri(document.uri);
|
|
282
|
+
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
283
|
+
if (!sourceScript
|
|
284
|
+
|| !(sourceScript.generated?.root instanceof language_core_1.VueGeneratedCode)
|
|
285
|
+
|| !sourceScript.generated.root.sfc.template) {
|
|
286
|
+
return [];
|
|
287
|
+
}
|
|
288
|
+
const { template } = sourceScript.generated.root.sfc;
|
|
289
|
+
const spans = common_1.getComponentSpans.call({
|
|
290
|
+
files: context.language.scripts,
|
|
291
|
+
languageService,
|
|
292
|
+
typescript: ts,
|
|
293
|
+
vueOptions: getVueOptions(context.env),
|
|
294
|
+
}, sourceScript.generated.root, template, {
|
|
295
|
+
start: document.offsetAt(range.start),
|
|
296
|
+
length: document.offsetAt(range.end) - document.offsetAt(range.start),
|
|
297
|
+
});
|
|
298
|
+
const classTokenIndex = legend.tokenTypes.indexOf('class');
|
|
299
|
+
return spans.map(span => {
|
|
300
|
+
const start = document.positionAt(span.start);
|
|
301
|
+
return [
|
|
302
|
+
start.line,
|
|
303
|
+
start.character,
|
|
304
|
+
span.length,
|
|
305
|
+
classTokenIndex,
|
|
306
|
+
0,
|
|
307
|
+
];
|
|
308
|
+
});
|
|
309
|
+
},
|
|
256
310
|
};
|
|
257
311
|
async function provideHtmlData(sourceDocumentUri, vueCode) {
|
|
258
312
|
await (initializing ??= initialize());
|
|
259
313
|
const casing = await (0, nameCasing_1.getNameCasing)(context, sourceDocumentUri, tsPluginClient);
|
|
260
314
|
if (builtInData.tags) {
|
|
261
315
|
for (const tag of builtInData.tags) {
|
|
262
|
-
if (tag.name === 'slot')
|
|
316
|
+
if (tag.name === 'slot') {
|
|
263
317
|
continue;
|
|
264
|
-
|
|
318
|
+
}
|
|
319
|
+
if (tag.name === 'component') {
|
|
265
320
|
continue;
|
|
266
|
-
|
|
321
|
+
}
|
|
322
|
+
if (tag.name === 'template') {
|
|
267
323
|
continue;
|
|
324
|
+
}
|
|
268
325
|
if (casing.tag === types_1.TagNameCasing.Kebab) {
|
|
269
326
|
tag.name = (0, language_core_1.hyphenateTag)(tag.name);
|
|
270
327
|
}
|
|
@@ -324,10 +381,8 @@ function create(mode, ts, getVueOptions, tsPluginClient) {
|
|
|
324
381
|
}
|
|
325
382
|
return tags;
|
|
326
383
|
},
|
|
327
|
-
provideAttributes:
|
|
328
|
-
|
|
329
|
-
let failed = false;
|
|
330
|
-
let tagInfo = tagInfos.get(tag);
|
|
384
|
+
provideAttributes: tag => {
|
|
385
|
+
const tagInfo = tagInfos.get(tag);
|
|
331
386
|
if (!tagInfo) {
|
|
332
387
|
promises.push((async () => {
|
|
333
388
|
const attrs = await tsPluginClient?.getElementAttrs(vueCode.fileName, tag) ?? [];
|
|
@@ -342,9 +397,6 @@ function create(mode, ts, getVueOptions, tsPluginClient) {
|
|
|
342
397
|
})());
|
|
343
398
|
return [];
|
|
344
399
|
}
|
|
345
|
-
if (failed) {
|
|
346
|
-
return [];
|
|
347
|
-
}
|
|
348
400
|
const { attrs, props, events } = tagInfo;
|
|
349
401
|
const attributes = [];
|
|
350
402
|
const _tsCodegen = language_core_1.tsCodegen.get(vueCode.sfc);
|
|
@@ -467,8 +519,9 @@ function create(mode, ts, getVueOptions, tsPluginClient) {
|
|
|
467
519
|
const textWithoutModifier = replacement.text.split('.')[0];
|
|
468
520
|
if (validModifiers && hasModifier) {
|
|
469
521
|
for (const modifier in validModifiers) {
|
|
470
|
-
if (modifiers.includes(modifier))
|
|
522
|
+
if (modifiers.includes(modifier)) {
|
|
471
523
|
continue;
|
|
524
|
+
}
|
|
472
525
|
const modifierDes = validModifiers[modifier];
|
|
473
526
|
const insertText = textWithoutModifier + modifiers.slice(0, -1).map(m => '.' + m).join('') + '.' + modifier;
|
|
474
527
|
const newItem = {
|
|
@@ -489,8 +542,9 @@ function create(mode, ts, getVueOptions, tsPluginClient) {
|
|
|
489
542
|
}
|
|
490
543
|
else if (hasModifier && isModel) {
|
|
491
544
|
for (const modifier of modelData.globalAttributes ?? []) {
|
|
492
|
-
if (modifiers.includes(modifier.name))
|
|
545
|
+
if (modifiers.includes(modifier.name)) {
|
|
493
546
|
continue;
|
|
547
|
+
}
|
|
494
548
|
const insertText = textWithoutModifier + modifiers.slice(0, -1).map(m => '.' + m).join('') + '.' + modifier.name;
|
|
495
549
|
const newItem = {
|
|
496
550
|
label: modifier.name,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function create(ts: typeof import('typescript')):
|
|
1
|
+
import type { LanguageServicePlugin } from '@volar/language-service';
|
|
2
|
+
export declare function create(ts: typeof import('typescript')): LanguageServicePlugin;
|
|
@@ -10,16 +10,19 @@ function create(ts) {
|
|
|
10
10
|
provideCodeActions(document, range, _context) {
|
|
11
11
|
const startOffset = document.offsetAt(range.start);
|
|
12
12
|
const endOffset = document.offsetAt(range.end);
|
|
13
|
-
const
|
|
13
|
+
const decoded = context.decodeEmbeddedDocumentUri(document.uri);
|
|
14
|
+
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
15
|
+
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
|
|
14
16
|
if (!(virtualCode instanceof language_core_1.VueGeneratedCode)) {
|
|
15
17
|
return;
|
|
16
18
|
}
|
|
17
19
|
const { template } = virtualCode.sfc;
|
|
18
|
-
if (!template?.ast)
|
|
20
|
+
if (!template?.ast) {
|
|
19
21
|
return;
|
|
22
|
+
}
|
|
20
23
|
const templateStartOffset = template.startTagEnd;
|
|
21
24
|
const result = [];
|
|
22
|
-
for (const node of (0, language_core_1.
|
|
25
|
+
for (const node of (0, language_core_1.forEachElementNode)(template.ast)) {
|
|
23
26
|
if (startOffset > templateStartOffset + node.loc.end.offset || endOffset < templateStartOffset + node.loc.start.offset) {
|
|
24
27
|
return;
|
|
25
28
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function create(ts: typeof import('typescript'),
|
|
1
|
+
import type { ServiceContext, LanguageServicePlugin } from '@volar/language-service';
|
|
2
|
+
export declare function create(ts: typeof import('typescript'), getTsPluginClient?: (context: ServiceContext) => typeof import('@vue/typescript-plugin/lib/client') | undefined): LanguageServicePlugin;
|