@vue/typescript-plugin 2.2.8 → 3.0.0-alpha.2
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 +2 -2
- package/index.js +96 -9
- package/lib/client.d.ts +4 -1
- package/lib/client.js +2 -1
- package/lib/common.d.ts +1 -3
- package/lib/common.js +75 -2
- package/lib/proxy.d.ts +3 -0
- package/lib/proxy.js +356 -0
- package/lib/requests/getElementAttrs.js +14 -17
- package/lib/requests/getElementNames.d.ts +5 -0
- package/lib/requests/getElementNames.js +23 -0
- package/lib/requests/getPropertiesAtLocation.js +1 -0
- package/lib/requests/getSlotNames.d.ts +6 -0
- package/lib/requests/getSlotNames.js +30 -0
- package/lib/requests/index.d.ts +17 -0
- package/lib/requests/index.js +3 -0
- package/lib/requests/utils.js +8 -8
- package/lib/server.d.ts +1 -1
- package/lib/server.js +4 -0
- package/lib/utils.js +1 -3
- package/package.json +3 -3
- package/lib/requests/componentInfos.d.ts +0 -13
- package/lib/requests/componentInfos.js +0 -249
- package/lib/requests/getComponentInfo.d.ts +0 -5
- package/lib/requests/getComponentInfo.js +0 -23
package/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type * as ts from 'typescript';
|
|
2
|
-
declare const
|
|
3
|
-
export =
|
|
2
|
+
declare const _default: ts.server.PluginModuleFactory;
|
|
3
|
+
export = _default;
|
package/index.js
CHANGED
|
@@ -2,21 +2,26 @@
|
|
|
2
2
|
const createLanguageServicePlugin_1 = require("@volar/typescript/lib/quickstart/createLanguageServicePlugin");
|
|
3
3
|
const vue = require("@vue/language-core");
|
|
4
4
|
const common_1 = require("./lib/common");
|
|
5
|
-
const
|
|
5
|
+
const collectExtractProps_1 = require("./lib/requests/collectExtractProps");
|
|
6
|
+
const getComponentDirectives_1 = require("./lib/requests/getComponentDirectives");
|
|
7
|
+
const getComponentEvents_1 = require("./lib/requests/getComponentEvents");
|
|
8
|
+
const getComponentNames_1 = require("./lib/requests/getComponentNames");
|
|
9
|
+
const getComponentProps_1 = require("./lib/requests/getComponentProps");
|
|
10
|
+
const getElementAttrs_1 = require("./lib/requests/getElementAttrs");
|
|
11
|
+
const getElementNames_1 = require("./lib/requests/getElementNames");
|
|
12
|
+
const getImportPathForFile_1 = require("./lib/requests/getImportPathForFile");
|
|
13
|
+
const getPropertiesAtLocation_1 = require("./lib/requests/getPropertiesAtLocation");
|
|
6
14
|
const windowsPathReg = /\\/g;
|
|
7
|
-
const
|
|
8
|
-
|
|
15
|
+
const project2Service = new WeakMap();
|
|
16
|
+
module.exports = (0, createLanguageServicePlugin_1.createLanguageServicePlugin)((ts, info) => {
|
|
9
17
|
const vueOptions = getVueCompilerOptions();
|
|
10
18
|
const languagePlugin = vue.createVueLanguagePlugin(ts, info.languageServiceHost.getCompilationSettings(), vueOptions, id => id);
|
|
11
|
-
|
|
19
|
+
addVueCommands();
|
|
12
20
|
return {
|
|
13
21
|
languagePlugins: [languagePlugin],
|
|
14
22
|
setup: language => {
|
|
23
|
+
project2Service.set(info.project, [language, info.languageServiceHost, info.languageService]);
|
|
15
24
|
info.languageService = (0, common_1.proxyLanguageServiceForVue)(ts, language, info.languageService, vueOptions, fileName => fileName);
|
|
16
|
-
if (info.project.projectKind === ts.server.ProjectKind.Configured
|
|
17
|
-
|| info.project.projectKind === ts.server.ProjectKind.Inferred) {
|
|
18
|
-
(0, server_1.startNamedPipeServer)(ts, info, language, info.project.projectKind);
|
|
19
|
-
}
|
|
20
25
|
// #3963
|
|
21
26
|
const timer = setInterval(() => {
|
|
22
27
|
if (info.project['program']) {
|
|
@@ -35,6 +40,88 @@ const plugin = (0, createLanguageServicePlugin_1.createLanguageServicePlugin)((t
|
|
|
35
40
|
return vue.createParsedCommandLineByJson(ts, ts.sys, info.languageServiceHost.getCurrentDirectory(), {}).vueOptions;
|
|
36
41
|
}
|
|
37
42
|
}
|
|
43
|
+
// https://github.com/JetBrains/intellij-plugins/blob/6435723ad88fa296b41144162ebe3b8513f4949b/Angular/src-js/angular-service/src/index.ts#L69
|
|
44
|
+
function addVueCommands() {
|
|
45
|
+
const projectService = info.project.projectService;
|
|
46
|
+
projectService.logger.info("Vue: called handler processing " + info.project.projectKind);
|
|
47
|
+
const session = info.session;
|
|
48
|
+
if (session == undefined) {
|
|
49
|
+
projectService.logger.info("Vue: there is no session in info.");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (session.addProtocolHandler == undefined) {
|
|
53
|
+
// addProtocolHandler was introduced in TS 4.4 or 4.5 in 2021, see https://github.com/microsoft/TypeScript/issues/43893
|
|
54
|
+
projectService.logger.info("Vue: there is no addProtocolHandler method.");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (session.vueCommandsAdded) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
session.vueCommandsAdded = true;
|
|
61
|
+
session.addProtocolHandler('vue:collectExtractProps', ({ arguments: args }) => {
|
|
62
|
+
return {
|
|
63
|
+
response: collectExtractProps_1.collectExtractProps.apply(getRequestContext(args[0]), args),
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
session.addProtocolHandler('vue:getImportPathForFile', ({ arguments: args }) => {
|
|
67
|
+
return {
|
|
68
|
+
response: getImportPathForFile_1.getImportPathForFile.apply(getRequestContext(args[0]), args),
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
session.addProtocolHandler('vue:getPropertiesAtLocation', ({ arguments: args }) => {
|
|
72
|
+
return {
|
|
73
|
+
response: getPropertiesAtLocation_1.getPropertiesAtLocation.apply(getRequestContext(args[0]), args),
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
session.addProtocolHandler('vue:getComponentNames', ({ arguments: args }) => {
|
|
77
|
+
return {
|
|
78
|
+
response: getComponentNames_1.getComponentNames.apply(getRequestContext(args[0]), args) ?? [],
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
session.addProtocolHandler('vue:getComponentProps', ({ arguments: args }) => {
|
|
82
|
+
return {
|
|
83
|
+
response: getComponentProps_1.getComponentProps.apply(getRequestContext(args[0]), args),
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
session.addProtocolHandler('vue:getComponentEvents', ({ arguments: args }) => {
|
|
87
|
+
return {
|
|
88
|
+
response: getComponentEvents_1.getComponentEvents.apply(getRequestContext(args[0]), args),
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
session.addProtocolHandler('vue:getComponentDirectives', ({ arguments: args }) => {
|
|
92
|
+
return {
|
|
93
|
+
response: getComponentDirectives_1.getComponentDirectives.apply(getRequestContext(args[0]), args),
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
session.addProtocolHandler('vue:getElementAttrs', ({ arguments: args }) => {
|
|
97
|
+
return {
|
|
98
|
+
response: getElementAttrs_1.getElementAttrs.apply(getRequestContext(args[0]), args),
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
session.addProtocolHandler('vue:getElementNames', ({ arguments: args }) => {
|
|
102
|
+
return {
|
|
103
|
+
response: getElementNames_1.getElementNames.apply(getRequestContext(args[0]), args),
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
projectService.logger.info('Vue specific commands are successfully added.');
|
|
107
|
+
}
|
|
108
|
+
function getRequestContext(fileName) {
|
|
109
|
+
const fileAndProject = info.session.getFileAndProject({
|
|
110
|
+
file: fileName,
|
|
111
|
+
projectFileName: undefined,
|
|
112
|
+
});
|
|
113
|
+
const service = project2Service.get(fileAndProject.project);
|
|
114
|
+
if (!service) {
|
|
115
|
+
throw 'No RequestContext';
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
typescript: ts,
|
|
119
|
+
languageService: service[2],
|
|
120
|
+
languageServiceHost: service[1],
|
|
121
|
+
language: service[0],
|
|
122
|
+
isTsPlugin: true,
|
|
123
|
+
getFileId: (fileName) => fileName,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
38
126
|
});
|
|
39
|
-
module.exports = plugin;
|
|
40
127
|
//# sourceMappingURL=index.js.map
|
package/lib/client.d.ts
CHANGED
|
@@ -10,4 +10,7 @@ export declare function getComponentProps(fileName: string, componentName: strin
|
|
|
10
10
|
export declare const getComponentEvents: (fileName: string, tag: string) => Promise<string[] | null | undefined>;
|
|
11
11
|
export declare const getComponentDirectives: (fileName: string) => Promise<string[] | null | undefined>;
|
|
12
12
|
export declare function getComponentNames(fileName: string): Promise<string[] | undefined>;
|
|
13
|
-
export declare const getElementAttrs: (fileName: string, tagName: string) => Promise<
|
|
13
|
+
export declare const getElementAttrs: (fileName: string, tagName: string) => Promise<{
|
|
14
|
+
name: string;
|
|
15
|
+
}[] | null | undefined>;
|
|
16
|
+
export declare const getSlotNames: (fileName: string) => Promise<string[] | null | undefined>;
|
package/lib/client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getElementAttrs = exports.getComponentDirectives = exports.getComponentEvents = exports.getQuickInfoAtPosition = exports.getPropertiesAtLocation = exports.getImportPathForFile = exports.collectExtractProps = void 0;
|
|
3
|
+
exports.getSlotNames = exports.getElementAttrs = exports.getComponentDirectives = exports.getComponentEvents = exports.getQuickInfoAtPosition = exports.getPropertiesAtLocation = exports.getImportPathForFile = exports.collectExtractProps = void 0;
|
|
4
4
|
exports.getComponentProps = getComponentProps;
|
|
5
5
|
exports.getComponentNames = getComponentNames;
|
|
6
6
|
const utils_1 = require("./utils");
|
|
@@ -30,6 +30,7 @@ async function getComponentNames(fileName) {
|
|
|
30
30
|
return Object.keys(componentAndProps);
|
|
31
31
|
}
|
|
32
32
|
exports.getElementAttrs = createRequest('getElementAttrs');
|
|
33
|
+
exports.getSlotNames = createRequest('getSlotNames');
|
|
33
34
|
function createRequest(requestType) {
|
|
34
35
|
return async function (...[fileName, ...rest]) {
|
|
35
36
|
const server = await (0, utils_1.getBestServer)(fileName);
|
package/lib/common.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { Language, VueCompilerOptions
|
|
1
|
+
import { Language, VueCompilerOptions } from '@vue/language-core';
|
|
2
2
|
import type * as ts from 'typescript';
|
|
3
|
-
import type { RequestContext } from './requests/types';
|
|
4
3
|
export declare function proxyLanguageServiceForVue<T>(ts: typeof import('typescript'), language: Language<T>, languageService: ts.LanguageService, vueOptions: VueCompilerOptions, asScriptId: (fileName: string) => T): ts.LanguageService;
|
|
5
|
-
export declare function getComponentSpans(this: Pick<RequestContext, 'typescript' | 'languageService'>, vueCode: VueVirtualCode, template: NonNullable<VueVirtualCode['_sfc']['template']>, spanTemplateRange: ts.TextSpan): ts.TextSpan[];
|
package/lib/common.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.proxyLanguageServiceForVue = proxyLanguageServiceForVue;
|
|
4
|
-
exports.getComponentSpans = getComponentSpans;
|
|
5
4
|
const language_core_1 = require("@vue/language-core");
|
|
6
5
|
const shared_1 = require("@vue/shared");
|
|
7
6
|
const getComponentNames_1 = require("./requests/getComponentNames");
|
|
7
|
+
const getElementNames_1 = require("./requests/getElementNames");
|
|
8
8
|
const windowsPathReg = /\\/g;
|
|
9
9
|
function proxyLanguageServiceForVue(ts, language, languageService, vueOptions, asScriptId) {
|
|
10
10
|
const proxyCache = new Map();
|
|
@@ -13,6 +13,7 @@ function proxyLanguageServiceForVue(ts, language, languageService, vueOptions, a
|
|
|
13
13
|
case 'getCompletionsAtPosition': return getCompletionsAtPosition(vueOptions, target[p]);
|
|
14
14
|
case 'getCompletionEntryDetails': return getCompletionEntryDetails(language, asScriptId, target[p]);
|
|
15
15
|
case 'getCodeFixesAtPosition': return getCodeFixesAtPosition(target[p]);
|
|
16
|
+
case 'getDefinitionAndBoundSpan': return getDefinitionAndBoundSpan(ts, language, languageService, vueOptions, asScriptId, target[p]);
|
|
16
17
|
case 'getQuickInfoAtPosition': return getQuickInfoAtPosition(ts, target, target[p]);
|
|
17
18
|
// TS plugin only
|
|
18
19
|
case 'getEncodedSemanticClassifications': return getEncodedSemanticClassifications(ts, language, target, asScriptId, target[p]);
|
|
@@ -128,6 +129,77 @@ function getCodeFixesAtPosition(getCodeFixesAtPosition) {
|
|
|
128
129
|
return result;
|
|
129
130
|
};
|
|
130
131
|
}
|
|
132
|
+
function getDefinitionAndBoundSpan(ts, language, languageService, vueOptions, asScriptId, getDefinitionAndBoundSpan) {
|
|
133
|
+
return (fileName, position) => {
|
|
134
|
+
const result = getDefinitionAndBoundSpan(fileName, position);
|
|
135
|
+
if (!result?.definitions?.length) {
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
const program = languageService.getProgram();
|
|
139
|
+
const sourceScript = language.scripts.get(asScriptId(fileName));
|
|
140
|
+
if (!sourceScript?.generated) {
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
const root = sourceScript.generated.root;
|
|
144
|
+
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
if (!root.sfc.template
|
|
148
|
+
|| position < root.sfc.template.startTagEnd
|
|
149
|
+
|| position > root.sfc.template.endTagStart) {
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
const definitions = new Set(result.definitions);
|
|
153
|
+
const skippedDefinitions = [];
|
|
154
|
+
for (const definition of result.definitions) {
|
|
155
|
+
if (vueOptions.extensions.some(ext => definition.fileName.endsWith(ext))) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const sourceFile = program.getSourceFile(definition.fileName);
|
|
159
|
+
if (!sourceFile) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
visit(sourceFile, definition, sourceFile);
|
|
163
|
+
}
|
|
164
|
+
for (const definition of skippedDefinitions) {
|
|
165
|
+
definitions.delete(definition);
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
definitions: [...definitions],
|
|
169
|
+
textSpan: result.textSpan,
|
|
170
|
+
};
|
|
171
|
+
function visit(node, definition, sourceFile) {
|
|
172
|
+
if (ts.isPropertySignature(node) && node.type) {
|
|
173
|
+
proxy(node.name, node.type, definition, sourceFile);
|
|
174
|
+
}
|
|
175
|
+
else if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.type && !node.initializer) {
|
|
176
|
+
proxy(node.name, node.type, definition, sourceFile);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
ts.forEachChild(node, child => visit(child, definition, sourceFile));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function proxy(name, type, definition, sourceFile) {
|
|
183
|
+
const { textSpan, fileName } = definition;
|
|
184
|
+
const start = name.getStart(sourceFile);
|
|
185
|
+
const end = name.getEnd();
|
|
186
|
+
if (start !== textSpan.start || end - start !== textSpan.length) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (!ts.isIndexedAccessTypeNode(type)) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const pos = type.indexType.getStart(sourceFile);
|
|
193
|
+
const res = getDefinitionAndBoundSpan(fileName, pos);
|
|
194
|
+
if (res?.definitions?.length) {
|
|
195
|
+
for (const definition of res.definitions) {
|
|
196
|
+
definitions.add(definition);
|
|
197
|
+
}
|
|
198
|
+
skippedDefinitions.push(definition);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
}
|
|
131
203
|
function getQuickInfoAtPosition(ts, languageService, getQuickInfoAtPosition) {
|
|
132
204
|
return (...args) => {
|
|
133
205
|
const result = getQuickInfoAtPosition(...args);
|
|
@@ -191,6 +263,7 @@ function getComponentSpans(vueCode, template, spanTemplateRange) {
|
|
|
191
263
|
const { typescript: ts, languageService } = this;
|
|
192
264
|
const result = [];
|
|
193
265
|
const validComponentNames = (0, getComponentNames_1._getComponentNames)(ts, languageService, vueCode);
|
|
266
|
+
const elements = new Set((0, getElementNames_1._getElementNames)(ts, languageService, vueCode));
|
|
194
267
|
const components = new Set([
|
|
195
268
|
...validComponentNames,
|
|
196
269
|
...validComponentNames.map(language_core_1.hyphenateTag),
|
|
@@ -200,7 +273,7 @@ function getComponentSpans(vueCode, template, spanTemplateRange) {
|
|
|
200
273
|
if (node.loc.end.offset <= spanTemplateRange.start || node.loc.start.offset >= (spanTemplateRange.start + spanTemplateRange.length)) {
|
|
201
274
|
continue;
|
|
202
275
|
}
|
|
203
|
-
if (components.has(node.tag)) {
|
|
276
|
+
if (components.has(node.tag) && !elements.has(node.tag)) {
|
|
204
277
|
let start = node.loc.start.offset;
|
|
205
278
|
if (template.lang === 'html') {
|
|
206
279
|
start += '<'.length;
|
package/lib/proxy.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Language, VueCompilerOptions } from '@vue/language-core';
|
|
2
|
+
import type * as ts from 'typescript';
|
|
3
|
+
export declare function proxyLanguageServiceForVue<T>(ts: typeof import('typescript'), language: Language<T>, languageService: ts.LanguageService, vueOptions: VueCompilerOptions, asScriptId: (fileName: string) => T): ts.LanguageService;
|
package/lib/proxy.js
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.proxyLanguageServiceForVue = proxyLanguageServiceForVue;
|
|
4
|
+
const language_core_1 = require("@vue/language-core");
|
|
5
|
+
const shared_1 = require("@vue/shared");
|
|
6
|
+
const getComponentNames_1 = require("./requests/getComponentNames");
|
|
7
|
+
const windowsPathReg = /\\/g;
|
|
8
|
+
function proxyLanguageServiceForVue(ts, language, languageService, vueOptions, asScriptId) {
|
|
9
|
+
const proxyCache = new Map();
|
|
10
|
+
const getProxyMethod = (target, p) => {
|
|
11
|
+
switch (p) {
|
|
12
|
+
case 'getCompletionsAtPosition': return getCompletionsAtPosition(vueOptions, target[p]);
|
|
13
|
+
case 'getCompletionEntryDetails': return getCompletionEntryDetails(language, asScriptId, target[p]);
|
|
14
|
+
case 'getCodeFixesAtPosition': return getCodeFixesAtPosition(target[p]);
|
|
15
|
+
case 'getDefinitionAndBoundSpan': return getDefinitionAndBoundSpan(ts, language, languageService, vueOptions, asScriptId, target[p]);
|
|
16
|
+
case 'getEncodedSemanticClassifications': return getEncodedSemanticClassifications(ts, language, target, asScriptId, target[p]);
|
|
17
|
+
case 'getQuickInfoAtPosition': return getQuickInfoAtPosition(ts, target, target[p]);
|
|
18
|
+
case 'getSemanticDiagnostics': return getSemanticDiagnostics(ts, language, languageService, asScriptId, target[p]);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
return new Proxy(languageService, {
|
|
22
|
+
get(target, p, receiver) {
|
|
23
|
+
if (getProxyMethod) {
|
|
24
|
+
if (!proxyCache.has(p)) {
|
|
25
|
+
proxyCache.set(p, getProxyMethod(target, p));
|
|
26
|
+
}
|
|
27
|
+
const proxyMethod = proxyCache.get(p);
|
|
28
|
+
if (proxyMethod) {
|
|
29
|
+
return proxyMethod;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return Reflect.get(target, p, receiver);
|
|
33
|
+
},
|
|
34
|
+
set(target, p, value, receiver) {
|
|
35
|
+
return Reflect.set(target, p, value, receiver);
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function getCompletionsAtPosition(vueOptions, getCompletionsAtPosition) {
|
|
40
|
+
return (filePath, position, options, formattingSettings) => {
|
|
41
|
+
const fileName = filePath.replace(windowsPathReg, '/');
|
|
42
|
+
const result = getCompletionsAtPosition(fileName, position, options, formattingSettings);
|
|
43
|
+
if (result) {
|
|
44
|
+
// filter __VLS_
|
|
45
|
+
result.entries = result.entries.filter(entry => !entry.name.includes('__VLS_')
|
|
46
|
+
&& !entry.labelDetails?.description?.includes('__VLS_'));
|
|
47
|
+
// modify label
|
|
48
|
+
for (const item of result.entries) {
|
|
49
|
+
if (item.source) {
|
|
50
|
+
const originalName = item.name;
|
|
51
|
+
for (const vueExt of vueOptions.extensions) {
|
|
52
|
+
const suffix = (0, shared_1.capitalize)(vueExt.slice(1)); // .vue -> Vue
|
|
53
|
+
if (item.source.endsWith(vueExt) && item.name.endsWith(suffix)) {
|
|
54
|
+
item.name = (0, shared_1.capitalize)(item.name.slice(0, -suffix.length));
|
|
55
|
+
if (item.insertText) {
|
|
56
|
+
// #2286
|
|
57
|
+
item.insertText = item.insertText.replace(`${suffix}$1`, '$1');
|
|
58
|
+
}
|
|
59
|
+
if (item.data) {
|
|
60
|
+
// @ts-expect-error
|
|
61
|
+
item.data.__isComponentAutoImport = {
|
|
62
|
+
ext: vueExt,
|
|
63
|
+
suffix,
|
|
64
|
+
originalName,
|
|
65
|
+
newName: item.insertText,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (item.data) {
|
|
72
|
+
// @ts-expect-error
|
|
73
|
+
item.data.__isAutoImport = {
|
|
74
|
+
fileName,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function getCompletionEntryDetails(language, asScriptId, getCompletionEntryDetails) {
|
|
84
|
+
return (...args) => {
|
|
85
|
+
const details = getCompletionEntryDetails(...args);
|
|
86
|
+
// modify import statement
|
|
87
|
+
// @ts-expect-error
|
|
88
|
+
if (args[6]?.__isComponentAutoImport) {
|
|
89
|
+
// @ts-expect-error
|
|
90
|
+
const { ext, suffix, originalName, newName } = args[6]?.__isComponentAutoImport;
|
|
91
|
+
for (const codeAction of details?.codeActions ?? []) {
|
|
92
|
+
for (const change of codeAction.changes) {
|
|
93
|
+
for (const textChange of change.textChanges) {
|
|
94
|
+
textChange.newText = textChange.newText.replace('import ' + originalName + ' from ', 'import ' + newName + ' from ');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// @ts-expect-error
|
|
100
|
+
if (args[6]?.__isAutoImport) {
|
|
101
|
+
// @ts-expect-error
|
|
102
|
+
const { fileName } = args[6]?.__isAutoImport;
|
|
103
|
+
const sourceScript = language.scripts.get(asScriptId(fileName));
|
|
104
|
+
if (sourceScript?.generated?.root instanceof language_core_1.VueVirtualCode) {
|
|
105
|
+
const sfc = sourceScript.generated.root.vueSfc;
|
|
106
|
+
if (!sfc?.descriptor.script && !sfc?.descriptor.scriptSetup) {
|
|
107
|
+
for (const codeAction of details?.codeActions ?? []) {
|
|
108
|
+
for (const change of codeAction.changes) {
|
|
109
|
+
for (const textChange of change.textChanges) {
|
|
110
|
+
textChange.newText = `<script setup lang="ts">${textChange.newText}</script>\n\n`;
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return details;
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function getCodeFixesAtPosition(getCodeFixesAtPosition) {
|
|
124
|
+
return (...args) => {
|
|
125
|
+
let result = getCodeFixesAtPosition(...args);
|
|
126
|
+
// filter __VLS_
|
|
127
|
+
result = result.filter(entry => !entry.description.includes('__VLS_'));
|
|
128
|
+
return result;
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function getDefinitionAndBoundSpan(ts, language, languageService, vueOptions, asScriptId, getDefinitionAndBoundSpan) {
|
|
132
|
+
return (fileName, position) => {
|
|
133
|
+
const result = getDefinitionAndBoundSpan(fileName, position);
|
|
134
|
+
if (!result?.definitions?.length) {
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
const program = languageService.getProgram();
|
|
138
|
+
const sourceScript = language.scripts.get(asScriptId(fileName));
|
|
139
|
+
if (!sourceScript?.generated) {
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
const root = sourceScript.generated.root;
|
|
143
|
+
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
if (!root.sfc.template
|
|
147
|
+
|| position < root.sfc.template.startTagEnd
|
|
148
|
+
|| position > root.sfc.template.endTagStart) {
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
const definitions = new Set(result.definitions);
|
|
152
|
+
const skippedDefinitions = [];
|
|
153
|
+
for (const definition of result.definitions) {
|
|
154
|
+
if (vueOptions.extensions.some(ext => definition.fileName.endsWith(ext))) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
const sourceFile = program.getSourceFile(definition.fileName);
|
|
158
|
+
if (!sourceFile) {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
visit(sourceFile, definition, sourceFile);
|
|
162
|
+
}
|
|
163
|
+
for (const definition of skippedDefinitions) {
|
|
164
|
+
definitions.delete(definition);
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
definitions: [...definitions],
|
|
168
|
+
textSpan: result.textSpan,
|
|
169
|
+
};
|
|
170
|
+
function visit(node, definition, sourceFile) {
|
|
171
|
+
if (ts.isPropertySignature(node) && node.type) {
|
|
172
|
+
proxy(node.name, node.type, definition, sourceFile);
|
|
173
|
+
}
|
|
174
|
+
else if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.type && !node.initializer) {
|
|
175
|
+
proxy(node.name, node.type, definition, sourceFile);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
ts.forEachChild(node, child => visit(child, definition, sourceFile));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function proxy(name, type, definition, sourceFile) {
|
|
182
|
+
const { textSpan, fileName } = definition;
|
|
183
|
+
const start = name.getStart(sourceFile);
|
|
184
|
+
const end = name.getEnd();
|
|
185
|
+
if (start !== textSpan.start || end - start !== textSpan.length) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (!ts.isIndexedAccessTypeNode(type)) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
const pos = type.indexType.getStart(sourceFile);
|
|
192
|
+
const res = getDefinitionAndBoundSpan(fileName, pos);
|
|
193
|
+
if (res?.definitions?.length) {
|
|
194
|
+
for (const definition of res.definitions) {
|
|
195
|
+
definitions.add(definition);
|
|
196
|
+
}
|
|
197
|
+
skippedDefinitions.push(definition);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function getQuickInfoAtPosition(ts, languageService, getQuickInfoAtPosition) {
|
|
203
|
+
return (...args) => {
|
|
204
|
+
const result = getQuickInfoAtPosition(...args);
|
|
205
|
+
if (result && result.documentation?.length === 1 && result.documentation[0].text.startsWith('__VLS_emit,')) {
|
|
206
|
+
const [_, emitVarName, eventName] = result.documentation[0].text.split(',');
|
|
207
|
+
const program = languageService.getProgram();
|
|
208
|
+
const typeChecker = program.getTypeChecker();
|
|
209
|
+
const sourceFile = program.getSourceFile(args[0]);
|
|
210
|
+
result.documentation = undefined;
|
|
211
|
+
let symbolNode;
|
|
212
|
+
sourceFile?.forEachChild(function visit(node) {
|
|
213
|
+
if (ts.isIdentifier(node) && node.text === emitVarName) {
|
|
214
|
+
symbolNode = node;
|
|
215
|
+
}
|
|
216
|
+
if (symbolNode) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
ts.forEachChild(node, visit);
|
|
220
|
+
});
|
|
221
|
+
if (symbolNode) {
|
|
222
|
+
const emitSymbol = typeChecker.getSymbolAtLocation(symbolNode);
|
|
223
|
+
if (emitSymbol) {
|
|
224
|
+
const type = typeChecker.getTypeOfSymbolAtLocation(emitSymbol, symbolNode);
|
|
225
|
+
const calls = type.getCallSignatures();
|
|
226
|
+
for (const call of calls) {
|
|
227
|
+
const callEventName = typeChecker.getTypeOfSymbolAtLocation(call.parameters[0], symbolNode).value;
|
|
228
|
+
call.getJsDocTags();
|
|
229
|
+
if (callEventName === eventName) {
|
|
230
|
+
result.documentation = call.getDocumentationComment(typeChecker);
|
|
231
|
+
result.tags = call.getJsDocTags();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return result;
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function getSemanticDiagnostics(ts, language, languageService, asScriptId, getSemanticDiagnostics) {
|
|
241
|
+
return (fileName) => {
|
|
242
|
+
const result = getSemanticDiagnostics(fileName);
|
|
243
|
+
const program = languageService.getProgram();
|
|
244
|
+
const sourceScript = language.scripts.get(asScriptId(fileName));
|
|
245
|
+
if (!sourceScript?.generated) {
|
|
246
|
+
return result;
|
|
247
|
+
}
|
|
248
|
+
const root = sourceScript.generated.root;
|
|
249
|
+
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
const { template } = root.sfc;
|
|
253
|
+
if (!template) {
|
|
254
|
+
return result;
|
|
255
|
+
}
|
|
256
|
+
const sourceFile = program.getSourceFile(fileName);
|
|
257
|
+
if (!sourceFile) {
|
|
258
|
+
return result;
|
|
259
|
+
}
|
|
260
|
+
const additionalResult = [];
|
|
261
|
+
const { commentDirectives } = template;
|
|
262
|
+
for (const dir of commentDirectives) {
|
|
263
|
+
const start = template.startTagEnd + dir.start;
|
|
264
|
+
const end = template.startTagEnd + dir.end;
|
|
265
|
+
const rangeStart = template.startTagEnd + dir.rangeStart;
|
|
266
|
+
const rangeEnd = template.startTagEnd + dir.rangeEnd;
|
|
267
|
+
if (dir.name === 'expect-error') {
|
|
268
|
+
let containError = false;
|
|
269
|
+
for (let i = 0; i < result.length; i++) {
|
|
270
|
+
const diag = result[i];
|
|
271
|
+
if (diag.start >= rangeStart && diag.start + diag.length <= rangeEnd) {
|
|
272
|
+
containError = true;
|
|
273
|
+
result.splice(i, 1);
|
|
274
|
+
i--;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (!containError) {
|
|
278
|
+
additionalResult.push({
|
|
279
|
+
category: ts.DiagnosticCategory.Error,
|
|
280
|
+
code: 2578,
|
|
281
|
+
file: sourceFile,
|
|
282
|
+
start,
|
|
283
|
+
length: end - start,
|
|
284
|
+
messageText: `Unused '@vue-expect-error' directive.`,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
else if (dir.name === 'ignore') {
|
|
289
|
+
for (let i = 0; i < result.length; i++) {
|
|
290
|
+
const diag = result[i];
|
|
291
|
+
if (diag.start >= rangeStart && diag.start + diag.length <= rangeEnd) {
|
|
292
|
+
result.splice(i, 1);
|
|
293
|
+
i--;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return [...result, ...additionalResult];
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function getEncodedSemanticClassifications(ts, language, languageService, asScriptId, getEncodedSemanticClassifications) {
|
|
302
|
+
return (filePath, span, format) => {
|
|
303
|
+
const fileName = filePath.replace(windowsPathReg, '/');
|
|
304
|
+
const result = getEncodedSemanticClassifications(fileName, span, format);
|
|
305
|
+
const sourceScript = language.scripts.get(asScriptId(fileName));
|
|
306
|
+
const root = sourceScript?.generated?.root;
|
|
307
|
+
if (root instanceof language_core_1.VueVirtualCode) {
|
|
308
|
+
const { template } = root.sfc;
|
|
309
|
+
if (template) {
|
|
310
|
+
for (const componentSpan of getComponentSpans.call({ typescript: ts, languageService }, root, template, {
|
|
311
|
+
start: span.start - template.startTagEnd,
|
|
312
|
+
length: span.length,
|
|
313
|
+
})) {
|
|
314
|
+
result.spans.push(componentSpan.start + template.startTagEnd, componentSpan.length, 256 // class
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return result;
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
function getComponentSpans(vueCode, template, spanTemplateRange) {
|
|
323
|
+
const { typescript: ts, languageService } = this;
|
|
324
|
+
const result = [];
|
|
325
|
+
const validComponentNames = (0, getComponentNames_1._getComponentNames)(ts, languageService, vueCode);
|
|
326
|
+
const elements = new Set((0, getComponentNames_1._getElementNames)(ts, languageService, vueCode));
|
|
327
|
+
const components = new Set([
|
|
328
|
+
...validComponentNames,
|
|
329
|
+
...validComponentNames.map(language_core_1.hyphenateTag),
|
|
330
|
+
]);
|
|
331
|
+
if (template.ast) {
|
|
332
|
+
for (const node of (0, language_core_1.forEachTemplateChild)(template.ast)) {
|
|
333
|
+
if (node.loc.end.offset <= spanTemplateRange.start || node.loc.start.offset >= (spanTemplateRange.start + spanTemplateRange.length)) {
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
if (components.has(node.tag) && !elements.has(node.tag)) {
|
|
337
|
+
let start = node.loc.start.offset;
|
|
338
|
+
if (template.lang === 'html') {
|
|
339
|
+
start += '<'.length;
|
|
340
|
+
}
|
|
341
|
+
result.push({
|
|
342
|
+
start,
|
|
343
|
+
length: node.tag.length,
|
|
344
|
+
});
|
|
345
|
+
if (template.lang === 'html' && !node.isSelfClosing) {
|
|
346
|
+
result.push({
|
|
347
|
+
start: node.loc.start.offset + node.loc.source.lastIndexOf(node.tag),
|
|
348
|
+
length: node.tag.length,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return result;
|
|
355
|
+
}
|
|
356
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -1,29 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getElementAttrs = getElementAttrs;
|
|
4
|
-
const
|
|
4
|
+
const language_core_1 = require("@vue/language-core");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
5
6
|
function getElementAttrs(fileName, tagName) {
|
|
6
7
|
const { typescript: ts, language, languageService, getFileId } = this;
|
|
7
8
|
const volarFile = language.scripts.get(getFileId(fileName));
|
|
8
|
-
if (!(volarFile?.generated?.root instanceof
|
|
9
|
+
if (!(volarFile?.generated?.root instanceof language_core_1.VueVirtualCode)) {
|
|
9
10
|
return;
|
|
10
11
|
}
|
|
12
|
+
const vueCode = volarFile.generated.root;
|
|
11
13
|
const program = languageService.getProgram();
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
.filter(ts.isTypeAliasDeclaration)
|
|
17
|
-
.find(node => node.name.getText() === '__VLS_IntrinsicElementsCompletion');
|
|
18
|
-
if (checker && typeNode) {
|
|
19
|
-
const type = checker.getTypeFromTypeNode(typeNode.type);
|
|
20
|
-
const el = type.getProperty(tagName);
|
|
21
|
-
if (el) {
|
|
22
|
-
const attrs = checker.getTypeOfSymbolAtLocation(el, typeNode).getProperties();
|
|
23
|
-
return attrs.map(c => c.name);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
14
|
+
const checker = program.getTypeChecker();
|
|
15
|
+
const elements = (0, utils_1.getVariableType)(ts, languageService, vueCode, '__VLS_elements');
|
|
16
|
+
if (!elements) {
|
|
17
|
+
return [];
|
|
26
18
|
}
|
|
27
|
-
|
|
19
|
+
const elementType = elements.type.getProperty(tagName);
|
|
20
|
+
if (!elementType) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
const attrs = checker.getTypeOfSymbol(elementType).getProperties();
|
|
24
|
+
return attrs.map(c => c.name);
|
|
28
25
|
}
|
|
29
26
|
//# sourceMappingURL=getElementAttrs.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { VueVirtualCode } from '@vue/language-core';
|
|
2
|
+
import type * as ts from 'typescript';
|
|
3
|
+
import type { RequestContext } from './types';
|
|
4
|
+
export declare function getElementNames(this: RequestContext, fileName: string): string[] | undefined;
|
|
5
|
+
export declare function _getElementNames(ts: typeof import('typescript'), tsLs: ts.LanguageService, vueCode: VueVirtualCode): string[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getElementNames = getElementNames;
|
|
4
|
+
exports._getElementNames = _getElementNames;
|
|
5
|
+
const language_core_1 = require("@vue/language-core");
|
|
6
|
+
const utils_1 = require("./utils");
|
|
7
|
+
function getElementNames(fileName) {
|
|
8
|
+
const { typescript: ts, language, languageService, getFileId } = this;
|
|
9
|
+
const volarFile = language.scripts.get(getFileId(fileName));
|
|
10
|
+
if (!(volarFile?.generated?.root instanceof language_core_1.VueVirtualCode)) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const vueCode = volarFile.generated.root;
|
|
14
|
+
return _getElementNames(ts, languageService, vueCode);
|
|
15
|
+
}
|
|
16
|
+
function _getElementNames(ts, tsLs, vueCode) {
|
|
17
|
+
return (0, utils_1.getVariableType)(ts, tsLs, vueCode, '__VLS_elements')
|
|
18
|
+
?.type
|
|
19
|
+
?.getProperties()
|
|
20
|
+
.map(c => c.name)
|
|
21
|
+
?? [];
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=getElementNames.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSlotNames = getSlotNames;
|
|
4
|
+
const language_core_1 = require("@vue/language-core");
|
|
5
|
+
function getSlotNames(fileName) {
|
|
6
|
+
const { typescript: ts, language, languageService, getFileId } = this;
|
|
7
|
+
const sourceScript = language.scripts.get(getFileId(fileName));
|
|
8
|
+
if (!sourceScript?.generated) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const root = sourceScript.generated.root;
|
|
12
|
+
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const program = languageService.getProgram();
|
|
16
|
+
const tsSourceFile = program.getSourceFile(fileName);
|
|
17
|
+
if (!tsSourceFile) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const checker = program.getTypeChecker();
|
|
21
|
+
const typeNode = tsSourceFile.statements
|
|
22
|
+
.filter(ts.isTypeAliasDeclaration)
|
|
23
|
+
.find(node => node.name.getText() === '__VLS_Slots');
|
|
24
|
+
if (typeNode) {
|
|
25
|
+
const attrs = checker.getTypeFromTypeNode(typeNode.type).getProperties();
|
|
26
|
+
return attrs.map(attr => attr.name);
|
|
27
|
+
}
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=getSlotNames.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type ToRequest<T extends (...args: any) => any> = (...args: Parameters<T>) => Promise<ReturnType<T> | null | undefined>;
|
|
2
|
+
export type Requests = {
|
|
3
|
+
collectExtractProps: ToRequest<typeof import('./collectExtractProps.js')['collectExtractProps']>;
|
|
4
|
+
getImportPathForFile: ToRequest<typeof import('./getImportPathForFile.js')['getImportPathForFile']>;
|
|
5
|
+
getPropertiesAtLocation: ToRequest<typeof import('./getPropertiesAtLocation.js')['getPropertiesAtLocation']>;
|
|
6
|
+
getComponentNames: ToRequest<typeof import('./getComponentNames.js')['getComponentNames']>;
|
|
7
|
+
getComponentProps: ToRequest<typeof import('./getComponentProps.js')['getComponentProps']>;
|
|
8
|
+
getComponentEvents: ToRequest<typeof import('./getComponentEvents.js')['getComponentEvents']>;
|
|
9
|
+
getComponentDirectives: ToRequest<typeof import('./getComponentDirectives.js')['getComponentDirectives']>;
|
|
10
|
+
getElementAttrs: ToRequest<typeof import('./getElementAttrs.js')['getElementAttrs']>;
|
|
11
|
+
getElementNames: ToRequest<typeof import('./getElementNames.js')['getElementNames']>;
|
|
12
|
+
getQuickInfoAtPosition: ToRequest<(fileName: string, position: {
|
|
13
|
+
line: number;
|
|
14
|
+
character: number;
|
|
15
|
+
}) => string>;
|
|
16
|
+
};
|
|
17
|
+
export {};
|
package/lib/requests/utils.js
CHANGED
|
@@ -36,11 +36,11 @@ function getSelfComponentName(fileName) {
|
|
|
36
36
|
}
|
|
37
37
|
function getVariableType(ts, languageService, vueCode, name) {
|
|
38
38
|
const program = languageService.getProgram();
|
|
39
|
-
|
|
40
|
-
if (tsSourceFile
|
|
41
|
-
const node = searchVariableDeclarationNode(ts, tsSourceFile, name);
|
|
39
|
+
const tsSourceFile = program.getSourceFile(vueCode.fileName);
|
|
40
|
+
if (tsSourceFile) {
|
|
42
41
|
const checker = program.getTypeChecker();
|
|
43
|
-
|
|
42
|
+
const node = searchVariableDeclarationNode(ts, tsSourceFile, name);
|
|
43
|
+
if (node) {
|
|
44
44
|
return {
|
|
45
45
|
node: node,
|
|
46
46
|
type: checker.getTypeAtLocation(node),
|
|
@@ -49,15 +49,15 @@ function getVariableType(ts, languageService, vueCode, name) {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
function searchVariableDeclarationNode(ts, sourceFile, name) {
|
|
52
|
-
let
|
|
52
|
+
let result;
|
|
53
53
|
walk(sourceFile);
|
|
54
|
-
return
|
|
54
|
+
return result;
|
|
55
55
|
function walk(node) {
|
|
56
|
-
if (
|
|
56
|
+
if (result) {
|
|
57
57
|
return;
|
|
58
58
|
}
|
|
59
59
|
else if (ts.isVariableDeclaration(node) && node.name.getText() === name) {
|
|
60
|
-
|
|
60
|
+
result = node;
|
|
61
61
|
}
|
|
62
62
|
else {
|
|
63
63
|
node.forEachChild(walk);
|
package/lib/server.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Language } from '@vue/language-core';
|
|
2
2
|
import type * as ts from 'typescript';
|
|
3
|
-
export type RequestType = 'containsFile' | 'projectInfo' | 'collectExtractProps' | 'getImportPathForFile' | 'getPropertiesAtLocation' | 'getQuickInfoAtPosition' | 'subscribeComponentProps' | 'getComponentEvents' | 'getComponentDirectives' | 'getElementAttrs';
|
|
3
|
+
export type RequestType = 'containsFile' | 'projectInfo' | 'collectExtractProps' | 'getImportPathForFile' | 'getPropertiesAtLocation' | 'getQuickInfoAtPosition' | 'subscribeComponentProps' | 'getComponentEvents' | 'getComponentDirectives' | 'getElementAttrs' | 'getSlotNames';
|
|
4
4
|
export type NotificationType = 'componentNamesUpdated' | 'componentPropsUpdated';
|
|
5
5
|
export type RequestData = [
|
|
6
6
|
seq: number,
|
package/lib/server.js
CHANGED
|
@@ -13,6 +13,7 @@ const getElementAttrs_1 = require("./requests/getElementAttrs");
|
|
|
13
13
|
const getImportPathForFile_1 = require("./requests/getImportPathForFile");
|
|
14
14
|
const getPropertiesAtLocation_1 = require("./requests/getPropertiesAtLocation");
|
|
15
15
|
const getQuickInfoAtPosition_1 = require("./requests/getQuickInfoAtPosition");
|
|
16
|
+
const getSlotNames_1 = require("./requests/getSlotNames");
|
|
16
17
|
const utils_1 = require("./utils");
|
|
17
18
|
async function startNamedPipeServer(ts, info, language, projectKind) {
|
|
18
19
|
let lastProjectVersion;
|
|
@@ -193,6 +194,9 @@ async function startNamedPipeServer(ts, info, language, projectKind) {
|
|
|
193
194
|
else if (requestType === 'getElementAttrs') {
|
|
194
195
|
return getElementAttrs_1.getElementAttrs.apply(requestContext, args);
|
|
195
196
|
}
|
|
197
|
+
else if (requestType === 'getSlotNames') {
|
|
198
|
+
return getSlotNames_1.getSlotNames.apply(requestContext, args);
|
|
199
|
+
}
|
|
196
200
|
console.warn('[Vue Named Pipe Server] Unknown request:', requestType);
|
|
197
201
|
debugger;
|
|
198
202
|
return undefined;
|
package/lib/utils.js
CHANGED
|
@@ -153,9 +153,7 @@ class NamedPipeServer {
|
|
|
153
153
|
else if (type === 'componentPropsUpdated') {
|
|
154
154
|
const components = this.componentNamesAndProps.get(fileName) ?? {};
|
|
155
155
|
const [name, props] = data;
|
|
156
|
-
|
|
157
|
-
components[name] = props;
|
|
158
|
-
}
|
|
156
|
+
components[name] = props;
|
|
159
157
|
}
|
|
160
158
|
else {
|
|
161
159
|
console.error('Unknown notification type:', type);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vue/typescript-plugin",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0-alpha.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"**/*.js",
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@volar/typescript": "~2.4.11",
|
|
17
|
-
"@vue/language-core": "
|
|
17
|
+
"@vue/language-core": "3.0.0-alpha.2",
|
|
18
18
|
"@vue/shared": "^3.5.0"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "^22.10.4"
|
|
22
22
|
},
|
|
23
|
-
"gitHead": "
|
|
23
|
+
"gitHead": "79247b7c24b7202ec676723440fdb36c38e6d450"
|
|
24
24
|
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import * as vue from '@vue/language-core';
|
|
2
|
-
import type * as ts from 'typescript';
|
|
3
|
-
import type { RequestContext } from './types';
|
|
4
|
-
export declare function getComponentProps(this: RequestContext, fileName: string, tag: string): {
|
|
5
|
-
name: string;
|
|
6
|
-
required?: true;
|
|
7
|
-
commentMarkdown?: string;
|
|
8
|
-
}[] | undefined;
|
|
9
|
-
export declare function getComponentEvents(this: RequestContext, fileName: string, tag: string): string[] | undefined;
|
|
10
|
-
export declare function getTemplateContextProps(this: RequestContext, fileName: string): string[] | undefined;
|
|
11
|
-
export declare function getComponentNames(this: RequestContext, fileName: string): string[] | undefined;
|
|
12
|
-
export declare function _getComponentNames(ts: typeof import('typescript'), tsLs: ts.LanguageService, vueCode: vue.VueVirtualCode): string[];
|
|
13
|
-
export declare function getElementAttrs(this: RequestContext, fileName: string, tagName: string): string[] | undefined;
|
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getComponentProps = getComponentProps;
|
|
4
|
-
exports.getComponentEvents = getComponentEvents;
|
|
5
|
-
exports.getTemplateContextProps = getTemplateContextProps;
|
|
6
|
-
exports.getComponentNames = getComponentNames;
|
|
7
|
-
exports._getComponentNames = _getComponentNames;
|
|
8
|
-
exports.getElementAttrs = getElementAttrs;
|
|
9
|
-
const vue = require("@vue/language-core");
|
|
10
|
-
const shared_1 = require("@vue/shared");
|
|
11
|
-
function getComponentProps(fileName, tag) {
|
|
12
|
-
const { typescript: ts, language, languageService, getFileId } = this;
|
|
13
|
-
const volarFile = language.scripts.get(getFileId(fileName));
|
|
14
|
-
if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
const vueCode = volarFile.generated.root;
|
|
18
|
-
const program = languageService.getProgram();
|
|
19
|
-
const checker = program.getTypeChecker();
|
|
20
|
-
const components = getVariableType(ts, languageService, vueCode, '__VLS_components');
|
|
21
|
-
if (!components) {
|
|
22
|
-
return [];
|
|
23
|
-
}
|
|
24
|
-
const name = tag.split('.');
|
|
25
|
-
let componentSymbol = components.type.getProperty(name[0])
|
|
26
|
-
?? components.type.getProperty((0, shared_1.camelize)(name[0]))
|
|
27
|
-
?? components.type.getProperty((0, shared_1.capitalize)((0, shared_1.camelize)(name[0])));
|
|
28
|
-
if (!componentSymbol) {
|
|
29
|
-
return [];
|
|
30
|
-
}
|
|
31
|
-
let componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
|
|
32
|
-
for (let i = 1; i < name.length; i++) {
|
|
33
|
-
componentSymbol = componentType.getProperty(name[i]);
|
|
34
|
-
if (componentSymbol) {
|
|
35
|
-
componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
return [];
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
const result = new Map();
|
|
42
|
-
for (const sig of componentType.getCallSignatures()) {
|
|
43
|
-
const propParam = sig.parameters[0];
|
|
44
|
-
if (propParam) {
|
|
45
|
-
const propsType = checker.getTypeOfSymbolAtLocation(propParam, components.node);
|
|
46
|
-
const props = propsType.getProperties();
|
|
47
|
-
for (const prop of props) {
|
|
48
|
-
const name = prop.name;
|
|
49
|
-
const required = !(prop.flags & ts.SymbolFlags.Optional) || undefined;
|
|
50
|
-
const commentMarkdown = generateCommentMarkdown(prop.getDocumentationComment(checker), prop.getJsDocTags()) || undefined;
|
|
51
|
-
result.set(name, { name, required, commentMarkdown });
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
for (const sig of componentType.getConstructSignatures()) {
|
|
56
|
-
const instanceType = sig.getReturnType();
|
|
57
|
-
const propsSymbol = instanceType.getProperty('$props');
|
|
58
|
-
if (propsSymbol) {
|
|
59
|
-
const propsType = checker.getTypeOfSymbolAtLocation(propsSymbol, components.node);
|
|
60
|
-
const props = propsType.getProperties();
|
|
61
|
-
for (const prop of props) {
|
|
62
|
-
if (prop.flags & ts.SymbolFlags.Method) { // #2443
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
const name = prop.name;
|
|
66
|
-
const required = !(prop.flags & ts.SymbolFlags.Optional) || undefined;
|
|
67
|
-
const commentMarkdown = generateCommentMarkdown(prop.getDocumentationComment(checker), prop.getJsDocTags()) || undefined;
|
|
68
|
-
result.set(name, { name, required, commentMarkdown });
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return [...result.values()];
|
|
73
|
-
}
|
|
74
|
-
function getComponentEvents(fileName, tag) {
|
|
75
|
-
const { typescript: ts, language, languageService, getFileId } = this;
|
|
76
|
-
const volarFile = language.scripts.get(getFileId(fileName));
|
|
77
|
-
if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const vueCode = volarFile.generated.root;
|
|
81
|
-
const program = languageService.getProgram();
|
|
82
|
-
const checker = program.getTypeChecker();
|
|
83
|
-
const components = getVariableType(ts, languageService, vueCode, '__VLS_components');
|
|
84
|
-
if (!components) {
|
|
85
|
-
return [];
|
|
86
|
-
}
|
|
87
|
-
const name = tag.split('.');
|
|
88
|
-
let componentSymbol = components.type.getProperty(name[0]);
|
|
89
|
-
if (!componentSymbol) {
|
|
90
|
-
componentSymbol = components.type.getProperty((0, shared_1.camelize)(name[0]))
|
|
91
|
-
?? components.type.getProperty((0, shared_1.capitalize)((0, shared_1.camelize)(name[0])));
|
|
92
|
-
}
|
|
93
|
-
if (!componentSymbol) {
|
|
94
|
-
return [];
|
|
95
|
-
}
|
|
96
|
-
let componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
|
|
97
|
-
for (let i = 1; i < name.length; i++) {
|
|
98
|
-
componentSymbol = componentType.getProperty(name[i]);
|
|
99
|
-
if (componentSymbol) {
|
|
100
|
-
componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
return [];
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
const result = new Set();
|
|
107
|
-
// for (const sig of componentType.getCallSignatures()) {
|
|
108
|
-
// const emitParam = sig.parameters[1];
|
|
109
|
-
// if (emitParam) {
|
|
110
|
-
// // TODO
|
|
111
|
-
// }
|
|
112
|
-
// }
|
|
113
|
-
for (const sig of componentType.getConstructSignatures()) {
|
|
114
|
-
const instanceType = sig.getReturnType();
|
|
115
|
-
const emitSymbol = instanceType.getProperty('$emit');
|
|
116
|
-
if (emitSymbol) {
|
|
117
|
-
const emitType = checker.getTypeOfSymbolAtLocation(emitSymbol, components.node);
|
|
118
|
-
for (const call of emitType.getCallSignatures()) {
|
|
119
|
-
const eventNameParamSymbol = call.parameters[0];
|
|
120
|
-
if (eventNameParamSymbol) {
|
|
121
|
-
const eventNameParamType = checker.getTypeOfSymbolAtLocation(eventNameParamSymbol, components.node);
|
|
122
|
-
if (eventNameParamType.isStringLiteral()) {
|
|
123
|
-
result.add(eventNameParamType.value);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return [...result];
|
|
130
|
-
}
|
|
131
|
-
function getTemplateContextProps(fileName) {
|
|
132
|
-
const { typescript: ts, language, languageService, getFileId } = this;
|
|
133
|
-
const volarFile = language.scripts.get(getFileId(fileName));
|
|
134
|
-
if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
const vueCode = volarFile.generated.root;
|
|
138
|
-
return getVariableType(ts, languageService, vueCode, '__VLS_ctx')
|
|
139
|
-
?.type
|
|
140
|
-
?.getProperties()
|
|
141
|
-
.map(c => c.name);
|
|
142
|
-
}
|
|
143
|
-
function getComponentNames(fileName) {
|
|
144
|
-
const { typescript: ts, language, languageService, getFileId } = this;
|
|
145
|
-
const volarFile = language.scripts.get(getFileId(fileName));
|
|
146
|
-
if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
const vueCode = volarFile.generated.root;
|
|
150
|
-
return getVariableType(ts, languageService, vueCode, '__VLS_components')
|
|
151
|
-
?.type
|
|
152
|
-
?.getProperties()
|
|
153
|
-
.map(c => c.name)
|
|
154
|
-
.filter(entry => !entry.includes('$') && !entry.startsWith('_'))
|
|
155
|
-
?? [];
|
|
156
|
-
}
|
|
157
|
-
function _getComponentNames(ts, tsLs, vueCode) {
|
|
158
|
-
return getVariableType(ts, tsLs, vueCode, '__VLS_components')
|
|
159
|
-
?.type
|
|
160
|
-
?.getProperties()
|
|
161
|
-
.map(c => c.name)
|
|
162
|
-
.filter(entry => !entry.includes('$') && !entry.startsWith('_'))
|
|
163
|
-
?? [];
|
|
164
|
-
}
|
|
165
|
-
function getElementAttrs(fileName, tagName) {
|
|
166
|
-
const { typescript: ts, language, languageService, getFileId } = this;
|
|
167
|
-
const volarFile = language.scripts.get(getFileId(fileName));
|
|
168
|
-
if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
const program = languageService.getProgram();
|
|
172
|
-
let tsSourceFile;
|
|
173
|
-
if (tsSourceFile = program.getSourceFile(fileName)) {
|
|
174
|
-
const typeNode = tsSourceFile.statements.find((node) => ts.isTypeAliasDeclaration(node) && node.name.getText() === '__VLS_IntrinsicElementsCompletion');
|
|
175
|
-
const checker = program.getTypeChecker();
|
|
176
|
-
if (checker && typeNode) {
|
|
177
|
-
const type = checker.getTypeFromTypeNode(typeNode.type);
|
|
178
|
-
const el = type.getProperty(tagName);
|
|
179
|
-
if (el) {
|
|
180
|
-
const attrs = checker.getTypeOfSymbolAtLocation(el, typeNode).getProperties();
|
|
181
|
-
return attrs.map(c => c.name);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
return [];
|
|
186
|
-
}
|
|
187
|
-
function getVariableType(ts, languageService, vueCode, name) {
|
|
188
|
-
const program = languageService.getProgram();
|
|
189
|
-
let tsSourceFile;
|
|
190
|
-
if (tsSourceFile = program.getSourceFile(vueCode.fileName)) {
|
|
191
|
-
const node = searchVariableDeclarationNode(ts, tsSourceFile, name);
|
|
192
|
-
const checker = program.getTypeChecker();
|
|
193
|
-
if (checker && node) {
|
|
194
|
-
return {
|
|
195
|
-
node: node,
|
|
196
|
-
type: checker.getTypeAtLocation(node),
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
function searchVariableDeclarationNode(ts, sourceFile, name) {
|
|
202
|
-
let componentsNode;
|
|
203
|
-
walk(sourceFile);
|
|
204
|
-
return componentsNode;
|
|
205
|
-
function walk(node) {
|
|
206
|
-
if (componentsNode) {
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
else if (ts.isVariableDeclaration(node) && node.name.getText() === name) {
|
|
210
|
-
componentsNode = node;
|
|
211
|
-
}
|
|
212
|
-
else {
|
|
213
|
-
node.forEachChild(walk);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
function generateCommentMarkdown(parts, jsDocTags) {
|
|
218
|
-
const parsedComment = _symbolDisplayPartsToMarkdown(parts);
|
|
219
|
-
const parsedJsDoc = _jsDocTagInfoToMarkdown(jsDocTags);
|
|
220
|
-
let result = [parsedComment, parsedJsDoc].filter(str => !!str).join('\n\n');
|
|
221
|
-
return result;
|
|
222
|
-
}
|
|
223
|
-
function _symbolDisplayPartsToMarkdown(parts) {
|
|
224
|
-
return parts.map(part => {
|
|
225
|
-
switch (part.kind) {
|
|
226
|
-
case 'keyword':
|
|
227
|
-
return `\`${part.text}\``;
|
|
228
|
-
case 'functionName':
|
|
229
|
-
return `**${part.text}**`;
|
|
230
|
-
default:
|
|
231
|
-
return part.text;
|
|
232
|
-
}
|
|
233
|
-
}).join('');
|
|
234
|
-
}
|
|
235
|
-
function _jsDocTagInfoToMarkdown(jsDocTags) {
|
|
236
|
-
return jsDocTags.map(tag => {
|
|
237
|
-
const tagName = `*@${tag.name}*`;
|
|
238
|
-
const tagText = tag.text?.map(t => {
|
|
239
|
-
if (t.kind === 'parameterName') {
|
|
240
|
-
return `\`${t.text}\``;
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
243
|
-
return t.text;
|
|
244
|
-
}
|
|
245
|
-
}).join('') || '';
|
|
246
|
-
return `${tagName} ${tagText}`;
|
|
247
|
-
}).join('\n\n');
|
|
248
|
-
}
|
|
249
|
-
//# sourceMappingURL=componentInfos.js.map
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getComponentInfo = getComponentInfo;
|
|
4
|
-
const shared_1 = require("@vue/shared");
|
|
5
|
-
const getComponentEvents_1 = require("./getComponentEvents");
|
|
6
|
-
const getComponentProps_1 = require("./getComponentProps");
|
|
7
|
-
const globalProperties = [
|
|
8
|
-
'key',
|
|
9
|
-
'ref',
|
|
10
|
-
'ref_for',
|
|
11
|
-
'ref_key',
|
|
12
|
-
'class',
|
|
13
|
-
'style'
|
|
14
|
-
];
|
|
15
|
-
function getComponentInfo(fileName, tag) {
|
|
16
|
-
const props = getComponentProps_1.getComponentProps.call(this, fileName, tag, true)?.filter(({ name }) => !globalProperties.includes(name) && !(0, shared_1.hyphenate)(name).startsWith('on-vnode-'));
|
|
17
|
-
const events = getComponentEvents_1.getComponentEvents.call(this, fileName, tag);
|
|
18
|
-
return {
|
|
19
|
-
props,
|
|
20
|
-
events,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
//# sourceMappingURL=getComponentInfo.js.map
|