lithos-gotmpl-core

Crates.iolithos-gotmpl-core
lib.rslithos-gotmpl-core
version0.1.0
created_at2025-11-01 19:46:42.267614+00
updated_at2025-11-01 19:46:42.267614+00
descriptionCore helpers and runtime wiring for lithos-gotmpl-engine, mirroring Go's built-in template functions.
homepagehttps://github.com/hans-d/lithos-gotmpl-rs
repositoryhttps://github.com/hans-d/lithos-gotmpl-rs
max_upload_size
id1912343
size40,735
Hans Donner (hans-d)

documentation

https://docs.rs/lithos-gotmpl-core

README

lithos-gotmpl-rs

A Rust implementation for go template and related libraries. The core surface is split into:

  • lithos-gotmpl-engine: hand-rolled lexer/parser/runtime that evaluates Go text/template syntax. Apps inject function registries when building templates.
  • lithos-gotmpl-core: default helper pack that mirrors the stock Go text/template built-ins (e.g. eq, printf, index, default).
  • lithos-sprig: a Rust-friendly slice of the sprig function library so gitmpl and similar engines can avoid cgo while staying behaviourally aligned with upstream Sprig.

Project layout

  • crates/lithos-gotmpl-engine/src/ – core parser/evaluator. Template instances accept a FunctionRegistry and execute pipelines by delegating to registered helpers. Action nodes expose parsed Pipeline/Command structures, so constructs like {{ .name | default "foo" | upper }} surface as three distinct commands in the AST (field lookup, default, then upper). Branching forms such as if/range/with materialise as dedicated AST nodes with nested blocks, matching the shape of Go's parse package. The engine honours Go-style whitespace trim markers ({{- / -}}) and pipeline variable bindings like {{$val := .item}} with lexical scoping across control structures.
  • crates/lithos-gotmpl-core/src/ – base helper bundle that registers the canonical Go text/template built-ins atop the engine.
  • crates/lithos-sprig/src/ – sprig-style helpers layered on top of the engine/core crates.
  • test-cases/lithos-sprig.json – shared test vectors describing calls that mirror Go sprig behaviour. Each entry captures both function arguments and a template snippet with its expected rendering.
  • test-cases/lithos-gotmpl-core.json – vectors harvested from Go's text/template tests to validate our built-in helper semantics.
  • go-sanity/ – shared Go runner used to sanity-check test cases against the real Go implementation.
  • crates/lithos-sprig/tests/compat.rs – integration test that drives the go-sanity runner and asserts the Rust implementations stay in lock-step.
  • justfile – light CLI automation for common tasks.

Development

You can work either inside the provided dev container or with a native toolchain:

  • Dev container – use the Dev Containers specification. For example, with the devcontainer CLI:
    devcontainer up --workspace-folder .
    devcontainer exec --workspace-folder . just ci-test
    
    Editors such as VS Code or GitHub Codespaces can also consume the same definition. The container installs Rust (stable + nightly), Go 1.25.1, Python 3.12, and all required CLI tools via .devcontainer/postCreate.sh.
  • Native setup – install the prerequisites manually and run just install-ci-tools to pull in the cargo utilities and linters we use in CI.
just go-sanity  # runs the shared Go sanity harness against sprig test cases
just test       # runs the Rust unit + integration tests
just verify     # executes both
just ci-test    # matches the GitHub Actions test job locally
just ci-behavior  # runs compat + optional property/contract suites
just ci-quality # fmt + clippy gate
just ci-security # cargo audit / cargo deny (requires tools installed)
just ci-mutation # cargo-mutants sweep (requires `cargo install cargo-mutants`)
just mutation   # alias for ci-mutation
just ci-fuzz    # smoke-tests the fuzz harnesses (requires nightly + cargo-fuzz)
just fuzz       # alias for ci-fuzz
just ci-release  # dry-run release-plz workflow
just release    # alias for ci-release
just install-ci-tools # installs cargo-audit, cargo-deny, cargo-tarpaulin, cargo-mutants, cargo-fuzz, actionlint, yamllint, release-plz
just install-cargo-audit|deny|tarpaulin|cargo-mutants|cargo-fuzz|actionlint|yamllint|release-plz # install individual extras

The integration test will skip itself gracefully if Go is missing. Keep the cases in test-cases/lithos-sprig.json aligned with the functions implemented in Rust for deterministic comparisons. When scenarios get more complex, add subdirectories under test-cases/ containing input.tmpl, input.json, and expected.* assets that both the Rust harness and Go oracle can consume (see test-cases/sprig/nested-default/ for an example covering nested pipelines).

Rust toolchain: the workspace targets the 2021 edition. The minimum supported Rust version (MSRV) is 1.70.0; CI should exercise the latest stable release as well as MSRV once it is wired up.

Automation

  • GitHub Actions CI (.github/workflows/ci.yml) fan-outs into dedicated jobs: the core unit test suite, behavioural validation (including the Go-backed compatibility harness), code quality (fmt, Clippy, actionlint, yamllint, optional Sonar scan), and security scans (cargo audit + cargo deny).
  • Deep Testing (.github/workflows/deep-testing.yml) is scheduled weekly to run the fuzz harnesses (requires the Rust nightly toolchain) and, on the first of each month, mutation tests.
  • SonarQube / SonarCloud (.github/workflows/sonar.yml) is ready to analyse the workspace. Provide a SONAR_TOKEN repository secret and, if needed, SONAR_HOST_URL before enabling the workflow; adjust sonar-project.properties with your actual organisation/project keys.
  • Renovate Bot (renovate.json) is configured to group weekly Rust and Go dependency updates. Install the Renovate GitHub App (or hook through GitHub Actions) to activate automated PRs.
  • CodeRabbit (.coderabbit.yaml) supplies default review hints for pull requests. Once the CodeRabbit GitHub App is installed, it will auto-review changes that touch the Rust crates or the Go oracle code.

Using the helper crates

A typical integration wires the engine, default Go helpers, and Sprig helpers together before parsing templates:

use lithos_gotmpl_core::{install_text_template_functions, Template};
use lithos_sprig::install_sprig_functions;

let mut builder = lithos_gotmpl_core::FunctionRegistryBuilder::new();
install_text_template_functions(&mut builder);      // Go defaults (`eq`, `printf`, ...)
install_sprig_functions(&mut builder);              // Sprig helpers (flow, strings, lists)

let registry = builder.build();
let tmpl = Template::parse_with_functions(
    "example",
    "{{ coalesce .name \"friend\" | title }}",
    registry,
)?;

let rendered = tmpl.render(&serde_json::json!({"name": null}))?;
assert_eq!(rendered, "Friend");

Run the ready-made example to see a fuller template in action:

cargo run --example flow_and_lists --package lithos-sprig

When you need a read-only view of helper usage, call Template::analyze() and inspect the returned TemplateAnalysis. It reports function invocations, variable paths, template calls, and control structures, allowing downstream systems to reason about dynamic helper requirements without executing the template.

cargo run --example analyze --package lithos-gotmpl-core

The Sprig layer is organised the same way as the upstream documentation:

  • Flow control: default, coalesce, ternary, empty, fail, and JSON helpers (fromJson, toJson, plus the must* variants).
  • Strings: case conversion, trim/affix helpers, contains, replace, substr, trunc, wrap, indent/nindent, nospace, and repeat.
  • String slices: splitList, split, splitn, join, and sortAlpha.
  • Lists: list, first/last/rest/initial, append/prepend/concat, reverse, compact, uniq, without, and has.
  • Maps: dict, merge, set, unset, hasKey, keys, and values. Our implementation sorts the outputs of keys and values to guarantee deterministic results, deviating from Go’s unspecified map iteration order.

We intentionally omit Sprig helpers that rely on randomness, regular expressions, or pluralisation until downstream demand materialises.

See docs/function-coverage.md for the full helper matrix, including the Go defaults handled by lithos-gotmpl-core.

Compatibility & Limitations

  • Behaviour is intentionally focused on the subset of Go templates that our downstream tooling depends on. We do not support every construct that text/template provides (for example else if, define/template, or keyword helpers such as break). See docs/template-syntax-coverage.md for the current status.
  • The project is not affiliated with or endorsed by the Go project or by the Masterminds/sprig maintainers. Compatibility tests rely on their public implementations for reference only.
  • The Go-based go-sanity runner is an optional development aid. It requires a local Go toolchain and honours the upstream sprig licence. CI and local workflows should treat it as a verification step rather than a runtime dependency of the crates.

Roadmap

  • Flesh out additional helpers based on the needs of downstream consumers. Each new helper should add test cases and assertions to keep the Go sanity checks in sync.
  • Explore publishing the helper registry as a trait or adapter
  • Eventually wire in property tests for string/collection helpers once coverage expands.

Attribution & Notices

This workspace includes test materials derived from the Go programming language (text/template) and uses Masterminds' sprig library inside the go-sanity tool. Full attribution details are recorded in NOTICE.

License

All crates in this workspace are dual-licensed under either the Apache License 2.0 or the MIT License. You may choose either licence to use the code. Copies of both licences are provided in LICENSE-APACHE and LICENSE-MIT. Unless otherwise stated, contributions are accepted under the same dual-licence terms.

Commit count: 0

cargo fmt