@vue/language-service 3.0.0-alpha.6 → 3.0.0-alpha.8
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/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) {
|
|
@@ -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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vue/language-service",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.8",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"data",
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
"@volar/language-service": "~2.4.13",
|
|
22
22
|
"@volar/typescript": "~2.4.13",
|
|
23
23
|
"@vue/compiler-dom": "^3.5.0",
|
|
24
|
-
"@vue/language-core": "3.0.0-alpha.
|
|
24
|
+
"@vue/language-core": "3.0.0-alpha.8",
|
|
25
25
|
"@vue/shared": "^3.5.0",
|
|
26
|
-
"@vue/typescript-plugin": "3.0.0-alpha.
|
|
27
|
-
"alien-signals": "^
|
|
26
|
+
"@vue/typescript-plugin": "3.0.0-alpha.8",
|
|
27
|
+
"alien-signals": "^2.0.5",
|
|
28
28
|
"path-browserify": "^1.0.1",
|
|
29
29
|
"volar-service-css": "0.0.64",
|
|
30
30
|
"volar-service-emmet": "0.0.64",
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"@volar/kit": "~2.4.13",
|
|
46
46
|
"vscode-languageserver-protocol": "^3.17.5"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "d38cb93558fe8015c7ffe9ceacfdd3296e3692f6"
|
|
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
|