blast_radius/report/
mod.rs1use anyhow::Result;
2
3use crate::cli::OutputFormat;
4use crate::graph::{AnalysisMode, AnalysisResult};
5
6mod graph_formats;
7use graph_formats::{render_dot, render_mermaid};
8
9mod theme;
10
11mod tree;
12use tree::render_tree;
13
14pub fn render(
15 format: &OutputFormat,
16 result: &AnalysisResult,
17 verbose: bool,
18 color: bool,
19) -> Result<String> {
20 let rendered = match format {
21 OutputFormat::Tree if matches!(result.mode, AnalysisMode::Graph) => {
24 render_graph_edge_list(result)
25 }
26 OutputFormat::Tree => render_tree(result, verbose, color),
27 OutputFormat::Json => serde_json::to_string_pretty(result)?,
28 OutputFormat::Mermaid => render_mermaid(result),
29 OutputFormat::Dot => render_dot(result),
30 };
31
32 Ok(rendered)
33}
34
35fn render_graph_edge_list(result: &AnalysisResult) -> String {
38 use std::collections::BTreeMap;
39
40 let labels: BTreeMap<&str, &str> = result
41 .nodes
42 .iter()
43 .map(|node| (node.id.as_str(), node.label.as_str()))
44 .collect();
45 let mut lines: Vec<String> = result
46 .edges
47 .iter()
48 .map(|edge| {
49 let importer = labels.get(edge.to.as_str()).copied().unwrap_or(&edge.to);
50 let importee = labels
51 .get(edge.from.as_str())
52 .copied()
53 .unwrap_or(&edge.from);
54 format!("{importer} -> {importee}")
55 })
56 .collect();
57 lines.sort();
58 if lines.is_empty() {
59 format!("{} files, no import edges", result.source_file_count)
60 } else {
61 lines.join("\n")
62 }
63}