Quillon.Transform.Normalize (Quillon v0.3.0)

Copy Markdown View Source

Normalization operations for text nodes.

Normalizes content by:

  1. Removing empty text nodes
  2. Merging adjacent text nodes with identical marks

Summary

Types

Any node these predicates may be handed.

List of inline children

A text node tuple

Functions

Check if a text node is empty.

Merge adjacent text nodes with identical marks.

Check if two text nodes can be merged (same marks).

Normalize a list of text nodes.

Normalize a paragraph or heading node.

Remove empty text nodes from a list.

Types

any_node()

@type any_node() :: text_node() | {atom(), map(), list()}

Any node these predicates may be handed.

Children lists normally hold text nodes, but a consumer may introduce a custom node type - a scanned line carrying a bounding box, say - and normalization has to pass it through rather than raise on it.

children()

@type children() :: [any_node()]

List of inline children

text_node()

@type text_node() :: {:text, %{text: String.t(), marks: list()}, []}

A text node tuple

Functions

empty_text?(arg1)

@spec empty_text?(any_node()) :: boolean()

Check if a text node is empty.

Only a text node can be empty. Any other node — including a custom node type a consumer has introduced — is reported as non-empty so that normalization leaves it alone rather than discarding it.

Examples

iex> Quillon.Transform.Normalize.empty_text?({:text, %{text: "", marks: []}, []})
true

iex> Quillon.Transform.Normalize.empty_text?({:text, %{text: "Hi", marks: []}, []})
false

iex> Quillon.Transform.Normalize.empty_text?({:line, %{page: 2}, [Quillon.text("Hi")]})
false

merge_adjacent(list)

@spec merge_adjacent(children()) :: children()

Merge adjacent text nodes with identical marks.

Uses loose equality (compares marks only, ignores text content).

Examples

iex> children = [
...>   {:text, %{text: "A", marks: []}, []},
...>   {:text, %{text: "B", marks: []}, []},
...>   {:text, %{text: "C", marks: []}, []}
...> ]
iex> Quillon.Transform.Normalize.merge_adjacent(children)
[{:text, %{text: "ABC", marks: []}, []}]

iex> children = [
...>   {:text, %{text: "Hello", marks: [:bold]}, []},
...>   {:text, %{text: " world", marks: []}, []}
...> ]
iex> Quillon.Transform.Normalize.merge_adjacent(children)
[
  {:text, %{text: "Hello", marks: [:bold]}, []},
  {:text, %{text: " world", marks: []}, []}
]

mergeable?(arg1, arg2)

@spec mergeable?(any_node(), any_node()) :: boolean()

Check if two text nodes can be merged (same marks).

Examples

iex> n1 = {:text, %{text: "Hello", marks: [:bold, :italic]}, []}
iex> n2 = {:text, %{text: " world", marks: [:italic, :bold]}, []}
iex> Quillon.Transform.Normalize.mergeable?(n1, n2)
true

iex> n1 = {:text, %{text: "Hello", marks: [:bold]}, []}
iex> n2 = {:text, %{text: " world", marks: []}, []}
iex> Quillon.Transform.Normalize.mergeable?(n1, n2)
false

iex> n1 = {:text, %{text: "Hello", marks: []}, []}
iex> n2 = {:line, %{page: 2}, [Quillon.text(" world")]}
iex> Quillon.Transform.Normalize.mergeable?(n1, n2)
false

normalize(children)

@spec normalize(children()) :: children()

Normalize a list of text nodes.

Removes empty text nodes and merges adjacent nodes with identical marks.

Examples

iex> children = [
...>   {:text, %{text: "Hello", marks: [:bold]}, []},
...>   {:text, %{text: " world", marks: [:bold]}, []},
...>   {:text, %{text: "", marks: []}, []}
...> ]
iex> Quillon.Transform.Normalize.normalize(children)
[{:text, %{text: "Hello world", marks: [:bold]}, []}]

iex> Quillon.Transform.Normalize.normalize([])
[]

normalize_block(arg)

@spec normalize_block(tuple()) :: tuple()

Normalize a paragraph or heading node.

Accepts only :paragraph and :heading, and raises otherwise. Those are the block types whose children are inline text; a container node holds blocks, and merging those is a different operation this function does not perform.

Examples

iex> para = {:paragraph, %{}, [
...>   {:text, %{text: "Hello", marks: [:bold]}, []},
...>   {:text, %{text: " world", marks: [:bold]}, []}
...> ]}
iex> Quillon.Transform.Normalize.normalize_block(para)
{:paragraph, %{}, [{:text, %{text: "Hello world", marks: [:bold]}, []}]}

remove_empty(children)

@spec remove_empty(children()) :: children()

Remove empty text nodes from a list.

Examples

iex> children = [
...>   {:text, %{text: "Hello", marks: []}, []},
...>   {:text, %{text: "", marks: []}, []},
...>   {:text, %{text: "world", marks: []}, []}
...> ]
iex> Quillon.Transform.Normalize.remove_empty(children)
[
  {:text, %{text: "Hello", marks: []}, []},
  {:text, %{text: "world", marks: []}, []}
]