cargo-whys 0.1.0

A cargo subcommand that explains why dependencies are in your tree
Documentation
use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
use std::path::PathBuf;

mod analyzer;
mod dependency_graph;
mod scanner;

use analyzer::DependencyAnalyzer;

#[derive(Parser)]
#[command(name = "cargo-why")]
#[command(bin_name = "cargo")]
#[command(version, about = "Explains why dependencies are in your tree", long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    #[command(about = "Explains why dependencies are in your tree")]
    Why {
        #[arg(help = "The dependency name to analyze")]
        dependency: String,

        #[arg(
            long,
            help = "Show where in the codebase the dependency is used"
        )]
        where_used: bool,

        #[arg(
            long,
            default_value = ".",
            help = "Path to the Cargo project directory"
        )]
        manifest_path: PathBuf,

        #[arg(
            long,
            help = "Show all versions of the dependency in the tree"
        )]
        all_versions: bool,

        #[arg(long, help = "Output in JSON format")]
        json: bool,
    },
}

fn main() -> Result<()> {
    let cli = Cli::parse();

    match cli.command {
        Commands::Why {
            dependency,
            where_used,
            manifest_path,
            all_versions,
            json,
        } => {
            let analyzer = DependencyAnalyzer::new(manifest_path)
                .context("Failed to initialize dependency analyzer")?;

            let result = analyzer
                .analyze(&dependency, where_used, all_versions)
                .context("Failed to analyze dependency")?;

            if json {
                println!("{}", serde_json::to_string_pretty(&result)?);
            } else {
                result.print();
            }

            Ok(())
        }
    }
}