Statifier.Validator.Checks.Enums (Statifier v2.0.0)

Copy Markdown View Source

Out-of-range enumerated attribute values (spec 3.2.1 and 3.5).

Statifier.Lowering.Attributes.atom/4 maps an unrecognised value onto the attribute's default rather than erroring, so type="sideways" lowers to :external and binding="whenever" lowers to :early - indistinguishable on the struct from the valid spellings that produce the same atom. Only the source text can tell them apart, which is what validate/2's source argument exists for: the written attribute's span is sliced back out and compared against the range.

Four reasons, one per enumerated attribute this check owns:

  • {:transition_bad_type, raw} - a <transition type="..."> that is neither "internal" nor "external" (spec 3.5). Covers every transition the document holds, including those under an <initial> element and a <history>'s default transition, since Statifier.Validator.Context already walks all three.
  • {:scxml_bad_binding, raw} - an <scxml binding="..."> that is neither "early" nor "late" (spec 3.2.1).
  • {:scxml_bad_datamodel, raw} - an <scxml datamodel="..."> outside ["predicator", "elixir", "null", "ecmascript", "xpath"] (spec 3.2.1). 3.2.1's Valid Values clause is itself open-ended - "null", "ecmascript", "xpath" or other platform-defined values - so the allow-list is the spec's three named values plus this platform's two (docs/datamodel.md:6-7), not a strict ["predicator", "elixir"] rejection of everything else. Accepting "ecmascript" does not mean this engine implements ECMAScript: which datamodel actually runs is ADR-0004's answer and the corpus tooling's, never this attribute's. What this check catches is a typo (datamodel="predicater", datamodel="javascript") - the ordinary job of a validator check on an enumerated NMTOKEN. An absent datamodel attribute is "predicator", this platform's documented default (3.2.2), so it is never reported.
  • {:invoke_bad_autoforward, raw} - an <invoke autoforward="..."> that is neither "true" nor "false" (spec 6.4.1). Walks every <invoke> in the document directly (this check's own flatten/1, the same shape Checks.Donedata/Checks.Content/Checks.Param use), since Statifier.Validator.Context indexes transitions but not invocations.

The fifth enumerated attribute lowering maps this way, <history type="...">, is not here: Statifier.Validator.Checks.History reports it as :history_bad_type under spec 3.10, alongside that element's other structural rules. The slice-and-compare shape is duplicated between the two modules rather than shared, so each check stays readable on its own and neither has to reach into the other's spec section.

An attribute that was never written has no attribute_locations entry and is not reported - an absent enumerated attribute is its default, which is always in range.

Summary

Functions

Returns a :transition_bad_type error for every <transition type="..."> whose written value is neither "internal" nor "external", a :scxml_bad_binding error when the root <scxml binding="..."> is neither "early" nor "late", a :scxml_bad_datamodel error when the root <scxml datamodel="..."> is outside ["predicator", "elixir", "null", "ecmascript", "xpath"], and an :invoke_bad_autoforward error for every <invoke autoforward="..."> whose written value is neither "true" nor "false". All four slice the raw source text rather than trusting the lowered atom/boolean, since an out-of-range value and a valid one can lower to the same default. Returns [] when all four enumerated attributes are in range everywhere they were written.

Functions

check(document, context)

@spec check(
  document :: Statifier.Document.t(),
  context :: Statifier.Validator.Context.t()
) :: [
  Statifier.Validator.Error.t()
]

Returns a :transition_bad_type error for every <transition type="..."> whose written value is neither "internal" nor "external", a :scxml_bad_binding error when the root <scxml binding="..."> is neither "early" nor "late", a :scxml_bad_datamodel error when the root <scxml datamodel="..."> is outside ["predicator", "elixir", "null", "ecmascript", "xpath"], and an :invoke_bad_autoforward error for every <invoke autoforward="..."> whose written value is neither "true" nor "false". All four slice the raw source text rather than trusting the lowered atom/boolean, since an out-of-range value and a valid one can lower to the same default. Returns [] when all four enumerated attributes are in range everywhere they were written.