Kotoba.Document (Kotoba v0.5.0)

Copy Markdown View Source

A rich text document in memory.

The stored form of a document is an envelope around the serialized editor state of Lexical:

%{"kotoba" => 1, "lexical" => "0.51", "root" => root_node_json}

parse/2 reads the envelope into a tree of node structs (see Kotoba.Node) and checks each node. to_json/1 writes the envelope again. For the nodes in the registry, to_json/1 writes the same JSON that parse/2 read, when that JSON has all the keys that Lexical writes. A node of a type that is not in the registry becomes a Kotoba.Nodes.Unknown node, and to_json/1 writes its JSON with no change.

Summary

Functions

Returns the attachment nodes of the document, in document order.

Returns true when the document has no text other than white space and no node other than element, text and line break nodes.

Returns a document with fun applied to each node, depth first.

Returns the mention nodes of the document, in document order.

Reads a document from its envelope, as a map or as a JSON string.

Reduces the nodes of the document, depth first, the parent before its children.

Returns the plain text of the document, with the :default render policy.

Returns the envelope of the document as a map.

Calls fun on each node of the document, depth first, the parent before its children. Returns :ok.

Types

t()

@type t() :: %Kotoba.Document{
  lexical: String.t(),
  root: Kotoba.Nodes.Root.t(),
  version: pos_integer()
}

Functions

attachments(doc)

@spec attachments(t()) :: [Kotoba.Nodes.Attachment.t()]

Returns the attachment nodes of the document, in document order.

empty?(doc)

@spec empty?(t()) :: boolean()

Returns true when the document has no text other than white space and no node other than element, text and line break nodes.

map(doc, fun)

@spec map(t(), (Kotoba.Node.t() -> Kotoba.Node.t())) :: t()

Returns a document with fun applied to each node, depth first.

fun gets the parent before its children, and Kotoba then maps the children of the node that fun returns. fun gets the root node too, and must return a Kotoba.Nodes.Root for it.

mentions(doc)

@spec mentions(t()) :: [Kotoba.Nodes.Mention.t()]

Returns the mention nodes of the document, in document order.

parse(envelope, opts \\ [])

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

Reads a document from its envelope, as a map or as a JSON string.

Returns {:ok, document}, or {:error, messages} with one message for each problem.

Options

Examples

iex> {:ok, doc} =
...>   Kotoba.Document.parse(%{
...>     "kotoba" => 1,
...>     "lexical" => "0.51",
...>     "root" => %{"type" => "root", "children" => []}
...>   })
iex> Kotoba.Document.empty?(doc)
true

reduce(document, acc, fun)

@spec reduce(t(), acc, (Kotoba.Node.t(), acc -> acc)) :: acc when acc: term()

Reduces the nodes of the document, depth first, the parent before its children.

Examples

iex> {:ok, doc} = Kotoba.Document.parse(%{"kotoba" => 1, "lexical" => "0.51", "root" => %{"type" => "root"}})
iex> Kotoba.Document.reduce(doc, 0, fn _node, count -> count + 1 end)
1

text(doc)

@spec text(t()) :: String.t()

Returns the plain text of the document, with the :default render policy.

Delegates to Kotoba.Renderer.to_text/2, so the two always agree: a root-level decorator with no text (for example a horizontal rule) gives no blank line, and a node that Kotoba.Sanitizer refuses (for example a node nested where it is not valid) gives no text either, the same as an unknown node.

to_json(doc)

@spec to_json(t()) :: map()

Returns the envelope of the document as a map.

walk(doc, fun)

@spec walk(t(), (Kotoba.Node.t() -> term())) :: :ok

Calls fun on each node of the document, depth first, the parent before its children. Returns :ok.