Coelho (coelho v0.3.1)

Copy Markdown View Source

Structured rich text for Elixir.

Coelho stores a rich text document as a validated tree — the same shape ProseMirror produces — rather than as a blob of HTML. A schema, written once in Elixir, says which nodes and marks exist; validating a document against it is the sanitisation step, and rendering it is a pure function the application can override node by node.

This module is the convenience surface over the three that do the work:

Every function here defaults to Coelho.Schema.default/0; applications with their own schema call the underlying modules directly.

iex> document = %{
...>   "type" => "doc",
...>   "content" => [
...>     %{"type" => "paragraph", "content" => [%{"type" => "text", "text" => "hello"}]}
...>   ]
...> }
iex> {:ok, document} = Coelho.validate(document)
iex> Coelho.to_html(document)
"<p>hello</p>"

Summary

Functions

A byte-for-byte stable serialisation of a validated document.

The empty document of a schema.

Converts existing HTML into a validated document, and says what it left behind.

The hex digest of a validated document, or nil when it holds nothing.

Moves a document from one schema version to the next.

Folds a document into any term at all, for a target that is not HTML.

Turns any term into a document the schema accepts, without failing.

The number of characters a writer typed, counted the way the editor counts.

Renders a validated document to HTML.

Extracts the plain text of a document, for full text search.

Validates and normalises a document against a schema.

Functions

canonical(document)

@spec canonical(term()) :: binary()

A byte-for-byte stable serialisation of a validated document.

empty(schema \\ Schema.default())

@spec empty(Coelho.Schema.t()) :: map()

The empty document of a schema.

The child is derived from the top node's content expression rather than assumed to be a paragraph, so a schema that calls its block node something else still gets a document its own validate/2 accepts.

from_html(html, schema \\ Schema.default())

@spec from_html(String.t(), Coelho.Schema.t()) ::
  {:ok, map(), [Coelho.HTML.warning()]} | {:error, term()}

Converts existing HTML into a validated document, and says what it left behind.

The migration path for content already stored as HTML. Requires the optional :floki dependency; see Coelho.HTML.from_html/2 for what the import does with markup the schema does not know, and for the shape of the warnings.

hash(document, algorithm \\ :sha256)

@spec hash(term(), :sha256 | :sha512 | :sha384 | :sha224 | :sha) :: String.t() | nil

The hex digest of a validated document, or nil when it holds nothing.

migrate(document, opts)

@spec migrate(
  map(),
  keyword()
) :: {:ok, map()} | {:error, String.t()}

Moves a document from one schema version to the next.

A schema that declares a :version stamps it on every document it validates, and refuses a document stamped with another — which is the whole point: when a node is renamed or an attribute retired, there is otherwise no way to tell a document written under the old vocabulary from one that is simply wrong.

Coelho.migrate(document, from: 1, to: 2, with: &MyApp.RichText.v1_to_v2/1)

:with takes the document and returns the rewritten one. Crossing more than one version at a time takes a map of the step to run into each version:

Coelho.migrate(document, from: 1, to: 3, with: %{2 => &v1_to_v2/1, 3 => &v2_to_v3/1})

The result is stamped with :to and is not validated: run it through validate/2 with the new schema, which is where a migration that missed something says so.

reduce(document, schema \\ Schema.default(), callbacks, opts \\ [])

Folds a document into any term at all, for a target that is not HTML.

See Coelho.Render.reduce/4.

sanitize(document, schema \\ Schema.default())

@spec sanitize(term(), Coelho.Schema.t()) :: map()

Turns any term into a document the schema accepts, without failing.

The counterpart of validate/2 for the way out: see Coelho.Document.sanitize/2 for what it removes and why a stored document needs it at all.

text_length(document)

@spec text_length(term()) :: non_neg_integer()

The number of characters a writer typed, counted the way the editor counts.

to_html(document)

@spec to_html(map()) :: String.t()

Renders a validated document to HTML.

The schema may be left out, in which case the render options can be passed straight as the second argument.

to_html(document, opts)

@spec to_html(map(), Coelho.Schema.t() | Coelho.Render.opts()) :: String.t()

to_html(document, schema, opts)

@spec to_html(map(), Coelho.Schema.t(), Coelho.Render.opts()) :: String.t()

to_text(document, schema \\ Schema.default())

@spec to_text(map(), Coelho.Schema.t()) :: String.t()

Extracts the plain text of a document, for full text search.

validate(document, schema \\ Schema.default())

@spec validate(term(), Coelho.Schema.t()) ::
  {:ok, map()} | {:error, [Coelho.Document.Error.t()]}

Validates and normalises a document against a schema.