Current section

Files

Jump to
nldoc_spec lib nldoc spec.ex
Raw

lib/nldoc/spec.ex

defmodule NLdoc.Spec do
@moduledoc """
This module defines the Ecto schema for the NLdoc spec objects.
"""
use EnumType
@doc """
Returns the version of the NLdoc API spec that the `NLdoc.Spec` library implements.
"""
@version "6.2.0"
@spec version() :: String.t()
def version, do: @version
alias NLdoc.Spec.{
Asset,
BlockQuotation,
BooleanDescriptor,
DefinitionDetails,
DefinitionList,
DefinitionTerm,
Document,
Footnote,
FootnoteReference,
Heading,
Image,
IntegerDescriptor,
Link,
ListItem,
NumberDescriptor,
ObjectDescriptor,
OrderedList,
Paragraph,
Preformatted,
StringDescriptor,
Table,
TableCell,
TableHeader,
TableRow,
Text,
UnorderedList
}
@type object ::
Asset.t()
| BlockQuotation.t()
| DefinitionDetails.t()
| DefinitionList.t()
| DefinitionTerm.t()
| Document.t()
| Footnote.t()
| FootnoteReference.t()
| Heading.t()
| Image.t()
| Link.t()
| ListItem.t()
| OrderedList.t()
| Paragraph.t()
| Preformatted.t()
| Table.t()
| TableCell.t()
| TableHeader.t()
| TableRow.t()
| Text.t()
| UnorderedList.t()
@objects [
Asset,
BlockQuotation,
DefinitionDetails,
DefinitionList,
DefinitionTerm,
Document,
Footnote,
FootnoteReference,
Heading,
Image,
Link,
ListItem,
OrderedList,
Paragraph,
Preformatted,
Table,
TableCell,
TableHeader,
TableRow,
Text,
UnorderedList
]
@type descriptor ::
ObjectDescriptor.t()
| BooleanDescriptor.t()
| StringDescriptor.t()
| NumberDescriptor.t()
| IntegerDescriptor.t()
@descriptors [
ObjectDescriptor,
BooleanDescriptor,
StringDescriptor,
NumberDescriptor,
IntegerDescriptor
]
def objects, do: @objects
def descriptors, do: @descriptors
defenum Type do
# Resource objects
value Asset, "https://spec.nldoc.nl/Resource/Asset"
value BlockQuotation, "https://spec.nldoc.nl/Resource/BlockQuotation"
value DefinitionDetails, "https://spec.nldoc.nl/Resource/DefinitionDetails"
value DefinitionList, "https://spec.nldoc.nl/Resource/DefinitionList"
value DefinitionTerm, "https://spec.nldoc.nl/Resource/DefinitionTerm"
value Document, "https://spec.nldoc.nl/Resource/Document"
value Footnote, "https://spec.nldoc.nl/Resource/Footnote"
value FootnoteReference, "https://spec.nldoc.nl/Resource/FootnoteReference"
value Heading, "https://spec.nldoc.nl/Resource/Heading"
value Image, "https://spec.nldoc.nl/Resource/Image"
value Link, "https://spec.nldoc.nl/Resource/Link"
value ListItem, "https://spec.nldoc.nl/Resource/ListItem"
value OrderedList, "https://spec.nldoc.nl/Resource/OrderedList"
value Paragraph, "https://spec.nldoc.nl/Resource/Paragraph"
value Preformatted, "https://spec.nldoc.nl/Resource/Preformatted"
value Table, "https://spec.nldoc.nl/Resource/Table"
value TableCell, "https://spec.nldoc.nl/Resource/TableCell"
value TableHeader, "https://spec.nldoc.nl/Resource/TableHeader"
value TableRow, "https://spec.nldoc.nl/Resource/TableRow"
value Text, "https://spec.nldoc.nl/Resource/Text"
value UnorderedList, "https://spec.nldoc.nl/Resource/UnorderedList"
# Descriptors
value ObjectDescriptor, "https://spec.nldoc.nl/Resource/ObjectDescriptor"
value BooleanDescriptor, "https://spec.nldoc.nl/Resource/BooleanDescriptor"
value StringDescriptor, "https://spec.nldoc.nl/Resource/StringDescriptor"
value NumberDescriptor, "https://spec.nldoc.nl/Resource/NumberDescriptor"
value IntegerDescriptor, "https://spec.nldoc.nl/Resource/IntegerDescriptor"
# Validation
value Validation, "https://spec.validation.nldoc.nl/Resource/Validation"
end
@type blockquote_child() ::
DefinitionList.t()
| Heading.t()
| Image.t()
| OrderedList.t()
| Paragraph.t()
| Preformatted.t()
| Table.t()
| UnorderedList.t()
def blockquote_children do
[
DefinitionList,
Heading,
Image,
OrderedList,
Paragraph,
Preformatted,
Table,
UnorderedList
]
end
@type document_child() :: BlockQuotation.t() | blockquote_child()
def document_children do
[BlockQuotation | blockquote_children()]
end
@type paragraph_child() :: Image.t() | Link.t() | Text.t() | FootnoteReference.t()
def paragraph_children do
[Image, Link, Text, FootnoteReference]
end
@type text_style() ::
:bold
| :italic
| :underline
| :strikethrough
| :code
| :superscript
| :subscript
| :mark
@spec text_styling() :: [text_style()]
def text_styling do
[:bold, :italic, :underline, :strikethrough, :code, :superscript, :subscript, :mark]
end
@doc """
Recursively find the first spec object to match the given predicate, or return the given default value.
This function performs a depth-first search through the children of a spec object or list of spec objects,
and returns the first spec object for which the predicate returns true.
## Examples
iex> alias NLdoc.Spec.{Paragraph, Text}
iex> NLdoc.Spec.find_recursive(
...> [%Text{text: "1"}, %Text{text: "2"}],
...> fn object -> object.text === "2" end
...> )
%Text{text: "2"}
iex> NLdoc.Spec.find_recursive(
...> [%Paragraph{children: [%Text{text: "1"}, %Text{text: "2"}]}, %Paragraph{children: [%Text{text: "3"}, %Text{text: "4"}]}],
...> fn
...> %Text{text: text} -> text |> String.to_integer() |> rem(2) === 0
...> _ -> false
...> end
...> )
%Text{text: "2"}
iex> NLdoc.Spec.find_recursive([], fn _ -> true end)
nil
iex> NLdoc.Spec.find_recursive([], fn _ -> true end, "test")
"test"
iex> NLdoc.Spec.find_recursive([%Text{text: "1"}, %Text{text: "2"}], fn _ -> false end)
nil
iex> NLdoc.Spec.find_recursive([%Text{text: "1"}, %Text{text: "2"}], fn _ -> false end, "default")
"default"
"""
@spec find_recursive(object() | [object()], (object() -> boolean())) :: object() | nil
def find_recursive([], _predicate),
do: nil
def find_recursive([head | tail], predicate) when is_list(tail),
do: find_recursive(head, predicate) || find_recursive(tail, predicate)
def find_recursive(%type{} = object, predicate) when type in @objects do
if predicate.(object) do
object
else
object |> Map.get(:children, []) |> find_recursive(predicate)
end
end
@spec find_recursive([object()], (object() -> boolean()), default) :: object() | default
when default: var
def find_recursive(elements, predicate, default),
do: find_recursive(elements, predicate) || default
end