Skip to main content

merman_render/svg/pipeline/
context.rs

1use super::builtin::util::extract_root_svg_id;
2use super::preset::SvgPipelinePreset;
3
4#[derive(Debug, Clone, Default, PartialEq, Eq)]
5pub struct SvgPostprocessMetadata {
6    diagram_type: Option<String>,
7    diagram_title: Option<String>,
8    svg_id: Option<String>,
9}
10
11impl SvgPostprocessMetadata {
12    pub fn new() -> Self {
13        Self::default()
14    }
15
16    pub fn from_svg(svg: &str) -> Self {
17        Self {
18            svg_id: extract_root_svg_id(svg),
19            ..Self::default()
20        }
21    }
22
23    pub fn with_diagram_type(mut self, diagram_type: impl Into<String>) -> Self {
24        self.diagram_type = Some(diagram_type.into());
25        self
26    }
27
28    pub fn with_optional_diagram_type(mut self, diagram_type: Option<impl Into<String>>) -> Self {
29        self.diagram_type = diagram_type.map(Into::into);
30        self
31    }
32
33    pub fn with_diagram_title(mut self, diagram_title: impl Into<String>) -> Self {
34        self.diagram_title = Some(diagram_title.into());
35        self
36    }
37
38    pub fn with_optional_diagram_title(mut self, diagram_title: Option<impl Into<String>>) -> Self {
39        self.diagram_title = diagram_title.map(Into::into);
40        self
41    }
42
43    pub fn with_svg_id(mut self, svg_id: impl Into<String>) -> Self {
44        self.svg_id = Some(svg_id.into());
45        self
46    }
47
48    pub fn with_optional_svg_id(mut self, svg_id: Option<impl Into<String>>) -> Self {
49        if let Some(svg_id) = svg_id {
50            self.svg_id = Some(svg_id.into());
51        }
52        self
53    }
54
55    pub fn diagram_type(&self) -> Option<&str> {
56        self.diagram_type.as_deref()
57    }
58
59    pub fn diagram_title(&self) -> Option<&str> {
60        self.diagram_title.as_deref()
61    }
62
63    pub fn svg_id(&self) -> Option<&str> {
64        self.svg_id.as_deref()
65    }
66}
67
68#[derive(Debug, Clone, Copy)]
69pub struct SvgPostprocessContext<'a> {
70    preset: SvgPipelinePreset,
71    pass_index: usize,
72    pass_name: &'a str,
73    metadata: &'a SvgPostprocessMetadata,
74}
75
76impl<'a> SvgPostprocessContext<'a> {
77    pub(crate) fn new(
78        preset: SvgPipelinePreset,
79        pass_index: usize,
80        pass_name: &'a str,
81        metadata: &'a SvgPostprocessMetadata,
82    ) -> Self {
83        Self {
84            preset,
85            pass_index,
86            pass_name,
87            metadata,
88        }
89    }
90
91    pub fn preset(&self) -> SvgPipelinePreset {
92        self.preset
93    }
94
95    pub fn pass_index(&self) -> usize {
96        self.pass_index
97    }
98
99    pub fn pass_name(&self) -> &'a str {
100        self.pass_name
101    }
102
103    pub fn diagram_type(&self) -> Option<&'a str> {
104        self.metadata.diagram_type()
105    }
106
107    pub fn diagram_title(&self) -> Option<&'a str> {
108        self.metadata.diagram_title()
109    }
110
111    pub fn svg_id(&self) -> Option<&'a str> {
112        self.metadata.svg_id()
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn metadata_extracts_root_svg_id() {
122        let metadata = SvgPostprocessMetadata::from_svg(
123            r#"<svg xmlns="http://www.w3.org/2000/svg" id="diagram-1"><g/></svg>"#,
124        );
125
126        assert_eq!(metadata.svg_id(), Some("diagram-1"));
127    }
128
129    #[test]
130    fn metadata_ignores_non_root_ids() {
131        let metadata = SvgPostprocessMetadata::from_svg(r#"<g id="nested"></g>"#);
132
133        assert_eq!(metadata.svg_id(), None);
134    }
135}