dgmod/
mermaid.rs

1//! Mermaid diagram output formatting
2
3use std::fmt::Write;
4
5use crate::graph::{EdgeKind, ModuleGraph};
6
7/// Sanitize a module path for use as a Mermaid node ID
8/// Replaces :: with _ since Mermaid doesn't allow :: in IDs
9fn sanitize_id(path: &str) -> String {
10    path.replace("::", "_")
11}
12
13/// Emit node declarations for all modules
14fn emit_nodes(graph: &ModuleGraph, output: &mut String) {
15    let mut paths: Vec<_> = graph.modules().map(|m| m.path.as_str()).collect();
16    paths.sort_unstable();
17
18    for path in paths {
19        let id = sanitize_id(path);
20        let _ = writeln!(output, "    {id}[\"{path}\"]");
21    }
22}
23
24/// Emit edge declarations
25fn emit_edges(graph: &ModuleGraph, output: &mut String) {
26    let mut edges: Vec<_> = graph
27        .edges()
28        .map(|(from, to, kind)| (from.as_str(), to.as_str(), kind))
29        .collect();
30    edges.sort_unstable();
31
32    for (from, to, kind) in edges {
33        let from_id = sanitize_id(from);
34        let to_id = sanitize_id(to);
35        // Use solid arrow for mod declarations, dashed for use imports
36        let arrow = match kind {
37            EdgeKind::ModDeclaration => "-->",
38            EdgeKind::UseImport => "-.->",
39        };
40        let _ = writeln!(output, "    {from_id} {arrow} {to_id}");
41    }
42}
43
44impl ModuleGraph {
45    /// Convert the graph to Mermaid flowchart syntax
46    #[must_use]
47    pub fn to_mermaid(&self) -> String {
48        let mut output = String::from("flowchart TD\n");
49
50        emit_nodes(self, &mut output);
51        output.push('\n');
52        emit_edges(self, &mut output);
53
54        output
55    }
56}