bomboni_template/helpers/
string.rs1use crate::helpers::utility::get_param_opt;
2use crate::helpers::utility::get_param_value;
3use convert_case::{Case, Casing};
4use handlebars::{Context, Handlebars, Helper, HelperResult, Output, RenderContext};
5use std::collections::BTreeMap;
6
7use super::utility::get_param;
8
9pub const UPPER_CASE_HELPER_NAME: &str = "upperCase";
10pub const LOWER_CASE_HELPER_NAME: &str = "lowerCase";
11pub const TITLE_CASE_HELPER_NAME: &str = "titleCase";
12pub const TOGGLE_CASE_HELPER_NAME: &str = "toggleCase";
13pub const ALTERNATING_CASE_HELPER_NAME: &str = "alternatingCase";
14pub const CAMEL_CASE_HELPER_NAME: &str = "camelCase";
15pub const PASCAL_CASE_HELPER_NAME: &str = "pascalCase";
16pub const UPPER_CAMEL_CASE_HELPER_NAME: &str = "upperCamelCase";
17pub const SNAKE_CASE_HELPER_NAME: &str = "snakeCase";
18pub const UPPER_SNAKE_CASE_HELPER_NAME: &str = "upperSnakeCase";
19pub const SCREAMING_SNAKE_CASE_HELPER_NAME: &str = "screamingSnakeCase";
20pub const KEBAB_CASE_HELPER_NAME: &str = "kebabCase";
21pub const COBOL_CASE_HELPER_NAME: &str = "cobolCase";
22pub const TRAIN_CASE_HELPER_NAME: &str = "trainCase";
23pub const FLAT_CASE_HELPER_NAME: &str = "flatCase";
24pub const UPPER_FLAT_CASE_HELPER_NAME: &str = "upperFlatCase";
25
26pub const TO_STRING_HELPER_NAME: &str = "toString";
27pub const TO_JSON_HELPER_NAME: &str = "toJson";
28pub const CONCAT_HELPER_NAME: &str = "concat";
29pub const TO_INTEGER_STRING_HELPER_NAME: &str = "toIntegerString";
30
31pub fn register_string_helpers(handlebars_registry: &mut Handlebars) {
32    register_string_helpers_with_name_map(handlebars_registry, BTreeMap::default());
33}
34
35pub fn register_string_helpers_with_name_map(
36    handlebars_registry: &mut Handlebars,
37    name_map: BTreeMap<String, String>,
38) {
39    macro_rules! name {
40        ($name:expr) => {
41            name_map.get($name).map(String::as_str).unwrap_or($name)
42        };
43    }
44    macro_rules! register_case_helper {
45        ($($name:ident),* $(,)?) => {
46            $(
47                handlebars_registry.register_helper(
48                    name!($name),
49                    Box::new(convert_case_helper),
50                );
51            )*
52        };
53    }
54    register_case_helper!(
55        UPPER_CASE_HELPER_NAME,
56        LOWER_CASE_HELPER_NAME,
57        TITLE_CASE_HELPER_NAME,
58        TOGGLE_CASE_HELPER_NAME,
59        ALTERNATING_CASE_HELPER_NAME,
60        CAMEL_CASE_HELPER_NAME,
61        PASCAL_CASE_HELPER_NAME,
62        UPPER_CAMEL_CASE_HELPER_NAME,
63        SNAKE_CASE_HELPER_NAME,
64        UPPER_SNAKE_CASE_HELPER_NAME,
65        SCREAMING_SNAKE_CASE_HELPER_NAME,
66        KEBAB_CASE_HELPER_NAME,
67        COBOL_CASE_HELPER_NAME,
68        TRAIN_CASE_HELPER_NAME,
69        FLAT_CASE_HELPER_NAME,
70        UPPER_FLAT_CASE_HELPER_NAME,
71    );
72
73    handlebars_registry.register_helper(name!(TO_STRING_HELPER_NAME), Box::new(to_string_helper));
74    handlebars_registry.register_helper(name!(TO_JSON_HELPER_NAME), Box::new(to_json_helper));
75    handlebars_registry.register_helper(name!(CONCAT_HELPER_NAME), Box::new(concat_helper));
76    handlebars_registry.register_helper(
77        name!(TO_INTEGER_STRING_HELPER_NAME),
78        Box::new(to_integer_string_helper),
79    );
80}
81
82fn convert_case_helper(
83    h: &Helper,
84    _: &Handlebars,
85    _: &Context,
86    _: &mut RenderContext,
87    out: &mut dyn Output,
88) -> HelperResult {
89    let value = get_param_value(h, 0, "value")?;
90    let value = if let Some(s) = value.as_str() {
91        s.to_string()
92    } else {
93        value.to_string()
94    };
95    out.write(&match h.name() {
96        UPPER_CASE_HELPER_NAME => value.to_case(Case::Upper),
97        LOWER_CASE_HELPER_NAME => value.to_case(Case::Lower),
98        TITLE_CASE_HELPER_NAME => value.to_case(Case::Title),
99        TOGGLE_CASE_HELPER_NAME => value.to_case(Case::Toggle),
100        ALTERNATING_CASE_HELPER_NAME => value.to_case(Case::Alternating),
101        CAMEL_CASE_HELPER_NAME => value.to_case(Case::Camel),
102        PASCAL_CASE_HELPER_NAME => value.to_case(Case::Pascal),
103        UPPER_CAMEL_CASE_HELPER_NAME => value.to_case(Case::UpperCamel),
104        SNAKE_CASE_HELPER_NAME => value.to_case(Case::Snake),
105        UPPER_SNAKE_CASE_HELPER_NAME => value.to_case(Case::UpperSnake),
106        SCREAMING_SNAKE_CASE_HELPER_NAME => value.to_case(Case::ScreamingSnake),
107        KEBAB_CASE_HELPER_NAME => value.to_case(Case::Kebab),
108        COBOL_CASE_HELPER_NAME => value.to_case(Case::Cobol),
109        TRAIN_CASE_HELPER_NAME => value.to_case(Case::Train),
110        FLAT_CASE_HELPER_NAME => value.to_case(Case::Flat),
111        UPPER_FLAT_CASE_HELPER_NAME => value.to_case(Case::UpperFlat),
112        _ => unreachable!("helper `{}` not implemented", h.name()),
113    })?;
114
115    Ok(())
116}
117
118fn to_string_helper(
119    h: &Helper,
120    _: &Handlebars,
121    _: &Context,
122    _: &mut RenderContext,
123    out: &mut dyn Output,
124) -> HelperResult {
125    let value = get_param_value(h, 0, "value")?;
126    if let Some(s) = value.as_str() {
127        out.write(s)?;
128    } else {
129        out.write(&value.to_string())?;
130    }
131    Ok(())
132}
133
134fn to_json_helper(
135    h: &Helper,
136    _: &Handlebars,
137    _: &Context,
138    _: &mut RenderContext,
139    out: &mut dyn Output,
140) -> HelperResult {
141    let value = get_param_value(h, 0, "value")?;
142    let pretty: bool = get_param_opt(h, 1, "pretty")?.unwrap_or_default();
143
144    out.write(
145        &(if pretty {
146            serde_json::to_string_pretty(value)
147        } else {
148            serde_json::to_string(value)
149        })
150        .unwrap(),
151    )?;
152
153    Ok(())
154}
155
156fn concat_helper(
157    h: &Helper,
158    _: &Handlebars,
159    _: &Context,
160    _: &mut RenderContext,
161    out: &mut dyn Output,
162) -> HelperResult {
163    let mut buf = String::new();
164    for param in h.params().iter().map(handlebars::PathAndJson::value) {
165        if let Some(s) = param.as_str() {
166            buf.push_str(s);
167        } else {
168            buf.push_str(¶m.to_string());
169        }
170    }
171    out.write(&buf)?;
172    Ok(())
173}
174
175fn to_integer_string_helper(
176    h: &Helper,
177    _: &Handlebars,
178    _: &Context,
179    _: &mut RenderContext,
180    out: &mut dyn Output,
181) -> HelperResult {
182    let value: f64 = get_param(h, 0, "value")?;
183    out.write(&(value.trunc() as i64).to_string())?;
184    Ok(())
185}
186
187#[cfg(test)]
188mod tests {
189    use super::*;
190    use serde_json::Value;
191
192    #[test]
193    fn convert_case() {
194        let r = get_handlebars_registry();
195        macro_rules! assert_case {
196            ($case:expr, $source:expr, $expected:expr $(,)?) => {
197                assert_eq!(
198                    r.render_template(
199                        &format!(r#"{{{{{} "{}" }}}}"#, $case, $source),
200                        &Value::Null
201                    )
202                    .unwrap()
203                    .as_str(),
204                    $expected
205                );
206            };
207        }
208
209        assert_case!(UPPER_CASE_HELPER_NAME, "variable name", "VARIABLE NAME");
210        assert_case!(PASCAL_CASE_HELPER_NAME, "variable name", "VariableName");
211        assert_case!(
212            SCREAMING_SNAKE_CASE_HELPER_NAME,
213            "variable name",
214            "VARIABLE_NAME"
215        );
216        assert_case!(CAMEL_CASE_HELPER_NAME, "variable name", "variableName");
217    }
218
219    #[test]
220    fn printing() {
221        let r = get_handlebars_registry();
222        macro_rules! assert_print {
223            ($expr:expr, $result:expr) => {
224                assert_eq!(r.render_template($expr, &Value::Null).unwrap(), $result);
225            };
226        }
227
228        assert_print!(r"{{toIntegerString 3.14}}", "3");
229    }
230
231    fn get_handlebars_registry() -> Handlebars<'static> {
232        let mut r = Handlebars::new();
233        r.set_strict_mode(true);
234        register_string_helpers(&mut r);
235        r
236    }
237}