/** * Console implementation that captures all log output for code execution. * * Provides the same interface as the native console object but appends * all output to an internal log string that can be retrieved. */ export class ExecuteCodeTaskConsole { /** * Accumulated log output from all console method calls. */ private logOutput: string = ""; /** * Resets the accumulated log output to empty string. * Should be called before each code execution to start with clean logs. */ resetLog(): void { this.logOutput = ""; } /** * Gets the accumulated log output from all console method calls. * @returns The complete log output as a string */ getLog(): string { return this.logOutput; } /** * Formats one argument of a captured console call. * Errors have no enumerable fields, and values such as circular objects * cannot be serialized to JSON, so fall back to their string form. */ private formatLogArgument(arg: unknown): string { if (arg instanceof Error) { return String(arg); } if (typeof arg === "object") { try { return JSON.stringify(arg, null, 2); } catch { return String(arg); } } return String(arg); } /** * Appends a formatted message to the log output. * @param level - Log level prefix (e.g., "LOG", "WARN", "ERROR") * @param args - Arguments to log, will be stringified and joined */ private appendToLog(level: string, ...args: any[]): void { const message = args.map((arg) => this.formatLogArgument(arg)).join(" "); this.logOutput += `[${level}] ${message}\n`; } /** * Logs a message to the captured output. */ log(...args: any[]): void { this.appendToLog("LOG", ...args); } /** * Logs a warning message to the captured output. */ warn(...args: any[]): void { this.appendToLog("WARN", ...args); } /** * Logs an error message to the captured output. */ error(...args: any[]): void { this.appendToLog("ERROR", ...args); } /** * Logs an informational message to the captured output. */ info(...args: any[]): void { this.appendToLog("INFO", ...args); } /** * Logs a debug message to the captured output. */ debug(...args: any[]): void { this.appendToLog("DEBUG", ...args); } /** * Logs a message with trace information to the captured output. */ trace(...args: any[]): void { this.appendToLog("TRACE", ...args); } /** * Logs a table to the captured output (simplified as JSON). */ table(data: any): void { this.appendToLog("TABLE", data); } /** * Starts a timer (simplified implementation that just logs). */ time(label?: string): void { this.appendToLog("TIME", `Timer started: ${label || "default"}`); } /** * Ends a timer (simplified implementation that just logs). */ timeEnd(label?: string): void { this.appendToLog("TIME_END", `Timer ended: ${label || "default"}`); } /** * Logs messages in a group (simplified to just log the label). */ group(label?: string): void { this.appendToLog("GROUP", label || ""); } /** * Logs messages in a collapsed group (simplified to just log the label). */ groupCollapsed(label?: string): void { this.appendToLog("GROUP_COLLAPSED", label || ""); } /** * Ends the current group (simplified implementation). */ groupEnd(): void { this.appendToLog("GROUP_END", ""); } /** * Clears the console (no-op in this implementation since we want to capture logs). */ clear(): void { // intentionally empty - we don't want to clear captured logs } /** * Counts occurrences of calls with the same label (simplified implementation). */ count(label?: string): void { this.appendToLog("COUNT", label || "default"); } /** * Resets the count for a label (simplified implementation). */ countReset(label?: string): void { this.appendToLog("COUNT_RESET", label || "default"); } /** * Logs an assertion (simplified to just log if condition is false). */ assert(condition: boolean, ...args: any[]): void { if (!condition) { this.appendToLog("ASSERT", ...args); } } }