Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Empty line stripping fix #448

Merged
merged 11 commits into from
Jun 30, 2021
5 changes: 3 additions & 2 deletions examples/render_file/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
<body>
<h1>CSL {{year}}</h1>
<ul>
{{#each teams as |t| ~}}
{{#each teams as |t| }}
<li class="{{ranking_label @index ../teams}}">
{{~log @index~}}
{{!-- I'm comment --}}
<b>{{t.name}}</b>: {{format t.pts ~}}
</li>
{{/each~}}
{{/each}}
</ul>

<p>Rendered by Handlebars from {{engine}} data.</p>
Expand Down
47 changes: 20 additions & 27 deletions src/grammar.pest
Original file line number Diff line number Diff line change
Expand Up @@ -62,44 +62,37 @@ pro_whitespace_omitter? ~ "}}" }
partial_expression = { "{{" ~ pre_whitespace_omitter? ~ ">" ~ partial_exp_line
~ pro_whitespace_omitter? ~ "}}" }

brackets_open = @{ (NEWLINE ~ (" "|"\t")*)? ~ "{{" }
brackets_close = @{ "}}" ~ ((" "|"\t")* ~ NEWLINE)? }

invert_tag_item = { "else"|"^" }
invert_tag = { !escape ~ brackets_open ~ pre_whitespace_omitter? ~ invert_tag_item
~ pro_whitespace_omitter? ~ brackets_close }
helper_block_start = { brackets_open ~ pre_whitespace_omitter? ~ "#" ~ exp_line ~
pro_whitespace_omitter? ~ brackets_close }
helper_block_end = { brackets_open ~ pre_whitespace_omitter? ~ "/" ~ identifier ~
pro_whitespace_omitter? ~ brackets_close }
invert_tag = { !escape ~ "{{" ~ pre_whitespace_omitter? ~ invert_tag_item
~ pro_whitespace_omitter? ~ "}}" }
helper_block_start = { "{{" ~ pre_whitespace_omitter? ~ "#" ~ exp_line ~
pro_whitespace_omitter? ~ "}}" }
helper_block_end = { "{{" ~ pre_whitespace_omitter? ~ "/" ~ identifier ~
pro_whitespace_omitter? ~ "}}" }
helper_block = _{ helper_block_start ~ template ~
(invert_tag ~ template)? ~ helper_block_end }

decorator_block_start = { brackets_open ~ pre_whitespace_omitter? ~ "#" ~ "*"
~ exp_line ~ pro_whitespace_omitter? ~ brackets_close }
decorator_block_end = { brackets_open ~ pre_whitespace_omitter? ~ "/" ~ identifier ~
pro_whitespace_omitter? ~ brackets_close }
decorator_block_start = { "{{" ~ pre_whitespace_omitter? ~ "#" ~ "*"
~ exp_line ~ pro_whitespace_omitter? ~ "}}" }
decorator_block_end = { "{{" ~ pre_whitespace_omitter? ~ "/" ~ identifier ~
pro_whitespace_omitter? ~ "}}" }
decorator_block = _{ decorator_block_start ~ template ~
decorator_block_end }

partial_block_start = { brackets_open ~ pre_whitespace_omitter? ~ "#" ~ ">"
~ partial_exp_line ~ pro_whitespace_omitter? ~ brackets_close }
partial_block_end = { brackets_open ~ pre_whitespace_omitter? ~ "/" ~ partial_identifier ~
pro_whitespace_omitter? ~ brackets_close }
partial_block_start = { "{{" ~ pre_whitespace_omitter? ~ "#" ~ ">"
~ partial_exp_line ~ pro_whitespace_omitter? ~ "}}" }
partial_block_end = { "{{" ~ pre_whitespace_omitter? ~ "/" ~ partial_identifier ~
pro_whitespace_omitter? ~ "}}" }
partial_block = _{ partial_block_start ~ template ~ partial_block_end }

double_brackets_open = @{ (NEWLINE ~ (" "|"\t")*)? ~ "{{{{" }
double_brackets_close = @{ "}}}}" ~ ((" "|"\t")* ~ NEWLINE)? }

raw_block_start = { double_brackets_open ~ pre_whitespace_omitter? ~ exp_line ~
pro_whitespace_omitter? ~ double_brackets_close }
raw_block_end = { double_brackets_open ~ pre_whitespace_omitter? ~ "/" ~ identifier ~
pro_whitespace_omitter? ~ double_brackets_close }
raw_block_start = { "{{{{" ~ pre_whitespace_omitter? ~ exp_line ~
pro_whitespace_omitter? ~ "}}}}" }
raw_block_end = { "{{{{" ~ pre_whitespace_omitter? ~ "/" ~ identifier ~
pro_whitespace_omitter? ~ "}}}}" }
raw_block = _{ raw_block_start ~ raw_block_text ~ raw_block_end }

comment_brackets_open = @{ ("\r"? ~ "\n" ~ (" "|"\t")*)? ~ "{{!" }
hbs_comment = { comment_brackets_open ~ "--" ~ (!"--}}" ~ ANY)* ~ "--" ~ brackets_close }
hbs_comment_compact = { comment_brackets_open ~ (!"}}" ~ ANY)* ~ brackets_close }
hbs_comment = { "{{!" ~ "--" ~ (!"--}}" ~ ANY)* ~ "--" ~ "}}" }
hbs_comment_compact = { "{{!" ~ (!"}}" ~ ANY)* ~ "}}" }

template = { (
raw_text |
Expand Down
27 changes: 20 additions & 7 deletions src/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@
#[grammar = "grammar.pest"]
pub struct HandlebarsParser;

#[inline]
pub(crate) fn whitespace_matcher(c: char) -> bool {
c == ' ' || c == '\t'
}

#[inline]
pub(crate) fn newline_matcher(c: char) -> bool {
c == '\n' || c == '\r'
}

pub(crate) fn ends_with_empty_line(text: &str) -> bool {
text.trim_end_matches(whitespace_matcher)
.ends_with(newline_matcher)
}

pub(crate) fn starts_with_empty_line(text: &str) -> bool {
text.trim_start_matches(whitespace_matcher)
.starts_with(newline_matcher)
}

#[cfg(test)]
mod test {
use super::{HandlebarsParser, Rule};
Expand Down Expand Up @@ -144,7 +164,6 @@ mod test {
"{{!--
<li><a href=\"{{up-dir nest-count}}{{base-url}}index.html\">{{this.title}}</a></li>
--}}",
"\r\n {{!-- yes --}} \r\n",
"{{! -- good --}}"];
for i in s.iter() {
assert_rule!(Rule::hbs_comment, i);
Expand Down Expand Up @@ -226,10 +245,6 @@ mod test {
"{{#each people as |person|}}",
"{{#each-obj obj as |val key|}}",
"{{#each assets}}",
"\n{{#each assets}}\n",
"\r\n{{#each assets}}\r\n",
"\r\n {{#each assets}}\r\n",
"\r\n\t\t{{#each assets}}\r\n",
];
for i in s.iter() {
assert_rule!(Rule::helper_block_start, i);
Expand Down Expand Up @@ -257,7 +272,6 @@ mod test {
"{{#if}}hello{{else~}}world{{/if}}",
"{{#if}}hello{{~^~}}world{{/if}}",
"{{#if}}{{/if}}",
"\r\n{{#if}}\r\n\r\n{{/if}}\r\n",
];
for i in s.iter() {
assert_rule!(Rule::helper_block, i);
Expand All @@ -269,7 +283,6 @@ mod test {
let s = vec![
"{{{{if hello}}}}good {{hello}}{{{{/if}}}}",
"{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}",
"\n{{{{if hello}}}}\n{{#if nice}}{{/if}}{{{{/if}}}}",
];
for i in s.iter() {
assert_rule!(Rule::raw_block, i);
Expand Down
19 changes: 19 additions & 0 deletions src/helpers/helper_each.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,4 +571,23 @@ mod test {
.render_template("{{#each data}}{{else}}food{{/each}}", &json!({"data": 24}))
.is_ok());
}

#[test]
fn newline_stripping_for_each() {
let reg = Registry::new();

let tpl = r#"<ul>
{{#each a}}
{{!-- comment --}}
<li>{{this}}</li>
{{/each}}
</ul>"#;
assert_eq!(
r#"<ul>
<li>0</li>
<li>1</li>
</ul>"#,
reg.render_template(tpl, &json!({"a": [0, 1]})).unwrap()
);
}
}
6 changes: 6 additions & 0 deletions src/helpers/helper_if.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,5 +135,11 @@ mod test {
hbs.render_template("{{#if a}}\nyes\n{{/if}}\n", &json!({"a": true}))
.unwrap()
);

assert_eq!(
"x\ny",
hbs.render_template("{{#if a}}x{{/if}}\ny", &json!({"a": true}))
.unwrap()
);
}
}
Loading