1use crate::{Error, ParseMetadata, Result};
2use serde_json::Value;
3
4pub type DiagramSemanticParser = fn(code: &str, meta: &ParseMetadata) -> Result<Value>;
5pub type RenderSemanticParser = fn(code: &str, meta: &ParseMetadata) -> Result<RenderSemanticModel>;
6
7#[derive(Debug, Clone, Default)]
8pub struct DiagramRegistry {
9 parsers: std::collections::HashMap<&'static str, DiagramSemanticParser>,
10}
11
12impl DiagramRegistry {
13 pub fn new() -> Self {
14 Self::default()
15 }
16
17 pub fn insert(&mut self, diagram_type: &'static str, parser: DiagramSemanticParser) {
18 self.parsers.insert(diagram_type, parser);
19 }
20
21 pub fn get(&self, diagram_type: &str) -> Option<DiagramSemanticParser> {
22 self.parsers.get(diagram_type).copied()
23 }
24
25 pub fn default_mermaid_11_12_2() -> Self {
26 let mut reg = Self::new();
27
28 reg.insert("error", crate::diagrams::error_diagram::parse_error);
29
30 reg.insert("flowchart-v2", crate::diagrams::flowchart::parse_flowchart);
31 reg.insert("flowchart", crate::diagrams::flowchart::parse_flowchart);
32 reg.insert("flowchart-elk", crate::diagrams::flowchart::parse_flowchart);
33
34 reg.insert("info", crate::diagrams::info::parse_info);
35 reg.insert("pie", crate::diagrams::pie::parse_pie);
36 reg.insert("c4", crate::diagrams::c4::parse_c4);
37 reg.insert(
38 "requirement",
39 crate::diagrams::requirement::parse_requirement,
40 );
41 reg.insert("sequence", crate::diagrams::sequence::parse_sequence);
42 reg.insert("zenuml", crate::diagrams::zenuml::parse_zenuml);
43
44 reg.insert("classDiagram", crate::diagrams::class::parse_class);
45 reg.insert("class", crate::diagrams::class::parse_class);
46
47 reg.insert("er", crate::diagrams::er::parse_er);
48 reg.insert("erDiagram", crate::diagrams::er::parse_er);
49
50 reg.insert("stateDiagram", crate::diagrams::state::parse_state);
51 reg.insert("state", crate::diagrams::state::parse_state);
52
53 reg.insert("mindmap", crate::diagrams::mindmap::parse_mindmap);
54 reg.insert("gantt", crate::diagrams::gantt::parse_gantt);
55 reg.insert("timeline", crate::diagrams::timeline::parse_timeline);
56 reg.insert("journey", crate::diagrams::journey::parse_journey);
57 reg.insert("kanban", crate::diagrams::kanban::parse_kanban);
58 reg.insert(
59 "architecture",
60 crate::diagrams::architecture::parse_architecture,
61 );
62 reg.insert("block", crate::diagrams::block::parse_block);
63 reg.insert("gitGraph", crate::diagrams::git_graph::parse_git_graph);
64 reg.insert(
65 "quadrantChart",
66 crate::diagrams::quadrant_chart::parse_quadrant_chart,
67 );
68 reg.insert("packet", crate::diagrams::packet::parse_packet);
69 reg.insert("radar", crate::diagrams::radar::parse_radar);
70 reg.insert("treemap", crate::diagrams::treemap::parse_treemap);
71 reg.insert("sankey", crate::diagrams::sankey::parse_sankey);
72 reg.insert("xychart", crate::diagrams::xychart::parse_xychart);
73
74 reg
75 }
76}
77
78#[derive(Debug, Clone)]
79pub struct ParsedDiagram {
80 pub meta: ParseMetadata,
81 pub model: Value,
82}
83
84#[derive(Debug, Clone)]
85pub enum RenderSemanticModel {
86 Json(Value),
87 Mindmap(crate::diagrams::mindmap::MindmapDiagramRenderModel),
88 State(crate::diagrams::state::StateDiagramRenderModel),
89 Sequence(crate::diagrams::sequence::SequenceDiagramRenderModel),
90 Flowchart(crate::diagrams::flowchart::FlowchartV2Model),
91 Architecture(crate::diagrams::architecture::ArchitectureDiagramRenderModel),
92 Class(crate::models::class_diagram::ClassDiagram),
93 C4(crate::diagrams::c4::C4DiagramRenderModel),
94 Kanban(crate::diagrams::kanban::KanbanDiagramRenderModel),
95 Gantt(crate::diagrams::gantt::GanttDiagramRenderModel),
96 Pie(crate::diagrams::pie::PieDiagramRenderModel),
97 Packet(crate::diagrams::packet::PacketDiagramRenderModel),
98 Timeline(crate::diagrams::timeline::TimelineDiagramRenderModel),
99 Journey(crate::diagrams::journey::JourneyDiagramRenderModel),
100 Requirement(crate::diagrams::requirement::RequirementDiagramRenderModel),
101 Sankey(crate::diagrams::sankey::SankeyDiagramRenderModel),
102 Radar(crate::diagrams::radar::RadarDiagramRenderModel),
103 Info(crate::diagrams::info::InfoDiagramRenderModel),
104 Treemap(crate::diagrams::treemap::TreemapDiagramRenderModel),
105 Block(crate::diagrams::block::BlockDiagramRenderModel),
106 Er(crate::diagrams::er::ErDiagramRenderModel),
107 QuadrantChart(crate::diagrams::quadrant_chart::QuadrantChartRenderModel),
108 XyChart(crate::diagrams::xychart::XyChartDiagramRenderModel),
109 GitGraph(crate::diagrams::git_graph::GitGraphRenderModel),
110}
111
112impl RenderSemanticModel {
113 pub fn kind(&self) -> &'static str {
114 match self {
115 Self::Json(_) => "json",
116 Self::Mindmap(_) => "mindmap",
117 Self::State(_) => "state",
118 Self::Sequence(_) => "sequence",
119 Self::Flowchart(_) => "flowchart",
120 Self::Architecture(_) => "architecture",
121 Self::Class(_) => "class",
122 Self::C4(_) => "c4",
123 Self::Kanban(_) => "kanban",
124 Self::Gantt(_) => "gantt",
125 Self::Pie(_) => "pie",
126 Self::Packet(_) => "packet",
127 Self::Timeline(_) => "timeline",
128 Self::Journey(_) => "journey",
129 Self::Requirement(_) => "requirement",
130 Self::Sankey(_) => "sankey",
131 Self::Radar(_) => "radar",
132 Self::Info(_) => "info",
133 Self::Treemap(_) => "treemap",
134 Self::Block(_) => "block",
135 Self::Er(_) => "er",
136 Self::QuadrantChart(_) => "quadrantChart",
137 Self::XyChart(_) => "xychart",
138 Self::GitGraph(_) => "gitGraph",
139 }
140 }
141
142 pub fn supports_diagram_type(&self, diagram_type: &str) -> bool {
143 match self {
144 Self::Json(_) => true,
145 Self::Mindmap(_) => diagram_type == "mindmap",
146 Self::State(_) => matches!(diagram_type, "stateDiagram" | "state"),
147 Self::Sequence(_) => matches!(diagram_type, "sequence" | "zenuml"),
148 Self::Flowchart(_) => {
149 matches!(diagram_type, "flowchart-v2" | "flowchart" | "flowchart-elk")
150 }
151 Self::Architecture(_) => diagram_type == "architecture",
152 Self::Class(_) => matches!(diagram_type, "classDiagram" | "class"),
153 Self::C4(_) => diagram_type == "c4",
154 Self::Kanban(_) => diagram_type == "kanban",
155 Self::Gantt(_) => diagram_type == "gantt",
156 Self::Pie(_) => diagram_type == "pie",
157 Self::Packet(_) => diagram_type == "packet",
158 Self::Timeline(_) => diagram_type == "timeline",
159 Self::Journey(_) => diagram_type == "journey",
160 Self::Requirement(_) => diagram_type == "requirement",
161 Self::Sankey(_) => diagram_type == "sankey",
162 Self::Radar(_) => diagram_type == "radar",
163 Self::Info(_) => diagram_type == "info",
164 Self::Treemap(_) => diagram_type == "treemap",
165 Self::Block(_) => diagram_type == "block",
166 Self::Er(_) => matches!(diagram_type, "er" | "erDiagram"),
167 Self::QuadrantChart(_) => diagram_type == "quadrantChart",
168 Self::XyChart(_) => diagram_type == "xychart",
169 Self::GitGraph(_) => diagram_type == "gitGraph",
170 }
171 }
172}
173
174#[derive(Debug, Clone, Default)]
175pub struct RenderDiagramRegistry {
176 parsers: std::collections::HashMap<&'static str, RenderSemanticParser>,
177}
178
179impl RenderDiagramRegistry {
180 pub fn new() -> Self {
181 Self::default()
182 }
183
184 pub fn insert(&mut self, diagram_type: &'static str, parser: RenderSemanticParser) {
185 self.parsers.insert(diagram_type, parser);
186 }
187
188 pub fn get(&self, diagram_type: &str) -> Option<RenderSemanticParser> {
189 self.parsers.get(diagram_type).copied()
190 }
191
192 pub fn default_mermaid_11_12_2() -> Self {
193 let mut reg = Self::new();
194
195 reg.insert("mindmap", |code, meta| {
196 crate::diagrams::mindmap::parse_mindmap_model_for_render(code, meta)
197 .map(RenderSemanticModel::Mindmap)
198 });
199 reg.insert("stateDiagram", |code, meta| {
200 crate::diagrams::state::parse_state_model_for_render(code, meta)
201 .map(RenderSemanticModel::State)
202 });
203 reg.insert("state", |code, meta| {
204 crate::diagrams::state::parse_state_model_for_render(code, meta)
205 .map(RenderSemanticModel::State)
206 });
207 reg.insert("zenuml", |code, meta| {
208 crate::diagrams::zenuml::parse_zenuml_model_for_render(code, meta)
209 .map(RenderSemanticModel::Sequence)
210 });
211 reg.insert("sequence", |code, meta| {
212 crate::diagrams::sequence::parse_sequence_model_for_render(code, meta)
213 .map(RenderSemanticModel::Sequence)
214 });
215 reg.insert("flowchart-v2", |code, meta| {
216 crate::diagrams::flowchart::parse_flowchart_model_for_render(code, meta)
217 .map(RenderSemanticModel::Flowchart)
218 });
219 reg.insert("flowchart", |code, meta| {
220 crate::diagrams::flowchart::parse_flowchart_model_for_render(code, meta)
221 .map(RenderSemanticModel::Flowchart)
222 });
223 reg.insert("flowchart-elk", |code, meta| {
224 crate::diagrams::flowchart::parse_flowchart_model_for_render(code, meta)
225 .map(RenderSemanticModel::Flowchart)
226 });
227 reg.insert("classDiagram", |code, meta| {
228 crate::diagrams::class::parse_class_typed(code, meta).map(RenderSemanticModel::Class)
229 });
230 reg.insert("class", |code, meta| {
231 crate::diagrams::class::parse_class_typed(code, meta).map(RenderSemanticModel::Class)
232 });
233 reg.insert("c4", |code, meta| {
234 crate::diagrams::c4::parse_c4_model_for_render(code, meta).map(RenderSemanticModel::C4)
235 });
236 reg.insert("architecture", |code, meta| {
237 crate::diagrams::architecture::parse_architecture_model_for_render(code, meta)
238 .map(RenderSemanticModel::Architecture)
239 });
240 reg.insert("kanban", |code, meta| {
241 crate::diagrams::kanban::parse_kanban_model_for_render(code, meta)
242 .map(RenderSemanticModel::Kanban)
243 });
244 reg.insert("gantt", |code, meta| {
245 crate::diagrams::gantt::parse_gantt_model_for_render(code, meta)
246 .map(RenderSemanticModel::Gantt)
247 });
248 reg.insert("pie", |code, meta| {
249 crate::diagrams::pie::parse_pie_model_for_render(code, meta)
250 .map(RenderSemanticModel::Pie)
251 });
252 reg.insert("packet", |code, meta| {
253 crate::diagrams::packet::parse_packet_model_for_render(code, meta)
254 .map(RenderSemanticModel::Packet)
255 });
256 reg.insert("timeline", |code, meta| {
257 crate::diagrams::timeline::parse_timeline_model_for_render(code, meta)
258 .map(RenderSemanticModel::Timeline)
259 });
260 reg.insert("journey", |code, meta| {
261 crate::diagrams::journey::parse_journey_model_for_render(code, meta)
262 .map(RenderSemanticModel::Journey)
263 });
264 reg.insert("requirement", |code, meta| {
265 crate::diagrams::requirement::parse_requirement_model_for_render(code, meta)
266 .map(RenderSemanticModel::Requirement)
267 });
268 reg.insert("sankey", |code, meta| {
269 crate::diagrams::sankey::parse_sankey_model_for_render(code, meta)
270 .map(RenderSemanticModel::Sankey)
271 });
272 reg.insert("radar", |code, meta| {
273 crate::diagrams::radar::parse_radar_model_for_render(code, meta)
274 .map(RenderSemanticModel::Radar)
275 });
276 reg.insert("info", |code, meta| {
277 crate::diagrams::info::parse_info_model_for_render(code, meta)
278 .map(RenderSemanticModel::Info)
279 });
280 reg.insert("treemap", |code, meta| {
281 crate::diagrams::treemap::parse_treemap_model_for_render(code, meta)
282 .map(RenderSemanticModel::Treemap)
283 });
284 reg.insert("block", |code, meta| {
285 crate::diagrams::block::parse_block_model_for_render(code, meta)
286 .map(RenderSemanticModel::Block)
287 });
288 reg.insert("er", |code, meta| {
289 crate::diagrams::er::parse_er_model_for_render(code, meta).map(RenderSemanticModel::Er)
290 });
291 reg.insert("erDiagram", |code, meta| {
292 crate::diagrams::er::parse_er_model_for_render(code, meta).map(RenderSemanticModel::Er)
293 });
294 reg.insert("quadrantChart", |code, meta| {
295 crate::diagrams::quadrant_chart::parse_quadrant_chart_model_for_render(code, meta)
296 .map(RenderSemanticModel::QuadrantChart)
297 });
298 reg.insert("xychart", |code, meta| {
299 crate::diagrams::xychart::parse_xychart_model_for_render(code, meta)
300 .map(RenderSemanticModel::XyChart)
301 });
302 reg.insert("gitGraph", |code, meta| {
303 crate::diagrams::git_graph::parse_git_graph_model_for_render(code, meta)
304 .map(RenderSemanticModel::GitGraph)
305 });
306
307 reg
308 }
309}
310
311#[derive(Debug, Clone)]
312pub struct ParsedDiagramRender {
313 pub meta: ParseMetadata,
314 pub model: RenderSemanticModel,
315}
316
317pub fn parse_or_unsupported(
318 registry: &DiagramRegistry,
319 diagram_type: &str,
320 code: &str,
321 meta: &ParseMetadata,
322) -> Result<Value> {
323 let Some(parser) = registry.get(diagram_type) else {
324 return Err(Error::UnsupportedDiagram {
325 diagram_type: diagram_type.to_string(),
326 });
327 };
328 parser(code, meta)
329}