/** * Shared formatting utilities for CLI output * Used by fetch, pull, push, and update commands for consistent output */ import { bold, cyan, dim, green, red, yellow, gray } from "./colors.js"; import log from "./log.js"; /** * Format a success message with green checkmark */ export function formatSuccess(message) { return `${green('✓')} ${message}`; } /** * Format a warning message with yellow warning icon */ export function formatWarning(message) { return `${yellow('⚠️')} ${message}`; } /** * Build document header lines (shared between printDocumentHeader and formatDocumentPlan) */ function buildDocumentHeaderLines(label, url, info) { const lines = []; lines.push(bold(label)); lines.push(dim(url)); if (info) { lines.push(dim(info)); } return lines; } /** * Get colored symbol for file status */ function getStatusSymbol(status) { switch (status) { case 'new': return green('+'); case 'modified': return yellow('~'); case 'unchanged': case 'synced': case 'included': return green('✓'); case 'add': return cyan('↑'); case 'remove': return red('↓'); case 'ignored': return gray('✗'); default: return ' '; } } /** * Get label for file status (used in parentheses) */ function getStatusLabel(status) { switch (status) { case 'new': return 'new'; case 'modified': return 'modified'; case 'synced': return 'synced'; case 'add': return 'new'; case 'remove': return 'remove'; case 'ignored': return 'ignored'; case 'included': case 'unchanged': default: return null; } } /** * Format a single document plan for display */ export function formatDocumentPlan(plan, options = {}) { const lines = []; const { showAllFiles = false, hiddenFiles = [] } = options; // Header: Label and URL (using shared builder) const archiveInfo = plan.archiveInfo ? `Archive: ${plan.archiveInfo}` : undefined; lines.push(''); lines.push(...buildDocumentHeaderLines(plan.label, plan.url, archiveInfo)); // Filter out hidden files const visibleFiles = plan.files.filter(f => !hiddenFiles.includes(f.file)); // Group files by status const newFiles = visibleFiles.filter(f => f.status === 'new' || f.status === 'add'); const modifiedFiles = visibleFiles.filter(f => f.status === 'modified'); const unchangedFiles = visibleFiles.filter(f => f.status === 'unchanged' || f.status === 'synced' || f.status === 'included'); const removedFiles = visibleFiles.filter(f => f.status === 'remove'); const ignoredFiles = visibleFiles.filter(f => f.status === 'ignored'); if (showAllFiles) { // Show all files individually (update style) for (const file of visibleFiles) { const symbol = getStatusSymbol(file.status); const label = getStatusLabel(file.status); if (label) { lines.push(`${symbol} ${file.file} ${dim(`(${label})`)}`); } else { lines.push(`${symbol} ${file.file}`); } } } else { // Show changes with summaries (fetch style) for (const file of newFiles) { lines.push(`${green('+')} ${file.file} ${dim('(new)')}`); } for (const file of modifiedFiles) { lines.push(`${yellow('~')} ${file.file} ${dim('(modified)')}`); } for (const file of removedFiles) { lines.push(`${red('↓')} ${file.file} ${dim('(remove)')}`); } for (const file of ignoredFiles) { lines.push(`${gray('✗')} ${gray(file.file)} ${dim('(ignored)')}`); } // Summary for unchanged if (unchangedFiles.length > 0) { if (newFiles.length > 0 || modifiedFiles.length > 0 || removedFiles.length > 0) { lines.push(formatSuccess(`${unchangedFiles.length} file(s) unchanged`)); } else { lines.push(formatSuccess(`${unchangedFiles.length} file(s) up to date`)); } } } // Extra info (e.g. settings changes) if (plan.extraInfo && plan.extraInfo.length > 0) { for (const info of plan.extraInfo) { lines.push(`${gray('•')} ${info}`); } } return lines.join('\n'); } /** * Print header with server and page info */ export function printHeader(serverUrl, pagePath) { const serverDomain = new URL(serverUrl).host; log.info(`${bold('Server:')} ${serverDomain}`); log.info(`${bold('Page:')} ${pagePath}`); } //# sourceMappingURL=formatPlan.js.map