summaryrefslogtreecommitdiffstats
path: root/vendor/handlebars/src/template.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/handlebars/src/template.rs')
-rw-r--r--vendor/handlebars/src/template.rs233
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>),