StatifierUI.Fixtures.Lint (StatifierUI v0.7.0)

Copy Markdown View Source

ADR-0006's two lint findings for a fixture bundle: an expression whose source text matches no compiled guard, and an expect key naming no dataset. Both are warnings, never errors - this module has no {:error, _} return path anywhere in its public API.

Guard matching is byte equality on source text only. A t_index never appears as a matching key, only as an output pointer for a consumer that wants to annotate a transition: t_index values are document-order positions that shift under any edit above the transition (a state inserted earlier in the document, for example), so matching by index would silently pin the wrong guard the moment the chart changes shape. Matching by source text survives exactly that kind of edit, which is why ADR-0006 fixes it as the identity.

An unmatched expression is a warning, not an error, because a free-standing expression with no corresponding guard is a legal state of the contract - ADR-0006 does not require every expression to mirror a guard. The warning exists for the near-miss case: an expression authored against a guard that has since drifted (reformatted, requoted, or otherwise edited), where matching is exact and a near match does not count. That case is exactly the one a bare "no match" message hides, so the finding's message carries the expression's own source text: a drift of one space or one quote style is invisible until the two strings can be read against each other, and the reader has the chart's guards in front of them already.

Reads a compiled %Statifier.Machine{} only for its transitions' guard source text (Statifier.Machine.Transition.cond, the {:compiled, _, source} shape Statifier.Machine.expr/0 documents). Nothing here calls Predicator - it reads source strings, it does not evaluate them - and nothing here modifies the engine (ADR-0002).

Summary

Functions

A warning per expect key naming no dataset in fixtures.

Expression names matched to the t_index of every transition whose guard source text is byte-equal to the expression's source.

Every lint finding for fixtures, sorted by path for stable, byte-comparable output (ADR-0005's canonical-order habit).

A warning per expression whose source text is byte-equal to no guard in machine.

Functions

dangling_expect_keys(fixtures)

@spec dangling_expect_keys(StatifierUI.Fixtures.t()) :: [
  StatifierUI.Fixtures.diagnostic()
]

A warning per expect key naming no dataset in fixtures.

Needs no machine: this is a fact about the bundle alone, so it is callable on a bundle by itself.

guard_matches(fixtures, machine)

Expression names matched to the t_index of every transition whose guard source text is byte-equal to the expression's source.

A {:static, _} guard and a transition with no cond at all (nil) carry no author-written expression text, so both are skipped without error. An expression can match more than one guard; all matching t_index values are returned, sorted.

The t_index values in the result are an output - a pointer for a consumer (a truth table, a guard annotation) that wants to point back at the transition - never an input to the match. See the moduledoc for why matching by index would be wrong.

lint(fixtures, machine)

Every lint finding for fixtures, sorted by path for stable, byte-comparable output (ADR-0005's canonical-order habit).

machine of nil runs only the machine-free check (dangling_expect_keys/1); given a %Statifier.Machine{}, both checks run.

unmatched_expressions(fixtures, machine)

A warning per expression whose source text is byte-equal to no guard in machine.

See the moduledoc for why this is a warning: an unmatched expression is a legal, free-standing fixture, and the finding exists to surface the near-miss case where an author expected a match and a text drift (however small) broke it.