Revision history for Template::Jinja2
0.2.0 2026-04-30T00:14:18+01:00
- Bump Github Actions to use node 24+
- Add raise_exception() builtin global. Throws TemplateRuntimeError
with the supplied message; used by HuggingFace chat templates
(Mistral, Llama-3-Instruct, etc.) to assert structural invariants
such as user/assistant alternation and validate role/content shapes.
- Fix string + concatenation. The BinOp '+' branch had inverted
logic — both code paths fell through to numeric addition, so
`{{ "[INST]" + msg + "[/INST]" }}` threw X::Str::Numeric. Real
HF templates (Mistral, Llama-3-Instruct, Qwen) use + for string
concat throughout, so this blocked rendering them.
- Fix rebinding of render-arg variables via `{% set %}`. Context
pushed the slurpy *%vars Hash directly, preserving readonly value
containers from named-arg binding; any later `{% set foo = ... %}`
where `foo` was a render arg died with "Cannot assign to an
immutable value". Mistral and Llama-3-Instruct use this idiom
for option self-defaulting (e.g. `set re = re if re is defined
and re is not none else 'none'`).
- With both fixes: Mistral Small 4's full upstream chat template
now renders end-to-end (see t/09-huggingface.rakutest). This
exercises namespace mutation for alternation tracking, sort
(attribute=…), structured {type, text|thinking|image} content
arrays, raise_exception, and render-arg self-defaulting.
0.1.1 2026-04-09T04:35:22+01:00
- Fix LoopContext forward declaration causing precompilation failure on zef install
- Remove Python reference tests from distribution
0.1.0 2026-04-09T04:09:36+01:00
- Initial release
- Complete Jinja2 template engine for Raku targeting compatibility with Python Jinja2 3.1
- Grammar-based lexer with Pratt-style expression parser
- All 15 tag types: if/elif/else, for, set, with, block, extends, include, import, from,
macro, call, filter, do, raw, comment, break, continue, autoescape
- Full expression syntax: arithmetic, comparison, logical, membership, identity, ternary,
string concat (~), chained comparisons, slicing
- 52 built-in filters including tojson, escape, upper, lower, sort, groupby, map,
select, reject, batch, slice, truncate, filesizeformat, and more
- 20+ built-in tests: defined, undefined, none, even, odd, divisibleby, string, number, etc.
- Template inheritance with extends/block/super() supporting multi-level chains
- Recursive for loops with loop() callable, depth tracking, break/continue
- Full loop context: index, index0, revindex, first, last, length, cycle, changed,
previtem, nextitem
- Macros with default arguments, varargs, kwargs, caller(), recursive self-calls
- Call blocks with parameterized caller
- Namespace objects for cross-scope state in loops
- Whitespace control: trim markers ({%- -%}), +/- markers, trim_blocks, lstrip_blocks
- Custom delimiters (PHP, ERB, comment syntax, etc.)
- Line statement prefix and line comment prefix
- Autoescape with SafeString support for set blocks
- Numeric literals: hex, octal, binary, scientific notation, underscores
- Django-style numeric dot access, string literal concatenation
- Dotted attribute resolution in filters (sort, groupby, sum, etc.)
- Built-in globals: range(), namespace(), dict(), cycler(), joiner()
- DictLoader, FileSystemLoader
- keep_trailing_newline, newline_sequence configuration
- Error validation for reserved names, constant assignment, block hyphens, macro params
- 612 tests across 22 test files
- Real-world validation: byte-identical output against Python Jinja2 for ChatML, Llama 3,
Mistral, Gemma 2, Zephyr, and Cohere Command A (15K char template) formats