Juli4nG/elm-json-render/2.0.0

NOTE: the latest version is 3.0.0

JsonRender.Expr

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.

Expressions

type Expr
= ELiteral Value
| EState String
| EItem String
| EIndex
| EBindState String
| EBindItem String
| ETemplate String

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.
decoder : Decoder Expr

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.

Resolution scope

type alias Context =
{ state : Value
, item : Maybe Value
, index : Maybe Int
, basePath : Maybe String
}

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.
rootContext : Value -> Context

The top-level scope: global state only, no repeat item.

childContext : String -> Int -> Value -> Context -> Context

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.

JSON Pointers

getByPath : String -> Value -> Maybe Value

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.

Resolving

resolve : Context -> Expr -> Value

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.

resolveDisplay : Context -> Expr -> String

Resolve an expression to its display string (for Text / Badge). Scalars render as themselves; null / missing renders as ""; objects / arrays render as "".

resolveBool : Context -> Expr -> Bool

Resolve an expression to a boolean (for Checkbox checked). Only a JSON true is True; everything else (including missing) is False.

writeBackPath : Context -> Expr -> Maybe String

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.

resolveParams : Context -> Value -> Value

Resolve an action's params object per the pinned resolveActionParam semantics:

  • A top-level { "$item": "field" } resolves to the absolute state path (basePath ++ "/" ++ field) so the host can target the row.
  • A top-level { "$index": true } resolves to the index number.
  • Everything else (including $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.

validatedParams : Decoder Value

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.