/** * Main render dispatcher for CLI output. * * Selects the appropriate renderer based on output options. */ import chalk from 'chalk' import YAML from 'yaml' import type { AnyCommandResult, CommandError, OutputOptions } from './types.js' import { renderTable } from './table.js' import { renderJson } from './json.js' import { renderYaml } from './yaml.js' import { renderQuiet } from './quiet.js' /** Default output options */ export const defaultOutputOptions: OutputOptions = { format: 'table', quiet: false, noHeaders: false, noColor: false, } /** Render command result to string based on output options */ export function render( result: AnyCommandResult, options: Partial = {} ): string { const opts: OutputOptions = { ...defaultOutputOptions, ...options } // Quiet mode takes precedence if (opts.quiet) { return renderQuiet(result, opts) } // Dispatch to format-specific renderer switch (opts.format) { case 'json': return renderJson(result, opts) case 'yaml': return renderYaml(result, opts) case 'table': default: return renderTable(result, opts) } } /** Convert an unknown error to a CommandError */ export function toCommandError(error: unknown): CommandError { if (isCommandError(error)) { return error } if (error instanceof Error) { return { code: 'UNKNOWN_ERROR', message: error.message, details: error.stack, } } return { code: 'UNKNOWN_ERROR', message: String(error), } } /** Type guard for CommandError */ function isCommandError(error: unknown): error is CommandError { return ( typeof error === 'object' && error !== null && 'code' in error && 'message' in error && typeof (error as CommandError).code === 'string' && typeof (error as CommandError).message === 'string' ) } /** Render an error to string based on output options */ export function renderError( error: CommandError, options: Partial = {} ): string { const opts: OutputOptions = { ...defaultOutputOptions, ...options } if (opts.format === 'json') { return JSON.stringify({ error }, null, 2) } if (opts.format === 'yaml') { return YAML.stringify({ error }) } // Table/default format: human-readable error const prefix = opts.noColor ? 'Error: ' : chalk.red('Error: ') const message = error.message if (error.details && typeof error.details === 'string') { return `${prefix}${message}\n${error.details}` } return `${prefix}${message}` }