目录

Stencil

MoonBit License GitHub CI GitLink CI

Stencil is a lightweight Mustache-style template engine for MoonBit. It focuses on the subset of features that are most useful in application code: variable interpolation, sections, inverted sections, partials, comments, dotted-path lookup, and safe HTML escaping by default.

Why this project

  • Small API surface: render, compile, and partial-aware rendering helpers.
  • Safe-by-default output: {{name}} escapes HTML automatically.
  • Practical Mustache coverage: sections, inverted sections, lists, object contexts, comments, raw variables, and partials.
  • MoonBit-first maintenance: tests, CI, changelog, and repository self-checks are part of the project itself.

Feature Summary

  • Escaped variables: {{name}}
  • Raw variables: {{{html}}} and {{&html}}
  • Sections: {{#items}}...{{/items}}
  • Inverted sections: {{^items}}...{{/items}}
  • Dotted-path lookup: {{user.profile.name}}
  • Implicit iterator for lists: {{.}}
  • Partials with standalone indentation propagation
  • Comment tags: {{! ignored }}

Installation

Add the package to your MoonBit module:

moon add LL124-Arch/stencil

Or import it directly in code:

import {
  "LL124-Arch/stencil/src" @stencil,
}

Quick Start

fn main {
  let template = "Hello {{name}}! Welcome to {{project}}."
  let data : Json = {
    "name": "Developer",
    "project": "Stencil",
  }

  try {
    let result = @stencil.render(template, data)
    println(result)
  } catch {
    @stencil.TemplateError(msg) => println("Template error: \{msg}")
  }
}

Output:

Hello Developer! Welcome to Stencil.

API

render(template : String, data : Json) -> String raise TemplateError

Compile and render a template in one step.

compile(source : String) -> Template raise TemplateError

Compile a template once and reuse it with different JSON inputs.

Template::render(self : Template, data : Json) -> String

Render a precompiled template with the provided context.

render_with_partials(template : String, data : Json, partials : Map[String, String]) -> String raise TemplateError

Render a template while supplying partial sources by name.

Template::render_with(self : Template, data : Json, partials : Map[String, String]) -> String

Render a precompiled template with named partial sources.

Mustache Compatibility Notes

Stencil intentionally supports a practical core instead of every corner of the full Mustache spec.

Supported behavior:

  • Variables and raw variables
  • Truthy and falsey section rendering
  • List iteration with {{.}}
  • Nested object contexts
  • Inverted sections
  • Partials
  • Comments
  • Dotted-path lookup

Current behavior boundaries:

  • Missing keys render as empty strings
  • Arrays stringify as [Array] outside section iteration
  • Objects stringify as [Object] outside section traversal
  • Missing partials currently render as empty strings
  • Invalid partial source is ignored by render_with_partials / Template::render_with

These boundaries are documented so callers can rely on stable behavior instead of guessing from implementation details.

Examples

HTML-safe output

let tpl = "<p>{{content}}</p>"
let result = @stencil.render(tpl, { "content": "<script>alert(1)</script>" })
// <p>&lt;script&gt;alert(1)&lt;/script&gt;</p>

Reusing a compiled template

let tpl = @stencil.compile("User: {{name}}")
println(tpl.render({ "name": "Alice" }))
println(tpl.render({ "name": "Bob" }))

Partials with indentation

let template = "items:\n  {{>item}}\ndone"
let partials = {
  "item": "- {{name}}\n- ready",
}
let data : Json = { "name": "Stencil" }
let result = @stencil.render_with_partials(template, data, partials)

Output:

items:
  - Stencil
  - ready
done

Production-style email snippet

let template =
  "Hello {{user.name}},\n" +
  "{{#items}}- {{title}}: {{status}}\n{{/items}}" +
  "{{^items}}No pending tasks.\n{{/items}}"

let data : Json = {
  "user": { "name": "Ops Team" },
  "items": [
    { "title": "CI", "status": "green" },
    { "title": "Release", "status": "pending" },
  ],
}

CLI Demo

This repository includes a small runnable CLI example:

moon run cli

Development

Recommended local verification loop:

moon fmt --check
moon check --deny-warn --target all
moon info --target all
git diff --exit-code
moon test --deny-warn --target wasm,wasm-gc,js

If a system C compiler is available, also run:

moon test --deny-warn --target native

CI and Toolchain Notes

The official OSC2026 feedback asked for strict formatting, interface generation, type checking, and tests under the latest MoonBit toolchain.

With current MoonBit CLI moonc v0.10.3, strict warning mode is available on moon check and moon test, but not exposed on moon fmt or moon info. This repository therefore enforces the current strict equivalents in CI:

  • moon fmt --check
  • moon check --deny-warn --target all
  • moon info --target all
  • git diff --exit-code
  • moon test --deny-warn --target ...

Both GitHub Actions and GitLink CI are included:

OSC2026 Self-Check

For competition maintenance, run:

powershell -ExecutionPolicy Bypass -File scripts\verify_acceptance.ps1

The script checks:

  • repository structure,
  • README and license presence,
  • GitHub and GitLink CI files,
  • commit history summary,
  • default branch visibility,
  • MoonBit source scale,
  • local verification commands.

See docs/acceptance-checklist.md for the requirement-to-evidence mapping used in this repository.

License

This project is licensed under the Apache License 2.0. See LICENSE for details.

关于

一个用 MoonBit 编写的轻量级模板引擎库,支持变量插值、条件渲染、列表迭代、模板组合等能力,基于 MoonBit 内置 Json 类型实现数据绑定,适用于 Web 渲染、代码生成、文档输出等场景。

320.0 KB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号