# `Statifier.Document.Assign`
[🔗](https://github.com/riddler/statifier-ex/blob/v2.10.0/lib/statifier/document/assign.ex#L1)

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:

- `location` is the SCXML `location` attribute'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 forbids `Predicator` anywhere under `lib/statifier/document/`.
- `node_location` is this `<assign>` element's own `Statifier.Parser.Location`
  span in the source document - what every other Document node calls
  `location`. 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.

# `t`

```elixir
@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
}
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
