@vue/typescript-plugin 2.1.10 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.d.ts +4 -3
- package/lib/client.js +26 -44
- package/lib/common.js +8 -7
- package/lib/requests/collectExtractProps.js +9 -5
- package/lib/requests/componentInfos.d.ts +3 -2
- package/lib/requests/componentInfos.js +14 -18
- package/lib/requests/types.d.ts +1 -1
- package/lib/server.d.ts +18 -5
- package/lib/server.js +204 -72
- package/lib/utils.d.ts +36 -14
- package/lib/utils.js +192 -188
- package/package.json +4 -4
package/lib/client.d.ts
CHANGED
|
@@ -6,11 +6,12 @@ export declare function collectExtractProps(...args: Parameters<typeof import('.
|
|
|
6
6
|
export declare function getImportPathForFile(...args: Parameters<typeof import('./requests/getImportPathForFile.js')['getImportPathForFile']>): Promise<string | null | undefined>;
|
|
7
7
|
export declare function getPropertiesAtLocation(...args: Parameters<typeof import('./requests/getPropertiesAtLocation.js')['getPropertiesAtLocation']>): Promise<string[] | null | undefined>;
|
|
8
8
|
export declare function getQuickInfoAtPosition(...args: Parameters<typeof import('./requests/getQuickInfoAtPosition.js')['getQuickInfoAtPosition']>): Promise<string | null | undefined>;
|
|
9
|
-
export declare function getComponentProps(
|
|
9
|
+
export declare function getComponentProps(fileName: string, componentName: string): Promise<{
|
|
10
10
|
name: string;
|
|
11
|
-
|
|
11
|
+
required?: true;
|
|
12
|
+
commentMarkdown?: string;
|
|
12
13
|
}[] | null | undefined>;
|
|
13
14
|
export declare function getComponentEvents(...args: Parameters<typeof import('./requests/componentInfos.js')['getComponentEvents']>): Promise<string[] | null | undefined>;
|
|
14
15
|
export declare function getTemplateContextProps(...args: Parameters<typeof import('./requests/componentInfos.js')['getTemplateContextProps']>): Promise<string[] | null | undefined>;
|
|
15
|
-
export declare function getComponentNames(
|
|
16
|
+
export declare function getComponentNames(fileName: string): Promise<string[] | undefined>;
|
|
16
17
|
export declare function getElementAttrs(...args: Parameters<typeof import('./requests/componentInfos.js')['getElementAttrs']>): Promise<string[] | null | undefined>;
|
package/lib/client.js
CHANGED
|
@@ -11,68 +11,50 @@ exports.getComponentNames = getComponentNames;
|
|
|
11
11
|
exports.getElementAttrs = getElementAttrs;
|
|
12
12
|
const utils_1 = require("./utils");
|
|
13
13
|
function collectExtractProps(...args) {
|
|
14
|
-
return sendRequest(
|
|
15
|
-
type: 'collectExtractProps',
|
|
16
|
-
args,
|
|
17
|
-
});
|
|
14
|
+
return sendRequest('collectExtractProps', ...args);
|
|
18
15
|
}
|
|
19
16
|
async function getImportPathForFile(...args) {
|
|
20
|
-
return await sendRequest(
|
|
21
|
-
type: 'getImportPathForFile',
|
|
22
|
-
args,
|
|
23
|
-
});
|
|
17
|
+
return await sendRequest('getImportPathForFile', ...args);
|
|
24
18
|
}
|
|
25
19
|
async function getPropertiesAtLocation(...args) {
|
|
26
|
-
return await sendRequest(
|
|
27
|
-
type: 'getPropertiesAtLocation',
|
|
28
|
-
args,
|
|
29
|
-
});
|
|
20
|
+
return await sendRequest('getPropertiesAtLocation', ...args);
|
|
30
21
|
}
|
|
31
22
|
function getQuickInfoAtPosition(...args) {
|
|
32
|
-
return sendRequest(
|
|
33
|
-
type: 'getQuickInfoAtPosition',
|
|
34
|
-
args,
|
|
35
|
-
});
|
|
23
|
+
return sendRequest('getQuickInfoAtPosition', ...args);
|
|
36
24
|
}
|
|
37
25
|
// Component Infos
|
|
38
|
-
function getComponentProps(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
26
|
+
async function getComponentProps(fileName, componentName) {
|
|
27
|
+
const server = await (0, utils_1.getBestServer)(fileName);
|
|
28
|
+
if (!server) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
return await server.getComponentProps(fileName, componentName);
|
|
43
32
|
}
|
|
44
33
|
function getComponentEvents(...args) {
|
|
45
|
-
return sendRequest(
|
|
46
|
-
type: 'getComponentEvents',
|
|
47
|
-
args,
|
|
48
|
-
});
|
|
34
|
+
return sendRequest('getComponentEvents', ...args);
|
|
49
35
|
}
|
|
50
36
|
function getTemplateContextProps(...args) {
|
|
51
|
-
return sendRequest(
|
|
52
|
-
type: 'getTemplateContextProps',
|
|
53
|
-
args,
|
|
54
|
-
});
|
|
37
|
+
return sendRequest('getTemplateContextProps', ...args);
|
|
55
38
|
}
|
|
56
|
-
function getComponentNames(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
39
|
+
async function getComponentNames(fileName) {
|
|
40
|
+
const server = await (0, utils_1.getBestServer)(fileName);
|
|
41
|
+
if (!server) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const componentAndProps = server.componentNamesAndProps.get(fileName);
|
|
45
|
+
if (!componentAndProps) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
return Object.keys(componentAndProps);
|
|
61
49
|
}
|
|
62
50
|
function getElementAttrs(...args) {
|
|
63
|
-
return sendRequest(
|
|
64
|
-
type: 'getElementAttrs',
|
|
65
|
-
args,
|
|
66
|
-
});
|
|
51
|
+
return sendRequest('getElementAttrs', ...args);
|
|
67
52
|
}
|
|
68
|
-
async function sendRequest(
|
|
69
|
-
const server =
|
|
53
|
+
async function sendRequest(requestType, fileName, ...rest) {
|
|
54
|
+
const server = await (0, utils_1.getBestServer)(fileName);
|
|
70
55
|
if (!server) {
|
|
71
|
-
console.warn('[Vue Named Pipe Client] No server found for', request.args[0]);
|
|
72
56
|
return;
|
|
73
57
|
}
|
|
74
|
-
|
|
75
|
-
server.socket.end();
|
|
76
|
-
return res;
|
|
58
|
+
return server.sendRequest(requestType, fileName, ...rest);
|
|
77
59
|
}
|
|
78
60
|
//# sourceMappingURL=client.js.map
|
package/lib/common.js
CHANGED
|
@@ -42,8 +42,8 @@ function getCompletionsAtPosition(vueOptions, getCompletionsAtPosition) {
|
|
|
42
42
|
const result = getCompletionsAtPosition(fileName, position, options, formattingSettings);
|
|
43
43
|
if (result) {
|
|
44
44
|
// filter __VLS_
|
|
45
|
-
result.entries = result.entries.filter(entry => entry.name.
|
|
46
|
-
&&
|
|
45
|
+
result.entries = result.entries.filter(entry => !entry.name.includes('__VLS_')
|
|
46
|
+
&& !entry.labelDetails?.description?.includes('__VLS_'));
|
|
47
47
|
// modify label
|
|
48
48
|
for (const item of result.entries) {
|
|
49
49
|
if (item.source) {
|
|
@@ -124,7 +124,7 @@ function getCodeFixesAtPosition(getCodeFixesAtPosition) {
|
|
|
124
124
|
return (...args) => {
|
|
125
125
|
let result = getCodeFixesAtPosition(...args);
|
|
126
126
|
// filter __VLS_
|
|
127
|
-
result = result.filter(entry => entry.description.
|
|
127
|
+
result = result.filter(entry => !entry.description.includes('__VLS_'));
|
|
128
128
|
return result;
|
|
129
129
|
};
|
|
130
130
|
}
|
|
@@ -170,11 +170,12 @@ function getEncodedSemanticClassifications(ts, language, languageService, asScri
|
|
|
170
170
|
return (filePath, span, format) => {
|
|
171
171
|
const fileName = filePath.replace(windowsPathReg, '/');
|
|
172
172
|
const result = getEncodedSemanticClassifications(fileName, span, format);
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
173
|
+
const sourceScript = language.scripts.get(asScriptId(fileName));
|
|
174
|
+
const root = sourceScript?.generated?.root;
|
|
175
|
+
if (root instanceof language_core_1.VueVirtualCode) {
|
|
176
|
+
const { template } = root._sfc;
|
|
176
177
|
if (template) {
|
|
177
|
-
for (const componentSpan of getComponentSpans.call({ typescript: ts, languageService },
|
|
178
|
+
for (const componentSpan of getComponentSpans.call({ typescript: ts, languageService }, root, template, {
|
|
178
179
|
start: span.start - template.startTagEnd,
|
|
179
180
|
length: span.length,
|
|
180
181
|
})) {
|
|
@@ -4,17 +4,21 @@ exports.collectExtractProps = collectExtractProps;
|
|
|
4
4
|
const language_core_1 = require("@vue/language-core");
|
|
5
5
|
function collectExtractProps(fileName, templateCodeRange) {
|
|
6
6
|
const { typescript: ts, languageService, language, isTsPlugin, getFileId } = this;
|
|
7
|
-
const
|
|
8
|
-
if (!
|
|
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)) {
|
|
9
13
|
return;
|
|
10
14
|
}
|
|
11
15
|
const result = new Map();
|
|
12
16
|
const program = languageService.getProgram();
|
|
13
17
|
const sourceFile = program.getSourceFile(fileName);
|
|
14
18
|
const checker = program.getTypeChecker();
|
|
15
|
-
const script =
|
|
19
|
+
const script = sourceScript.generated?.languagePlugin.typescript?.getServiceScript(root);
|
|
16
20
|
const maps = script ? [...language.maps.forEach(script.code)].map(([_sourceScript, map]) => map) : [];
|
|
17
|
-
const sfc =
|
|
21
|
+
const sfc = root._sfc;
|
|
18
22
|
sourceFile.forEachChild(function visit(node) {
|
|
19
23
|
if (ts.isPropertyAccessExpression(node)
|
|
20
24
|
&& ts.isIdentifier(node.expression)
|
|
@@ -23,7 +27,7 @@ function collectExtractProps(fileName, templateCodeRange) {
|
|
|
23
27
|
const { name } = node;
|
|
24
28
|
for (const map of maps) {
|
|
25
29
|
let mapped = false;
|
|
26
|
-
for (const source of map.toSourceLocation(name.getEnd() - (isTsPlugin ?
|
|
30
|
+
for (const source of map.toSourceLocation(name.getEnd() - (isTsPlugin ? sourceScript.snapshot.getLength() : 0))) {
|
|
27
31
|
if (source[0] >= sfc.template.startTagEnd + templateCodeRange[0]
|
|
28
32
|
&& source[0] <= sfc.template.startTagEnd + templateCodeRange[1]
|
|
29
33
|
&& (0, language_core_1.isSemanticTokensEnabled)(source[1].data)) {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as vue from '@vue/language-core';
|
|
2
2
|
import type * as ts from 'typescript';
|
|
3
3
|
import type { RequestContext } from './types';
|
|
4
|
-
export declare function getComponentProps(this: RequestContext, fileName: string, tag: string
|
|
4
|
+
export declare function getComponentProps(this: RequestContext, fileName: string, tag: string): {
|
|
5
5
|
name: string;
|
|
6
|
-
|
|
6
|
+
required?: true;
|
|
7
|
+
commentMarkdown?: string;
|
|
7
8
|
}[] | undefined;
|
|
8
9
|
export declare function getComponentEvents(this: RequestContext, fileName: string, tag: string): string[] | undefined;
|
|
9
10
|
export declare function getTemplateContextProps(this: RequestContext, fileName: string): string[] | undefined;
|
|
@@ -8,7 +8,7 @@ exports._getComponentNames = _getComponentNames;
|
|
|
8
8
|
exports.getElementAttrs = getElementAttrs;
|
|
9
9
|
const vue = require("@vue/language-core");
|
|
10
10
|
const shared_1 = require("@vue/shared");
|
|
11
|
-
function getComponentProps(fileName, tag
|
|
11
|
+
function getComponentProps(fileName, tag) {
|
|
12
12
|
const { typescript: ts, language, languageService, getFileId } = this;
|
|
13
13
|
const volarFile = language.scripts.get(getFileId(fileName));
|
|
14
14
|
if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
|
|
@@ -22,11 +22,9 @@ function getComponentProps(fileName, tag, requiredOnly = false) {
|
|
|
22
22
|
return [];
|
|
23
23
|
}
|
|
24
24
|
const name = tag.split('.');
|
|
25
|
-
let componentSymbol = components.type.getProperty(name[0])
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
?? components.type.getProperty((0, shared_1.capitalize)((0, shared_1.camelize)(name[0])));
|
|
29
|
-
}
|
|
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])));
|
|
30
28
|
if (!componentSymbol) {
|
|
31
29
|
return [];
|
|
32
30
|
}
|
|
@@ -47,11 +45,10 @@ function getComponentProps(fileName, tag, requiredOnly = false) {
|
|
|
47
45
|
const propsType = checker.getTypeOfSymbolAtLocation(propParam, components.node);
|
|
48
46
|
const props = propsType.getProperties();
|
|
49
47
|
for (const prop of props) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
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 });
|
|
55
52
|
}
|
|
56
53
|
}
|
|
57
54
|
}
|
|
@@ -65,11 +62,10 @@ function getComponentProps(fileName, tag, requiredOnly = false) {
|
|
|
65
62
|
if (prop.flags & ts.SymbolFlags.Method) { // #2443
|
|
66
63
|
continue;
|
|
67
64
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
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 });
|
|
73
69
|
}
|
|
74
70
|
}
|
|
75
71
|
}
|
|
@@ -155,7 +151,7 @@ function getComponentNames(fileName) {
|
|
|
155
151
|
?.type
|
|
156
152
|
?.getProperties()
|
|
157
153
|
.map(c => c.name)
|
|
158
|
-
.filter(entry => entry.
|
|
154
|
+
.filter(entry => !entry.includes('$') && !entry.startsWith('_'))
|
|
159
155
|
?? [];
|
|
160
156
|
}
|
|
161
157
|
function _getComponentNames(ts, tsLs, vueCode) {
|
|
@@ -163,7 +159,7 @@ function _getComponentNames(ts, tsLs, vueCode) {
|
|
|
163
159
|
?.type
|
|
164
160
|
?.getProperties()
|
|
165
161
|
.map(c => c.name)
|
|
166
|
-
.filter(entry => entry.
|
|
162
|
+
.filter(entry => !entry.includes('$') && !entry.startsWith('_'))
|
|
167
163
|
?? [];
|
|
168
164
|
}
|
|
169
165
|
function getElementAttrs(fileName, tagName) {
|
package/lib/requests/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Language } from '@vue/language-core';
|
|
2
2
|
import type * as ts from 'typescript';
|
|
3
3
|
export interface RequestContext<T = any> {
|
|
4
|
-
typescript: typeof
|
|
4
|
+
typescript: typeof ts;
|
|
5
5
|
languageService: ts.LanguageService;
|
|
6
6
|
languageServiceHost: ts.LanguageServiceHost;
|
|
7
7
|
language: Language<T>;
|
package/lib/server.d.ts
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Language } from '@vue/language-core';
|
|
2
2
|
import type * as ts from 'typescript';
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
export type RequestType = 'containsFile' | 'projectInfo' | 'collectExtractProps' | 'getImportPathForFile' | 'getPropertiesAtLocation' | 'getQuickInfoAtPosition' | 'subscribeComponentProps' | 'getComponentEvents' | 'getTemplateContextProps' | 'getElementAttrs';
|
|
4
|
+
export type NotificationType = 'componentNamesUpdated' | 'componentPropsUpdated';
|
|
5
|
+
export type RequestData = [
|
|
6
|
+
seq: number,
|
|
7
|
+
type: RequestType,
|
|
8
|
+
fileName: string,
|
|
9
|
+
...args: any[]
|
|
10
|
+
];
|
|
11
|
+
export type ResponseData = [
|
|
12
|
+
seq: number,
|
|
13
|
+
data: any
|
|
14
|
+
];
|
|
15
|
+
export type NotificationData = [
|
|
16
|
+
type: NotificationType,
|
|
17
|
+
fileName: string,
|
|
18
|
+
data: any
|
|
19
|
+
];
|
|
7
20
|
export interface ProjectInfo {
|
|
8
21
|
name: string;
|
|
9
22
|
kind: ts.server.ProjectKind;
|
package/lib/server.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.startNamedPipeServer = startNamedPipeServer;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const language_core_1 = require("@vue/language-core");
|
|
5
|
+
const fs = require("node:fs");
|
|
6
|
+
const net = require("node:net");
|
|
6
7
|
const collectExtractProps_1 = require("./requests/collectExtractProps");
|
|
7
8
|
const componentInfos_1 = require("./requests/componentInfos");
|
|
8
9
|
const getImportPathForFile_1 = require("./requests/getImportPathForFile");
|
|
@@ -10,82 +11,55 @@ const getPropertiesAtLocation_1 = require("./requests/getPropertiesAtLocation");
|
|
|
10
11
|
const getQuickInfoAtPosition_1 = require("./requests/getQuickInfoAtPosition");
|
|
11
12
|
const utils_1 = require("./utils");
|
|
12
13
|
async function startNamedPipeServer(ts, info, language, projectKind) {
|
|
14
|
+
let lastProjectVersion;
|
|
15
|
+
const requestContext = {
|
|
16
|
+
typescript: ts,
|
|
17
|
+
languageService: info.languageService,
|
|
18
|
+
languageServiceHost: info.languageServiceHost,
|
|
19
|
+
language: language,
|
|
20
|
+
isTsPlugin: true,
|
|
21
|
+
getFileId: (fileName) => fileName,
|
|
22
|
+
};
|
|
23
|
+
const dataChunks = [];
|
|
24
|
+
const currentData = new language_core_1.FileMap(false);
|
|
25
|
+
const allConnections = new Set();
|
|
26
|
+
const pendingRequests = new Set();
|
|
13
27
|
const server = net.createServer(connection => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
kind: info.project.projectKind,
|
|
37
|
-
currentDirectory: info.project.getCurrentDirectory(),
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
else if (request.type === 'collectExtractProps') {
|
|
41
|
-
const result = collectExtractProps_1.collectExtractProps.apply(requestContext, request.args);
|
|
42
|
-
sendResponse(result);
|
|
43
|
-
}
|
|
44
|
-
else if (request.type === 'getImportPathForFile') {
|
|
45
|
-
const result = getImportPathForFile_1.getImportPathForFile.apply(requestContext, request.args);
|
|
46
|
-
sendResponse(result);
|
|
47
|
-
}
|
|
48
|
-
else if (request.type === 'getPropertiesAtLocation') {
|
|
49
|
-
const result = getPropertiesAtLocation_1.getPropertiesAtLocation.apply(requestContext, request.args);
|
|
50
|
-
sendResponse(result);
|
|
51
|
-
}
|
|
52
|
-
else if (request.type === 'getQuickInfoAtPosition') {
|
|
53
|
-
const result = getQuickInfoAtPosition_1.getQuickInfoAtPosition.apply(requestContext, request.args);
|
|
54
|
-
sendResponse(result);
|
|
55
|
-
}
|
|
56
|
-
// Component Infos
|
|
57
|
-
else if (request.type === 'getComponentProps') {
|
|
58
|
-
const result = componentInfos_1.getComponentProps.apply(requestContext, request.args);
|
|
59
|
-
sendResponse(result);
|
|
60
|
-
}
|
|
61
|
-
else if (request.type === 'getComponentEvents') {
|
|
62
|
-
const result = componentInfos_1.getComponentEvents.apply(requestContext, request.args);
|
|
63
|
-
sendResponse(result);
|
|
64
|
-
}
|
|
65
|
-
else if (request.type === 'getTemplateContextProps') {
|
|
66
|
-
const result = componentInfos_1.getTemplateContextProps.apply(requestContext, request.args);
|
|
67
|
-
sendResponse(result);
|
|
68
|
-
}
|
|
69
|
-
else if (request.type === 'getComponentNames') {
|
|
70
|
-
const result = componentInfos_1.getComponentNames.apply(requestContext, request.args);
|
|
71
|
-
sendResponse(result);
|
|
72
|
-
}
|
|
73
|
-
else if (request.type === 'getElementAttrs') {
|
|
74
|
-
const result = componentInfos_1.getElementAttrs.apply(requestContext, request.args);
|
|
75
|
-
sendResponse(result);
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
console.warn('[Vue Named Pipe Server] Unknown request type:', request.type);
|
|
28
|
+
allConnections.add(connection);
|
|
29
|
+
connection.on('end', () => {
|
|
30
|
+
allConnections.delete(connection);
|
|
31
|
+
});
|
|
32
|
+
connection.on('data', buffer => {
|
|
33
|
+
dataChunks.push(buffer);
|
|
34
|
+
const text = dataChunks.toString();
|
|
35
|
+
if (text.endsWith('\n\n')) {
|
|
36
|
+
dataChunks.length = 0;
|
|
37
|
+
const requests = text.split('\n\n');
|
|
38
|
+
for (let json of requests) {
|
|
39
|
+
json = json.trim();
|
|
40
|
+
if (!json) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
onRequest(connection, JSON.parse(json));
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
console.error('[Vue Named Pipe Server] JSON parse error:', e);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
79
50
|
}
|
|
80
51
|
});
|
|
81
52
|
connection.on('error', err => console.error('[Vue Named Pipe Server]', err.message));
|
|
82
|
-
|
|
83
|
-
connection
|
|
53
|
+
for (const [fileName, [componentNames, componentProps]] of currentData) {
|
|
54
|
+
notify(connection, 'componentNamesUpdated', fileName, Object.keys(componentNames));
|
|
55
|
+
for (const [name, props] of Object.entries(componentProps)) {
|
|
56
|
+
notify(connection, 'componentPropsUpdated', fileName, [name, props]);
|
|
57
|
+
}
|
|
84
58
|
}
|
|
85
59
|
});
|
|
86
|
-
for (let i = 0; i <
|
|
87
|
-
const path = (0, utils_1.
|
|
88
|
-
const socket = await
|
|
60
|
+
for (let i = 0; i < 10; i++) {
|
|
61
|
+
const path = (0, utils_1.getServerPath)(projectKind, i);
|
|
62
|
+
const socket = await connect(path, 100);
|
|
89
63
|
if (typeof socket === 'object') {
|
|
90
64
|
socket.end();
|
|
91
65
|
}
|
|
@@ -98,6 +72,164 @@ async function startNamedPipeServer(ts, info, language, projectKind) {
|
|
|
98
72
|
break;
|
|
99
73
|
}
|
|
100
74
|
}
|
|
75
|
+
updateWhile();
|
|
76
|
+
async function updateWhile() {
|
|
77
|
+
while (true) {
|
|
78
|
+
await sleep(500);
|
|
79
|
+
const projectVersion = info.project.getProjectVersion();
|
|
80
|
+
if (lastProjectVersion === projectVersion) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const connections = [...allConnections].filter(c => !c.destroyed);
|
|
84
|
+
if (!connections.length) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const token = info.languageServiceHost.getCancellationToken?.();
|
|
88
|
+
const openedScriptInfos = info.project.getRootScriptInfos().filter(info => info.isScriptOpen());
|
|
89
|
+
if (!openedScriptInfos.length) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
for (const scriptInfo of openedScriptInfos) {
|
|
93
|
+
await sleep(10);
|
|
94
|
+
if (token?.isCancellationRequested()) {
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
let data = currentData.get(scriptInfo.fileName);
|
|
98
|
+
if (!data) {
|
|
99
|
+
data = [[], {}];
|
|
100
|
+
currentData.set(scriptInfo.fileName, data);
|
|
101
|
+
}
|
|
102
|
+
const [oldComponentNames, componentProps] = data;
|
|
103
|
+
const newComponentNames = componentInfos_1.getComponentNames.apply(requestContext, [scriptInfo.fileName]) ?? [];
|
|
104
|
+
if (JSON.stringify(oldComponentNames) !== JSON.stringify(newComponentNames)) {
|
|
105
|
+
data[0] = newComponentNames;
|
|
106
|
+
for (const connection of connections) {
|
|
107
|
+
notify(connection, 'componentNamesUpdated', scriptInfo.fileName, newComponentNames);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
for (const [name, props] of Object.entries(componentProps)) {
|
|
111
|
+
await sleep(10);
|
|
112
|
+
if (token?.isCancellationRequested()) {
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
const newProps = componentInfos_1.getComponentProps.apply(requestContext, [scriptInfo.fileName, name]) ?? [];
|
|
116
|
+
if (JSON.stringify(props) !== JSON.stringify(newProps)) {
|
|
117
|
+
componentProps[name] = newProps;
|
|
118
|
+
for (const connection of connections) {
|
|
119
|
+
notify(connection, 'componentPropsUpdated', scriptInfo.fileName, [name, newProps]);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
lastProjectVersion = projectVersion;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function sleep(ms) {
|
|
128
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
129
|
+
}
|
|
130
|
+
function notify(connection, type, fileName, data) {
|
|
131
|
+
connection.write(JSON.stringify([type, fileName, data]) + '\n\n');
|
|
132
|
+
}
|
|
133
|
+
function onRequest(connection, [seq, requestType, ...args]) {
|
|
134
|
+
if (pendingRequests.has(seq)) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
setTimeout(() => pendingRequests.delete(seq), 500);
|
|
138
|
+
pendingRequests.add(seq);
|
|
139
|
+
let data;
|
|
140
|
+
try {
|
|
141
|
+
data = handleRequest(requestType, ...args);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
data = null;
|
|
145
|
+
}
|
|
146
|
+
connection.write(JSON.stringify([seq, data ?? null]) + '\n\n');
|
|
147
|
+
}
|
|
148
|
+
function handleRequest(requestType, ...args) {
|
|
149
|
+
const fileName = args[0];
|
|
150
|
+
if (requestType === 'projectInfo') {
|
|
151
|
+
return {
|
|
152
|
+
name: info.project.getProjectName(),
|
|
153
|
+
kind: info.project.projectKind,
|
|
154
|
+
currentDirectory: info.project.getCurrentDirectory(),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
else if (requestType === 'containsFile') {
|
|
158
|
+
return info.project.containsFile(ts.server.toNormalizedPath(fileName));
|
|
159
|
+
}
|
|
160
|
+
else if (requestType === 'collectExtractProps') {
|
|
161
|
+
return collectExtractProps_1.collectExtractProps.apply(requestContext, args);
|
|
162
|
+
}
|
|
163
|
+
else if (requestType === 'getImportPathForFile') {
|
|
164
|
+
return getImportPathForFile_1.getImportPathForFile.apply(requestContext, args);
|
|
165
|
+
}
|
|
166
|
+
else if (requestType === 'getPropertiesAtLocation') {
|
|
167
|
+
return getPropertiesAtLocation_1.getPropertiesAtLocation.apply(requestContext, args);
|
|
168
|
+
}
|
|
169
|
+
else if (requestType === 'getQuickInfoAtPosition') {
|
|
170
|
+
return getQuickInfoAtPosition_1.getQuickInfoAtPosition.apply(requestContext, args);
|
|
171
|
+
}
|
|
172
|
+
else if (requestType === 'subscribeComponentProps') {
|
|
173
|
+
const tag = args[1];
|
|
174
|
+
const props = componentInfos_1.getComponentProps.apply(requestContext, [fileName, tag]) ?? [];
|
|
175
|
+
let data = currentData.get(fileName);
|
|
176
|
+
if (!data) {
|
|
177
|
+
data = [[], {}];
|
|
178
|
+
currentData.set(fileName, data);
|
|
179
|
+
}
|
|
180
|
+
data[1][tag] = props;
|
|
181
|
+
return props;
|
|
182
|
+
}
|
|
183
|
+
else if (requestType === 'getComponentEvents') {
|
|
184
|
+
return componentInfos_1.getComponentEvents.apply(requestContext, args);
|
|
185
|
+
}
|
|
186
|
+
else if (requestType === 'getTemplateContextProps') {
|
|
187
|
+
return componentInfos_1.getTemplateContextProps.apply(requestContext, args);
|
|
188
|
+
}
|
|
189
|
+
else if (requestType === 'getElementAttrs') {
|
|
190
|
+
return componentInfos_1.getElementAttrs.apply(requestContext, args);
|
|
191
|
+
}
|
|
192
|
+
console.warn('[Vue Named Pipe Server] Unknown request:', requestType);
|
|
193
|
+
debugger;
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function connect(namedPipePath, timeout) {
|
|
198
|
+
return new Promise(resolve => {
|
|
199
|
+
const socket = net.connect(namedPipePath);
|
|
200
|
+
if (timeout) {
|
|
201
|
+
socket.setTimeout(timeout);
|
|
202
|
+
}
|
|
203
|
+
const onConnect = () => {
|
|
204
|
+
cleanup();
|
|
205
|
+
resolve(socket);
|
|
206
|
+
};
|
|
207
|
+
const onError = (err) => {
|
|
208
|
+
if (err.code === 'ECONNREFUSED') {
|
|
209
|
+
try {
|
|
210
|
+
console.log('[Vue Named Pipe Client] Deleting:', namedPipePath);
|
|
211
|
+
fs.promises.unlink(namedPipePath);
|
|
212
|
+
}
|
|
213
|
+
catch { }
|
|
214
|
+
}
|
|
215
|
+
cleanup();
|
|
216
|
+
resolve('error');
|
|
217
|
+
socket.end();
|
|
218
|
+
};
|
|
219
|
+
const onTimeout = () => {
|
|
220
|
+
cleanup();
|
|
221
|
+
resolve('timeout');
|
|
222
|
+
socket.end();
|
|
223
|
+
};
|
|
224
|
+
const cleanup = () => {
|
|
225
|
+
socket.off('connect', onConnect);
|
|
226
|
+
socket.off('error', onError);
|
|
227
|
+
socket.off('timeout', onTimeout);
|
|
228
|
+
};
|
|
229
|
+
socket.on('connect', onConnect);
|
|
230
|
+
socket.on('error', onError);
|
|
231
|
+
socket.on('timeout', onTimeout);
|
|
232
|
+
});
|
|
101
233
|
}
|
|
102
234
|
function tryListen(server, namedPipePath) {
|
|
103
235
|
return new Promise(resolve => {
|
package/lib/utils.d.ts
CHANGED
|
@@ -1,16 +1,38 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FileMap } from '@vue/language-core';
|
|
2
|
+
import * as net from 'node:net';
|
|
2
3
|
import type * as ts from 'typescript';
|
|
3
|
-
import type { ProjectInfo,
|
|
4
|
+
import type { NotificationData, ProjectInfo, RequestData } from './server';
|
|
4
5
|
export { TypeScriptProjectHost } from '@volar/typescript';
|
|
5
|
-
export declare
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} |
|
|
16
|
-
|
|
6
|
+
export declare function getServerPath(kind: ts.server.ProjectKind, id: number): string;
|
|
7
|
+
declare class NamedPipeServer {
|
|
8
|
+
path: string;
|
|
9
|
+
connecting: boolean;
|
|
10
|
+
projectInfo?: ProjectInfo;
|
|
11
|
+
containsFileCache: Map<string, Promise<boolean | null | undefined>>;
|
|
12
|
+
componentNamesAndProps: FileMap<Record<string, {
|
|
13
|
+
name: string;
|
|
14
|
+
required?: true;
|
|
15
|
+
commentMarkdown?: string;
|
|
16
|
+
}[] | null>>;
|
|
17
|
+
constructor(kind: ts.server.ProjectKind, id: number);
|
|
18
|
+
containsFile(fileName: string): Promise<boolean | null | undefined> | undefined;
|
|
19
|
+
getComponentProps(fileName: string, tag: string): Promise<{
|
|
20
|
+
name: string;
|
|
21
|
+
required?: true;
|
|
22
|
+
commentMarkdown?: string;
|
|
23
|
+
}[] | null | undefined>;
|
|
24
|
+
update(): void;
|
|
25
|
+
connect(): void;
|
|
26
|
+
close(): void;
|
|
27
|
+
socket?: net.Socket;
|
|
28
|
+
seq: number;
|
|
29
|
+
dataChunks: Buffer[];
|
|
30
|
+
requestHandlers: Map<number, (res: any) => void>;
|
|
31
|
+
onData(chunk: Buffer): void;
|
|
32
|
+
onNotification(type: NotificationData[0], fileName: string, data: any): void;
|
|
33
|
+
sendRequest<T>(requestType: RequestData[1], fileName: string, ...args: any[]): Promise<T | null | undefined>;
|
|
34
|
+
}
|
|
35
|
+
export declare const configuredServers: NamedPipeServer[];
|
|
36
|
+
export declare const inferredServers: NamedPipeServer[];
|
|
37
|
+
export declare const onServerReady: (() => void)[];
|
|
38
|
+
export declare function getBestServer(fileName: string): Promise<NamedPipeServer | undefined>;
|
package/lib/utils.js
CHANGED
|
@@ -1,195 +1,232 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.
|
|
5
|
-
exports.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const path = require("path");
|
|
3
|
+
exports.onServerReady = exports.inferredServers = exports.configuredServers = void 0;
|
|
4
|
+
exports.getServerPath = getServerPath;
|
|
5
|
+
exports.getBestServer = getBestServer;
|
|
6
|
+
const language_core_1 = require("@vue/language-core");
|
|
7
|
+
const shared_1 = require("@vue/shared");
|
|
8
|
+
const fs = require("node:fs");
|
|
9
|
+
const net = require("node:net");
|
|
10
|
+
const os = require("node:os");
|
|
11
|
+
const path = require("node:path");
|
|
13
12
|
const { version } = require('../package.json');
|
|
14
13
|
const platform = os.platform();
|
|
15
14
|
const pipeDir = platform === 'win32'
|
|
16
|
-
? `\\\\.\\pipe
|
|
17
|
-
: `/tmp
|
|
18
|
-
|
|
19
|
-
if (
|
|
20
|
-
return pipeDir
|
|
15
|
+
? `\\\\.\\pipe\\`
|
|
16
|
+
: `/tmp/`;
|
|
17
|
+
function getServerPath(kind, id) {
|
|
18
|
+
if (kind === 1) {
|
|
19
|
+
return `${pipeDir}vue-named-pipe-${version}-configured-${id}`;
|
|
21
20
|
}
|
|
22
21
|
else {
|
|
23
|
-
return pipeDir
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
const configuredNamedPipePathPrefix = toFullPath(`vue-named-pipe-${version}-configured-`);
|
|
27
|
-
const inferredNamedPipePathPrefix = toFullPath(`vue-named-pipe-${version}-inferred-`);
|
|
28
|
-
const pipes = new Map();
|
|
29
|
-
exports.onSomePipeReadyCallbacks = [];
|
|
30
|
-
function waitingForNamedPipeServerReady(namedPipePath) {
|
|
31
|
-
const socket = net.connect(namedPipePath);
|
|
32
|
-
const start = Date.now();
|
|
33
|
-
socket.on('connect', () => {
|
|
34
|
-
console.log('[Vue Named Pipe Client] Connected:', namedPipePath, 'in', (Date.now() - start) + 'ms');
|
|
35
|
-
socket.write('ping');
|
|
36
|
-
});
|
|
37
|
-
socket.on('data', () => {
|
|
38
|
-
console.log('[Vue Named Pipe Client] Ready:', namedPipePath, 'in', (Date.now() - start) + 'ms');
|
|
39
|
-
pipes.set(namedPipePath, 'ready');
|
|
40
|
-
socket.end();
|
|
41
|
-
exports.onSomePipeReadyCallbacks.forEach(cb => cb());
|
|
42
|
-
});
|
|
43
|
-
socket.on('error', err => {
|
|
44
|
-
if (err.code === 'ECONNREFUSED') {
|
|
45
|
-
try {
|
|
46
|
-
console.log('[Vue Named Pipe Client] Deleting:', namedPipePath);
|
|
47
|
-
fs.promises.unlink(namedPipePath);
|
|
48
|
-
}
|
|
49
|
-
catch { }
|
|
50
|
-
}
|
|
51
|
-
pipes.delete(namedPipePath);
|
|
52
|
-
socket.end();
|
|
53
|
-
});
|
|
54
|
-
socket.on('timeout', () => {
|
|
55
|
-
pipes.delete(namedPipePath);
|
|
56
|
-
socket.end();
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
function getNamedPipePath(projectKind, key) {
|
|
60
|
-
return projectKind === 1
|
|
61
|
-
? `${configuredNamedPipePathPrefix}${key}`
|
|
62
|
-
: `${inferredNamedPipePathPrefix}${key}`;
|
|
22
|
+
return `${pipeDir}vue-named-pipe-${version}-inferred-${id}`;
|
|
23
|
+
}
|
|
63
24
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
25
|
+
class NamedPipeServer {
|
|
26
|
+
constructor(kind, id) {
|
|
27
|
+
this.connecting = false;
|
|
28
|
+
this.containsFileCache = new Map();
|
|
29
|
+
this.componentNamesAndProps = new language_core_1.FileMap(false);
|
|
30
|
+
this.seq = 0;
|
|
31
|
+
this.dataChunks = [];
|
|
32
|
+
this.requestHandlers = new Map();
|
|
33
|
+
this.path = getServerPath(kind, id);
|
|
34
|
+
}
|
|
35
|
+
containsFile(fileName) {
|
|
36
|
+
if (this.projectInfo) {
|
|
37
|
+
if (!this.containsFileCache.has(fileName)) {
|
|
38
|
+
this.containsFileCache.set(fileName, (async () => {
|
|
39
|
+
const res = await this.sendRequest('containsFile', fileName);
|
|
40
|
+
if (typeof res !== 'boolean') {
|
|
41
|
+
// If the request fails, delete the cache
|
|
42
|
+
this.containsFileCache.delete(fileName);
|
|
43
|
+
}
|
|
44
|
+
return res;
|
|
45
|
+
})());
|
|
46
|
+
}
|
|
47
|
+
return this.containsFileCache.get(fileName);
|
|
76
48
|
}
|
|
77
|
-
|
|
78
|
-
|
|
49
|
+
}
|
|
50
|
+
async getComponentProps(fileName, tag) {
|
|
51
|
+
const componentAndProps = this.componentNamesAndProps.get(fileName);
|
|
52
|
+
if (!componentAndProps) {
|
|
53
|
+
return;
|
|
79
54
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
55
|
+
const props = componentAndProps[tag]
|
|
56
|
+
?? componentAndProps[(0, shared_1.camelize)(tag)]
|
|
57
|
+
?? componentAndProps[(0, shared_1.capitalize)((0, shared_1.camelize)(tag))];
|
|
58
|
+
if (props) {
|
|
59
|
+
return props;
|
|
83
60
|
}
|
|
61
|
+
return await this.sendRequest('subscribeComponentProps', fileName, tag);
|
|
84
62
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
function connect(namedPipePath, timeout) {
|
|
91
|
-
return new Promise(resolve => {
|
|
92
|
-
const socket = net.connect(namedPipePath);
|
|
93
|
-
if (timeout) {
|
|
94
|
-
socket.setTimeout(timeout);
|
|
63
|
+
update() {
|
|
64
|
+
if (!this.connecting && !this.projectInfo) {
|
|
65
|
+
this.connecting = true;
|
|
66
|
+
this.connect();
|
|
95
67
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
68
|
+
}
|
|
69
|
+
connect() {
|
|
70
|
+
this.socket = net.connect(this.path);
|
|
71
|
+
this.socket.on('data', this.onData.bind(this));
|
|
72
|
+
this.socket.on('connect', async () => {
|
|
73
|
+
const projectInfo = await this.sendRequest('projectInfo', '');
|
|
74
|
+
if (projectInfo) {
|
|
75
|
+
console.log('TSServer project ready:', projectInfo.name);
|
|
76
|
+
this.projectInfo = projectInfo;
|
|
77
|
+
this.containsFileCache.clear();
|
|
78
|
+
exports.onServerReady.forEach(cb => cb());
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
this.close();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
this.socket.on('error', err => {
|
|
101
85
|
if (err.code === 'ECONNREFUSED') {
|
|
102
86
|
try {
|
|
103
|
-
console.log('
|
|
104
|
-
fs.promises.unlink(
|
|
87
|
+
console.log('Deleteing invalid named pipe file:', this.path);
|
|
88
|
+
fs.promises.unlink(this.path);
|
|
105
89
|
}
|
|
106
90
|
catch { }
|
|
107
91
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
92
|
+
this.close();
|
|
93
|
+
});
|
|
94
|
+
this.socket.on('timeout', () => {
|
|
95
|
+
this.close();
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
close() {
|
|
99
|
+
this.connecting = false;
|
|
100
|
+
this.projectInfo = undefined;
|
|
101
|
+
this.socket?.end();
|
|
102
|
+
}
|
|
103
|
+
onData(chunk) {
|
|
104
|
+
this.dataChunks.push(chunk);
|
|
105
|
+
const data = Buffer.concat(this.dataChunks);
|
|
106
|
+
const text = data.toString();
|
|
107
|
+
if (text.endsWith('\n\n')) {
|
|
108
|
+
this.dataChunks.length = 0;
|
|
109
|
+
const results = text.split('\n\n');
|
|
110
|
+
for (let result of results) {
|
|
111
|
+
result = result.trim();
|
|
112
|
+
if (!result) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
const data = JSON.parse(result.trim());
|
|
117
|
+
if (typeof data[0] === 'number') {
|
|
118
|
+
const [seq, res] = data;
|
|
119
|
+
this.requestHandlers.get(seq)?.(res);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
const [type, fileName, res] = data;
|
|
123
|
+
this.onNotification(type, fileName, res);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (e) {
|
|
127
|
+
console.error('JSON parse error:', e);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
onNotification(type, fileName, data) {
|
|
133
|
+
// console.log(`[${type}] ${fileName} ${JSON.stringify(data)}`);
|
|
134
|
+
if (type === 'componentNamesUpdated') {
|
|
135
|
+
let components = this.componentNamesAndProps.get(fileName);
|
|
136
|
+
if (!components) {
|
|
137
|
+
components = {};
|
|
138
|
+
this.componentNamesAndProps.set(fileName, components);
|
|
139
|
+
}
|
|
140
|
+
const newNames = data;
|
|
141
|
+
const newNameSet = new Set(newNames);
|
|
142
|
+
for (const name in components) {
|
|
143
|
+
if (!newNameSet.has(name)) {
|
|
144
|
+
delete components[name];
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
for (const name of newNames) {
|
|
148
|
+
if (!components[name]) {
|
|
149
|
+
components[name] = null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else if (type === 'componentPropsUpdated') {
|
|
154
|
+
const components = this.componentNamesAndProps.get(fileName) ?? {};
|
|
155
|
+
const [name, props] = data;
|
|
156
|
+
components[name] = props;
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
console.error('Unknown notification type:', type);
|
|
160
|
+
debugger;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
sendRequest(requestType, fileName, ...args) {
|
|
164
|
+
return new Promise(resolve => {
|
|
165
|
+
const seq = this.seq++;
|
|
166
|
+
// console.time(`[${seq}] ${requestType} ${fileName}`);
|
|
167
|
+
this.requestHandlers.set(seq, data => {
|
|
168
|
+
// console.timeEnd(`[${seq}] ${requestType} ${fileName}`);
|
|
169
|
+
this.requestHandlers.delete(seq);
|
|
170
|
+
resolve(data);
|
|
171
|
+
clearInterval(retryTimer);
|
|
172
|
+
});
|
|
173
|
+
const retry = () => {
|
|
174
|
+
const data = [seq, requestType, fileName, ...args];
|
|
175
|
+
this.socket.write(JSON.stringify(data) + '\n\n');
|
|
176
|
+
};
|
|
177
|
+
retry();
|
|
178
|
+
const retryTimer = setInterval(retry, 1000);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
127
181
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
182
|
+
exports.configuredServers = [];
|
|
183
|
+
exports.inferredServers = [];
|
|
184
|
+
exports.onServerReady = [];
|
|
185
|
+
for (let i = 0; i < 10; i++) {
|
|
186
|
+
exports.configuredServers.push(new NamedPipeServer(1, i));
|
|
187
|
+
exports.inferredServers.push(new NamedPipeServer(0, i));
|
|
188
|
+
}
|
|
189
|
+
async function getBestServer(fileName) {
|
|
190
|
+
for (const server of exports.configuredServers) {
|
|
191
|
+
server.update();
|
|
192
|
+
}
|
|
193
|
+
let servers = (await Promise.all(exports.configuredServers.map(async (server) => {
|
|
194
|
+
const projectInfo = server.projectInfo;
|
|
195
|
+
if (!projectInfo) {
|
|
134
196
|
return;
|
|
135
197
|
}
|
|
136
|
-
|
|
137
|
-
const containsFile = await sendRequestWorker({ type: 'containsFile', args: [fileName] }, socket);
|
|
198
|
+
const containsFile = await server.containsFile(fileName);
|
|
138
199
|
if (!containsFile) {
|
|
139
|
-
socket.end();
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
// Get project info for each server
|
|
143
|
-
const projectInfo = await sendRequestWorker({ type: 'projectInfo', args: [fileName] }, socket);
|
|
144
|
-
if (!projectInfo) {
|
|
145
|
-
socket.end();
|
|
146
200
|
return;
|
|
147
201
|
}
|
|
148
|
-
return
|
|
149
|
-
socket,
|
|
150
|
-
projectInfo,
|
|
151
|
-
};
|
|
202
|
+
return server;
|
|
152
203
|
}))).filter(server => !!server);
|
|
153
204
|
// Sort servers by tsconfig
|
|
154
|
-
|
|
155
|
-
if (
|
|
156
|
-
// Close all but the first server
|
|
157
|
-
for (let i = 1; i < configuredServers.length; i++) {
|
|
158
|
-
configuredServers[i].socket.end();
|
|
159
|
-
}
|
|
205
|
+
servers.sort((a, b) => sortTSConfigs(fileName, a.projectInfo.name, b.projectInfo.name));
|
|
206
|
+
if (servers.length) {
|
|
160
207
|
// Return the first server
|
|
161
|
-
return
|
|
208
|
+
return servers[0];
|
|
162
209
|
}
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
// Get project info for each server
|
|
170
|
-
const projectInfo = await sendRequestWorker({ type: 'projectInfo', args: [fileName] }, socket);
|
|
210
|
+
for (const server of exports.inferredServers) {
|
|
211
|
+
server.update();
|
|
212
|
+
}
|
|
213
|
+
servers = (await Promise.all(exports.inferredServers.map(server => {
|
|
214
|
+
const projectInfo = server.projectInfo;
|
|
171
215
|
if (!projectInfo) {
|
|
172
|
-
socket.end();
|
|
173
216
|
return;
|
|
174
217
|
}
|
|
175
218
|
// Check if the file is in the project's directory
|
|
176
|
-
if (
|
|
177
|
-
return
|
|
178
|
-
socket,
|
|
179
|
-
projectInfo,
|
|
180
|
-
};
|
|
219
|
+
if (path.relative(projectInfo.currentDirectory, fileName).startsWith('..')) {
|
|
220
|
+
return;
|
|
181
221
|
}
|
|
222
|
+
return server;
|
|
182
223
|
}))).filter(server => !!server);
|
|
183
224
|
// Sort servers by directory
|
|
184
|
-
|
|
225
|
+
servers.sort((a, b) => b.projectInfo.currentDirectory.replace(/\\/g, '/').split('/').length
|
|
185
226
|
- a.projectInfo.currentDirectory.replace(/\\/g, '/').split('/').length);
|
|
186
|
-
if (
|
|
187
|
-
// Close all but the first server
|
|
188
|
-
for (let i = 1; i < inferredServers.length; i++) {
|
|
189
|
-
inferredServers[i].socket.end();
|
|
190
|
-
}
|
|
227
|
+
if (servers.length) {
|
|
191
228
|
// Return the first server
|
|
192
|
-
return
|
|
229
|
+
return servers[0];
|
|
193
230
|
}
|
|
194
231
|
}
|
|
195
232
|
function sortTSConfigs(file, a, b) {
|
|
@@ -208,37 +245,4 @@ function isFileInDir(fileName, dir) {
|
|
|
208
245
|
const relative = path.relative(dir, fileName);
|
|
209
246
|
return !!relative && !relative.startsWith('..') && !path.isAbsolute(relative);
|
|
210
247
|
}
|
|
211
|
-
function sendRequestWorker(request, socket) {
|
|
212
|
-
return new Promise(resolve => {
|
|
213
|
-
let dataChunks = [];
|
|
214
|
-
const onData = (chunk) => {
|
|
215
|
-
dataChunks.push(chunk);
|
|
216
|
-
const data = Buffer.concat(dataChunks);
|
|
217
|
-
const text = data.toString();
|
|
218
|
-
if (text.endsWith('\n\n')) {
|
|
219
|
-
let json = null;
|
|
220
|
-
try {
|
|
221
|
-
json = JSON.parse(text);
|
|
222
|
-
}
|
|
223
|
-
catch (e) {
|
|
224
|
-
console.error('[Vue Named Pipe Client] Failed to parse response:', text);
|
|
225
|
-
}
|
|
226
|
-
cleanup();
|
|
227
|
-
resolve(json);
|
|
228
|
-
}
|
|
229
|
-
};
|
|
230
|
-
const onError = (err) => {
|
|
231
|
-
console.error('[Vue Named Pipe Client] Error:', err.message);
|
|
232
|
-
cleanup();
|
|
233
|
-
resolve(undefined);
|
|
234
|
-
};
|
|
235
|
-
const cleanup = () => {
|
|
236
|
-
socket.off('data', onData);
|
|
237
|
-
socket.off('error', onError);
|
|
238
|
-
};
|
|
239
|
-
socket.on('data', onData);
|
|
240
|
-
socket.on('error', onError);
|
|
241
|
-
socket.write(JSON.stringify(request));
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
248
|
//# sourceMappingURL=utils.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vue/typescript-plugin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"**/*.js",
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
"directory": "packages/typescript-plugin"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@volar/typescript": "~2.4.
|
|
17
|
-
"@vue/language-core": "2.
|
|
16
|
+
"@volar/typescript": "~2.4.11",
|
|
17
|
+
"@vue/language-core": "2.2.0",
|
|
18
18
|
"@vue/shared": "^3.5.0"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "latest"
|
|
22
22
|
},
|
|
23
|
-
"gitHead": "
|
|
23
|
+
"gitHead": "5babca774658d4b9afbe877ac7c8cafdaecf2c3e"
|
|
24
24
|
}
|