1use std::sync::Arc;
15
16use camel_component_api::{CamelError, ComponentBundle, ComponentRegistrar};
17use camel_language_api::MinijinjaLimitsConfig;
18use serde::Deserialize;
19
20use crate::component::TemplateComponent;
21use crate::config::ExternalTemplateLimitsConfig;
22
23#[derive(Debug, Default, Deserialize)]
33#[serde(rename_all = "kebab-case", deny_unknown_fields)]
34pub struct TemplateBundleConfig {
35 #[serde(default)]
37 pub limits: ExternalTemplateLimitsConfig,
38
39 #[serde(default)]
41 pub render_limits: MinijinjaLimitsConfig,
42}
43
44pub struct TemplateBundle {
50 config: TemplateBundleConfig,
51}
52
53impl ComponentBundle for TemplateBundle {
54 fn config_key() -> &'static str {
55 "template"
56 }
57
58 fn from_toml(value: toml::Value) -> Result<Self, CamelError> {
59 let config: TemplateBundleConfig = value
60 .try_into()
61 .map_err(|e: toml::de::Error| CamelError::Config(e.to_string()))?;
62 Ok(Self { config })
63 }
64
65 fn register_all(self, ctx: &mut dyn ComponentRegistrar) {
66 let component = TemplateComponent::new(self.config.limits, self.config.render_limits);
67 ctx.register_component_dyn(Arc::new(component));
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 struct TestRegistrar {
76 schemes: Vec<String>,
77 }
78
79 impl ComponentRegistrar for TestRegistrar {
80 fn register_component_dyn(&mut self, component: Arc<dyn camel_component_api::Component>) {
81 self.schemes.push(component.scheme().to_string());
82 }
83 }
84
85 #[test]
86 fn config_key_is_template() {
87 assert_eq!(TemplateBundle::config_key(), "template");
88 }
89
90 #[test]
91 fn from_toml_empty_uses_defaults() {
92 let value: toml::Value = toml::from_str("").unwrap();
93 let bundle = TemplateBundle::from_toml(value);
94 assert!(bundle.is_ok(), "empty TOML must use defaults");
95 }
96
97 #[test]
98 fn from_toml_parses_both_limit_layers() {
99 let raw = r#"
100limits.max-include-count = 8
101render-limits.fuel = 1234
102"#;
103 let value: toml::Value = toml::from_str(raw).unwrap();
104 let bundle = TemplateBundle::from_toml(value).expect("both limit layers must deserialize");
105 assert_eq!(bundle.config.limits.max_include_count, Some(8));
106 assert_eq!(bundle.config.render_limits.fuel, Some(1234));
107 }
108
109 #[test]
110 fn from_toml_rejects_unknown_field() {
111 let raw = "bogus = 1\n";
112 let value: toml::Value = toml::from_str(raw).unwrap();
113 let result = TemplateBundle::from_toml(value);
114 assert!(result.is_err(), "deny_unknown_fields must reject `bogus`");
115 }
116
117 #[test]
118 fn register_all_registers_template_scheme() {
119 let bundle = TemplateBundle::from_toml(toml::Value::Table(toml::map::Map::new())).unwrap();
120 let mut registrar = TestRegistrar { schemes: vec![] };
121 bundle.register_all(&mut registrar);
122 assert_eq!(registrar.schemes, vec!["template"]);
123 }
124}