UNPKG

@git.zone/cli

Version:

A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.

171 lines (150 loc) 5.12 kB
import * as plugins from './mod.plugins.js'; import { FormatContext } from './classes.formatcontext.js'; import { BaseFormatter } from './classes.baseformatter.js'; import type { IFormatPlan, IPlannedChange } from './interfaces.format.js'; import { logger } from '../gitzone.logging.js'; import { DependencyAnalyzer } from './classes.dependency-analyzer.js'; import { DiffReporter } from './classes.diffreporter.js'; export class FormatPlanner { private plannedChanges: Map<string, IPlannedChange[]> = new Map(); private dependencyAnalyzer = new DependencyAnalyzer(); private diffReporter = new DiffReporter(); async planFormat(modules: BaseFormatter[]): Promise<IFormatPlan> { const plan: IFormatPlan = { summary: { totalFiles: 0, filesAdded: 0, filesModified: 0, filesRemoved: 0, estimatedTime: 0, }, changes: [], warnings: [], }; for (const module of modules) { try { const changes = await module.analyze(); this.plannedChanges.set(module.name, changes); for (const change of changes) { plan.changes.push(change); // Update summary switch (change.type) { case 'create': plan.summary.filesAdded++; break; case 'modify': plan.summary.filesModified++; break; case 'delete': plan.summary.filesRemoved++; break; } } } catch (error) { plan.warnings.push({ level: 'error', message: `Failed to analyze module ${module.name}: ${error.message}`, module: module.name, }); } } plan.summary.totalFiles = plan.summary.filesAdded + plan.summary.filesModified + plan.summary.filesRemoved; plan.summary.estimatedTime = plan.summary.totalFiles * 100; // 100ms per file estimate return plan; } async executePlan( plan: IFormatPlan, modules: BaseFormatter[], context: FormatContext, parallel: boolean = false, ): Promise<void> { const startTime = Date.now(); try { // Always use sequential execution to avoid race conditions for (const module of modules) { const changes = this.plannedChanges.get(module.name) || []; if (changes.length > 0) { logger.log('info', `Executing ${module.name} formatter...`); await module.execute(changes); } } const endTime = Date.now(); const duration = endTime - startTime; logger.log('info', `Format operations completed in ${duration}ms`); } catch (error) { throw error; } } async displayPlan( plan: IFormatPlan, detailed: boolean = false, ): Promise<void> { console.log('\nFormat Plan:'); console.log('━'.repeat(50)); console.log(`Summary: ${plan.summary.totalFiles} files will be changed`); console.log(` • ${plan.summary.filesAdded} new files`); console.log(` • ${plan.summary.filesModified} modified files`); console.log(` • ${plan.summary.filesRemoved} deleted files`); console.log(''); console.log('Changes by module:'); // Group changes by module const changesByModule = new Map<string, IPlannedChange[]>(); for (const change of plan.changes) { const moduleChanges = changesByModule.get(change.module) || []; moduleChanges.push(change); changesByModule.set(change.module, moduleChanges); } for (const [module, changes] of changesByModule) { console.log( `\n${this.getModuleIcon(module)} ${module} (${changes.length} ${changes.length === 1 ? 'file' : 'files'})`, ); for (const change of changes) { const icon = this.getChangeIcon(change.type); console.log(` ${icon} ${change.path} - ${change.description}`); // Show diff for modified files if detailed view is requested if (detailed && change.type === 'modify') { const diff = await this.diffReporter.generateDiffForChange(change); if (diff) { this.diffReporter.displayDiff(change.path, diff); } } } } if (plan.warnings.length > 0) { console.log('\nWarnings:'); for (const warning of plan.warnings) { const icon = warning.level === 'error' ? '❌' : '⚠️'; console.log(` ${icon} ${warning.message}`); } } console.log('\n' + '━'.repeat(50)); } private getModuleIcon(module: string): string { const icons: Record<string, string> = { packagejson: '📦', license: '📝', tsconfig: '🔧', cleanup: '🚮', gitignore: '🔒', prettier: '✨', readme: '📖', templates: '📄', npmextra: '⚙️', copy: '📋', }; return icons[module] || '📁'; } private getChangeIcon(type: 'create' | 'modify' | 'delete'): string { switch (type) { case 'create': return '✅'; case 'modify': return '✏️'; case 'delete': return '❌'; } } }