Vascula v0.1.5

Filters

A filter transforms the value on its left: {{ value | filter: argument }}. See Expressions for how chaining and arguments work.

Filters convert their input as needed: string filters treat a number as its printed text, number filters read a numeric string as a number, and array filters treat nil as an empty array. A filter that cannot work with its arguments fails with an error that names it.

Applications add their own filters. Three built-ins can never be replaced by an application: escape, json and default, because they define how output stays safe.

On this page: Strings · HTML · Numbers · Arrays · Dates · URLs · Fallbacks · JSON

#Strings

#upcase

Converts to upper case.

Template
{{ "Café au lait" | upcase }}
Output
CAFÉ AU LAIT

#downcase

Converts to lower case.

Template
{{ "Café AU Lait" | downcase }}
Output
café au lait

#capitalize

Upper-cases the first character and lower-cases the rest.

Template
{{ "éCLAIR WITH CREAM" | capitalize }}
Output
Éclair with cream

#strip, lstrip, rstrip

Remove whitespace from both ends, the start, or the end.

Template
[{{ "  tea  " | strip }}] [{{ "  tea  " | lstrip }}] [{{ "  tea  " | rstrip }}]
Output
[tea] [tea  ] [  tea]

#strip_newlines

Removes every line break.

Template
{{ settings.text | strip_newlines }}
Data
{"settings": {"text": "one\ntwo\r\nthree"}}
Output
onetwothree

#append, prepend

append: text adds text at the end; prepend: text adds it at the start.

Template
{{ "tea" | append: "pot" }} {{ "pot" | prepend: "tea" }}
Output
teapot teapot

#replace, replace_first

replace: old, new replaces every occurrence; replace_first only the first.

Template
{{ "a-b-c" | replace: "-", "+" }} {{ "a-b-c" | replace_first: "-", "+" }}
Output
a+b+c a+b-c

#remove, remove_first

remove: text deletes every occurrence; remove_first only the first.

Template
{{ "a-b-c" | remove: "-" }} {{ "a-b-c" | remove_first: "-" }}
Output
abc ab-c

#truncate

truncate: length, ending shortens text to at most length characters, counting the ending. The default length is 50 and the default ending is .... Text that already fits is unchanged. Characters are never split.

Template
{{ "Vascula templates" | truncate: 10 }} | {{ "Vascula templates" | truncate: 10, "…" }} | {{ "Short" | truncate: 10 }}
Output
Vascula... | Vascula t… | Short

#truncatewords

truncatewords: count, ending keeps the first count words and adds the ending (default ...) when it removed any. Runs of whitespace become single spaces. The count must be at least 1.

Template
{{ "one two  three four" | truncatewords: 2 }} | {{ "one two" | truncatewords: 5 }}
Output
one two... | one two

#split

split: separator splits text into an array. An empty separator splits into single characters; an empty input gives an empty array.

Template
{{ "a,b,,c" | split: "," | join: "|" }} {{ "abc" | split: "" | join: "." }} {{ "" | split: "," | size }}
Output
a|b||c a.b.c 0

#slice

slice: offset, length returns part of a string or an array. A negative offset counts from the end. The length defaults to 1.

Template
{{ "Vascula" | slice: 0, 3 }} {{ "Vascula" | slice: -3 }} {{ "Vascula" | slice: -3, 3 }} {{ settings.list | slice: 1, 2 | join: "," }}
Data
{"settings": {"list": ["a", "b", "c", "d"]}}
Output
Vas u ula b,c

#size

The number of characters in a string, items in an array, or keys in a map. Anything else is 0. The .size property gives the same result.

Template
{{ "Café" | size }} {{ settings.list | size }} {{ nil | size }}
Data
{"settings": {"list": [1, 2, 3]}}
Output
4 3 0

#HTML

#escape

Escapes text for HTML. Printing the result does not escape it again, so escape never double-escapes. Output is escaped anyway; use escape when you store markup-safe text in a variable or pass it to an application filter.

Template
{{ "<b>Tea</b> & cake" | escape }}
Output
&lt;b&gt;Tea&lt;/b&gt; &amp; cake

#escape_once

Escapes text that may already contain character references, without escaping them a second time.

Template
{{ "1 &lt; 2 & 3 > 2" | escape_once }}
Output
1 &lt; 2 &amp; 3 &gt; 2

#strip_html

Removes everything between < and >. The result is text, and is escaped when printed. This is not a sanitizer: use it to make a plain-text summary, not to make markup safe.

Template
{{ "<p>Hello <b>world</b></p>" | strip_html }}
Output
Hello world

#newline_to_br

Escapes the text and replaces each line break with <br>.

Template
{{ settings.text | newline_to_br }}
Data
{"settings": {"text": "line one\n<line two>"}}
Output
line one<br>&lt;line two&gt;

#Numbers

Number filters read numbers and numeric strings. Two integers give an exact integer result (falling back to a decimal on 64-bit overflow); anything with a decimal gives a decimal.

#plus, minus, times

Template
{{ 7 | plus: 3 }} {{ 7 | minus: 10 }} {{ 7 | times: 3 }} {{ 1.5 | times: 2 }} {{ "4" | plus: 1 }}
Output
10 -3 21 3 5

#divided_by

Divides. Two integers that divide exactly give an integer; otherwise the result is a decimal. Dividing by zero is an error.

Template
{{ 10 | divided_by: 2 }} {{ 7 | divided_by: 2 }} {{ 1 | divided_by: 3 | round: 4 }}
Output
5 3.5 0.3333
Template
{{ 1 | divided_by: 0 }}
Error
divided_by: division by zero

#modulo

The remainder of a division, exact for two integers. Its sign follows the input. A zero divisor is an error.

Template
{{ 7 | modulo: 3 }} {{ -7 | modulo: 3 }} {{ 7.5 | modulo: 2 }}
Output
1 -1 1.5

#round, ceil, floor

Round to the nearest integer, up, or down. An optional argument keeps that many decimal places. Halves round away from zero.

Template
{{ 2.5 | round }} {{ 3.14159 | round: 2 }} {{ 2.1 | ceil }} {{ 2.9 | floor }} {{ -2.5 | round }}
Output
3 3.14 3 2 -3

#abs

The absolute value.

Template
{{ -7 | abs }} {{ 2.5 | abs }}
Output
7 2.5

#at_least, at_most

at_least: n returns the larger of the value and n; at_most: n the smaller. Use them to clamp.

Template
{{ 3 | at_least: 5 }} {{ 30 | at_most: 12 }} {{ 8 | at_least: 1 | at_most: 10 }}
Output
5 12 8

#Arrays

#join

join: separator prints each item and joins them. The separator defaults to no separator.

Template
{{ settings.list | join: ", " }} {{ settings.list | join }}
Data
{"settings": {"list": ["a", "b", "c"]}}
Output
a, b, c abc

#first, last

The first or last item, or nil for an empty array. The .first and .last properties do the same.

Template
{{ settings.list | first }} {{ settings.list | last }}
Data
{"settings": {"list": ["a", "b", "c"]}}
Output
a c

#map

map: field returns an array of one field from each item.

Template
{{ settings.people | map: "name" | join: ", " }}
Data
{"settings": {"people": [{"name": "Ada"}, {"name": "Grace"}]}}
Output
Ada, Grace

#where

where: field keeps the items whose field is truthy. where: field, value keeps the items whose field equals the value.

Template
{{ settings.items | where: "available" | map: "name" | join: "," }} / {{ settings.items | where: "color", "red" | map: "name" | join: "," }}
Data
{"settings": {"items": [
  {"name": "cup", "available": true, "color": "red"},
  {"name": "pot", "available": false, "color": "red"},
  {"name": "jug", "available": true, "color": "blue"}
]}}
Output
cup,jug / cup,pot

#sort, sort_natural

sort orders items ascending; sort: field orders by a field. Numbers sort as numbers and strings in character order (upper case before lower case). sort_natural compares the printed text case-insensitively. Items that cannot be compared keep their original order.

Template
{{ settings.nums | sort | join: "," }} {{ settings.words | sort | join: "," }} {{ settings.words | sort_natural | join: "," }} {{ settings.items | sort: "price" | map: "name" | join: "," }}
Data
{"settings": {
  "nums": [10, 2, 33],
  "words": ["banana", "Cherry", "apple"],
  "items": [{"name": "b", "price": 5}, {"name": "a", "price": 2}]
}}
Output
2,10,33 Cherry,apple,banana apple,banana,Cherry a,b

#reverse

Reverses the order.

Template
{{ (1..4) | reverse | join: "," }}
Output
4,3,2,1

#uniq

Removes repeated items, keeping the first of each. Items compare with equality, so 1 and 1.0 are the same.

Template
{{ settings.list | uniq | join: "," }}
Data
{"settings": {"list": ["a", "b", "a", "c", "b"]}}
Output
a,b,c

#compact

Removes nil items.

Template
{{ settings.list | compact | join: "," }}
Data
{"settings": {"list": ["a", null, "b", null]}}
Output
a,b

#concat

concat: other joins two arrays.

Template
{{ settings.a | concat: settings.b | join: "," }}
Data
{"settings": {"a": [1, 2], "b": [3]}}
Output
1,2,3

#sum

Adds up the items, or sum: field adds up one field of each item. Items that are not numbers are skipped.

Template
{{ settings.prices | sum }} {{ settings.lines | sum: "qty" }}
Data
{"settings": {"prices": [1.5, 2, "x"], "lines": [{"qty": 2}, {"qty": 3}]}}
Output
3.5 5

#Dates

#date

date: format formats a date. The input is a date string (2026-10-02, 2026-10-02 14:30:00, or RFC 3339 such as 2026-10-02T14:30:00Z), a date value from the application, or "now" or "today" (the current time in UTC). The format uses strftime directives:

DirectiveMeaningExample
%Y, %yyear, two-digit year2026, 26
%m, %d, %emonth, day, day padded with a space10, 02, 2
%B, %bmonth name, short month nameOctober, Oct
%A, %aweekday, short weekdayFriday, Fri
%H, %I, %phour (24h), hour (12h), AM/PM14, 02, PM
%M, %Sminute, second30, 00
%jday of the year275
%sUnix seconds1790951400
%Z, %ztime zone name, offsetUTC, +0000
%%a percent sign%

Other directives are printed as written. A value that is not a date, or a missing format, is an error.

Template
{{ "2026-10-02T14:30:00Z" | date: "%A, %e %B %Y at %H:%M" }} | {{ "2026-10-02" | date: "%d/%m/%y" }}
Output
Friday,  2 October 2026 at 14:30 | 02/10/26
Template
{{ "next week" | date: "%Y" }}
Error
date: cannot parse "next week" as a date

#URLs

#url_encode, url_decode

Encode text for use in a URL query, or decode it. Spaces become +.

Template
{{ "tea & cake" | url_encode }} {{ "tea+%26+cake" | url_decode }}
Output
tea+%26+cake tea &amp; cake

#Fallbacks

#default

default: fallback returns the fallback when the value is nil, false, an empty string or an empty collection. Unlike a condition, it treats "" as missing. 0 is a real value and is kept.

With allow_false: true, an explicit false is kept, which lets a setting that defaults to true still be switched off.

Template
[{{ settings.title | default: "Untitled" }}] [{{ settings.count | default: 10 }}] [{{ settings.missing | default: "none" }}] [{{ settings.flag | default: true }}] [{{ settings.flag | default: true, allow_false: true }}]
Data
{"settings": {"title": "", "count": 0, "flag": false}}
Output
[Untitled] [0] [none] [true] [false]

#JSON

#json

Converts a value to JSON. Inside <script> it is printed as JSON with <, > and & encoded; inside an HTML tag it is also escaped for HTML. See Output: JSON.

Template
<script>const data = {{ settings.data | json }};</script>
Data
{"settings": {"data": {"tags": ["a", "<b>"], "count": 2}}}
Output
<script>const data = {"count":2,"tags":["a","\u003cb\u003e"]};</script>

Map keys are written in sorted order.