gobby_code/commands/graph/
payload.rs1use 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}