singularity-forge/packages/native/src/stream-process/index.ts
2026-05-05 14:46:18 +02:00

76 lines
2 KiB
TypeScript

/**
* Bash stream processor — single-pass UTF-8 decode + ANSI strip + binary sanitization.
*
* Handles chunk boundaries for incomplete UTF-8 and ANSI escape sequences.
*/
import { native } from "../native.js";
export interface StreamState {
utf8Pending: number[];
ansiPending: number[];
}
export interface StreamChunkResult {
text: string;
state: StreamState;
}
/**
* Process a raw bash output chunk in a single pass.
*
* Decodes UTF-8 (handling incomplete multibyte sequences at boundaries),
* strips ANSI escape sequences, removes control characters (except tab and
* newline), removes carriage returns, and filters Unicode format characters.
*
* Pass the returned `state` to the next call to handle sequences split
* across chunk boundaries.
*/
export function processStreamChunk(
chunk: Buffer,
state?: StreamState,
): StreamChunkResult {
// Convert StreamState arrays to the format napi expects (Vec<u8>)
const napiState = state
? {
utf8Pending: Array.from(state.utf8Pending),
ansiPending: Array.from(state.ansiPending),
}
: undefined;
const result = (
native as Record<string, (...args: unknown[]) => unknown>
).processStreamChunk(chunk, napiState) as {
text: string;
state: { utf8Pending: Buffer; ansiPending: Buffer };
};
return {
text: result.text,
state: {
utf8Pending: Array.from(result.state.utf8Pending),
ansiPending: Array.from(result.state.ansiPending),
},
};
}
/**
* Strip ANSI escape sequences from a string.
*/
export function stripAnsiNative(text: string): string {
return (
native as Record<string, (...args: unknown[]) => unknown>
).stripAnsiNative(text) as string;
}
/**
* Remove binary garbage and control characters from a string.
*
* Keeps tab and newline. Removes carriage return, all other control
* characters, Unicode format characters (U+FFF9-U+FFFB), and lone surrogates.
*/
export function sanitizeBinaryOutputNative(text: string): string {
return (
native as Record<string, (...args: unknown[]) => unknown>
).sanitizeBinaryOutputNative(text) as string;
}