# `Statifier.Validator.Checks.Data`
[🔗](https://github.com/riddler/statifier-ex/blob/v2.0.0/lib/statifier/validator/checks/data.ex#L1)

Check 13: `<datamodel>` and `<data>` structural rules that lowering leaves
representable on purpose (`lib/statifier/document/data.ex`,
`lib/statifier/document/datamodel.ex`), following the same division of
labour `Checks.Content` and `Checks.Donedata` already have with their own
document nodes.

Four reasons, over every `<datamodel>` the document holds - the root's own
`document.datamodel_element` and every state's:

- `{:data_expr_and_src, id}` - a `<data>` written with both `expr` and
  `src` (5.3.2: "MAY have either a 'src' or an 'expr' attribute, but MUST
  NOT have both").
- `{:data_value_and_children, id}` - a `<data>` with `expr` or `src`
  written **and** non-blank child text (5.3.2: "if either attribute is
  present, the element MUST NOT have any children"). Whitespace-only text
  is not text - same `blank?/1` shape and reasoning as
  `Checks.Content.blank?/1` (`lib/statifier/validator/checks/content.ex:66-67`):
  pretty-printed XML leaves formatting text nodes that are not payload.
- `{:data_reserved_id, id}` - a `<data id="...">` beginning with `_`
  (5.10: "A conformant SCXML document MUST NOT contain ids beginning with
  '_' in the `<data>` element").
- `{:datamodel_bad_parent, kind}` - a `<datamodel>` on a `:final` or
  `:history` state. `<datamodel>` is legal under `<scxml>`, `<state>`, and
  `<parallel>` only (3.2.2 / 3.3.2 / 3.4.2); lowering cannot catch this
  because all four state kinds share one `%Document.State{}` struct
  (`lib/statifier/document/state.ex`'s kind-scoped fields table). Follows
  `Checks.Donedata.offending?/1`'s shape.

Each `<data>`-level reason is reported at the offending `<data>`'s own
span: `attribute_locations[:id]` when written, its own `location`
otherwise (mirroring `Checks.Ids.id_location/1` - `id` is required to
build a `Data` struct at all, so `attribute_locations[:id]` is always
present in practice, but the fallback keeps the two checks' shape
identical). `:datamodel_bad_parent` is reported at the `<datamodel>`'s own
`location`.

# `check`

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

Returns `:data_expr_and_src`, `:data_value_and_children`, and
`:data_reserved_id` errors for every offending `<data>` in the document,
and a `:datamodel_bad_parent` error for every `<datamodel>` on a `:final`
or `:history` state. Returns `[]` when every `<datamodel>`/`<data>` in the
document is well-formed and correctly placed.

---

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