Interpolation
</p> is missing. HTML makes
it optional there and Slurp drops it. Every output sample on these pages is
minified.
Use the ${ } form. A bare { } means exactly the same thing and is accepted,
but it reads ambiguously next to a block tag such as {if}, so these guides
use ${ } throughout.
Everything interpolated is escaped for the context it lands in. A value
containing <script> renders as text in a paragraph, and as an escaped
attribute value in an attribute. Escaping is always on. See
Escaping for the details and for the one tag that bypasses
it.
Property access
Dots walk into objects, brackets index arrays and string keys.{each} loop index. After a . only
an identifier is accepted, so items.0 is a parse error and items[0] is the
only spelling.
Navigation is null-safe at every depth, and there is no ?. operator.
Missing values render nothing
--verbose, and read
Common mistakes.
Operators
+ - * / %, comparison is == != < > <= >=, logic is
&& || !, and there is a ternary and a backtick template literal.
&& and || return the operand value rather than a boolean, so
user.nickname || user.name is the usual way to write a fallback for a value
that might be blank. For a value that might be missing entirely, prefer
| default(...).
A few behaviours differ from JavaScript:
Any arithmetic result that would be NaN or infinite becomes 0.
Arithmetic coerces, comparison does not
This asymmetry produces a wrong page rather than an error."10" - 1 is 9.
Comparison does not coerce at all. Only number against number and string
against string actually compare. Every other pairing is treated as equal, so
> and < are false, and >= and <= are false too because the two values
are not equal either. A string that looks like a number loses every comparison
it is in.
Server data arrives as strings often. Postgres and most other databases
serialise a decimal to JSON as a string, so a price or a stock count is
frequently "10" rather than 10. Coerce it:
| int and | float are the two coercions, and both are all-or-nothing:
"12abc" becomes 0, not 12.
Truthiness
null, false, 0, the empty string, the empty array and the empty object
are falsy. Everything else is truthy.
Two of those differ from JavaScript:
- An empty array is falsy, so
{if cart.items}is a valid emptiness check. - The strings
"0"and"false"are truthy, because they are non-empty strings. A boolean that arrived from a form or a query string as text needs comparing explicitly.
What expressions cannot do
Slurp expressions are not a programming language. A template cannot run code at render time. Several habits carried over from other engines silently produce nothing. There are no callable functions. A call parses and always evaluates to null, with no diagnostic:items.length behaves the same way: there are no array properties or methods.
The only call-shaped construct in the language is a filter.
These operators do not exist:
===, !==, ??, ?., in, **,
typeof, instanceof, every bitwise operator, every assignment operator, and
arrow functions. Unlike a bad property name, writing one of these is a parse
error rather than a silent failure.
There are no array or object literals. Both [1, 2] and {a: 1} are parse
errors. Pass collections in through the render context.
Interpolating into attributes
A quoted element attribute interpolates, and an expression attribute in braces does too:A nested double quote ends the attribute
How data reaches a template
At build time it comes from a JSON file, and every top-level key becomes a global:data.json
--globals the context is empty, and because missing values render
nothing, the build still succeeds and every page comes out with the data
missing. If a whole page renders blank, check that flag first.
When Slurp is embedded in a server the picture changes: the host supplies the
context per request, and --globals covers only the values a theme must
resolve at compile time. See Embedding with Rust.
Inside the template there is no difference between the two: a page cannot tell
where its context came from. A theme can therefore be developed against a
fixture file and shipped against live data.
Next
Control flow
Conditionals, loops and the iteration budget.
Filters
Formatting values on the way out.
Escaping
Per-context escaping, and the unescaped forms.
Expressions
The full grammar, precedence table and operator semantics.