import * as plugins from './mod.plugins.js'; import type { IPlannedChange } from './interfaces.format.js'; import { logger } from '../gitzone.logging.js'; export class DiffReporter { private diffs: Map = new Map(); async generateDiff( filePath: string, oldContent: string, newContent: string, ): Promise { const diff = plugins.smartdiff.createDiff(oldContent, newContent); this.diffs.set(filePath, diff); return diff; } async generateDiffForChange(change: IPlannedChange): Promise { if (change.type !== 'modify') { return null; } try { const exists = await plugins.smartfile.fs.fileExists(change.path); if (!exists) { return null; } const currentContent = await plugins.smartfile.fs.toStringSync( change.path, ); // For planned changes, we need the new content if (!change.content) { return null; } return await this.generateDiff( change.path, currentContent, change.content, ); } catch (error) { logger.log( 'error', `Failed to generate diff for ${change.path}: ${error.message}`, ); return null; } } displayDiff(filePath: string, diff?: string): void { const diffToShow = diff || this.diffs.get(filePath); if (!diffToShow) { logger.log('warn', `No diff available for ${filePath}`); return; } console.log(`\n${this.formatDiffHeader(filePath)}`); console.log(this.colorDiff(diffToShow)); console.log('━'.repeat(50)); } displayAllDiffs(): void { if (this.diffs.size === 0) { logger.log('info', 'No diffs to display'); return; } console.log('\nFile Changes:'); console.log('═'.repeat(50)); for (const [filePath, diff] of this.diffs) { this.displayDiff(filePath, diff); } } private formatDiffHeader(filePath: string): string { return `📄 ${filePath}`; } private colorDiff(diff: string): string { const lines = diff.split('\n'); const coloredLines = lines.map((line) => { if (line.startsWith('+') && !line.startsWith('+++')) { return `\x1b[32m${line}\x1b[0m`; // Green for additions } else if (line.startsWith('-') && !line.startsWith('---')) { return `\x1b[31m${line}\x1b[0m`; // Red for deletions } else if (line.startsWith('@')) { return `\x1b[36m${line}\x1b[0m`; // Cyan for line numbers } else { return line; } }); return coloredLines.join('\n'); } async saveDiffReport(outputPath: string): Promise { const report = { timestamp: new Date().toISOString(), totalFiles: this.diffs.size, diffs: Array.from(this.diffs.entries()).map(([path, diff]) => ({ path, diff, })), }; await plugins.smartfile.memory.toFs( JSON.stringify(report, null, 2), outputPath, ); logger.log('info', `Diff report saved to ${outputPath}`); } hasAnyDiffs(): boolean { return this.diffs.size > 0; } getDiffCount(): number { return this.diffs.size; } }