import type { FeedItem } from '../../interfaces/feed.types.js'; export class TerminalFormatter { format(items: FeedItem[]): string { if (items.length === 0) { return '\n No items to display.\n'; } const lines: string[] = []; lines.push(''); lines.push(` ${this.bold(`Found ${items.length} item${items.length === 1 ? '' : 's'}`)}`); lines.push(''); items.forEach((item, index) => { const number = `${index + 1}.`.padStart(3); lines.push(` ${this.dim(number)} ${this.cyan(item.source)}`); lines.push(` ${this.bold(item.title)}`); lines.push(` ${this.dim(this.formatDate(item.publishedAt))}`); lines.push(` ${this.blue(item.url)}`); if (item.summary) { const truncated = this.truncate(item.summary, 80); lines.push(` ${this.dim(truncated)}`); } lines.push(''); }); return lines.join('\n'); } private formatDate(date: Date): string { return date.toLocaleString('en-US', { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); } private truncate(text: string, maxLength: number): string { if (text.length <= maxLength) { return text; } return text.substring(0, maxLength - 3) + '...'; } // ANSI color codes private bold(text: string): string { return `\x1b[1m${text}\x1b[0m`; } private dim(text: string): string { return `\x1b[2m${text}\x1b[0m`; } private cyan(text: string): string { return `\x1b[36m${text}\x1b[0m`; } private blue(text: string): string { return `\x1b[34m${text}\x1b[0m`; } }