websocket-text-relay 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +3 -0
- package/.prettierrc +4 -0
- package/changelog.md +7 -0
- package/docs/code-structure.md +1 -1
- package/eslint.config.js +28 -0
- package/package.json +15 -10
- package/{index.js → src/index.js} +23 -21
- package/src/language-server/JsonRpcInterface.js +59 -29
- package/src/language-server/JsonRpcInterface.test.js +102 -72
- package/src/language-server/LspReader.js +30 -20
- package/src/language-server/LspReader.test.js +147 -65
- package/src/language-server/LspWriter.js +5 -5
- package/src/language-server/LspWriter.test.js +31 -24
- package/src/ui/css/fonts.css +0 -1
- package/src/ui/css/main.css +7 -7
- package/src/ui/index.html +4 -4
- package/src/ui/js/components/ActivityTimeseriesGraph.js +83 -32
- package/src/ui/js/components/HeaderSummary.js +11 -5
- package/src/ui/js/components/ServerStatus.js +19 -7
- package/src/ui/js/components/SessionLabels.js +197 -49
- package/src/ui/js/components/SessionWedges.js +44 -24
- package/src/ui/js/components/StatusRing.js +20 -8
- package/src/ui/js/components/grids.js +14 -7
- package/src/ui/js/index.js +23 -19
- package/src/ui/js/main.js +53 -21
- package/src/ui/js/util/DependencyManager.js +5 -5
- package/src/ui/js/util/EventEmitter.js +11 -7
- package/src/ui/js/util/WebsocketClient.js +28 -22
- package/src/ui/js/util/constants.js +2 -2
- package/src/ui/js/util/drawing.js +58 -28
- package/src/websocket-interface/WebsocketClient.js +15 -15
- package/src/websocket-interface/WebsocketInterface.js +30 -22
- package/src/websocket-interface/WtrSession.js +49 -33
- package/src/websocket-interface/httpServer.js +11 -10
- package/src/websocket-interface/sessionManager.js +16 -13
- package/src/websocket-interface/util.js +1 -1
- package/src/websocket-interface/websocketApi.js +51 -34
- package/src/websocket-interface/websocketServer.js +9 -9
- package/start.js +1 -1
- package/.eslintrc +0 -29
|
@@ -1,25 +1,33 @@
|
|
|
1
1
|
import { describe, it, expect, beforeAll } from "vitest"
|
|
2
|
-
import { PassThrough, Writable } from
|
|
2
|
+
import { PassThrough, Writable } from "node:stream"
|
|
3
3
|
import { JsonRpcInterface } from "./JsonRpcInterface.js"
|
|
4
4
|
import { TESTONLY_resetRequestId } from "./LspWriter.js"
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
invalidRequestErrorCode,
|
|
7
|
+
invalidRequestErrorMessage,
|
|
8
|
+
methodNotFoundErrorCode,
|
|
9
|
+
methodNotFoundErrorMessage,
|
|
10
|
+
unexpectedNotificationErrorCode,
|
|
11
|
+
unexpectedNotificationErrorMessage,
|
|
12
|
+
unexpectedRequestErrorCode,
|
|
13
|
+
unexpectedRequestErrorMessage,
|
|
14
|
+
} from "./constants.js"
|
|
7
15
|
|
|
8
16
|
describe("JsonRpcInterface", () => {
|
|
9
17
|
describe("onNotification", () => {
|
|
10
18
|
describe("when a we receive a notification message that has a handler", () => {
|
|
11
19
|
let inputStream, outputStream, jsonRpc
|
|
12
20
|
const incomingMessage = `Content-Length: 64\r\n\r\n{"jsonrpc":"2.0","method":"test/test-method","params":{"a":"1"}}`
|
|
13
|
-
const expectedParams = {a: "1"}
|
|
21
|
+
const expectedParams = { a: "1" }
|
|
14
22
|
let actualParams = null
|
|
15
23
|
|
|
16
24
|
beforeAll(() => {
|
|
17
25
|
inputStream = new PassThrough()
|
|
18
26
|
outputStream = new PassThrough()
|
|
19
|
-
jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
27
|
+
jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
20
28
|
|
|
21
29
|
jsonRpc.onNotification("test/test-method", (params) => {
|
|
22
|
-
actualParams= params
|
|
30
|
+
actualParams = params
|
|
23
31
|
})
|
|
24
32
|
|
|
25
33
|
inputStream.write(incomingMessage)
|
|
@@ -38,14 +46,15 @@ describe("JsonRpcInterface", () => {
|
|
|
38
46
|
beforeAll(() => {
|
|
39
47
|
inputStream = new PassThrough()
|
|
40
48
|
outputStream = new PassThrough()
|
|
41
|
-
jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
49
|
+
jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
42
50
|
|
|
43
51
|
jsonRpc.onNotification("test/test-method", f1)
|
|
44
|
-
|
|
45
52
|
})
|
|
46
53
|
|
|
47
54
|
it("should throw an error if we try to register the same method twice (without first removing the handler)", () => {
|
|
48
|
-
expect(() => jsonRpc.onNotification("test/test-method", f2)).to.toThrowError(
|
|
55
|
+
expect(() => jsonRpc.onNotification("test/test-method", f2)).to.toThrowError(
|
|
56
|
+
/duplicate method handlers/i,
|
|
57
|
+
)
|
|
49
58
|
})
|
|
50
59
|
})
|
|
51
60
|
|
|
@@ -54,13 +63,13 @@ describe("JsonRpcInterface", () => {
|
|
|
54
63
|
const incomingMessage = `Content-Length: 64\r\n\r\n{"jsonrpc":"2.0","method":"test/test-method","params":{"a":"1"}}`
|
|
55
64
|
let f1Fired = false
|
|
56
65
|
let f2Fired = false
|
|
57
|
-
let f1 = () => f1Fired = true
|
|
58
|
-
let f2 = () => f2Fired = true
|
|
66
|
+
let f1 = () => (f1Fired = true)
|
|
67
|
+
let f2 = () => (f2Fired = true)
|
|
59
68
|
|
|
60
69
|
beforeAll(() => {
|
|
61
70
|
inputStream = new PassThrough()
|
|
62
71
|
outputStream = new PassThrough()
|
|
63
|
-
jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
72
|
+
jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
64
73
|
|
|
65
74
|
jsonRpc.onNotification("test/test-method", f1)
|
|
66
75
|
jsonRpc.removeNotificationHandler("test/test-method")
|
|
@@ -78,19 +87,23 @@ describe("JsonRpcInterface", () => {
|
|
|
78
87
|
describe("when a notification handler throws an error", () => {
|
|
79
88
|
let inputStream, outputStream, jsonRpc
|
|
80
89
|
const incomingMessage = `Content-Length: 64\r\n\r\n{"jsonrpc":"2.0","method":"test/test-method","params":{"a":"1"}}`
|
|
81
|
-
const expectedError = {
|
|
90
|
+
const expectedError = {
|
|
91
|
+
code: unexpectedNotificationErrorCode,
|
|
92
|
+
message: unexpectedNotificationErrorMessage,
|
|
93
|
+
data: { method: "test/test-method", params: { a: "1" }, error: "Test notification error" },
|
|
94
|
+
}
|
|
82
95
|
let actualError
|
|
83
96
|
|
|
84
97
|
beforeAll(() => {
|
|
85
98
|
inputStream = new PassThrough()
|
|
86
99
|
outputStream = new PassThrough()
|
|
87
|
-
jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
100
|
+
jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
88
101
|
|
|
89
102
|
jsonRpc.onNotification("test/test-method", () => {
|
|
90
103
|
throw new Error("Test notification error")
|
|
91
104
|
})
|
|
92
105
|
|
|
93
|
-
jsonRpc.events.on(
|
|
106
|
+
jsonRpc.events.on("notification-error", (error) => {
|
|
94
107
|
actualError = error
|
|
95
108
|
})
|
|
96
109
|
|
|
@@ -105,15 +118,19 @@ describe("JsonRpcInterface", () => {
|
|
|
105
118
|
describe("when we receive a notification without a handler", () => {
|
|
106
119
|
let inputStream, outputStream, jsonRpc
|
|
107
120
|
const incomingMessage = `Content-Length: 64\r\n\r\n{"jsonrpc":"2.0","method":"test/test-method","params":{"a":"1"}}`
|
|
108
|
-
const expectedError = {
|
|
121
|
+
const expectedError = {
|
|
122
|
+
code: methodNotFoundErrorCode,
|
|
123
|
+
message: methodNotFoundErrorMessage,
|
|
124
|
+
data: { method: "test/test-method" },
|
|
125
|
+
}
|
|
109
126
|
let actualError
|
|
110
127
|
|
|
111
128
|
beforeAll(() => {
|
|
112
129
|
inputStream = new PassThrough()
|
|
113
130
|
outputStream = new PassThrough()
|
|
114
|
-
jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
131
|
+
jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
115
132
|
|
|
116
|
-
jsonRpc.events.on(
|
|
133
|
+
jsonRpc.events.on("notification-error", (error) => {
|
|
117
134
|
actualError = error
|
|
118
135
|
})
|
|
119
136
|
|
|
@@ -129,7 +146,7 @@ describe("JsonRpcInterface", () => {
|
|
|
129
146
|
describe("onRequest", () => {
|
|
130
147
|
describe("when a we receive a request message that has a handler", () => {
|
|
131
148
|
const incomingMessage = `Content-Length: 73\r\n\r\n{"jsonrpc":"2.0","id":"0","method":"test/test-method","params":{"a":"1"}}`
|
|
132
|
-
const expectedParams = {a: "1"}
|
|
149
|
+
const expectedParams = { a: "1" }
|
|
133
150
|
let actualParams = null
|
|
134
151
|
const expectedOutput = `Content-Length: 54\r\n\r\n{"jsonrpc":"2.0","id":"0","result":{"someValue":"33"}}`
|
|
135
152
|
let actualOutput = ""
|
|
@@ -137,16 +154,16 @@ describe("JsonRpcInterface", () => {
|
|
|
137
154
|
beforeAll(() => {
|
|
138
155
|
const inputStream = new PassThrough()
|
|
139
156
|
const outputStream = new Writable({
|
|
140
|
-
write
|
|
157
|
+
write(data, _enc, next) {
|
|
141
158
|
actualOutput += data.toString()
|
|
142
159
|
next()
|
|
143
|
-
}
|
|
160
|
+
},
|
|
144
161
|
})
|
|
145
|
-
const jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
162
|
+
const jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
146
163
|
|
|
147
164
|
jsonRpc.onRequest("test/test-method", (params) => {
|
|
148
|
-
actualParams= params
|
|
149
|
-
return {someValue: "33"}
|
|
165
|
+
actualParams = params
|
|
166
|
+
return { someValue: "33" }
|
|
150
167
|
})
|
|
151
168
|
|
|
152
169
|
inputStream.write(incomingMessage)
|
|
@@ -163,7 +180,7 @@ describe("JsonRpcInterface", () => {
|
|
|
163
180
|
|
|
164
181
|
describe("should be able to use an async function as a handler", () => {
|
|
165
182
|
const incomingMessage = `Content-Length: 73\r\n\r\n{"jsonrpc":"2.0","id":"0","method":"test/test-method","params":{"a":"1"}}`
|
|
166
|
-
const expectedParams = {a: "1"}
|
|
183
|
+
const expectedParams = { a: "1" }
|
|
167
184
|
let actualParams = null
|
|
168
185
|
const expectedOutput = `Content-Length: 54\r\n\r\n{"jsonrpc":"2.0","id":"0","result":{"someValue":"34"}}`
|
|
169
186
|
let actualOutput = ""
|
|
@@ -171,19 +188,19 @@ describe("JsonRpcInterface", () => {
|
|
|
171
188
|
beforeAll(() => {
|
|
172
189
|
const inputStream = new PassThrough()
|
|
173
190
|
const outputStream = new Writable({
|
|
174
|
-
write
|
|
191
|
+
write(data, _enc, next) {
|
|
175
192
|
actualOutput += data.toString()
|
|
176
193
|
next()
|
|
177
|
-
}
|
|
194
|
+
},
|
|
178
195
|
})
|
|
179
|
-
const jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
196
|
+
const jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
180
197
|
|
|
181
198
|
jsonRpc.onRequest("test/test-method", async (params) => {
|
|
182
|
-
actualParams= params
|
|
199
|
+
actualParams = params
|
|
183
200
|
const someValue = await new Promise((resolve) => {
|
|
184
201
|
setTimeout(() => resolve("34"), 1)
|
|
185
202
|
})
|
|
186
|
-
return {someValue}
|
|
203
|
+
return { someValue }
|
|
187
204
|
})
|
|
188
205
|
|
|
189
206
|
inputStream.write(incomingMessage)
|
|
@@ -211,10 +228,9 @@ describe("JsonRpcInterface", () => {
|
|
|
211
228
|
beforeAll(() => {
|
|
212
229
|
inputStream = new PassThrough()
|
|
213
230
|
outputStream = new PassThrough()
|
|
214
|
-
jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
231
|
+
jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
215
232
|
|
|
216
233
|
jsonRpc.onRequest("test/test-method", f1)
|
|
217
|
-
|
|
218
234
|
})
|
|
219
235
|
|
|
220
236
|
it("should throw an error if we try to register the same method twice (without first removing the handler)", () => {
|
|
@@ -226,13 +242,13 @@ describe("JsonRpcInterface", () => {
|
|
|
226
242
|
const incomingMessage = `Content-Length: 73\r\n\r\n{"jsonrpc":"2.0","id":"0","method":"test/test-method","params":{"a":"1"}}`
|
|
227
243
|
let f1Fired = false
|
|
228
244
|
let f2Fired = false
|
|
229
|
-
let f1 = () => f1Fired = true
|
|
230
|
-
let f2 = () => f2Fired = true
|
|
245
|
+
let f1 = () => (f1Fired = true)
|
|
246
|
+
let f2 = () => (f2Fired = true)
|
|
231
247
|
|
|
232
248
|
beforeAll(() => {
|
|
233
249
|
const inputStream = new PassThrough()
|
|
234
250
|
const outputStream = new PassThrough()
|
|
235
|
-
const jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
251
|
+
const jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
236
252
|
|
|
237
253
|
jsonRpc.onRequest("test/test-method", f1)
|
|
238
254
|
jsonRpc.removeRequestHandler("test/test-method")
|
|
@@ -249,7 +265,14 @@ describe("JsonRpcInterface", () => {
|
|
|
249
265
|
|
|
250
266
|
describe("when a request handler throws an error", () => {
|
|
251
267
|
const incomingMessage = `Content-Length: 73\r\n\r\n{"jsonrpc":"2.0","id":"0","method":"test/test-method","params":{"a":"1"}}`
|
|
252
|
-
const expectedError = {
|
|
268
|
+
const expectedError = {
|
|
269
|
+
id: "0",
|
|
270
|
+
error: {
|
|
271
|
+
code: unexpectedRequestErrorCode,
|
|
272
|
+
message: unexpectedRequestErrorMessage,
|
|
273
|
+
data: { method: "test/test-method", params: { a: "1" }, error: "Test request error" },
|
|
274
|
+
},
|
|
275
|
+
}
|
|
253
276
|
let actualError
|
|
254
277
|
const expectedOutput = `Content-Length: 179\r\n\r\n{"jsonrpc":"2.0","id":"0","error":{"code":-2,"message":"${unexpectedRequestErrorMessage}","data":{"method":"test/test-method","params":{"a":"1"},"error":"Test request error"}}}`
|
|
255
278
|
let actualOutput = ""
|
|
@@ -257,18 +280,18 @@ describe("JsonRpcInterface", () => {
|
|
|
257
280
|
beforeAll(() => {
|
|
258
281
|
const inputStream = new PassThrough()
|
|
259
282
|
const outputStream = new Writable({
|
|
260
|
-
write
|
|
283
|
+
write(data, _enc, next) {
|
|
261
284
|
actualOutput += data.toString()
|
|
262
285
|
next()
|
|
263
|
-
}
|
|
286
|
+
},
|
|
264
287
|
})
|
|
265
|
-
const jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
288
|
+
const jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
266
289
|
|
|
267
290
|
jsonRpc.onRequest("test/test-method", () => {
|
|
268
291
|
throw new Error("Test request error")
|
|
269
292
|
})
|
|
270
293
|
|
|
271
|
-
jsonRpc.events.on(
|
|
294
|
+
jsonRpc.events.on("request-error", (error) => {
|
|
272
295
|
actualError = error
|
|
273
296
|
})
|
|
274
297
|
|
|
@@ -286,7 +309,14 @@ describe("JsonRpcInterface", () => {
|
|
|
286
309
|
|
|
287
310
|
describe("when we receive a request without a handler", () => {
|
|
288
311
|
const incomingMessage = `Content-Length: 73\r\n\r\n{"jsonrpc":"2.0","id":"0","method":"test/test-method","params":{"a":"1"}}`
|
|
289
|
-
const expectedError = {
|
|
312
|
+
const expectedError = {
|
|
313
|
+
id: "0",
|
|
314
|
+
error: {
|
|
315
|
+
code: methodNotFoundErrorCode,
|
|
316
|
+
message: methodNotFoundErrorMessage,
|
|
317
|
+
data: { method: "test/test-method" },
|
|
318
|
+
},
|
|
319
|
+
}
|
|
290
320
|
let actualError
|
|
291
321
|
const expectedOutput = `Content-Length: 116\r\n\r\n{"jsonrpc":"2.0","id":"0","error":{"code":-32601,"message":"${methodNotFoundErrorMessage}","data":{"method":"test/test-method"}}}`
|
|
292
322
|
let actualOutput = ""
|
|
@@ -294,14 +324,14 @@ describe("JsonRpcInterface", () => {
|
|
|
294
324
|
beforeAll(() => {
|
|
295
325
|
const inputStream = new PassThrough()
|
|
296
326
|
const outputStream = new Writable({
|
|
297
|
-
write
|
|
327
|
+
write(data, _enc, next) {
|
|
298
328
|
actualOutput += data.toString()
|
|
299
329
|
next()
|
|
300
|
-
}
|
|
330
|
+
},
|
|
301
331
|
})
|
|
302
|
-
const jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
332
|
+
const jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
303
333
|
|
|
304
|
-
jsonRpc.events.on(
|
|
334
|
+
jsonRpc.events.on("request-error", (error) => {
|
|
305
335
|
actualError = error
|
|
306
336
|
})
|
|
307
337
|
|
|
@@ -320,19 +350,19 @@ describe("JsonRpcInterface", () => {
|
|
|
320
350
|
|
|
321
351
|
describe("sendNotification", () => {
|
|
322
352
|
const method = "test/test-method"
|
|
323
|
-
const parameters = {
|
|
353
|
+
const parameters = { a: "1" }
|
|
324
354
|
const expectedOutput = `Content-Length: 64\r\n\r\n{"jsonrpc":"2.0","method":"test/test-method","params":{"a":"1"}}`
|
|
325
355
|
let actualOutput = ""
|
|
326
356
|
|
|
327
357
|
beforeAll(() => {
|
|
328
358
|
const inputStream = new PassThrough()
|
|
329
359
|
const outputStream = new Writable({
|
|
330
|
-
write
|
|
360
|
+
write(data, _enc, next) {
|
|
331
361
|
actualOutput += data.toString()
|
|
332
362
|
next()
|
|
333
|
-
}
|
|
363
|
+
},
|
|
334
364
|
})
|
|
335
|
-
const jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
365
|
+
const jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
336
366
|
jsonRpc.sendNotification(method, parameters)
|
|
337
367
|
})
|
|
338
368
|
|
|
@@ -344,11 +374,11 @@ describe("JsonRpcInterface", () => {
|
|
|
344
374
|
describe("sendRequest", () => {
|
|
345
375
|
describe("with result response", () => {
|
|
346
376
|
const method = "test/test-method"
|
|
347
|
-
const parameters = {
|
|
377
|
+
const parameters = { a: "1" }
|
|
348
378
|
const expectedOutput = `Content-Length: 73\r\n\r\n{"jsonrpc":"2.0","id":"0","method":"test/test-method","params":{"a":"1"}}`
|
|
349
379
|
let actualOutput = ""
|
|
350
380
|
const clientResponse = `Content-Length: 52\r\n\r\n{"jsonrpc":"2.0","id":"0","result":{"testVal":"39"}}`
|
|
351
|
-
const expectedResult = {testVal: "39"}
|
|
381
|
+
const expectedResult = { testVal: "39" }
|
|
352
382
|
let actualResult = null
|
|
353
383
|
let inputStream, requestPromise
|
|
354
384
|
|
|
@@ -356,12 +386,12 @@ describe("JsonRpcInterface", () => {
|
|
|
356
386
|
TESTONLY_resetRequestId()
|
|
357
387
|
inputStream = new PassThrough()
|
|
358
388
|
const outputStream = new Writable({
|
|
359
|
-
write
|
|
389
|
+
write(data, _enc, next) {
|
|
360
390
|
actualOutput += data.toString()
|
|
361
391
|
next()
|
|
362
|
-
}
|
|
392
|
+
},
|
|
363
393
|
})
|
|
364
|
-
const jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
394
|
+
const jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
365
395
|
requestPromise = jsonRpc.sendRequest(method, parameters)
|
|
366
396
|
requestPromise.then((result) => {
|
|
367
397
|
actualResult = result
|
|
@@ -386,11 +416,11 @@ describe("JsonRpcInterface", () => {
|
|
|
386
416
|
|
|
387
417
|
describe("with error response", () => {
|
|
388
418
|
const method = "test/test-method"
|
|
389
|
-
const parameters = {
|
|
419
|
+
const parameters = { a: "1" }
|
|
390
420
|
const expectedOutput = `Content-Length: 73\r\n\r\n{"jsonrpc":"2.0","id":"0","method":"test/test-method","params":{"a":"1"}}`
|
|
391
421
|
let actualOutput = ""
|
|
392
422
|
const clientResponse = `Content-Length: 83\r\n\r\n{"jsonrpc":"2.0","id":"0","error":{"code":1,"message":"test error","data":{"t":5}}}`
|
|
393
|
-
const expectedError = {
|
|
423
|
+
const expectedError = { code: 1, message: "test error", data: { t: 5 } }
|
|
394
424
|
let actualResult = null
|
|
395
425
|
let inputStream, requestPromise
|
|
396
426
|
|
|
@@ -398,12 +428,12 @@ describe("JsonRpcInterface", () => {
|
|
|
398
428
|
TESTONLY_resetRequestId()
|
|
399
429
|
inputStream = new PassThrough()
|
|
400
430
|
const outputStream = new Writable({
|
|
401
|
-
write
|
|
431
|
+
write(data, _enc, next) {
|
|
402
432
|
actualOutput += data.toString()
|
|
403
433
|
next()
|
|
404
|
-
}
|
|
434
|
+
},
|
|
405
435
|
})
|
|
406
|
-
const jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
436
|
+
const jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
407
437
|
requestPromise = jsonRpc.sendRequest(method, parameters)
|
|
408
438
|
requestPromise.catch((result) => {
|
|
409
439
|
actualResult = result
|
|
@@ -427,22 +457,22 @@ describe("JsonRpcInterface", () => {
|
|
|
427
457
|
})
|
|
428
458
|
})
|
|
429
459
|
})
|
|
430
|
-
|
|
460
|
+
|
|
431
461
|
describe("when the lspInputStream encounters a parse-error", () => {
|
|
432
|
-
const error = {code: 1, message: "test error", data: {t: 5}}
|
|
462
|
+
const error = { code: 1, message: "test error", data: { t: 5 } }
|
|
433
463
|
const expectedOutput = `Content-Length: 84\r\n\r\n{"jsonrpc":"2.0","id":null,"error":{"code":1,"message":"test error","data":{"t":5}}}`
|
|
434
464
|
let actualOutput = ""
|
|
435
465
|
|
|
436
466
|
beforeAll(() => {
|
|
437
467
|
const inputStream = new PassThrough()
|
|
438
468
|
const outputStream = new Writable({
|
|
439
|
-
write
|
|
469
|
+
write(data, _enc, next) {
|
|
440
470
|
actualOutput += data.toString()
|
|
441
471
|
next()
|
|
442
|
-
}
|
|
472
|
+
},
|
|
443
473
|
})
|
|
444
|
-
const jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
445
|
-
jsonRpc.lspInputStream.emit(
|
|
474
|
+
const jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
475
|
+
jsonRpc.lspInputStream.emit("parse-error", error)
|
|
446
476
|
})
|
|
447
477
|
|
|
448
478
|
it("should write the error to the output stream", () => {
|
|
@@ -456,7 +486,7 @@ describe("JsonRpcInterface", () => {
|
|
|
456
486
|
beforeAll(() => {
|
|
457
487
|
const inputStream = new PassThrough()
|
|
458
488
|
const outputStream = new PassThrough()
|
|
459
|
-
jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
489
|
+
jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
460
490
|
})
|
|
461
491
|
|
|
462
492
|
it("should not throw an error when there is not a response handler for that id", () => {
|
|
@@ -467,22 +497,22 @@ describe("JsonRpcInterface", () => {
|
|
|
467
497
|
describe("_handleIncomingLspMessage: when there is no id or method", () => {
|
|
468
498
|
let jsonRpc, actualError
|
|
469
499
|
let actualOutput = ""
|
|
470
|
-
const expectedError = {code: invalidRequestErrorCode, message: invalidRequestErrorMessage}
|
|
500
|
+
const expectedError = { code: invalidRequestErrorCode, message: invalidRequestErrorMessage }
|
|
471
501
|
const expectedOutput = `Content-Length: 105\r\n\r\n{"jsonrpc":"2.0","id":null,"error":{"code":${invalidRequestErrorCode},"message":"${invalidRequestErrorMessage}"}}`
|
|
472
502
|
|
|
473
503
|
beforeAll(() => {
|
|
474
504
|
const inputStream = new PassThrough()
|
|
475
505
|
const outputStream = new Writable({
|
|
476
|
-
write
|
|
506
|
+
write(data, _enc, next) {
|
|
477
507
|
actualOutput += data.toString()
|
|
478
508
|
next()
|
|
479
|
-
}
|
|
509
|
+
},
|
|
480
510
|
})
|
|
481
|
-
jsonRpc = new JsonRpcInterface({inputStream, outputStream})
|
|
482
|
-
jsonRpc.events.on(
|
|
511
|
+
jsonRpc = new JsonRpcInterface({ inputStream, outputStream })
|
|
512
|
+
jsonRpc.events.on("rpc-error", (error) => {
|
|
483
513
|
actualError = error
|
|
484
514
|
})
|
|
485
|
-
jsonRpc._handleIncomingLspMessage({id: null, message: null})
|
|
515
|
+
jsonRpc._handleIncomingLspMessage({ id: null, message: null })
|
|
486
516
|
})
|
|
487
517
|
|
|
488
518
|
it("should emit an rpc-error event on the events emitter", () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Transform } from
|
|
2
|
-
import { headerKey, parseErrorCode, parseHeaderErrorMessage, parseJsonErrorMessage } from
|
|
1
|
+
import { Transform } from "node:stream"
|
|
2
|
+
import { headerKey, parseErrorCode, parseHeaderErrorMessage, parseJsonErrorMessage } from "./constants.js"
|
|
3
3
|
|
|
4
4
|
const defaultInitialBufferSize = 10000
|
|
5
5
|
|
|
@@ -9,7 +9,9 @@ const jsonStartCharCode = "{".charCodeAt(0)
|
|
|
9
9
|
const findJsonStartIndex = (data, bufferStartIndex, bufferEndIndex) => {
|
|
10
10
|
const bufferedData = data.subarray(bufferStartIndex, bufferEndIndex)
|
|
11
11
|
const index = bufferedData.indexOf(jsonStartCharCode)
|
|
12
|
-
if (index < 0) {
|
|
12
|
+
if (index < 0) {
|
|
13
|
+
return index
|
|
14
|
+
}
|
|
13
15
|
return index + bufferStartIndex
|
|
14
16
|
}
|
|
15
17
|
|
|
@@ -18,24 +20,26 @@ const frameStartRegex = new RegExp(`${headerKey}: ([0-9]+)`, "i")
|
|
|
18
20
|
const getJsonLength = (data, bufferStartIndex, jsonStartIndex) => {
|
|
19
21
|
const startStr = data.subarray(bufferStartIndex, jsonStartIndex).toString()
|
|
20
22
|
const match = frameStartRegex.exec(startStr)
|
|
21
|
-
if (!match) {
|
|
23
|
+
if (!match) {
|
|
24
|
+
return null
|
|
25
|
+
}
|
|
22
26
|
return Number.parseInt(match[1])
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
export class LspReader extends Transform {
|
|
26
|
-
constructor
|
|
27
|
-
super({readableObjectMode: true})
|
|
30
|
+
constructor(options = {}) {
|
|
31
|
+
super({ readableObjectMode: true })
|
|
28
32
|
this.buffer = Buffer.alloc(options.initialBufferSize || defaultInitialBufferSize)
|
|
29
33
|
this._resetBuffer()
|
|
30
34
|
}
|
|
31
35
|
|
|
32
|
-
_transform
|
|
36
|
+
_transform(data, _enc, next) {
|
|
33
37
|
this._writeToBuffer(data)
|
|
34
38
|
this._handleBufferedData()
|
|
35
39
|
next()
|
|
36
40
|
}
|
|
37
41
|
|
|
38
|
-
_resetBuffer
|
|
42
|
+
_resetBuffer() {
|
|
39
43
|
this.bufferStartIndex = 0
|
|
40
44
|
this.bufferIndex = 0
|
|
41
45
|
this.jsonStartIndex = -1
|
|
@@ -43,20 +47,20 @@ export class LspReader extends Transform {
|
|
|
43
47
|
this.jsonLength = null
|
|
44
48
|
}
|
|
45
49
|
|
|
46
|
-
_resetBufferWithRemainingData
|
|
50
|
+
_resetBufferWithRemainingData() {
|
|
47
51
|
const remainingData = this.buffer.subarray(this.bufferStartIndex, this.bufferIndex)
|
|
48
52
|
this._resetBuffer()
|
|
49
53
|
this._writeToBuffer(remainingData)
|
|
50
54
|
}
|
|
51
55
|
|
|
52
|
-
_advanceBufferOneMessage
|
|
56
|
+
_advanceBufferOneMessage() {
|
|
53
57
|
this.bufferStartIndex = this.jsonEndIndex
|
|
54
58
|
this.jsonStartIndex = -1
|
|
55
59
|
this.jsonEndIndex = -1
|
|
56
60
|
this.jsonLength = null
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
_writeToBuffer
|
|
63
|
+
_writeToBuffer(data) {
|
|
60
64
|
const spaceLeft = this.buffer.length - this.bufferIndex
|
|
61
65
|
if (data.length > spaceLeft) {
|
|
62
66
|
const newBufferSize = (this.bufferIndex + data.length) * 1.3 // add a padding of 30% to reduce the number of resizes
|
|
@@ -67,15 +71,17 @@ export class LspReader extends Transform {
|
|
|
67
71
|
this.bufferIndex += data.length
|
|
68
72
|
}
|
|
69
73
|
|
|
70
|
-
_foundJsonLength
|
|
74
|
+
_foundJsonLength() {
|
|
71
75
|
if (this.jsonStartIndex < 0) {
|
|
72
76
|
this.jsonStartIndex = findJsonStartIndex(this.buffer, this.bufferStartIndex, this.bufferIndex)
|
|
73
|
-
if (this.jsonStartIndex < 0) {
|
|
77
|
+
if (this.jsonStartIndex < 0) {
|
|
78
|
+
return false
|
|
79
|
+
}
|
|
74
80
|
|
|
75
81
|
this.jsonLength = getJsonLength(this.buffer, this.bufferStartIndex, this.jsonStartIndex)
|
|
76
82
|
|
|
77
83
|
if (this.jsonLength === null) {
|
|
78
|
-
this.emit("parse-error", {code: parseErrorCode, message: parseHeaderErrorMessage})
|
|
84
|
+
this.emit("parse-error", { code: parseErrorCode, message: parseHeaderErrorMessage })
|
|
79
85
|
this._resetBuffer()
|
|
80
86
|
return false
|
|
81
87
|
}
|
|
@@ -86,19 +92,23 @@ export class LspReader extends Transform {
|
|
|
86
92
|
return true
|
|
87
93
|
}
|
|
88
94
|
|
|
89
|
-
_handleBufferedData
|
|
95
|
+
_handleBufferedData() {
|
|
90
96
|
// loop as long as we have messages to parse in the buffer (ignore the eslint warning about the constant true value)
|
|
91
|
-
while (true) {
|
|
92
|
-
if (!this._foundJsonLength()) {
|
|
93
|
-
|
|
97
|
+
while (true) {
|
|
98
|
+
if (!this._foundJsonLength()) {
|
|
99
|
+
break
|
|
100
|
+
} // we don't have a header to read yet, keep buffering
|
|
101
|
+
if (this.jsonEndIndex > this.bufferIndex) {
|
|
102
|
+
break
|
|
103
|
+
} // we have a header but not the complete json message, keep buffering
|
|
94
104
|
|
|
95
105
|
const messageStr = this.buffer.subarray(this.jsonStartIndex, this.jsonEndIndex).toString()
|
|
96
106
|
|
|
97
107
|
let messageObj
|
|
98
108
|
try {
|
|
99
109
|
messageObj = JSON.parse(messageStr)
|
|
100
|
-
} catch
|
|
101
|
-
this.emit("parse-error", {code: parseErrorCode, message: parseJsonErrorMessage})
|
|
110
|
+
} catch {
|
|
111
|
+
this.emit("parse-error", { code: parseErrorCode, message: parseJsonErrorMessage })
|
|
102
112
|
this._resetBuffer()
|
|
103
113
|
return
|
|
104
114
|
}
|