impl DeterministicMermaidEngine {
#[must_use]
pub fn generate_codebase_modules_mmd(
&self,
graph: &SimpleStableGraph<ModuleNode, EdgeType>,
) -> String {
let pagerank = self.compute_pagerank(graph, 0.85, self.pagerank_iterations);
let quantized: BTreeMap<NodeIndex, u32> = pagerank
.into_iter()
.map(|(idx, score)| (idx, (score * self.quantization_factor as f32) as u32))
.collect();
let mut mermaid = String::from("graph TD\n");
let mut nodes: Vec<_> = graph.node_indices().collect();
nodes.sort_by_key(|&idx| {
(
std::cmp::Reverse(quantized.get(&idx).copied().unwrap_or(0)),
graph[idx].name.clone(),
)
});
for idx in nodes {
let node = &graph[idx];
let sanitized_id = self.sanitize_id(&node.name);
let escaped_label = self.escape_mermaid_label(&node.name);
writeln!(&mut mermaid, " {sanitized_id}[{escaped_label}]")
.expect("writing to String never fails");
}
mermaid.push('\n');
let mut edges: Vec<_> = graph.edge_references().collect();
edges.sort_by_key(|e| {
(
graph[e.source()].name.clone(),
graph[e.target()].name.clone(),
)
});
for edge in edges {
let arrow = self.get_edge_arrow(edge.weight());
writeln!(
&mut mermaid,
" {} {} {}",
self.sanitize_id(&graph[edge.source()].name),
arrow,
self.sanitize_id(&graph[edge.target()].name)
)
.expect("writing to String never fails");
}
mermaid
}
#[must_use]
pub fn generate_service_interactions_mmd(
&self,
graph: &SimpleStableGraph<ModuleNode, EdgeType>,
_metrics: &ProjectMetrics,
) -> String {
let service_graph = self.filter_to_services(graph);
let complexity_scores: BTreeMap<NodeIndex, ComplexityBucket> = service_graph
.node_indices()
.map(|idx| {
let node = &service_graph[idx];
let score = node.metrics.complexity;
let bucket = match score {
0..=10 => ComplexityBucket::Low,
11..=20 => ComplexityBucket::Medium,
_ => ComplexityBucket::High,
};
(idx, bucket)
})
.collect();
let mut mermaid = String::from("graph TD\n");
let mut nodes: Vec<_> = service_graph.node_indices().collect();
nodes.sort_by_key(|&idx| &service_graph[idx].name);
for idx in nodes {
let node = &service_graph[idx];
let sanitized_id = self.sanitize_id(&node.name);
let escaped_label = self.escape_mermaid_label(&node.name);
writeln!(&mut mermaid, " {sanitized_id}[{escaped_label}]")
.expect("writing to String never fails");
}
mermaid.push('\n');
let mut edges: Vec<_> = service_graph.edge_references().collect();
edges.sort_by_key(|e| {
(
service_graph[e.source()].name.clone(),
service_graph[e.target()].name.clone(),
)
});
for edge in edges {
let arrow = match edge.weight() {
EdgeType::Calls => "-->",
EdgeType::Imports => "---",
EdgeType::Inherits => "-.->",
EdgeType::Implements => "-.->",
EdgeType::Uses => "---",
};
writeln!(
&mut mermaid,
" {} {} {}",
self.sanitize_id(&service_graph[edge.source()].name),
arrow,
self.sanitize_id(&service_graph[edge.target()].name)
)
.expect("writing to String never fails");
}
mermaid.push('\n');
for (idx, bucket) in &complexity_scores {
let color = match bucket {
ComplexityBucket::Low => "#90EE90",
ComplexityBucket::Medium => "#FFA500",
ComplexityBucket::High => "#FF6347",
};
writeln!(
&mut mermaid,
" style {} fill:{},stroke-width:2px",
self.sanitize_id(&service_graph[*idx].name),
color
)
.expect("writing to String never fails");
}
mermaid
}
}