1use crate::{Error, MermaidConfig, ParseMetadata, Result};
2use serde_json::Value;
3
4pub type DiagramSemanticParser = fn(code: &str, meta: &ParseMetadata) -> Result<Value>;
6
7pub type RenderSemanticParser = fn(code: &str, meta: &ParseMetadata) -> Result<RenderSemanticModel>;
9
10#[derive(Debug, Clone, Default)]
12pub struct DiagramRegistry {
13 parsers: std::collections::HashMap<&'static str, DiagramSemanticParser>,
14}
15
16impl DiagramRegistry {
17 pub fn new() -> Self {
19 Self::default()
20 }
21
22 pub fn insert(&mut self, diagram_type: &'static str, parser: DiagramSemanticParser) {
24 self.parsers.insert(diagram_type, parser);
25 }
26
27 pub fn get(&self, diagram_type: &str) -> Option<DiagramSemanticParser> {
29 self.parsers.get(diagram_type).copied()
30 }
31
32 pub fn for_pinned_mermaid_baseline() -> Self {
34 let mut reg = Self::new();
35 for fact in crate::family::semantic_parser_facts() {
36 reg.insert(fact.id, fact.parser);
37 }
38
39 reg
40 }
41
42 #[cfg(test)]
43 pub(crate) fn parser_ids(&self) -> impl Iterator<Item = &'static str> + '_ {
44 self.parsers.keys().copied()
45 }
46}
47
48#[derive(Debug, Clone)]
50pub struct ParsedDiagram {
51 pub meta: ParseMetadata,
53 pub model: Value,
55}
56
57#[derive(Debug, Clone)]
62pub enum RenderSemanticModel {
63 Json(Value),
64 Mindmap(crate::diagrams::mindmap::MindmapDiagramRenderModel),
65 State(crate::diagrams::state::StateDiagramRenderModel),
66 Sequence(crate::diagrams::sequence::SequenceDiagramRenderModel),
67 Flowchart(crate::diagrams::flowchart::FlowchartV2Model),
68 Architecture(crate::diagrams::architecture::ArchitectureDiagramRenderModel),
69 Class(crate::models::class_diagram::ClassDiagram),
70 C4(crate::diagrams::c4::C4DiagramRenderModel),
71 Kanban(crate::diagrams::kanban::KanbanDiagramRenderModel),
72 Gantt(crate::diagrams::gantt::GanttDiagramRenderModel),
73 Pie(crate::diagrams::pie::PieDiagramRenderModel),
74 Packet(crate::diagrams::packet::PacketDiagramRenderModel),
75 Timeline(crate::diagrams::timeline::TimelineDiagramRenderModel),
76 Journey(crate::diagrams::journey::JourneyDiagramRenderModel),
77 Requirement(crate::diagrams::requirement::RequirementDiagramRenderModel),
78 Sankey(crate::diagrams::sankey::SankeyDiagramRenderModel),
79 Radar(crate::diagrams::radar::RadarDiagramRenderModel),
80 Info(crate::diagrams::info::InfoDiagramRenderModel),
81 Treemap(crate::diagrams::treemap::TreemapDiagramRenderModel),
82 Block(crate::diagrams::block::BlockDiagramRenderModel),
83 Er(crate::diagrams::er::ErDiagramRenderModel),
84 QuadrantChart(crate::diagrams::quadrant_chart::QuadrantChartRenderModel),
85 XyChart(crate::diagrams::xychart::XyChartDiagramRenderModel),
86 GitGraph(crate::diagrams::git_graph::GitGraphRenderModel),
87 TreeView(crate::diagrams::tree_view::TreeViewDiagramRenderModel),
88 Ishikawa(crate::diagrams::ishikawa::IshikawaDiagramRenderModel),
89 EventModeling(crate::diagrams::eventmodeling::EventModelingDiagramRenderModel),
90 Venn(crate::diagrams::venn::VennDiagramRenderModel),
91}
92
93impl RenderSemanticModel {
94 pub(crate) fn sanitize_common_db_fields(&mut self, config: &MermaidConfig) {
96 match self {
97 Self::Json(v) => crate::common_db::apply_common_db_sanitization(v, config),
98 Self::Mindmap(_) => {}
99 Self::State(v) => v.sanitize_common_db_fields(config),
100 Self::Sequence(v) => v.sanitize_common_db_fields(config),
101 Self::Flowchart(v) => v.sanitize_common_db_fields(config),
102 Self::Architecture(v) => v.sanitize_common_db_fields(config),
103 Self::Class(v) => v.sanitize_common_db_fields(config),
104 Self::C4(v) => v.sanitize_common_db_fields(config),
105 Self::Kanban(_) => {}
106 Self::Gantt(v) => v.sanitize_common_db_fields(config),
107 Self::Pie(v) => v.sanitize_common_db_fields(config),
108 Self::Packet(v) => v.sanitize_common_db_fields(config),
109 Self::Timeline(v) => v.sanitize_common_db_fields(config),
110 Self::Journey(v) => v.sanitize_common_db_fields(config),
111 Self::Requirement(v) => v.sanitize_common_db_fields(config),
112 Self::Sankey(_) => {}
113 Self::Radar(v) => v.sanitize_common_db_fields(config),
114 Self::Info(_) => {}
115 Self::Treemap(v) => v.sanitize_common_db_fields(config),
116 Self::Block(_) => {}
117 Self::Er(v) => v.sanitize_common_db_fields(config),
118 Self::QuadrantChart(v) => v.sanitize_common_db_fields(config),
119 Self::XyChart(v) => v.sanitize_common_db_fields(config),
120 Self::GitGraph(v) => v.sanitize_common_db_fields(config),
121 Self::TreeView(v) => v.sanitize_common_db_fields(config),
122 Self::Ishikawa(v) => v.sanitize_common_db_fields(config),
123 Self::EventModeling(v) => v.sanitize_common_db_fields(config),
124 Self::Venn(v) => v.sanitize_common_db_fields(config),
125 }
126 }
127
128 pub fn kind(&self) -> &'static str {
130 match self {
131 Self::Json(_) => "json",
132 Self::Mindmap(_) => "mindmap",
133 Self::State(_) => "state",
134 Self::Sequence(_) => "sequence",
135 Self::Flowchart(_) => "flowchart",
136 Self::Architecture(_) => "architecture",
137 Self::Class(_) => "class",
138 Self::C4(_) => "c4",
139 Self::Kanban(_) => "kanban",
140 Self::Gantt(_) => "gantt",
141 Self::Pie(_) => "pie",
142 Self::Packet(_) => "packet",
143 Self::Timeline(_) => "timeline",
144 Self::Journey(_) => "journey",
145 Self::Requirement(_) => "requirement",
146 Self::Sankey(_) => "sankey",
147 Self::Radar(_) => "radar",
148 Self::Info(_) => "info",
149 Self::Treemap(_) => "treemap",
150 Self::Block(_) => "block",
151 Self::Er(_) => "er",
152 Self::QuadrantChart(_) => "quadrantChart",
153 Self::XyChart(_) => "xychart",
154 Self::GitGraph(_) => "gitGraph",
155 Self::TreeView(_) => "treeView",
156 Self::Ishikawa(_) => "ishikawa",
157 Self::EventModeling(_) => "eventmodeling",
158 Self::Venn(_) => "venn",
159 }
160 }
161
162 pub fn supports_diagram_type(&self, diagram_type: &str) -> bool {
164 match self {
165 Self::Json(_) => true,
166 other => {
167 crate::family::render_model_kind_supports_diagram_type(other.kind(), diagram_type)
168 }
169 }
170 }
171}
172
173#[derive(Debug, Clone, Default)]
175pub struct RenderDiagramRegistry {
176 parsers: std::collections::HashMap<&'static str, RenderSemanticParser>,
177}
178
179impl RenderDiagramRegistry {
180 pub fn new() -> Self {
182 Self::default()
183 }
184
185 pub fn insert(&mut self, diagram_type: &'static str, parser: RenderSemanticParser) {
187 self.parsers.insert(diagram_type, parser);
188 }
189
190 pub fn get(&self, diagram_type: &str) -> Option<RenderSemanticParser> {
192 self.parsers.get(diagram_type).copied()
193 }
194
195 #[cfg(test)]
196 pub(crate) fn remove(&mut self, diagram_type: &str) -> Option<RenderSemanticParser> {
197 self.parsers.remove(diagram_type)
198 }
199
200 pub fn for_pinned_mermaid_baseline() -> Self {
202 let mut reg = Self::new();
203 for fact in crate::family::render_parser_facts() {
204 reg.insert(fact.id, fact.parser);
205 }
206
207 reg
208 }
209
210 #[cfg(test)]
211 pub(crate) fn parser_ids(&self) -> impl Iterator<Item = &'static str> + '_ {
212 self.parsers.keys().copied()
213 }
214}
215
216#[derive(Debug, Clone)]
218pub struct ParsedDiagramRender {
219 pub meta: ParseMetadata,
221 pub model: RenderSemanticModel,
223}
224
225pub fn parse_or_unsupported(
227 registry: &DiagramRegistry,
228 diagram_type: &str,
229 code: &str,
230 meta: &ParseMetadata,
231) -> Result<Value> {
232 let Some(parser) = registry.get(diagram_type) else {
233 return Err(Error::UnsupportedDiagram {
234 diagram_type: diagram_type.to_string(),
235 });
236 };
237 parser(code, meta)
238}