// Prints an HTML table built from a template, with every value escaped.
//
// nikaia run
// <table>
// <tr class="odd"><td>Ada</td><td>fine</td></tr><tr class="even"><td>a<b & c</td>…
//
// Shows: a `dsl html` template, a `<for>` loop inside it, and `html::Raw` for
// markup the program built itself.
//
// A package: `nikaia run` in this directory runs it, and `nikaia test` checks
// what it prints against `tests/` (ADR-269 D13).
use std::html
pub struct Row {
name: String,
note: String,
shade: String,
}
// Every `{…}` hole in a template is escaped, always; there is no way to turn
// that off. A hole is only allowed where escaping is enough: text, or a quoted
// attribute like `class="…"`. In a `<script>` body, an `href` or an unquoted
// attribute the compiler refuses it. The holes need no `f`, and `{{` is a
// literal brace, as in an `f"…"` string.
//
// In `<for r in :rows>`, the colon marks `rows` as a name from the program
// around the template rather than one the template defines.
fn table(rows: Vec[Row]) -> String {
return dsl html {
<table>
<for r in :rows><tr class="{r.shade}"><td>{r.name}</td><td>{r.note}</td></tr></for>
</table>
} eod
}
// The one way to put markup into a hole is the type `html::Raw`: its value is
// not escaped again. So the name is escaped first, with `html::escape`, and the
// `<em>` around it survives.
fn emphasised(name: String) -> String {
let mut built = String()
built.push_str("<em>")
built.push_str(ref html::escape(name))
built.push_str("</em>")
let markup = html::Raw(built)
return dsl html {
<tr class="odd"><td>{name}</td><td>{markup}</td></tr>
} eod
}
fn main() {
let rows = [
Row { name: "Ada", note: "fine", shade: "odd" },
Row { name: "a<b & c", note: "\"quoted\"", shade: "even" },
Row { name: "O'Hara", note: "</td> is not a tag here", shade: "odd" },
]
println(f"{table(rows)}")
println(f"{emphasised("Ada")}")
}
The file itself · all the examples