morph-cli 0.1.0

AST-based codebase migration and codemod tool for JavaScript and TypeScript projects.
Documentation
use std::path::Path;
use colored::Colorize;
use anyhow::{Result, Context};
use crate::core::presets::all_presets;
use crate::core::registry::RecipeRegistry;
use crate::utils::terminal;

pub fn list() -> Result<()> {
    println!();
    println!("{}", terminal::label("Available Presets:"));
    println!("{}", terminal::label("".repeat(50).as_str()));

    let registry = RecipeRegistry::new();

    for preset in all_presets() {
        use crate::core::presets::RiskLevel;
        let risk_str = match preset.risk_level {
            RiskLevel::Low => format!("{}", "low".bold().green()),
            RiskLevel::Medium => format!("{}", "medium".bold().yellow()),
            RiskLevel::High => format!("{}", "high".bold().red()),
        };

        let mut recipe_parts = Vec::new();
        for &recipe_name in preset.recipes {
            if let Some(recipe) = registry.find(recipe_name) {
                recipe_parts.push(format!("{} (category: {})", recipe_name, recipe.metadata().category));
            } else {
                recipe_parts.push(recipe_name.to_string());
            }
        }

        println!("  {} - {}", terminal::label(preset.name), preset.description);
        println!("    Recipes: {}", recipe_parts.join(", "));
        println!("    Risk:    {}", risk_str);
        println!();
    }
    Ok(())
}

pub fn run(name: &str, path: &Path, write: bool, project_root: &Path) -> Result<()> {
    let preset = crate::core::presets::find_preset(name)
        .with_context(|| format!("Preset not found: {}", name))?;

    let mut registry = RecipeRegistry::new();
    registry.load_plugins(path);
    let mut recipe_parts = Vec::new();
    for &recipe_name in preset.recipes {
        if let Some(recipe) = registry.find(recipe_name) {
            recipe_parts.push(format!("{} (category: {})", recipe_name, recipe.metadata().category));
        } else {
            recipe_parts.push(recipe_name.to_string());
        }
    }

    println!();
    println!("{} Running preset: {}", terminal::success_prefix(), terminal::label(preset.name));
    println!("  Description: {}", preset.description);
    println!("  Recipes:     {}", recipe_parts.join(", "));
    println!("  Risk Level:  {:?}", preset.risk_level);
    println!("  Flags:       review={}, allow_risky={}, strict={}", 
        preset.recommended_flags.review,
        preset.recommended_flags.allow_risky,
        preset.recommended_flags.strict
    );

    let recipes: Vec<String> = preset.recipes.iter().map(|&s| s.to_string()).collect();
    
    // Call the existing run command executor
    crate::commands::run::execute(
        &recipes,
        path,
        !write, // dry_run if not write
        write,
        preset.recommended_flags.review,
        false, // autofix
        false, // verbose
        false, // summary_only
        None,  // max_preview_lines
        preset.recommended_flags.allow_risky,
        preset.recommended_flags.strict,
        false, // report_json
        false, // report_md
        Path::new(".morph-cli/reports"), // report_dir
        false, // format
        false, // prettier
        false, // no_format
        None,  // jobs
        false, // sequential
        project_root,
        None,  // package
        None, // profile
        None, // output_style
        None, // tag
    )
}