@@ -10,6 +10,9 @@ function createTSServerInstance() {
1010 let tsserverProcess = null ;
1111 let seqNumber = 0 ;
1212 const pendingCommands = new Map ( ) ;
13+ let buffer = '' ;
14+ let expectedLength = 0 ;
15+ const CONNECT_MESSAGE_KEY = - 1 ;
1316
1417 /**
1518 * Initializes the TypeScript Server instance.
@@ -33,19 +36,9 @@ function createTSServerInstance() {
3336 tsserverProcess = spawn ( nodePath , [ tsserverPath ] ) ;
3437 tsserverProcess . stdout . setEncoding ( 'utf8' ) ;
3538
39+ pendingCommands . set ( CONNECT_MESSAGE_KEY , { resolve, reject} ) ;
3640 tsserverProcess . stdout . on ( 'data' , ( data ) => {
37- const lines = data . split ( '\n' ) ;
38- console . log ( lines ) ;
39- for ( const line of lines ) {
40- if ( line . trim ( ) . startsWith ( '{' ) ) {
41- const message = JSON . parse ( line . trim ( ) ) ;
42- if ( message . type === 'event' && message . event === 'typingsInstallerPid' ) {
43- // Server is ready
44- resolve ( ) ;
45- }
46- onData ( line ) ;
47- }
48- }
41+ onData ( data ) ;
4942 } ) ;
5043
5144 tsserverProcess . stderr . on ( 'data' , ( data ) => {
@@ -65,21 +58,65 @@ function createTSServerInstance() {
6558
6659 /**
6760 * Handles incoming data from the TypeScript Server.
68- * @param {string } line - A line of data received from tsserver.
61+ * @param {string } rawData - Raw data received from tsserver.
6962 */
70- function onData ( line ) {
63+ function onData ( rawData ) {
64+ buffer += rawData ;
65+ // Check if we have received the complete message based on Content-Length
66+ while ( hasCompleteMessage ( ) ) {
67+ const headerEndIndex = buffer . indexOf ( '\r\n\r\n' ) + 4 ; // +4 to move past the \r\n\r\n
68+ const message = buffer . substring ( headerEndIndex , headerEndIndex + expectedLength ) ;
69+ buffer = buffer . substring ( headerEndIndex + expectedLength ) ;
70+ expectedLength = 0 ; // Reset for the next message
71+ processMessage ( message ) ;
72+ }
73+ }
74+
75+ /**
76+ * Processes a complete message from tsserver.
77+ * @param {string } message - A complete message in JSON format.
78+ */
79+ function processMessage ( message ) {
7180 try {
72- const response = JSON . parse ( line ) ;
81+ console . log ( "++++++++++" , message ) ;
82+ const response = JSON . parse ( message ) ;
83+ if ( response . type === 'event' && response . event === 'typingsInstallerPid' ) {
84+ // Server is ready
85+ const { resolve} = pendingCommands . get ( CONNECT_MESSAGE_KEY ) ;
86+ pendingCommands . delete ( CONNECT_MESSAGE_KEY ) ;
87+ resolve ( ) ;
88+ return ;
89+ }
90+
7391 if ( response . request_seq !== undefined && pendingCommands . has ( response . request_seq ) ) {
7492 const { resolve} = pendingCommands . get ( response . request_seq ) ;
7593 pendingCommands . delete ( response . request_seq ) ;
7694 resolve ( response ) ;
7795 }
7896 } catch ( e ) {
79- console . error ( 'Error parsing line from tsserver:' , e ) ;
97+ console . error ( 'Error parsing message from tsserver:' , e ) ;
8098 }
8199 }
82100
101+ /**
102+ * Checks if the buffer has a complete message based on Content-Length.
103+ * @returns {boolean } True if a complete message is present in the buffer.
104+ */
105+ function hasCompleteMessage ( ) {
106+ if ( ! expectedLength ) {
107+ const headerEndIndex = buffer . indexOf ( '\r\n\r\n' ) ;
108+ if ( headerEndIndex !== - 1 ) {
109+ const header = buffer . substring ( 0 , headerEndIndex ) ;
110+ const contentLengthMatch = header . match ( / C o n t e n t - L e n g t h : ( \d + ) / ) ;
111+ if ( contentLengthMatch ) {
112+ expectedLength = parseInt ( contentLengthMatch [ 1 ] , 10 ) ;
113+ }
114+ }
115+ }
116+ return buffer . length >= expectedLength + buffer . indexOf ( '\r\n\r\n' ) + 4 ; // +4 for header's \r\n\r\n
117+ }
118+
119+
83120 /**
84121 * Sends a command to the TypeScript Server.
85122 * Special handling for 'open' command as it does not receive a response.
@@ -253,6 +290,25 @@ function createTSServerInstance() {
253290 return sendCommand ( command ) ;
254291 }
255292
293+ /**
294+ * Sends a 'completionInfo' command to the TypeScript Server.
295+ * @param {string } filePath - The path to the file.
296+ * @param {number } line - The line number of the position.
297+ * @param {number } offset - The offset in the line of the position.
298+ * @returns {Promise<Object> } A promise that resolves with the response from tsserver.
299+ */
300+ function getCompletionInfo ( filePath , line , offset ) {
301+ const command = {
302+ command : "completionInfo" ,
303+ arguments : {
304+ file : filePath ,
305+ line : line ,
306+ offset : offset
307+ }
308+ } ;
309+ return sendCommand ( command ) ;
310+ }
311+
256312 /**
257313 * Sends an 'exit' command to the TypeScript Server to gracefully shut it down.
258314 * @function exitServer
@@ -291,6 +347,7 @@ function createTSServerInstance() {
291347 findReferences,
292348 getQuickInfo,
293349 findSourceDefinition,
350+ getCompletionInfo,
294351 exitServer
295352 } ;
296353}
0 commit comments