From 2c5c2d239c81d4119ad3bf69ceca3e8d2f21f143 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 13 Jun 2020 22:03:48 -0400 Subject: [PATCH] Add a special case to not render anything if the method parameter to the math helper is a template to match the official DustJS implementation. --- src/renderer/parameters_context.rs | 56 ++++++++++++++++++------------ src/renderer/renderer.rs | 25 +++++++++++-- 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index 461b732..25695e0 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -24,7 +24,7 @@ use std::collections::HashMap; #[derive(Debug)] pub struct ParametersContext<'a> { parent: Option<&'a ParametersContext<'a>>, - params: HashMap<&'a str, Option>>, + params: HashMap<&'a str, (&'a RValue<'a>, Option>)>, } impl<'a> ParametersContext<'a> { @@ -42,25 +42,26 @@ impl<'a> ParametersContext<'a> { // then those are resolved at the time of access rather than // the time of assignment, so we leave them into their // original IntoContextElement state. - let rendered_params: HashMap<&'a str, Option>> = params - .iter() - .map(|kvpair| { - let k = kvpair.key; - let v: Option> = match &kvpair.value { - RValue::RVLiteral(_owned_literal) => { - Some(BreadcrumbTreeElement::from_borrowed(&kvpair.value)) - } - RValue::RVPath(_path) => kvpair - .value - .into_context_element(renderer, breadcrumbs) - .map(std::convert::From::from), - RValue::RVTemplate(_template) => { - Some(BreadcrumbTreeElement::from_borrowed(&kvpair.value)) - } - }; - (k, v) - }) - .collect(); + let rendered_params: HashMap<&'a str, (&'a RValue<'a>, Option>)> = + params + .iter() + .map(|kvpair| { + let k = kvpair.key; + let v: Option> = match &kvpair.value { + RValue::RVLiteral(_owned_literal) => { + Some(BreadcrumbTreeElement::from_borrowed(&kvpair.value)) + } + RValue::RVPath(_path) => kvpair + .value + .into_context_element(renderer, breadcrumbs) + .map(std::convert::From::from), + RValue::RVTemplate(_template) => { + Some(BreadcrumbTreeElement::from_borrowed(&kvpair.value)) + } + }; + (k, (&kvpair.value, v)) + }) + .collect(); ParametersContext { parent: parent, @@ -70,7 +71,7 @@ impl<'a> ParametersContext<'a> { pub fn from_values( parent: Option<&'a ParametersContext<'a>>, - params: HashMap<&'a str, Option>>, + params: HashMap<&'a str, (&'a RValue<'a>, Option>)>, ) -> Self { ParametersContext { parent: parent, @@ -85,6 +86,17 @@ impl<'a> ParametersContext<'a> { .map(|p| p.contains_key(segment)) .unwrap_or(false) } + + pub fn get_original_rvalue(&self, segment: &str) -> Option<&'a RValue<'a>> { + self.params + .get(segment) + .map(|(rvalue, _bte)| *rvalue) + .or_else(|| { + self.parent + .map(|p| p.get_original_rvalue(segment)) + .flatten() + }) + } } impl<'a> IntoContextElement for ParametersContext<'a> { @@ -99,7 +111,7 @@ impl<'a> IntoContextElement for ParametersContext<'a> { impl<'a> Walkable for ParametersContext<'a> { fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> { - match self.params.get(segment) { + match self.params.get(segment).map(|(_rvalue, bte)| bte) { Some(Some(bte)) => Ok(bte.borrow()), Some(None) => Err(WalkError::CantWalk), None => self diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index 002e78e..8801ed7 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -5,6 +5,7 @@ use crate::parser::Filter; use crate::parser::OwnedLiteral; use crate::parser::PartialNameElement; use crate::parser::Path; +use crate::parser::RValue; use crate::parser::Special; use crate::parser::Template; use crate::parser::TemplateElement; @@ -675,8 +676,13 @@ impl<'a> DustRenderer<'a> { // Generate a ParametersContext with the result of the math operation as key let converted_value: BreadcrumbTreeElement<'_> = calculated_value.into(); - let calculated_param_map: HashMap<&str, Option>> = - vec![("key", Some(converted_value))].into_iter().collect(); + let dummy_rvalue = RValue::RVLiteral(OwnedLiteral::LPositiveInteger(0)); + let calculated_param_map: HashMap< + &str, + (&RValue<'_>, Option>), + > = vec![("key", (&dummy_rvalue, Some(converted_value)))] + .into_iter() + .collect(); let calculated_context = ParametersContext::from_values(None, calculated_param_map); // calculate are_any_checks_true @@ -982,6 +988,21 @@ impl<'a> DustRenderer<'a> { breadcrumbs: &'a Vec>, math_parameters: &'a ParametersContext<'a>, ) -> Option> { + // Special case: if method is a template then do not render + // anything. This is to match the behavior of dustjs even + // though it works fine. + match math_parameters.get_original_rvalue("method") { + Some(RValue::RVTemplate(template)) => { + if template.iter().any(|pne| match pne { + PartialNameElement::PNReference { .. } => true, + PartialNameElement::PNSpan { .. } => false, + }) { + return None; + } + } + _ => (), + } + let method = match self.tap(breadcrumbs, math_parameters, "method") { None | Some(Err(_)) => return None, Some(Ok(ice_result)) => ice_result,