morph-cli 0.1.0

AST-based codebase migration and codemod tool for JavaScript and TypeScript projects.
Documentation
use std::path::Path;
use anyhow::Result;
use crate::cli::DryRunAction;
use crate::core::dry_run::DryRunSnapshotStore;
use chrono::{TimeZone, Utc};
use crate::utils::terminal;

pub fn execute_list(project_root: &Path) -> Result<()> {
    let store = DryRunSnapshotStore::new(project_root);
    let list = store.list()?;

    println!();
    println!("{}", terminal::label("Dry-Run Snapshots:"));
    println!("{}", terminal::label("".repeat(50).as_str()));

    if list.is_empty() {
        println!("  No dry-run snapshots stored yet.");
        return Ok(());
    }

    for snap in list {
        let dt = Utc.timestamp_opt(snap.timestamp as i64, 0).unwrap();
        let datetime = dt.format("%Y-%m-%d %H:%M:%S UTC").to_string();
        println!(
            "  {} {} [changed: {} file(s), risky: {} file(s)] [{}]",
            terminal::bullet(),
            terminal::label(&snap.id),
            snap.changed_files_count,
            snap.risky_files_count,
            datetime
        );
        println!("    Path:    {}", snap.target_path.display());
        println!("    Recipes: {}", snap.recipes.join(", "));
        println!();
    }

    Ok(())
}

pub fn execute_show(action: DryRunAction, project_root: &Path) -> Result<()> {
    match action {
        DryRunAction::Show { id } => {
            let store = DryRunSnapshotStore::new(project_root);
            let snapshot = store.load(&id)?;

            let Some(snap) = snapshot else {
                anyhow::bail!("Dry-run snapshot not found: {}", id);
            };

            let dt = Utc.timestamp_opt(snap.timestamp as i64, 0).unwrap();
            let datetime = dt.format("%Y-%m-%d %H:%M:%S UTC").to_string();

            println!();
            println!(
                "{} Dry-Run Snapshot Detail: {}",
                terminal::success_prefix(),
                terminal::label(&snap.id)
            );
            println!("  Timestamp:   {}", datetime);
            println!("  Target Path: {}", snap.target_path.display());
            println!("  Recipes:     {}", snap.recipes.join(", "));
            println!();
            println!("  {}", terminal::label("Execution Metrics:"));
            println!("    Changed Files Count: {}", snap.changed_files_count);
            println!("    Risky Files Count:   {}", snap.risky_files_count);
            println!();
            println!("  {}", terminal::label("Warnings:"));
            if snap.warnings.is_empty() {
                println!("    None");
            } else {
                for warning in &snap.warnings {
                    println!("    {} {}", terminal::warning_prefix(), warning);
                }
            }
            println!();
            Ok(())
        }
    }
}