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, title, 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, title, 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 diagram_title: Option<&str>,
590 options: &SvgRenderOptions,
591) -> Result<String> {
592 requirement::render_requirement_diagram_svg(
593 layout,
594 semantic,
595 effective_config,
596 diagram_title,
597 options,
598 )
599}
600
601pub fn render_block_diagram_svg(
602 layout: &BlockDiagramLayout,
603 semantic: &serde_json::Value,
604 effective_config: &serde_json::Value,
605 options: &SvgRenderOptions,
606) -> Result<String> {
607 block::render_block_diagram_svg(layout, semantic, effective_config, options)
608}
609
610pub fn render_radar_diagram_svg(
611 layout: &RadarDiagramLayout,
612 semantic: &serde_json::Value,
613 effective_config: &serde_json::Value,
614 options: &SvgRenderOptions,
615) -> Result<String> {
616 radar::render_radar_diagram_svg(layout, semantic, effective_config, options)
617}
618
619pub fn render_quadrantchart_diagram_svg(
620 layout: &QuadrantChartDiagramLayout,
621 _semantic: &serde_json::Value,
622 _effective_config: &serde_json::Value,
623 options: &SvgRenderOptions,
624) -> Result<String> {
625 quadrantchart::render_quadrantchart_diagram_svg(layout, _semantic, _effective_config, options)
626}
627
628pub fn render_xychart_diagram_svg(
629 layout: &XyChartDiagramLayout,
630 _semantic: &serde_json::Value,
631 _effective_config: &serde_json::Value,
632 options: &SvgRenderOptions,
633) -> Result<String> {
634 xychart::render_xychart_diagram_svg(layout, _semantic, _effective_config, options)
635}
636
637pub fn render_treemap_diagram_svg(
638 layout: &crate::model::TreemapDiagramLayout,
639 _semantic: &serde_json::Value,
640 effective_config: &serde_json::Value,
641 options: &SvgRenderOptions,
642) -> Result<String> {
643 treemap::render_treemap_diagram_svg(layout, _semantic, effective_config, options)
644}
645
646pub fn render_packet_diagram_svg(
647 layout: &PacketDiagramLayout,
648 semantic: &serde_json::Value,
649 _effective_config: &serde_json::Value,
650 diagram_title: Option<&str>,
651 options: &SvgRenderOptions,
652) -> Result<String> {
653 packet::render_packet_diagram_svg(layout, semantic, _effective_config, diagram_title, options)
654}
655
656pub fn render_timeline_diagram_svg(
657 layout: &TimelineDiagramLayout,
658 semantic: &serde_json::Value,
659 effective_config: &serde_json::Value,
660 _diagram_title: Option<&str>,
661 _measurer: &dyn TextMeasurer,
662 options: &SvgRenderOptions,
663) -> Result<String> {
664 timeline::render_timeline_diagram_svg(
665 layout,
666 semantic,
667 effective_config,
668 _diagram_title,
669 _measurer,
670 options,
671 )
672}
673
674pub fn render_journey_diagram_svg(
675 layout: &crate::model::JourneyDiagramLayout,
676 semantic: &serde_json::Value,
677 effective_config: &serde_json::Value,
678 _diagram_title: Option<&str>,
679 _measurer: &dyn TextMeasurer,
680 options: &SvgRenderOptions,
681) -> Result<String> {
682 journey::render_journey_diagram_svg(
683 layout,
684 semantic,
685 effective_config,
686 _diagram_title,
687 _measurer,
688 options,
689 )
690}
691
692pub fn render_kanban_diagram_svg(
693 layout: &crate::model::KanbanDiagramLayout,
694 _semantic: &serde_json::Value,
695 _effective_config: &serde_json::Value,
696 options: &SvgRenderOptions,
697) -> Result<String> {
698 kanban::render_kanban_diagram_svg(layout, _semantic, _effective_config, options)
699}
700
701pub fn render_gitgraph_diagram_svg(
702 layout: &crate::model::GitGraphDiagramLayout,
703 semantic: &serde_json::Value,
704 _effective_config: &serde_json::Value,
705 diagram_title: Option<&str>,
706 measurer: &dyn TextMeasurer,
707 options: &SvgRenderOptions,
708) -> Result<String> {
709 gitgraph::render_gitgraph_diagram_svg(
710 layout,
711 semantic,
712 _effective_config,
713 diagram_title,
714 measurer,
715 options,
716 )
717}
718
719pub fn render_gantt_diagram_svg(
720 layout: &crate::model::GanttDiagramLayout,
721 semantic: &serde_json::Value,
722 _effective_config: &serde_json::Value,
723 options: &SvgRenderOptions,
724) -> Result<String> {
725 gantt::render_gantt_diagram_svg(layout, semantic, _effective_config, options)
726}
727
728#[derive(Debug, Clone, Deserialize)]
729struct C4SvgModelText {
730 #[allow(dead_code)]
731 text: String,
732}
733
734#[derive(Debug, Clone, Deserialize)]
735struct C4SvgModelShape {
736 alias: String,
737 #[serde(default, rename = "bgColor")]
738 bg_color: Option<String>,
739 #[serde(default, rename = "borderColor")]
740 border_color: Option<String>,
741 #[serde(default, rename = "fontColor")]
742 font_color: Option<String>,
743 #[serde(default, rename = "typeC4Shape")]
744 #[allow(dead_code)]
745 type_c4_shape: Option<C4SvgModelText>,
746}
747
748#[derive(Debug, Clone, Deserialize)]
749struct C4SvgModelBoundary {
750 alias: String,
751 #[serde(default, rename = "nodeType")]
752 node_type: Option<String>,
753 #[serde(default, rename = "bgColor")]
754 bg_color: Option<String>,
755 #[serde(default, rename = "borderColor")]
756 border_color: Option<String>,
757 #[serde(default, rename = "fontColor")]
758 #[allow(dead_code)]
759 font_color: Option<String>,
760}
761
762#[derive(Debug, Clone, Deserialize)]
763struct C4SvgModelRel {
764 #[serde(rename = "from")]
765 from_alias: String,
766 #[serde(rename = "to")]
767 to_alias: String,
768 #[serde(default, rename = "lineColor")]
769 line_color: Option<String>,
770 #[serde(default, rename = "textColor")]
771 text_color: Option<String>,
772}
773
774#[derive(Debug, Clone, Deserialize)]
775struct C4SvgModel {
776 #[serde(default, rename = "accTitle")]
777 acc_title: Option<String>,
778 #[serde(default, rename = "accDescr")]
779 acc_descr: Option<String>,
780 #[serde(default)]
781 title: Option<String>,
782 #[serde(default)]
783 shapes: Vec<C4SvgModelShape>,
784 #[serde(default)]
785 boundaries: Vec<C4SvgModelBoundary>,
786 #[serde(default)]
787 rels: Vec<C4SvgModelRel>,
788}
789
790pub fn render_mindmap_diagram_svg(
791 layout: &MindmapDiagramLayout,
792 semantic: &serde_json::Value,
793 _effective_config: &serde_json::Value,
794 options: &SvgRenderOptions,
795) -> Result<String> {
796 mindmap::render_mindmap_diagram_svg(layout, semantic, _effective_config, options)
797}
798
799pub fn render_mindmap_diagram_svg_with_config(
800 layout: &MindmapDiagramLayout,
801 semantic: &serde_json::Value,
802 effective_config: &merman_core::MermaidConfig,
803 options: &SvgRenderOptions,
804) -> Result<String> {
805 mindmap::render_mindmap_diagram_svg_with_config(layout, semantic, effective_config, options)
806}
807
808pub fn render_architecture_diagram_svg(
809 layout: &ArchitectureDiagramLayout,
810 semantic: &serde_json::Value,
811 effective_config: &serde_json::Value,
812 options: &SvgRenderOptions,
813) -> Result<String> {
814 architecture::render_architecture_diagram_svg(layout, semantic, effective_config, options)
815}
816
817pub fn render_c4_diagram_svg(
818 layout: &crate::model::C4DiagramLayout,
819 semantic: &serde_json::Value,
820 effective_config: &serde_json::Value,
821 diagram_title: Option<&str>,
822 _measurer: &dyn TextMeasurer,
823 options: &SvgRenderOptions,
824) -> Result<String> {
825 c4::render_c4_diagram_svg(
826 layout,
827 semantic,
828 effective_config,
829 diagram_title,
830 _measurer,
831 options,
832 )
833}
834
835pub fn render_flowchart_v2_svg(
836 layout: &FlowchartV2Layout,
837 semantic: &serde_json::Value,
838 effective_config: &serde_json::Value,
839 diagram_title: Option<&str>,
840 measurer: &dyn TextMeasurer,
841 options: &SvgRenderOptions,
842) -> Result<String> {
843 flowchart::render_flowchart_v2_svg(
844 layout,
845 semantic,
846 effective_config,
847 diagram_title,
848 measurer,
849 options,
850 )
851}
852
853pub fn render_flowchart_v2_svg_model(
854 layout: &FlowchartV2Layout,
855 model: &merman_core::diagrams::flowchart::FlowchartV2Model,
856 effective_config: &serde_json::Value,
857 diagram_title: Option<&str>,
858 measurer: &dyn TextMeasurer,
859 options: &SvgRenderOptions,
860) -> Result<String> {
861 flowchart::render_flowchart_v2_svg_model(
862 layout,
863 model,
864 effective_config,
865 diagram_title,
866 measurer,
867 options,
868 )
869}
870
871pub fn render_flowchart_v2_svg_with_config(
872 layout: &FlowchartV2Layout,
873 semantic: &serde_json::Value,
874 effective_config: &merman_core::MermaidConfig,
875 diagram_title: Option<&str>,
876 measurer: &dyn TextMeasurer,
877 options: &SvgRenderOptions,
878) -> Result<String> {
879 flowchart::render_flowchart_v2_svg_with_config(
880 layout,
881 semantic,
882 effective_config,
883 diagram_title,
884 measurer,
885 options,
886 )
887}
888
889pub fn render_flowchart_v2_svg_model_with_config(
890 layout: &FlowchartV2Layout,
891 model: &merman_core::diagrams::flowchart::FlowchartV2Model,
892 effective_config: &merman_core::MermaidConfig,
893 diagram_title: Option<&str>,
894 measurer: &dyn TextMeasurer,
895 options: &SvgRenderOptions,
896) -> Result<String> {
897 flowchart::render_flowchart_v2_svg_model_with_config(
898 layout,
899 model,
900 effective_config,
901 diagram_title,
902 measurer,
903 options,
904 )
905}
906
907pub fn render_state_diagram_v2_svg(
908 layout: &StateDiagramV2Layout,
909 semantic: &serde_json::Value,
910 effective_config: &serde_json::Value,
911 diagram_title: Option<&str>,
912 measurer: &dyn TextMeasurer,
913 options: &SvgRenderOptions,
914) -> Result<String> {
915 state::render_state_diagram_v2_svg(
916 layout,
917 semantic,
918 effective_config,
919 diagram_title,
920 measurer,
921 options,
922 )
923}
924
925pub fn render_state_diagram_v2_debug_svg(
926 layout: &StateDiagramV2Layout,
927 options: &SvgRenderOptions,
928) -> String {
929 state::render_state_diagram_v2_debug_svg(layout, options)
930}
931
932pub fn render_class_diagram_v2_debug_svg(
933 layout: &ClassDiagramV2Layout,
934 options: &SvgRenderOptions,
935) -> String {
936 class::render_class_diagram_v2_debug_svg(layout, options)
937}
938
939pub fn render_class_diagram_v2_svg(
940 layout: &ClassDiagramV2Layout,
941 semantic: &serde_json::Value,
942 effective_config: &serde_json::Value,
943 diagram_title: Option<&str>,
944 measurer: &dyn TextMeasurer,
945 options: &SvgRenderOptions,
946) -> Result<String> {
947 class::render_class_diagram_v2_svg(
948 layout,
949 semantic,
950 effective_config,
951 diagram_title,
952 measurer,
953 options,
954 )
955}
956
957pub fn render_er_diagram_debug_svg(layout: &ErDiagramLayout, options: &SvgRenderOptions) -> String {
958 er::render_er_diagram_debug_svg(layout, options)
959}
960
961pub fn render_er_diagram_svg(
962 layout: &ErDiagramLayout,
963 semantic: &serde_json::Value,
964 effective_config: &serde_json::Value,
965 diagram_title: Option<&str>,
966 measurer: &dyn TextMeasurer,
967 options: &SvgRenderOptions,
968) -> Result<String> {
969 er::render_er_diagram_svg(
970 layout,
971 semantic,
972 effective_config,
973 diagram_title,
974 measurer,
975 options,
976 )
977}
978
979pub fn render_sankey_diagram_svg(
980 layout: &SankeyDiagramLayout,
981 _semantic: &serde_json::Value,
982 effective_config: &serde_json::Value,
983 options: &SvgRenderOptions,
984) -> Result<String> {
985 sankey::render_sankey_diagram_svg(layout, _semantic, effective_config, options)
986}
987
988fn curve_monotone_path_d(points: &[crate::model::LayoutPoint], swap_xy: bool) -> String {
989 curve::curve_monotone_path_d(points, swap_xy)
990}
991
992fn curve_monotone_x_path_d(points: &[crate::model::LayoutPoint]) -> String {
993 curve_monotone_path_d(points, false)
994}
995
996fn curve_monotone_y_path_d(points: &[crate::model::LayoutPoint]) -> String {
997 curve_monotone_path_d(points, true)
998}
999
1000fn curve_basis_path_d(points: &[crate::model::LayoutPoint]) -> String {
1002 curve::curve_basis_path_d(points)
1003}
1004
1005fn curve_linear_path_d(points: &[crate::model::LayoutPoint]) -> String {
1006 curve::curve_linear_path_d(points)
1007}
1008
1009fn curve_natural_path_d(points: &[crate::model::LayoutPoint]) -> String {
1010 curve::curve_natural_path_d(points)
1011}
1012
1013fn curve_bump_y_path_d(points: &[crate::model::LayoutPoint]) -> String {
1015 curve::curve_bump_y_path_d(points)
1016}
1017
1018fn curve_catmull_rom_path_d(points: &[crate::model::LayoutPoint]) -> String {
1020 curve::curve_catmull_rom_path_d(points)
1021}
1022
1023fn curve_step_after_path_d(points: &[crate::model::LayoutPoint]) -> String {
1025 curve::curve_step_after_path_d(points)
1026}
1027
1028fn curve_step_before_path_d(points: &[crate::model::LayoutPoint]) -> String {
1030 curve::curve_step_before_path_d(points)
1031}
1032
1033fn curve_step_path_d(points: &[crate::model::LayoutPoint]) -> String {
1035 curve::curve_step_path_d(points)
1036}
1037
1038fn curve_cardinal_path_d(points: &[crate::model::LayoutPoint], tension: f64) -> String {
1040 curve::curve_cardinal_path_d(points, tension)
1041}
1042fn render_node(out: &mut String, n: &LayoutNode) {
1043 layout_debug::render_node(out, n)
1044}
1045
1046fn render_state_node(out: &mut String, n: &LayoutNode) {
1047 layout_debug::render_state_node(out, n)
1048}
1049
1050fn render_cluster(out: &mut String, c: &LayoutCluster, include_markers: bool) {
1051 layout_debug::render_cluster(out, c, include_markers)
1052}
1053
1054fn compute_layout_bounds(
1055 clusters: &[LayoutCluster],
1056 nodes: &[LayoutNode],
1057 edges: &[crate::model::LayoutEdge],
1058) -> Option<Bounds> {
1059 layout_debug::compute_layout_bounds(clusters, nodes, edges)
1060}