# MoonJinja

[English](README.md)

MoonJinja 是面向 MoonBit 的运行时 Jinja 风格模板引擎。0.2 版本以
`Environment` 统一管理模板、loader、缓存和扩展，直接接受任意 `ToJson` 数据，
并支持 wasm、wasm-gc、JavaScript 与 native 后端。

## 安装

```bash
moon add ZSeanYves/moonjinja@0.2.1
```

在应用包的 `moon.pkg` 中导入：

```moonbit
import {
  "ZSeanYves/moonjinja",
}
```

## 快速开始

```moonbit
fn render_page() -> String raise Error {
  let environment = @moonjinja.Environment::new()
  environment.set_options(
    @moonjinja.RenderOptions::default().with_autoescape(true),
  )
  environment.add_template(
    "hello.html",
    "Hello {{ user.name | upper }}!",
  )
  environment.render("hello.html", {
    "user": { "name": "MoonBit" },
  })
}
```

仓库内的完整可执行示例位于 `src/examples/basic`：

```bash
moon run src/examples/basic
```

## 模板加载

模板既可以直接注册，也可以交给应用提供的 loader。核心包不再访问文件系统：

```moonbit
let environment = @moonjinja.Environment::new()
environment.set_loader(name => {
  match name {
    "layout.html" => Ok("<{% block body %}{% endblock %}>")
    "page.html" => Ok(
      "{% extends \"layout.html\" %}" +
      "{% block body %}{{ message }}{% endblock %}",
    )
    _ => Err("template not found: " + name)
  }
})
let output = environment.render("page.html", { "message": "Ready" })
```

loader 结果和解析后的模板都会缓存。替换 loader 时只失效 loader 加载的条目，
不会删除 `add_template` 注册的模板；`reload_template` 刷新单个 loader 条目，
`clear_cache` 清除全部解析缓存，容量设为 0 可关闭解析和 loader 源缓存。
开发态可使用返回 `(source, version)` 的 `set_versioned_loader`；只有版本令牌变化时
才重新编译。

## 扩展函数、过滤器和测试

内置能力和外部扩展使用相同的 registry 接口：

```moonbit
environment.add_filter("surround", (value, args) => {
  let marker = match args {
    [first, ..] => first.to_display_string()
    [] => "*"
  }
  Ok(@moonjinja.Value::StrValue(
    marker + value.to_display_string() + marker,
  ))
})
environment.add_function("answer", _ =>
  Ok(@moonjinja.Value::IntValue(42)))
environment.add_test("positive", (value, _) =>
  match value {
    @moonjinja.Value::IntValue(number) => Ok(number > 0)
    _ => Err("positive expects an integer")
  })
```

带 context 的注册接口还支持 keyword arguments，并通过 `ExtensionContext` 提供
模板名、autoescape 和 sandbox 状态。回调边界会深拷贝动态值。

## 支持的语法

- 变量、点路径、索引、列表/映射字面量、真除法、`**`、`~`、比较链、
  保留操作数的 `and`/`or`、行内条件、`not`、`in` 和 `is` 测试。
- `if`/`elif`/`else`、`for`/`else`、循环元数据、`break`、`continue`。
- `set`、具有独立 scope 的 `with`、带/不带 context 的 include、raw 块。
- `macro`、默认参数、`call`/`caller`、`import`、`from import`。
- 多级 `extends`、`block`、`super()` 和 `self.block()`。
- `-` 空白标记，以及环境级 `trim_blocks`、`lstrip_blocks`。

内置过滤器包括 `upper`、`lower`、`trim`、`split`、`safe`、`escape`
（别名 `e`）、`length`、`default`、`join`、`replace`、`first`、`last`、
`reverse`、`abs`、`string`、`capitalize`、`title`、`wordcount`、`sum`、
`min`、`max`、`unique`、`sort`、`keys`、`values` 和 `items`；内置函数包括
`range`、`list`、`dict` 与 `namespace`。

## 安全与资源限制

渲染 HTML 时应开启 autoescape。`escape` 会实际编码不安全文本并返回安全字符串；
`safe` 只能用于可信 HTML。

`RenderOptions` 可以配置严格未定义变量、空白策略、fuel、解析/渲染/include 深度、
UTF-8 输出/源码字节上限、有界缓存和 `range` 最大分配。模板名拒绝绝对路径、
盘符路径和 `..`；include 与继承循环会被拒绝。

`with_sandbox(true)` 会强制 autoescape、拒绝 `safe`，并默认禁止用户扩展；
经过审计的扩展可用 `allow_extension_in_sandbox` 逐个放行。loader 和获准回调仍是
可信宿主代码，完全不可信模板还需要进程或容器隔离。

`CompiledTemplate::render_to` 可把输出片段直接写入回调，不构造完整结果字符串。

## 验证

```bash
moon fmt --check
moon check --target all --deny-warn
moon test --target all --deny-warn
moon bench --target native --release --deny-warn
```

详细信息参见[兼容矩阵](docs/COMPATIBILITY.md)、
[0.2 迁移指南](docs/MIGRATION_0.2.md)和[性能报告](docs/PERFORMANCE.md)。

## 许可证

Apache-2.0。
