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

A document type's table of `$` tags (spec/01 §6).

A value JSON can't express is written as a **tag**: a one-key object whose key starts
with a single `$`, such as `{"$atom": "ok"}`. Each document type has one table, declared
in a module of its own:

    defmodule MyApp.Layout.Tags do
      use Macaw.Layers.Tags,
        live: ~w($ratio $span),
        retired: %{"$cols" => "was removed in v2: say columns"},
        renamed: %{"$tint" => "$color"}
    end

The kernel's own tags, `$atom`, `$time` and `$version`, are live in every table.

- **Writing:** `tag/2`, a macro in the table's module, refuses at compile time a literal
  tag the table does not list as live, so nothing is written that a reader would refuse.
- **Reading:** `read/1` holds a parsed document to the table: a renamed tag is read under
  its new name, and an unknown or retired tag is refused at the path of its object,
  `{:unknown_tag, tag}` or `{:retired_tag, tag, why}`, never read as data.
- **Escaping:** data may hold any key. A data key that starts with `$` is written with one
  more `$` (`escape/1`) and read back with one fewer (`unescape/1`), so `$$` never names
  a tag. The stamp `$version` at a document's root is not data, and is not escaped.

The generic part of visualize's `Visualize.Chart.Codec.Tags`, with the table supplied by
each type.

# `live`

```elixir
@callback live() :: [String.t()]
```

A table's live, retired and renamed tags.

# `renamed`

```elixir
@callback renamed() :: %{required(String.t()) =&gt; String.t()}
```

Tags written under another name now, old => new.

# `retired`

```elixir
@callback retired() :: %{required(String.t()) =&gt; String.t()}
```

Tags no longer written, each with what replaced it.

# `escape`

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

A data key as a document writes it: one that starts with `$` gets one more.

    iex> Macaw.Layers.Tags.escape("$price")
    "$$price"

# `kernel`

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

The tags the kernel writes, live in every table.

# `read`

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

The parsed document held to `table`: `{:ok, term}` with every renamed tag under its new
name, or every unknown or retired tag refused at its object's path, ordered by path.
Data keys are left as written; `unescape/1` reads them.

# `tag!`

```elixir
@spec tag!(module(), String.t(), term()) :: map()
```

The one-key object of a live tag of `table`; raises `ArgumentError` for any other.

# `unescape`

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

A data key as a document holds it, read: one that starts with `$$` loses one.

    iex> Macaw.Layers.Tags.unescape("$$price")
    "$price"

---

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