Skip to main content

blast_radius/
cli.rs

1use std::path::PathBuf;
2
3use clap::error::ErrorKind;
4use clap::{Parser, ValueEnum};
5
6use crate::graph::RiskTier;
7
8#[derive(Debug, Clone, Parser)]
9#[command(name = "blast-radius")]
10#[command(
11    version,
12    about = "Estimate the transitive blast radius of frontend code changes"
13)]
14pub struct Cli {
15    #[command(subcommand)]
16    pub command: Command,
17
18    #[arg(long, global = true, default_value = ".")]
19    pub repo_root: PathBuf,
20
21    #[arg(long, global = true, value_enum, default_value_t = OutputFormat::Tree)]
22    pub format: OutputFormat,
23
24    #[arg(long, global = true)]
25    pub output: Option<PathBuf>,
26
27    /// Show the full cascade tree and analyzer internals in tree output.
28    #[arg(long, short = 'v', global = true, default_value_t = false)]
29    pub verbose: bool,
30
31    /// Include grouped unresolved-import diagnostics in warnings.
32    #[arg(long, global = true, default_value_t = false)]
33    pub explain_unresolved: bool,
34
35    /// Exit non-zero (code 2) when more than this many downstream files are
36    /// impacted (the changed files themselves are not counted).
37    #[arg(long, global = true)]
38    pub fail_threshold: Option<usize>,
39
40    /// Exit non-zero (code 2) when the risk verdict is at or above this tier.
41    #[arg(long, global = true, value_enum)]
42    pub fail_on_risk: Option<RiskTier>,
43}
44
45#[derive(Debug, Clone, Parser)]
46pub enum Command {
47    /// Analyze downstream impact from a named export.
48    Export { file: PathBuf, export_name: String },
49    /// Analyze downstream impact from every export of a file.
50    File { file: PathBuf },
51    /// Blast radius for several files at once (e.g. a pre-commit hook over
52    /// staged files). Pass one or more paths.
53    Files {
54        #[arg(required = true, num_args = 1..)]
55        files: Vec<PathBuf>,
56    },
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
60pub enum OutputFormat {
61    Tree,
62    Json,
63    Mermaid,
64    Dot,
65}
66
67impl Cli {
68    /// Exit code 2 is reserved for tripped risk gates, so usage errors exit
69    /// with 64 (EX_USAGE) instead of clap's default 2. `--help`/`--version`
70    /// still exit 0.
71    pub fn parse_args() -> Self {
72        match Self::try_parse() {
73            Ok(cli) => cli,
74            Err(error) => {
75                let code = match error.kind() {
76                    ErrorKind::DisplayHelp | ErrorKind::DisplayVersion => 0,
77                    _ => 64,
78                };
79                let _ = error.print();
80                std::process::exit(code);
81            }
82        }
83    }
84}