Renders a compiled Statifier.Machine and an active configuration as
Mermaid stateDiagram-v2 source, for display via Kino.Mermaid (or any
other Mermaid consumer - this module is pure and depends on neither Kino
nor LiveView).
render/2 is a pure function: machine and configuration in, diagram
source out. That interface is the stable part. The Mermaid backend is the
Livebook inspector's first rendering (statifier-ui ADR-0008 fixes the
destination stack as client-side elkjs producing SVG, and explicitly
leaves this first cut to the inspector epic); when the elkjs renderer
arrives it replaces the body of this module, not its callers.
The accepted Mermaid compromise
Mermaid cannot draw a transition between internal states of two
different composite states - the cross-hierarchy edges SCXML's LCCA
semantics make routine, and the limitation that disqualified Mermaid as
the destination renderer (ADR-0008). Rather than drop those transitions,
render/2 lifts each one to the pair of composite siblings under the
endpoints' least common ancestor and draws the edge there, with a
[lifted: <source> -> <target>] marker appended to the label naming the
real endpoints. The same lifting applies to a composite's [*] initial
marker when its resolved initial state is a deep descendant rather than a
direct child - the marker there is [deep: <target>].
What the source contains
- Every state except the synthesized
:scxmlroot is declared with a stables<index>alias (the engine's document-order state index, the identity vocabulary of statifier ADR-0012), so tests and callers can address nodes without depending on how labels are escaped. - Compound states are composite blocks; parallel states are composite
blocks whose children are separated by Mermaid's
--region divider. <final>states carry a(final)label suffix; history states carry(H)(shallow) or(H*)(deep) - Mermaid has no native pseudo-state notation for either.- Transitions are labeled with their event descriptors; a guarded
transition carries a
[cond]marker (the Machine retains the compiled expression, not its source text). - Active states - every index in the configuration, ancestors included,
per the full-configuration convention of statifier-ui ADR-0005 - are
assigned the
activeMermaid class. Out-of-range indexes and the root are ignored, so a stale or empty configuration degrades to an unhighlighted chart rather than an error.
Summary
Functions
Renders machine with configuration highlighted, as Mermaid
stateDiagram-v2 source.
Functions
@spec render(Statifier.Machine.t(), Enumerable.t()) :: String.t()
Renders machine with configuration highlighted, as Mermaid
stateDiagram-v2 source.
configuration is any enumerable of state indexes - typically the full
active configuration (MapSet.t(non_neg_integer())) a trace message or
Statifier.MachineState carries. Pass [] (or an empty set) for a chart
that is not running.
Examples
iex> {:ok, machine} =
...> Statifier.compile("""
...> <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="on">
...> <state id="on">
...> <transition event="toggle" target="off"/>
...> </state>
...> <state id="off"/>
...> </scxml>
...> """)
iex> source = StatifierUI.Diagram.render(machine, [1])
iex> String.starts_with?(source, "stateDiagram-v2")
true
iex> source =~ "class s1 active"
true