Repository: sunng87/handlebars-rust
Pull request #375 (2020-08-12 01:15:26)

Helper call support in html expression
This is a follow up of #373 that adds helper call support in html expression.

This patch introduces break change in `TemplateElement` API. 


Patch:
diff --git a/src/grammar.pest b/src/grammar.pest
index 415b0a2..3404432 100644
--- a/src/grammar.pest
+++ b/src/grammar.pest
@@ -44,7 +44,8 @@ pro_whitespace_omitter = { "~" }
 expression = { !invert_tag ~ "{{" ~ pre_whitespace_omitter? ~
               ((identifier ~ (hash|param)+) | name )
               ~ pro_whitespace_omitter? ~ "}}" }
-html_expression_triple_bracket = _{ "{{{" ~ pre_whitespace_omitter? ~ name ~
+html_expression_triple_bracket = _{ "{{{" ~ pre_whitespace_omitter? ~
+                                    ((identifier ~ (hash|param)+) | name ) ~
                                     pro_whitespace_omitter? ~ "}}}" }
 amp_expression = _{ "{{" ~ pre_whitespace_omitter? ~ "&" ~ name ~
                        pro_whitespace_omitter? ~ "}}" }
diff --git a/src/grammar.rs b/src/grammar.rs
index 5de84ba..40d526b 100644
--- a/src/grammar.rs
+++ b/src/grammar.rs
@@ -198,7 +198,14 @@ mod test {
 
     #[test]
     fn test_html_expression() {
-        let s = vec!["{{{html}}}", "{{{(html)}}}", "{{{(html)}}}", "{{&html}}"];
+        let s = vec![
+            "{{{html}}}",
+            "{{{(html)}}}",
+            "{{{(html)}}}",
+            "{{&html}}",
+            "{{{html 1}}}",
+            "{{{html p=true}}}",
+        ];
         for i in s.iter() {
             assert_rule!(Rule::html_expression, i);
         }
diff --git a/src/render.rs b/src/render.rs
index 007ec9d..15ad11a 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -731,9 +731,14 @@ impl Renderable for TemplateElement {
                 out.write(v.as_ref())?;
                 Ok(())
             }
-            Expression(ref ht) => {
+            Expression(ref ht) | HTMLExpression(ref ht) => {
+                let is_html_expression = matches!(self, HTMLExpression(_));
+                if is_html_expression {
+                    rc.set_disable_escape(true);
+                }
+
                 // test if the expression is to render some value
-                if ht.is_name_only() {
+                let result = if ht.is_name_only() {
                     let helper_name = ht.name.expand_as_name(registry, ctx, rc)?;
                     if helper_exists(&helper_name, registry, rc) {
                         render_helper(ht, registry, ctx, rc, out)
@@ -762,20 +767,13 @@ impl Renderable for TemplateElement {
                 } else {
                     // this is a helper expression
                     render_helper(ht, registry, ctx, rc, out)
-                }
-            }
-            HTMLExpression(ref v) => {
-                debug!("Rendering value: {:?}", v);
-                let context_json = v.expand(registry, ctx, rc)?;
+                };
 
-                // strict mode check
-                if registry.strict_mode() && context_json.is_value_missing() {
-                    return Err(RenderError::strict_error(context_json.relative_path()));
+                if is_html_expression {
+                    rc.set_disable_escape(false);
                 }
 
-                let rendered = context_json.value().render();
-                out.write(rendered.as_ref())?;
-                Ok(())
+                result
             }
             HelperBlock(ref ht) => render_helper(ht, registry, ctx, rc, out),
             DecoratorExpression(_) | DecoratorBlock(_) => self.eval(registry, ctx, rc),
@@ -855,7 +853,9 @@ fn test_expression() {
 #[test]
 fn test_html_expression() {
     let r = Registry::new();
-    let element = HTMLExpression(Parameter::Path(Path::with_named_paths(&["hello"])));
+    let element = HTMLExpression(Box::new(HelperTemplate::with_path(Path::with_named_paths(
+        &["hello"],
+    ))));
 
     let mut out = StringOutput::new();
     let mut m: BTreeMap<String, String> = BTreeMap::new();
diff --git a/src/template.rs b/src/template.rs
index 79db431..5c81990 100644
--- a/src/template.rs
+++ b/src/template.rs
@@ -598,12 +598,7 @@ impl Template {
                         omit_pro_ws = exp.omit_pro_ws;
 
                         match rule {
-                            Rule::html_expression => {
-                                let el = HTMLExpression(exp.name);
-                                let t = template_stack.front_mut().unwrap();
-                                t.push_element(el, line_no, col_no);
-                            }
-                            Rule::expression => {
+                            Rule::expression | Rule::html_expression => {
                                 let helper_template = HelperTemplate {
                                     name: exp.name,
                                     params: exp.params,
@@ -613,7 +608,11 @@ impl Template {
                                     template: None,
                                     inverse: None,
                                 };
-                                let el = Expression(Box::new(helper_template));
+                                let el = if rule == Rule::expression {
+                                    Expression(Box::new(helper_template))
+                                } else {
+                                    HTMLExpression(Box::new(helper_template))
+                                };
                                 let t = template_stack.front_mut().unwrap();
                                 t.push_element(el, line_no, col_no);
                             }
@@ -733,7 +732,7 @@ impl Template {
 #[derive(PartialEq, Clone, Debug)]
 pub enum TemplateElement {
     RawString(String),
-    HTMLExpression(Parameter),
+    HTMLExpression(Box<HelperTemplate>),
     Expression(Box<HelperTemplate>),
     HelperBlock(Box<HelperTemplate>),
     DecoratorExpression(Box<DecoratorTemplate>),
@@ -792,7 +791,9 @@ fn test_parse_template() {
 
     assert_eq!(
         *t.elements.get(3).unwrap(),
-        HTMLExpression(Parameter::Path(Path::with_named_paths(&["content"])))
+        HTMLExpression(Box::new(HelperTemplate::with_path(Path::with_named_paths(
+            &["content"],
+        ))))
     );
 
     match *t.elements.get(5).unwrap() {


Test patch:
diff --git a/tests/helper_macro.rs b/tests/helper_macro.rs
index 9a845bb..9a8d2dc 100644
--- a/tests/helper_macro.rs
+++ b/tests/helper_macro.rs
@@ -68,4 +68,9 @@ fn test_macro_helper() {
         hbs.render_template("{{tag \"html\"}}", &()).unwrap(),
         "&lt;html&gt;"
     );
+
+    assert_eq!(
+        hbs.render_template("{{{tag \"html\"}}}", &()).unwrap(),
+        "<html>"
+    );
 }