Skip to main content

gobby_code/commands/graph/
payload.rs

1use crate::config::Context;
2use crate::graph::code_graph::{self, GraphBlastRadiusTarget, GraphPayload};
3use crate::graph::report::{ProjectGraphReport, ProjectGraphReportOptions};
4use crate::output::{self, Format};
5
6fn format_graph_payload_text(payload: &GraphPayload) -> String {
7    let mut lines = Vec::new();
8    lines.push(format!(
9        "nodes: {}, links: {}",
10        payload.node_count(),
11        payload.links.len()
12    ));
13    if let Some(center) = &payload.center {
14        lines.push(format!("center: {center}"));
15    }
16    for node in payload.nodes() {
17        match node.file_path.as_deref() {
18            Some(file) if !file.is_empty() => lines.push(format!(
19                "node {} [{}] {} {}",
20                node.id, node.node_type, node.name, file
21            )),
22            _ => {
23                lines.push(format!(
24                    "node {} [{}] {}",
25                    node.id, node.node_type, node.name
26                ));
27            }
28        }
29    }
30    for link in &payload.links {
31        lines.push(format!(
32            "link {} -[{}]-> {}",
33            link.source, link.link_type, link.target
34        ));
35    }
36    lines.join("\n")
37}
38
39fn print_graph_payload(payload: &GraphPayload, format: Format) -> anyhow::Result<()> {
40    match format {
41        Format::Json => output::print_json(payload),
42        Format::Text => output::print_text(&format_graph_payload_text(payload)),
43    }
44}
45
46pub(super) fn format_report_text(report: &ProjectGraphReport) -> &str {
47    &report.markdown
48}
49
50pub fn report(ctx: &Context, top_n: usize, format: Format) -> anyhow::Result<()> {
51    let generated_report = crate::graph::report::generate_report_with_options(
52        ctx,
53        ProjectGraphReportOptions { top_n },
54    )?;
55    match format {
56        Format::Json => output::print_json(&generated_report),
57        Format::Text => output::print_text(format_report_text(&generated_report)),
58    }
59}
60
61pub fn overview(ctx: &Context, limit: usize, format: Format) -> anyhow::Result<()> {
62    let payload = code_graph::project_overview_graph(ctx, limit)?;
63    print_graph_payload(&payload, format)
64}
65
66pub fn file(ctx: &Context, file_path: &str, format: Format) -> anyhow::Result<()> {
67    let payload = code_graph::file_graph(ctx, file_path)?;
68    print_graph_payload(&payload, format)
69}
70
71pub fn neighbors(
72    ctx: &Context,
73    symbol_id: &str,
74    limit: usize,
75    format: Format,
76) -> anyhow::Result<()> {
77    let payload = code_graph::symbol_neighbors(ctx, symbol_id, limit)?;
78    print_graph_payload(&payload, format)
79}
80
81pub fn graph_blast_radius(
82    ctx: &Context,
83    symbol_id: Option<&str>,
84    file_path: Option<&str>,
85    depth: usize,
86    limit: usize,
87    format: Format,
88) -> anyhow::Result<()> {
89    let target = match (symbol_id, file_path) {
90        (Some(symbol_id), None) => GraphBlastRadiusTarget::SymbolId(symbol_id.to_string()),
91        (None, Some(file_path)) => GraphBlastRadiusTarget::FilePath(file_path.to_string()),
92        _ => anyhow::bail!("provide exactly one of --symbol-id or --file"),
93    };
94    let payload = code_graph::blast_radius_graph(ctx, target, depth, limit)?;
95    print_graph_payload(&payload, format)
96}