mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-27 04:50:40 +00:00
Merge pull request #584 from GuillaumeGomez/extends-first
Emit an error if an extends block doesn't come first in a template
This commit is contained in:
commit
5c4b52ad62
@ -44,7 +44,9 @@ fn compare_ex(
|
||||
) {
|
||||
let generated = jinja_to_rust(jinja, fields, prefix);
|
||||
|
||||
let expected: TokenStream = expected.parse().unwrap();
|
||||
let expected: TokenStream = expected
|
||||
.parse()
|
||||
.expect("`TokenStream` failed to parse input");
|
||||
let expected: syn::File = syn::parse_quote! {
|
||||
#[automatically_derived]
|
||||
impl askama::Template for Foo {
|
||||
@ -159,7 +161,10 @@ struct Foo {{ {} }}"##,
|
||||
.join(","),
|
||||
);
|
||||
|
||||
let generated = build_template(&syn::parse_str::<syn::DeriveInput>(&jinja).unwrap()).unwrap();
|
||||
let generated = build_template(
|
||||
&syn::parse_str::<syn::DeriveInput>(&jinja).expect("`syn` failed to parse code"),
|
||||
)
|
||||
.expect("`build_template` failed");
|
||||
match syn::parse2(generated.clone()) {
|
||||
Ok(generated) => generated,
|
||||
Err(err) => panic!(
|
||||
@ -1150,11 +1155,11 @@ fn test_concat() {
|
||||
fn extends_with_whitespace_control() {
|
||||
const CONTROL: &[&str] = &["", "\t", "-", "+", "~"];
|
||||
|
||||
let expected = jinja_to_rust(r#"front {% extends "a.html" %} back"#, &[], "");
|
||||
let expected = jinja_to_rust(r#"{% extends "a.html" %} back"#, &[], "");
|
||||
let expected = unparse(&expected);
|
||||
for front in CONTROL {
|
||||
for back in CONTROL {
|
||||
let src = format!(r#"front {{%{front} extends "a.html" {back}%}} back"#);
|
||||
let src = format!(r#"{{%{front} extends "a.html" {back}%}} back"#);
|
||||
let actual = jinja_to_rust(&src, &[], "");
|
||||
let actual = unparse(&actual);
|
||||
assert_eq!(expected, actual, "source: {src:?}");
|
||||
|
@ -38,8 +38,27 @@ pub enum Node<'a> {
|
||||
|
||||
impl<'a: 'l, 'l> Node<'a> {
|
||||
pub(super) fn parse_template(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Vec<Box<Self>>> {
|
||||
let mut p = parse_with_unexpected_fallback(Self::many, unexpected_tag);
|
||||
let nodes = p.parse_next(i)?;
|
||||
let mut nodes = vec![];
|
||||
let mut allow_extends = true;
|
||||
while let Some(node) = parse_with_unexpected_fallback(
|
||||
opt(move |i: &mut _| Self::one(i, allow_extends)),
|
||||
unexpected_tag,
|
||||
)
|
||||
.parse_next(i)?
|
||||
{
|
||||
if allow_extends {
|
||||
match &*node {
|
||||
// Since comments don't impact generated code, we allow them before `extends`.
|
||||
Node::Comment(_) => {}
|
||||
// If it only contains whitespace characters, it's fine too.
|
||||
Node::Lit(lit) if lit.val.is_empty() => {}
|
||||
// Everything else must not come before an `extends` block.
|
||||
_ => allow_extends = false,
|
||||
}
|
||||
}
|
||||
nodes.push(node);
|
||||
}
|
||||
|
||||
if !i.is_empty() {
|
||||
opt(unexpected_tag).parse_next(i)?;
|
||||
return cut_error!(
|
||||
@ -53,12 +72,15 @@ impl<'a: 'l, 'l> Node<'a> {
|
||||
}
|
||||
|
||||
fn many(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Vec<Box<Self>>> {
|
||||
repeat(
|
||||
0..,
|
||||
alt((Lit::parse, Comment::parse, Self::expr, Self::parse)),
|
||||
)
|
||||
.map(|v: Vec<_>| v)
|
||||
.parse_next(i)
|
||||
repeat(0.., |i: &mut _| Self::one(i, false)).parse_next(i)
|
||||
}
|
||||
|
||||
fn one(i: &mut InputStream<'a, 'l>, allow_extends: bool) -> ParseResult<'a, Box<Self>> {
|
||||
let node = alt((Lit::parse, Comment::parse, Self::expr, Self::parse)).parse_next(i)?;
|
||||
if !allow_extends && let Node::Extends(node) = &*node {
|
||||
return cut_error!("`extends` block must come first in a template", node.span());
|
||||
}
|
||||
Ok(node)
|
||||
}
|
||||
|
||||
fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Self>> {
|
||||
|
@ -1160,10 +1160,10 @@ fn extends_with_whitespace_control() {
|
||||
const CONTROL: &[&str] = &["", "\t", "-", "+", "~"];
|
||||
|
||||
let syntax = Syntax::default();
|
||||
let expected = Ast::from_str(r#"front {% extends "nothing" %} back"#, None, &syntax).unwrap();
|
||||
let expected = Ast::from_str(r#"{% extends "nothing" %} back"#, None, &syntax).unwrap();
|
||||
for front in CONTROL {
|
||||
for back in CONTROL {
|
||||
let src = format!(r#"front {{%{front} extends "nothing" {back}%}} back"#);
|
||||
let src = format!(r#"{{%{front} extends "nothing" {back}%}} back"#);
|
||||
let actual = Ast::from_str(&src, None, &syntax).unwrap();
|
||||
assert_eq!(expected.nodes(), actual.nodes(), "source: {src:?}");
|
||||
}
|
||||
|
@ -25,3 +25,17 @@ fn test_macro_in_block_inheritance() {
|
||||
|
||||
assert_eq!(A.render().unwrap(), "\n\n1 1\n2 2\n--> 3");
|
||||
}
|
||||
|
||||
// This test ensures that comments are allowed before `extends` block.
|
||||
#[test]
|
||||
fn test_comment_before_extend() {
|
||||
#[derive(Template)]
|
||||
#[template(
|
||||
source = r##"{# comment #}{% extends "base.html" %}"##,
|
||||
ext = "txt",
|
||||
print = "ast"
|
||||
)]
|
||||
pub struct X {
|
||||
title: &'static str,
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: `extends` blocks are not allowed below top level
|
||||
--> MyTemplate1.txt:3:2
|
||||
error: `extends` block must come first in a template
|
||||
--> <source attribute>:3:2
|
||||
" extends \"bla.txt\" %}\n{% endblock %}\n"
|
||||
--> tests/ui/blocks_below_top_level.rs:4:21
|
||||
|
|
||||
|
13
testing/tests/ui/extend.rs
Normal file
13
testing/tests/ui/extend.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use askama::Template;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(
|
||||
source = r##"bla
|
||||
{% extends "base.html" %}
|
||||
"##,
|
||||
ext = "txt",
|
||||
print = "ast"
|
||||
)]
|
||||
pub struct X;
|
||||
|
||||
fn main() {}
|
10
testing/tests/ui/extend.stderr
Normal file
10
testing/tests/ui/extend.stderr
Normal file
@ -0,0 +1,10 @@
|
||||
error: `extends` block must come first in a template
|
||||
--> <source attribute>:2:2
|
||||
" extends \"base.html\" %}\n"
|
||||
--> tests/ui/extend.rs:5:14
|
||||
|
|
||||
5 | source = r##"bla
|
||||
| ______________^
|
||||
6 | | {% extends "base.html" %}
|
||||
7 | | "##,
|
||||
| |___^
|
@ -1,5 +1,5 @@
|
||||
error: multiple extend blocks found
|
||||
--> MyTemplate4.txt:3:2
|
||||
error: `extends` block must come first in a template
|
||||
--> <source attribute>:3:2
|
||||
" extends \"foo.html\" %}\n"
|
||||
--> tests/ui/multiple_extends.rs:4:21
|
||||
|
|
||||
|
Loading…
x
Reference in New Issue
Block a user