# `Coelho.Document.Error`
[🔗](https://github.com/nseaSeb/coelho/blob/main/lib/coelho/document/error.ex#L1)

A single validation failure, located in the document tree.

The `:path` is a list of segments from the root: string keys for map
fields, integers for positions inside `content`.

# `description`

```elixir
@type description() :: %{
  position: [pos_integer()],
  scope: :document | :node | :mark | :attribute,
  attribute: String.t() | nil,
  mark: pos_integer() | nil,
  location: String.t(),
  message: String.t()
}
```

# `segment`

```elixir
@type segment() :: String.t() | non_neg_integer()
```

# `t`

```elixir
@type t() :: %Coelho.Document.Error{message: String.t(), path: [segment()]}
```

# `describe`

```elixir
@spec describe(t()) :: description()
```

Takes an error apart, for an application that has to word it itself.

`format/1` says `content[0].attrs.href: scheme "javascript" is not
allowed`, which is right for a log and wrong for the person who pasted the
link. Wording it for them needs their language and their vocabulary — a
market gardener reads "the link in the first paragraph", not a path — and
neither of those is Coelho's to choose. This gives the pieces:

    %{
      position: [1],
      scope: :attribute,
      attribute: "href",
      mark: 1,
      location: "content[0].marks[0].attrs.href",
      message: ~s(scheme "javascript" is not allowed)
    }

`:position` counts from 1, down the content tree, so `[2, 1]` is the first
child of the second block. `:scope` is `:document`, `:node`, `:mark` or
`:attribute`. `:mark` is which mark on the node, from 1, when the failure
is on one; `:attribute` is the attribute's name.

What is deliberately absent is the *type* — which node, which mark. An
error path carries positions, not names, and inventing them here would
mean re-walking the document this error came from without being handed it.
An application that needs the type has the document.

    case Coelho.Document.Error.describe(error) do
      %{scope: :attribute, attribute: "href", position: [n]} ->
        gettext("The link in paragraph %{n} is not allowed.", n: n)

      %{position: [n | _]} ->
        gettext("Paragraph %{n} could not be saved.", n: n)
    end

# `format`

```elixir
@spec format(t()) :: String.t()
```

Renders an error as `content[0].attrs.href: message`.

# `format_path`

```elixir
@spec format_path([segment()]) :: String.t()
```

Renders a path as `content[0].attrs.href`, or `""` for the document itself.

# `humanize`

```elixir
@spec humanize(t()) :: String.t()
```

An English sentence, for when there is no translator in the building.

A default and not an answer: it reads `block 2, "href": scheme
"javascript" is not allowed`, which is a great deal better than a dotted
path and still not what you would write for your own readers. Use
`describe/1` for that.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
