Add oxlint-tsgolint and configure typescript/no-unnecessary-type-assertion to flag redundant `!` and `as Foo` casts. Type-aware mode is left off by default to keep `npm run lint` fast; the rule sits configured for when we turn type-aware on intentionally. Auto-fix removed ~283 redundant casts; two manual touch-ups: a real tsgolint false positive in split-container.tsx and a stale ChildProcess import after a double-cast collapsed.
88 lines
2.0 KiB
TypeScript
88 lines
2.0 KiB
TypeScript
export interface TerminalOutputCoalescerTimers {
|
|
setTimeout: typeof setTimeout;
|
|
clearTimeout: typeof clearTimeout;
|
|
}
|
|
|
|
export interface TerminalOutputCoalescerFlush {
|
|
payload: Buffer;
|
|
chars: number;
|
|
bytes: number;
|
|
}
|
|
|
|
export interface TerminalOutputCoalescerOptions {
|
|
timers: TerminalOutputCoalescerTimers;
|
|
flushDelayMs?: number;
|
|
onFlush: (payload: TerminalOutputCoalescerFlush) => void;
|
|
}
|
|
|
|
const DEFAULT_FLUSH_DELAY_MS = 5;
|
|
|
|
export class TerminalOutputCoalescer {
|
|
private readonly timers: TerminalOutputCoalescerTimers;
|
|
private readonly flushDelayMs: number;
|
|
private readonly onFlush: (payload: TerminalOutputCoalescerFlush) => void;
|
|
private chunks: Buffer[] = [];
|
|
private bytes = 0;
|
|
private chars = 0;
|
|
private flushTimer: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
constructor(options: TerminalOutputCoalescerOptions) {
|
|
this.timers = options.timers;
|
|
this.flushDelayMs = options.flushDelayMs ?? DEFAULT_FLUSH_DELAY_MS;
|
|
this.onFlush = options.onFlush;
|
|
}
|
|
|
|
handle(data: string): void {
|
|
if (data.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const chunk = Buffer.from(data, "utf8");
|
|
this.chunks.push(chunk);
|
|
this.bytes += chunk.byteLength;
|
|
this.chars += data.length;
|
|
|
|
if (!this.flushTimer) {
|
|
this.flushTimer = this.timers.setTimeout(() => {
|
|
this.flushTimer = null;
|
|
this.flush();
|
|
}, this.flushDelayMs);
|
|
}
|
|
}
|
|
|
|
flush(): void {
|
|
this.clearTimer();
|
|
|
|
if (this.chunks.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const payload =
|
|
this.chunks.length === 1 ? this.chunks[0] : Buffer.concat(this.chunks, this.bytes);
|
|
const bytes = this.bytes;
|
|
const chars = this.chars;
|
|
this.clearPending();
|
|
|
|
this.onFlush({ payload, bytes, chars });
|
|
}
|
|
|
|
dispose(): void {
|
|
this.clearTimer();
|
|
this.clearPending();
|
|
}
|
|
|
|
private clearTimer(): void {
|
|
if (!this.flushTimer) {
|
|
return;
|
|
}
|
|
this.timers.clearTimeout(this.flushTimer);
|
|
this.flushTimer = null;
|
|
}
|
|
|
|
private clearPending(): void {
|
|
this.chunks = [];
|
|
this.bytes = 0;
|
|
this.chars = 0;
|
|
}
|
|
}
|