Coelho.Schema.ContentExpression (coelho v0.3.1)

Copy Markdown View Source

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".

Summary

Functions

Checks whether children satisfies the expression.

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

Parses a content expression into an AST.

Types

ast()

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

Functions

matches?(ast, children, match_fun)

@spec matches?(ast(), [term()], (atom(), term() -> 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(ast)

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

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

parse(source)

@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.