use std::collections::HashMap; use serde::Serialize; use archlens_domain::{ CodeGraph, DomainError, RelationshipKind, RenderOutput, RenderedFile, ports::DiagramRenderer, }; pub struct HtmlRenderer; impl Default for HtmlRenderer { fn default() -> Self { Self::new() } } impl HtmlRenderer { pub fn new() -> Self { Self } } #[derive(Serialize)] struct GraphData { nodes: Vec, edges: Vec, } #[derive(Serialize)] struct NodeData { id: String, label: String, module: String, kind: String, fields: Vec, methods: Vec, } #[derive(Serialize)] struct EdgeData { source: String, target: String, kind: String, } impl DiagramRenderer for HtmlRenderer { fn render(&self, graph: &CodeGraph) -> Result { // Build graph data let mut id_map: HashMap = HashMap::new(); let mut nodes = Vec::new(); for (i, el) in graph.elements().iter().enumerate() { let id = format!("n{i}"); id_map.insert(el.qualified_name().to_string(), id.clone()); id_map.insert(el.name().to_string(), id.clone()); nodes.push(NodeData { id, label: el.name().to_string(), module: el .module() .map(|m| m.as_str().to_string()) .unwrap_or_default(), kind: format!("{:?}", el.kind()), fields: el.fields().to_vec(), methods: el.methods().to_vec(), }); } let edges = graph .relationships() .iter() .filter(|r| r.kind() != RelationshipKind::Import) .filter_map(|r| { let src = id_map.get(r.source())?; let tgt = id_map.get(r.target())?; Some(EdgeData { source: src.clone(), target: tgt.clone(), kind: format!("{:?}", r.kind()), }) }) .collect(); let data = GraphData { nodes, edges }; let json = serde_json::to_string(&data).map_err(|e| DomainError::ConfigError(e.to_string()))?; let html = build_html(&json); let file = RenderedFile::new("diagram.html", &html)?; Ok(RenderOutput::single(file)) } } fn build_html(graph_json: &str) -> String { format!( r#" Architecture Diagram
"#, graph_json = graph_json ) }