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