morph-cli 0.1.0

AST-based codebase migration and codemod tool for JavaScript and TypeScript projects.
Documentation
use clap::{Parser, Subcommand};
use std::path::PathBuf;

#[derive(Debug, Parser)]
#[command(
    name = "morph",
    version,
    about = "Plugin-based code transformation CLI for migrating codebases",
    long_about = None,
    after_help = "✨ GETTING STARTED WITH morph-cli ✨\n\n\
                  1. Scan your project to identify files & technologies:\n\
                     $ morph scan\n\n\
                  2. Plan recommendations & estimate maturity/confidence:\n\
                     $ morph plan\n\n\
                  3. Run the interactive guided assistant wizard:\n\
                     $ morph magic\n\n\
                  🚀 BEGINNER-SAFE RECOMMENDATIONS:\n\n\
                  • Migrate legacy CommonJS require calls to modern ESM imports:\n\
                    $ morph run commonjs-to-esm . --dry-run --review\n\n\
                  • Safely upgrade JavaScript files to TypeScript with complete confidence:\n\
                    $ morph run js-to-ts . --dry-run --review\n\n\
                  • Validate repository setup and environment health:\n\
                    $ morph doctor .\n\n\
                  👉 Need help? Visit our docs or run a preset workflow: `morph preset list`"
)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Command,
}

#[derive(Debug, Subcommand)]
pub enum Command {
    /// Print the current morph-cli version
    Version,
    /// List available migration recipes
    List {
        #[arg(default_value = ".")]
        path: PathBuf,
        /// Filter recipes by category (e.g. migration, cleanup, modernization, analysis, experimental)
        #[arg(long)]
        category: Option<String>,
        /// Filter recipes by tag (e.g. safe, fast, risky, typescript, react, backend, frontend)
        #[arg(long)]
        tag: Option<String>,
    },
    /// Search for recipes matching a query
    Search {
        /// Search query (matches name, description, category, tags)
        query: String,
        #[arg(default_value = ".")]
        path: PathBuf,
        /// Filter by category (e.g. migration, cleanup, modernization, analysis, experimental)
        #[arg(long)]
        category: Option<String>,
        /// Filter by maturity (e.g. stable, beta, experimental)
        #[arg(long)]
        maturity: Option<String>,
    },
    /// Show migration history summaries
    History {
        /// Limit the number of sessions to display
        #[arg(short = 'n', long, default_value_t = 10)]
        limit: usize,
    },
    /// Initialize a new morph-cli.toml configuration file
    Init {
        #[arg(default_value = ".")]
        path: PathBuf,
    },
    /// Plan recommended migration recipes for a project
    #[command(visible_alias = "p")]
    Plan {
        #[arg(default_value = ".")]
        path: PathBuf,
        /// Filter by file tag (e.g. commonjs, esm, react, typescript, risky, generated, ignored)
        #[arg(long)]
        tag: Option<String>,
    },
    /// Explain migration detection for a file
    Explain { file: PathBuf },
    /// Run a recipe against a target path
    Run {
        #[arg(required = true, num_args = 2.., value_name = "RECIPE... PATH")]
        args: Vec<String>,
        #[arg(long)]
        write: bool,
        #[arg(long)]
        dry_run: bool,
        #[arg(long)]
        review: bool,
        #[arg(long)]
        autofix: bool,
        #[arg(long)]
        verbose: bool,
        #[arg(long)]
        summary_only: bool,
        #[arg(long)]
        max_preview_lines: Option<usize>,
        #[arg(long)]
        allow_risky: bool,
        #[arg(long)]
        strict: bool,
        /// Generate JSON report
        #[arg(long)]
        report_json: bool,
        /// Generate Markdown report
        #[arg(long)]
        report_md: bool,
        /// Output directory for reports
        #[arg(long, default_value = ".morph-cli/reports")]
        report_dir: PathBuf,
        /// Enable formatting preservation
        #[arg(long)]
        format: bool,
        /// Use Prettier for formatting
        #[arg(long)]
        prettier: bool,
        /// Disable formatting
        #[arg(long)]
        no_format: bool,
        /// Number of parallel jobs (default: CPU count)
        #[arg(long)]
        jobs: Option<usize>,
        /// Run sequentially (disable parallelism)
        #[arg(long)]
        sequential: bool,
        /// Limit execution to a workspace package by package name
        #[arg(long)]
        package: Option<String>,
        /// Profile name to load config overrides from
        #[arg(long)]
        profile: Option<String>,
        /// Output style (minimal, default, detailed)
        #[arg(long)]
        output_style: Option<String>,
        /// Filter by file tag (e.g. commonjs, esm, react, typescript, risky, generated, ignored)
        #[arg(long)]
        tag: Option<String>,
    },
    /// List migration run sessions
    Sessions,
    /// Show a migration run session
    Session { id: String },
    /// Rollback files from a previous transformation session
    Rollback {
        session_id: String,
        #[arg(long)]
        preview: bool,
        #[arg(long)]
        force: bool,
    },
    /// Replay a previous transformation session with stored options
    Replay {
        session_id: String,
        /// Apply changes (write to disk), overrides stored mode if true
        #[arg(long)]
        write: bool,
    },
    /// Resume migration from a saved checkpoint
    Resume {
        /// Checkpoint ID to resume from
        #[arg(long)]
        checkpoint: String,
    },
    /// List scan snapshots
    Scans,
    /// Generate shell completion scripts
    Completions {
        /// The shell to generate completions for
        #[arg(value_enum)]
        shell: clap_complete::Shell,
    },
    /// Scan project and detect technologies
    #[command(visible_alias = "s")]
    Scan {
        #[command(subcommand)]
        action: Option<ScanAction>,

        #[arg(default_value = ".")]
        path: PathBuf,
        /// Filter by file tag (e.g. commonjs, esm, react, typescript, risky, generated, ignored)
        #[arg(long)]
        tag: Option<String>,
        /// Show verbose skip output
        #[arg(short = 'v', long)]
        verbose: bool,
    },
    /// Analyze lightweight dependencies
    Deps {
        #[arg(default_value = ".")]
        path: PathBuf,
    },
    /// Calculate modernization score and readiness
    Score {
        #[arg(default_value = ".")]
        path: PathBuf,
        /// Output format (text or json)
        #[arg(long, default_value = "text")]
        format: String,
    },
    /// Simulate migration impact without transforming files
    #[command(visible_alias = "sim")]
    Simulate {
        /// Recipes to simulate; repeat to select multiple recipes
        #[arg(short = 'r', long = "recipe", required = true)]
        recipes: Vec<String>,

        #[arg(default_value = ".")]
        path: PathBuf,
    },
    /// Start the local dashboard backend
    Dashboard {
        /// Port to listen on (default: 8080)
        #[arg(long, default_value_t = 8080)]
        port: u16,
    },
    /// Start a guided migration workflow
    Magic {
        #[arg(default_value = ".")]
        path: PathBuf,
    },
    /// Run a full validation suite on a repository (scan, detect, dry-run, verify)
    #[command(visible_alias = "validate")]
    ValidateRepo {
        #[arg(default_value = ".")]
        path: PathBuf,
    },
    /// Benchmark Morph execution performance on the target path
    #[command(visible_alias = "bench")]
    Benchmark {
        #[arg(default_value = ".")]
        path: PathBuf,
    },
    /// Generate visualization graphs (Mermaid or JSON)
    Graph {
        /// Type of graph to generate (pipeline, workspace, deps)
        #[arg(long, default_value = "pipeline")]
        graph_type: String,

        /// Output format (mermaid or json)
        #[arg(long, default_value = "mermaid")]
        format: String,

        #[arg(default_value = ".")]
        path: PathBuf,
    },
    /// Manage preset workflows
    Preset {
        #[command(subcommand)]
        action: PresetAction,
    },
    /// Verify the integrity of transformed files (syntax, imports, exports)
    Verify {
        #[arg(default_value = ".")]
        path: PathBuf,
    },
    /// Watch for file changes and re-run migration analysis
    Watch {
        #[arg(default_value = ".")]
        path: PathBuf,
        /// Recipe to analyze; repeat to select multiple recipes
        #[arg(long = "recipe")]
        recipes: Vec<String>,
        /// Debounce delay in milliseconds
        #[arg(long, default_value_t = 500)]
        debounce_ms: u64,
    },
    /// AI-powered suggestions and analysis
    Ai {
        #[command(subcommand)]
        action: AiAction,
    },
    /// Manage and run migration manifests
    Manifest {
        #[command(subcommand)]
        action: ManifestAction,
    },
    /// Manage plugins
    Plugins {
        #[command(subcommand)]
        action: PluginAction,
    },
    /// View ignored and skipped files with reasons
    Ignored {
        #[arg(default_value = ".")]
        path: PathBuf,
        /// Show detailed list of all ignored files instead of a summary
        #[arg(short, long)]
        detailed: bool,
    },
    /// List all dry-run execution snapshots
    DryRuns,
    /// View detailed metrics of a specific dry-run execution snapshot
    DryRun {
        #[command(subcommand)]
        action: DryRunAction,
    },
    /// Generate markdown documentation for Morph CLI components
    Docs,
    /// Check repository health and environment
    Doctor {
        #[arg(default_value = ".")]
        path: PathBuf,
    },
}

#[derive(Debug, Subcommand)]
pub enum AiAction {
    /// Suggest improvements for a specific file
    Suggest { file: PathBuf },
}

#[derive(Debug, Subcommand)]
pub enum PresetAction {
    /// List all built-in presets
    List,
    /// Run a specific preset workflow
    Run {
        /// Name of the preset to run
        name: String,
        /// Target path (defaults to current directory)
        #[arg(default_value = ".")]
        path: PathBuf,
        /// Apply changes (write to disk)
        #[arg(long)]
        write: bool,
    },
}

#[derive(Debug, Subcommand)]
pub enum PluginAction {
    /// List all discovered plugins
    List,
    /// Show detailed info about a plugin
    Info { name: String },
}

#[derive(Debug, Subcommand, Clone)]
pub enum ManifestAction {
    /// Create a migration manifest file
    Create {
        /// Path to save the manifest (e.g. morph-migration.toml)
        #[arg(default_value = "morph-migration.toml")]
        file: std::path::PathBuf,
        /// Optional configuration profile to use
        #[arg(long)]
        profile: Option<String>,
        /// Recipes to execute; repeat to specify multiple recipes
        #[arg(short = 'r', long = "recipe")]
        recipes: Vec<String>,
        /// Target path to apply migration to (defaults to current directory)
        #[arg(short = 't', long = "target", default_value = ".")]
        target: std::path::PathBuf,
        /// Apply changes (write to disk)
        #[arg(long)]
        write: bool,
        /// Simulate execution without writing to disk
        #[arg(long)]
        dry_run: bool,
        /// Allow recipes to execute even with potential risks
        #[arg(long)]
        allow_risky: bool,
        /// Enforce strict type checking and zero warnings
        #[arg(long)]
        strict: bool,
        /// Automatically fix minor lint/style issues
        #[arg(long)]
        autofix: bool,
    },
    /// Run a migration manifest file
    Run {
        /// Path to the manifest file (e.g. morph-migration.toml)
        file: std::path::PathBuf,
    },
}

#[derive(Debug, Subcommand, Clone)]
pub enum DryRunAction {
    /// Show a specific dry-run execution snapshot by ID
    Show { id: String },
}

#[derive(Debug, Subcommand, Clone)]
pub enum ScanAction {
    /// Show a specific scan snapshot by ID
    Show { id: String },
}

pub fn parse() -> Cli {
    Cli::parse()
}