@vue/language-service 2.2.10 → 3.0.0-alpha.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/index.d.ts +7 -6
- package/index.js +31 -20
- package/lib/plugins/css.js +54 -42
- package/lib/plugins/vue-autoinsert-dotvalue.d.ts +1 -1
- package/lib/plugins/vue-compiler-dom-errors.d.ts +1 -1
- package/lib/plugins/vue-document-drop.d.ts +2 -2
- package/lib/plugins/vue-document-links.js +63 -31
- package/lib/plugins/vue-extract-file.d.ts +2 -2
- package/lib/plugins/vue-file-references.d.ts +2 -0
- package/lib/plugins/vue-file-references.js +64 -0
- package/lib/plugins/vue-missing-props-hints.d.ts +1 -1
- package/lib/plugins/vue-missing-props-hints.js +1 -2
- package/lib/plugins/vue-sfc.js +3 -1
- package/lib/plugins/vue-template-refs.d.ts +2 -0
- package/lib/plugins/vue-template-refs.js +44 -0
- package/lib/plugins/vue-template.d.ts +2 -2
- package/lib/plugins/vue-template.js +22 -245
- package/lib/plugins/vue-twoslash-queries.d.ts +1 -1
- package/lib/plugins/vue-twoslash-queries.js +1 -1
- package/package.json +17 -17
- package/lib/ideFeatures/nameCasing.d.ts +0 -14
- package/lib/ideFeatures/nameCasing.js +0 -202
package/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export * from '@volar/language-service';
|
|
2
2
|
export * from '@vue/language-core';
|
|
3
|
-
export * from './lib/
|
|
3
|
+
export * from './lib/nameCasing';
|
|
4
4
|
export * from './lib/types';
|
|
5
5
|
import type { LanguageServicePlugin } from '@volar/language-service';
|
|
6
|
-
import { VueCompilerOptions } from '@vue/language-core';
|
|
6
|
+
import { type VueCompilerOptions } from '@vue/language-core';
|
|
7
7
|
declare module '@volar/language-service' {
|
|
8
8
|
interface ProjectContext {
|
|
9
9
|
vue?: {
|
|
@@ -11,7 +11,8 @@ declare module '@volar/language-service' {
|
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
-
export declare function getFullLanguageServicePlugins(ts: typeof import('typescript')
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
export declare function getFullLanguageServicePlugins(ts: typeof import('typescript')): LanguageServicePlugin<any>[];
|
|
15
|
+
import type * as ts from 'typescript';
|
|
16
|
+
export declare function getHybridModeLanguageServicePlugins(ts: typeof import('typescript'), tsPluginClient: (import('@vue/typescript-plugin/lib/requests').Requests & {
|
|
17
|
+
getDocumentHighlights: (fileName: string, position: number) => Promise<ts.DocumentHighlights[] | null>;
|
|
18
|
+
}) | undefined): LanguageServicePlugin<any>[];
|
package/index.js
CHANGED
|
@@ -19,7 +19,7 @@ exports.getFullLanguageServicePlugins = getFullLanguageServicePlugins;
|
|
|
19
19
|
exports.getHybridModeLanguageServicePlugins = getHybridModeLanguageServicePlugins;
|
|
20
20
|
__exportStar(require("@volar/language-service"), exports);
|
|
21
21
|
__exportStar(require("@vue/language-core"), exports);
|
|
22
|
-
__exportStar(require("./lib/
|
|
22
|
+
__exportStar(require("./lib/nameCasing"), exports);
|
|
23
23
|
__exportStar(require("./lib/types"), exports);
|
|
24
24
|
const types_1 = require("./lib/types");
|
|
25
25
|
const volar_service_emmet_1 = require("volar-service-emmet");
|
|
@@ -32,12 +32,15 @@ const syntactic_1 = require("volar-service-typescript/lib/plugins/syntactic");
|
|
|
32
32
|
const css_1 = require("./lib/plugins/css");
|
|
33
33
|
const vue_autoinsert_dotvalue_1 = require("./lib/plugins/vue-autoinsert-dotvalue");
|
|
34
34
|
const vue_autoinsert_space_1 = require("./lib/plugins/vue-autoinsert-space");
|
|
35
|
+
const vue_compiler_dom_errors_1 = require("./lib/plugins/vue-compiler-dom-errors");
|
|
35
36
|
const vue_complete_define_assignment_1 = require("./lib/plugins/vue-complete-define-assignment");
|
|
36
37
|
const vue_directive_comments_1 = require("./lib/plugins/vue-directive-comments");
|
|
37
38
|
const vue_document_drop_1 = require("./lib/plugins/vue-document-drop");
|
|
39
|
+
const vue_document_highlights_1 = require("./lib/plugins/vue-document-highlights");
|
|
38
40
|
const vue_document_links_1 = require("./lib/plugins/vue-document-links");
|
|
39
41
|
const vue_extract_file_1 = require("./lib/plugins/vue-extract-file");
|
|
40
42
|
const vue_inlayhints_1 = require("./lib/plugins/vue-inlayhints");
|
|
43
|
+
const vue_missing_props_hints_1 = require("./lib/plugins/vue-missing-props-hints");
|
|
41
44
|
const vue_sfc_1 = require("./lib/plugins/vue-sfc");
|
|
42
45
|
const vue_template_1 = require("./lib/plugins/vue-template");
|
|
43
46
|
const vue_twoslash_queries_1 = require("./lib/plugins/vue-twoslash-queries");
|
|
@@ -49,14 +52,15 @@ const getComponentEvents_1 = require("@vue/typescript-plugin/lib/requests/getCom
|
|
|
49
52
|
const getComponentNames_1 = require("@vue/typescript-plugin/lib/requests/getComponentNames");
|
|
50
53
|
const getComponentProps_1 = require("@vue/typescript-plugin/lib/requests/getComponentProps");
|
|
51
54
|
const getElementAttrs_1 = require("@vue/typescript-plugin/lib/requests/getElementAttrs");
|
|
55
|
+
const getElementNames_1 = require("@vue/typescript-plugin/lib/requests/getElementNames");
|
|
52
56
|
const getImportPathForFile_1 = require("@vue/typescript-plugin/lib/requests/getImportPathForFile");
|
|
53
57
|
const getPropertiesAtLocation_1 = require("@vue/typescript-plugin/lib/requests/getPropertiesAtLocation");
|
|
54
58
|
const vscode_uri_1 = require("vscode-uri");
|
|
55
|
-
const nameCasing_1 = require("./lib/
|
|
56
|
-
function getFullLanguageServicePlugins(ts
|
|
59
|
+
const nameCasing_1 = require("./lib/nameCasing");
|
|
60
|
+
function getFullLanguageServicePlugins(ts) {
|
|
57
61
|
const plugins = [
|
|
58
|
-
...(0, volar_service_typescript_1.create)(ts
|
|
59
|
-
...getCommonLanguageServicePlugins(ts, getTsPluginClientForLSP)
|
|
62
|
+
...(0, volar_service_typescript_1.create)(ts),
|
|
63
|
+
...getCommonLanguageServicePlugins(ts, getTsPluginClientForLSP),
|
|
60
64
|
];
|
|
61
65
|
for (let i = 0; i < plugins.length; i++) {
|
|
62
66
|
const plugin = plugins[i];
|
|
@@ -102,28 +106,31 @@ function getFullLanguageServicePlugins(ts, { disableAutoImportCache } = {}) {
|
|
|
102
106
|
};
|
|
103
107
|
return {
|
|
104
108
|
async collectExtractProps(...args) {
|
|
105
|
-
return
|
|
109
|
+
return collectExtractProps_1.collectExtractProps.apply(requestContext, args);
|
|
106
110
|
},
|
|
107
111
|
async getPropertiesAtLocation(...args) {
|
|
108
|
-
return
|
|
112
|
+
return getPropertiesAtLocation_1.getPropertiesAtLocation.apply(requestContext, args);
|
|
109
113
|
},
|
|
110
114
|
async getImportPathForFile(...args) {
|
|
111
|
-
return
|
|
115
|
+
return getImportPathForFile_1.getImportPathForFile.apply(requestContext, args);
|
|
112
116
|
},
|
|
113
117
|
async getComponentEvents(...args) {
|
|
114
|
-
return
|
|
118
|
+
return getComponentEvents_1.getComponentEvents.apply(requestContext, args);
|
|
115
119
|
},
|
|
116
120
|
async getComponentDirectives(...args) {
|
|
117
|
-
return
|
|
121
|
+
return getComponentDirectives_1.getComponentDirectives.apply(requestContext, args);
|
|
118
122
|
},
|
|
119
123
|
async getComponentNames(...args) {
|
|
120
|
-
return
|
|
124
|
+
return getComponentNames_1.getComponentNames.apply(requestContext, args);
|
|
121
125
|
},
|
|
122
126
|
async getComponentProps(...args) {
|
|
123
|
-
return
|
|
127
|
+
return getComponentProps_1.getComponentProps.apply(requestContext, args);
|
|
124
128
|
},
|
|
125
129
|
async getElementAttrs(...args) {
|
|
126
|
-
return
|
|
130
|
+
return getElementAttrs_1.getElementAttrs.apply(requestContext, args);
|
|
131
|
+
},
|
|
132
|
+
async getElementNames(...args) {
|
|
133
|
+
return getElementNames_1.getElementNames.apply(requestContext, args);
|
|
127
134
|
},
|
|
128
135
|
async getQuickInfoAtPosition(fileName, position) {
|
|
129
136
|
const languageService = context.getLanguageService();
|
|
@@ -132,8 +139,7 @@ function getFullLanguageServicePlugins(ts, { disableAutoImportCache } = {}) {
|
|
|
132
139
|
if (!sourceScript) {
|
|
133
140
|
return;
|
|
134
141
|
}
|
|
135
|
-
const
|
|
136
|
-
const hover = await languageService.getHover(uri, document.positionAt(position));
|
|
142
|
+
const hover = await languageService.getHover(uri, position);
|
|
137
143
|
let text = '';
|
|
138
144
|
if (typeof hover?.contents === 'string') {
|
|
139
145
|
text = hover.contents;
|
|
@@ -161,12 +167,15 @@ function getFullLanguageServicePlugins(ts, { disableAutoImportCache } = {}) {
|
|
|
161
167
|
};
|
|
162
168
|
}
|
|
163
169
|
}
|
|
164
|
-
function getHybridModeLanguageServicePlugins(ts,
|
|
170
|
+
function getHybridModeLanguageServicePlugins(ts, tsPluginClient) {
|
|
165
171
|
const plugins = [
|
|
166
172
|
(0, syntactic_1.create)(ts),
|
|
167
173
|
(0, docCommentTemplate_1.create)(ts),
|
|
168
|
-
...getCommonLanguageServicePlugins(ts, () =>
|
|
174
|
+
...getCommonLanguageServicePlugins(ts, () => tsPluginClient)
|
|
169
175
|
];
|
|
176
|
+
if (tsPluginClient) {
|
|
177
|
+
plugins.push((0, vue_document_highlights_1.create)(tsPluginClient.getDocumentHighlights));
|
|
178
|
+
}
|
|
170
179
|
for (const plugin of plugins) {
|
|
171
180
|
// avoid affecting TS plugin
|
|
172
181
|
delete plugin.capabilities.semanticTokensProvider;
|
|
@@ -179,12 +188,14 @@ function getCommonLanguageServicePlugins(ts, getTsPluginClient) {
|
|
|
179
188
|
(0, css_1.create)(),
|
|
180
189
|
(0, volar_service_pug_beautify_1.create)(),
|
|
181
190
|
(0, volar_service_json_1.create)(),
|
|
182
|
-
(0, vue_template_1.create)('html',
|
|
183
|
-
(0, vue_template_1.create)('pug',
|
|
191
|
+
(0, vue_template_1.create)('html', getTsPluginClient),
|
|
192
|
+
(0, vue_template_1.create)('pug', getTsPluginClient),
|
|
193
|
+
(0, vue_missing_props_hints_1.create)(getTsPluginClient),
|
|
194
|
+
(0, vue_compiler_dom_errors_1.create)(),
|
|
184
195
|
(0, vue_sfc_1.create)(),
|
|
185
196
|
(0, vue_twoslash_queries_1.create)(getTsPluginClient),
|
|
186
|
-
(0, vue_document_links_1.create)(),
|
|
187
197
|
(0, vue_document_drop_1.create)(ts, getTsPluginClient),
|
|
198
|
+
(0, vue_document_links_1.create)(),
|
|
188
199
|
(0, vue_complete_define_assignment_1.create)(),
|
|
189
200
|
(0, vue_autoinsert_dotvalue_1.create)(ts, getTsPluginClient),
|
|
190
201
|
(0, vue_autoinsert_space_1.create)(),
|
package/lib/plugins/css.js
CHANGED
|
@@ -23,55 +23,67 @@ function create() {
|
|
|
23
23
|
return diagnostics;
|
|
24
24
|
},
|
|
25
25
|
/**
|
|
26
|
-
* If the
|
|
27
|
-
* skip the CSS
|
|
26
|
+
* If the position is within the virtual code and navigation is enabled,
|
|
27
|
+
* skip the CSS navigation feature.
|
|
28
28
|
*/
|
|
29
|
+
provideReferences(document, position) {
|
|
30
|
+
if (isWithinNavigationVirtualCode(document, position)) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
return worker(document, (stylesheet, cssLs) => {
|
|
34
|
+
return cssLs.findReferences(document, position, stylesheet);
|
|
35
|
+
});
|
|
36
|
+
},
|
|
29
37
|
provideRenameRange(document, position) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
34
|
-
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
|
|
35
|
-
if (!sourceScript?.generated || !virtualCode?.id.startsWith('style_')) {
|
|
36
|
-
break;
|
|
37
|
-
}
|
|
38
|
-
const root = sourceScript.generated.root;
|
|
39
|
-
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
|
-
const block = root.sfc.styles.find(style => style.name === decoded[1]);
|
|
43
|
-
if (!block) {
|
|
44
|
-
break;
|
|
45
|
-
}
|
|
46
|
-
let script;
|
|
47
|
-
for (const [key, value] of sourceScript.generated.embeddedCodes) {
|
|
48
|
-
if (key.startsWith('script_')) {
|
|
49
|
-
script = value;
|
|
50
|
-
break;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (!script) {
|
|
54
|
-
break;
|
|
55
|
-
}
|
|
56
|
-
const offset = document.offsetAt(position) + block.startTagEnd;
|
|
57
|
-
for (const { sourceOffsets, lengths, data } of script.mappings) {
|
|
58
|
-
if (!sourceOffsets.length
|
|
59
|
-
|| !data.navigation
|
|
60
|
-
|| typeof data.navigation === 'object' && !data.navigation.shouldRename) {
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
const start = sourceOffsets[0];
|
|
64
|
-
const end = sourceOffsets.at(-1) + lengths.at(-1);
|
|
65
|
-
if (offset >= start && offset <= end) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
} while (0);
|
|
38
|
+
if (isWithinNavigationVirtualCode(document, position)) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
70
41
|
return worker(document, (stylesheet, cssLs) => {
|
|
71
42
|
return cssLs.prepareRename(document, position, stylesheet);
|
|
72
43
|
});
|
|
73
44
|
}
|
|
74
45
|
};
|
|
46
|
+
function isWithinNavigationVirtualCode(document, position) {
|
|
47
|
+
const uri = vscode_uri_1.URI.parse(document.uri);
|
|
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 || !virtualCode?.id.startsWith('style_')) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const root = sourceScript.generated.root;
|
|
55
|
+
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const block = root.sfc.styles.find(style => style.name === decoded[1]);
|
|
59
|
+
if (!block) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
let script;
|
|
63
|
+
for (const [key, value] of sourceScript.generated.embeddedCodes) {
|
|
64
|
+
if (key.startsWith('script_')) {
|
|
65
|
+
script = value;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (!script) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const offset = document.offsetAt(position) + block.startTagEnd;
|
|
73
|
+
for (const { sourceOffsets, lengths, data } of script.mappings) {
|
|
74
|
+
if (!sourceOffsets.length
|
|
75
|
+
|| !data.navigation
|
|
76
|
+
|| typeof data.navigation === 'object' && !data.navigation.shouldRename) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const start = sourceOffsets[0];
|
|
80
|
+
const end = sourceOffsets.at(-1) + lengths.at(-1);
|
|
81
|
+
if (offset >= start && offset <= end) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
75
87
|
function worker(document, callback) {
|
|
76
88
|
const cssLs = getCssLs(document);
|
|
77
89
|
if (!cssLs) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { LanguageServiceContext, LanguageServicePlugin } from '@volar/language-service';
|
|
2
|
-
export declare function create(ts: typeof import('typescript'), getTsPluginClient?: (context: LanguageServiceContext) =>
|
|
2
|
+
export declare function create(ts: typeof import('typescript'), getTsPluginClient?: (context: LanguageServiceContext) => import('@vue/typescript-plugin/lib/requests').Requests | undefined): LanguageServicePlugin;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { LanguageServicePlugin } from '../types';
|
|
1
|
+
import type { LanguageServicePlugin } from '../types';
|
|
2
2
|
export declare function create(): LanguageServicePlugin;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { LanguageServiceContext, LanguageServicePlugin } from '../types';
|
|
2
|
-
export declare function create(ts: typeof import('typescript'), getTsPluginClient?: (context: LanguageServiceContext) =>
|
|
1
|
+
import { type LanguageServiceContext, type LanguageServicePlugin } from '../types';
|
|
2
|
+
export declare function create(ts: typeof import('typescript'), getTsPluginClient?: (context: LanguageServiceContext) => import('@vue/typescript-plugin/lib/requests').Requests | undefined): LanguageServicePlugin;
|
|
@@ -16,52 +16,84 @@ function create() {
|
|
|
16
16
|
const decoded = context.decodeEmbeddedDocumentUri(uri);
|
|
17
17
|
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
18
18
|
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
|
|
19
|
-
if (!sourceScript?.generated || virtualCode?.id !== 'template') {
|
|
19
|
+
if (!sourceScript?.generated || (virtualCode?.id !== 'template' && virtualCode?.id !== "scriptsetup_raw")) {
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
const root = sourceScript.generated.root;
|
|
23
23
|
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
|
-
const result = [];
|
|
27
26
|
const { sfc } = root;
|
|
28
27
|
const codegen = language_core_1.tsCodegen.get(sfc);
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
28
|
+
const result = [];
|
|
29
|
+
if (virtualCode.id === 'template') {
|
|
30
|
+
const scopedClasses = codegen?.getGeneratedTemplate()?.scopedClasses ?? [];
|
|
31
|
+
const styleClasses = new Map();
|
|
32
|
+
const option = root.vueCompilerOptions.experimentalResolveStyleCssClasses;
|
|
33
|
+
for (let i = 0; i < sfc.styles.length; i++) {
|
|
34
|
+
const style = sfc.styles[i];
|
|
35
|
+
if (option === 'always' || (option === 'scoped' && style.scoped)) {
|
|
36
|
+
for (const className of style.classNames) {
|
|
37
|
+
if (!styleClasses.has(className.text.slice(1))) {
|
|
38
|
+
styleClasses.set(className.text.slice(1), []);
|
|
39
|
+
}
|
|
40
|
+
styleClasses.get(className.text.slice(1)).push({
|
|
41
|
+
index: i,
|
|
42
|
+
style,
|
|
43
|
+
classOffset: className.offset,
|
|
44
|
+
});
|
|
38
45
|
}
|
|
39
|
-
styleClasses.get(className.text.slice(1)).push({
|
|
40
|
-
index: i,
|
|
41
|
-
style,
|
|
42
|
-
classOffset: className.offset,
|
|
43
|
-
});
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
for (const { className, offset } of scopedClasses) {
|
|
49
|
+
const styles = styleClasses.get(className);
|
|
50
|
+
if (styles) {
|
|
51
|
+
for (const style of styles) {
|
|
52
|
+
const styleDocumentUri = context.encodeEmbeddedDocumentUri(decoded[0], 'style_' + style.index);
|
|
53
|
+
const styleVirtualCode = sourceScript.generated.embeddedCodes.get('style_' + style.index);
|
|
54
|
+
if (!styleVirtualCode) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const styleDocument = context.documents.get(styleDocumentUri, styleVirtualCode.languageId, styleVirtualCode.snapshot);
|
|
58
|
+
const start = styleDocument.positionAt(style.classOffset);
|
|
59
|
+
const end = styleDocument.positionAt(style.classOffset + className.length + 1);
|
|
60
|
+
result.push({
|
|
61
|
+
range: {
|
|
62
|
+
start: document.positionAt(offset),
|
|
63
|
+
end: document.positionAt(offset + className.length),
|
|
64
|
+
},
|
|
65
|
+
target: context.encodeEmbeddedDocumentUri(decoded[0], 'style_' + style.index) + `#L${start.line + 1},${start.character + 1}-L${end.line + 1},${end.character + 1}`,
|
|
66
|
+
});
|
|
55
67
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (virtualCode.id === 'scriptsetup_raw') {
|
|
72
|
+
if (!sfc.scriptSetup) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const templateVirtualCode = sourceScript.generated.embeddedCodes.get('template');
|
|
76
|
+
if (!templateVirtualCode) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const templateDocumentUri = context.encodeEmbeddedDocumentUri(decoded[0], 'template');
|
|
80
|
+
const templateDocument = context.documents.get(templateDocumentUri, templateVirtualCode.languageId, templateVirtualCode.snapshot);
|
|
81
|
+
const templateRefs = codegen?.getGeneratedTemplate()?.templateRefs;
|
|
82
|
+
const useTemplateRefs = codegen?.getScriptSetupRanges()?.useTemplateRef ?? [];
|
|
83
|
+
for (const { arg } of useTemplateRefs) {
|
|
84
|
+
if (!arg) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const name = sfc.scriptSetup.content.slice(arg.start + 1, arg.end - 1);
|
|
88
|
+
for (const { offset } of templateRefs?.get(name) ?? []) {
|
|
89
|
+
const start = templateDocument.positionAt(offset);
|
|
90
|
+
const end = templateDocument.positionAt(offset + name.length);
|
|
59
91
|
result.push({
|
|
60
92
|
range: {
|
|
61
|
-
start: document.positionAt(
|
|
62
|
-
end: document.positionAt(
|
|
93
|
+
start: document.positionAt(arg.start + 1),
|
|
94
|
+
end: document.positionAt(arg.end - 1),
|
|
63
95
|
},
|
|
64
|
-
target:
|
|
96
|
+
target: templateDocumentUri + `#L${start.line + 1},${start.character + 1}-L${end.line + 1},${end.character + 1}`,
|
|
65
97
|
});
|
|
66
98
|
}
|
|
67
99
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { LanguageServiceContext, LanguageServicePlugin } from '@volar/language-service';
|
|
2
|
-
import { Sfc } from '@vue/language-core';
|
|
2
|
+
import { type Sfc } from '@vue/language-core';
|
|
3
3
|
import type * as ts from 'typescript';
|
|
4
|
-
export declare function create(ts: typeof import('typescript'), getTsPluginClient?: (context: LanguageServiceContext) =>
|
|
4
|
+
export declare function create(ts: typeof import('typescript'), getTsPluginClient?: (context: LanguageServiceContext) => import('@vue/typescript-plugin/lib/requests').Requests | undefined): LanguageServicePlugin;
|
|
5
5
|
export declare function getLastImportNode(ts: typeof import('typescript'), sourceFile: ts.SourceFile): ts.Node | undefined;
|
|
6
6
|
export declare function createAddComponentToOptionEdit(ts: typeof import('typescript'), sfc: Sfc, ast: ts.SourceFile, componentName: string): {
|
|
7
7
|
range: import("@vue/language-core").TextRange;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.create = create;
|
|
4
|
+
const language_core_1 = require("@vue/language-core");
|
|
5
|
+
const vscode_uri_1 = require("vscode-uri");
|
|
6
|
+
function create(getTsPluginClient) {
|
|
7
|
+
return {
|
|
8
|
+
name: 'vue-file-references',
|
|
9
|
+
capabilities: {
|
|
10
|
+
codeLensProvider: {
|
|
11
|
+
resolveProvider: true,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
create(context) {
|
|
15
|
+
const tsPluginClient = getTsPluginClient?.(context);
|
|
16
|
+
void tsPluginClient;
|
|
17
|
+
return {
|
|
18
|
+
provideReferencesCodeLensRanges(document) {
|
|
19
|
+
return worker(document, context, root => {
|
|
20
|
+
if (root.sfc.template) {
|
|
21
|
+
return [{
|
|
22
|
+
start: document.positionAt(root.sfc.template.start + 1),
|
|
23
|
+
end: document.positionAt(root.sfc.template.start + 1 + 'template'.length),
|
|
24
|
+
}];
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
provideReferences(document, position) {
|
|
29
|
+
return worker(document, context, async (root) => {
|
|
30
|
+
if (!root.sfc.template) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const offset = document.offsetAt(position);
|
|
34
|
+
const start = root.sfc.template.start + 1;
|
|
35
|
+
const end = start + 'template'.length;
|
|
36
|
+
if (offset < start || offset > end) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
console.time('[VVVIP] getFileReferences');
|
|
40
|
+
const references = await tsPluginClient?.getFileReferences(root.fileName) ?? [];
|
|
41
|
+
console.timeEnd('[VVVIP] getFileReferences');
|
|
42
|
+
return references.map(({ fileName, range }) => ({
|
|
43
|
+
uri: vscode_uri_1.URI.file(fileName).toString(),
|
|
44
|
+
range,
|
|
45
|
+
}));
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
function worker(document, context, callback) {
|
|
52
|
+
if (document.languageId !== 'vue-root-tags') {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const uri = vscode_uri_1.URI.parse(document.uri);
|
|
56
|
+
const decoded = context.decodeEmbeddedDocumentUri(uri);
|
|
57
|
+
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
58
|
+
const root = sourceScript?.generated?.root;
|
|
59
|
+
if (root instanceof language_core_1.VueVirtualCode) {
|
|
60
|
+
return callback(root);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=vue-file-references.js.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { LanguageServiceContext } from '@volar/language-service';
|
|
2
|
-
import { LanguageServicePlugin } from '../types';
|
|
2
|
+
import { type LanguageServicePlugin } from '../types';
|
|
3
3
|
export declare function create(getTsPluginClient?: (context: LanguageServiceContext) => import('@vue/typescript-plugin/lib/requests').Requests | undefined): LanguageServicePlugin;
|
|
@@ -23,7 +23,6 @@ function create(getTsPluginClient) {
|
|
|
23
23
|
if (!context.project.vue) {
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
|
-
const vueCompilerOptions = context.project.vue.compilerOptions;
|
|
27
26
|
const enabled = await context.env.getConfiguration?.('vue.inlayHints.missingProps') ?? false;
|
|
28
27
|
if (!enabled) {
|
|
29
28
|
return;
|
|
@@ -101,7 +100,7 @@ function create(getTsPluginClient) {
|
|
|
101
100
|
attrText = attrText.slice('v-model:'.length);
|
|
102
101
|
}
|
|
103
102
|
else if (attrText === 'v-model') {
|
|
104
|
-
attrText =
|
|
103
|
+
attrText = 'modelValue'; // TODO: support for experimentalModelPropName?
|
|
105
104
|
}
|
|
106
105
|
else if (attrText.startsWith('v-on:')) {
|
|
107
106
|
attrText = 'on-' + (0, language_core_1.hyphenateAttr)(attrText.slice('v-on:'.length));
|
package/lib/plugins/vue-sfc.js
CHANGED
|
@@ -193,7 +193,9 @@ function create() {
|
|
|
193
193
|
if (!result) {
|
|
194
194
|
return;
|
|
195
195
|
}
|
|
196
|
-
result.items = result.items.filter(item => item.label !== '!DOCTYPE' &&
|
|
196
|
+
result.items = result.items.filter(item => item.label !== '!DOCTYPE' &&
|
|
197
|
+
item.label !== 'Custom Blocks' &&
|
|
198
|
+
item.label !== 'data-');
|
|
197
199
|
const tags = sfcDataProvider?.provideTags();
|
|
198
200
|
const scriptLangs = getLangs('script');
|
|
199
201
|
const scriptItems = result.items.filter(item => item.label === 'script' || item.label === 'script setup');
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.create = create;
|
|
4
|
+
const language_core_1 = require("@vue/language-core");
|
|
5
|
+
const vscode_uri_1 = require("vscode-uri");
|
|
6
|
+
const utils_1 = require("./utils");
|
|
7
|
+
function create() {
|
|
8
|
+
return {
|
|
9
|
+
name: 'vue-document-drop',
|
|
10
|
+
capabilities: {
|
|
11
|
+
completionProvider: {},
|
|
12
|
+
},
|
|
13
|
+
create(context) {
|
|
14
|
+
return {
|
|
15
|
+
provideCompletionItems(document) {
|
|
16
|
+
if (!(0, utils_1.isTsDocument)(document)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const uri = vscode_uri_1.URI.parse(document.uri);
|
|
20
|
+
const decoded = context.decodeEmbeddedDocumentUri(uri);
|
|
21
|
+
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
22
|
+
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
|
|
23
|
+
if (!sourceScript?.generated || !virtualCode) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const root = sourceScript.generated.root;
|
|
27
|
+
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const { sfc } = root;
|
|
31
|
+
const codegen = language_core_1.tsCodegen.get(sfc);
|
|
32
|
+
const scriptSetupRanges = codegen.getScriptSetupRanges();
|
|
33
|
+
for (const {} of scriptSetupRanges?.useTemplateRef ?? []) {
|
|
34
|
+
return {
|
|
35
|
+
isIncomplete: false,
|
|
36
|
+
items: [],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=vue-template-refs.js.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { LanguageServiceContext } from '@volar/language-service';
|
|
2
|
-
import { LanguageServicePlugin } from '../types';
|
|
3
|
-
export declare function create(mode: 'html' | 'pug',
|
|
2
|
+
import { type LanguageServicePlugin } from '../types';
|
|
3
|
+
export declare function create(mode: 'html' | 'pug', getTsPluginClient?: (context: LanguageServiceContext) => import('@vue/typescript-plugin/lib/requests').Requests | undefined): LanguageServicePlugin;
|
|
@@ -3,12 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.create = create;
|
|
4
4
|
const language_core_1 = require("@vue/language-core");
|
|
5
5
|
const shared_1 = require("@vue/shared");
|
|
6
|
-
const common_1 = require("@vue/typescript-plugin/lib/common");
|
|
7
6
|
const volar_service_html_1 = require("volar-service-html");
|
|
8
7
|
const volar_service_pug_1 = require("volar-service-pug");
|
|
9
8
|
const html = require("vscode-html-languageservice");
|
|
10
9
|
const vscode_uri_1 = require("vscode-uri");
|
|
11
|
-
const nameCasing_1 = require("../
|
|
10
|
+
const nameCasing_1 = require("../nameCasing");
|
|
12
11
|
const types_1 = require("../types");
|
|
13
12
|
const data_1 = require("./data");
|
|
14
13
|
const specialTags = new Set([
|
|
@@ -26,7 +25,7 @@ const specialProps = new Set([
|
|
|
26
25
|
]);
|
|
27
26
|
let builtInData;
|
|
28
27
|
let modelData;
|
|
29
|
-
function create(mode,
|
|
28
|
+
function create(mode, getTsPluginClient) {
|
|
30
29
|
let customData = [];
|
|
31
30
|
let extraCustomData = [];
|
|
32
31
|
let lastCompletionComponentNames = new Set();
|
|
@@ -70,18 +69,7 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
70
69
|
'@', // vue event shorthand
|
|
71
70
|
],
|
|
72
71
|
},
|
|
73
|
-
inlayHintProvider: {},
|
|
74
72
|
hoverProvider: true,
|
|
75
|
-
diagnosticProvider: {
|
|
76
|
-
interFileDependencies: false,
|
|
77
|
-
workspaceDiagnostics: false,
|
|
78
|
-
},
|
|
79
|
-
semanticTokensProvider: {
|
|
80
|
-
legend: {
|
|
81
|
-
tokenTypes: ['class'],
|
|
82
|
-
tokenModifiers: [],
|
|
83
|
-
},
|
|
84
|
-
}
|
|
85
73
|
},
|
|
86
74
|
create(context) {
|
|
87
75
|
const tsPluginClient = getTsPluginClient?.(context);
|
|
@@ -159,122 +147,6 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
159
147
|
}
|
|
160
148
|
return htmlComplete;
|
|
161
149
|
},
|
|
162
|
-
async provideInlayHints(document) {
|
|
163
|
-
if (!isSupportedDocument(document)) {
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
if (!context.project.vue) {
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
const vueCompilerOptions = context.project.vue.compilerOptions;
|
|
170
|
-
const enabled = await context.env.getConfiguration?.('vue.inlayHints.missingProps') ?? false;
|
|
171
|
-
if (!enabled) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
const uri = vscode_uri_1.URI.parse(document.uri);
|
|
175
|
-
const decoded = context.decodeEmbeddedDocumentUri(uri);
|
|
176
|
-
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
177
|
-
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
|
|
178
|
-
if (!virtualCode) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
const root = sourceScript?.generated?.root;
|
|
182
|
-
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
const scanner = getScanner(baseServiceInstance, document);
|
|
186
|
-
if (!scanner) {
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
const result = [];
|
|
190
|
-
// visualize missing required props
|
|
191
|
-
const casing = await (0, nameCasing_1.getNameCasing)(context, decoded[0]);
|
|
192
|
-
const components = await tsPluginClient?.getComponentNames(root.fileName) ?? [];
|
|
193
|
-
const componentProps = {};
|
|
194
|
-
let token;
|
|
195
|
-
let current;
|
|
196
|
-
while ((token = scanner.scan()) !== html.TokenType.EOS) {
|
|
197
|
-
if (token === html.TokenType.StartTag) {
|
|
198
|
-
const tagName = scanner.getTokenText();
|
|
199
|
-
const checkTag = tagName.includes('.')
|
|
200
|
-
? tagName
|
|
201
|
-
: components.find(component => component === tagName || (0, language_core_1.hyphenateTag)(component) === tagName);
|
|
202
|
-
if (checkTag) {
|
|
203
|
-
componentProps[checkTag] ??= (await tsPluginClient?.getComponentProps(root.fileName, checkTag) ?? [])
|
|
204
|
-
.filter(prop => prop.required)
|
|
205
|
-
.map(prop => prop.name);
|
|
206
|
-
current = {
|
|
207
|
-
unburnedRequiredProps: [...componentProps[checkTag]],
|
|
208
|
-
labelOffset: scanner.getTokenOffset() + scanner.getTokenLength(),
|
|
209
|
-
insertOffset: scanner.getTokenOffset() + scanner.getTokenLength(),
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
else if (token === html.TokenType.AttributeName) {
|
|
214
|
-
if (current) {
|
|
215
|
-
let attrText = scanner.getTokenText();
|
|
216
|
-
if (attrText === 'v-bind') {
|
|
217
|
-
current.unburnedRequiredProps = [];
|
|
218
|
-
}
|
|
219
|
-
else {
|
|
220
|
-
// remove modifiers
|
|
221
|
-
if (attrText.includes('.')) {
|
|
222
|
-
attrText = attrText.split('.')[0];
|
|
223
|
-
}
|
|
224
|
-
// normalize
|
|
225
|
-
if (attrText.startsWith('v-bind:')) {
|
|
226
|
-
attrText = attrText.slice('v-bind:'.length);
|
|
227
|
-
}
|
|
228
|
-
else if (attrText.startsWith(':')) {
|
|
229
|
-
attrText = attrText.slice(':'.length);
|
|
230
|
-
}
|
|
231
|
-
else if (attrText.startsWith('v-model:')) {
|
|
232
|
-
attrText = attrText.slice('v-model:'.length);
|
|
233
|
-
}
|
|
234
|
-
else if (attrText === 'v-model') {
|
|
235
|
-
attrText = vueCompilerOptions.target >= 3 ? 'modelValue' : 'value'; // TODO: support for experimentalModelPropName?
|
|
236
|
-
}
|
|
237
|
-
else if (attrText.startsWith('v-on:')) {
|
|
238
|
-
attrText = 'on-' + (0, language_core_1.hyphenateAttr)(attrText.slice('v-on:'.length));
|
|
239
|
-
}
|
|
240
|
-
else if (attrText.startsWith('@')) {
|
|
241
|
-
attrText = 'on-' + (0, language_core_1.hyphenateAttr)(attrText.slice('@'.length));
|
|
242
|
-
}
|
|
243
|
-
current.unburnedRequiredProps = current.unburnedRequiredProps.filter(propName => {
|
|
244
|
-
return attrText !== propName
|
|
245
|
-
&& attrText !== (0, language_core_1.hyphenateAttr)(propName);
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
else if (token === html.TokenType.StartTagSelfClose || token === html.TokenType.StartTagClose) {
|
|
251
|
-
if (current) {
|
|
252
|
-
for (const requiredProp of current.unburnedRequiredProps) {
|
|
253
|
-
result.push({
|
|
254
|
-
label: `${requiredProp}!`,
|
|
255
|
-
paddingLeft: true,
|
|
256
|
-
position: document.positionAt(current.labelOffset),
|
|
257
|
-
kind: 2,
|
|
258
|
-
textEdits: [{
|
|
259
|
-
range: {
|
|
260
|
-
start: document.positionAt(current.insertOffset),
|
|
261
|
-
end: document.positionAt(current.insertOffset),
|
|
262
|
-
},
|
|
263
|
-
newText: ` :${casing.attr === types_1.AttrNameCasing.Kebab ? (0, language_core_1.hyphenateAttr)(requiredProp) : requiredProp}=`,
|
|
264
|
-
}],
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
current = undefined;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
if (token === html.TokenType.AttributeName || token === html.TokenType.AttributeValue) {
|
|
271
|
-
if (current) {
|
|
272
|
-
current.insertOffset = scanner.getTokenOffset() + scanner.getTokenLength();
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
return result;
|
|
277
|
-
},
|
|
278
150
|
provideHover(document, position, token) {
|
|
279
151
|
if (!isSupportedDocument(document)) {
|
|
280
152
|
return;
|
|
@@ -284,98 +156,6 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
284
156
|
}
|
|
285
157
|
return baseServiceInstance.provideHover?.(document, position, token);
|
|
286
158
|
},
|
|
287
|
-
async provideDiagnostics(document, token) {
|
|
288
|
-
if (!isSupportedDocument(document)) {
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
const uri = vscode_uri_1.URI.parse(document.uri);
|
|
292
|
-
const decoded = context.decodeEmbeddedDocumentUri(uri);
|
|
293
|
-
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
294
|
-
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
|
|
295
|
-
if (!virtualCode) {
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
const root = sourceScript?.generated?.root;
|
|
299
|
-
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
const originalResult = await baseServiceInstance.provideDiagnostics?.(document, token);
|
|
303
|
-
const templateErrors = [];
|
|
304
|
-
const { template } = root.sfc;
|
|
305
|
-
if (template) {
|
|
306
|
-
for (const error of template.errors) {
|
|
307
|
-
onCompilerError(error, 1);
|
|
308
|
-
}
|
|
309
|
-
for (const warning of template.warnings) {
|
|
310
|
-
onCompilerError(warning, 2);
|
|
311
|
-
}
|
|
312
|
-
function onCompilerError(error, severity) {
|
|
313
|
-
const templateHtmlRange = {
|
|
314
|
-
start: error.loc?.start.offset ?? 0,
|
|
315
|
-
end: error.loc?.end.offset ?? 0,
|
|
316
|
-
};
|
|
317
|
-
let errorMessage = error.message;
|
|
318
|
-
templateErrors.push({
|
|
319
|
-
range: {
|
|
320
|
-
start: document.positionAt(templateHtmlRange.start),
|
|
321
|
-
end: document.positionAt(templateHtmlRange.end),
|
|
322
|
-
},
|
|
323
|
-
severity,
|
|
324
|
-
code: error.code,
|
|
325
|
-
source: 'vue',
|
|
326
|
-
message: errorMessage,
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
return [
|
|
331
|
-
...originalResult ?? [],
|
|
332
|
-
...templateErrors,
|
|
333
|
-
];
|
|
334
|
-
},
|
|
335
|
-
provideDocumentSemanticTokens(document, range, legend) {
|
|
336
|
-
if (!isSupportedDocument(document)) {
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
if (!context.project.vue) {
|
|
340
|
-
return;
|
|
341
|
-
}
|
|
342
|
-
const vueCompilerOptions = context.project.vue.compilerOptions;
|
|
343
|
-
const languageService = context.inject('typescript/languageService');
|
|
344
|
-
if (!languageService) {
|
|
345
|
-
return;
|
|
346
|
-
}
|
|
347
|
-
const uri = vscode_uri_1.URI.parse(document.uri);
|
|
348
|
-
const decoded = context.decodeEmbeddedDocumentUri(uri);
|
|
349
|
-
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
350
|
-
const root = sourceScript?.generated?.root;
|
|
351
|
-
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
const { template } = root.sfc;
|
|
355
|
-
if (!template) {
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
const spans = common_1.getComponentSpans.call({
|
|
359
|
-
files: context.language.scripts,
|
|
360
|
-
languageService,
|
|
361
|
-
typescript: ts,
|
|
362
|
-
vueOptions: vueCompilerOptions,
|
|
363
|
-
}, root, template, {
|
|
364
|
-
start: document.offsetAt(range.start),
|
|
365
|
-
length: document.offsetAt(range.end) - document.offsetAt(range.start),
|
|
366
|
-
});
|
|
367
|
-
const classTokenIndex = legend.tokenTypes.indexOf('class');
|
|
368
|
-
return spans.map(span => {
|
|
369
|
-
const start = document.positionAt(span.start);
|
|
370
|
-
return [
|
|
371
|
-
start.line,
|
|
372
|
-
start.character,
|
|
373
|
-
span.length,
|
|
374
|
-
classTokenIndex,
|
|
375
|
-
0,
|
|
376
|
-
];
|
|
377
|
-
});
|
|
378
|
-
},
|
|
379
159
|
};
|
|
380
160
|
async function provideHtmlData(sourceDocumentUri, vueCode) {
|
|
381
161
|
await (initializing ??= initialize());
|
|
@@ -467,14 +247,19 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
467
247
|
return [];
|
|
468
248
|
}
|
|
469
249
|
const { attrs, propInfos, events, directives } = tagInfo;
|
|
470
|
-
const
|
|
471
|
-
|
|
472
|
-
|
|
250
|
+
for (const prop of propInfos) {
|
|
251
|
+
if ((0, language_core_1.hyphenateTag)(prop.name).startsWith('on-vnode-')) {
|
|
252
|
+
prop.name = 'onVue:' + prop.name.slice('onVnode'.length);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
473
255
|
const attributes = [];
|
|
474
|
-
const propsSet = new Set(
|
|
475
|
-
for (const prop of [
|
|
476
|
-
|
|
477
|
-
|
|
256
|
+
const propsSet = new Set(propInfos.map(prop => prop.name));
|
|
257
|
+
for (const prop of [
|
|
258
|
+
...propInfos,
|
|
259
|
+
...attrs.map(attr => ({ name: attr })),
|
|
260
|
+
]) {
|
|
261
|
+
const isGlobal = prop.isAttribute || !propsSet.has(prop.name);
|
|
262
|
+
const name = casing.attr === types_1.AttrNameCasing.Camel ? prop.name : (0, language_core_1.hyphenateAttr)(prop.name);
|
|
478
263
|
const isEvent = (0, language_core_1.hyphenateAttr)(name).startsWith('on-');
|
|
479
264
|
if (isEvent) {
|
|
480
265
|
const propNameBase = name.startsWith('on-')
|
|
@@ -502,6 +287,7 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
502
287
|
attributes.push({
|
|
503
288
|
name: propName,
|
|
504
289
|
description: propKey,
|
|
290
|
+
valueSet: prop.values?.some(value => typeof value === 'string') ? '__deferred__' : undefined,
|
|
505
291
|
}, {
|
|
506
292
|
name: ':' + propName,
|
|
507
293
|
description: propKey,
|
|
@@ -529,10 +315,13 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
529
315
|
});
|
|
530
316
|
}
|
|
531
317
|
const models = [];
|
|
532
|
-
for (const prop of [
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
318
|
+
for (const prop of [
|
|
319
|
+
...propInfos,
|
|
320
|
+
...attrs.map(attr => ({ name: attr })),
|
|
321
|
+
]) {
|
|
322
|
+
if (prop.name.startsWith('onUpdate:')) {
|
|
323
|
+
const isGlobal = !propsSet.has(prop.name);
|
|
324
|
+
models.push([isGlobal, prop.name.slice('onUpdate:'.length)]);
|
|
536
325
|
}
|
|
537
326
|
}
|
|
538
327
|
for (const event of events) {
|
|
@@ -806,17 +595,6 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
806
595
|
}
|
|
807
596
|
},
|
|
808
597
|
};
|
|
809
|
-
function getScanner(service, document) {
|
|
810
|
-
if (mode === 'html') {
|
|
811
|
-
return service.provide['html/languageService']().createScanner(document.getText());
|
|
812
|
-
}
|
|
813
|
-
else {
|
|
814
|
-
const pugDocument = service.provide['pug/pugDocument'](document);
|
|
815
|
-
if (pugDocument) {
|
|
816
|
-
return service.provide['pug/languageService']().createScanner(pugDocument);
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
598
|
function updateExtraCustomData(extraData) {
|
|
821
599
|
extraCustomData = extraData;
|
|
822
600
|
onDidChangeCustomDataListeners.forEach(l => l());
|
|
@@ -830,7 +608,6 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
830
608
|
}
|
|
831
609
|
}
|
|
832
610
|
}
|
|
833
|
-
;
|
|
834
611
|
function parseLabel(label) {
|
|
835
612
|
const leadingSlash = label.startsWith('/');
|
|
836
613
|
const name = label.slice(leadingSlash ? 1 : 0);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { LanguageServiceContext, LanguageServicePlugin } from '@volar/language-service';
|
|
2
|
-
export declare function create(getTsPluginClient?: (context: LanguageServiceContext) =>
|
|
2
|
+
export declare function create(getTsPluginClient?: (context: LanguageServiceContext) => import('@vue/typescript-plugin/lib/requests').Requests | undefined): LanguageServicePlugin;
|
|
@@ -38,7 +38,7 @@ function create(getTsPluginClient) {
|
|
|
38
38
|
for (const [pointerPosition, hoverOffset] of hoverOffsets) {
|
|
39
39
|
const map = context.language.maps.get(virtualCode, sourceScript);
|
|
40
40
|
for (const [sourceOffset] of map.toSourceLocation(hoverOffset)) {
|
|
41
|
-
const quickInfo = await tsPluginClient?.getQuickInfoAtPosition(root.fileName, sourceOffset);
|
|
41
|
+
const quickInfo = await tsPluginClient?.getQuickInfoAtPosition(root.fileName, document.positionAt(sourceOffset));
|
|
42
42
|
if (quickInfo) {
|
|
43
43
|
inlayHints.push({
|
|
44
44
|
position: { line: pointerPosition.line, character: pointerPosition.character + 2 },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vue/language-service",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0-alpha.10",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"data",
|
|
@@ -17,23 +17,23 @@
|
|
|
17
17
|
"update-html-data": "node ./scripts/update-html-data.js"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@volar/language-core": "~2.4.
|
|
21
|
-
"@volar/language-service": "~2.4.
|
|
22
|
-
"@volar/typescript": "~2.4.
|
|
20
|
+
"@volar/language-core": "~2.4.13",
|
|
21
|
+
"@volar/language-service": "~2.4.13",
|
|
22
|
+
"@volar/typescript": "~2.4.13",
|
|
23
23
|
"@vue/compiler-dom": "^3.5.0",
|
|
24
|
-
"@vue/language-core": "
|
|
24
|
+
"@vue/language-core": "3.0.0-alpha.10",
|
|
25
25
|
"@vue/shared": "^3.5.0",
|
|
26
|
-
"@vue/typescript-plugin": "
|
|
27
|
-
"alien-signals": "^
|
|
26
|
+
"@vue/typescript-plugin": "3.0.0-alpha.10",
|
|
27
|
+
"alien-signals": "^2.0.5",
|
|
28
28
|
"path-browserify": "^1.0.1",
|
|
29
|
-
"volar-service-css": "0.0.
|
|
30
|
-
"volar-service-emmet": "0.0.
|
|
31
|
-
"volar-service-html": "0.0.
|
|
32
|
-
"volar-service-json": "0.0.
|
|
33
|
-
"volar-service-pug": "0.0.
|
|
34
|
-
"volar-service-pug-beautify": "0.0.
|
|
35
|
-
"volar-service-typescript": "0.0.
|
|
36
|
-
"volar-service-typescript-twoslash-queries": "0.0.
|
|
29
|
+
"volar-service-css": "0.0.64",
|
|
30
|
+
"volar-service-emmet": "0.0.64",
|
|
31
|
+
"volar-service-html": "0.0.64",
|
|
32
|
+
"volar-service-json": "0.0.64",
|
|
33
|
+
"volar-service-pug": "0.0.64",
|
|
34
|
+
"volar-service-pug-beautify": "0.0.64",
|
|
35
|
+
"volar-service-typescript": "0.0.64",
|
|
36
|
+
"volar-service-typescript-twoslash-queries": "0.0.64",
|
|
37
37
|
"vscode-css-languageservice": "^6.3.1",
|
|
38
38
|
"vscode-html-languageservice": "^5.2.0",
|
|
39
39
|
"vscode-languageserver-textdocument": "^1.0.11",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^22.10.4",
|
|
44
44
|
"@types/path-browserify": "^1.0.1",
|
|
45
|
-
"@volar/kit": "~2.4.
|
|
45
|
+
"@volar/kit": "~2.4.13",
|
|
46
46
|
"vscode-languageserver-protocol": "^3.17.5"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "28308b4f76cc80c7632f39ae7e0944f1889661a2"
|
|
49
49
|
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { LanguageServiceContext } from '@volar/language-service';
|
|
2
|
-
import type * as vscode from 'vscode-languageserver-protocol';
|
|
3
|
-
import type { URI } from 'vscode-uri';
|
|
4
|
-
import { AttrNameCasing, TagNameCasing } from '../types';
|
|
5
|
-
export declare function convertTagName(context: LanguageServiceContext, uri: URI, casing: TagNameCasing, tsPluginClient: typeof import('@vue/typescript-plugin/lib/client') | undefined): Promise<vscode.TextEdit[] | undefined>;
|
|
6
|
-
export declare function convertAttrName(context: LanguageServiceContext, uri: URI, casing: AttrNameCasing, tsPluginClient?: typeof import('@vue/typescript-plugin/lib/client')): Promise<vscode.TextEdit[] | undefined>;
|
|
7
|
-
export declare function getNameCasing(context: LanguageServiceContext, uri: URI): Promise<{
|
|
8
|
-
tag: TagNameCasing;
|
|
9
|
-
attr: AttrNameCasing;
|
|
10
|
-
}>;
|
|
11
|
-
export declare function detect(context: LanguageServiceContext, uri: URI): Promise<{
|
|
12
|
-
tag: TagNameCasing[];
|
|
13
|
-
attr: AttrNameCasing[];
|
|
14
|
-
}>;
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.convertTagName = convertTagName;
|
|
4
|
-
exports.convertAttrName = convertAttrName;
|
|
5
|
-
exports.getNameCasing = getNameCasing;
|
|
6
|
-
exports.detect = detect;
|
|
7
|
-
const vue = require("@vue/language-core");
|
|
8
|
-
const language_core_1 = require("@vue/language-core");
|
|
9
|
-
const alien_signals_1 = require("alien-signals");
|
|
10
|
-
const types_1 = require("../types");
|
|
11
|
-
async function convertTagName(context, uri, casing, tsPluginClient) {
|
|
12
|
-
const sourceFile = context.language.scripts.get(uri);
|
|
13
|
-
if (!sourceFile) {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
const root = sourceFile?.generated?.root;
|
|
17
|
-
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
const { template } = root.sfc;
|
|
21
|
-
if (!template) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
const document = context.documents.get(sourceFile.id, sourceFile.languageId, sourceFile.snapshot);
|
|
25
|
-
const edits = [];
|
|
26
|
-
const components = await tsPluginClient?.getComponentNames(root.fileName) ?? [];
|
|
27
|
-
const tags = getTemplateTagsAndAttrs(root);
|
|
28
|
-
for (const [tagName, { offsets }] of tags) {
|
|
29
|
-
const componentName = components.find(component => component === tagName || (0, language_core_1.hyphenateTag)(component) === tagName);
|
|
30
|
-
if (componentName) {
|
|
31
|
-
for (const offset of offsets) {
|
|
32
|
-
const start = document.positionAt(template.startTagEnd + offset);
|
|
33
|
-
const end = document.positionAt(template.startTagEnd + offset + tagName.length);
|
|
34
|
-
const range = { start, end };
|
|
35
|
-
if (casing === types_1.TagNameCasing.Kebab && tagName !== (0, language_core_1.hyphenateTag)(componentName)) {
|
|
36
|
-
edits.push({ range, newText: (0, language_core_1.hyphenateTag)(componentName) });
|
|
37
|
-
}
|
|
38
|
-
if (casing === types_1.TagNameCasing.Pascal && tagName !== componentName) {
|
|
39
|
-
edits.push({ range, newText: componentName });
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return edits;
|
|
45
|
-
}
|
|
46
|
-
async function convertAttrName(context, uri, casing, tsPluginClient) {
|
|
47
|
-
const sourceFile = context.language.scripts.get(uri);
|
|
48
|
-
if (!sourceFile) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const root = sourceFile?.generated?.root;
|
|
52
|
-
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
const { template } = root.sfc;
|
|
56
|
-
if (!template) {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
const document = context.documents.get(uri, sourceFile.languageId, sourceFile.snapshot);
|
|
60
|
-
const edits = [];
|
|
61
|
-
const components = await tsPluginClient?.getComponentNames(root.fileName) ?? [];
|
|
62
|
-
const tags = getTemplateTagsAndAttrs(root);
|
|
63
|
-
for (const [tagName, { attrs }] of tags) {
|
|
64
|
-
const componentName = components.find(component => component === tagName || (0, language_core_1.hyphenateTag)(component) === tagName);
|
|
65
|
-
if (componentName) {
|
|
66
|
-
const props = (await tsPluginClient?.getComponentProps(root.fileName, componentName) ?? []).map(prop => prop.name);
|
|
67
|
-
for (const [attrName, { offsets }] of attrs) {
|
|
68
|
-
const propName = props.find(prop => prop === attrName || (0, language_core_1.hyphenateAttr)(prop) === attrName);
|
|
69
|
-
if (propName) {
|
|
70
|
-
for (const offset of offsets) {
|
|
71
|
-
const start = document.positionAt(template.startTagEnd + offset);
|
|
72
|
-
const end = document.positionAt(template.startTagEnd + offset + attrName.length);
|
|
73
|
-
const range = { start, end };
|
|
74
|
-
if (casing === types_1.AttrNameCasing.Kebab && attrName !== (0, language_core_1.hyphenateAttr)(propName)) {
|
|
75
|
-
edits.push({ range, newText: (0, language_core_1.hyphenateAttr)(propName) });
|
|
76
|
-
}
|
|
77
|
-
if (casing === types_1.AttrNameCasing.Camel && attrName !== propName) {
|
|
78
|
-
edits.push({ range, newText: propName });
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return edits;
|
|
86
|
-
}
|
|
87
|
-
async function getNameCasing(context, uri) {
|
|
88
|
-
const detected = await detect(context, uri);
|
|
89
|
-
const [attr, tag] = await Promise.all([
|
|
90
|
-
context.env.getConfiguration?.('vue.complete.casing.props', uri.toString()),
|
|
91
|
-
context.env.getConfiguration?.('vue.complete.casing.tags', uri.toString()),
|
|
92
|
-
]);
|
|
93
|
-
const tagNameCasing = detected.tag.length === 1 && (tag === 'autoPascal' || tag === 'autoKebab') ? detected.tag[0] : (tag === 'autoKebab' || tag === 'kebab') ? types_1.TagNameCasing.Kebab : types_1.TagNameCasing.Pascal;
|
|
94
|
-
const attrNameCasing = detected.attr.length === 1 && (attr === 'autoCamel' || attr === 'autoKebab') ? detected.attr[0] : (attr === 'autoCamel' || attr === 'camel') ? types_1.AttrNameCasing.Camel : types_1.AttrNameCasing.Kebab;
|
|
95
|
-
return {
|
|
96
|
-
tag: tagNameCasing,
|
|
97
|
-
attr: attrNameCasing,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
async function detect(context, uri) {
|
|
101
|
-
const rootFile = context.language.scripts.get(uri)?.generated?.root;
|
|
102
|
-
if (!(rootFile instanceof language_core_1.VueVirtualCode)) {
|
|
103
|
-
return {
|
|
104
|
-
tag: [],
|
|
105
|
-
attr: [],
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
return {
|
|
109
|
-
tag: await getTagNameCase(rootFile),
|
|
110
|
-
attr: getAttrNameCase(rootFile),
|
|
111
|
-
};
|
|
112
|
-
function getAttrNameCase(file) {
|
|
113
|
-
const tags = getTemplateTagsAndAttrs(file);
|
|
114
|
-
const result = [];
|
|
115
|
-
for (const [_, { attrs }] of tags) {
|
|
116
|
-
for (const [tagName] of attrs) {
|
|
117
|
-
// attrName
|
|
118
|
-
if (tagName !== (0, language_core_1.hyphenateTag)(tagName)) {
|
|
119
|
-
result.push(types_1.AttrNameCasing.Camel);
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
for (const [tagName] of attrs) {
|
|
124
|
-
// attr-name
|
|
125
|
-
if (tagName.includes('-')) {
|
|
126
|
-
result.push(types_1.AttrNameCasing.Kebab);
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return result;
|
|
132
|
-
}
|
|
133
|
-
function getTagNameCase(file) {
|
|
134
|
-
const result = new Set();
|
|
135
|
-
if (file.sfc.template?.ast) {
|
|
136
|
-
for (const element of vue.forEachElementNode(file.sfc.template.ast)) {
|
|
137
|
-
if (element.tagType === 1) {
|
|
138
|
-
if (element.tag !== (0, language_core_1.hyphenateTag)(element.tag)) {
|
|
139
|
-
// TagName
|
|
140
|
-
result.add(types_1.TagNameCasing.Pascal);
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
// Tagname -> tagname
|
|
144
|
-
// TagName -> tag-name
|
|
145
|
-
result.add(types_1.TagNameCasing.Kebab);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return [...result];
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
const map = new WeakMap();
|
|
154
|
-
function getTemplateTagsAndAttrs(sourceFile) {
|
|
155
|
-
if (!map.has(sourceFile)) {
|
|
156
|
-
const getter = (0, alien_signals_1.computed)(() => {
|
|
157
|
-
if (!(sourceFile instanceof vue.VueVirtualCode)) {
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
const ast = sourceFile.sfc.template?.ast;
|
|
161
|
-
const tags = new Map();
|
|
162
|
-
if (ast) {
|
|
163
|
-
for (const node of vue.forEachElementNode(ast)) {
|
|
164
|
-
if (!tags.has(node.tag)) {
|
|
165
|
-
tags.set(node.tag, { offsets: [], attrs: new Map() });
|
|
166
|
-
}
|
|
167
|
-
const tag = tags.get(node.tag);
|
|
168
|
-
const startTagHtmlOffset = node.loc.start.offset + node.loc.source.indexOf(node.tag);
|
|
169
|
-
const endTagHtmlOffset = node.loc.start.offset + node.loc.source.lastIndexOf(node.tag);
|
|
170
|
-
tag.offsets.push(startTagHtmlOffset);
|
|
171
|
-
if (!node.isSelfClosing) {
|
|
172
|
-
tag.offsets.push(endTagHtmlOffset);
|
|
173
|
-
}
|
|
174
|
-
for (const prop of node.props) {
|
|
175
|
-
let name;
|
|
176
|
-
let offset;
|
|
177
|
-
if (prop.type === 7
|
|
178
|
-
&& prop.arg?.type === 4
|
|
179
|
-
&& prop.arg.isStatic) {
|
|
180
|
-
name = prop.arg.content;
|
|
181
|
-
offset = prop.arg.loc.start.offset;
|
|
182
|
-
}
|
|
183
|
-
else if (prop.type === 6) {
|
|
184
|
-
name = prop.name;
|
|
185
|
-
offset = prop.loc.start.offset;
|
|
186
|
-
}
|
|
187
|
-
if (name !== undefined && offset !== undefined) {
|
|
188
|
-
if (!tag.attrs.has(name)) {
|
|
189
|
-
tag.attrs.set(name, { offsets: [] });
|
|
190
|
-
}
|
|
191
|
-
tag.attrs.get(name).offsets.push(offset);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return tags;
|
|
197
|
-
});
|
|
198
|
-
map.set(sourceFile, getter);
|
|
199
|
-
}
|
|
200
|
-
return map.get(sourceFile)() ?? new Map();
|
|
201
|
-
}
|
|
202
|
-
//# sourceMappingURL=nameCasing.js.map
|