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::core::detection::scanner::Scanner;
use crate::utils::terminal;

pub fn execute(path: &Path, detailed: bool) -> Result<()> {
    let path = if path.exists() && path.is_relative() {
        std::env::current_dir()?.join(path)
    } else {
        path.to_path_buf()
    };

    println!("Analyzing ignored and skipped files in {}...", path.display());

    let mut scanner = Scanner::new(path);
    let result = scanner.scan();

    let mut gitignore_count = 0;
    let mut morph_exclusion_count = 0;
    let mut generated_minified_count = 0;
    let mut safeguard_count = 0;

    for skipped in &result.skipped_files {
        let reason_lower = skipped.reason.to_lowercase();
        if reason_lower.contains(".gitignore") {
            gitignore_count += 1;
        } else if reason_lower.contains("exclusion") || reason_lower.contains("config") {
            morph_exclusion_count += 1;
        } else if reason_lower.contains("minified") || reason_lower.contains("generated") || reason_lower.contains("binary") {
            generated_minified_count += 1;
        } else {
            safeguard_count += 1;
        }
    }

    println!();
    println!("{}", terminal::label("Ignored & Skipped Files Summary"));
    println!("{}", terminal::label("".repeat(50).as_str()));
    println!("  .gitignore:                 {} file(s)", gitignore_count);
    println!("  Morph exclusions:           {} file(s)", morph_exclusion_count);
    println!("  Generated/minified/binary:  {} file(s)", generated_minified_count);
    println!("  Safeguards & other:         {} file(s)", safeguard_count);
    println!("{}", terminal::label("".repeat(50).as_str()));
    println!("  Total Ignored & Skipped:    {} file(s)", result.skipped_files.len());
    println!();

    if detailed {
        println!("{}", terminal::label("Detailed Ignored Files List"));
        println!("{}", terminal::label("".repeat(50).as_str()));
        if result.skipped_files.is_empty() {
            println!("  No skipped files found.");
        } else {
            for skipped in &result.skipped_files {
                let category = {
                    let reason_lower = skipped.reason.to_lowercase();
                    if reason_lower.contains(".gitignore") {
                        ".gitignore"
                    } else if reason_lower.contains("exclusion") || reason_lower.contains("config") {
                        "morph exclusion"
                    } else if reason_lower.contains("minified") || reason_lower.contains("generated") || reason_lower.contains("binary") {
                        "generated/minified"
                    } else {
                        "safeguard/other"
                    }
                };

                println!(
                    "  {} {} [Category: {}] (Reason: {})",
                    terminal::bullet(),
                    terminal::label(skipped.path.to_string_lossy().as_ref()),
                    category,
                    skipped.reason
                );
            }
        }
        println!();
    } else {
        println!("Use `morph ignored --detailed` to view the complete list of files and specific reasons.");
        println!();
    }

    Ok(())
}