Skip to content

Commit d651b33

Browse files
committed
feat: intial code for tsserver connection
1 parent 7e851e6 commit d651b33

File tree

4 files changed

+172
-51
lines changed

4 files changed

+172
-51
lines changed

package-lock.json

Lines changed: 7 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"name": "@aicore/template-nodejs",
3-
"version": "1.0.9",
2+
"name": "@phcode/ts-intelligence",
3+
"version": "1.0.0",
44
"description": "Template for nodejs with unit gulp build, test, coverage, code guardian, github and Other defaults",
55
"main": "src/index.js",
66
"type": "module",
@@ -57,5 +57,7 @@
5757
"husky": "8.0.3",
5858
"mocha": "10.2.0"
5959
},
60-
"dependencies": {}
60+
"dependencies": {
61+
"typescript": "5.3.3"
62+
}
6163
}

src/index.js

Lines changed: 21 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,25 @@
1-
/*
2-
* GNU AGPL-3.0 License
3-
*
4-
* Copyright (c) 2021 - present core.ai . All rights reserved.
5-
*
6-
* This program is free software: you can redistribute it and/or modify it under
7-
* the terms of the GNU Affero General Public License as published by the Free
8-
* Software Foundation, either version 3 of the License, or (at your option) any later version.
9-
*
10-
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11-
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12-
* See the GNU Affero General Public License for more details.
13-
*
14-
* You should have received a copy of the GNU Affero General Public License along
15-
* with this program. If not, see https://opensource.org/licenses/AGPL-3.0.
16-
*
17-
*/
1+
import createTSServerInstance from './utils/startTsserver.js';
182

19-
// @INCLUDE_IN_API_DOCS
3+
const tsServer = createTSServerInstance();
204

21-
/**
22-
* Write your module docs here. tell something about this module in markdown.
23-
*
24-
* See https://github.com/aicore/template-nodejs/wiki/How-To-Write-Docs for more details on how to style docs.
25-
* ### Use markdown headings!
26-
* and markdown code!
27-
* ```js
28-
* console.log("write sample code examples with code blocks");
29-
* ```
30-
*
31-
* @module hello
32-
*/
5+
// Initialize tsserver
6+
tsServer.init()
7+
.then(() => {
8+
console.log('tsserver is ready');
339

34-
/**
35-
* says hello world
36-
* @param name
37-
* @returns {string}
38-
* @type {function}
39-
*/
40-
function helloWorld(name) {
41-
return "Hello World " + name;
42-
}
10+
// Path to the TypeScript file you want to open
11+
const filePath = '/home/charly/repo/tsIntelligence/src/utils/startTsserver.js ';
4312

44-
export default helloWorld;
13+
// Open a TypeScript file
14+
return tsServer.openFile(filePath, 10000); // Set a 10-second timeout for response
15+
})
16+
.then(response => {
17+
console.log('File opened successfully:', response);
18+
// Handle the response for opening the file
19+
20+
// Optionally, you can kill the server after processing the response
21+
// tsServer.killServer();
22+
})
23+
.catch(error => {
24+
console.error('Error:', error);
25+
});

src/utils/startTsserver.js

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import { spawn } from 'child_process';
2+
import path from 'path';
3+
import { fileURLToPath } from 'url';
4+
5+
/**
6+
* Creates a new instance of TypeScript Server.
7+
* @returns {Object} An object containing methods to interact with TypeScript Server.
8+
*/
9+
function createTSServerInstance() {
10+
let tsserverProcess = null;
11+
let seqNumber = 0;
12+
const pendingCommands = new Map();
13+
14+
/**
15+
* Initializes the TypeScript Server process.
16+
*/
17+
function initTSServer() {
18+
return new Promise((resolve, reject) => {
19+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
20+
const tsserverPath = path.join(__dirname, '..', '..', 'node_modules', 'typescript', 'bin', 'tsserver');
21+
const nodePath = '/home/charly/.nvm/versions/node/v20.10.0/bin/node';
22+
tsserverProcess = spawn(nodePath, [tsserverPath]);
23+
tsserverProcess.stdout.setEncoding('utf8');
24+
25+
tsserverProcess.stdout.on('data', (data) => {
26+
const lines = data.split('\n');
27+
for (const line of lines) {
28+
if (line.trim().startsWith('{')) {
29+
const message = JSON.parse(line.trim());
30+
if (message.type === 'event' && message.event === 'typingsInstallerPid') {
31+
// Server is ready
32+
resolve();
33+
}
34+
onData(line);
35+
}
36+
}
37+
});
38+
39+
tsserverProcess.stderr.on('data', (data) => {
40+
console.error(`stderr: ${data}`);
41+
});
42+
43+
tsserverProcess.on('close', (code) => {
44+
console.log(`tsserver process exited with code ${code}`);
45+
});
46+
47+
// Add a timeout for server initialization
48+
setTimeout(() => {
49+
reject(new Error('Timeout waiting for tsserver to be ready'));
50+
}, 10000); // 10 seconds timeout
51+
});
52+
}
53+
/**
54+
* Handles incoming data from the TypeScript Server.
55+
* @param {string} line - A line of data received from tsserver.
56+
*/
57+
function onData(line) {
58+
try {
59+
console.log(line);
60+
const response = JSON.parse(line);
61+
// Check if it's a command response and has a matching sequence number
62+
if (response.request_seq !== undefined && pendingCommands.has(response.request_seq)) {
63+
const { resolve } = pendingCommands.get(response.request_seq);
64+
pendingCommands.delete(response.request_seq);
65+
resolve(response);
66+
} else if (response.type === 'event') {
67+
// Handle or log event messages from tsserver
68+
console.log('Event from tsserver:', response);
69+
}
70+
} catch (e) {
71+
console.error('Error parsing line from tsserver:', e);
72+
}
73+
}
74+
75+
/**
76+
* Sends a command to the TypeScript Server.
77+
* @param {Object} command - The command object to send.
78+
* @param {number} [timeout=5000] - The timeout in milliseconds for the command.
79+
* @returns {Promise<Object>} A promise that resolves with the response from tsserver.
80+
*/
81+
function sendCommand(command, timeout = 5000) {
82+
return new Promise((resolve, reject) => {
83+
if (!tsserverProcess) {
84+
reject(new Error('tsserver is not initialized'));
85+
return;
86+
}
87+
88+
const seq = ++seqNumber;
89+
pendingCommands.set(seq, { resolve, reject });
90+
91+
const timeoutId = setTimeout(() => {
92+
if (pendingCommands.has(seq)) {
93+
pendingCommands.delete(seq);
94+
reject(new Error('tsserver response timeout'));
95+
}
96+
}, timeout);
97+
98+
command.seq = seq;
99+
command.type = 'request';
100+
console.log(command);
101+
102+
if (tsserverProcess.stdin.writable) {
103+
tsserverProcess.stdin.write(`${JSON.stringify(command)}\n`);
104+
} else {
105+
clearTimeout(timeoutId);
106+
reject(new Error('tsserver stdin not writable'));
107+
}
108+
});
109+
}
110+
111+
/**
112+
* Sends an 'open file' command to the TypeScript Server.
113+
* @param {string} filePath - The path to the TypeScript file to open.
114+
* @param {number} timeout - The timeout in milliseconds for the command.
115+
* @returns {Promise<Object>} A promise that resolves with the response from tsserver.
116+
*/
117+
function openFile(filePath, timeout) {
118+
const command = {
119+
command: 'open',
120+
arguments: { file: filePath }
121+
};
122+
return sendCommand(command, timeout);
123+
}
124+
125+
/**
126+
* Kills the TypeScript Server process.
127+
*/
128+
function killTSServer() {
129+
if (tsserverProcess) {
130+
tsserverProcess.kill();
131+
tsserverProcess = null;
132+
console.log('tsserver process terminated');
133+
}
134+
}
135+
136+
return { init: initTSServer, openFile, killServer: killTSServer };
137+
}
138+
139+
export default createTSServerInstance;

0 commit comments

Comments
 (0)