mist

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 24, 2026 License: MIT Imports: 8 Imported by: 0

README

mist

CI

A single-pass renderer for a strict subset of Liquid, fast enough that it's cheap to try before falling back to a full engine.

mist evaluates as it scans: no tokenize, compile or AST step, and no allocations on the hot path. As soon as it meets anything outside the subset it returns ErrUnsupported, and you render with your full Liquid engine instead. For every template it accepts, its output matches liquidjs 10 (lenientIf: true) byte for byte.

out, err := mist.Render(tpl, vars, strict)
switch {
case errors.Is(err, mist.ErrUnsupported):
	// outside the subset: render with the full engine
case errors.Is(err, mist.ErrUndefined):
	// strict mode, undefined variable; the full engine fails too
}

Append(dst, tpl, vars, strict) does the same into a reusable buffer, with no allocations.

RenderChain renders a sequence of templates whose outputs feed later ones, such as snippets, then subject, then body, then layout. It stops at the first step mist can't handle, so only the remaining steps go to the full engine.

What's supported

Variables and paths ({{ a.b[0]['k'] }}), string/integer/boolean/nil literals, if/elsif/else/unless, for … in, assign, comment, raw, comparisons including == blank/!= blank, and/or, and whitespace control. No filters yet. SPEC.md is the normative grammar and semantics.

Check whether templates are in the subset:

go run github.com/hownowstephen/mist/cmd/mistcheck@latest template.liquid

Testing

Beyond unit tests, mist is diffed against liquidjs on every template from Shopify/liquid-spec and Shopify/liquid's test suite, plus grammar-generated templates (100k new ones nightly) and fuzzing. See SPEC.md § Verification.

License

MIT

Documentation

Overview

Package mist renders a strict subset of Liquid in a single pass, bailing with ErrUnsupported on anything outside the subset so the caller can fall back to a full engine. See SPEC.md for the exact subset.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrUnsupported means the template is outside the subset; render it with the full engine instead.
	ErrUnsupported = errors.New("mist: unsupported")
	// ErrUndefined is a strict-mode undefined variable. The full engine fails too, though a
	// syntax error later in the template may take precedence there.
	ErrUndefined = errors.New("mist: undefined variable")
)

Functions

func Append added in v0.2.0

func Append(dst []byte, tpl string, vars map[string]any, strict bool) (out []byte, err error)

Append is Render appending to dst, so callers can reuse a buffer and render without allocating. On error out is nil.

func Check

func Check(tpl string) (err error)

Check reports whether tpl is inside the subset, parsing every branch without data. Templates that pass can still bail at render time on data-dependent rules (see SPEC.md).

func Render

func Render(tpl string, vars map[string]any, strict bool) (string, error)

Render renders tpl with vars. strict makes undefined variables in output an error.

Types

type Error

type Error struct {
	Kind error // ErrUnsupported or ErrUndefined
	Pos  int   // byte offset into the template
	Msg  string
}

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

type Result

type Result struct {
	Out string
	Err error // ErrUndefined; unsupported steps are never returned
}

func RenderChain

func RenderChain(steps []Step, vars map[string]any) (res []Result, n int, hydrated map[string]any)

RenderChain renders steps in order, binding each output into the vars seen by later steps (see SPEC.md § Chains). It stops at the first step mist can't render and returns n, its index; the caller renders steps[n:] with the full engine using the returned vars. The caller's maps are never mutated.

type Step

type Step struct {
	Body   string
	Key    []string // where the output is bound for later steps
	Strict bool
	Vars   map[string]any // replaces the chain vars for this step only
}

Step is one template in a RenderChain.

Directories

Path Synopsis
cmd
mistcheck command
Command mistcheck reports whether Liquid templates are inside the mist subset.
Command mistcheck reports whether Liquid templates are inside the mist subset.
scripts
gen command
Command gen writes random templates drawn from the SPEC.md grammar, with random data, in harvest.rb's format for oracle.mjs.
Command gen writes random templates drawn from the SPEC.md grammar, with random data, in harvest.rb's format for oracle.mjs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL