StatifierUI.Trace.Manifest (StatifierUI v0.1.0)

Copy Markdown View Source

Turns a compiled %Statifier.Machine{} plus caller-supplied context into the session.start definition message (docs/wire-format.md) - the message that makes every later index (state index, t_index, c_index, d_index) resolvable to a source location without a compiler on the reading end. Pure, no process.

The Machine does not retain the SCXML source text and has no id -> index reverse map beyond the partial id_to_index (deps/statifier/lib/statifier/machine.ex:29), so the state table is built by walking machine.states (a tuple in document order) rather than by any lookup, and source is accepted from the caller rather than derived (decision 7 of the plan).

The Content.Script/Content.Assign location gotcha

Every executable-content node kind carries a :location field holding its own %Statifier.Parser.Location{} span, with two exceptions this module handles explicitly rather than by a generic fallback:

  • Statifier.Machine.Content.Script has no :location field at all - its span lives on :node_location instead (deps/statifier/lib/statifier/machine/content/script.ex:48).
  • Statifier.Machine.Content.Assign has both fields, but its :location is a String.t() - the raw, uncompiled location attribute (a path expression such as "foo.bar"), not a location span. Its span is on :node_location (deps/statifier/lib/statifier/machine/content/assign.ex:42-46).

A naive Map.get(node, :location) || Map.get(node, :node_location) handles Script correctly (its :location key does not exist, so Map.get/2 returns nil and the fallback wins) but silently picks the wrong value for Assign - its :location is a truthy string, so the || never reaches :node_location, and a string ends up where a location object belongs. content_location/1 below dispatches on the struct itself instead, naming Assign and Script as the two kinds whose span is :node_location and treating every other kind's :location as the span it already is.

Summary

Types

Caller-supplied context build/3 cannot derive from the Machine alone.

Functions

Builds the session.start message for machine, stamped session: session and seq: 0.

The session.start schema version this module produces - 1 (ADR-0005's initial value).

Types

opts()

@type opts() :: [
  source: String.t(),
  fixtures: map(),
  parent_session: String.t(),
  invokeid: String.t()
]

Caller-supplied context build/3 cannot derive from the Machine alone.

Functions

build(machine, session, opts \\ [])

@spec build(Statifier.Machine.t(), session :: String.t(), opts()) ::
  {:ok, StatifierUI.Trace.Message.t()} | {:error, term()}

Builds the session.start message for machine, stamped session: session and seq: 0.

Returns {:error, {:invalid_fixtures, opts[:fixtures]}} when :fixtures is supplied and is not a map, and {:error, {:invalid_source, opts[:source]}} when :source is supplied and is not a binary. Nothing else can fail: every other field comes from a compiled Machine, which is well-formed by construction.

version()

@spec version() :: pos_integer()

The session.start schema version this module produces - 1 (ADR-0005's initial value).