forge_tree/generator/
template_engine.rs1use crate::{Result, ForgeTreeError};
2use handlebars::Handlebars;
3use serde_json::Value;
4use std::collections::HashMap;
5
6pub struct TemplateEngine {
7 handlebars: Handlebars<'static>,
8}
9
10impl TemplateEngine {
11 pub fn new() -> Self {
12 let mut handlebars = Handlebars::new();
13
14 handlebars.register_helper("uppercase", Box::new(uppercase_helper));
16 handlebars.register_helper("lowercase", Box::new(lowercase_helper));
17 handlebars.register_helper("snake_case", Box::new(snake_case_helper));
18 handlebars.register_helper("pascal_case", Box::new(pascal_case_helper));
19
20 Self { handlebars }
21 }
22
23 pub fn render_template(&self, template: &str, variables: &HashMap<String, String>) -> Result<String> {
24 let json_vars: Value = serde_json::to_value(variables)
25 .map_err(|e| ForgeTreeError::Parse(format!("Failed to serialize variables: {}", e)))?;
26
27 self.handlebars
29 .render_template(template, &json_vars)
30 .map_err(ForgeTreeError::TemplateRender)
31 }
32
33 pub fn register_template(&mut self, name: &str, template: &str) -> Result<()> {
34 self.handlebars
36 .register_template_string(name, template)
37 .map_err(ForgeTreeError::TemplateParse)
38 }
39}
40
41fn uppercase_helper(
43 h: &handlebars::Helper,
44 _: &Handlebars,
45 _: &handlebars::Context,
46 _: &mut handlebars::RenderContext,
47 out: &mut dyn handlebars::Output,
48) -> handlebars::HelperResult {
49 let param = h.param(0)
50 .and_then(|v| v.value().as_str())
51 .unwrap_or("");
52 out.write(¶m.to_uppercase())?;
53 Ok(())
54}
55
56fn lowercase_helper(
57 h: &handlebars::Helper,
58 _: &Handlebars,
59 _: &handlebars::Context,
60 _: &mut handlebars::RenderContext,
61 out: &mut dyn handlebars::Output,
62) -> handlebars::HelperResult {
63 let param = h.param(0)
64 .and_then(|v| v.value().as_str())
65 .unwrap_or("");
66 out.write(¶m.to_lowercase())?;
67 Ok(())
68}
69
70fn snake_case_helper(
71 h: &handlebars::Helper,
72 _: &Handlebars,
73 _: &handlebars::Context,
74 _: &mut handlebars::RenderContext,
75 out: &mut dyn handlebars::Output,
76) -> handlebars::HelperResult {
77 let param = h.param(0)
78 .and_then(|v| v.value().as_str())
79 .unwrap_or("");
80
81 let snake_case = param
82 .chars()
83 .map(|c| if c.is_uppercase() { format!("_{}", c.to_lowercase()) } else { c.to_string() })
84 .collect::<String>()
85 .trim_start_matches('_')
86 .to_string();
87
88 out.write(&snake_case)?;
89 Ok(())
90}
91
92fn pascal_case_helper(
93 h: &handlebars::Helper,
94 _: &Handlebars,
95 _: &handlebars::Context,
96 _: &mut handlebars::RenderContext,
97 out: &mut dyn handlebars::Output,
98) -> handlebars::HelperResult {
99 let param = h.param(0)
100 .and_then(|v| v.value().as_str())
101 .unwrap_or("");
102
103 let pascal_case = param
104 .split(['_', '-', ' '])
105 .map(|word| {
106 let mut chars = word.chars();
107 match chars.next() {
108 None => String::new(),
109 Some(first) => first.to_uppercase().collect::<String>() + &chars.collect::<String>(),
110 }
111 })
112 .collect::<String>();
113
114 out.write(&pascal_case)?;
115 Ok(())
116}
117
118impl Default for TemplateEngine {
119 fn default() -> Self {
120 Self::new()
121 }
122}