merman_render/presentation/
mod.rs1mod compiler;
4mod presets;
5mod profile;
6mod theme;
7
8pub use presets::{HostThemePreset, ThemePresetDescriptor, theme_preset_descriptors};
9#[cfg(any(
10 feature = "diagram-flowchart",
11 feature = "diagram-swimlane",
12 feature = "diagram-agentflow"
13))]
14pub(crate) use profile::FlowchartPresentationPolicy;
15pub use profile::{
16 Presentation, PresentationAspectApplicability, PresentationAspectDescriptor,
17 PresentationAspectResolution, PresentationAspectState, PresentationProfile,
18 PresentationProfileDescriptor, PresentationRenderPolicy, ResolvedPresentation,
19 presentation_profile_descriptors,
20};
21pub use theme::{HostTheme, HostThemeAppearance, ThemeRole};
22
23#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
24#[non_exhaustive]
25pub enum PresentationError {
26 #[error("unknown host theme preset `{0}`")]
27 UnknownThemePreset(String),
28 #[error("unknown presentation profile `{0}`")]
29 UnknownPresentationProfile(String),
30 #[error("unknown theme role `{0}`")]
31 UnknownThemeRole(String),
32 #[error("{field} must be a non-empty single CSS declaration value")]
33 InvalidCssValue { field: String },
34}
35
36fn css_declaration_value(
37 value: impl Into<String>,
38 field: &str,
39) -> Result<String, PresentationError> {
40 let value = value.into();
41 let trimmed = value.trim();
42 let invalid = trimmed.is_empty()
43 || trimmed
44 .chars()
45 .any(|ch| ch.is_control() || matches!(ch, ';' | '"' | '\'' | '<' | '>' | '{' | '}'));
46 if invalid {
47 return Err(PresentationError::InvalidCssValue {
48 field: field.to_string(),
49 });
50 }
51 Ok(trimmed.to_string())
52}
53
54fn css_font_family(value: impl Into<String>, field: &str) -> Result<String, PresentationError> {
55 let value = value.into();
56 let trimmed = value.trim();
57 let invalid = trimmed.is_empty()
58 || trimmed
59 .chars()
60 .any(|ch| ch.is_control() || matches!(ch, ';' | '<' | '>' | '{' | '}'));
61 if invalid {
62 return Err(PresentationError::InvalidCssValue {
63 field: field.to_string(),
64 });
65 }
66 Ok(trimmed.to_string())
67}