Repository: djc/askama (rust)

Issue:
Allow Trailing Commas in Arrays Inside Template Expressions
Basically what the title says.

To give an example of what I mean, this here compiles just fine:

```html
<nav class="flex justify-between items-center max-w-7xl gap-x-12">
    {% for (route, name) in [
        ("/about", "About"),
        ("/contact", "Contact"),
        ("/events", "Events"),
        ("/history", "History")
    ] %}
    <div class="gap-x-6 leading-6 hover:bg-gray-200">
        <a href="{{ route }}"><span>{{ name }}</span></a>
    </div>
    {% endfor %}
</nav>
```

But this here doesn't:

```html
<nav class="flex justify-between items-center max-w-7xl gap-x-12">
    {% for (route, name) in [
        ("/about", "About"),
        ("/contact", "Contact"),
        ("/events", "Events"),
        ("/history", "History"),
    ] %}
    <div class="gap-x-6 leading-6 hover:bg-gray-200">
        <a href="{{ route }}"><span>{{ name }}</span></a>
    </div>
    {% endfor %}
</nav>
```

Note the little comma after the `("/history", "History")` tuple in the second example.

I'm not sure if this is trivial to implement or not, but I thought I might bring it to y'alls' attention.

It wasn't that of a big deal in the end though, so I wouldn't call this a "major issue" or whatever, not by a long shot. Though, since Rust allows such trailing commas, I think `askama` should as well.

For reference, this is the error I got:
```
error: problems parsing template source at row 30, column 31 near:
       ",\n    ] %}\n    <div class=\"gap-x-6 leadi"...
  --> src/routes/mod.rs:96:10
   |
96 | #[derive(Template)]
   |          ^^^^^^^^
   |
   = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)
```

Running with `RUSTFLAGS="-Zmacro-backtrace" cargo +nightly build` gives the following:
```
error: problems parsing template source at row 30, column 31 near:
       ",\n    ] %}\n    <div class=\"gap-x-6 leadi"...
  --> src/routes/mod.rs:96:10
   |
96 | #[derive(Template)]
   |          ^^^^^^^^ in this derive macro expansion
   |
  ::: /home/max/.cargo/registry/src/index.crates.io-6f17d22bba15001f/askama_derive-0.12.5/src/lib.rs:22:1
   |
22 | pub fn derive_template(input: TokenStream) -> TokenStream {
   | --------------------------------------------------------- in this expansion of `#[derive(Template)]`
```

Neither error was too helpful, but it does point to line 30, column 31, which in my code is precisely the closing parenthesis before the trailing comma; careful reading helps at least.

Pull request description:
Accept trailing comma in array
Fix #1086

Patch:
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 2c9eed5..c439f30 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -10,6 +10,7 @@ on:
 jobs:
   Test:
     strategy:
+      fail-fast: false
       matrix:
         os: [ubuntu-latest, macos-latest, windows-latest]
         rust: [stable, beta]
@@ -30,6 +31,7 @@ jobs:
 
   Package:
     strategy:
+      fail-fast: false
       matrix:
         package: [
           askama, askama_actix, askama_axum, askama_derive, askama_escape,
diff --git a/askama_parser/src/expr.rs b/askama_parser/src/expr.rs
index 4ea4fe6..94f7d40 100644
--- a/askama_parser/src/expr.rs
+++ b/askama_parser/src/expr.rs
@@ -270,7 +270,7 @@ impl<'a> Expr<'a> {
                     separated_list0(char(','), ws(move |i| Self::parse(i, level))),
                     Self::Array,
                 ),
-                char(']'),
+                pair(opt(ws(char(','))), char(']')),
             )),
         )(i)
     }


Test patch:
diff --git a/testing/tests/loops.rs b/testing/tests/loops.rs
index 4a02153..48ae030 100644
--- a/testing/tests/loops.rs
+++ b/testing/tests/loops.rs
@@ -83,6 +83,16 @@ fn test_for_array() {
     assert_eq!(t.render().unwrap(), "123");
 }
 
+#[derive(Template)]
+#[template(source = "{% for i in [1, 2, 3, ] %}{{ i }}{% endfor %}", ext = "txt")]
+struct ForArrayTailingCommaTemplate;
+
+#[test]
+fn test_for_array_trailing_comma() {
+    let t = ForArrayTailingCommaTemplate;
+    assert_eq!(t.render().unwrap(), "123");
+}
+
 #[derive(Template)]
 #[template(
     source = "{% for i in [1, 2, 3].iter() %}{{ i }}{% endfor %}",