| Crates.io | lithos-sprig |
| lib.rs | lithos-sprig |
| version | 0.1.0 |
| created_at | 2025-11-01 19:46:43.367625+00 |
| updated_at | 2025-11-01 19:46:43.367625+00 |
| description | Sprig-compatible helper library built on top of lithos-gotmpl-core for Rust-based gotmpl rendering. |
| homepage | https://github.com/hans-d/lithos-gotmpl-rs |
| repository | https://github.com/hans-d/lithos-gotmpl-rs |
| max_upload_size | |
| id | 1912344 |
| size | 62,933 |
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.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.You can work either inside the provided dev container or with a native toolchain:
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.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.
.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)..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..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.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.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.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:
default, coalesce, ternary, empty, fail, and JSON
helpers (fromJson, toJson, plus the must* variants).contains, replace,
substr, trunc, wrap, indent/nindent, nospace, and repeat.splitList, split, splitn, join, and sortAlpha.list, first/last/rest/initial, append/prepend/concat,
reverse, compact, uniq, without, and has.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.
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.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.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.
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.