mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-28 21:41:35 +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 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! {
|
let expected: syn::File = syn::parse_quote! {
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl askama::Template for Foo {
|
impl askama::Template for Foo {
|
||||||
@ -159,7 +161,10 @@ struct Foo {{ {} }}"##,
|
|||||||
.join(","),
|
.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()) {
|
match syn::parse2(generated.clone()) {
|
||||||
Ok(generated) => generated,
|
Ok(generated) => generated,
|
||||||
Err(err) => panic!(
|
Err(err) => panic!(
|
||||||
@ -1150,11 +1155,11 @@ fn test_concat() {
|
|||||||
fn extends_with_whitespace_control() {
|
fn extends_with_whitespace_control() {
|
||||||
const CONTROL: &[&str] = &["", "\t", "-", "+", "~"];
|
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);
|
let expected = unparse(&expected);
|
||||||
for front in CONTROL {
|
for front in CONTROL {
|
||||||
for back 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 = jinja_to_rust(&src, &[], "");
|
||||||
let actual = unparse(&actual);
|
let actual = unparse(&actual);
|
||||||
assert_eq!(expected, actual, "source: {src:?}");
|
assert_eq!(expected, actual, "source: {src:?}");
|
||||||
|
@ -38,8 +38,27 @@ pub enum Node<'a> {
|
|||||||
|
|
||||||
impl<'a: 'l, 'l> Node<'a> {
|
impl<'a: 'l, 'l> Node<'a> {
|
||||||
pub(super) fn parse_template(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Vec<Box<Self>>> {
|
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 mut nodes = vec![];
|
||||||
let nodes = p.parse_next(i)?;
|
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() {
|
if !i.is_empty() {
|
||||||
opt(unexpected_tag).parse_next(i)?;
|
opt(unexpected_tag).parse_next(i)?;
|
||||||
return cut_error!(
|
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>>> {
|
fn many(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Vec<Box<Self>>> {
|
||||||
repeat(
|
repeat(0.., |i: &mut _| Self::one(i, false)).parse_next(i)
|
||||||
0..,
|
}
|
||||||
alt((Lit::parse, Comment::parse, Self::expr, Self::parse)),
|
|
||||||
)
|
fn one(i: &mut InputStream<'a, 'l>, allow_extends: bool) -> ParseResult<'a, Box<Self>> {
|
||||||
.map(|v: Vec<_>| v)
|
let node = alt((Lit::parse, Comment::parse, Self::expr, Self::parse)).parse_next(i)?;
|
||||||
.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>> {
|
fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Self>> {
|
||||||
|
@ -1160,10 +1160,10 @@ fn extends_with_whitespace_control() {
|
|||||||
const CONTROL: &[&str] = &["", "\t", "-", "+", "~"];
|
const CONTROL: &[&str] = &["", "\t", "-", "+", "~"];
|
||||||
|
|
||||||
let syntax = Syntax::default();
|
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 front in CONTROL {
|
||||||
for back 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();
|
let actual = Ast::from_str(&src, None, &syntax).unwrap();
|
||||||
assert_eq!(expected.nodes(), actual.nodes(), "source: {src:?}");
|
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");
|
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
|
error: `extends` block must come first in a template
|
||||||
--> MyTemplate1.txt:3:2
|
--> <source attribute>:3:2
|
||||||
" extends \"bla.txt\" %}\n{% endblock %}\n"
|
" extends \"bla.txt\" %}\n{% endblock %}\n"
|
||||||
--> tests/ui/blocks_below_top_level.rs:4:21
|
--> 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
|
error: `extends` block must come first in a template
|
||||||
--> MyTemplate4.txt:3:2
|
--> <source attribute>:3:2
|
||||||
" extends \"foo.html\" %}\n"
|
" extends \"foo.html\" %}\n"
|
||||||
--> tests/ui/multiple_extends.rs:4:21
|
--> tests/ui/multiple_extends.rs:4:21
|
||||||
|
|
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user