# `Macaw.Layers.Document`
[🔗](https://github.com/dcoai/macaw_layers/blob/v0.2.2/lib/macaw/layers/document.ex#L1)

Reading a document through the gates, in order (spec/01 §5).

A document type implements this behavior and `Macaw.Layers.Version`: its version line
and steps, and `c:validate/1`, which judges a document at the current version. Whatever
the document came from (a file, a database, an object store), it is read the same way,
by `read/3`, and nothing in it is evaluated:

1. **bytes**: an encoded document longer than the `bytes` limit is refused;
2. **decode** with the `depth` and `items` limits, by `Macaw.Layers.Scan`, which stops at
   a limit before any value is built; only then is it decoded, with Elixir's `JSON`;
3. **version**: a newer stamp is refused by name before anything else is read;
4. **migrate**, step by step;
5. **validate**, and count `depth` and `items` again, since a migration can grow a
   document.

Faults from one gate stop the gates after it. Within the last, the type's faults and the
recount's are all reported, ordered by path.

# `option`

```elixir
@type option() :: {:limits, keyword() | map()}
```

`read/3`'s options.

# `validate`

```elixir
@callback validate(document :: map()) :: :ok | {:error, [Macaw.Layers.Fault.t(), ...]}
```

`:ok`, or every fault of a document at the type's current version. Unknown keys are
refused by name (see `unknown_keys/3`).

# `digest`

```elixir
@spec digest(map()) :: String.t()
```

The canonical digest of a document's map form (`Macaw.Layers.Form.to_map/2`): 64
lowercase hex characters, the SHA-256 of its canonical encoding (spec/01 §7).

The encoding is JSON with objects' keys sorted bytewise, no insignificant whitespace,
each string as `JSON` encodes it, an integer in decimal, and a float in its shortest
spelling that reads back as the same float. Reordering keys, at any depth, does not
change the digest; a document and its JSON round trip have the same one. The encoding is
part of the kernel's contract: changing it changes every digest, so it changes only with
a new major version.

Raises `ArgumentError` for a term that is not a map form: an atom key, a tuple, any
value JSON has no form for. Write the value's map form first.

    iex> Macaw.Layers.Document.digest(%{"b" => 1, "a" => [true, nil]}) ==
    ...>   Macaw.Layers.Document.digest(%{"a" => [true, nil], "b" => 1})
    true

# `read`

```elixir
@spec read(binary() | map(), module(), [option()]) ::
  {:ok, map()} | {:error, [Macaw.Layers.Fault.t(), ...]}
```

The document, read through every gate, at the type's current version: `{:ok, map}`, or
every fault of the first gate that refuses it.

`input` is the JSON form, a binary, or the map form, which skips the bytes gate and is
walked for `depth` and `items` instead of scanned. `type` implements this behavior and
`Macaw.Layers.Version`. `limits:` tightens the limits, as `Macaw.Layers.Limits.new/1`
takes them.

# `unknown_keys`

```elixir
@spec unknown_keys(map(), [String.t()], Macaw.Layers.Fault.path()) :: [
  Macaw.Layers.Fault.t()
]
```

The faults of `map`'s keys that are not among `known`, each at its own spelling under
`path`: `{path ++ [key], :unknown_key}`, ordered by path.

`known` is the type's keys as the document spells them, strings. A key the type knows
stays the type's to read; one it does not is refused by name, never dropped.

    iex> Macaw.Layers.Document.unknown_keys(%{"title" => "t", "ttle" => "x"}, ["title"], [:page])
    [{[:page, "ttle"], :unknown_key}]

---

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