Mirror: TypeScript LSP plugin that finds GraphQL documents in your code and provides diagnostics, auto-complete and hover-information.
at main 2.2 kB view raw
1import { ChildProcess, fork } from 'node:child_process'; 2import readline from 'node:readline'; 3import ts from 'typescript/lib/tsserverlibrary'; 4 5type Command = `${ts.server.protocol.CommandTypes}`; 6 7export class TSServer { 8 #server: ChildProcess; 9 #seq = 0; 10 #resolvePromise: (() => void) | undefined; 11 #waitFor: 12 | (( 13 response: ts.server.protocol.Response | ts.server.protocol.Event 14 ) => boolean) 15 | undefined; 16 17 responses: Array<ts.server.protocol.Response | ts.server.protocol.Event> = []; 18 19 constructor( 20 public projectPath: string, 21 public options: { debugLog?: boolean } = {} 22 ) { 23 const tsserverPath = require.resolve('typescript/lib/tsserver'); 24 25 const server = fork(tsserverPath, ['--logVerbosity', 'verbose'], { 26 stdio: ['pipe', 'pipe', 'pipe', 'ipc'], 27 cwd: projectPath, 28 env: { 29 TSS_LOG: 30 '-level verbose -traceToConsole false -logToFile true -file ./tsserver.log', 31 }, 32 }); 33 34 if (!server?.stdout) { 35 throw new Error('Failed to start tsserver'); 36 } 37 38 server.stdout.setEncoding('utf-8'); 39 readline.createInterface({ input: server.stdout }).on('line', line => { 40 if (!line.startsWith('{')) return; 41 42 try { 43 const data = JSON.parse(line); 44 45 this.responses.push(data); 46 47 if (this.#resolvePromise && this.#waitFor?.(data)) { 48 this.#resolvePromise(); 49 this.#waitFor = undefined; 50 this.#resolvePromise = undefined; 51 } 52 53 if (options.debugLog) { 54 console.log(data); 55 } 56 } catch (e) { 57 console.error(e); 58 } 59 }); 60 61 this.#server = server; 62 } 63 64 sendCommand(command: Command, args?: Record<string, unknown>) { 65 this.send({ command, arguments: args }); 66 } 67 68 send(data: {}) { 69 const request = JSON.stringify({ 70 seq: ++this.#seq, 71 type: 'request', 72 ...data, 73 }); 74 75 this.#server.stdin?.write(`${request}\n`); 76 } 77 78 waitForResponse = ( 79 cb: ( 80 response: ts.server.protocol.Response | ts.server.protocol.Event 81 ) => boolean 82 ) => { 83 this.#waitFor = cb; 84 return new Promise<void>(resolve => { 85 this.#resolvePromise = resolve; 86 }); 87 }; 88 89 close() { 90 this.#server.kill(); 91 } 92}