# `MishkaCmsCore.Builder.Literal`
[🔗](https://github.com/mishka-group/mishka_cms_core/blob/v0.0.1/lib/mishka_cms_core/builder/literal.ex#L5)

Quoted Elixir back into the term it stands for, when it stands for a term and nothing else.

## Why not `Code.eval_quoted/1`

Because every caller here is holding something an author, or a package, or a database row supplied.
Evaluating it would run it. This walks it instead: a map, a tuple, a list and the three scalar
kinds resolve, and everything else — a call, a variable, an assign, an interpolation — answers
`:error` and is left as the source text it always was.

## The two directions

`term/1` is the exact inverse of `Macro.escape/1`, which is what makes `data?/1` a one-liner rather
than a second allowlist kept in step with the first by hand. A value is data when escaping it and
unescaping it gives it back — and that property is the same one `MishkaCmsCore.Builder.Command`
relies on to print a term as source without an `Inspect` of its own.

# `data?`

```elixir
@spec data?(term()) :: boolean()
```

Whether a term is data a page can carry — no function, no pid, no reference.

The check a writer needs before printing a term as source, and the trap it is guarding against is
quiet: a three-element tuple like `{:foo, [], nil}` is a perfectly ordinary term AND a valid quoted
variable, so printing it unescaped writes `foo` into somebody's page. Escaping first is what makes
it print as a tuple; this says whether escaping it was enough.

    iex> MishkaCmsCore.Builder.Literal.data?(%{"a" => [1, {:b, "c"}]})
    true

    iex> MishkaCmsCore.Builder.Literal.data?(&String.trim/1)
    false

# `term`

```elixir
@spec term(Macro.t()) :: {:ok, term()} | :error
```

The term a quoted expression stands for, or `:error`.

Quoted Elixir says what a thing is by its shape: a map is `{:%{}, meta, pairs}`, a tuple of any
size but two is `{:{}, meta, items}`, a two-tuple is itself — and every OTHER three-element tuple
is a call, a variable or an alias, which is precisely what must not resolve. Listing what is
allowed rather than what is not is the only way round that stays right when a syntax is added.

# `value`

```elixir
@spec value(String.t()) :: {:ok, term()} | :error
```

The term a source string stands for, or `:error`.

    iex> MishkaCmsCore.Builder.Literal.value(~s|%{"kind" => :info}|)
    {:ok, %{"kind" => :info}}

    iex> MishkaCmsCore.Builder.Literal.value("@assign")
    :error

---

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