StatifierUI.Fixtures.Sidecar (StatifierUI v0.1.0)

Copy Markdown View Source

Reads a <chart>.fixtures.json sidecar (ADR-0003) and produces the same StatifierUI.Fixtures struct the behaviour-based delivery path produces.

Uses the stdlib JSON module (Elixir 1.18) to decode, never jason - jason reaches this repository only through the optional phoenix_live_view dependency and must not become load-bearing for core fixture loading.

Every top-level key beyond "version", "scenarios", and "events" is ignored with a :unknown_key diagnostic (ADR-0006's extension-friendly requirement), and every value under "scenarios" and "events" is decoded through StatifierUI.Value.decode/1.

A $duration cannot appear inside "scenarios": it decodes to an atom-keyed map, and a datamodel forbids atom keys at every level (the engine's own invariant, tightened in StatifierUI.Fixtures). Such a sidecar is rejected with {:duration_in_scenario, path}. Durations under "events" are fine - an _event.data payload has no key constraint.

Summary

Functions

Converts an already JSON-decoded sidecar map into a validated StatifierUI.Fixtures struct.

Reads, parses, and validates a sidecar file at path, returning the same struct StatifierUI.Fixtures.from_source/1 produces.

Derives the sidecar path for chart_path and loads it.

Derives a sidecar path from a chart path, per ADR-0003's naming: payment.scxml becomes payment.fixtures.json. A path with no extension has .fixtures.json appended.

Functions

from_json(json, opts \\ [])

@spec from_json(
  map(),
  keyword()
) :: {:ok, StatifierUI.Fixtures.t()} | {:error, term()}

Converts an already JSON-decoded sidecar map into a validated StatifierUI.Fixtures struct.

Options:

  • :source - the file the map was read from, recorded on each diagnostic and named in each logged warning. load/1 passes it; omitting it is for a map that never was a file.

load(path)

@spec load(Path.t()) :: {:ok, StatifierUI.Fixtures.t()} | {:error, term()}

Reads, parses, and validates a sidecar file at path, returning the same struct StatifierUI.Fixtures.from_source/1 produces.

Every error names path, because a corpus run loads many sidecars and a bare POSIX reason does not say which one failed.

load_for_chart(chart_path)

@spec load_for_chart(Path.t()) :: {:ok, StatifierUI.Fixtures.t()} | {:error, term()}

Derives the sidecar path for chart_path and loads it.

A missing sidecar is {:error, {:sidecar_not_found, path}}, not an empty bundle - whether "no fixtures" is acceptable is a caller-level decision, and a typo'd chart path must not look like a chart without fixtures.

sidecar_path(chart_path)

@spec sidecar_path(Path.t()) :: Path.t()

Derives a sidecar path from a chart path, per ADR-0003's naming: payment.scxml becomes payment.fixtures.json. A path with no extension has .fixtures.json appended.

Examples

iex> StatifierUI.Fixtures.Sidecar.sidecar_path("payment.scxml")
"payment.fixtures.json"

iex> StatifierUI.Fixtures.Sidecar.sidecar_path("payment")
"payment.fixtures.json"