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