# `Coelho.Schema.ContentExpression`
[🔗](https://github.com/nseaSeb/coelho/blob/main/lib/coelho/schema/content_expression.ex#L1)

Parser and matcher for ProseMirror-style content expressions.

A content expression describes the sequence of children a node may hold,
for example `"block+"`, `"paragraph block*"`, `"(text | image)*"` or
`"heading{1,3}"`. Names refer either to a node name or to a group name.

Matching is done by simulating the expression over the child list with a
set of reachable positions, which handles alternation and repetition
without building an explicit automaton. The child list of a rich text node
is short, so the position-set simulation is cheap and, unlike a greedy
matcher, it never backtracks incorrectly on expressions such as
`"paragraph* paragraph"`.

# `ast`

```elixir
@type ast() ::
  :empty
  | {:name, atom()}
  | {:seq, [ast()]}
  | {:choice, [ast()]}
  | {:repeat, ast(), non_neg_integer(), non_neg_integer() | :infinity}
```

# `matches?`

```elixir
@spec matches?(ast(), [term()], (atom(), term() -&gt; boolean())) :: boolean()
```

Checks whether `children` satisfies the expression.

`match_fun` receives a name from the expression and a child, and answers
whether that child is an instance of that name (directly, or through a
group it belongs to).

# `names`

```elixir
@spec names(ast()) :: [atom()]
```

Returns every name referenced by an expression, node or group alike.

# `parse`

```elixir
@spec parse(String.t()) :: {:ok, ast()} | {:error, String.t()}
```

Parses a content expression into an AST.

Names become atoms, so this must only ever see developer-authored
expressions — the same trust level as the schema declaration it comes
from. Untrusted input goes through `Coelho.Schema.resolve_node_name/2`,
which resolves against the schema instead of creating atoms.

---

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