Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .github/workflows/docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ concurrency:
env:
# Keep in step with test.yml's pin -- docs runs `mojo doc`, which compiles the
# sources and so breaks on the same stdlib changes the tests do.
MOJO_VERSION: "1.0.0b3.dev2026073014"
MOJO_VERSION: "1.0.0"

jobs:
build-deploy:
Expand All @@ -35,9 +35,7 @@ jobs:
- name: Install Mojo
run: |
uv venv
uv pip install "mojo==$MOJO_VERSION" \
--index https://whl.modular.com/nightly/simple/ \
--prerelease allow
uv pip install "mojo==$MOJO_VERSION"

- name: Generate API reference
run: |
Expand Down
16 changes: 7 additions & 9 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ on:
workflow_dispatch:

env:
# The nightly this repo is known to build and pass on. CI installs exactly
# this for pushes and PRs, so upstream churn cannot turn a green repo red
# without a commit. Bump it when the weekly drift check goes green on a newer
# one, or after fixing whatever it caught.
MOJO_VERSION: "1.0.0b3.dev2026073014"
# The released Mojo this repo is known to build and pass on. CI installs
# exactly this for pushes and PRs, so upstream churn cannot turn a green repo
# red without a commit. Bump it when the weekly drift check goes green on a
# newer one, or after fixing whatever it caught.
MOJO_VERSION: "1.0.0"

jobs:
test:
Expand All @@ -40,9 +40,7 @@ jobs:
--index https://whl.modular.com/nightly/simple/ \
--prerelease allow
else
uv pip install "mojo==$MOJO_VERSION" \
--index https://whl.modular.com/nightly/simple/ \
--prerelease allow
uv pip install "mojo==$MOJO_VERSION"
fi
.venv/bin/mojo --version

Expand Down Expand Up @@ -75,7 +73,7 @@ jobs:
Run: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID

Fix the breakage, then bump MOJO_VERSION in .github/workflows/test.yml
and .github/workflows/docs.yaml to the nightly that passes.
and .github/workflows/docs.yaml to the release that passes.
EOF
)
existing=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open \
Expand Down
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
# Changelog

## Unreleased
## 0.2.0 — 2026-08-11

- **Builds on released Mojo 1.0.** The pixi channel moved from
`max-nightly` to `max` and the dependency pin from `>=1.0.0b3.dev…` to
`>=1.0,<2`; CI installs `mojo==1.0.0` from PyPI instead of the nightly
index with `--prerelease allow`. The weekly drift check still runs
against the latest nightly, so the repo still reports when the language
moves under it.
- **1.0 source fixes.** `_Parser.parse_body`'s `stops` list and
`_make_loop`'s `keys`/`values` are now annotated (`List[String]` and
`List[TemplateValue]`). Under 1.0 a bare list expression builds an
`Array`, which no longer converts to a `List` parameter.
- README test count corrected: 59 → 104.

- New `template.errors` module (exported from the package), following the
error-reporting pattern shared across the mojo-* parser suite:
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
**A Jinja-flavored template engine in pure Mojo, verified byte-for-byte against Jinja2. No Python dependencies, no FFI.**

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](LICENSE)
[![Mojo](https://img.shields.io/badge/Mojo-1.0.0b3%2B_nightly-orange?style=flat-square)](https://mojolang.org)
[![Mojo](https://img.shields.io/badge/Mojo-1.0-orange?style=flat-square)](https://mojolang.org)
[![Podcast](https://img.shields.io/badge/Podcast-Chain_of_Thought-purple?style=flat-square)](https://chainofthought.show/?utm_source=github&utm_medium=referral&utm_campaign=repo-readme&utm_content=mojo-template)
[![X](https://img.shields.io/badge/X-@ConorBronsdon-black?style=flat-square&logo=x)](https://x.com/ConorBronsdon)

Expand Down Expand Up @@ -157,11 +157,11 @@ Or with uv:

```bash
uv venv
uv pip install mojo --index https://whl.modular.com/nightly/simple/ --prerelease allow
uv pip install mojo
.venv/bin/mojo run -I src test/test_template.mojo
```

Requires a Mojo nightly (`>=1.0.0b3`).
Requires Mojo 1.0 or newer.

## Usage

Expand All @@ -175,12 +175,12 @@ body built from a nested context with a loop and a conditional).
## Tests

```bash
pixi run test # 59 tests: per-feature + Jinja2 fixture parity
pixi run test # 104 tests: per-feature, Jinja2 parity, error positions
pixi run demo # render the example email
pixi run fuzz "{% for x in items %}{{ x }}{% endfor %}"
```

59 tests total, all green, plus Jinja2 byte-compatibility: Jinja2's
104 tests total, all green, plus Jinja2 byte-compatibility: Jinja2's
escaping and whitespace defaults (`autoescape=True`) are the spec.
`test/data/gen_fixtures.py` renders 43 templates against a shared context
with Jinja2 and writes the outputs to `test/data/fixtures/manifest.txt`;
Expand Down
6 changes: 3 additions & 3 deletions pixi.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[workspace]
authors = ["Conor Bronsdon <cmbronsdon@gmail.com>"]
channels = ["https://conda.modular.com/max-nightly", "conda-forge"]
channels = ["https://conda.modular.com/max", "conda-forge"]
name = "mojo-template"
description = "A standalone Jinja-flavored template engine in pure Mojo"
platforms = ["linux-64", "osx-arm64"]
version = "0.1.0"
version = "0.2.0"

[tasks]
test = "mojo run -I src test/test_template.mojo && mojo run -I src test/test_errors.mojo"
Expand All @@ -15,4 +15,4 @@ fmt = "mojo format src/ test/ examples/ bench/"
docs = "mojo doc -o docs/api.json -I src src/template && python3 docs/render_api.py docs/api.json docs/api.html"

[dependencies]
mojo = ">=1.0.0b3.dev0,<2"
mojo = ">=1.0,<2"
4 changes: 2 additions & 2 deletions recipe.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# Build locally with: rattler-build build --recipe recipe.yaml

context:
version: "0.1.0"
version: "0.2.0"

package:
name: mojo-template
Expand All @@ -29,7 +29,7 @@ build:

requirements:
run:
- mojo >=1.0.0b3.dev0,<2
- mojo >=1.0,<2

about:
homepage: https://github.com/conorbronsdon/mojo-template
Expand Down
6 changes: 5 additions & 1 deletion src/template/parser.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,11 @@ struct _Parser(Copyable, Movable):
var cond_base = content_off + self._word_end(inner, String("if"))
conds.append(self.parse_expr_string(cond_src, cond_base))
self.pos += 1 # consume the {% if %}
var stops = [String("elif"), String("else"), String("endif")]
var stops: List[String] = [
String("elif"),
String("else"),
String("endif"),
]
branches.append(self.parse_body(stops, depth + 1, opened_at))
var else_body = List[Int]()
var has_else = False
Expand Down
4 changes: 2 additions & 2 deletions src/template/render.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ def _apply_filter(


def _make_loop(index0: Int, length: Int) raises -> TemplateValue:
var keys = [
var keys: List[String] = [
String("index"),
String("index0"),
String("first"),
Expand All @@ -365,7 +365,7 @@ def _make_loop(index0: Int, length: Int) raises -> TemplateValue:
String("revindex"),
String("revindex0"),
]
var values = [
var values: List[TemplateValue] = [
TemplateValue(index0 + 1),
TemplateValue(index0),
TemplateValue(index0 == 0),
Expand Down
Loading