Skip to content

Commit e8bd161

Browse files
feat(typescript-plugin): define named pipe unique file name based on pid (#3916)
1 parent 4b8fa93 commit e8bd161

File tree

5 files changed

+107
-9
lines changed

5 files changed

+107
-9
lines changed

packages/typescript-plugin/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ function createLanguageServicePlugin(): ts.server.PluginModuleFactory {
6060

6161
decorateLanguageService(files, info.languageService);
6262
decorateLanguageServiceHost(files, info.languageServiceHost, ts);
63-
startNamedPipeServer();
63+
startNamedPipeServer(info.project.projectKind);
6464

6565
const getCompletionsAtPosition = info.languageService.getCompletionsAtPosition;
6666
const getEncodedSemanticClassifications = info.languageService.getEncodedSemanticClassifications;

packages/typescript-plugin/lib/client.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import * as net from 'net';
2+
import * as fs from 'fs';
3+
import type * as ts from 'typescript';
24
import type { Request } from './server';
3-
import { pipeFile } from './utils';
5+
import type { PipeTable } from './utils';
6+
import { pipeTable } from './utils';
47

58
export function collectExtractProps(
69
...args: Parameters<typeof import('./requests/collectExtractProps.js')['collectExtractProps']>
@@ -76,7 +79,41 @@ export function getElementAttrs(
7679
});
7780
}
7881

79-
function sendRequest<T>(request: Request) {
82+
async function sendRequest<T>(request: Request) {
83+
const pipeFile = await getPipeFile(request.args[0]);
84+
if (!pipeFile) {
85+
console.error('[Vue Named Pipe Client] pipeFile not found');
86+
return;
87+
}
88+
return await _sendRequest<T>(request, pipeFile);
89+
}
90+
91+
async function getPipeFile(fileName: string) {
92+
if (fs.existsSync(pipeTable)) {
93+
const table: PipeTable = JSON.parse(fs.readFileSync(pipeTable, 'utf8'));
94+
const all = Object.values(table);
95+
const configuredServers = all
96+
.filter(item => item.serverKind === 1 satisfies ts.server.ProjectKind.Configured)
97+
.sort((a, b) => Math.abs(process.pid - a.pid) - Math.abs(process.pid - b.pid));
98+
const inferredServers = all
99+
.filter(item => item.serverKind === 0 satisfies ts.server.ProjectKind.Inferred)
100+
.sort((a, b) => Math.abs(process.pid - a.pid) - Math.abs(process.pid - b.pid));
101+
for (const server of configuredServers) {
102+
const response = await _sendRequest<boolean>({ type: 'containsFile', args: [fileName] }, server.pipeFile);
103+
if (response) {
104+
return server.pipeFile;
105+
}
106+
}
107+
for (const server of inferredServers) {
108+
const response = await _sendRequest<boolean>({ type: 'containsFile', args: [fileName] }, server.pipeFile);
109+
if (typeof response === 'boolean') {
110+
return server.pipeFile;
111+
}
112+
}
113+
}
114+
}
115+
116+
function _sendRequest<T>(request: Request, pipeFile: string) {
80117
return new Promise<T | undefined | null>(resolve => {
81118
try {
82119
const client = net.connect(pipeFile);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { getProject } from '../utils';
2+
3+
export function containsFile(fileName: string) {
4+
return !!getProject(fileName);
5+
}

packages/typescript-plugin/lib/server.ts

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import * as fs from 'fs';
22
import * as net from 'net';
3+
import type * as ts from 'typescript';
34
import { collectExtractProps } from './requests/collectExtractProps';
45
import { getComponentEvents, getComponentNames, getComponentProps, getElementAttrs, getTemplateContextProps } from './requests/componentInfos';
6+
import { containsFile } from './requests/containsFile';
57
import { getPropertiesAtLocation } from './requests/getPropertiesAtLocation';
68
import { getQuickInfoAtPosition } from './requests/getQuickInfoAtPosition';
7-
import { pipeFile } from './utils';
9+
import { PipeTable, pipeTable } from './utils';
810

911
export interface Request {
10-
type: 'collectExtractProps'
12+
type: 'containsFile'
13+
| 'collectExtractProps'
1114
| 'getPropertiesAtLocation'
1215
| 'getQuickInfoAtPosition'
1316
// Component Infos
@@ -21,13 +24,23 @@ export interface Request {
2124

2225
let started = false;
2326

24-
export function startNamedPipeServer() {
27+
export function startNamedPipeServer(serverKind: ts.server.ProjectKind) {
28+
2529
if (started) return;
2630
started = true;
31+
32+
const pipeFile = process.platform === 'win32'
33+
? `\\\\.\\pipe\\vue-tsp-${process.pid}`
34+
: `/tmp/vue-tsp-${process.pid}`;
2735
const server = net.createServer(connection => {
2836
connection.on('data', data => {
29-
const request: Request = JSON.parse(data.toString());
30-
if (request.type === 'collectExtractProps') {
37+
const text = data.toString();
38+
const request: Request = JSON.parse(text);
39+
if (request.type === 'containsFile') {
40+
const result = containsFile.apply(null, request.args);
41+
connection.write(JSON.stringify(result ?? null));
42+
}
43+
else if (request.type === 'collectExtractProps') {
3144
const result = collectExtractProps.apply(null, request.args);
3245
connection.write(JSON.stringify(result ?? null));
3346
}
@@ -68,9 +81,42 @@ export function startNamedPipeServer() {
6881
connection.on('error', err => console.error('[Vue Named Pipe Server]', err.message));
6982
});
7083

84+
clearupPipeTable();
85+
86+
if (!fs.existsSync(pipeTable)) {
87+
fs.writeFileSync(pipeTable, JSON.stringify({}));
88+
}
89+
const table: PipeTable = JSON.parse(fs.readFileSync(pipeTable, 'utf8'));
90+
table[process.pid] = {
91+
pid: process.pid,
92+
pipeFile,
93+
serverKind,
94+
};
95+
fs.writeFileSync(pipeTable, JSON.stringify(table, undefined, 2));
96+
7197
try {
7298
fs.unlinkSync(pipeFile);
7399
} catch { }
74100

75101
server.listen(pipeFile);
76102
}
103+
104+
function clearupPipeTable() {
105+
if (fs.existsSync(pipeTable)) {
106+
const table: PipeTable = JSON.parse(fs.readFileSync(pipeTable, 'utf8'));
107+
for (const pid in table) {
108+
const { pipeFile } = table[pid];
109+
try {
110+
const client = net.connect(pipeFile);
111+
client.on('connect', () => {
112+
client.end();
113+
});
114+
client.on('error', () => {
115+
const table = JSON.parse(fs.readFileSync(pipeTable, 'utf8'));
116+
delete table[pid];
117+
fs.writeFileSync(pipeTable, JSON.stringify(table, undefined, 2));
118+
});
119+
} catch { }
120+
}
121+
}
122+
}

packages/typescript-plugin/lib/utils.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
import type * as ts from 'typescript';
22
import type { FileRegistry, VueCompilerOptions } from '@vue/language-core';
33

4-
export const pipeFile = process.platform === 'win32' ? '\\\\.\\pipe\\vue-tsp' : '/tmp/vue-tsp';
4+
export interface PipeTable {
5+
[pid: string]: {
6+
pid: number;
7+
pipeFile: string;
8+
serverKind: ts.server.ProjectKind;
9+
};
10+
}
11+
12+
export const pipeTable = process.platform === 'win32'
13+
? `\\\\.\\pipe\\vue-tsp-table.json`
14+
: `/tmp/vue-tsp-table.json`;
515

616
export const projects = new Map<ts.server.Project, {
717
info: ts.server.PluginCreateInfo;

0 commit comments

Comments
 (0)