diff --git a/packages/typescript-plugin/index.ts b/packages/typescript-plugin/index.ts index 492597d22..96325be49 100644 --- a/packages/typescript-plugin/index.ts +++ b/packages/typescript-plugin/index.ts @@ -61,7 +61,7 @@ function createLanguageServicePlugin(): ts.server.PluginModuleFactory { decorateLanguageService(files, info.languageService); decorateLanguageServiceHost(files, info.languageServiceHost, ts); - startNamedPipeServer(info.project.projectKind); + startNamedPipeServer(info.project.projectKind, info.project.getCurrentDirectory()); const getCompletionsAtPosition = info.languageService.getCompletionsAtPosition; const getCompletionEntryDetails = info.languageService.getCompletionEntryDetails; diff --git a/packages/typescript-plugin/lib/client.ts b/packages/typescript-plugin/lib/client.ts index 5c7a004c7..27d553281 100644 --- a/packages/typescript-plugin/lib/client.ts +++ b/packages/typescript-plugin/lib/client.ts @@ -1,9 +1,10 @@ -import * as net from 'net'; import * as fs from 'fs'; +import type * as net from 'net'; +import * as path from 'path'; import type * as ts from 'typescript'; import type { Request } from './server'; -import type { PipeTable } from './utils'; -import { pipeTable } from './utils'; +import type { NamedPipeServer } from './utils'; +import { connect, pipeTable } from './utils'; export function collectExtractProps( ...args: Parameters @@ -80,58 +81,51 @@ export function getElementAttrs( } async function sendRequest(request: Request) { - const pipeFile = await getPipeFile(request.args[0]); - if (!pipeFile) { - console.error('[Vue Named Pipe Client] pipeFile not found'); + const client = await connectForFile(request.args[0]); + if (!client) { + console.warn('[Vue Named Pipe Client] No server found for', request.args[0]); return; } - return await _sendRequest(request, pipeFile); + const result = await sendRequestWorker(request, client); + client.end(); + return result; } -async function getPipeFile(fileName: string) { - if (fs.existsSync(pipeTable)) { - const table: PipeTable = JSON.parse(fs.readFileSync(pipeTable, 'utf8')); - const all = Object.values(table); - const configuredServers = all - .filter(item => item.serverKind === 1 satisfies ts.server.ProjectKind.Configured) - .sort((a, b) => Math.abs(process.pid - a.pid) - Math.abs(process.pid - b.pid)); - const inferredServers = all - .filter(item => item.serverKind === 0 satisfies ts.server.ProjectKind.Inferred) - .sort((a, b) => Math.abs(process.pid - a.pid) - Math.abs(process.pid - b.pid)); - for (const server of configuredServers) { - const response = await _sendRequest({ type: 'containsFile', args: [fileName] }, server.pipeFile); +async function connectForFile(fileName: string) { + if (!fs.existsSync(pipeTable)) { + return; + } + const servers: NamedPipeServer[] = JSON.parse(fs.readFileSync(pipeTable, 'utf8')); + const configuredServers = servers + .filter(item => item.serverKind === 1 satisfies ts.server.ProjectKind.Configured); + const inferredServers = servers + .filter(item => item.serverKind === 0 satisfies ts.server.ProjectKind.Inferred) + .sort((a, b) => b.currentDirectory.length - a.currentDirectory.length); + for (const server of configuredServers) { + const client = await connect(server.path); + if (client) { + const response = await sendRequestWorker({ type: 'containsFile', args: [fileName] }, client); if (response) { - return server.pipeFile; + return client; } } - for (const server of inferredServers) { - const response = await _sendRequest({ type: 'containsFile', args: [fileName] }, server.pipeFile); - if (typeof response === 'boolean') { - return server.pipeFile; + } + for (const server of inferredServers) { + if (!path.relative(server.currentDirectory, fileName).startsWith('..')) { + const client = await connect(server.path); + if (client) { + return client; } } } } -function _sendRequest(request: Request, pipeFile: string) { +function sendRequestWorker(request: Request, client: net.Socket) { return new Promise(resolve => { - try { - const client = net.connect(pipeFile); - client.on('connect', () => { - client.write(JSON.stringify(request)); - }); - client.on('data', data => { - const text = data.toString(); - resolve(JSON.parse(text)); - client.end(); - }); - client.on('error', err => { - console.error('[Vue Named Pipe Client]', err); - return resolve(undefined); - }); - } catch (e) { - console.error('[Vue Named Pipe Client]', e); - return resolve(undefined); - } + client.once('data', data => { + const text = data.toString(); + resolve(JSON.parse(text)); + }); + client.write(JSON.stringify(request)); }); } diff --git a/packages/typescript-plugin/lib/server.ts b/packages/typescript-plugin/lib/server.ts index b42d36989..65a052f6d 100644 --- a/packages/typescript-plugin/lib/server.ts +++ b/packages/typescript-plugin/lib/server.ts @@ -6,7 +6,7 @@ import { getComponentEvents, getComponentNames, getComponentProps, getElementAtt import { containsFile } from './requests/containsFile'; import { getPropertiesAtLocation } from './requests/getPropertiesAtLocation'; import { getQuickInfoAtPosition } from './requests/getQuickInfoAtPosition'; -import { PipeTable, pipeTable } from './utils'; +import { NamedPipeServer, connect, pipeTable } from './utils'; export interface Request { type: 'containsFile' @@ -24,7 +24,7 @@ export interface Request { let started = false; -export function startNamedPipeServer(serverKind: ts.server.ProjectKind) { +export function startNamedPipeServer(serverKind: ts.server.ProjectKind, currentDirectory: string) { if (started) return; started = true; @@ -84,14 +84,14 @@ export function startNamedPipeServer(serverKind: ts.server.ProjectKind) { clearupPipeTable(); if (!fs.existsSync(pipeTable)) { - fs.writeFileSync(pipeTable, JSON.stringify({})); + fs.writeFileSync(pipeTable, JSON.stringify([] satisfies NamedPipeServer[])); } - const table: PipeTable = JSON.parse(fs.readFileSync(pipeTable, 'utf8')); - table[process.pid] = { - pid: process.pid, - pipeFile, + const table: NamedPipeServer[] = JSON.parse(fs.readFileSync(pipeTable, 'utf8')); + table.push({ + path: pipeFile, serverKind, - }; + currentDirectory, + }); fs.writeFileSync(pipeTable, JSON.stringify(table, undefined, 2)); try { @@ -102,21 +102,19 @@ export function startNamedPipeServer(serverKind: ts.server.ProjectKind) { } function clearupPipeTable() { - if (fs.existsSync(pipeTable)) { - const table: PipeTable = JSON.parse(fs.readFileSync(pipeTable, 'utf8')); - for (const pid in table) { - const { pipeFile } = table[pid]; - try { - const client = net.connect(pipeFile); - client.on('connect', () => { - client.end(); - }); - client.on('error', () => { - const table = JSON.parse(fs.readFileSync(pipeTable, 'utf8')); - delete table[pid]; - fs.writeFileSync(pipeTable, JSON.stringify(table, undefined, 2)); - }); - } catch { } - } + if (!fs.existsSync(pipeTable)) { + return; + } + for (const server of JSON.parse(fs.readFileSync(pipeTable, 'utf8'))) { + connect(server.path).then(client => { + if (client) { + client.end(); + } + else { + let table: NamedPipeServer[] = JSON.parse(fs.readFileSync(pipeTable, 'utf8')); + table = table.filter(item => item.path !== server.path); + fs.writeFileSync(pipeTable, JSON.stringify(table, undefined, 2)); + } + }); } } diff --git a/packages/typescript-plugin/lib/utils.ts b/packages/typescript-plugin/lib/utils.ts index 95c258d08..9d9c79915 100644 --- a/packages/typescript-plugin/lib/utils.ts +++ b/packages/typescript-plugin/lib/utils.ts @@ -1,17 +1,18 @@ import type { FileRegistry, VueCompilerOptions } from '@vue/language-core'; import * as os from 'os'; +import * as net from 'net'; import * as path from 'path'; import type * as ts from 'typescript'; -export interface PipeTable { - [pid: string]: { - pid: number; - pipeFile: string; - serverKind: ts.server.ProjectKind; - }; +export interface NamedPipeServer { + path: string; + serverKind: ts.server.ProjectKind; + currentDirectory: string; } -export const pipeTable = path.join(os.tmpdir(), 'vue-tsp-table.json'); +const { version } = require('../package.json'); + +export const pipeTable = path.join(os.tmpdir(), `vue-tsp-table-${version}.json`); export const projects = new Map(resolve => { + const client = net.connect(path); + client.on('connect', () => { + resolve(client); + }); + client.on('error', () => { + return resolve(undefined); + }); + }); +}