LuaFilters
User-defined template filters written in Lua.
Scripts live either site-wide in filters/*.lua (like shortcodes) or
in the current theme's filters/*.lua; on name collisions the
site-level script wins. Each script must return a table mapping filter
names to functions; every function becomes a Crinja filter callable as
{{ value | name(extra, args) }}, invoked as name(value, extra, args).
Example (themes/<theme>/filters/example.lua):
return {
shout = function(text)
return string.upper(text) .. "!"
end,
}
Loading model: each Crinja environment owns one State which parses
every script exactly once per build. Script top-level code runs once
per environment, so keep it free of side effects (returning the table
of functions is all that matters).
Concurrency: the env pool in Templates guarantees an environment is never used by two fibers at once, so Lua states need no locking.
Staleness: script files are declared as inputs of every template- rendering task family (posts, pages, taxonomies, listings, books, galleries, archive, base16), so Croupier re-renders affected pages when they change and reports them through its modified set; States rebuild off that signal instead of polling the filesystem.
Security: scripts run with Lua's full standard library (os, io, debug), so themes are trusted code. Anyone who can write filters/*.lua can do anything the build user can — same trust level as conf.yml or the shell shortcode, but worth knowing before installing third-party themes.
Constants
Class methods
Merge theme and site script lists; both groups stay alphabetically sorted, theme group first. State loads paths in order and last export wins, so site-level scripts override theme defaults. Internal (exercised by specs); not part of the public API.
Script file paths to declare as task inputs, so pages rendered with these filters get invalidated (and watched in auto mode) when any script changes.
Directory holding user scripts for the current theme. Internal (used by State); not part of the public API.
Register all exported functions as Crinja filters on env.
The State is built eagerly here: this both discovers filter names and performs the environment's only parse of the scripts. The closures bind that same State, so concurrent fibers never share a Lua state (one State per environment, guaranteed by Templates).
All script files currently on disk: site-level filters/*.lua
first-class like shortcodes, plus the current theme's scripts.
Site files sort last so their exports win name collisions.
Internal (used by State); not part of the public API.