diff --git a/src/parser/parser.rs b/src/parser/parser.rs index f9fe91d..04204b6 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -110,6 +110,7 @@ pub struct NamedBlock<'a> { #[derive(Clone, Debug, PartialEq)] pub struct ParameterizedBlock<'a> { pub name: &'a str, + pub explicit_context: Option>, pub params: Vec>, pub contents: Option>, pub else_contents: Option>, @@ -482,25 +483,28 @@ where F: Fn(ParameterizedBlock<'a>) -> DustTag<'a>, { move |i: &'a str| { - let (i, (name, params, inner, maybe_else, _closing_name)) = tuple(( - preceded(tag(open_matcher), tag(tag_name)), - terminated( - opt(delimited( - space1, - separated_list1(space1, key_value_pair), - space0, - )), - tag("}"), - ), - opt(body), - opt(preceded(tag("{:else}"), opt(body))), - delimited(tag("{/"), tag(tag_name), tag("}")), - ))(i)?; + let (i, (name, maybe_explicit_context, params, inner, maybe_else, _closing_name)) = + tuple(( + preceded(tag(open_matcher), tag(tag_name)), + opt(preceded(tag(":"), path)), + terminated( + opt(delimited( + space1, + separated_list1(space1, key_value_pair), + space0, + )), + tag("}"), + ), + opt(body), + opt(preceded(tag("{:else}"), opt(body))), + delimited(tag("{/"), tag(tag_name), tag("}")), + ))(i)?; Ok(( i, constructor(ParameterizedBlock { name: name, + explicit_context: maybe_explicit_context, params: params.unwrap_or(Vec::new()), contents: inner, else_contents: maybe_else.flatten(), @@ -518,10 +522,11 @@ where F: Fn(ParameterizedBlock<'a>) -> DustTag<'a>, { move |i: &'a str| { - let (i, (name, params)) = delimited( + let (i, (name, maybe_explicit_context, params)) = delimited( tag(open_matcher), tuple(( tag(tag_name), + opt(preceded(tag(":"), path)), opt(delimited( space1, separated_list1(space1, key_value_pair), @@ -535,6 +540,7 @@ where i, constructor(ParameterizedBlock { name: name, + explicit_context: maybe_explicit_context, params: params.unwrap_or(Vec::new()), contents: None, else_contents: None, @@ -1323,6 +1329,7 @@ mod tests { "", DustTag::DTHelperEquals(ParameterizedBlock { name: "eq", + explicit_context: None, params: vec![ KVPair { key: "key", @@ -1359,6 +1366,74 @@ mod tests { "", DustTag::DTHelperEquals(ParameterizedBlock { name: "eq", + explicit_context: None, + params: vec![ + KVPair { + key: "key", + value: RValue::RVPath(Path { keys: vec!["name"] }) + }, + KVPair { + key: "value", + value: RValue::RVLiteral(OwnedLiteral::LString("cat".to_owned())) + } + ], + contents: None, + else_contents: None + }) + )) + ); + } + + #[test] + fn test_helper_with_explicit_context() { + assert_eq!( + dust_tag(r#"{@eq:foo.bar key=name value="cat"}Pet the {name}!{/eq}"#), + Ok(( + "", + DustTag::DTHelperEquals(ParameterizedBlock { + name: "eq", + explicit_context: Some(Path { + keys: vec!["foo", "bar"] + }), + params: vec![ + KVPair { + key: "key", + value: RValue::RVPath(Path { keys: vec!["name"] }) + }, + KVPair { + key: "value", + value: RValue::RVLiteral(OwnedLiteral::LString("cat".to_owned())) + } + ], + contents: Some(Body { + elements: vec![ + TemplateElement::TESpan(Span { + contents: "Pet the " + }), + TemplateElement::TETag(DustTag::DTReference(Reference { + path: Path { keys: vec!["name"] }, + filters: Vec::new() + })), + TemplateElement::TESpan(Span { contents: "!" }) + ] + }), + else_contents: None + }) + )) + ); + } + + #[test] + fn test_self_closing_helper_with_explicit_context() { + assert_eq!( + dust_tag(r#"{@eq:foo.bar key=name value="cat"/}"#), + Ok(( + "", + DustTag::DTHelperEquals(ParameterizedBlock { + name: "eq", + explicit_context: Some(Path { + keys: vec!["foo", "bar"] + }), params: vec![ KVPair { key: "key",