Skip to content

Commit e4df674

Browse files
isc-kluclaude
andcommitted
Make WebSocketMessage a discriminated union
Every field but `type` was optional, so reading any of them needed a non-null assertion. Spelling out one member per message type lets the compiler tell which fields a message actually has. `currentNs` becomes optional to match: `ns` is only sent by IRIS 2025.3+, so the old `message.ns!` was writing `undefined` into a field declared `string`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 022765a commit e4df674

1 file changed

Lines changed: 18 additions & 24 deletions

File tree

src/commands/webSocketTerminal.ts

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,12 @@ const actions = {
3636
};
3737

3838
/** Data received from the WebSocket */
39-
interface WebSocketMessage {
40-
/** The type of the message */
41-
type: "prompt" | "read" | "error" | "output" | "init" | "color";
42-
/** The text of the message. Present for all types but "read" and "init". */
43-
text?: string;
44-
/** The WebSocket protocol version. Only present for "init". */
45-
protocol?: number;
46-
/** The InterSystems IRIS `$ZVERSION`. Only present for "init". */
47-
version?: string;
48-
/** The current namespace. Only present for "prompt" on IRIS 2025.3+. */
49-
ns?: string;
50-
}
39+
type WebSocketMessage =
40+
/** `ns` is only sent by IRIS 2025.3+ */
41+
| { type: "prompt"; text: string; ns?: string }
42+
| { type: "error" | "output" | "color"; text: string }
43+
| { type: "read" }
44+
| { type: "init"; protocol: number; version: string };
5145

5246
class WebSocketTerminal implements vscode.Pseudoterminal {
5347
private _writeEmitter = new vscode.EventEmitter<string>();
@@ -99,7 +93,7 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
9993
private _colorsRegex = /\x1b[^m]*?m/g;
10094

10195
/** The terminal's current namespace */
102-
public currentNs: string;
96+
public currentNs?: string;
10397

10498
constructor(
10599
public readonly targetUri: vscode.Uri,
@@ -259,19 +253,19 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
259253
// Write the output to the terminal
260254
if (this._firstOutputLineSincePrompt) {
261255
// Strip leading \r\n since we printed it already
262-
message.text = message.text!.startsWith("\r\n") ? message.text!.slice(2) : message.text;
256+
message.text = message.text.startsWith("\r\n") ? message.text.slice(2) : message.text;
263257
this._firstOutputLineSincePrompt = false;
264258
}
265-
if (message.text!.includes("\x1b[31;1m")) {
266-
if (message.text!.includes("\x1b[31;1m<INTERRUPT>")) {
259+
if (message.text.includes("\x1b[31;1m")) {
260+
if (message.text.includes("\x1b[31;1m<INTERRUPT>")) {
267261
// Report no exit code for interrupts
268262
this._promptExitCode = "";
269263
} else {
270264
this._promptExitCode = ";1";
271265
}
272266
}
273-
this._margin = this._cursorCol = message.text!.split("\r\n").pop()!.length;
274-
this._hideCursorWrite(message.text!);
267+
this._margin = this._cursorCol = message.text.split("\r\n").pop()!.length;
268+
this._hideCursorWrite(message.text);
275269
break;
276270
case "prompt":
277271
case "read":
@@ -280,11 +274,11 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
280274
this._hideCursorWrite(
281275
`\x1b]633;D${this._promptExitCode}\x07\r\n\x1b]633;A\x07${message.text}\x1b]633;B\x07`
282276
);
283-
this._margin = this._cursorCol = message.text!.replace(this._colorsRegex, "").length;
284-
this._prompt = message.text!;
277+
this._margin = this._cursorCol = message.text.replace(this._colorsRegex, "").length;
278+
this._prompt = message.text;
285279
this._promptExitCode = ";0";
286280
// Store the current namespace
287-
this.currentNs = message.ns!;
281+
this.currentNs = message.ns;
288282
}
289283
// Enable input
290284
this._state = message.type;
@@ -305,13 +299,13 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
305299
if (this._state != "prompt") break;
306300
// Replace the input with the syntax colored text, keeping the cursor at the same spot
307301
let cursorLine = Math.ceil((this._cursorCol + 1) / this._cols) - 1;
308-
if (message.text!.includes("\r\n")) {
309-
const lines = message.text!.replace(this._colorsRegex, "").split("\r\n");
302+
if (message.text.includes("\r\n")) {
303+
const lines = message.text.replace(this._colorsRegex, "").split("\r\n");
310304
lines.pop();
311305
cursorLine += lines.reduce((sum, line) => sum + Math.ceil((line.length + 1) / this._cols), 0);
312306
}
313307
this._hideCursorWrite(
314-
`\x1b7${cursorLine > 0 ? `\x1b[${cursorLine}A` : ""}\r\x1b[0J${this._prompt}${message.text!.replace(
308+
`\x1b7${cursorLine > 0 ? `\x1b[${cursorLine}A` : ""}\r\x1b[0J${this._prompt}${message.text.replace(
315309
/\r\n/g,
316310
`\r\n${this.multiLinePrompt}`
317311
)}\x1b8`

0 commit comments

Comments
 (0)