diff options
Diffstat (limited to 'packages/lsp/src/framing.ts')
| -rw-r--r-- | packages/lsp/src/framing.ts | 116 |
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; + } } |
