summaryrefslogtreecommitdiffhomepage
path: root/packages/lsp/src/framing.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/lsp/src/framing.ts')
-rw-r--r--packages/lsp/src/framing.ts116
1 files changed, 58 insertions, 58 deletions
diff --git a/packages/lsp/src/framing.ts b/packages/lsp/src/framing.ts
index 88e60c1..b86fcbf 100644
--- a/packages/lsp/src/framing.ts
+++ b/packages/lsp/src/framing.ts
@@ -16,13 +16,13 @@ const LF = 0x0a; // \n
const CONTENT_LENGTH_RE = /Content-Length:\s*(\d+)/i;
export function encode(msg: string): Uint8Array {
- const body = new TextEncoder().encode(msg);
- const header = `Content-Length: ${body.length}\r\n\r\n`;
- const frame = new TextEncoder().encode(header);
- const result = new Uint8Array(frame.length + body.length);
- result.set(frame);
- result.set(body, frame.length);
- return result;
+ const body = new TextEncoder().encode(msg);
+ const header = `Content-Length: ${body.length}\r\n\r\n`;
+ const frame = new TextEncoder().encode(header);
+ const result = new Uint8Array(frame.length + body.length);
+ result.set(frame);
+ result.set(body, frame.length);
+ return result;
}
/**
@@ -30,65 +30,65 @@ export function encode(msg: string): Uint8Array {
* starting at offset `from`. Returns the index of the first byte, or -1.
*/
function findHeaderSep(buf: Uint8Array, from: number): number {
- const limit = buf.length - 3;
- for (let i = from; i < limit; i++) {
- if (buf[i] === CR && buf[i + 1] === LF && buf[i + 2] === CR && buf[i + 3] === LF) {
- return i;
- }
- }
- return -1;
+ const limit = buf.length - 3;
+ for (let i = from; i < limit; i++) {
+ if (buf[i] === CR && buf[i + 1] === LF && buf[i + 2] === CR && buf[i + 3] === LF) {
+ return i;
+ }
+ }
+ return -1;
}
export class FrameDecoder {
- private buffer: Uint8Array = new Uint8Array(0);
- private expectedLength: number | null = null;
- private headerEndByte = -1;
+ private buffer: Uint8Array = new Uint8Array(0);
+ private expectedLength: number | null = null;
+ private headerEndByte = -1;
- /**
- * Feed raw bytes into the decoder. Returns all complete JSON messages
- * that can be extracted from the accumulated buffer.
- */
- decode(chunk: Uint8Array): string[] {
- // Append the new chunk to the internal byte buffer.
- const newBuf = new Uint8Array(this.buffer.length + chunk.length);
- newBuf.set(this.buffer);
- newBuf.set(chunk, this.buffer.length);
- this.buffer = newBuf;
+ /**
+ * Feed raw bytes into the decoder. Returns all complete JSON messages
+ * that can be extracted from the accumulated buffer.
+ */
+ decode(chunk: Uint8Array): string[] {
+ // Append the new chunk to the internal byte buffer.
+ const newBuf = new Uint8Array(this.buffer.length + chunk.length);
+ newBuf.set(this.buffer);
+ newBuf.set(chunk, this.buffer.length);
+ this.buffer = newBuf;
- const messages: string[] = [];
+ const messages: string[] = [];
- while (true) {
- if (this.expectedLength === null) {
- const sepIdx = findHeaderSep(this.buffer, 0);
- if (sepIdx === -1) break;
+ while (true) {
+ if (this.expectedLength === null) {
+ const sepIdx = findHeaderSep(this.buffer, 0);
+ if (sepIdx === -1) break;
- // Decode only the header bytes (always ASCII) to read Content-Length.
- const headerStr = new TextDecoder().decode(this.buffer.slice(0, sepIdx));
- const match = CONTENT_LENGTH_RE.exec(headerStr);
- if (!match?.[1]) {
- // Not a Content-Length header — skip past this separator and retry.
- this.buffer = this.buffer.slice(sepIdx + 4);
- continue;
- }
- this.expectedLength = Number.parseInt(match[1], 10);
- this.headerEndByte = sepIdx + 4; // skip \r\n\r\n
- }
+ // Decode only the header bytes (always ASCII) to read Content-Length.
+ const headerStr = new TextDecoder().decode(this.buffer.slice(0, sepIdx));
+ const match = CONTENT_LENGTH_RE.exec(headerStr);
+ if (!match?.[1]) {
+ // Not a Content-Length header — skip past this separator and retry.
+ this.buffer = this.buffer.slice(sepIdx + 4);
+ continue;
+ }
+ this.expectedLength = Number.parseInt(match[1], 10);
+ this.headerEndByte = sepIdx + 4; // skip \r\n\r\n
+ }
- const bodyStart = this.headerEndByte;
- const available = this.buffer.length - bodyStart;
+ const bodyStart = this.headerEndByte;
+ const available = this.buffer.length - bodyStart;
- if (available >= this.expectedLength) {
- // Extract exactly `expectedLength` bytes (Content-Length is in bytes).
- const bodyBytes = this.buffer.slice(bodyStart, bodyStart + this.expectedLength);
- messages.push(new TextDecoder().decode(bodyBytes));
- this.buffer = this.buffer.slice(bodyStart + this.expectedLength);
- this.expectedLength = null;
- this.headerEndByte = -1;
- } else {
- break;
- }
- }
+ if (available >= this.expectedLength) {
+ // Extract exactly `expectedLength` bytes (Content-Length is in bytes).
+ const bodyBytes = this.buffer.slice(bodyStart, bodyStart + this.expectedLength);
+ messages.push(new TextDecoder().decode(bodyBytes));
+ this.buffer = this.buffer.slice(bodyStart + this.expectedLength);
+ this.expectedLength = null;
+ this.headerEndByte = -1;
+ } else {
+ break;
+ }
+ }
- return messages;
- }
+ return messages;
+ }
}