Skip to main content
A filter transforms a value as it is rendered. Filters are the only call-shaped construct in Slurp, so they are where all the formatting lives: there are no functions to call and no methods on a value.
They chain left to right:
This page groups the filters by task. For the complete alphabetical list with the null behaviour of each one, see the filter reference.

Arguments must be literals

Breaking this rule fails silently.
A filter argument is read as a literal and never evaluated. A variable argument is seen as the empty string, so currency falls back to no symbol at all and a leading space appears where the currency marker should be. The compiler says nothing.
default is the one exception. Its argument is evaluated in scope, so default(user.name) works. Every other filter reads its arguments literally.
For a currency chosen at runtime, branch on it or format the value server-side and pass the finished string through.

Filters bind loosest

A filter applies to the whole expression to its left, including a ternary.
The status is archived, so the ternary chose "live", and upper then applied to that result rather than to the "draft" it sits next to. Parenthesise for the other reading:
A filter also cannot be followed by a binary operator. ${ n | int + 1 } is a parse error; write ${ (n | int) + 1 }.

Text

upper, lower and truncate(n, suffix).
truncate counts characters rather than bytes, so it is safe on non-ASCII text, and it appends the suffix only when it actually cut something. The default length is 50 and the default suffix is three dots.
truncate does not understand HTML. If a cut lands inside a tag the rest of that tag is dropped, and nothing balances the tags you left open. Truncate plain text, not markup.

Numbers

int and float coerce, fixed(n) formats.
fixed replaces toFixed, and it returns a string with exactly that many decimal places. int and float parse all-or-nothing. "12abc" becomes 0, not 12, and so does anything else that is not cleanly a number, including null, arrays and objects. Comparisons in Slurp do not coerce, so {if product.stock > 0} is false when stock is the string "10". Write {if (product.stock | int) > 0}. That trap is explained in full under displaying data.

Money

Known codes are USD, EUR, GBP, JPY, CAD, AUD and CHF. Three things about the output:
  • The symbol always prefixes, for every code, so EUR renders as a leading euro sign rather than the trailing one much of Europe writes. Grouping and the decimal separator do follow the code.
  • Only JPY uses zero decimals. Everything else uses two, and rounds once, so 19.999 renders as $20.00.
  • An unknown code is not an error. The code plus a space becomes the symbol, which is how SEK 12.50 comes out.

Money arrives as a string

A server decimal serialises to JSON as a string such as "49.990000", not as a number. Filters coerce, so this is invisible most of the time:
In emitted JavaScript the value is a string and has no numeric methods:
Without the Number(...) wrapper that is "49.990000".toFixed(2), which throws at runtime. The compiler does not read emitted JavaScript, so nothing warns. Format with | currency or | fixed server-side and pass the finished string where possible.

Dates

The complete token set is YYYY, YY, MMMM, MMM, MM, M, DD and D. There are no time tokens at all: no hours, minutes, seconds, timezone or day-of-week. For a time, format it server-side. There is also no escaping in the format string, so a stray D or M in surrounding text gets substituted. Keep the format to the date and write the words outside the filter.
| date parses ISO strings, not epoch milliseconds. The parser takes the text before the first T or space and splits it on -; fewer than three parts and the input is returned unchanged.
The number renders verbatim with no diagnostic. Return RFC 3339 strings from the server and it cannot arise.

Fallbacks and counts

default substitutes when a value is empty, where empty means null, the empty string, the empty array or the empty object. 0 and false are not empty and pass straight through.
plural picks a word from a count:
The output includes the number. Writing ${ order.count } ${ order.count | plural("item") } renders 3 3 items. The second argument is only needed when adding an s is wrong.

Collections

Four filters work only in an {each} header, and they run before iteration. They are a separate set from everything above.
They chain in the order written:
Two edge cases:
Only the exact lowercase string "desc" reverses. "DESC" and "descending" both silently mean ascending. And filter compares strictly, exactly like ==. filter("stock", "3") never matches a numeric 3, and items that are not objects or that lack the key are dropped rather than kept. sort is stable, and it orders cross-type pairs by type rank rather than erratically, so a mixed collection sorts deterministically.

Sending values to JavaScript

js and json put a value safely inside a <script> body or a JavaScript-evaluated attribute. Every ${ } in a script body must end in one of them, and which one depends on where the slot sits.
The compiler enforces those rules at build time. See Scripts and attributes.

When a filter goes wrong

Filters fail in three ways. An unknown filter fails the build. So does using a loop filter in value position, or a value filter in an {each} header. The two sets are disjoint and the compiler checks both directions:
A missing or non-numeric limit() argument fails the build, because that argument is required rather than defaulted:
Anything else is silent. A non-literal argument to filter() empties the collection, which then renders the {empty} branch:
A loop filter that errors empties the collection rather than raising, so a broken filter looks exactly like missing data. If an {empty} branch appears while the data is present, check the filter arguments first.

Next

Filter reference

All 17 filters alphabetically, with null behaviour and traps.

Control flow

Where the loop filters go, and the iteration budget.

Scripts and attributes

When | js applies and when | json does.

Common mistakes

The silent failures, collected in one place.