feat: add rendering-primitives crate, share non_import_rels across renderers

This commit is contained in:
2026-06-17 13:26:02 +02:00
parent 7487cea0e2
commit 97c7268661
12 changed files with 100 additions and 39 deletions

View File

@@ -6,6 +6,7 @@ publish = false
[dependencies]
archlens-domain.workspace = true
archlens-rendering-primitives.workspace = true
[dev-dependencies]
tempfile.workspace = true

View File

@@ -1,6 +1,7 @@
use archlens_domain::{
CodeGraph, DiagramLevel, DomainError, RenderOutput, RenderedFile, ports::DiagramRenderer,
};
use archlens_rendering_primitives::{non_import_rels, sanitize_identifier};
pub struct D2Renderer {
level: DiagramLevel,
@@ -36,20 +37,16 @@ impl DiagramRenderer for D2Renderer {
}
}
fn sanitize(name: &str) -> String {
name.replace("::", "_").replace(['-', ' '], "_")
}
fn render_type(graph: &CodeGraph) -> String {
let mut lines = Vec::new();
let (by_module, ungrouped) = graph.elements_by_module();
// Grouped by module
for (module, elements) in &by_module {
let mod_id = sanitize(module);
let mod_id = sanitize_identifier(module);
lines.push(format!("{mod_id}: {{"));
for el in elements {
let el_id = sanitize(el.name());
let el_id = sanitize_identifier(el.name());
lines.push(format!(" {el_id}: {{"));
lines.push(" shape: class".to_string());
for field in el.fields() {
@@ -69,21 +66,21 @@ fn render_type(graph: &CodeGraph) -> String {
// Ungrouped elements
for el in &ungrouped {
let el_id = sanitize(el.name());
let el_id = sanitize_identifier(el.name());
lines.push(format!("{el_id}: {{"));
lines.push(" shape: class".to_string());
lines.push("}".to_string());
}
// Relationships
for rel in graph.relationships() {
for rel in non_import_rels(graph.relationships()) {
use archlens_domain::RelationshipKind;
let src = sanitize(rel.source());
let tgt = sanitize(rel.target());
let src = sanitize_identifier(rel.source());
let tgt = sanitize_identifier(rel.target());
let arrow = match rel.kind() {
RelationshipKind::Inheritance => format!("{src} -> {tgt}: {{style.stroke-dash: 0}}"),
RelationshipKind::Composition => format!("{src} -> {tgt}"),
RelationshipKind::Import => continue,
RelationshipKind::Import => unreachable!("imports filtered by non_import_rels"),
};
lines.push(arrow);
}
@@ -95,47 +92,43 @@ fn render_module(graph: &CodeGraph) -> String {
let mut lines = Vec::new();
for module in graph.modules() {
let id = sanitize(module.as_str());
let id = sanitize_identifier(module.as_str());
lines.push(format!("{id}: {}", module.as_str()));
}
for (src, tgt) in graph.module_edges().keys() {
lines.push(format!("{} -> {}", sanitize(src), sanitize(tgt)));
lines.push(format!("{} -> {}", sanitize_identifier(src), sanitize_identifier(tgt)));
}
lines.join("\n")
}
fn render_project(graph: &CodeGraph) -> String {
use archlens_domain::RelationshipKind;
use std::collections::HashMap;
let mut lines = Vec::new();
let (by_module, ungrouped) = graph.elements_by_module();
for (module, elements) in &by_module {
let mod_id = sanitize(module);
let mod_id = sanitize_identifier(module);
lines.push(format!("{mod_id}: {{"));
for el in elements {
lines.push(format!(" {}: {}", sanitize(el.name()), el.name()));
lines.push(format!(" {}: {}", sanitize_identifier(el.name()), el.name()));
}
lines.push("}".to_string());
}
for el in &ungrouped {
lines.push(format!("{}: {}", sanitize(el.name()), el.name()));
lines.push(format!("{}: {}", sanitize_identifier(el.name()), el.name()));
}
let name_to_id: HashMap<&str, String> = graph
.elements()
.iter()
.map(|e| (e.name(), sanitize(e.name())))
.map(|e| (e.name(), sanitize_identifier(e.name())))
.collect();
for rel in graph.relationships() {
if rel.kind() == RelationshipKind::Import {
continue;
}
for rel in non_import_rels(graph.relationships()) {
if let (Some(src), Some(tgt)) = (name_to_id.get(rel.source()), name_to_id.get(rel.target()))
{
lines.push(format!("{src} -> {tgt}"));