diff options
Diffstat (limited to 'vendor/handlebars/src/render.rs')
-rw-r--r-- | vendor/handlebars/src/render.rs | 93 |
1 files changed, 81 insertions, 12 deletions
diff --git a/vendor/handlebars/src/render.rs b/vendor/handlebars/src/render.rs index 188ea221a..036352b3a 100644 --- a/vendor/handlebars/src/render.rs +++ b/vendor/handlebars/src/render.rs @@ -14,6 +14,7 @@ use crate::json::value::{JsonRender, PathAndJson, ScopedJson}; use crate::output::{Output, StringOutput}; use crate::partial; use crate::registry::Registry; +use crate::support; use crate::template::TemplateElement::*; use crate::template::{ BlockParam, DecoratorTemplate, HelperTemplate, Parameter, Template, TemplateElement, @@ -47,10 +48,11 @@ pub struct RenderContextInner<'reg: 'rc, 'rc> { /// root template name root_template: Option<&'reg String>, disable_escape: bool, + indent_string: Option<&'reg String>, } impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { - /// Create a render context from a `Write` + /// Create a render context pub fn new(root_template: Option<&'reg String>) -> RenderContext<'reg, 'rc> { let inner = Rc::new(RenderContextInner { partials: BTreeMap::new(), @@ -60,6 +62,7 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { current_template: None, root_template, disable_escape: false, + indent_string: None, }); let mut blocks = VecDeque::with_capacity(5); @@ -73,7 +76,6 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { } } - // TODO: better name pub(crate) fn new_for_block(&self) -> RenderContext<'reg, 'rc> { let inner = self.inner.clone(); @@ -101,6 +103,10 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { self.blocks.pop_front(); } + pub(crate) fn clear_blocks(&mut self) { + self.blocks.clear(); + } + /// Borrow a reference to current block context pub fn block(&self) -> Option<&BlockContext<'reg>> { self.blocks.front() @@ -190,7 +196,19 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { } pub(crate) fn dec_partial_block_depth(&mut self) { - self.inner_mut().partial_block_depth -= 1; + let depth = &mut self.inner_mut().partial_block_depth; + if *depth > 0 { + *depth -= 1; + } + } + + pub(crate) fn set_indent_string(&mut self, indent: Option<&'reg String>) { + self.inner_mut().indent_string = indent; + } + + #[inline] + pub(crate) fn get_indent_string(&self) -> Option<&'reg String> { + self.inner.indent_string } /// Remove a registered partial @@ -201,7 +219,7 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { fn get_local_var(&self, level: usize, name: &str) -> Option<&Json> { self.blocks .get(level) - .and_then(|blk| blk.get_local_var(&name)) + .and_then(|blk| blk.get_local_var(name)) } /// Test if given template name is current template. @@ -275,9 +293,10 @@ impl<'reg, 'rc> fmt::Debug for RenderContextInner<'reg, 'rc> { f.debug_struct("RenderContextInner") .field("partials", &self.partials) .field("partial_block_stack", &self.partial_block_stack) + .field("partial_block_depth", &self.partial_block_depth) .field("root_template", &self.root_template) .field("current_template", &self.current_template) - .field("disable_eacape", &self.disable_escape) + .field("disable_escape", &self.disable_escape) .finish() } } @@ -435,6 +454,7 @@ pub struct Decorator<'reg, 'rc> { params: Vec<PathAndJson<'reg, 'rc>>, hash: BTreeMap<&'reg str, PathAndJson<'reg, 'rc>>, template: Option<&'reg Template>, + indent: Option<&'reg String>, } impl<'reg: 'rc, 'rc> Decorator<'reg, 'rc> { @@ -463,6 +483,7 @@ impl<'reg: 'rc, 'rc> Decorator<'reg, 'rc> { params: pv, hash: hm, template: dt.template.as_ref(), + indent: dt.indent.as_ref(), }) } @@ -495,6 +516,10 @@ impl<'reg: 'rc, 'rc> Decorator<'reg, 'rc> { pub fn template(&self) -> Option<&'reg Template> { self.template } + + pub fn indent(&self) -> Option<&'reg String> { + self.indent + } } /// Render trait @@ -747,6 +772,20 @@ pub(crate) fn do_escape(r: &Registry<'_>, rc: &RenderContext<'_, '_>, content: S } } +#[inline] +fn indent_aware_write( + v: &str, + rc: &mut RenderContext<'_, '_>, + out: &mut dyn Output, +) -> Result<(), RenderError> { + if let Some(indent) = rc.get_indent_string() { + out.write(support::str::with_indent(v, indent).as_ref())?; + } else { + out.write(v.as_ref())?; + } + Ok(()) +} + impl Renderable for TemplateElement { fn render<'reg: 'rc, 'rc>( &'reg self, @@ -755,11 +794,8 @@ impl Renderable for TemplateElement { rc: &mut RenderContext<'reg, 'rc>, out: &mut dyn Output, ) -> Result<(), RenderError> { - match *self { - RawString(ref v) => { - out.write(v.as_ref())?; - Ok(()) - } + match self { + RawString(ref v) => indent_aware_write(v.as_ref(), rc, out), Expression(ref ht) | HtmlExpression(ref ht) => { let is_html_expression = matches!(self, HtmlExpression(_)); if is_html_expression { @@ -789,8 +825,7 @@ impl Renderable for TemplateElement { } else { let rendered = context_json.value().render(); let output = do_escape(registry, rc, rendered); - out.write(output.as_ref())?; - Ok(()) + indent_aware_write(output.as_ref(), rc, out) } } } else { @@ -1117,3 +1152,37 @@ fn test_zero_args_heler() { "Output name: first_name not resolved" ); } + +#[test] +fn test_identifiers_starting_with_numbers() { + let mut r = Registry::new(); + + assert!(r + .register_template_string("r1", "{{#if 0a}}true{{/if}}") + .is_ok()); + let r1 = r.render("r1", &json!({"0a": true})).unwrap(); + assert_eq!(r1, "true"); + + assert!(r.register_template_string("r2", "{{eq 1a 1}}").is_ok()); + let r2 = r.render("r2", &json!({"1a": 2, "a": 1})).unwrap(); + assert_eq!(r2, "false"); + + assert!(r + .register_template_string("r3", "0: {{0}} {{#if (eq 0 true)}}resolved from context{{/if}}\n1a: {{1a}} {{#if (eq 1a true)}}resolved from context{{/if}}\n2_2: {{2_2}} {{#if (eq 2_2 true)}}resolved from context{{/if}}") // YUP it is just eq that barfs! is if handled specially? maybe this test should go nearer to specific helpers that fail? + .is_ok()); + let r3 = r + .render("r3", &json!({"0": true, "1a": true, "2_2": true})) + .unwrap(); + assert_eq!( + r3, + "0: true \n1a: true resolved from context\n2_2: true resolved from context" + ); + + // these should all be errors: + assert!(r.register_template_string("r4", "{{eq 1}}").is_ok()); + assert!(r.register_template_string("r5", "{{eq a1}}").is_ok()); + assert!(r.register_template_string("r6", "{{eq 1a}}").is_ok()); + assert!(r.render("r4", &()).is_err()); + assert!(r.render("r5", &()).is_err()); + assert!(r.render("r6", &()).is_err()); +} |