2 use std
::iter
::Peekable
;
3 use std
::convert
::From
;
4 use std
::collections
::{BTreeMap, VecDeque}
;
7 use serde_json
::value
::Value
as Json
;
10 use grammar
::{Rdp, Rule}
;
12 use error
::{TemplateError, TemplateErrorReason}
;
14 use self::TemplateElement
::*;
16 #[derive(PartialEq, Clone, Debug)]
17 pub struct TemplateMapping(pub usize, pub usize);
19 /// A handlebars template
20 #[derive(PartialEq, Clone, Debug)]
22 pub name
: Option
<String
>,
23 pub elements
: Vec
<TemplateElement
>,
24 pub mapping
: Option
<Vec
<TemplateMapping
>>,
27 #[derive(PartialEq, Clone, Debug)]
28 pub struct Subexpression
{
30 pub params
: Vec
<Parameter
>,
31 pub hash
: BTreeMap
<String
, Parameter
>,
35 pub fn is_helper(&self) -> bool
{
36 !(self.params
.is_empty() && self.hash
.is_empty())
39 pub fn as_template(&self) -> Template
{
40 let mut t
= Template
::new(false);
41 let el
= if self.is_helper() {
42 HelperExpression(HelperTemplate
::from(self))
44 Expression(Parameter
::Name(self.name
.clone()))
51 #[derive(PartialEq, Clone, Debug)]
54 Pair((Parameter
, Parameter
)),
57 #[derive(PartialEq, Clone, Debug)]
58 pub struct ExpressionSpec
{
60 pub params
: Vec
<Parameter
>,
61 pub hash
: BTreeMap
<String
, Parameter
>,
62 pub block_param
: Option
<BlockParam
>,
63 pub omit_pre_ws
: bool
,
64 pub omit_pro_ws
: bool
,
67 #[derive(PartialEq, Clone, Debug)]
71 Subexpression(Subexpression
),
74 #[derive(PartialEq, Clone, Debug)]
75 pub struct HelperTemplate
{
77 pub params
: Vec
<Parameter
>,
78 pub hash
: BTreeMap
<String
, Parameter
>,
79 pub block_param
: Option
<BlockParam
>,
80 pub template
: Option
<Template
>,
81 pub inverse
: Option
<Template
>,
85 impl<'a
> From
<&'a Subexpression
> for HelperTemplate
{
86 fn from(s
: &Subexpression
) -> HelperTemplate
{
89 params
: s
.params
.clone(),
99 #[derive(PartialEq, Clone, Debug)]
100 pub struct Directive
{
102 pub params
: Vec
<Parameter
>,
103 pub hash
: BTreeMap
<String
, Parameter
>,
104 pub template
: Option
<Template
>,
108 pub fn as_name(self) -> Option
<String
> {
109 if let Parameter
::Name(n
) = self {
116 pub fn parse(s
: &str) -> Result
<Parameter
, TemplateError
> {
117 let mut parser
= Rdp
::new(StringInput
::new(s
));
118 if !parser
.parameter() {
119 return Err(TemplateError
::of(TemplateErrorReason
::InvalidParam(s
.to_owned())));
122 let mut it
= parser
.queue().iter().peekable();
123 Template
::parse_param(s
, &mut it
, s
.len() - 1)
128 pub fn new(mapping
: bool
) -> Template
{
130 elements
: Vec
::new(),
132 mapping
: if mapping { Some(Vec::new()) }
else { None }
,
136 fn push_element(&mut self, e
: TemplateElement
, line
: usize, col
: usize) {
137 self.elements
.push(e
);
138 if let Some(ref mut maps
) = self.mapping
{
139 maps
.push(TemplateMapping(line
, col
));
143 pub fn compile
<S
: AsRef
<str>>(source
: S
) -> Result
<Template
, TemplateError
> {
144 Template
::compile2(source
, false)
148 fn parse_subexpression
<'a
>(source
: &'a
str,
149 it
: &mut Peekable
<Iter
<Token
<Rule
>>>,
151 -> Result
<Parameter
, TemplateError
> {
152 let espec
= try
!(Template
::parse_expression(source
, it
.by_ref(), limit
));
153 if let Parameter
::Name(name
) = espec
.name
{
154 Ok(Parameter
::Subexpression(Subexpression
{
156 params
: espec
.params
,
161 Err(TemplateError
::of(TemplateErrorReason
::NestedSubexpression
))
166 fn parse_name
<'a
>(source
: &'a
str,
167 it
: &mut Peekable
<Iter
<Token
<Rule
>>>,
169 -> Result
<Parameter
, TemplateError
> {
170 let name_node
= it
.next().unwrap();
171 match name_node
.rule
{
174 Rule
::invert_tag_item
=> {
175 Ok(Parameter
::Name(source
[name_node
.start
..name_node
.end
].to_owned()))
177 Rule
::subexpression
=> {
178 Template
::parse_subexpression(source
, it
.by_ref(), name_node
.end
)
185 fn parse_param
<'a
>(source
: &'a
str,
186 it
: &mut Peekable
<Iter
<Token
<Rule
>>>,
188 -> Result
<Parameter
, TemplateError
> {
189 let mut param
= it
.next().unwrap();
190 if param
.rule
== Rule
::param
{
191 param
= it
.next().unwrap();
193 let result
= match param
.rule
{
194 Rule
::reference
=> Parameter
::Name(source
[param
.start
..param
.end
].to_owned()),
196 let s
= &source
[param
.start
..param
.end
];
197 if let Ok(json
) = Json
::from_str(s
) {
198 Parameter
::Literal(json
)
200 Parameter
::Name(s
.to_owned())
203 Rule
::subexpression
=> {
204 try
!(Template
::parse_subexpression(source
, it
.by_ref(), param
.end
))
210 if let Some(ref n
) = it
.peek() {
211 if n
.end
> param
.end
{
225 fn parse_hash
<'a
>(source
: &'a
str,
226 it
: &mut Peekable
<Iter
<Token
<Rule
>>>,
228 -> Result
<(String
, Parameter
), TemplateError
> {
229 let name
= it
.next().unwrap();
231 let key
= source
[name
.start
..name
.end
].to_owned();
233 let value
= try
!(Template
::parse_param(source
, it
.by_ref(), limit
));
238 fn parse_block_param
<'a
>(source
: &'a
str,
239 it
: &mut Peekable
<Iter
<Token
<Rule
>>>,
241 -> Result
<BlockParam
, TemplateError
> {
242 let p1_name
= it
.next().unwrap();
244 let p1
= source
[p1_name
.start
..p1_name
.end
].to_owned();
246 let p2
= it
.peek().and_then(|p2_name
| if p2_name
.end
<= limit
{
247 Some(source
[p2_name
.start
..p2_name
.end
].to_owned())
254 Ok(BlockParam
::Pair((Parameter
::Name(p1
), Parameter
::Name(p2
.unwrap()))))
256 Ok(BlockParam
::Single(Parameter
::Name(p1
)))
261 fn parse_expression
<'a
>(source
: &'a
str,
262 it
: &mut Peekable
<Iter
<Token
<Rule
>>>,
264 -> Result
<ExpressionSpec
, TemplateError
> {
265 let mut params
: Vec
<Parameter
> = Vec
::new();
266 let mut hashes
: BTreeMap
<String
, Parameter
> = BTreeMap
::new();
267 let mut omit_pre_ws
= false;
268 let mut omit_pro_ws
= false;
269 let mut block_param
= None
;
271 if it
.peek().unwrap().rule
== Rule
::pre_whitespace_omitter
{
276 let name
= try
!(Template
::parse_name(source
, it
.by_ref(), limit
));
281 if let Some(ref token
) = it
.peek() {
282 if token
.end
< limit
{
296 params
.push(try
!(Template
::parse_param(source
, it
.by_ref(), end
)));
299 let (key
, value
) = try
!(Template
::parse_hash(source
, it
.by_ref(), end
));
300 hashes
.insert(key
, value
);
302 Rule
::block_param
=> {
303 block_param
= Some(try
!(Template
::parse_block_param(source
, it
.by_ref(), end
)));
305 Rule
::pro_whitespace_omitter
=> {
315 block_param
: block_param
,
316 omit_pre_ws
: omit_pre_ws
,
317 omit_pro_ws
: omit_pro_ws
,
322 fn remove_previous_whitespace(template_stack
: &mut VecDeque
<Template
>) {
323 let mut t
= template_stack
.front_mut().unwrap();
324 if let Some(el
) = t
.elements
.pop() {
325 if let RawString(ref text
) = el
{
326 t
.elements
.push(RawString(text
.trim_right().to_owned()));
333 pub fn compile2
<S
: AsRef
<str>>(source
: S
, mapping
: bool
) -> Result
<Template
, TemplateError
> {
334 let source
= source
.as_ref();
335 let mut helper_stack
: VecDeque
<HelperTemplate
> = VecDeque
::new();
336 let mut directive_stack
: VecDeque
<Directive
> = VecDeque
::new();
337 let mut template_stack
: VecDeque
<Template
> = VecDeque
::new();
339 let mut omit_pro_ws
= false;
341 let input
= StringInput
::new(source
);
342 let mut parser
= Rdp
::new(input
);
344 if !parser
.handlebars() {
345 let (_
, pos
) = parser
.expected();
346 let (line_no
, col_no
) = parser
.input().line_col(pos
);
347 return Err(TemplateError
::of(TemplateErrorReason
::InvalidSyntax
).at(line_no
, col_no
));
350 let mut it
= parser
.queue().iter().peekable();
351 let mut prev_end
= 0;
353 if let Some(ref token
) = it
.next() {
355 if token
.rule
!= Rule
::template
{
356 if token
.start
!= prev_end
&& !omit_pro_ws
&& token
.rule
!= Rule
::raw_text
&&
357 token
.rule
!= Rule
::raw_block_text
{
358 let (line_no
, col_no
) = parser
.input().line_col(prev_end
);
359 if token
.rule
== Rule
::raw_block_end
{
360 let text
= &source
[prev_end
..token
.start
];
361 let mut t
= Template
::new(mapping
);
362 t
.push_element(RawString(text
.to_owned()), line_no
, col_no
);
363 template_stack
.push_front(t
);
365 let text
= &source
[prev_end
..token
.start
];
366 let mut t
= template_stack
.front_mut().unwrap();
367 t
.push_element(RawString(text
.to_owned()), line_no
, col_no
);
372 let (line_no
, col_no
) = parser
.input().line_col(token
.start
);
375 template_stack
.push_front(Template
::new(mapping
));
378 let mut text
= &source
[prev_end
..token
.end
];
380 text
= text
.trim_left();
382 let mut t
= template_stack
.front_mut().unwrap();
383 t
.push_element(RawString(text
.to_owned()), line_no
, col_no
);
385 Rule
::helper_block_start
|
386 Rule
::raw_block_start
|
387 Rule
::directive_block_start
|
388 Rule
::partial_block_start
=> {
389 let exp
= try
!(Template
::parse_expression(source
, it
.by_ref(), token
.end
));
392 Rule
::helper_block_start
|
393 Rule
::raw_block_start
=> {
394 let helper_template
= HelperTemplate
{
395 name
: exp
.name
.as_name().unwrap(),
398 block_param
: exp
.block_param
,
403 helper_stack
.push_front(helper_template
);
405 Rule
::directive_block_start
|
406 Rule
::partial_block_start
=> {
407 let directive
= Directive
{
413 directive_stack
.push_front(directive
);
419 Template
::remove_previous_whitespace(&mut template_stack
);
421 omit_pro_ws
= exp
.omit_pro_ws
;
423 let mut t
= template_stack
.front_mut().unwrap();
424 if let Some(ref mut maps
) = t
.mapping
{
425 maps
.push(TemplateMapping(line_no
, col_no
));
428 Rule
::invert_tag
=> {
429 // hack: invert_tag structure is similar to ExpressionSpec, so I
430 // use it here to represent the data
431 let exp
= try
!(Template
::parse_expression(source
, it
.by_ref(), token
.end
));
434 Template
::remove_previous_whitespace(&mut template_stack
);
436 omit_pro_ws
= exp
.omit_pro_ws
;
438 let t
= template_stack
.pop_front().unwrap();
439 let mut h
= helper_stack
.front_mut().unwrap();
440 h
.template
= Some(t
);
442 Rule
::raw_block_text
=> {
443 let mut text
= &source
[prev_end
..token
.end
];
445 text
= text
.trim_left();
447 let mut t
= Template
::new(mapping
);
448 t
.push_element(RawString(text
.to_owned()), line_no
, col_no
);
449 template_stack
.push_front(t
);
452 Rule
::html_expression
|
453 Rule
::helper_expression
|
454 Rule
::directive_expression
|
455 Rule
::partial_expression
|
456 Rule
::helper_block_end
|
457 Rule
::raw_block_end
|
458 Rule
::directive_block_end
|
459 Rule
::partial_block_end
=> {
460 let exp
= try
!(Template
::parse_expression(source
, it
.by_ref(), token
.end
));
462 Template
::remove_previous_whitespace(&mut template_stack
);
465 omit_pro_ws
= exp
.omit_pro_ws
;
468 Rule
::expression
=> {
469 let el
= Expression(exp
.name
);
470 let mut t
= template_stack
.front_mut().unwrap();
471 t
.push_element(el
, line_no
, col_no
);
473 Rule
::html_expression
=> {
474 let el
= HTMLExpression(exp
.name
);
475 let mut t
= template_stack
.front_mut().unwrap();
476 t
.push_element(el
, line_no
, col_no
);
478 Rule
::helper_expression
=> {
479 let helper_template
= HelperTemplate
{
480 name
: exp
.name
.as_name().unwrap(),
483 block_param
: exp
.block_param
,
488 let el
= HelperExpression(helper_template
);
489 let mut t
= template_stack
.front_mut().unwrap();
490 t
.push_element(el
, line_no
, col_no
);
492 Rule
::directive_expression
|
493 Rule
::partial_expression
=> {
494 let directive
= Directive
{
500 let el
= if token
.rule
== Rule
::directive_expression
{
501 DirectiveExpression(directive
)
503 PartialExpression(directive
)
505 let mut t
= template_stack
.front_mut().unwrap();
506 t
.push_element(el
, line_no
, col_no
);
508 Rule
::helper_block_end
|
509 Rule
::raw_block_end
=> {
510 let mut h
= helper_stack
.pop_front().unwrap();
511 let close_tag_name
= exp
.name
.as_name().unwrap();
512 if h
.name
== close_tag_name
{
513 let prev_t
= template_stack
.pop_front().unwrap();
514 if h
.template
.is_some() {
515 h
.inverse
= Some(prev_t
);
517 h
.template
= Some(prev_t
);
519 let t
= template_stack
.front_mut().unwrap();
520 t
.elements
.push(HelperBlock(h
));
522 return Err(TemplateError
::of(
523 TemplateErrorReason
::MismatchingClosedHelper(
524 h
.name
, close_tag_name
)).at(line_no
, col_no
));
527 Rule
::directive_block_end
|
528 Rule
::partial_block_end
=> {
529 let mut d
= directive_stack
.pop_front().unwrap();
530 let close_tag_name
= exp
.name
;
531 if d
.name
== close_tag_name
{
532 let prev_t
= template_stack
.pop_front().unwrap();
533 d
.template
= Some(prev_t
);
534 let t
= template_stack
.front_mut().unwrap();
535 if token
.rule
== Rule
::directive_block_end
{
536 t
.elements
.push(DirectiveBlock(d
));
538 t
.elements
.push(PartialBlock(d
));
541 return Err(TemplateError
::of(
542 TemplateErrorReason
::MismatchingClosedDirective(
543 d
.name
, close_tag_name
)).at(line_no
, col_no
));
549 Rule
::hbs_comment
=> {
550 let text
= parser
.input().slice(token
.start
+ 3, token
.end
- 2);
551 let mut t
= template_stack
.front_mut().unwrap();
552 t
.push_element(Comment(text
.to_owned()), line_no
, col_no
);
557 if token
.rule
!= Rule
::template
{
558 prev_end
= token
.end
;
561 if prev_end
< source
.len() {
562 let text
= &source
[prev_end
..source
.len()];
563 let (line_no
, col_no
) = parser
.input().line_col(prev_end
);
564 let mut t
= template_stack
.front_mut().unwrap();
565 t
.push_element(RawString(text
.to_owned()), line_no
, col_no
);
567 return Ok(template_stack
.pop_front().unwrap());
572 pub fn compile_with_name
<S
: AsRef
<str>>(source
: S
,
575 -> Result
<Template
, TemplateError
> {
576 match Template
::compile2(source
, mapping
) {
581 Err(e
) => Err(e
.in_template(name
)),
586 #[derive(PartialEq, Clone, Debug)]
587 pub enum TemplateElement
{
589 Expression(Parameter
),
590 HTMLExpression(Parameter
),
591 HelperExpression(HelperTemplate
),
592 HelperBlock(HelperTemplate
),
593 DirectiveExpression(Directive
),
594 DirectiveBlock(Directive
),
595 PartialExpression(Directive
),
596 PartialBlock(Directive
),
601 fn test_parse_template() {
602 let source
= "<h1>{{title}} ä½ å¥½</h1> {{{content}}}
603 {{#if date}}<p>good</p>{{else}}<p>bad</p>{{/if}}<img>{{foo bar}}ä¸æ–‡ä½ 好
604 {{#unless true}}kitkat{{^}}lollipop{{/unless}}";
605 let t
= Template
::compile(source
.to_string()).ok().unwrap();
607 assert_eq
!(t
.elements
.len(), 10);
609 assert_eq
!(*t
.elements
.get(0).unwrap(), RawString("<h1>".to_string()));
610 assert_eq
!(*t
.elements
.get(1).unwrap(),
611 Expression(Parameter
::Name("title".to_string())));
613 assert_eq
!(*t
.elements
.get(3).unwrap(),
614 HTMLExpression(Parameter
::Name("content".to_string())));
616 match *t
.elements
.get(5).unwrap() {
617 HelperBlock(ref h
) => {
618 assert_eq
!(h
.name
, "if".to_string());
619 assert_eq
!(h
.params
.len(), 1);
620 assert_eq
!(h
.template
628 panic
!("Helper expected here.");
632 match *t
.elements
.get(7).unwrap() {
633 HelperExpression(ref h
) => {
634 assert_eq
!(h
.name
, "foo".to_string());
635 assert_eq
!(h
.params
.len(), 1);
636 assert_eq
!(*(h
.params
.get(0).unwrap()), Parameter
::Name("bar".into()));
639 panic
!("Helper expression here");
643 match *t
.elements
.get(9).unwrap() {
644 HelperBlock(ref h
) => {
645 assert_eq
!(h
.name
, "unless".to_string());
646 assert_eq
!(h
.params
.len(), 1);
655 panic
!("Helper expression here");
662 fn test_parse_error() {
663 let source
= "{{#ifequals name compare=\"hello\"}}\nhello\n\t{{else}}\ngood";
665 let t
= Template
::compile(source
.to_string());
667 assert_eq
!(t
.unwrap_err(),
668 TemplateError
::of(TemplateErrorReason
::InvalidSyntax
).at(4, 5));
672 fn test_subexpression() {
673 let source
= "{{foo (bar)}}{{foo (bar baz)}} hello {{#if (baz bar) then=(bar)}}world{{/if}}";
674 let t
= Template
::compile(source
.to_string()).ok().unwrap();
676 assert_eq
!(t
.elements
.len(), 4);
677 match *t
.elements
.get(0).unwrap() {
678 HelperExpression(ref h
) => {
679 assert_eq
!(h
.name
, "foo".to_owned());
680 assert_eq
!(h
.params
.len(), 1);
681 if let &Parameter
::Subexpression(ref t
) = h
.params
.get(0).unwrap() {
682 assert_eq
!(t
.name
, "bar".to_owned());
684 panic
!("Subexpression expected");
688 panic
!("Helper expression expected");
692 match *t
.elements
.get(1).unwrap() {
693 HelperExpression(ref h
) => {
694 assert_eq
!(h
.name
, "foo".to_string());
695 assert_eq
!(h
.params
.len(), 1);
696 if let &Parameter
::Subexpression(ref t
) = h
.params
.get(0).unwrap() {
697 assert_eq
!(t
.name
, "bar".to_owned());
698 if let Some(&Parameter
::Name(ref n
)) = t
.params
.get(0) {
699 assert_eq
!(n
, "baz");
701 panic
!("non-empty param expected ");
704 panic
!("Subexpression expected");
708 panic
!("Helper expression expected");
712 match *t
.elements
.get(3).unwrap() {
713 HelperBlock(ref h
) => {
714 assert_eq
!(h
.name
, "if".to_string());
715 assert_eq
!(h
.params
.len(), 1);
716 assert_eq
!(h
.hash
.len(), 1);
718 if let &Parameter
::Subexpression(ref t
) = h
.params
.get(0).unwrap() {
719 assert_eq
!(t
.name
, "baz".to_owned());
720 if let Some(&Parameter
::Name(ref n
)) = t
.params
.get(0) {
721 assert_eq
!(n
, "bar");
723 panic
!("non-empty param expected ");
727 panic
!("Subexpression expected (baz bar)");
730 if let &Parameter
::Subexpression(ref t
) = h
.hash
.get("then").unwrap() {
731 assert_eq
!(t
.name
, "bar".to_owned());
733 panic
!("Subexpression expected (bar)");
737 panic
!("HelperBlock expected");
743 fn test_white_space_omitter() {
744 let source
= "hello~ {{~world~}} \n !{{~#if true}}else{{/if~}}".to_string();
745 let t
= Template
::compile(source
).ok().unwrap();
747 assert_eq
!(t
.elements
.len(), 4);
749 assert_eq
!(t
.elements
[0], RawString("hello~".to_string()));
750 assert_eq
!(t
.elements
[1], Expression(Parameter
::Name("world".into())));
751 assert_eq
!(t
.elements
[2], RawString("!".to_string()));
753 let t2
= Template
::compile("{{#if true}}1 {{~ else ~}} 2 {{~/if}}".to_string()).ok().unwrap();
754 assert_eq
!(t2
.elements
.len(), 1);
755 match t2
.elements
[0] {
756 HelperBlock(ref h
) => {
757 assert_eq
!(h
.template
762 RawString("1".to_string()));
768 RawString("2".to_string()));
775 fn test_unclosed_expression() {
776 let sources
= ["{{invalid", "{{{invalid", "{{invalid}", "{{!hello"];
777 for s
in sources
.iter() {
778 let result
= Template
::compile(s
.to_owned());
779 if let Err(e
) = result
{
781 TemplateErrorReason
::InvalidSyntax
=> {}
783 panic
!("Unexpected error type {}", e
);
787 panic
!("Undetected error");
793 fn test_raw_helper() {
794 let source
= "hello{{{{raw}}}}good{{night}}{{{{/raw}}}}world";
795 match Template
::compile(source
.to_owned()) {
797 assert_eq
!(t
.elements
.len(), 3);
798 assert_eq
!(t
.elements
[0], RawString("hello".to_owned()));
799 assert_eq
!(t
.elements
[2], RawString("world".to_owned()));
800 match t
.elements
[1] {
801 HelperBlock(ref h
) => {
802 assert_eq
!(h
.name
, "raw".to_owned());
803 if let Some(ref ht
) = h
.template
{
804 assert_eq
!(ht
.elements
.len(), 1);
805 assert_eq
!(*ht
.elements
.get(0).unwrap(),
806 RawString("good{{night}}".to_owned()));
808 panic
!("helper template not found");
812 panic
!("Unexpected element type");
824 #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
825 fn test_literal_parameter_parser() {
826 match Template
::compile("{{hello 1 name=\"value\" valid=false ref=someref}}") {
828 if let HelperExpression(ref ht
) = t
.elements
[0] {
829 assert_eq
!(ht
.params
[0], Parameter
::Literal(Json
::U64(1)));
830 assert_eq
!(ht
.hash
["name"],
831 Parameter
::Literal(Json
::String("value".to_owned())));
832 assert_eq
!(ht
.hash
["valid"], Parameter
::Literal(Json
::Boolean(false)));
833 assert_eq
!(ht
.hash
["ref"], Parameter
::Name("someref".to_owned()));
836 Err(e
) => panic
!("{}", e
),
842 fn test_literal_parameter_parser() {
843 match Template
::compile("{{hello 1 name=\"value\" valid=false ref=someref}}") {
845 if let HelperExpression(ref ht
) = t
.elements
[0] {
846 assert_eq
!(ht
.params
[0], Parameter
::Literal(Json
::U64(1)));
847 assert_eq
!(ht
.hash
["name"],
848 Parameter
::Literal(Json
::String("value".to_owned())));
849 assert_eq
!(ht
.hash
["valid"], Parameter
::Literal(Json
::Bool(false)));
850 assert_eq
!(ht
.hash
["ref"], Parameter
::Name("someref".to_owned()));
853 Err(e
) => panic
!("{}", e
),
858 fn test_template_mapping() {
859 match Template
::compile2("hello\n {{~world}}\n{{#if nice}}\n\thello\n{{/if}}", true) {
861 if let Some(ref mapping
) = t
.mapping
{
862 assert_eq
!(mapping
.len(), t
.elements
.len());
863 assert_eq
!(mapping
[0], TemplateMapping(1, 1));
864 assert_eq
!(mapping
[1], TemplateMapping(2, 3));
865 assert_eq
!(mapping
[3], TemplateMapping(3, 1));
867 panic
!("should contains mapping");
870 Err(e
) => panic
!("{}", e
),
875 fn test_whitespace_elements() {
876 let c
= Template
::compile(" {{elem}}\n\t{{#if true}} \
877 {{/if}}\n{{{{raw}}}} {{{{/raw}}}}\n{{{{raw}}}}{{{{/raw}}}}\n");
886 fn test_block_param() {
887 match Template
::compile("{{#each people as |person|}}{{person}}{{/each}}") {
889 if let HelperBlock(ref ht
) = t
.elements
[0] {
890 if let Some(BlockParam
::Single(Parameter
::Name(ref n
))) = ht
.block_param
{
891 assert_eq
!(n
, "person");
893 panic
!("block param expected.")
896 panic
!("Helper block expected");
899 Err(e
) => panic
!("{}", e
),
902 match Template
::compile("{{#each people as |key val|}}{{person}}{{/each}}") {
904 if let HelperBlock(ref ht
) = t
.elements
[0] {
905 if let Some(BlockParam
::Pair((Parameter
::Name(ref n1
),
906 Parameter
::Name(ref n2
)))) = ht
.block_param
{
907 assert_eq
!(n1
, "key");
908 assert_eq
!(n2
, "val");
910 panic
!("helper block param expected.");
913 panic
!("Helper block expected");
916 Err(e
) => panic
!("{}", e
),
921 #[cfg(not(feature="partial_legacy"))]
922 fn test_directive() {
923 match Template
::compile("hello {{* ssh}} world") {
924 Err(e
) => panic
!("{}", e
),
926 if let DirectiveExpression(ref de
) = t
.elements
[1] {
927 assert_eq
!(de
.name
, Parameter
::Name("ssh".to_owned()));
928 assert_eq
!(de
.template
, None
);
933 match Template
::compile("hello {{> ssh}} world") {
934 Err(e
) => panic
!("{}", e
),
936 if let PartialExpression(ref de
) = t
.elements
[1] {
937 assert_eq
!(de
.name
, Parameter
::Name("ssh".to_owned()));
938 assert_eq
!(de
.template
, None
);
943 match Template
::compile("{{#*inline \"hello\"}}expand to hello{{/inline}}{{> hello}}") {
944 Err(e
) => panic
!("{}", e
),
946 if let DirectiveBlock(ref db
) = t
.elements
[0] {
947 assert_eq
!(db
.name
, Parameter
::Name("inline".to_owned()));
948 assert_eq
!(db
.params
[0],
949 Parameter
::Literal(Json
::String("hello".to_owned())));
950 assert_eq
!(db
.template
955 TemplateElement
::RawString("expand to hello".to_owned()));
960 match Template
::compile("{{#> layout \"hello\"}}expand to hello{{/layout}}{{> hello}}") {
961 Err(e
) => panic
!("{}", e
),
963 if let PartialBlock(ref db
) = t
.elements
[0] {
964 assert_eq
!(db
.name
, Parameter
::Name("layout".to_owned()));
965 assert_eq
!(db
.params
[0],
966 Parameter
::Literal(Json
::String("hello".to_owned())));
967 assert_eq
!(db
.template
972 TemplateElement
::RawString("expand to hello".to_owned()));