Skip to content

Commit

Permalink
Allow terminating void elements with semicolons (;)
Browse files Browse the repository at this point in the history
When Rust and HTML syntax differ, Maud tends to side with Rust syntax.
This can be seen with string literals, for example, where we use
backslash escapes instead of HTML entities. Using `;` to terminate void
elements is consistent with this idea.

Moreover, this reduces confusion around the generated code. Maud does
not insert an extra slash into the HTML output (as per the spec) but
the syntax may imply otherwise.

This confusion may have been the cause of a [bug I found in the
wild][1], where the code omitted the trailing slash on an `input`
element. I suspect that this is because the author thought that a
trailing slash in the Maud template would lead to one in the HTML
output. Switching to semicolons would prevent this misconception.

[1]: anowell/quasar#3
  • Loading branch information
lambda-fairy committed Aug 4, 2017
1 parent 21d19ad commit 1785071
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## [Unreleased]

- [Added] Allow terminating void elements with semicolons (`;`)
[#96](https://github.com/lfairy/maud/pull/96)
- [Changed] Update to Rocket 0.3
[#94](https://github.com/lfairy/maud/pull/94)
- [Changed] Port to new proc macro interface
Expand Down
20 changes: 13 additions & 7 deletions maud/tests/basic_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,20 @@ fn nesting_elements() {

#[test]
fn empty_elements() {
let s = html!("pinkie" br/ "pie").into_string();
let s = html!("pinkie" br; "pie").into_string();
assert_eq!(s, "pinkie<br>pie");
}

#[test]
fn empty_elements_slash() {
let s = html!("pinkie" br / "pie").into_string();
assert_eq!(s, "pinkie<br>pie");
}

#[test]
fn simple_attributes() {
let s = html! {
link rel="stylesheet" href="styles.css"/
link rel="stylesheet" href="styles.css";
section id="midriff" {
p class="hotpink" "Hello!"
}
Expand All @@ -73,18 +79,18 @@ fn simple_attributes() {

#[test]
fn empty_attributes() {
let s = html!(div readonly? input type="checkbox" checked? /).into_string();
let s = html!(div readonly? input type="checkbox" checked?;).into_string();
assert_eq!(s, r#"<div readonly><input type="checkbox" checked></div>"#);
}

#[test]
fn toggle_empty_attributes() {
let rocks = true;
let s = html!({
input checked?[true] /
input checked?[false] /
input checked?[rocks] /
input checked?[!rocks] /
input checked?[true];
input checked?[false];
input checked?[rocks];
input checked?[!rocks];
}).into_string();
assert_eq!(s, concat!(
r#"<input checked>"#,
Expand Down
1 change: 1 addition & 0 deletions maud_macros/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ impl Parser {
self.attrs(render)?;
render.element_open_end();
match self.peek() {
Some(TokenTree { kind: TokenNode::Op(';', _), .. }) |
Some(TokenTree { kind: TokenNode::Op('/', _), .. }) => {
// Void element
self.advance();
Expand Down

0 comments on commit 1785071

Please sign in to comment.