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.
Summary
Functions
Whether a term is data a page can carry — no function, no pid, no reference.
The term a quoted expression stands for, or :error.
The term a source string stands for, or :error.
Functions
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
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.
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