@vue/typescript-plugin 2.0.6 → 2.0.7
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/README.md +5 -11
- package/index.js +7 -121
- package/lib/client.d.ts +1 -4
- package/lib/client.js +3 -62
- package/lib/common.d.ts +8 -0
- package/lib/common.js +136 -0
- package/lib/requests/collectExtractProps.d.ts +9 -1
- package/lib/requests/collectExtractProps.js +3 -9
- package/lib/requests/componentInfos.d.ts +33 -5
- package/lib/requests/componentInfos.js +25 -47
- package/lib/requests/getPropertiesAtLocation.d.ts +9 -1
- package/lib/requests/getPropertiesAtLocation.js +3 -9
- package/lib/requests/getQuickInfoAtPosition.d.ts +4 -1
- package/lib/requests/getQuickInfoAtPosition.js +1 -7
- package/lib/server.d.ts +8 -2
- package/lib/server.js +69 -52
- package/lib/utils.d.ts +5 -23
- package/lib/utils.js +79 -9
- package/package.json +4 -4
- package/lib/requests/containsFile.d.ts +0 -1
- package/lib/requests/containsFile.js +0 -9
package/README.md
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
# typescript plugin
|
|
2
2
|
|
|
3
|
-
This is a plug-in for `tsserver` or `typescript-language-server`. It must be
|
|
4
|
-
installed in a file-system location accessible by the language server or in the
|
|
5
|
-
`node_modules` directory of projects being edited.
|
|
3
|
+
This is a plug-in for `tsserver` or `typescript-language-server`. It must be installed in a file-system location accessible by the language server or in the `node_modules` directory of projects being edited.
|
|
6
4
|
|
|
7
|
-
The LSP client must be configured to explicitly enable this plug-in. This is
|
|
8
|
-
done by passing `initializationOptions` with the appropriate [`plugins`]
|
|
9
|
-
configuration to the language server:
|
|
5
|
+
The LSP client must be configured to explicitly enable this plug-in. This is done by passing `initializationOptions` with the appropriate [`plugins`] configuration to the language server:
|
|
10
6
|
|
|
11
7
|
[`plugins`]: https://github.com/typescript-language-server/typescript-language-server/blob/b224b878652438bcdd639137a6b1d1a6630129e4/docs/configuration.md?plain=1#L27-L31
|
|
12
8
|
|
|
@@ -15,16 +11,14 @@ configuration to the language server:
|
|
|
15
11
|
"plugins": [
|
|
16
12
|
{
|
|
17
13
|
"name": "@vue/typescript-plugin",
|
|
18
|
-
"location": "/usr/local/lib/node_modules/@vue/
|
|
19
|
-
"languages": ["
|
|
14
|
+
"location": "/usr/local/lib/node_modules/@vue/language-server",
|
|
15
|
+
"languages": ["vue"],
|
|
20
16
|
},
|
|
21
17
|
],
|
|
22
18
|
},
|
|
23
19
|
```
|
|
24
20
|
|
|
25
|
-
The `languages` field must specify file-types for which the plug-in will be
|
|
26
|
-
enabled. If the plug-in package is installed in the local `node_modules`, the
|
|
27
|
-
`location` field may contain any arbitrary string, but MUST be present.
|
|
21
|
+
The `languages` field must specify file-types for which the plug-in will be enabled. If the plug-in package is installed in the local `node_modules`, the `location` field may contain any arbitrary string, but MUST be present.
|
|
28
22
|
|
|
29
23
|
## Client-specific configuration
|
|
30
24
|
|
package/index.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const decorateLanguageService_1 = require("@volar/typescript/lib/node/decorateLanguageService");
|
|
3
3
|
const decorateLanguageServiceHost_1 = require("@volar/typescript/lib/node/decorateLanguageServiceHost");
|
|
4
|
-
const language_core_1 = require("@vue/language-core");
|
|
5
|
-
const utils_1 = require("./lib/utils");
|
|
6
4
|
const vue = require("@vue/language-core");
|
|
5
|
+
const language_core_1 = require("@vue/language-core");
|
|
6
|
+
const common_1 = require("./lib/common");
|
|
7
7
|
const server_1 = require("./lib/server");
|
|
8
|
-
const componentInfos_1 = require("./lib/requests/componentInfos");
|
|
9
|
-
const shared_1 = require("@vue/shared");
|
|
10
8
|
const windowsPathReg = /\\/g;
|
|
11
9
|
const externalFiles = new WeakMap();
|
|
12
10
|
const projectExternalFileExtensions = new WeakMap();
|
|
@@ -21,7 +19,7 @@ function createLanguageServicePlugin() {
|
|
|
21
19
|
&& !decoratedLanguageServiceHosts.has(info.languageServiceHost)) {
|
|
22
20
|
decoratedLanguageServices.add(info.languageService);
|
|
23
21
|
decoratedLanguageServiceHosts.add(info.languageServiceHost);
|
|
24
|
-
const vueOptions =
|
|
22
|
+
const vueOptions = getVueCompilerOptions();
|
|
25
23
|
const languagePlugin = vue.createVueLanguagePlugin(ts, id => id, fileName => {
|
|
26
24
|
if (info.languageServiceHost.useCaseSensitiveFileNames?.() ?? false) {
|
|
27
25
|
return externalFiles.get(info.project)?.has(fileName) ?? false;
|
|
@@ -52,123 +50,11 @@ function createLanguageServicePlugin() {
|
|
|
52
50
|
}
|
|
53
51
|
});
|
|
54
52
|
projectExternalFileExtensions.set(info.project, extensions);
|
|
55
|
-
|
|
56
|
-
info,
|
|
57
|
-
files,
|
|
58
|
-
ts,
|
|
59
|
-
vueOptions,
|
|
60
|
-
});
|
|
53
|
+
server_1.projects.set(info.project, { info, files, vueOptions });
|
|
61
54
|
(0, decorateLanguageService_1.decorateLanguageService)(files, info.languageService);
|
|
55
|
+
(0, common_1.decorateLanguageServiceForVue)(files, info.languageService, vueOptions, ts, true);
|
|
62
56
|
(0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(files, info.languageServiceHost, ts);
|
|
63
|
-
(0, server_1.startNamedPipeServer)(info.project.projectKind, info.project.getCurrentDirectory());
|
|
64
|
-
const getCompletionsAtPosition = info.languageService.getCompletionsAtPosition;
|
|
65
|
-
const getCompletionEntryDetails = info.languageService.getCompletionEntryDetails;
|
|
66
|
-
const getCodeFixesAtPosition = info.languageService.getCodeFixesAtPosition;
|
|
67
|
-
const getEncodedSemanticClassifications = info.languageService.getEncodedSemanticClassifications;
|
|
68
|
-
info.languageService.getCompletionsAtPosition = (fileName, position, options) => {
|
|
69
|
-
const result = getCompletionsAtPosition(fileName, position, options);
|
|
70
|
-
if (result) {
|
|
71
|
-
// filter __VLS_
|
|
72
|
-
result.entries = result.entries.filter(entry => entry.name.indexOf('__VLS_') === -1
|
|
73
|
-
&& (!entry.labelDetails?.description || entry.labelDetails.description.indexOf('__VLS_') === -1));
|
|
74
|
-
// modify label
|
|
75
|
-
for (const item of result.entries) {
|
|
76
|
-
if (item.source) {
|
|
77
|
-
const originalName = item.name;
|
|
78
|
-
for (const ext of vueOptions.extensions) {
|
|
79
|
-
const suffix = (0, shared_1.capitalize)(ext.substring('.'.length)); // .vue -> Vue
|
|
80
|
-
if (item.source.endsWith(ext) && item.name.endsWith(suffix)) {
|
|
81
|
-
item.name = item.name.slice(0, -suffix.length);
|
|
82
|
-
if (item.insertText) {
|
|
83
|
-
// #2286
|
|
84
|
-
item.insertText = item.insertText.replace(`${suffix}$1`, '$1');
|
|
85
|
-
}
|
|
86
|
-
if (item.data) {
|
|
87
|
-
// @ts-expect-error
|
|
88
|
-
item.data.__isComponentAutoImport = {
|
|
89
|
-
ext,
|
|
90
|
-
suffix,
|
|
91
|
-
originalName,
|
|
92
|
-
newName: item.insertText,
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return result;
|
|
102
|
-
};
|
|
103
|
-
info.languageService.getCompletionEntryDetails = (...args) => {
|
|
104
|
-
const details = getCompletionEntryDetails(...args);
|
|
105
|
-
// modify import statement
|
|
106
|
-
// @ts-expect-error
|
|
107
|
-
if (args[6]?.__isComponentAutoImport) {
|
|
108
|
-
// @ts-expect-error
|
|
109
|
-
const { ext, suffix, originalName, newName } = args[6]?.__isComponentAutoImport;
|
|
110
|
-
for (const codeAction of details?.codeActions ?? []) {
|
|
111
|
-
for (const change of codeAction.changes) {
|
|
112
|
-
for (const textChange of change.textChanges) {
|
|
113
|
-
textChange.newText = textChange.newText.replace('import ' + originalName + ' from ', 'import ' + newName + ' from ');
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
return details;
|
|
119
|
-
};
|
|
120
|
-
info.languageService.getCodeFixesAtPosition = (...args) => {
|
|
121
|
-
let result = getCodeFixesAtPosition(...args);
|
|
122
|
-
// filter __VLS_
|
|
123
|
-
result = result.filter(entry => entry.description.indexOf('__VLS_') === -1);
|
|
124
|
-
return result;
|
|
125
|
-
};
|
|
126
|
-
info.languageService.getEncodedSemanticClassifications = (fileName, span, format) => {
|
|
127
|
-
const result = getEncodedSemanticClassifications(fileName, span, format);
|
|
128
|
-
const file = files.get(fileName);
|
|
129
|
-
if (file?.generated?.code instanceof vue.VueGeneratedCode
|
|
130
|
-
&& file.generated.code.sfc.template) {
|
|
131
|
-
const validComponentNames = (0, componentInfos_1._getComponentNames)(ts, info.languageService, file.generated.code, vueOptions);
|
|
132
|
-
const components = new Set([
|
|
133
|
-
...validComponentNames,
|
|
134
|
-
...validComponentNames.map(vue.hyphenateTag),
|
|
135
|
-
]);
|
|
136
|
-
const { template } = file.generated.code.sfc;
|
|
137
|
-
const spanTemplateRange = [
|
|
138
|
-
span.start - template.startTagEnd,
|
|
139
|
-
span.start + span.length - template.startTagEnd,
|
|
140
|
-
];
|
|
141
|
-
template.ast?.children.forEach(function visit(node) {
|
|
142
|
-
if (node.loc.end.offset <= spanTemplateRange[0] || node.loc.start.offset >= spanTemplateRange[1]) {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
if (node.type === 1) {
|
|
146
|
-
if (components.has(node.tag)) {
|
|
147
|
-
result.spans.push(node.loc.start.offset + node.loc.source.indexOf(node.tag) + template.startTagEnd, node.tag.length, 256);
|
|
148
|
-
if (template.lang === 'html' && !node.isSelfClosing) {
|
|
149
|
-
result.spans.push(node.loc.start.offset + node.loc.source.lastIndexOf(node.tag) + template.startTagEnd, node.tag.length, 256);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
for (const child of node.children) {
|
|
153
|
-
visit(child);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
else if (node.type === 9) {
|
|
157
|
-
for (const branch of node.branches) {
|
|
158
|
-
for (const child of branch.children) {
|
|
159
|
-
visit(child);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
else if (node.type === 11) {
|
|
164
|
-
for (const child of node.children) {
|
|
165
|
-
visit(child);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
return result;
|
|
171
|
-
};
|
|
57
|
+
(0, server_1.startNamedPipeServer)(ts, info.project.projectKind, info.project.getCurrentDirectory());
|
|
172
58
|
}
|
|
173
59
|
return info.languageService;
|
|
174
60
|
function getVueCompilerOptions() {
|
|
@@ -190,7 +76,7 @@ function createLanguageServicePlugin() {
|
|
|
190
76
|
if (oldFiles && !twoSetsEqual(oldFiles, newFiles)) {
|
|
191
77
|
for (const oldFile of oldFiles) {
|
|
192
78
|
if (!newFiles.has(oldFile)) {
|
|
193
|
-
|
|
79
|
+
server_1.projects.get(project)?.files.delete(oldFile);
|
|
194
80
|
}
|
|
195
81
|
}
|
|
196
82
|
project.refreshDiagnostics();
|
package/lib/client.d.ts
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import type * as ts from 'typescript';
|
|
2
|
-
import type { NamedPipeServer } from './utils';
|
|
3
1
|
export declare function collectExtractProps(...args: Parameters<typeof import('./requests/collectExtractProps.js')['collectExtractProps']>): Promise<{
|
|
4
2
|
name: string;
|
|
5
3
|
type: string;
|
|
6
4
|
model: boolean;
|
|
7
5
|
}[] | null | undefined>;
|
|
8
6
|
export declare function getPropertiesAtLocation(...args: Parameters<typeof import('./requests/getPropertiesAtLocation.js')['getPropertiesAtLocation']>): Promise<string[] | null | undefined>;
|
|
9
|
-
export declare function getQuickInfoAtPosition(...args: Parameters<typeof import('./requests/getQuickInfoAtPosition.js')['getQuickInfoAtPosition']>): Promise<
|
|
7
|
+
export declare function getQuickInfoAtPosition(...args: Parameters<typeof import('./requests/getQuickInfoAtPosition.js')['getQuickInfoAtPosition']>): Promise<import("typescript").QuickInfo | null | undefined>;
|
|
10
8
|
export declare function getComponentProps(...args: Parameters<typeof import('./requests/componentInfos.js')['getComponentProps']>): Promise<string[] | null | undefined>;
|
|
11
9
|
export declare function getComponentEvents(...args: Parameters<typeof import('./requests/componentInfos.js')['getComponentEvents']>): Promise<string[] | null | undefined>;
|
|
12
10
|
export declare function getTemplateContextProps(...args: Parameters<typeof import('./requests/componentInfos.js')['getTemplateContextProps']>): Promise<string[] | null | undefined>;
|
|
13
11
|
export declare function getComponentNames(...args: Parameters<typeof import('./requests/componentInfos.js')['getComponentNames']>): Promise<string[] | null | undefined>;
|
|
14
12
|
export declare function getElementAttrs(...args: Parameters<typeof import('./requests/componentInfos.js')['getElementAttrs']>): Promise<string[] | null | undefined>;
|
|
15
|
-
export declare function searchNamedPipeServerForFile(fileName: string): Promise<NamedPipeServer | undefined>;
|
package/lib/client.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const fs = require("fs");
|
|
5
|
-
const path = require("path");
|
|
3
|
+
exports.getElementAttrs = exports.getComponentNames = exports.getTemplateContextProps = exports.getComponentEvents = exports.getComponentProps = exports.getQuickInfoAtPosition = exports.getPropertiesAtLocation = exports.collectExtractProps = void 0;
|
|
6
4
|
const utils_1 = require("./utils");
|
|
7
5
|
function collectExtractProps(...args) {
|
|
8
6
|
return sendRequest({
|
|
@@ -62,7 +60,7 @@ function getElementAttrs(...args) {
|
|
|
62
60
|
}
|
|
63
61
|
exports.getElementAttrs = getElementAttrs;
|
|
64
62
|
async function sendRequest(request) {
|
|
65
|
-
const server = await searchNamedPipeServerForFile(request.args[0]);
|
|
63
|
+
const server = await (0, utils_1.searchNamedPipeServerForFile)(request.args[0]);
|
|
66
64
|
if (!server) {
|
|
67
65
|
console.warn('[Vue Named Pipe Client] No server found for', request.args[0]);
|
|
68
66
|
return;
|
|
@@ -72,63 +70,6 @@ async function sendRequest(request) {
|
|
|
72
70
|
console.warn('[Vue Named Pipe Client] Failed to connect to', server.path);
|
|
73
71
|
return;
|
|
74
72
|
}
|
|
75
|
-
return await sendRequestWorker(request, client);
|
|
76
|
-
}
|
|
77
|
-
async function searchNamedPipeServerForFile(fileName) {
|
|
78
|
-
if (!fs.existsSync(utils_1.pipeTable)) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
const servers = JSON.parse(fs.readFileSync(utils_1.pipeTable, 'utf8'));
|
|
82
|
-
const configuredServers = servers
|
|
83
|
-
.filter(item => item.serverKind === 1);
|
|
84
|
-
const inferredServers = servers
|
|
85
|
-
.filter(item => item.serverKind === 0)
|
|
86
|
-
.sort((a, b) => b.currentDirectory.length - a.currentDirectory.length);
|
|
87
|
-
for (const server of configuredServers) {
|
|
88
|
-
const client = await (0, utils_1.connect)(server.path);
|
|
89
|
-
if (client) {
|
|
90
|
-
const response = await sendRequestWorker({ type: 'containsFile', args: [fileName] }, client);
|
|
91
|
-
if (response) {
|
|
92
|
-
return server;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
for (const server of inferredServers) {
|
|
97
|
-
if (!path.relative(server.currentDirectory, fileName).startsWith('..')) {
|
|
98
|
-
const client = await (0, utils_1.connect)(server.path);
|
|
99
|
-
if (client) {
|
|
100
|
-
return server;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
exports.searchNamedPipeServerForFile = searchNamedPipeServerForFile;
|
|
106
|
-
function sendRequestWorker(request, client) {
|
|
107
|
-
return new Promise(resolve => {
|
|
108
|
-
let dataChunks = [];
|
|
109
|
-
client.on('data', chunk => {
|
|
110
|
-
dataChunks.push(chunk);
|
|
111
|
-
});
|
|
112
|
-
client.on('end', () => {
|
|
113
|
-
if (!dataChunks.length) {
|
|
114
|
-
console.warn('[Vue Named Pipe Client] No response from server for request:', request.type);
|
|
115
|
-
resolve(undefined);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
const data = Buffer.concat(dataChunks);
|
|
119
|
-
const text = data.toString();
|
|
120
|
-
let json = null;
|
|
121
|
-
try {
|
|
122
|
-
json = JSON.parse(text);
|
|
123
|
-
}
|
|
124
|
-
catch (e) {
|
|
125
|
-
console.error('[Vue Named Pipe Client] Failed to parse response:', text);
|
|
126
|
-
resolve(undefined);
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
resolve(json);
|
|
130
|
-
});
|
|
131
|
-
client.write(JSON.stringify(request));
|
|
132
|
-
});
|
|
73
|
+
return await (0, utils_1.sendRequestWorker)(request, client);
|
|
133
74
|
}
|
|
134
75
|
//# sourceMappingURL=client.js.map
|
package/lib/common.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as vue from '@vue/language-core';
|
|
2
|
+
import type * as ts from 'typescript';
|
|
3
|
+
export declare function decorateLanguageServiceForVue(files: vue.FileRegistry, languageService: ts.LanguageService, vueOptions: vue.VueCompilerOptions, ts: typeof import('typescript'), isTsPlugin: boolean): void;
|
|
4
|
+
export declare function getComponentSpans(this: {
|
|
5
|
+
typescript: typeof import('typescript');
|
|
6
|
+
languageService: ts.LanguageService;
|
|
7
|
+
vueOptions: vue.VueCompilerOptions;
|
|
8
|
+
}, vueCode: vue.VueGeneratedCode, template: NonNullable<vue.VueGeneratedCode['sfc']['template']>, spanTemplateRange: ts.TextSpan): ts.TextSpan[];
|
package/lib/common.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getComponentSpans = exports.decorateLanguageServiceForVue = void 0;
|
|
4
|
+
const vue = require("@vue/language-core");
|
|
5
|
+
const shared_1 = require("@vue/shared");
|
|
6
|
+
const componentInfos_1 = require("./requests/componentInfos");
|
|
7
|
+
function decorateLanguageServiceForVue(files, languageService, vueOptions, ts, isTsPlugin) {
|
|
8
|
+
const { getCompletionsAtPosition, getCompletionEntryDetails, getCodeFixesAtPosition, getEncodedSemanticClassifications, } = languageService;
|
|
9
|
+
languageService.getCompletionsAtPosition = (fileName, position, options) => {
|
|
10
|
+
const result = getCompletionsAtPosition(fileName, position, options);
|
|
11
|
+
if (result) {
|
|
12
|
+
// filter __VLS_
|
|
13
|
+
result.entries = result.entries.filter(entry => entry.name.indexOf('__VLS_') === -1
|
|
14
|
+
&& (!entry.labelDetails?.description || entry.labelDetails.description.indexOf('__VLS_') === -1));
|
|
15
|
+
// modify label
|
|
16
|
+
for (const item of result.entries) {
|
|
17
|
+
if (item.source) {
|
|
18
|
+
const originalName = item.name;
|
|
19
|
+
for (const ext of vueOptions.extensions) {
|
|
20
|
+
const suffix = (0, shared_1.capitalize)(ext.substring('.'.length)); // .vue -> Vue
|
|
21
|
+
if (item.source.endsWith(ext) && item.name.endsWith(suffix)) {
|
|
22
|
+
item.name = (0, shared_1.capitalize)(item.name.slice(0, -suffix.length));
|
|
23
|
+
if (item.insertText) {
|
|
24
|
+
// #2286
|
|
25
|
+
item.insertText = item.insertText.replace(`${suffix}$1`, '$1');
|
|
26
|
+
}
|
|
27
|
+
if (item.data) {
|
|
28
|
+
// @ts-expect-error
|
|
29
|
+
item.data.__isComponentAutoImport = {
|
|
30
|
+
ext,
|
|
31
|
+
suffix,
|
|
32
|
+
originalName,
|
|
33
|
+
newName: item.insertText,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
languageService.getCompletionEntryDetails = (...args) => {
|
|
45
|
+
const details = getCompletionEntryDetails(...args);
|
|
46
|
+
// modify import statement
|
|
47
|
+
// @ts-expect-error
|
|
48
|
+
if (args[6]?.__isComponentAutoImport) {
|
|
49
|
+
// @ts-expect-error
|
|
50
|
+
const { ext, suffix, originalName, newName } = args[6]?.__isComponentAutoImport;
|
|
51
|
+
for (const codeAction of details?.codeActions ?? []) {
|
|
52
|
+
for (const change of codeAction.changes) {
|
|
53
|
+
for (const textChange of change.textChanges) {
|
|
54
|
+
textChange.newText = textChange.newText.replace('import ' + originalName + ' from ', 'import ' + newName + ' from ');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return details;
|
|
60
|
+
};
|
|
61
|
+
languageService.getCodeFixesAtPosition = (...args) => {
|
|
62
|
+
let result = getCodeFixesAtPosition(...args);
|
|
63
|
+
// filter __VLS_
|
|
64
|
+
result = result.filter(entry => entry.description.indexOf('__VLS_') === -1);
|
|
65
|
+
return result;
|
|
66
|
+
};
|
|
67
|
+
if (isTsPlugin) {
|
|
68
|
+
languageService.getEncodedSemanticClassifications = (fileName, span, format) => {
|
|
69
|
+
const result = getEncodedSemanticClassifications(fileName, span, format);
|
|
70
|
+
const file = files.get(fileName);
|
|
71
|
+
if (file?.generated?.code instanceof vue.VueGeneratedCode) {
|
|
72
|
+
const { template } = file.generated.code.sfc;
|
|
73
|
+
if (template) {
|
|
74
|
+
for (const componentSpan of getComponentSpans.call({ typescript: ts, languageService, vueOptions }, file.generated.code, template, {
|
|
75
|
+
start: span.start - template.startTagEnd,
|
|
76
|
+
length: span.length,
|
|
77
|
+
})) {
|
|
78
|
+
result.spans.push(componentSpan.start + template.startTagEnd, componentSpan.length, 256);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
exports.decorateLanguageServiceForVue = decorateLanguageServiceForVue;
|
|
87
|
+
function getComponentSpans(vueCode, template, spanTemplateRange) {
|
|
88
|
+
const { typescript: ts, languageService, vueOptions } = this;
|
|
89
|
+
const result = [];
|
|
90
|
+
const validComponentNames = (0, componentInfos_1._getComponentNames)(ts, languageService, vueCode, vueOptions);
|
|
91
|
+
const components = new Set([
|
|
92
|
+
...validComponentNames,
|
|
93
|
+
...validComponentNames.map(vue.hyphenateTag),
|
|
94
|
+
]);
|
|
95
|
+
template.ast?.children.forEach(function visit(node) {
|
|
96
|
+
if (node.loc.end.offset <= spanTemplateRange.start || node.loc.start.offset >= (spanTemplateRange.start + spanTemplateRange.length)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (node.type === 1) {
|
|
100
|
+
if (components.has(node.tag)) {
|
|
101
|
+
let start = node.loc.start.offset;
|
|
102
|
+
if (template.lang === 'html') {
|
|
103
|
+
start += '<'.length;
|
|
104
|
+
}
|
|
105
|
+
result.push({
|
|
106
|
+
start,
|
|
107
|
+
length: node.tag.length,
|
|
108
|
+
});
|
|
109
|
+
if (template.lang === 'html' && !node.isSelfClosing) {
|
|
110
|
+
result.push({
|
|
111
|
+
start: node.loc.start.offset + node.loc.source.lastIndexOf(node.tag),
|
|
112
|
+
length: node.tag.length,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
for (const child of node.children) {
|
|
117
|
+
visit(child);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else if (node.type === 9) {
|
|
121
|
+
for (const branch of node.branches) {
|
|
122
|
+
for (const child of branch.children) {
|
|
123
|
+
visit(child);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else if (node.type === 11) {
|
|
128
|
+
for (const child of node.children) {
|
|
129
|
+
visit(child);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
exports.getComponentSpans = getComponentSpans;
|
|
136
|
+
//# sourceMappingURL=common.js.map
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import { FileRegistry } from '@vue/language-core';
|
|
2
|
+
import type * as ts from 'typescript';
|
|
3
|
+
export declare function collectExtractProps(this: {
|
|
4
|
+
typescript: typeof import('typescript');
|
|
5
|
+
languageService: ts.LanguageService;
|
|
6
|
+
files: FileRegistry;
|
|
7
|
+
isTsPlugin: boolean;
|
|
8
|
+
getFileId: (fileName: string) => string;
|
|
9
|
+
}, fileName: string, templateCodeRange: [number, number]): {
|
|
2
10
|
name: string;
|
|
3
11
|
type: string;
|
|
4
12
|
model: boolean;
|
|
@@ -2,19 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.collectExtractProps = void 0;
|
|
4
4
|
const language_core_1 = require("@vue/language-core");
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
if (!match) {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
const { info, files, ts } = match;
|
|
12
|
-
const volarFile = files.get(fileName);
|
|
5
|
+
function collectExtractProps(fileName, templateCodeRange) {
|
|
6
|
+
const { typescript: ts, languageService, files, isTsPlugin, getFileId } = this;
|
|
7
|
+
const volarFile = files.get(getFileId(fileName));
|
|
13
8
|
if (!(volarFile?.generated?.code instanceof language_core_1.VueGeneratedCode)) {
|
|
14
9
|
return;
|
|
15
10
|
}
|
|
16
11
|
const result = new Map();
|
|
17
|
-
const languageService = info.languageService;
|
|
18
12
|
const program = languageService.getCurrentProgram();
|
|
19
13
|
if (!program) {
|
|
20
14
|
return;
|
|
@@ -1,8 +1,36 @@
|
|
|
1
1
|
import * as vue from '@vue/language-core';
|
|
2
2
|
import type * as ts from 'typescript';
|
|
3
|
-
export declare function getComponentProps(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
export declare function getComponentProps(this: {
|
|
4
|
+
typescript: typeof import('typescript');
|
|
5
|
+
languageService: ts.LanguageService;
|
|
6
|
+
files: vue.FileRegistry;
|
|
7
|
+
vueOptions: vue.VueCompilerOptions;
|
|
8
|
+
getFileId: (fileName: string) => string;
|
|
9
|
+
}, fileName: string, tag: string, requiredOnly?: boolean): string[] | undefined;
|
|
10
|
+
export declare function getComponentEvents(this: {
|
|
11
|
+
typescript: typeof import('typescript');
|
|
12
|
+
languageService: ts.LanguageService;
|
|
13
|
+
files: vue.FileRegistry;
|
|
14
|
+
vueOptions: vue.VueCompilerOptions;
|
|
15
|
+
getFileId: (fileName: string) => string;
|
|
16
|
+
}, fileName: string, tag: string): string[] | undefined;
|
|
17
|
+
export declare function getTemplateContextProps(this: {
|
|
18
|
+
typescript: typeof import('typescript');
|
|
19
|
+
languageService: ts.LanguageService;
|
|
20
|
+
files: vue.FileRegistry;
|
|
21
|
+
getFileId: (fileName: string) => string;
|
|
22
|
+
}, fileName: string): string[] | undefined;
|
|
23
|
+
export declare function getComponentNames(this: {
|
|
24
|
+
typescript: typeof import('typescript');
|
|
25
|
+
languageService: ts.LanguageService;
|
|
26
|
+
files: vue.FileRegistry;
|
|
27
|
+
vueOptions: vue.VueCompilerOptions;
|
|
28
|
+
getFileId: (fileName: string) => string;
|
|
29
|
+
}, fileName: string): string[] | undefined;
|
|
7
30
|
export declare function _getComponentNames(ts: typeof import('typescript'), tsLs: ts.LanguageService, vueCode: vue.VueGeneratedCode, vueOptions: vue.VueCompilerOptions): string[];
|
|
8
|
-
export declare function getElementAttrs(
|
|
31
|
+
export declare function getElementAttrs(this: {
|
|
32
|
+
typescript: typeof import('typescript');
|
|
33
|
+
languageService: ts.LanguageService;
|
|
34
|
+
files: vue.FileRegistry;
|
|
35
|
+
getFileId: (fileName: string) => string;
|
|
36
|
+
}, fileName: string, tagName: string): string[] | undefined;
|
|
@@ -3,35 +3,31 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getElementAttrs = exports._getComponentNames = exports.getComponentNames = exports.getTemplateContextProps = exports.getComponentEvents = exports.getComponentProps = void 0;
|
|
4
4
|
const vue = require("@vue/language-core");
|
|
5
5
|
const shared_1 = require("@vue/shared");
|
|
6
|
-
const utils_1 = require("../utils");
|
|
7
6
|
function getComponentProps(fileName, tag, requiredOnly = false) {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
const { ts, files, vueOptions } = match;
|
|
13
|
-
const volarFile = files.get(fileName);
|
|
7
|
+
const { typescript: ts, files, vueOptions, languageService, getFileId } = this;
|
|
8
|
+
const volarFile = files.get(getFileId(fileName));
|
|
14
9
|
if (!(volarFile?.generated?.code instanceof vue.VueGeneratedCode)) {
|
|
15
10
|
return;
|
|
16
11
|
}
|
|
17
12
|
const vueCode = volarFile.generated.code;
|
|
18
|
-
const
|
|
19
|
-
const program = tsLs.getCurrentProgram();
|
|
13
|
+
const program = languageService.getCurrentProgram();
|
|
20
14
|
if (!program) {
|
|
21
15
|
return;
|
|
22
16
|
}
|
|
23
17
|
const checker = program.getTypeChecker();
|
|
24
|
-
const components = getVariableType(ts,
|
|
25
|
-
if (!components)
|
|
18
|
+
const components = getVariableType(ts, languageService, vueCode, '__VLS_components');
|
|
19
|
+
if (!components) {
|
|
26
20
|
return [];
|
|
21
|
+
}
|
|
27
22
|
const name = tag.split('.');
|
|
28
23
|
let componentSymbol = components.type.getProperty(name[0]);
|
|
29
24
|
if (!componentSymbol && !vueOptions.nativeTags.includes(name[0])) {
|
|
30
25
|
componentSymbol = components.type.getProperty((0, shared_1.camelize)(name[0]))
|
|
31
26
|
?? components.type.getProperty((0, shared_1.capitalize)((0, shared_1.camelize)(name[0])));
|
|
32
27
|
}
|
|
33
|
-
if (!componentSymbol)
|
|
28
|
+
if (!componentSymbol) {
|
|
34
29
|
return [];
|
|
30
|
+
}
|
|
35
31
|
let componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
|
|
36
32
|
for (let i = 1; i < name.length; i++) {
|
|
37
33
|
componentSymbol = componentType.getProperty(name[i]);
|
|
@@ -75,33 +71,30 @@ function getComponentProps(fileName, tag, requiredOnly = false) {
|
|
|
75
71
|
}
|
|
76
72
|
exports.getComponentProps = getComponentProps;
|
|
77
73
|
function getComponentEvents(fileName, tag) {
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
const { ts, files, vueOptions } = match;
|
|
83
|
-
const volarFile = files.get(fileName);
|
|
74
|
+
const { typescript: ts, files, vueOptions, languageService, getFileId } = this;
|
|
75
|
+
const volarFile = files.get(getFileId(fileName));
|
|
84
76
|
if (!(volarFile?.generated?.code instanceof vue.VueGeneratedCode)) {
|
|
85
77
|
return;
|
|
86
78
|
}
|
|
87
|
-
const tsLs = match.info.languageService;
|
|
88
79
|
const vueCode = volarFile.generated.code;
|
|
89
|
-
const program =
|
|
80
|
+
const program = languageService.getCurrentProgram();
|
|
90
81
|
if (!program) {
|
|
91
82
|
return;
|
|
92
83
|
}
|
|
93
84
|
const checker = program.getTypeChecker();
|
|
94
|
-
const components = getVariableType(ts,
|
|
95
|
-
if (!components)
|
|
85
|
+
const components = getVariableType(ts, languageService, vueCode, '__VLS_components');
|
|
86
|
+
if (!components) {
|
|
96
87
|
return [];
|
|
88
|
+
}
|
|
97
89
|
const name = tag.split('.');
|
|
98
90
|
let componentSymbol = components.type.getProperty(name[0]);
|
|
99
91
|
if (!componentSymbol && !vueOptions.nativeTags.includes(name[0])) {
|
|
100
92
|
componentSymbol = components.type.getProperty((0, shared_1.camelize)(name[0]))
|
|
101
93
|
?? components.type.getProperty((0, shared_1.capitalize)((0, shared_1.camelize)(name[0])));
|
|
102
94
|
}
|
|
103
|
-
if (!componentSymbol)
|
|
95
|
+
if (!componentSymbol) {
|
|
104
96
|
return [];
|
|
97
|
+
}
|
|
105
98
|
let componentType = checker.getTypeOfSymbolAtLocation(componentSymbol, components.node);
|
|
106
99
|
for (let i = 1; i < name.length; i++) {
|
|
107
100
|
componentSymbol = componentType.getProperty(name[i]);
|
|
@@ -139,36 +132,26 @@ function getComponentEvents(fileName, tag) {
|
|
|
139
132
|
}
|
|
140
133
|
exports.getComponentEvents = getComponentEvents;
|
|
141
134
|
function getTemplateContextProps(fileName) {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
const { ts, files } = match;
|
|
147
|
-
const volarFile = files.get(fileName);
|
|
135
|
+
const { typescript: ts, files, languageService, getFileId } = this;
|
|
136
|
+
const volarFile = files.get(getFileId(fileName));
|
|
148
137
|
if (!(volarFile?.generated?.code instanceof vue.VueGeneratedCode)) {
|
|
149
138
|
return;
|
|
150
139
|
}
|
|
151
|
-
const tsLs = match.info.languageService;
|
|
152
140
|
const vueCode = volarFile.generated.code;
|
|
153
|
-
return getVariableType(ts,
|
|
141
|
+
return getVariableType(ts, languageService, vueCode, '__VLS_ctx')
|
|
154
142
|
?.type
|
|
155
143
|
?.getProperties()
|
|
156
144
|
.map(c => c.name);
|
|
157
145
|
}
|
|
158
146
|
exports.getTemplateContextProps = getTemplateContextProps;
|
|
159
147
|
function getComponentNames(fileName) {
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
const { ts, files, vueOptions } = match;
|
|
165
|
-
const volarFile = files.get(fileName);
|
|
148
|
+
const { typescript: ts, files, vueOptions, languageService, getFileId } = this;
|
|
149
|
+
const volarFile = files.get(getFileId(fileName));
|
|
166
150
|
if (!(volarFile?.generated?.code instanceof vue.VueGeneratedCode)) {
|
|
167
151
|
return;
|
|
168
152
|
}
|
|
169
|
-
const tsLs = match.info.languageService;
|
|
170
153
|
const vueCode = volarFile.generated.code;
|
|
171
|
-
return getVariableType(ts,
|
|
154
|
+
return getVariableType(ts, languageService, vueCode, '__VLS_components')
|
|
172
155
|
?.type
|
|
173
156
|
?.getProperties()
|
|
174
157
|
.map(c => c.name)
|
|
@@ -188,17 +171,12 @@ function _getComponentNames(ts, tsLs, vueCode, vueOptions) {
|
|
|
188
171
|
}
|
|
189
172
|
exports._getComponentNames = _getComponentNames;
|
|
190
173
|
function getElementAttrs(fileName, tagName) {
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
const { ts, files } = match;
|
|
196
|
-
const volarFile = files.get(fileName);
|
|
174
|
+
const { typescript: ts, files, languageService, getFileId } = this;
|
|
175
|
+
const volarFile = files.get(getFileId(fileName));
|
|
197
176
|
if (!(volarFile?.generated?.code instanceof vue.VueGeneratedCode)) {
|
|
198
177
|
return;
|
|
199
178
|
}
|
|
200
|
-
const
|
|
201
|
-
const program = tsLs.getCurrentProgram();
|
|
179
|
+
const program = languageService.getCurrentProgram();
|
|
202
180
|
if (!program) {
|
|
203
181
|
return;
|
|
204
182
|
}
|
|
@@ -1 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import { FileRegistry } from '@vue/language-core';
|
|
2
|
+
import type * as ts from 'typescript';
|
|
3
|
+
export declare function getPropertiesAtLocation(this: {
|
|
4
|
+
typescript: typeof import('typescript');
|
|
5
|
+
languageService: ts.LanguageService;
|
|
6
|
+
files: FileRegistry;
|
|
7
|
+
isTsPlugin: boolean;
|
|
8
|
+
getFileId: (fileName: string) => string;
|
|
9
|
+
}, fileName: string, position: number): string[] | undefined;
|
|
@@ -2,16 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getPropertiesAtLocation = void 0;
|
|
4
4
|
const language_core_1 = require("@vue/language-core");
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const match = (0, utils_1.getProject)(fileName);
|
|
8
|
-
if (!match) {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
const { info, files, ts } = match;
|
|
12
|
-
const languageService = info.languageService;
|
|
5
|
+
function getPropertiesAtLocation(fileName, position) {
|
|
6
|
+
const { languageService, files, typescript: ts, isTsPlugin, getFileId } = this;
|
|
13
7
|
// mapping
|
|
14
|
-
const file = files.get(fileName);
|
|
8
|
+
const file = files.get(getFileId(fileName));
|
|
15
9
|
if (file?.generated) {
|
|
16
10
|
const virtualScript = file.generated.languagePlugin.typescript?.getScript(file.generated.code);
|
|
17
11
|
if (!virtualScript) {
|
|
@@ -1 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import type * as ts from 'typescript';
|
|
2
|
+
export declare function getQuickInfoAtPosition(this: {
|
|
3
|
+
languageService: ts.LanguageService;
|
|
4
|
+
}, fileName: string, position: number): ts.QuickInfo | undefined;
|
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getQuickInfoAtPosition = void 0;
|
|
4
|
-
const utils_1 = require("../utils");
|
|
5
4
|
function getQuickInfoAtPosition(fileName, position) {
|
|
6
|
-
const
|
|
7
|
-
if (!match) {
|
|
8
|
-
return;
|
|
9
|
-
}
|
|
10
|
-
const { info } = match;
|
|
11
|
-
const languageService = info.languageService;
|
|
5
|
+
const { languageService } = this;
|
|
12
6
|
return languageService.getQuickInfoAtPosition(fileName, position);
|
|
13
7
|
}
|
|
14
8
|
exports.getQuickInfoAtPosition = getQuickInfoAtPosition;
|
package/lib/server.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type * as ts from 'typescript';
|
|
2
|
+
import type { FileRegistry, VueCompilerOptions } from '@vue/language-core';
|
|
2
3
|
export interface Request {
|
|
3
4
|
type: 'containsFile' | 'collectExtractProps' | 'getPropertiesAtLocation' | 'getQuickInfoAtPosition' | 'getComponentProps' | 'getComponentEvents' | 'getTemplateContextProps' | 'getComponentNames' | 'getElementAttrs';
|
|
4
|
-
args: any;
|
|
5
|
+
args: [fileName: string, ...rest: any];
|
|
5
6
|
}
|
|
6
|
-
export declare function startNamedPipeServer(serverKind: ts.server.ProjectKind, currentDirectory: string): void;
|
|
7
|
+
export declare function startNamedPipeServer(ts: typeof import('typescript'), serverKind: ts.server.ProjectKind, currentDirectory: string): void;
|
|
8
|
+
export declare const projects: Map<ts.server.Project, {
|
|
9
|
+
info: ts.server.PluginCreateInfo;
|
|
10
|
+
files: FileRegistry;
|
|
11
|
+
vueOptions: VueCompilerOptions;
|
|
12
|
+
}>;
|
package/lib/server.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.startNamedPipeServer = void 0;
|
|
3
|
+
exports.projects = exports.startNamedPipeServer = void 0;
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const net = require("net");
|
|
6
6
|
const collectExtractProps_1 = require("./requests/collectExtractProps");
|
|
7
7
|
const componentInfos_1 = require("./requests/componentInfos");
|
|
8
|
-
const containsFile_1 = require("./requests/containsFile");
|
|
9
8
|
const getPropertiesAtLocation_1 = require("./requests/getPropertiesAtLocation");
|
|
10
9
|
const getQuickInfoAtPosition_1 = require("./requests/getQuickInfoAtPosition");
|
|
11
10
|
const utils_1 = require("./utils");
|
|
12
11
|
let started = false;
|
|
13
|
-
function startNamedPipeServer(serverKind, currentDirectory) {
|
|
14
|
-
if (started)
|
|
12
|
+
function startNamedPipeServer(ts, serverKind, currentDirectory) {
|
|
13
|
+
if (started) {
|
|
15
14
|
return;
|
|
15
|
+
}
|
|
16
16
|
started = true;
|
|
17
17
|
const pipeFile = process.platform === 'win32'
|
|
18
18
|
? `\\\\.\\pipe\\vue-tsp-${process.pid}`
|
|
@@ -21,61 +21,73 @@ function startNamedPipeServer(serverKind, currentDirectory) {
|
|
|
21
21
|
connection.on('data', data => {
|
|
22
22
|
const text = data.toString();
|
|
23
23
|
const request = JSON.parse(text);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
24
|
+
const fileName = request.args[0];
|
|
25
|
+
const project = getProject(fileName);
|
|
26
|
+
if (project) {
|
|
27
|
+
const requestContext = {
|
|
28
|
+
typescript: ts,
|
|
29
|
+
languageService: project.info.languageService,
|
|
30
|
+
files: project.files,
|
|
31
|
+
vueOptions: project.vueOptions,
|
|
32
|
+
isTsPlugin: true,
|
|
33
|
+
getFileId: (fileName) => fileName,
|
|
34
|
+
};
|
|
35
|
+
if (request.type === 'containsFile') {
|
|
36
|
+
const result = !!getProject(fileName);
|
|
37
|
+
connection.write(JSON.stringify(result ?? null));
|
|
38
|
+
}
|
|
39
|
+
else if (request.type === 'collectExtractProps') {
|
|
40
|
+
const result = collectExtractProps_1.collectExtractProps.apply(requestContext, request.args);
|
|
41
|
+
connection.write(JSON.stringify(result ?? null));
|
|
42
|
+
}
|
|
43
|
+
else if (request.type === 'getPropertiesAtLocation') {
|
|
44
|
+
const result = getPropertiesAtLocation_1.getPropertiesAtLocation.apply(requestContext, request.args);
|
|
45
|
+
connection.write(JSON.stringify(result ?? null));
|
|
46
|
+
}
|
|
47
|
+
else if (request.type === 'getQuickInfoAtPosition') {
|
|
48
|
+
const result = getQuickInfoAtPosition_1.getQuickInfoAtPosition.apply(requestContext, request.args);
|
|
49
|
+
connection.write(JSON.stringify(result ?? null));
|
|
50
|
+
}
|
|
51
|
+
// Component Infos
|
|
52
|
+
else if (request.type === 'getComponentProps') {
|
|
53
|
+
const result = componentInfos_1.getComponentProps.apply(requestContext, request.args);
|
|
54
|
+
connection.write(JSON.stringify(result ?? null));
|
|
55
|
+
}
|
|
56
|
+
else if (request.type === 'getComponentEvents') {
|
|
57
|
+
const result = componentInfos_1.getComponentEvents.apply(requestContext, request.args);
|
|
58
|
+
connection.write(JSON.stringify(result ?? null));
|
|
59
|
+
}
|
|
60
|
+
else if (request.type === 'getTemplateContextProps') {
|
|
61
|
+
const result = componentInfos_1.getTemplateContextProps.apply(requestContext, request.args);
|
|
62
|
+
connection.write(JSON.stringify(result ?? null));
|
|
63
|
+
}
|
|
64
|
+
else if (request.type === 'getComponentNames') {
|
|
65
|
+
const result = componentInfos_1.getComponentNames.apply(requestContext, request.args);
|
|
66
|
+
connection.write(JSON.stringify(result ?? null));
|
|
67
|
+
}
|
|
68
|
+
else if (request.type === 'getElementAttrs') {
|
|
69
|
+
const result = componentInfos_1.getElementAttrs.apply(requestContext, request.args);
|
|
70
|
+
connection.write(JSON.stringify(result ?? null));
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
console.warn('[Vue Named Pipe Server] Unknown request type:', request.type);
|
|
74
|
+
}
|
|
60
75
|
}
|
|
61
76
|
else {
|
|
62
|
-
console.warn('[Vue Named Pipe Server]
|
|
77
|
+
console.warn('[Vue Named Pipe Server] No project found for:', fileName);
|
|
63
78
|
}
|
|
64
79
|
connection.end();
|
|
65
80
|
});
|
|
66
81
|
connection.on('error', err => console.error('[Vue Named Pipe Server]', err.message));
|
|
67
82
|
});
|
|
68
83
|
cleanupPipeTable();
|
|
69
|
-
|
|
70
|
-
fs.writeFileSync(utils_1.pipeTable, JSON.stringify([]));
|
|
71
|
-
}
|
|
72
|
-
const table = JSON.parse(fs.readFileSync(utils_1.pipeTable, 'utf8'));
|
|
84
|
+
const table = (0, utils_1.readPipeTable)();
|
|
73
85
|
table.push({
|
|
74
86
|
path: pipeFile,
|
|
75
87
|
serverKind,
|
|
76
88
|
currentDirectory,
|
|
77
89
|
});
|
|
78
|
-
|
|
90
|
+
(0, utils_1.updatePipeTable)(table);
|
|
79
91
|
try {
|
|
80
92
|
fs.unlinkSync(pipeFile);
|
|
81
93
|
}
|
|
@@ -84,20 +96,25 @@ function startNamedPipeServer(serverKind, currentDirectory) {
|
|
|
84
96
|
}
|
|
85
97
|
exports.startNamedPipeServer = startNamedPipeServer;
|
|
86
98
|
function cleanupPipeTable() {
|
|
87
|
-
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
for (const server of JSON.parse(fs.readFileSync(utils_1.pipeTable, 'utf8'))) {
|
|
99
|
+
for (const server of (0, utils_1.readPipeTable)()) {
|
|
91
100
|
(0, utils_1.connect)(server.path).then(client => {
|
|
92
101
|
if (client) {
|
|
93
102
|
client.end();
|
|
94
103
|
}
|
|
95
104
|
else {
|
|
96
|
-
let table =
|
|
105
|
+
let table = (0, utils_1.readPipeTable)();
|
|
97
106
|
table = table.filter(item => item.path !== server.path);
|
|
98
|
-
|
|
107
|
+
(0, utils_1.updatePipeTable)(table);
|
|
99
108
|
}
|
|
100
109
|
});
|
|
101
110
|
}
|
|
102
111
|
}
|
|
112
|
+
exports.projects = new Map();
|
|
113
|
+
function getProject(fileName) {
|
|
114
|
+
for (const [project, data] of exports.projects) {
|
|
115
|
+
if (project.containsFile(fileName)) {
|
|
116
|
+
return data;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
103
120
|
//# sourceMappingURL=server.js.map
|
package/lib/utils.d.ts
CHANGED
|
@@ -1,32 +1,14 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import type { FileRegistry, VueCompilerOptions } from '@vue/language-core';
|
|
3
2
|
import * as net from 'net';
|
|
4
3
|
import type * as ts from 'typescript';
|
|
4
|
+
import type { Request } from './server';
|
|
5
5
|
export interface NamedPipeServer {
|
|
6
6
|
path: string;
|
|
7
7
|
serverKind: ts.server.ProjectKind;
|
|
8
8
|
currentDirectory: string;
|
|
9
9
|
}
|
|
10
|
-
export declare
|
|
11
|
-
export declare
|
|
12
|
-
info: ts.server.PluginCreateInfo;
|
|
13
|
-
files: FileRegistry;
|
|
14
|
-
ts: typeof ts;
|
|
15
|
-
vueOptions: VueCompilerOptions;
|
|
16
|
-
}>;
|
|
17
|
-
export declare function getProject(fileName: string): {
|
|
18
|
-
info: ts.server.PluginCreateInfo;
|
|
19
|
-
files: {
|
|
20
|
-
languagePlugins: import("@vue/language-core").LanguagePlugin<import("@vue/language-core").VirtualCode>[];
|
|
21
|
-
set(id: string, languageId: string, snapshot: ts.IScriptSnapshot, plugins?: import("@vue/language-core").LanguagePlugin<import("@vue/language-core").VirtualCode>[] | undefined): import("@vue/language-core").SourceFile;
|
|
22
|
-
delete(id: string): void;
|
|
23
|
-
get(id: string): import("@vue/language-core").SourceFile | undefined;
|
|
24
|
-
getByVirtualCode(virtualCode: import("@vue/language-core").VirtualCode): import("@vue/language-core").SourceFile;
|
|
25
|
-
getLinkedCodeMap(virtualCode: import("@vue/language-core").VirtualCode): import("@vue/language-core").LinkedCodeMap | undefined;
|
|
26
|
-
getMaps(virtualCode: import("@vue/language-core").VirtualCode): Map<string, [ts.IScriptSnapshot, import("@vue/language-core").SourceMap<import("@vue/language-core").CodeInformation>]>;
|
|
27
|
-
getVirtualCode(sourceFileId: string, virtualCodeId: string): readonly [import("@vue/language-core").VirtualCode, import("@vue/language-core").SourceFile] | readonly [undefined, undefined];
|
|
28
|
-
};
|
|
29
|
-
ts: typeof ts;
|
|
30
|
-
vueOptions: VueCompilerOptions;
|
|
31
|
-
} | undefined;
|
|
10
|
+
export declare function readPipeTable(): NamedPipeServer[];
|
|
11
|
+
export declare function updatePipeTable(servers: NamedPipeServer[]): void;
|
|
32
12
|
export declare function connect(path: string): Promise<net.Socket | undefined>;
|
|
13
|
+
export declare function searchNamedPipeServerForFile(fileName: string): Promise<NamedPipeServer | undefined>;
|
|
14
|
+
export declare function sendRequestWorker<T>(request: Request, client: net.Socket): Promise<T | null | undefined>;
|
package/lib/utils.js
CHANGED
|
@@ -1,20 +1,35 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.sendRequestWorker = exports.searchNamedPipeServerForFile = exports.connect = exports.updatePipeTable = exports.readPipeTable = void 0;
|
|
4
4
|
const os = require("os");
|
|
5
5
|
const net = require("net");
|
|
6
6
|
const path = require("path");
|
|
7
|
+
const fs = require("fs");
|
|
7
8
|
const { version } = require('../package.json');
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
const pipeTableFile = path.join(os.tmpdir(), `vue-tsp-table-${version}.json`);
|
|
10
|
+
function readPipeTable() {
|
|
11
|
+
if (!fs.existsSync(pipeTableFile)) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const servers = JSON.parse(fs.readFileSync(pipeTableFile, 'utf8'));
|
|
16
|
+
return servers;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
fs.unlinkSync(pipeTableFile);
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.readPipeTable = readPipeTable;
|
|
24
|
+
function updatePipeTable(servers) {
|
|
25
|
+
if (servers.length === 0) {
|
|
26
|
+
fs.unlinkSync(pipeTableFile);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
fs.writeFileSync(pipeTableFile, JSON.stringify(servers, undefined, 2));
|
|
15
30
|
}
|
|
16
31
|
}
|
|
17
|
-
exports.
|
|
32
|
+
exports.updatePipeTable = updatePipeTable;
|
|
18
33
|
function connect(path) {
|
|
19
34
|
return new Promise(resolve => {
|
|
20
35
|
const client = net.connect(path);
|
|
@@ -27,4 +42,59 @@ function connect(path) {
|
|
|
27
42
|
});
|
|
28
43
|
}
|
|
29
44
|
exports.connect = connect;
|
|
45
|
+
async function searchNamedPipeServerForFile(fileName) {
|
|
46
|
+
const servers = readPipeTable();
|
|
47
|
+
const configuredServers = servers
|
|
48
|
+
.filter(item => item.serverKind === 1);
|
|
49
|
+
const inferredServers = servers
|
|
50
|
+
.filter(item => item.serverKind === 0)
|
|
51
|
+
.sort((a, b) => b.currentDirectory.length - a.currentDirectory.length);
|
|
52
|
+
for (const server of configuredServers) {
|
|
53
|
+
const client = await connect(server.path);
|
|
54
|
+
if (client) {
|
|
55
|
+
const response = await sendRequestWorker({ type: 'containsFile', args: [fileName] }, client);
|
|
56
|
+
if (response) {
|
|
57
|
+
return server;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
for (const server of inferredServers) {
|
|
62
|
+
if (!path.relative(server.currentDirectory, fileName).startsWith('..')) {
|
|
63
|
+
const client = await connect(server.path);
|
|
64
|
+
if (client) {
|
|
65
|
+
return server;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.searchNamedPipeServerForFile = searchNamedPipeServerForFile;
|
|
71
|
+
function sendRequestWorker(request, client) {
|
|
72
|
+
return new Promise(resolve => {
|
|
73
|
+
let dataChunks = [];
|
|
74
|
+
client.on('data', chunk => {
|
|
75
|
+
dataChunks.push(chunk);
|
|
76
|
+
});
|
|
77
|
+
client.on('end', () => {
|
|
78
|
+
if (!dataChunks.length) {
|
|
79
|
+
console.warn('[Vue Named Pipe Client] No response from server for request:', request.type);
|
|
80
|
+
resolve(undefined);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const data = Buffer.concat(dataChunks);
|
|
84
|
+
const text = data.toString();
|
|
85
|
+
let json = null;
|
|
86
|
+
try {
|
|
87
|
+
json = JSON.parse(text);
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
console.error('[Vue Named Pipe Client] Failed to parse response:', text);
|
|
91
|
+
resolve(undefined);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
resolve(json);
|
|
95
|
+
});
|
|
96
|
+
client.write(JSON.stringify(request));
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
exports.sendRequestWorker = sendRequestWorker;
|
|
30
100
|
//# sourceMappingURL=utils.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vue/typescript-plugin",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.7",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"**/*.js",
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
"directory": "packages/typescript-plugin"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@volar/typescript": "~2.1.
|
|
16
|
-
"@vue/language-core": "2.0.
|
|
15
|
+
"@volar/typescript": "~2.1.3",
|
|
16
|
+
"@vue/language-core": "2.0.7",
|
|
17
17
|
"@vue/shared": "^3.4.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@types/node": "latest"
|
|
21
21
|
},
|
|
22
|
-
"gitHead": "
|
|
22
|
+
"gitHead": "4a37e8f3ebcf31ecfd2ea627f7611d5990ec5df6"
|
|
23
23
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function containsFile(fileName: string): boolean;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.containsFile = void 0;
|
|
4
|
-
const utils_1 = require("../utils");
|
|
5
|
-
function containsFile(fileName) {
|
|
6
|
-
return !!(0, utils_1.getProject)(fileName);
|
|
7
|
-
}
|
|
8
|
-
exports.containsFile = containsFile;
|
|
9
|
-
//# sourceMappingURL=containsFile.js.map
|