refactor: extract module_edges() to CodeGraph domain — removes duplication from Mermaid and D2 renderers
Some checks failed
CI / Check / Test (push) Failing after 42s
Architecture Docs / Generate diagrams (push) Successful in 3m20s

This commit is contained in:
2026-06-17 10:48:59 +02:00
parent 11a5656efc
commit 1447dc74bb
4 changed files with 133 additions and 117 deletions

View File

@@ -278,4 +278,72 @@ impl CodeGraph {
relationships: filtered_relationships,
}
}
/// Compute module-to-module edges with relationship counts.
///
/// Handles three cases:
/// - Direct module-name edges injected by `merge_project_deps_as_module_edges`
/// - Type-level composition/inheritance relationships resolved to their modules
/// - Import relationships resolved via file-stem → module mapping
pub fn module_edges(&self) -> HashMap<(String, String), usize> {
let mut name_to_module: HashMap<&str, &str> = HashMap::new();
let mut file_to_module: HashMap<String, String> = HashMap::new();
let mut modules: HashSet<String> = HashSet::new();
for el in &self.elements {
if let Some(m) = el.module() {
modules.insert(m.as_str().to_string());
name_to_module.insert(el.qualified_name(), m.as_str());
name_to_module.insert(el.name(), m.as_str());
let file_stem = std::path::Path::new(el.file_path().as_str())
.file_stem()
.and_then(|s| s.to_str())
.unwrap_or_default()
.to_string();
if !file_stem.is_empty() {
file_to_module.insert(file_stem, m.as_str().to_string());
}
}
}
let mut edges: HashMap<(String, String), usize> = HashMap::new();
for rel in &self.relationships {
match rel.kind() {
RelationshipKind::Import => {
let source_mod = file_to_module.get(rel.source());
let target_top = rel.target().split('.').next().unwrap_or("");
let target_mod = ModuleName::capitalize(target_top);
if let Some(src) = source_mod
&& modules.contains(&target_mod)
&& *src != target_mod
{
*edges.entry((src.clone(), target_mod)).or_insert(0) += 1;
}
}
_ => {
// Direct module-to-module edge (injected by merge_project_deps)
if modules.contains(rel.source())
&& modules.contains(rel.target())
&& rel.source() != rel.target()
{
*edges
.entry((rel.source().to_string(), rel.target().to_string()))
.or_insert(0) += 1;
continue;
}
let src_mod = name_to_module.get(rel.source()).copied();
let tgt_mod = name_to_module.get(rel.target()).copied();
if let (Some(s), Some(t)) = (src_mod, tgt_mod)
&& s != t
{
*edges.entry((s.to_string(), t.to_string())).or_insert(0) += 1;
}
}
}
}
edges
}
}