use std::path::PathBuf;
use anyhow::{Context, Result};
use clap::Parser;
use cviz::output;
use cviz::output::{DetailLevel, Direction, OutputFormat};
#[derive(Parser, Debug)]
#[command(name = "cviz")]
#[command(about = "Visualize WebAssembly component composition")]
#[command(version = concat!(env!("CARGO_PKG_VERSION"), " (", env!("CVIZ_GIT_SHA"), ") with wasmparser ", env!("WASMPARSER_VERSION")))]
struct Args {
#[arg(value_name = "FILE")]
file: PathBuf,
#[arg(short, long, default_value = "ascii", value_parser = parse_format)]
format: OutputFormat,
#[arg(short, long, default_value = "lr", value_parser = parse_direction)]
direction: Direction,
#[arg(short = 'l', long, default_value = "handler-chain", value_parser = parse_detail)]
detail: DetailLevel,
#[arg(short = 't', long, default_value = "true")]
types: bool,
#[arg(short, long)]
output: Option<PathBuf>,
}
fn parse_format(s: &str) -> Result<OutputFormat, String> {
s.parse()
}
fn parse_direction(s: &str) -> Result<Direction, String> {
s.parse()
}
fn parse_detail(s: &str) -> Result<DetailLevel, String> {
s.parse()
}
fn main() -> Result<()> {
let args = Args::parse();
let bytes = std::fs::read(&args.file)
.with_context(|| format!("Failed to read file: {}", args.file.display()))?;
let graph = cviz::parse::component::parse_component(&bytes)
.with_context(|| format!("Failed to parse component: {}", args.file.display()))?;
let diagram = match args.format {
OutputFormat::Ascii => output::ascii::generate_ascii(&graph, args.detail, args.types),
OutputFormat::Mermaid => {
output::mermaid::generate_mermaid(&graph, args.detail, args.direction, args.types)
}
OutputFormat::Json => output::json::generate_json(&graph, false)?, OutputFormat::JsonPretty => output::json::generate_json(&graph, true)?, };
if let Some(output_path) = args.output {
std::fs::write(&output_path, &diagram)
.with_context(|| format!("Failed to write output: {}", output_path.display()))?;
eprintln!("Diagram written to: {}", output_path.display());
} else {
println!("{}", diagram);
}
Ok(())
}