The json-render expression / binding dialect, scoped to this package's
supported set and pinned to @json-render/core v0.19.0 (see SUPPORT.md).
Every dynamic value in a manifest is a plain JSON object carrying a single
$-prefixed discriminant key. This module decodes the supported forms into a typed
Expr and resolves them against a host-owned state Value plus an optional
repeat scope, using RFC 6901 JSON Pointers throughout.
Fail-closed: an object carrying an unsupported $-directive (e.g. $cond,
$computed) fails the decode. json-render's own runtime is fail-open here; we are
not. The supported set is exactly the v1 subset.
Decode a prop value into an Expr.
A non-object (string / number / bool / array / null) decodes to ELiteral. An object
with no $-prefixed key decodes to ELiteral. An object with exactly one supported
$-directive decodes to that form. An object with an unsupported $-directive, or
more than one $-directive, fails. This is the fail-closed boundary.
The resolution scope handed to every expression.
state: the host-owned global state Value (the single source of truth).item: the current repeat item, if inside a repeat scope.index: the current repeat index, if inside a repeat scope.basePath: the repeat item's absolute JSON Pointer (statePath ++ "/" ++ index),
used to compute $bindItem / top-level $item write-back paths.The top-level scope: global state only, no repeat item.
Derive a per-item scope for a repeat element. statePath is the pointer to the
state array; index and item identify the current row. basePath becomes
statePath ++ "/" ++ index per the pinned reference.
Resolve an RFC 6901 JSON Pointer against a Value. Returns Nothing if any token
is missing. The empty pointer "" returns the whole value. Tokens are unescaped
(~1 → /, ~0 → ~). A leading / is honored; a bare token (no leading /, as
produced by $item field lookups) is tolerated as a single step.
Resolve an expression to a JSON Value. A missing pointer / item field yields
null. Two-way $bindState / $bindItem read exactly like their read-only siblings;
their write-back path is exposed separately via writeBackPath.
Resolve an expression to its display string (for Text / Badge). Scalars render
as themselves; null / missing renders as ""; objects / arrays render as "".
Resolve an expression to a boolean (for Checkbox checked). Only a JSON true
is True; everything else (including missing) is False.
The absolute JSON Pointer a two-way binding writes back to, or Nothing for
read-only expressions. $bindState writes its own pointer; $bindItem writes
basePath ++ "/" ++ field.
Resolve an action's params object per the pinned resolveActionParam semantics:
{ "$item": "field" } resolves to the absolute state path
(basePath ++ "/" ++ field) so the host can target the row.{ "$index": true } resolves to the index number.$item nested in an array) resolves to the value
by deep recursion.So { "ids": [ { "$item": "id" } ] } yields { "ids": ["<id>"] }: the literal id, never
a path.
A Decoder for an action's params that validates fail-closed at decode time:
it returns the params Value unchanged, but fails if any nested object carrying a
$-directive is not a supported, well-formed Expr (e.g. an unsupported
$cond, or a malformed { "$item": 123 }). This closes the gap where params are stored
raw and only resolved at dispatch: a bad directive is rejected with the rest of the
manifest, never emitted to the host.
A decoded json-render expression. The discriminant maps 1:1 to the pinned
$-forms:ELiteral v: any value with no$-directive (scalar, array, or plain object).EState ptr:{ "$state": "/ptr" }, read global state.EItem field:{ "$item": "field" }, read the current repeat item (field""= whole item).EIndex:{ "$index": true }, the current repeat index.EBindState ptr:{ "$bindState": "/ptr" }, two-way bind to global state.EBindItem field:{ "$bindItem": "field" }, two-way bind to a repeat-item field.ETemplate tmpl:{ "$template": "…${/ptr}…${bare}…" }, string interpolation.