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

Spec 6.4.1's five mutual-exclusion constraints on `<invoke>`'s attributes
and children, each reported at the `<invoke>` element's own `location`:

- `{:invoke_type_and_typeexpr}` - "type: Must not occur with the
  'typeexpr' attribute."
- `{:invoke_src_and_srcexpr}` - "src: Must not occur with the 'srcexpr'
  attribute or the `<content>` element."
- `{:invoke_src_and_content}` - the other half of that same constraint:
  `src` or `srcexpr` alongside a `<content>` child.
- `{:invoke_id_and_idlocation}` - "id: Must not occur with the
  'idlocation' attribute."
- `{:invoke_namelist_and_param}` - "namelist: Must not occur with the
  `<param>` element."

`lib/statifier/document/invoke.ex` makes every one of these pairs
simultaneously representable precisely so this check can report the shape
rather than lowering refusing to build it - the same division of labour
`Checks.Donedata`, `Checks.Content`, and `Checks.Param` already have for
their own mutually exclusive pairs. Collect-all: an `<invoke>` that trips
more than one of the five reports every one it trips, not just the first.

## The 6.5.2 warning: forbidden content inside `<finalize>`

`warn/2` walks each `<invoke>`'s `finalize` block and reports spec 6.5.2's
rule: "the executable content inside `<finalize>` MUST NOT raise events or
invoke external actions. In particular, the `<send>` and `<raise>`
elements MUST NOT occur." The forbidden set is `%Document.Raise{}` and
`%Document.Send{}` - both are lowered, executable content nodes with a
defined engine behavior (each executes like any other executable content
inside `<finalize>`), so a document that writes one there is told about
the violation rather than refused. `Statifier.Validator.Checks.Send`
enforces 6.2.2/6.2.3's own attribute constraints on the same `<send>`
independently of this warning - the two checks are not mutually
exclusive, and a `<send>` inside `<finalize>` can trip both at once. This
is a warning, not an error: `forbidden/1` carries the offending element's
own name as data (`"raise"` or `"send"`) rather than one reason tag per
element, per ADR-0033's consequences.

# `check`

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

Walks every `<invoke>` in the document and returns one error per 6.4.1
constraint it violates. Returns `[]` when every `<invoke>` in the document
satisfies all five.

# `warn`

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

Walks every `<invoke>`'s `finalize` block and returns one warning per
6.5.2 forbidden node found, at that node's own location. Returns `[]`
when no `<invoke>` in the document carries forbidden content inside
`<finalize>` - including when `finalize` is `nil` (no `<finalize>` child)
or `%Block{content: []}` (a written but childless one).

---

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