An <assign> executable-content element: spec 5.4's deep-path datamodel
write.
Two spans that are not the same thing
This struct carries two fields that are easy to confuse and must not be:
locationis the SCXMLlocationattribute's own value - the raw, uncompiled path expression ("foo.bar.baz","items[0]") an<assign>writes to. It is required (spec 5.4.2, "the value of the 'location' attribute MUST specify a valid location"), so it is@enforce_keys'd; resolving it against the datamodel happens at runtime (Statifier.Machine.Content.Assign), never here -lib/statifier/document.ex's moduledoc forbidsPredicatoranywhere underlib/statifier/document/.node_locationis this<assign>element's ownStatifier.Parser.Locationspan in the source document - what every other Document node callslocation. It is renamed here specifically so a reader (or a pattern match) can never mistake the path string for the element's span, or vice versa; it is also@enforce_keys'd, since every node has one.
expr is the value source read from the expr attribute - raw,
uncompiled predicator source, nilable. text is
Statifier.Parser.DOM.text/1's verbatim, untrimmed concatenation of
<assign>'s direct text children (verbatim except for the parser's XML
1.0 2.11 line-break fold - ADR-0045), mirroring Statifier.Document.Data.text
and Statifier.Document.Content.text); expr and text are both
representable on this struct at once, on purpose, so
Statifier.Validator.Checks.Assign can report the pair rather than
lowering refusing to build one (the same division of labour
Statifier.Document.Content's moduledoc states).
Markup children
Spec 5.4.2's "children of <assign>" are not restricted to text: an
in-line value specification may be markup, and the corpus writes exactly
that (test/scxml_tests/mandatory/invoke/test530_test.exs assigns an
<scxml> document to a variable and later passes it as
<content expr="Var1">). markup holds a verbatim source slice spanning
those children, and markup_location is that slice's own
Statifier.Parser.Location span in the parent source - the same two
fields, filled by the same Statifier.Lowering.Builders slicing helper,
that Statifier.Document.Content carries under ADR-0041 (extended to
<assign> by that record's 2026-09-02 Note). No DOM subtree enters this
struct, exactly as for <content>.
markup is nil unless <assign> has at least one element child. Unlike
text it is not line-break folded: it is opaque source bytes, CR
included, at this layer (ADR-0045 decision item 5). expr, text, and
markup are all representable at once for the same reason expr and
text are - reporting the 5.4.2 mutual-exclusion violation is
Statifier.Validator.Checks.Assign's job, not lowering's.
Summary
Types
@type t() :: %Statifier.Document.Assign{ attribute_locations: Statifier.Document.attribute_locations(), expr: String.t() | nil, location: String.t(), markup: String.t() | nil, markup_location: Statifier.Parser.Location.t() | nil, node_location: Statifier.Parser.Location.t(), text: String.t() | nil }