Options
All
  • Public
  • Public/Protected
  • All
Menu

Index

References

Re-exports build_time
Re-exports version

Type Aliases

RenderGroups: "cluster" | "chips" | "off"

How machine_to_dot renders FSL state groups (&group : [ … ];).

  • 'cluster' (default) — render the subset of groups that form a clean nesting tree as nested Graphviz subgraph cluster_<group> { … } boxes, deepest group innermost. A state that genuinely overlaps two groups (member of two groups where neither nests inside the other) can only be drawn inside one cluster, so its remaining memberships are shown as bracketed chips appended to the node label.
  • 'chips' — render every group membership as a chip on the node label and emit no clusters at all. Useful when cluster boxes clutter the diagram or when overlap is pervasive.
  • 'off' — ignore groups entirely; byte-for-byte the historical output.
VizRenderOpts: { engine?: string; footer?: string; hide_state_labels?: boolean; render_groups?: RenderGroups }

Options for the dot/SVG render entry points.

  • hide_state_labels (default false) — when true, the rendered dot output omits the label= attribute on every state's node line. Graphviz then draws the box without any text inside. Useful for diagrams where shape, color, or layout alone carry the meaning (icon-only diagrams, tutorial graphics, presentation slides).
  • footer — verbatim dot source inserted just before the closing } of the generated dot source (e.g. labelloc="b"; label="caption";).
  • engine — graphviz layout engine for the SVG render path (e.g. dot, neato, circo); honored by fsl_to_svg_string.
  • render_groups (default 'cluster') — how FSL state groups are drawn; see RenderGroups. 'off' reproduces the historical, group-blind output byte-for-byte.

Type declaration

  • Optional engine?: string
  • Optional footer?: string
  • Optional hide_state_labels?: boolean
  • Optional render_groups?: RenderGroups

Variables

_test: { chips_for_all_groups: (<T>(u_jssm: Machine<T>, l_states: string[]) => Map<string, string[]>); cluster_id_for: ((group: string, index: number) => string); color8to6: ((color8: string) => string); doublequote: ((txt: string) => string); edge_attr_for: ((key: string, value: string) => string | undefined); edge_defaults_body: ((config: JssmTransitionConfig) => string); graph_attr_for: ((key: string, value: string) => string | undefined); graph_attrs_body: ((config: JssmGraphConfig) => string); graph_bg_color_from_config: ((config: JssmGraphConfig, fallback: string) => string); group_ancestry: ((group: string, parents: Map<string, string>) => Set<string>); group_parent_map: ((registry: Map<string, JssmGroupMemberRef[]>, order: string[]) => Map<string, string>); groups_to_subgraph_string: (<T>(u_jssm: Machine<T>, l_states: string[], state_index: Map<string, string>, state_kinds: Map<string, StateKind>, hide_state_labels: boolean) => { clusters: string; ungrouped_nodes: string }); image_for_state: (<T>(u_jssm: Machine<T>, state: string) => string | undefined); label_with_chips: ((label: string, chips: string[]) => string); node_block_for: (<T>(u_jssm: Machine<T>, l_states: string[], state_index: Map<string, string>, state_kinds: Map<string, StateKind>, hide_labels: boolean, mode: RenderGroups) => string); node_of: ((state: string, state_index: string[] | Map<string, number> | Map<string, string>) => string); plan_cluster_groups: (<T>(u_jssm: Machine<T>, l_states: string[], order: string[], parents: Map<string, string>) => { chips: Map<string, string[]>; placement: Map<string, string> }); primary_group_for: (<T>(u_jssm: Machine<T>, state: string, order: string[]) => string | undefined); shape_for_state: (<T>(u_jssm: Machine<T>, state: string) => string | undefined); slug_for: ((state: string) => string); slug_states: ((states: string[]) => Map<string, string>); style_for_state: (<T>(u_jssm: Machine<T>, state: string) => string); u_color8to6: ((color8?: string) => string | undefined); vc: ((col: string) => string) } = ...
internal

— test-only access to private helpers.

Type declaration

  • chips_for_all_groups: (<T>(u_jssm: Machine<T>, l_states: string[]) => Map<string, string[]>)
      • <T>(u_jssm: Machine<T>, l_states: string[]): Map<string, string[]>
      • Build the per-state chip map for 'chips' mode: every group a state belongs to, in declaration order, becomes a chip on its label, and no clusters are emitted at all. This is the all-chips counterpart to the overflow-only chips produced by plan_cluster_groups.

        // for `&inner:[a]; &outer:[&inner b]; a -> b;`
        // chips_for_all_groups(m, ['a','b']) === Map { 'a' => ['inner','outer'], 'b' => ['outer'] }
        internal

        Type Parameters

        • T

        Parameters

        • u_jssm: Machine<T>
        • l_states: string[]

        Returns Map<string, string[]>

  • cluster_id_for: ((group: string, index: number) => string)
      • (group: string, index: number): string
      • Slugify a group name into the body of a Graphviz cluster_… subgraph identifier. Graphviz treats any subgraph whose name begins with the literal cluster as a visually-boxed cluster, so the emitted name is cluster_<slug>_<index>. The slug alphabet is lowercase alphanumerics joined by _; a name that slugs to empty (e.g. &"!!!") falls back to g<index> (the index alone, no slug component). The _<index> suffix guarantees every group gets a unique cluster id even when two distinct names happen to slugify identically (e.g. "Active Players" and "active-players" both slug to active_players).

        cluster_id_for('Active Players', 0);  // 'cluster_active_players_0'
        cluster_id_for('!!!', 3); // 'cluster_g3'
        internal

        Parameters

        • group: string

          The FSL group name.

        • index: number

          The group's stable declaration-order index (0-based); included in the emitted id to prevent slug collisions.

        Returns string

        A valid Graphviz subgraph identifier starting with cluster_.

  • color8to6: ((color8: string) => string)
      • (color8: string): string
      • Convert an 8-channel hex color (#RRGGBBAA) to a 6-channel hex color (#RRGGBB), discarding the alpha channel. Throws if the input is not a 9-character #-prefixed string.

        Graphviz dot does not support alpha; this is a lossy projection.

        internal

        Parameters

        • color8: string

        Returns string

  • doublequote: ((txt: string) => string)
      • (txt: string): string
      • Escape a string for safe interpolation inside a DOT double-quoted attribute value. Replaces every " with \" so that group names, state labels, and chip labels containing literal double-quotes produce valid, parseable DOT source.

        doublequote('a"b');  // 'a\\"b'
        doublequote('safe'); // 'safe'
        internal

        Parameters

        • txt: string

          Any string that will be placed inside "…" in a DOT attribute.

        Returns string

        The string with every " replaced by \".

  • edge_attr_for: ((key: string, value: string) => string | undefined)
      • (key: string, value: string): string | undefined
      • Map a single transition: {} config item ({ key, value }) to a Graphviz edge-scope attribute name="value" pair, or undefined when the key has no edge-meaningful projection. Mirrors the per-node mapping in {@link state_node_line}, but targets the attribute names Graphviz uses on edges:

        • color and the legacy graph_default_edge_color both set the edge line color.
        • text-color → edge label fontcolor.
        • line-style → edge style (dashed/dotted/solid pass through).

        Node-only keys (background-color, shape, corners, image, url, state-label, border-color) have no edge meaning and yield undefined, so they are dropped from the edge [ … ] default statement.

        internal

        Parameters

        • key: string
        • value: string

        Returns string | undefined

  • edge_defaults_body: ((config: JssmTransitionConfig) => string)
      • Project a JssmTransitionConfig (the compiled transition: {} block) onto the body of a Graphviz default-edge statement — the attribute list that belongs inside edge [ … ];. Per-key last-wins is already applied by the compiler, so the list is walked in order and each edge-meaningful key (see edge_attr_for) contributes one attribute. Returns the empty string when the config is absent or contributes nothing, so a machine with no transition: {} block produces byte-identical output to before.

        edge_defaults_body([{ key: 'color', value: '#0000ffff' }]);
        // 'color="#0000ffff"'
        internal

        Parameters

        Returns string

  • graph_attr_for: ((key: string, value: string) => string | undefined)
      • (key: string, value: string): string | undefined
      • Map a single graph: {} config item ({ key, value }) to a Graphviz graph-scope attribute name="value" pair, or undefined when the key is either not graph-meaningful or already handled by another machine path (graph_layout → SVG engine, flowrankdir, theme → style cascade, dot_preamble → preamble). background-color is handled separately — it feeds the existing single bgcolor slot in {@link dot_template} so it is never double-emitted — and so is excluded here.

        • color → graph color (cluster/graph border).
        • text-color → graph fontcolor.
        internal

        Parameters

        • key: string
        • value: string

        Returns string | undefined

  • graph_attrs_body: ((config: JssmGraphConfig) => string)
      • Project the graph-scope attributes of a JssmGraphConfig that are NOT the background color (handled via graph_bg_color_from_config) onto one Graphviz graph attribute statement per key (e.g. color="…";). Returns the empty string when nothing applies, so machines without graph-scope color attributes are byte-identical to before.

        internal

        Parameters

        Returns string

  • graph_bg_color_from_config: ((config: JssmGraphConfig, fallback: string) => string)
      • Read the effective graph background color from a JssmGraphConfig, honouring the background-color item the compiler folded graph_bg_color into (and into which an explicit graph: { background-color: … } block already won, last-wins). Falls back to the supplied palette default when the config carries no background color, so output is unchanged for machines without a graph: {} background.

        This is the single reconciliation point for the graph background: the value it returns flows into {@link dot_template}'s one bgcolor="…" slot, so the graph: {} value wins over the legacy alias and is never emitted twice.

        internal

        Parameters

        Returns string

  • group_ancestry: ((group: string, parents: Map<string, string>) => Set<string>)
      • (group: string, parents: Map<string, string>): Set<string>
      • Walk the primary-parent chain of a group up to its root, returning the ancestor set including the group itself. Used both to nest clusters and to decide which of a state's memberships its primary cluster already represents (so the rest become chips).

        internal

        Parameters

        • group: string
        • parents: Map<string, string>

        Returns Set<string>

  • group_parent_map: ((registry: Map<string, JssmGroupMemberRef[]>, order: string[]) => Map<string, string>)
      • Build the group→parent-group map used to lay groups out as a properly nested cluster tree. Graphviz clusters must nest strictly (a node lives in exactly one innermost cluster, and clusters may not partially overlap), but the FSL group registry is a DAG — a sub-group may be referenced by several parents. We therefore pick, for each group that is referenced as a group-kind member, a single primary parent: the earliest-declared group that lists it. Groups with no parent are roots.

        // for `&inner:[a]; &outer:[&inner b];`
        // group_parent_map(reg, ['inner','outer']) === Map { 'inner' => 'outer' }
        internal

        Parameters

        Returns Map<string, string>

  • groups_to_subgraph_string: (<T>(u_jssm: Machine<T>, l_states: string[], state_index: Map<string, string>, state_kinds: Map<string, StateKind>, hide_state_labels: boolean) => { clusters: string; ungrouped_nodes: string })
      • <T>(u_jssm: Machine<T>, l_states: string[], state_index: Map<string, string>, state_kinds: Map<string, StateKind>, hide_state_labels: boolean): { clusters: string; ungrouped_nodes: string }
      • Emit the nested-cluster DOT for a machine's groups, weaving each state's node statement into its primary cluster's subgraph cluster_<group> { … } block, deepest group innermost. Roots (groups with no primary parent) are emitted at top level; ungrouped states are returned separately so the caller can place them outside every cluster.

        The cluster tree follows group_parent_map — the strict-nesting subset of the group DAG — so output is always valid Graphviz even when the source groups genuinely overlap; the unrepresentable memberships travel as chips on the node label instead (see plan_cluster_groups).

        // for `&inner:[a]; &outer:[&inner b]; a -> b;` the result contains
        // subgraph cluster_outer { label="outer"; … subgraph cluster_inner { … } }
        internal

        Type Parameters

        • T

        Parameters

        • u_jssm: Machine<T>
        • l_states: string[]
        • state_index: Map<string, string>
        • state_kinds: Map<string, StateKind>
        • hide_state_labels: boolean

        Returns { clusters: string; ungrouped_nodes: string }

        { clusters, ungrouped_nodes } — the cluster DOT block and the node statements for states in no group.

        • clusters: string
        • ungrouped_nodes: string
  • image_for_state: (<T>(u_jssm: Machine<T>, state: string) => string | undefined)
      • <T>(u_jssm: Machine<T>, state: string): string | undefined
      • Read the image filename for a state through jssm.Machine.style_for, so theme-supplied images are honoured along with per-state declarations. Returns undefined if neither a theme nor a state declaration supplies an image.

        internal

        Type Parameters

        • T

        Parameters

        Returns string | undefined

  • label_with_chips: ((label: string, chips: string[]) => string)
      • (label: string, chips: string[]): string
      • Append group-membership chips to a node label. Each extra group becomes a bracketed suffix (e.g. Foo [overlap] [extra]), so a node that the cluster tree can only place in its primary group still surfaces its other memberships visually. With no chips the label is returned verbatim, so chip-free output is byte-identical to the historical label.

        label_with_chips('Foo', []);              // 'Foo'
        label_with_chips('Foo', ['a', 'b']); // 'Foo [a] [b]'
        internal

        Parameters

        • label: string
        • chips: string[]

        Returns string

  • node_block_for: (<T>(u_jssm: Machine<T>, l_states: string[], state_index: Map<string, string>, state_kinds: Map<string, StateKind>, hide_labels: boolean, mode: RenderGroups) => string)
      • <T>(u_jssm: Machine<T>, l_states: string[], state_index: Map<string, string>, state_kinds: Map<string, StateKind>, hide_labels: boolean, mode: RenderGroups): string
      • Assemble the node-declaration block for a machine, honouring the render_groups mode:

        • 'cluster' — emit nested subgraph cluster_<group> { … } boxes via groups_to_subgraph_string, with each member node statement woven into its primary cluster and overlap memberships chipped onto the label.
        • 'chips' — emit a flat node list (no clusters) with every group membership rendered as a label chip (see chips_for_all_groups).
        • 'off' — emit the historical flat node list, ignoring groups entirely; output is byte-identical to the pre-groups renderer.

        A machine that declares no groups produces the same flat node list in every mode, so 'cluster'/'chips' are no-ops there.

        internal

        Type Parameters

        • T

        Parameters

        • u_jssm: Machine<T>
        • l_states: string[]
        • state_index: Map<string, string>
        • state_kinds: Map<string, StateKind>
        • hide_labels: boolean
        • mode: RenderGroups

        Returns string

  • node_of: ((state: string, state_index: string[] | Map<string, number> | Map<string, string>) => string)
      • (state: string, state_index: string[] | Map<string, number> | Map<string, string>): string
      • Build a graphviz-safe node identifier for a state. Accepts either a string[] (legacy test-only path; returns an index-based n0/n1 identifier via indexOf), or a precomputed Map<state, slug> produced by slug_states (used by all rendering hot paths).

        When a slug map is supplied, the identifier is the slug wrapped in double quotes — dot allows quoted identifiers, and the slug alphabet (lowercase alphanumerics + -) requires quoting because bare dot IDs may not contain -. Graphviz round-trips the quoted form through to the SVG <title> element and uses the slug as a stable basis for the generated SVG element id attribute.

        node_of('Red Light', new Map([['Red Light', 'red-light']]));
        // '"red-light"'
        internal

        Parameters

        • state: string
        • state_index: string[] | Map<string, number> | Map<string, string>

        Returns string

  • plan_cluster_groups: (<T>(u_jssm: Machine<T>, l_states: string[], order: string[], parents: Map<string, string>) => { chips: Map<string, string[]>; placement: Map<string, string> })
      • <T>(u_jssm: Machine<T>, l_states: string[], order: string[], parents: Map<string, string>): { chips: Map<string, string[]>; placement: Map<string, string> }
      • Plan how each state's groups are rendered in 'cluster' mode. Produces, per state, the primary cluster it is placed in (or undefined for an ungrouped state) plus the chip groups — memberships the primary cluster's ancestry does not already represent, i.e. genuine overlap that nesting cannot show.

        internal

        Type Parameters

        • T

        Parameters

        • u_jssm: Machine<T>
        • l_states: string[]
        • order: string[]
        • parents: Map<string, string>

        Returns { chips: Map<string, string[]>; placement: Map<string, string> }

        { placement, chips } where placement maps state → primary group, and chips maps state → the overflow group names (declaration order).

        • chips: Map<string, string[]>
        • placement: Map<string, string>
  • primary_group_for: (<T>(u_jssm: Machine<T>, state: string, order: string[]) => string | undefined)
      • <T>(u_jssm: Machine<T>, state: string, order: string[]): string | undefined
      • Choose the primary cluster for a state: the innermost (smallest {@link membership_distance}) group containing it, ties broken by latest declaration order — the same precedence the config cascade uses, so a state's cluster placement agrees with the group whose style won. Returns undefined for a state in no group.

        internal

        Type Parameters

        • T

        Parameters

        • u_jssm: Machine<T>
        • state: string
        • order: string[]

        Returns string | undefined

  • shape_for_state: (<T>(u_jssm: Machine<T>, state: string) => string | undefined)
      • <T>(u_jssm: Machine<T>, state: string): string | undefined
      • Read the graphviz shape for a state through jssm.Machine.style_for, so theme-supplied shapes are honoured along with per-state declarations. Returns undefined if neither a theme nor a state declaration supplies a shape.

        internal

        Type Parameters

        • T

        Parameters

        Returns string | undefined

  • slug_for: ((state: string) => string)
      • (state: string): string
      • Convert a state name into a URL-friendly slug suitable for use as the body of a dot/SVG node identifier. The transformation is:

        1. Lowercase
        2. Any run of characters outside [a-z0-9] (after lowercasing) becomes a single -
        3. Leading and trailing - are trimmed

        If the result is empty (e.g. for a state named "!!!"), the empty string is returned — callers are expected to fall back to an indexed placeholder like node-N. See slug_states for the collision- resolving wrapper that consumes this helper.

        slug_for('Green Light');  // 'green-light'
        slug_for('!!!'); // ''
        slug_for(' Foo Bar '); // 'foo-bar'
        internal

        Parameters

        • state: string

          The state name to slugify.

        Returns string

        The lowercase hyphen-separated slug, or empty string if none of the characters were retainable.

  • slug_states: ((states: string[]) => Map<string, string>)
      • (states: string[]): Map<string, string>
      • Build a Map<state, slug> assigning every state in states a unique, deterministic, URL-safe slug used as its dot/SVG node identifier.

        Algorithm:

        1. Slug each state via slug_for. States whose slug comes out empty fall back to node-N, where N is the state's declaration index (1-based, to match user-visible numbering).
        2. Walk the state list in declaration order, tracking how many times each base slug has already been used. The first occurrence keeps the base slug; subsequent collisions get -2, -3, … suffixes. If the proposed suffixed slug itself collides with a base slug used later, the counter advances until a free slot is found.

        This yields a deterministic mapping given the state-declaration order, so output is stable across runs.

        slug_states(['Red Light', 'red-light']);
        // Map { 'Red Light' => 'red-light', 'red-light' => 'red-light-2' }

        slug_states(['!!!', '???']);
        // Map { '!!!' => 'node-1', '???' => 'node-2' }
        internal

        Parameters

        • states: string[]

          States in declaration order.

        Returns Map<string, string>

        A Map from each state name to its unique slug.

  • style_for_state: (<T>(u_jssm: Machine<T>, state: string) => string)
      • <T>(u_jssm: Machine<T>, state: string): string
      • Compose a graphviz style string for a state by looking up its merged style via jssm.Machine.style_for, then delegating to {@link compose_style_string}. Theme-supplied corners and lineStyle are honoured along with per-state declarations.

        internal

        Type Parameters

        • T

        Parameters

        Returns string

  • u_color8to6: ((color8?: string) => string | undefined)
      • (color8?: string): string | undefined
      • Variant of color8to6 that passes undefined through.

        internal

        Parameters

        • Optional color8: string

        Returns string | undefined

  • vc: ((col: string) => string)
      • (col: string): string
      • Look up a color from the default viz palette by key, returning empty string if the key is unknown (so it disappears in feature concatenation).

        internal

        Parameters

        • col: string

        Returns string

Functions

  • Inject runtime configuration for jssm/viz. Currently only accepts a custom DOMParser constructor for use by *_svg_element functions in environments that do not provide one globally (e.g. Node + jsdom).

    Idempotent — last call wins. No-op if called with no recognized keys.

    // Node, with jsdom:
    import { JSDOM } from 'jsdom';
    import { configure, fsl_to_svg_element } from 'jssm/viz';

    configure({ DOMParser: new JSDOM().window.DOMParser });
    const el = await fsl_to_svg_element('a -> b;');
    throws

    {JssmError} if DOMParser is provided and is not a constructor.

    Parameters

    • opts: { DOMParser?: { prototype: <internal>.DOMParser } }

      Configuration overrides.

      • Optional DOMParser?: { prototype: <internal>.DOMParser }

        Constructor compatible with the WHATWG DOMParser interface. Used as a fallback when globalThis.DOMParser is undefined.

    Returns void

  • dot<T>(machine: Machine<T>): string
  • dot_to_svg(dot: string, options?: { engine?: string }): Promise<string>
  • Render a graphviz dot source string to SVG using @viz-js/viz. The underlying viz instance is lazy-initialized on first call and cached for the lifetime of the module.

    const svg = await dot_to_svg('digraph G { a -> b }');
    const svg_neato = await dot_to_svg('digraph G { a -> b }', { engine: 'neato' });

    Parameters

    • dot: string

      Graphviz dot source.

    • Optional options: { engine?: string }

      Optional renderer overrides.

      • Optional engine?: string

        Graphviz layout engine to use (e.g. 'dot', 'neato', 'circo'). Unrecognized engine names cause @viz-js/viz to throw at render time.

    Returns Promise<string>

    A promise resolving to an SVG XML string.

  • Render an FSL string directly to graphviz dot source.

    import { fsl_to_dot } from 'jssm/viz';
    const dot = fsl_to_dot('a -> b;');

    // suppress state-name labels
    const dot2 = fsl_to_dot('a -> b;', { hide_state_labels: true });

    const dot_with_footer = fsl_to_dot('a -> b;', { footer: 'label="caption";' });
    // 'digraph G { ... label="caption"; }'

    Parameters

    Returns string

    A complete graphviz dot source string.

  • fsl_to_svg_string(fsl: string, opts?: VizRenderOpts): Promise<string>
  • Render an FSL string directly to SVG.

    const svg = await fsl_to_svg_string('a -> b;');
    const svg_neato = await fsl_to_svg_string('a -> b;', { engine: 'neato' });

    Parameters

    Returns Promise<string>

    A promise resolving to an SVG XML string.

  • Render a jssm.Machine as a graphviz dot string.

    An optional footer may be supplied via opts.footer; it is emitted verbatim just before the closing } of the dot source, after all arrange declarations. This is a function-argument-only feature for the moment — a machine-attribute equivalent is planned as a follow-up.

    import { sm } from 'jssm';
    import { machine_to_dot } from 'jssm/viz';

    const dot = machine_to_dot(sm`a -> b;`);
    // 'digraph G { ... }'

    // suppress state-name labels (boxes only, no text inside)
    const dot2 = machine_to_dot(sm`a -> b;`, { hide_state_labels: true });

    const dot_with_footer = machine_to_dot(sm`a -> b;`, { footer: 'labelloc="b"; label="caption";' });
    // 'digraph G { ... labelloc="b"; label="caption"; }'

    // render FSL state groups as nested clusters (the default)
    const grouped = machine_to_dot(sm`&g : [a b]; a -> b;`);
    // 'digraph G { ... subgraph cluster_g { label="g"; ... } ... }'

    // or as label chips, with no cluster boxes
    const chipped = machine_to_dot(sm`&g : [a b]; a -> b;`, { render_groups: 'chips' });

    Type Parameters

    • T

    Parameters

    Returns string

    A complete graphviz dot source string.

Generated using TypeDoc