diff options
Diffstat (limited to 'vendor/handlebars/src/template.rs')
-rw-r--r-- | vendor/handlebars/src/template.rs | 233 |
1 files changed, 150 insertions, 83 deletions
diff --git a/vendor/handlebars/src/template.rs b/vendor/handlebars/src/template.rs index 87f853799..617f47711 100644 --- a/vendor/handlebars/src/template.rs +++ b/vendor/handlebars/src/template.rs @@ -9,23 +9,39 @@ use pest::{Parser, Position, Span}; use serde_json::value::Value as Json; use crate::error::{TemplateError, TemplateErrorReason}; -use crate::grammar::{self, HandlebarsParser, Rule}; +use crate::grammar::{HandlebarsParser, Rule}; use crate::json::path::{parse_json_path_from_iter, Path}; +use crate::support; use self::TemplateElement::*; -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct TemplateMapping(pub usize, pub usize); /// A handlebars template -#[derive(PartialEq, Clone, Debug, Default)] +#[derive(PartialEq, Eq, Clone, Debug, Default)] pub struct Template { pub name: Option<String>, pub elements: Vec<TemplateElement>, pub mapping: Vec<TemplateMapping>, } -#[derive(PartialEq, Clone, Debug)] +#[derive(Default)] +pub(crate) struct TemplateOptions { + pub(crate) prevent_indent: bool, + pub(crate) name: Option<String>, +} + +impl TemplateOptions { + fn name(&self) -> String { + self.name + .as_ref() + .cloned() + .unwrap_or_else(|| "Unnamed".to_owned()) + } +} + +#[derive(PartialEq, Eq, Clone, Debug)] pub struct Subexpression { // we use box here avoid resursive struct definition pub element: Box<TemplateElement>, @@ -84,13 +100,13 @@ impl Subexpression { } } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub enum BlockParam { Single(Parameter), Pair((Parameter, Parameter)), } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct ExpressionSpec { pub name: Parameter, pub params: Vec<Parameter>, @@ -100,7 +116,7 @@ pub struct ExpressionSpec { pub omit_pro_ws: bool, } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub enum Parameter { // for helper name only Name(String), @@ -110,7 +126,7 @@ pub enum Parameter { Subexpression(Subexpression), } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct HelperTemplate { pub name: Parameter, pub params: Vec<Parameter>, @@ -122,6 +138,18 @@ pub struct HelperTemplate { } impl HelperTemplate { + pub fn new(exp: ExpressionSpec, block: bool) -> HelperTemplate { + HelperTemplate { + name: exp.name, + params: exp.params, + hash: exp.hash, + block_param: exp.block_param, + block, + template: None, + inverse: None, + } + } + // test only pub(crate) fn with_path(path: Path) -> HelperTemplate { HelperTemplate { @@ -140,12 +168,26 @@ impl HelperTemplate { } } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct DecoratorTemplate { pub name: Parameter, pub params: Vec<Parameter>, pub hash: HashMap<String, Parameter>, pub template: Option<Template>, + // for partial indent + pub indent: Option<String>, +} + +impl DecoratorTemplate { + pub fn new(exp: ExpressionSpec) -> DecoratorTemplate { + DecoratorTemplate { + name: exp.name, + params: exp.params, + hash: exp.hash, + template: None, + indent: None, + } + } } impl Parameter { @@ -380,34 +422,40 @@ impl Template { fn remove_previous_whitespace(template_stack: &mut VecDeque<Template>) { let t = template_stack.front_mut().unwrap(); - if let Some(el) = t.elements.last_mut() { - if let RawString(ref mut text) = el { - *text = text.trim_end().to_owned(); - } + if let Some(RawString(ref mut text)) = t.elements.last_mut() { + *text = text.trim_end().to_owned(); } } + // in handlebars, the whitespaces around statement are + // automatically trimed. + // this function checks if current span has both leading and + // trailing whitespaces, which we treat as a standalone statement. + // + // fn process_standalone_statement( template_stack: &mut VecDeque<Template>, source: &str, current_span: &Span<'_>, + prevent_indent: bool, ) -> bool { - let with_trailing_newline = grammar::starts_with_empty_line(&source[current_span.end()..]); + let with_trailing_newline = + support::str::starts_with_empty_line(&source[current_span.end()..]); if with_trailing_newline { let with_leading_newline = - grammar::ends_with_empty_line(&source[..current_span.start()]); + support::str::ends_with_empty_line(&source[..current_span.start()]); - if with_leading_newline { + // prevent_indent: a special toggle for partial expression + // (>) that leading whitespaces are kept + if prevent_indent && with_leading_newline { let t = template_stack.front_mut().unwrap(); // check the last element before current - if let Some(el) = t.elements.last_mut() { - if let RawString(ref mut text) = el { - // trim leading space for standalone statement - *text = text - .trim_end_matches(grammar::whitespace_matcher) - .to_owned(); - } + if let Some(RawString(ref mut text)) = t.elements.last_mut() { + // trim leading space for standalone statement + *text = text + .trim_end_matches(support::str::whitespace_matcher) + .to_owned(); } } @@ -453,17 +501,17 @@ impl Template { if trim_start { RawString(s.trim_start().to_owned()) } else if trim_start_line { - RawString( - s.trim_start_matches(grammar::whitespace_matcher) - .trim_start_matches(grammar::newline_matcher) - .to_owned(), - ) + let s = s.trim_start_matches(support::str::whitespace_matcher); + RawString(support::str::strip_first_newline(s).to_owned()) } else { RawString(s) } } - pub fn compile<'a>(source: &'a str) -> Result<Template, TemplateError> { + pub(crate) fn compile2<'a>( + source: &'a str, + options: TemplateOptions, + ) -> Result<Template, TemplateError> { let mut helper_stack: VecDeque<HelperTemplate> = VecDeque::new(); let mut decorator_stack: VecDeque<DecoratorTemplate> = VecDeque::new(); let mut template_stack: VecDeque<Template> = VecDeque::new(); @@ -472,14 +520,16 @@ impl Template { // flag for newline removal of standalone statements // this option is marked as true when standalone statement is detected // then the leading whitespaces and newline of next rawstring will be trimed - let mut trim_line_requiered = false; + let mut trim_line_required = false; let parser_queue = HandlebarsParser::parse(Rule::handlebars, source).map_err(|e| { let (line_no, col_no) = match e.line_col { LineColLocation::Pos(line_col) => line_col, LineColLocation::Span(line_col, _) => line_col, }; - TemplateError::of(TemplateErrorReason::InvalidSyntax).at(source, line_no, col_no) + TemplateError::of(TemplateErrorReason::InvalidSyntax) + .at(source, line_no, col_no) + .in_template(options.name()) })?; // dbg!(parser_queue.clone().flatten()); @@ -515,7 +565,7 @@ impl Template { &source[prev_end..span.start()], None, false, - trim_line_requiered, + trim_line_required, ), line_no, col_no, @@ -528,12 +578,15 @@ impl Template { &source[prev_end..span.start()], None, false, - trim_line_requiered, + trim_line_required, ), line_no, col_no, ); } + + // reset standalone statement marker + trim_line_required = false; } let (line_no, col_no) = span.start_pos().line_col(); @@ -555,14 +608,14 @@ impl Template { &source[start..span.end()], Some(pair.clone()), omit_pro_ws, - trim_line_requiered, + trim_line_required, ), line_no, col_no, ); // reset standalone statement marker - trim_line_requiered = false; + trim_line_required = false; } Rule::helper_block_start | Rule::raw_block_start @@ -572,24 +625,11 @@ impl Template { match rule { Rule::helper_block_start | Rule::raw_block_start => { - let helper_template = HelperTemplate { - name: exp.name, - params: exp.params, - hash: exp.hash, - block_param: exp.block_param, - block: true, - template: None, - inverse: None, - }; + let helper_template = HelperTemplate::new(exp.clone(), true); helper_stack.push_front(helper_template); } Rule::decorator_block_start | Rule::partial_block_start => { - let decorator = DecoratorTemplate { - name: exp.name, - params: exp.params, - hash: exp.hash, - template: None, - }; + let decorator = DecoratorTemplate::new(exp.clone()); decorator_stack.push_front(decorator); } _ => unreachable!(), @@ -602,10 +642,11 @@ impl Template { // standalone statement check, it also removes leading whitespaces of // previous rawstring when standalone statement detected - trim_line_requiered = Template::process_standalone_statement( + trim_line_required = Template::process_standalone_statement( &mut template_stack, source, &span, + true, ); let t = template_stack.front_mut().unwrap(); @@ -623,10 +664,11 @@ impl Template { // standalone statement check, it also removes leading whitespaces of // previous rawstring when standalone statement detected - trim_line_requiered = Template::process_standalone_statement( + trim_line_required = Template::process_standalone_statement( &mut template_stack, source, &span, + true, ); let t = template_stack.pop_front().unwrap(); @@ -640,7 +682,7 @@ impl Template { span.as_str(), Some(pair.clone()), omit_pro_ws, - trim_line_requiered, + trim_line_required, ), line_no, col_no, @@ -664,15 +706,7 @@ impl Template { match rule { Rule::expression | Rule::html_expression => { - let helper_template = HelperTemplate { - name: exp.name, - params: exp.params, - hash: exp.hash, - block_param: exp.block_param, - block: false, - template: None, - inverse: None, - }; + let helper_template = HelperTemplate::new(exp.clone(), false); let el = if rule == Rule::expression { Expression(Box::new(helper_template)) } else { @@ -682,12 +716,30 @@ impl Template { t.push_element(el, line_no, col_no); } Rule::decorator_expression | Rule::partial_expression => { - let decorator = DecoratorTemplate { - name: exp.name, - params: exp.params, - hash: exp.hash, - template: None, - }; + // do not auto trim ident spaces for + // partial_expression(>) + let prevent_indent = rule != Rule::partial_expression; + trim_line_required = Template::process_standalone_statement( + &mut template_stack, + source, + &span, + prevent_indent, + ); + + // indent for partial expression > + let mut indent = None; + if rule == Rule::partial_expression + && !options.prevent_indent + && !exp.omit_pre_ws + { + indent = support::str::find_trailing_whitespace_chars( + &source[..span.start()], + ); + } + + let mut decorator = DecoratorTemplate::new(exp.clone()); + decorator.indent = indent.map(|s| s.to_owned()); + let el = if rule == Rule::decorator_expression { DecoratorExpression(Box::new(decorator)) } else { @@ -699,10 +751,11 @@ impl Template { Rule::helper_block_end | Rule::raw_block_end => { // standalone statement check, it also removes leading whitespaces of // previous rawstring when standalone statement detected - trim_line_requiered = Template::process_standalone_statement( + trim_line_required = Template::process_standalone_statement( &mut template_stack, source, &span, + true, ); let mut h = helper_stack.pop_front().unwrap(); @@ -723,16 +776,18 @@ impl Template { exp.name.debug_name(), ), ) - .at(source, line_no, col_no)); + .at(source, line_no, col_no) + .in_template(options.name())); } } Rule::decorator_block_end | Rule::partial_block_end => { // standalone statement check, it also removes leading whitespaces of // previous rawstring when standalone statement detected - trim_line_requiered = Template::process_standalone_statement( + trim_line_required = Template::process_standalone_statement( &mut template_stack, source, &span, + true, ); let mut d = decorator_stack.pop_front().unwrap(); @@ -753,17 +808,19 @@ impl Template { exp.name.debug_name(), ), ) - .at(source, line_no, col_no)); + .at(source, line_no, col_no) + .in_template(options.name())); } } _ => unreachable!(), } } Rule::hbs_comment_compact => { - trim_line_requiered = Template::process_standalone_statement( + trim_line_required = Template::process_standalone_statement( &mut template_stack, source, &span, + true, ); let text = span @@ -774,10 +831,11 @@ impl Template { t.push_element(Comment(text.to_owned()), line_no, col_no); } Rule::hbs_comment => { - trim_line_requiered = Template::process_standalone_statement( + trim_line_required = Template::process_standalone_statement( &mut template_stack, source, &span, + true, ); let text = span @@ -802,27 +860,36 @@ impl Template { let t = template_stack.front_mut().unwrap(); t.push_element(RawString(text.to_owned()), line_no, col_no); } - let root_template = template_stack.pop_front().unwrap(); + let mut root_template = template_stack.pop_front().unwrap(); + root_template.name = options.name; return Ok(root_template); } } } + // These two compile functions are kept for compatibility with 4.x + // Template APIs in case that some developers are using them + // without registry. + + pub fn compile(source: &str) -> Result<Template, TemplateError> { + Self::compile2(source, TemplateOptions::default()) + } + pub fn compile_with_name<S: AsRef<str>>( source: S, name: String, ) -> Result<Template, TemplateError> { - match Template::compile(source.as_ref()) { - Ok(mut t) => { - t.name = Some(name); - Ok(t) - } - Err(e) => Err(e.in_template(name)), - } + Self::compile2( + source.as_ref(), + TemplateOptions { + name: Some(name), + ..Default::default() + }, + ) } } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub enum TemplateElement { RawString(String), HtmlExpression(Box<HelperTemplate>), |