Check 3 (spec 3.2, 3.3, 3.6): every initial reference - a state's
initial attribute, a state's <initial> element, and the document's own
root initial attribute - resolves and lands on a legal target. Three
reasons, in this precedence:
{:initial_on_atomic_state, id}: a state carryinginitialorinitial_elementthat has nothing to default into - an emptystateslist, or a:parallel,:final, or:historykind. Fires first and suppresses every other reason for that state: an atomic state's initial cannot be resolved, checked for descendancy, or anything else, so reporting more than this one error would be two errors for one mistake.{:unresolved_initial, id}: an id inState.initialorDocument.initialabsent fromContext.states. An<initial>element's own transition targets are not re-checked here for existence - check 2 already owns that; this check only asksContext.statesthe same question check 2 already answered, so it can skip the descendancy test below rather than re-reporting.{:initial_not_descendant, id, parent_id}: a resolved target - fromState.initialor from an<initial>element's transitions - that is not among the containing state's named descendants (Context.descendant?/3, ancestry all the way up, not direct-child membership - spec 3.3/3.6 both say "descendants", which is where v1 is wrong). This check has no analog forDocument.initial: spec 3.11's "additional requirement" ("all the states MUST be descendants of the containing<state>or<parallel>element") is written for<state>initialand for a<transition>inside<initial>/<history>only -<scxml>is named in neither. The root's owninitial(spec 3.2.1) is typed only as "a legal state specification" (spec 3.11), which for a single resolved id demands nothing beyond existing -enterStates(Appendix D) walks up from any resolved target and adds its ancestors regardless of how deep it sits, so a document-levelinitialnaming a descendant several levels down is legal and enters that descendant with every ancestor auto-added. There used to be a fourth reason here,{:initial_not_top_level, id}, requiring a resolvedDocument.initialid to be a direct child of<scxml>; it is gone because the spec never asked for that restriction -check_document_initial/2below now stops at existence.
Summary
Functions
Returns, per state and for the document's own root initial attribute, one
of :initial_on_atomic_state (the initial reference has nothing to default
into and suppresses every other reason for that state),
:unresolved_initial (the id does not resolve in Context.states), or
:initial_not_descendant (a resolved target is not a descendant of the
containing state - never fired for Document.initial, which has no
containing state to be a descendant of). Returns [] when every initial
reference in the document resolves and lands on a legal target.
Functions
@spec check( document :: Statifier.Document.t(), context :: Statifier.Validator.Context.t() ) :: [ Statifier.Validator.Error.t() ]
Returns, per state and for the document's own root initial attribute, one
of :initial_on_atomic_state (the initial reference has nothing to default
into and suppresses every other reason for that state),
:unresolved_initial (the id does not resolve in Context.states), or
:initial_not_descendant (a resolved target is not a descendant of the
containing state - never fired for Document.initial, which has no
containing state to be a descendant of). Returns [] when every initial
reference in the document resolves and lands on a legal target.