1use crate::model::{
2 ArchitectureDiagramLayout, BlockDiagramLayout, Bounds, ClassDiagramV2Layout, ErDiagramLayout,
3 ErrorDiagramLayout, FlowchartV2Layout, InfoDiagramLayout, LayoutCluster, LayoutNode,
4 MindmapDiagramLayout, PacketDiagramLayout, PieDiagramLayout, QuadrantChartDiagramLayout,
5 RadarDiagramLayout, RequirementDiagramLayout, SankeyDiagramLayout, SequenceDiagramLayout,
6 StateDiagramV2Layout, TimelineDiagramLayout, XyChartDiagramLayout,
7};
8use crate::text::{TextMeasurer, TextStyle, WrapMode};
9use crate::{Error, Result};
10use base64::Engine as _;
11use indexmap::IndexMap;
12use serde::Deserialize;
13use std::fmt::Write as _;
14
15mod architecture;
16mod block;
17mod c4;
18mod class;
19mod css;
20mod curve;
21mod er;
22mod error;
23mod fallback;
24mod flowchart;
25mod gantt;
26mod gitgraph;
27mod info;
28mod journey;
29mod kanban;
30mod layout_debug;
31mod mindmap;
32mod packet;
33mod path_bounds;
34mod pie;
35mod quadrantchart;
36mod radar;
37mod requirement;
38mod root_svg;
39mod roughjs46;
40mod sankey;
41mod sequence;
42mod state;
43mod style;
44mod timeline;
45mod timing;
46mod treemap;
47mod util;
48mod xychart;
49use crate::math::MathRenderer;
50use css::{
51 er_css, gantt_css, info_css_parts_with_config, info_css_with_config, pie_css, requirement_css,
52 sankey_css, treemap_css, xychart_css,
53};
54pub use fallback::foreign_object_label_fallback_svg_text;
55use path_bounds::svg_path_bounds_from_d;
56pub use state::{SvgEmittedBoundsContributor, SvgEmittedBoundsDebug, debug_svg_emitted_bounds};
57use state::{
58 roughjs_ops_to_svg_path_d, roughjs_parse_hex_color_to_srgba, roughjs_paths_for_rect,
59 svg_emitted_bounds_from_svg, svg_emitted_bounds_from_svg_inner,
60};
61use style::{is_rect_style_key, is_text_style_key, parse_style_decl};
62use util::{
63 apply_root_viewport_override, config_bool, config_f64, config_f64_css_px, config_string,
64 decode_mermaid_entities_for_render_text, escape_attr, escape_attr_display, escape_xml,
65 escape_xml_display, escape_xml_into, fmt, fmt_debug_3dp, fmt_display, fmt_into,
66 fmt_max_width_px, fmt_path, fmt_path_into, fmt_string, json_f64, json_stringify_points,
67 json_stringify_points_into, normalize_css_font_family, theme_color,
68};
69
70const MERMAID_SEQUENCE_BASE_DEFS_11_12_2: &str = include_str!(concat!(
71 env!("CARGO_MANIFEST_DIR"),
72 "/assets/sequence_base_defs_11_12_2.svgfrag"
73));
74
75#[derive(Debug, Clone)]
76pub struct SvgRenderOptions {
77 pub viewbox_padding: f64,
79 pub diagram_id: Option<String>,
81 pub aria_roledescription: Option<String>,
86 pub include_edges: bool,
88 pub include_nodes: bool,
90 pub include_clusters: bool,
92 pub include_cluster_debug_markers: bool,
94 pub include_edge_id_labels: bool,
96 pub now_ms_override: Option<i64>,
99 pub math_renderer: Option<std::sync::Arc<dyn MathRenderer + Send + Sync>>,
101}
102
103impl Default for SvgRenderOptions {
104 fn default() -> Self {
105 Self {
106 viewbox_padding: 8.0,
107 diagram_id: None,
108 aria_roledescription: None,
109 include_edges: true,
110 include_nodes: true,
111 include_clusters: true,
112 include_cluster_debug_markers: false,
113 include_edge_id_labels: false,
114 now_ms_override: None,
115 math_renderer: None,
116 }
117 }
118}
119
120pub fn render_layouted_svg(
121 diagram: &crate::model::LayoutedDiagram,
122 measurer: &dyn TextMeasurer,
123 options: &SvgRenderOptions,
124) -> Result<String> {
125 render_layout_svg_parts(
126 &diagram.layout,
127 &diagram.semantic,
128 &diagram.meta.effective_config,
129 diagram.meta.title.as_deref(),
130 measurer,
131 options,
132 )
133}
134
135pub fn render_layout_svg_parts(
136 layout: &crate::model::LayoutDiagram,
137 semantic: &serde_json::Value,
138 effective_config: &serde_json::Value,
139 title: Option<&str>,
140 measurer: &dyn TextMeasurer,
141 options: &SvgRenderOptions,
142) -> Result<String> {
143 use crate::model::LayoutDiagram;
144
145 match layout {
146 LayoutDiagram::ErrorDiagram(layout) => {
147 render_error_diagram_svg(layout, semantic, effective_config, options)
148 }
149 LayoutDiagram::BlockDiagram(layout) => {
150 render_block_diagram_svg(layout, semantic, effective_config, options)
151 }
152 LayoutDiagram::RequirementDiagram(layout) => {
153 render_requirement_diagram_svg(layout, semantic, effective_config, title, options)
154 }
155 LayoutDiagram::ArchitectureDiagram(layout) => {
156 render_architecture_diagram_svg(layout, semantic, effective_config, options)
157 }
158 LayoutDiagram::MindmapDiagram(layout) => {
159 render_mindmap_diagram_svg(layout, semantic, effective_config, options)
160 }
161 LayoutDiagram::SankeyDiagram(layout) => {
162 render_sankey_diagram_svg(layout, semantic, effective_config, options)
163 }
164 LayoutDiagram::RadarDiagram(layout) => {
165 render_radar_diagram_svg(layout, semantic, effective_config, options)
166 }
167 LayoutDiagram::TreemapDiagram(layout) => {
168 render_treemap_diagram_svg(layout, semantic, effective_config, options)
169 }
170 LayoutDiagram::XyChartDiagram(layout) => {
171 render_xychart_diagram_svg(layout, semantic, effective_config, options)
172 }
173 LayoutDiagram::QuadrantChartDiagram(layout) => {
174 render_quadrantchart_diagram_svg(layout, semantic, effective_config, options)
175 }
176 LayoutDiagram::FlowchartV2(layout) => {
177 render_flowchart_v2_svg(layout, semantic, effective_config, title, measurer, options)
178 }
179 LayoutDiagram::StateDiagramV2(layout) => render_state_diagram_v2_svg(
180 layout,
181 semantic,
182 effective_config,
183 title,
184 measurer,
185 options,
186 ),
187 LayoutDiagram::ClassDiagramV2(layout) => render_class_diagram_v2_svg(
188 layout,
189 semantic,
190 effective_config,
191 title,
192 measurer,
193 options,
194 ),
195 LayoutDiagram::ErDiagram(layout) => {
196 render_er_diagram_svg(layout, semantic, effective_config, title, measurer, options)
197 }
198 LayoutDiagram::SequenceDiagram(layout) => render_sequence_diagram_svg(
199 layout,
200 semantic,
201 effective_config,
202 title,
203 measurer,
204 options,
205 ),
206 LayoutDiagram::InfoDiagram(layout) => {
207 render_info_diagram_svg(layout, semantic, effective_config, options)
208 }
209 LayoutDiagram::PacketDiagram(layout) => {
210 render_packet_diagram_svg(layout, semantic, effective_config, title, options)
211 }
212 LayoutDiagram::TimelineDiagram(layout) => render_timeline_diagram_svg(
213 layout,
214 semantic,
215 effective_config,
216 title,
217 measurer,
218 options,
219 ),
220 LayoutDiagram::PieDiagram(layout) => {
221 render_pie_diagram_svg(layout, semantic, effective_config, options)
222 }
223 LayoutDiagram::JourneyDiagram(layout) => {
224 render_journey_diagram_svg(layout, semantic, effective_config, title, measurer, options)
225 }
226 LayoutDiagram::KanbanDiagram(layout) => {
227 render_kanban_diagram_svg(layout, semantic, effective_config, options)
228 }
229 LayoutDiagram::GitGraphDiagram(layout) => render_gitgraph_diagram_svg(
230 layout,
231 semantic,
232 effective_config,
233 title,
234 measurer,
235 options,
236 ),
237 LayoutDiagram::GanttDiagram(layout) => {
238 render_gantt_diagram_svg(layout, semantic, effective_config, options)
239 }
240 LayoutDiagram::C4Diagram(layout) => {
241 render_c4_diagram_svg(layout, semantic, effective_config, title, measurer, options)
242 }
243 }
244}
245
246pub fn render_layout_svg_parts_with_config(
247 layout: &crate::model::LayoutDiagram,
248 semantic: &serde_json::Value,
249 effective_config: &merman_core::MermaidConfig,
250 title: Option<&str>,
251 measurer: &dyn TextMeasurer,
252 options: &SvgRenderOptions,
253) -> Result<String> {
254 use crate::model::LayoutDiagram;
255
256 let effective_config_value = effective_config.as_value();
257
258 match layout {
259 LayoutDiagram::ErrorDiagram(layout) => {
260 render_error_diagram_svg(layout, semantic, effective_config_value, options)
261 }
262 LayoutDiagram::BlockDiagram(layout) => {
263 render_block_diagram_svg(layout, semantic, effective_config_value, options)
264 }
265 LayoutDiagram::RequirementDiagram(layout) => {
266 render_requirement_diagram_svg(layout, semantic, effective_config_value, title, options)
267 }
268 LayoutDiagram::ArchitectureDiagram(layout) => {
269 architecture::render_architecture_diagram_svg_with_config(
270 layout,
271 semantic,
272 effective_config,
273 options,
274 )
275 }
276 LayoutDiagram::MindmapDiagram(layout) => {
277 render_mindmap_diagram_svg_with_config(layout, semantic, effective_config, options)
278 }
279 LayoutDiagram::SankeyDiagram(layout) => {
280 render_sankey_diagram_svg(layout, semantic, effective_config_value, options)
281 }
282 LayoutDiagram::RadarDiagram(layout) => {
283 render_radar_diagram_svg(layout, semantic, effective_config_value, options)
284 }
285 LayoutDiagram::TreemapDiagram(layout) => {
286 render_treemap_diagram_svg(layout, semantic, effective_config_value, options)
287 }
288 LayoutDiagram::XyChartDiagram(layout) => {
289 render_xychart_diagram_svg(layout, semantic, effective_config_value, options)
290 }
291 LayoutDiagram::QuadrantChartDiagram(layout) => {
292 render_quadrantchart_diagram_svg(layout, semantic, effective_config_value, options)
293 }
294 LayoutDiagram::FlowchartV2(layout) => render_flowchart_v2_svg_with_config(
295 layout,
296 semantic,
297 effective_config,
298 title,
299 measurer,
300 options,
301 ),
302 LayoutDiagram::StateDiagramV2(layout) => render_state_diagram_v2_svg(
303 layout,
304 semantic,
305 effective_config_value,
306 title,
307 measurer,
308 options,
309 ),
310 LayoutDiagram::ClassDiagramV2(layout) => render_class_diagram_v2_svg(
311 layout,
312 semantic,
313 effective_config_value,
314 title,
315 measurer,
316 options,
317 ),
318 LayoutDiagram::ErDiagram(layout) => render_er_diagram_svg(
319 layout,
320 semantic,
321 effective_config_value,
322 title,
323 measurer,
324 options,
325 ),
326 LayoutDiagram::SequenceDiagram(layout) => {
327 sequence::render_sequence_diagram_svg_with_config(
328 layout,
329 semantic,
330 effective_config,
331 title,
332 measurer,
333 options,
334 )
335 }
336 LayoutDiagram::InfoDiagram(layout) => {
337 render_info_diagram_svg(layout, semantic, effective_config_value, options)
338 }
339 LayoutDiagram::PacketDiagram(layout) => {
340 render_packet_diagram_svg(layout, semantic, effective_config_value, title, options)
341 }
342 LayoutDiagram::TimelineDiagram(layout) => render_timeline_diagram_svg(
343 layout,
344 semantic,
345 effective_config_value,
346 title,
347 measurer,
348 options,
349 ),
350 LayoutDiagram::PieDiagram(layout) => {
351 render_pie_diagram_svg(layout, semantic, effective_config_value, options)
352 }
353 LayoutDiagram::JourneyDiagram(layout) => render_journey_diagram_svg(
354 layout,
355 semantic,
356 effective_config_value,
357 title,
358 measurer,
359 options,
360 ),
361 LayoutDiagram::KanbanDiagram(layout) => {
362 render_kanban_diagram_svg(layout, semantic, effective_config_value, options)
363 }
364 LayoutDiagram::GitGraphDiagram(layout) => render_gitgraph_diagram_svg(
365 layout,
366 semantic,
367 effective_config_value,
368 title,
369 measurer,
370 options,
371 ),
372 LayoutDiagram::GanttDiagram(layout) => {
373 render_gantt_diagram_svg(layout, semantic, effective_config_value, options)
374 }
375 LayoutDiagram::C4Diagram(layout) => render_c4_diagram_svg(
376 layout,
377 semantic,
378 effective_config_value,
379 title,
380 measurer,
381 options,
382 ),
383 }
384}
385
386pub fn render_layout_svg_parts_for_render_model(
387 layout: &crate::model::LayoutDiagram,
388 semantic: &merman_core::RenderSemanticModel,
389 effective_config: &serde_json::Value,
390 title: Option<&str>,
391 measurer: &dyn TextMeasurer,
392 options: &SvgRenderOptions,
393) -> Result<String> {
394 use crate::model::LayoutDiagram;
395 use merman_core::RenderSemanticModel;
396
397 match (layout, semantic) {
398 (LayoutDiagram::ArchitectureDiagram(layout), RenderSemanticModel::Architecture(model)) => {
399 architecture::render_architecture_diagram_svg_typed(
400 layout,
401 model,
402 effective_config,
403 options,
404 )
405 }
406 (LayoutDiagram::FlowchartV2(layout), RenderSemanticModel::Flowchart(model)) => {
407 render_flowchart_v2_svg_model(layout, model, effective_config, title, measurer, options)
408 }
409 (LayoutDiagram::MindmapDiagram(layout), RenderSemanticModel::Mindmap(model)) => {
410 mindmap::render_mindmap_diagram_svg_model(layout, model, effective_config, options)
411 }
412 (LayoutDiagram::StateDiagramV2(layout), RenderSemanticModel::State(model)) => {
413 state::render_state_diagram_v2_svg_model(
414 layout,
415 model,
416 effective_config,
417 title,
418 measurer,
419 options,
420 )
421 }
422 (LayoutDiagram::ClassDiagramV2(layout), RenderSemanticModel::Class(model)) => {
423 class::render_class_diagram_v2_svg_model(
424 layout,
425 model,
426 effective_config,
427 title,
428 measurer,
429 options,
430 )
431 }
432 (_, RenderSemanticModel::Json(semantic)) => {
433 render_layout_svg_parts(layout, semantic, effective_config, title, measurer, options)
434 }
435 _ => Err(Error::InvalidModel {
436 message: "semantic model does not match layout diagram type".to_string(),
437 }),
438 }
439}
440
441pub fn render_layout_svg_parts_for_render_model_with_config(
442 layout: &crate::model::LayoutDiagram,
443 semantic: &merman_core::RenderSemanticModel,
444 effective_config: &merman_core::MermaidConfig,
445 title: Option<&str>,
446 measurer: &dyn TextMeasurer,
447 options: &SvgRenderOptions,
448) -> Result<String> {
449 use crate::model::LayoutDiagram;
450 use merman_core::RenderSemanticModel;
451
452 match (layout, semantic) {
453 (LayoutDiagram::ArchitectureDiagram(layout), RenderSemanticModel::Architecture(model)) => {
454 architecture::render_architecture_diagram_svg_typed_with_config(
455 layout,
456 model,
457 effective_config,
458 options,
459 )
460 }
461 (LayoutDiagram::FlowchartV2(layout), RenderSemanticModel::Flowchart(model)) => {
462 render_flowchart_v2_svg_model_with_config(
463 layout,
464 model,
465 effective_config,
466 title,
467 measurer,
468 options,
469 )
470 }
471 (LayoutDiagram::MindmapDiagram(layout), RenderSemanticModel::Mindmap(model)) => {
472 mindmap::render_mindmap_diagram_svg_model_with_config(
473 layout,
474 model,
475 effective_config,
476 options,
477 )
478 }
479 (LayoutDiagram::StateDiagramV2(layout), RenderSemanticModel::State(model)) => {
480 state::render_state_diagram_v2_svg_model(
481 layout,
482 model,
483 effective_config.as_value(),
484 title,
485 measurer,
486 options,
487 )
488 }
489 (LayoutDiagram::ClassDiagramV2(layout), RenderSemanticModel::Class(model)) => {
490 class::render_class_diagram_v2_svg_model(
491 layout,
492 model,
493 effective_config.as_value(),
494 title,
495 measurer,
496 options,
497 )
498 }
499 (_, RenderSemanticModel::Json(semantic)) => render_layout_svg_parts_with_config(
500 layout,
501 semantic,
502 effective_config,
503 title,
504 measurer,
505 options,
506 ),
507 _ => Err(Error::InvalidModel {
508 message: "semantic model does not match layout diagram type".to_string(),
509 }),
510 }
511}
512
513pub fn render_flowchart_v2_debug_svg(
514 layout: &FlowchartV2Layout,
515 options: &SvgRenderOptions,
516) -> String {
517 flowchart::render_flowchart_v2_debug_svg(layout, options)
518}
519
520#[derive(Debug, Clone, Deserialize)]
521struct PieSvgSection {
522 #[allow(dead_code)]
523 label: String,
524 #[allow(dead_code)]
525 value: f64,
526}
527
528#[derive(Debug, Clone, Deserialize)]
529struct PieSvgModel {
530 #[serde(rename = "accTitle")]
531 acc_title: Option<String>,
532 #[serde(rename = "accDescr")]
533 acc_descr: Option<String>,
534 #[serde(rename = "showData")]
535 show_data: bool,
536 title: Option<String>,
537 #[allow(dead_code)]
538 sections: Vec<PieSvgSection>,
539}
540
541pub fn render_sequence_diagram_debug_svg(
542 layout: &SequenceDiagramLayout,
543 options: &SvgRenderOptions,
544) -> String {
545 sequence::render_sequence_diagram_debug_svg(layout, options)
546}
547
548pub fn render_sequence_diagram_svg(
549 layout: &SequenceDiagramLayout,
550 semantic: &serde_json::Value,
551 effective_config: &serde_json::Value,
552 diagram_title: Option<&str>,
553 measurer: &dyn TextMeasurer,
554 options: &SvgRenderOptions,
555) -> Result<String> {
556 sequence::render_sequence_diagram_svg(
557 layout,
558 semantic,
559 effective_config,
560 diagram_title,
561 measurer,
562 options,
563 )
564}
565
566pub fn render_error_diagram_svg(
567 layout: &ErrorDiagramLayout,
568 _semantic: &serde_json::Value,
569 _effective_config: &serde_json::Value,
570 options: &SvgRenderOptions,
571) -> Result<String> {
572 error::render_error_diagram_svg(layout, _semantic, _effective_config, options)
573}
574
575pub fn render_info_diagram_svg(
576 layout: &InfoDiagramLayout,
577 _semantic: &serde_json::Value,
578 _effective_config: &serde_json::Value,
579 options: &SvgRenderOptions,
580) -> Result<String> {
581 info::render_info_diagram_svg(layout, _semantic, _effective_config, options)
582}
583
584pub fn render_pie_diagram_svg(
585 layout: &PieDiagramLayout,
586 semantic: &serde_json::Value,
587 _effective_config: &serde_json::Value,
588 options: &SvgRenderOptions,
589) -> Result<String> {
590 pie::render_pie_diagram_svg(layout, semantic, _effective_config, options)
591}
592
593pub fn render_requirement_diagram_svg(
594 layout: &RequirementDiagramLayout,
595 semantic: &serde_json::Value,
596 effective_config: &serde_json::Value,
597 diagram_title: Option<&str>,
598 options: &SvgRenderOptions,
599) -> Result<String> {
600 requirement::render_requirement_diagram_svg(
601 layout,
602 semantic,
603 effective_config,
604 diagram_title,
605 options,
606 )
607}
608
609pub fn render_block_diagram_svg(
610 layout: &BlockDiagramLayout,
611 semantic: &serde_json::Value,
612 effective_config: &serde_json::Value,
613 options: &SvgRenderOptions,
614) -> Result<String> {
615 block::render_block_diagram_svg(layout, semantic, effective_config, options)
616}
617
618pub fn render_radar_diagram_svg(
619 layout: &RadarDiagramLayout,
620 semantic: &serde_json::Value,
621 effective_config: &serde_json::Value,
622 options: &SvgRenderOptions,
623) -> Result<String> {
624 radar::render_radar_diagram_svg(layout, semantic, effective_config, options)
625}
626
627pub fn render_quadrantchart_diagram_svg(
628 layout: &QuadrantChartDiagramLayout,
629 _semantic: &serde_json::Value,
630 _effective_config: &serde_json::Value,
631 options: &SvgRenderOptions,
632) -> Result<String> {
633 quadrantchart::render_quadrantchart_diagram_svg(layout, _semantic, _effective_config, options)
634}
635
636pub fn render_xychart_diagram_svg(
637 layout: &XyChartDiagramLayout,
638 _semantic: &serde_json::Value,
639 _effective_config: &serde_json::Value,
640 options: &SvgRenderOptions,
641) -> Result<String> {
642 xychart::render_xychart_diagram_svg(layout, _semantic, _effective_config, options)
643}
644
645pub fn render_treemap_diagram_svg(
646 layout: &crate::model::TreemapDiagramLayout,
647 _semantic: &serde_json::Value,
648 effective_config: &serde_json::Value,
649 options: &SvgRenderOptions,
650) -> Result<String> {
651 treemap::render_treemap_diagram_svg(layout, _semantic, effective_config, options)
652}
653
654pub fn render_packet_diagram_svg(
655 layout: &PacketDiagramLayout,
656 semantic: &serde_json::Value,
657 _effective_config: &serde_json::Value,
658 diagram_title: Option<&str>,
659 options: &SvgRenderOptions,
660) -> Result<String> {
661 packet::render_packet_diagram_svg(layout, semantic, _effective_config, diagram_title, options)
662}
663
664pub fn render_timeline_diagram_svg(
665 layout: &TimelineDiagramLayout,
666 semantic: &serde_json::Value,
667 effective_config: &serde_json::Value,
668 _diagram_title: Option<&str>,
669 _measurer: &dyn TextMeasurer,
670 options: &SvgRenderOptions,
671) -> Result<String> {
672 timeline::render_timeline_diagram_svg(
673 layout,
674 semantic,
675 effective_config,
676 _diagram_title,
677 _measurer,
678 options,
679 )
680}
681
682pub fn render_journey_diagram_svg(
683 layout: &crate::model::JourneyDiagramLayout,
684 semantic: &serde_json::Value,
685 effective_config: &serde_json::Value,
686 _diagram_title: Option<&str>,
687 _measurer: &dyn TextMeasurer,
688 options: &SvgRenderOptions,
689) -> Result<String> {
690 journey::render_journey_diagram_svg(
691 layout,
692 semantic,
693 effective_config,
694 _diagram_title,
695 _measurer,
696 options,
697 )
698}
699
700pub fn render_kanban_diagram_svg(
701 layout: &crate::model::KanbanDiagramLayout,
702 _semantic: &serde_json::Value,
703 _effective_config: &serde_json::Value,
704 options: &SvgRenderOptions,
705) -> Result<String> {
706 kanban::render_kanban_diagram_svg(layout, _semantic, _effective_config, options)
707}
708
709pub fn render_gitgraph_diagram_svg(
710 layout: &crate::model::GitGraphDiagramLayout,
711 semantic: &serde_json::Value,
712 _effective_config: &serde_json::Value,
713 diagram_title: Option<&str>,
714 measurer: &dyn TextMeasurer,
715 options: &SvgRenderOptions,
716) -> Result<String> {
717 gitgraph::render_gitgraph_diagram_svg(
718 layout,
719 semantic,
720 _effective_config,
721 diagram_title,
722 measurer,
723 options,
724 )
725}
726
727pub fn render_gantt_diagram_svg(
728 layout: &crate::model::GanttDiagramLayout,
729 semantic: &serde_json::Value,
730 _effective_config: &serde_json::Value,
731 options: &SvgRenderOptions,
732) -> Result<String> {
733 gantt::render_gantt_diagram_svg(layout, semantic, _effective_config, options)
734}
735
736#[derive(Debug, Clone, Deserialize)]
737struct C4SvgModelText {
738 #[allow(dead_code)]
739 text: String,
740}
741
742#[derive(Debug, Clone, Deserialize)]
743struct C4SvgModelShape {
744 alias: String,
745 #[serde(default, rename = "bgColor")]
746 bg_color: Option<String>,
747 #[serde(default, rename = "borderColor")]
748 border_color: Option<String>,
749 #[serde(default, rename = "fontColor")]
750 font_color: Option<String>,
751 #[serde(default, rename = "typeC4Shape")]
752 #[allow(dead_code)]
753 type_c4_shape: Option<C4SvgModelText>,
754}
755
756#[derive(Debug, Clone, Deserialize)]
757struct C4SvgModelBoundary {
758 alias: String,
759 #[serde(default, rename = "nodeType")]
760 node_type: Option<String>,
761 #[serde(default, rename = "bgColor")]
762 bg_color: Option<String>,
763 #[serde(default, rename = "borderColor")]
764 border_color: Option<String>,
765 #[serde(default, rename = "fontColor")]
766 #[allow(dead_code)]
767 font_color: Option<String>,
768}
769
770#[derive(Debug, Clone, Deserialize)]
771struct C4SvgModelRel {
772 #[serde(rename = "from")]
773 from_alias: String,
774 #[serde(rename = "to")]
775 to_alias: String,
776 #[serde(default, rename = "lineColor")]
777 line_color: Option<String>,
778 #[serde(default, rename = "textColor")]
779 text_color: Option<String>,
780}
781
782#[derive(Debug, Clone, Deserialize)]
783struct C4SvgModel {
784 #[serde(default, rename = "accTitle")]
785 acc_title: Option<String>,
786 #[serde(default, rename = "accDescr")]
787 acc_descr: Option<String>,
788 #[serde(default)]
789 title: Option<String>,
790 #[serde(default)]
791 shapes: Vec<C4SvgModelShape>,
792 #[serde(default)]
793 boundaries: Vec<C4SvgModelBoundary>,
794 #[serde(default)]
795 rels: Vec<C4SvgModelRel>,
796}
797
798pub fn render_mindmap_diagram_svg(
799 layout: &MindmapDiagramLayout,
800 semantic: &serde_json::Value,
801 _effective_config: &serde_json::Value,
802 options: &SvgRenderOptions,
803) -> Result<String> {
804 mindmap::render_mindmap_diagram_svg(layout, semantic, _effective_config, options)
805}
806
807pub fn render_mindmap_diagram_svg_with_config(
808 layout: &MindmapDiagramLayout,
809 semantic: &serde_json::Value,
810 effective_config: &merman_core::MermaidConfig,
811 options: &SvgRenderOptions,
812) -> Result<String> {
813 mindmap::render_mindmap_diagram_svg_with_config(layout, semantic, effective_config, options)
814}
815
816pub fn render_architecture_diagram_svg(
817 layout: &ArchitectureDiagramLayout,
818 semantic: &serde_json::Value,
819 effective_config: &serde_json::Value,
820 options: &SvgRenderOptions,
821) -> Result<String> {
822 architecture::render_architecture_diagram_svg(layout, semantic, effective_config, options)
823}
824
825pub fn render_c4_diagram_svg(
826 layout: &crate::model::C4DiagramLayout,
827 semantic: &serde_json::Value,
828 effective_config: &serde_json::Value,
829 diagram_title: Option<&str>,
830 _measurer: &dyn TextMeasurer,
831 options: &SvgRenderOptions,
832) -> Result<String> {
833 c4::render_c4_diagram_svg(
834 layout,
835 semantic,
836 effective_config,
837 diagram_title,
838 _measurer,
839 options,
840 )
841}
842
843pub fn render_flowchart_v2_svg(
844 layout: &FlowchartV2Layout,
845 semantic: &serde_json::Value,
846 effective_config: &serde_json::Value,
847 diagram_title: Option<&str>,
848 measurer: &dyn TextMeasurer,
849 options: &SvgRenderOptions,
850) -> Result<String> {
851 flowchart::render_flowchart_v2_svg(
852 layout,
853 semantic,
854 effective_config,
855 diagram_title,
856 measurer,
857 options,
858 )
859}
860
861pub fn render_flowchart_v2_svg_model(
862 layout: &FlowchartV2Layout,
863 model: &merman_core::diagrams::flowchart::FlowchartV2Model,
864 effective_config: &serde_json::Value,
865 diagram_title: Option<&str>,
866 measurer: &dyn TextMeasurer,
867 options: &SvgRenderOptions,
868) -> Result<String> {
869 flowchart::render_flowchart_v2_svg_model(
870 layout,
871 model,
872 effective_config,
873 diagram_title,
874 measurer,
875 options,
876 )
877}
878
879pub fn render_flowchart_v2_svg_with_config(
880 layout: &FlowchartV2Layout,
881 semantic: &serde_json::Value,
882 effective_config: &merman_core::MermaidConfig,
883 diagram_title: Option<&str>,
884 measurer: &dyn TextMeasurer,
885 options: &SvgRenderOptions,
886) -> Result<String> {
887 flowchart::render_flowchart_v2_svg_with_config(
888 layout,
889 semantic,
890 effective_config,
891 diagram_title,
892 measurer,
893 options,
894 )
895}
896
897pub fn render_flowchart_v2_svg_model_with_config(
898 layout: &FlowchartV2Layout,
899 model: &merman_core::diagrams::flowchart::FlowchartV2Model,
900 effective_config: &merman_core::MermaidConfig,
901 diagram_title: Option<&str>,
902 measurer: &dyn TextMeasurer,
903 options: &SvgRenderOptions,
904) -> Result<String> {
905 flowchart::render_flowchart_v2_svg_model_with_config(
906 layout,
907 model,
908 effective_config,
909 diagram_title,
910 measurer,
911 options,
912 )
913}
914
915pub fn render_state_diagram_v2_svg(
916 layout: &StateDiagramV2Layout,
917 semantic: &serde_json::Value,
918 effective_config: &serde_json::Value,
919 diagram_title: Option<&str>,
920 measurer: &dyn TextMeasurer,
921 options: &SvgRenderOptions,
922) -> Result<String> {
923 state::render_state_diagram_v2_svg(
924 layout,
925 semantic,
926 effective_config,
927 diagram_title,
928 measurer,
929 options,
930 )
931}
932
933pub fn render_state_diagram_v2_debug_svg(
934 layout: &StateDiagramV2Layout,
935 options: &SvgRenderOptions,
936) -> String {
937 state::render_state_diagram_v2_debug_svg(layout, options)
938}
939
940pub fn render_class_diagram_v2_debug_svg(
941 layout: &ClassDiagramV2Layout,
942 options: &SvgRenderOptions,
943) -> String {
944 class::render_class_diagram_v2_debug_svg(layout, options)
945}
946
947pub fn render_class_diagram_v2_svg(
948 layout: &ClassDiagramV2Layout,
949 semantic: &serde_json::Value,
950 effective_config: &serde_json::Value,
951 diagram_title: Option<&str>,
952 measurer: &dyn TextMeasurer,
953 options: &SvgRenderOptions,
954) -> Result<String> {
955 class::render_class_diagram_v2_svg(
956 layout,
957 semantic,
958 effective_config,
959 diagram_title,
960 measurer,
961 options,
962 )
963}
964
965pub fn render_er_diagram_debug_svg(layout: &ErDiagramLayout, options: &SvgRenderOptions) -> String {
966 er::render_er_diagram_debug_svg(layout, options)
967}
968
969pub fn render_er_diagram_svg(
970 layout: &ErDiagramLayout,
971 semantic: &serde_json::Value,
972 effective_config: &serde_json::Value,
973 diagram_title: Option<&str>,
974 measurer: &dyn TextMeasurer,
975 options: &SvgRenderOptions,
976) -> Result<String> {
977 er::render_er_diagram_svg(
978 layout,
979 semantic,
980 effective_config,
981 diagram_title,
982 measurer,
983 options,
984 )
985}
986
987pub fn render_sankey_diagram_svg(
988 layout: &SankeyDiagramLayout,
989 _semantic: &serde_json::Value,
990 effective_config: &serde_json::Value,
991 options: &SvgRenderOptions,
992) -> Result<String> {
993 sankey::render_sankey_diagram_svg(layout, _semantic, effective_config, options)
994}
995
996fn curve_basis_path_d(points: &[crate::model::LayoutPoint]) -> String {
998 curve::curve_basis_path_d(points)
999}
1000fn render_node(out: &mut String, n: &LayoutNode) {
1001 layout_debug::render_node(out, n)
1002}
1003
1004fn render_state_node(out: &mut String, n: &LayoutNode) {
1005 layout_debug::render_state_node(out, n)
1006}
1007
1008fn render_cluster(out: &mut String, c: &LayoutCluster, include_markers: bool) {
1009 layout_debug::render_cluster(out, c, include_markers)
1010}
1011
1012fn compute_layout_bounds(
1013 clusters: &[LayoutCluster],
1014 nodes: &[LayoutNode],
1015 edges: &[crate::model::LayoutEdge],
1016) -> Option<Bounds> {
1017 layout_debug::compute_layout_bounds(clusters, nodes, edges)
1018}