<feed xmlns='http://www.w3.org/2005/Atom'>
<title>colitur.git/lib/render/template.ml, branch v0.8.0</title>
<subtitle>deterministic OCaml engine to compute and validate liturgical calendars for multiple rites, template-driven output to year 9999</subtitle>
<id>https://git.labunix.xyz/colitur.git/atom?h=v0.8.0</id>
<link rel='self' href='https://git.labunix.xyz/colitur.git/atom?h=v0.8.0'/>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/'/>
<updated>2026-08-19T06:17:30Z</updated>
<entry>
<title>feat(render): template renderer with mandatory escaping</title>
<updated>2026-08-19T06:17:30Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-19T06:17:30Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=da9cf402ceed8102aec1a9d008f8e918a23d39f3'/>
<id>urn:sha1:da9cf402ceed8102aec1a9d008f8e918a23d39f3</id>
<content type='text'>
Every interpolated value is escaped for the template's flavour; the
template's own literal text never is, because that is the author's
markup. There is no raw form, so a template cannot opt out.

Scope is a stack with outward fallback, so a grid template can reach the
year number from inside a week without the view duplicating it into
every cell.

A missing key renders empty -- the one deliberate silence, so a template
survives a rite that does not set every optional field.

Mutation-tested: dropping the Escape.apply call reddens the
data-cannot-escape-flavour case.
</content>
</entry>
<entry>
<title>fix(render): reject empty tag paths, sharpen the raw-form test</title>
<updated>2026-08-19T06:09:12Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-19T06:09:12Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=a526d934cea17ff1b76ddad5c5f2934fb85c11cb'/>
<id>urn:sha1:a526d934cea17ff1b76ddad5c5f2934fb85c11cb</id>
<content type='text'>
F1: test_no_raw_or_partial_form's first assertion only excluded one
literal shape (Ok [Var ["{name"]]), so it could not actually catch a
future raw/unescaped constructor under a different name. Replace it
with an assertion of the real parse result for {{{name}}}
(Ok [Var ["{name"]; Text "}"]), documented behaviour rather than a
guarantee this test cannot check -- the real guarantee is structural:
node has exactly four constructors and none of them is raw.

F2: {{.}}, {{#}}, {{^}} and {{/}} used to parse to a Var/Section/
Inverted with an empty path, reachable but never designed. This engine
has no "current context" for a bare dot to mean, so a bare-dot or
empty-sigil path is now a parse error at lex time, covering all four
sigil forms via one path helper. The existing "empty tag {{}}" branch
is unchanged and still reachable (a fully empty body is a distinct
case from a sigil with an empty path).
</content>
</entry>
<entry>
<title>feat(render): logic-less template parser</title>
<updated>2026-08-19T06:01:11Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-19T06:01:11Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=eacb54ae44f655c010fdfc2b7292d24f06ffc445'/>
<id>urn:sha1:eacb54ae44f655c010fdfc2b7292d24f06ffc445</id>
<content type='text'>
Placeholders, sections, inverted sections, comments. Nothing else: no
partials, no lambdas, no expression evaluation, no raw form. A template
is data, never a program, which is what keeps an untrusted template safe.

Errors rather than silence on a malformed template: an unterminated tag,
an unclosed section, a mismatched close and a partial all return Error.
Swallowing '{{name' as text is how a typo becomes invisible missing
output in a printed booklet.
</content>
</entry>
</feed>
