Infers a structured shape from a predicator value, and renders that shape as a display label.
infer/1 walks a value from the predicator value domain (ADR-0003) and
produces a t() term describing its structure - scalars, lists, maps,
and the predicator-specific :null / :undefined / :duration
distinctions. label/2 renders that term as a short human-readable string
for use in the explorer tree; a later phase's editor completions consume
the structured term directly instead of the label.
Kept a pure, standalone module on purpose: it depends on nothing from
StatifierUI.Fixtures and nothing here reaches back into it.
Summary
Functions
Whether value is a predicator duration: a non-empty map whose keys are
atoms drawn from the eight duration units and whose values are all
integers.
Infers a t() shape from a predicator value.
Renders a t() shape as a short display label.
Types
Functions
Whether value is a predicator duration: a non-empty map whose keys are
atoms drawn from the eight duration units and whose values are all
integers.
A subset of the units is enough, deliberately. Predicator.Duration's
own builder returns all eight, but predicator's expression parser returns
seven - Predicator.evaluate("3d") omits :milliseconds - so requiring
the full set misses every duration produced by evaluating an expression,
which is the common case. Nothing else in the value domain can collide:
atom keys reach a fixture only from Elixir, and a datamodel forbids them
outright (StatifierUI.Fixtures), so the only atom-keyed maps that arrive
here are durations.
Public because StatifierUI.Fixtures and StatifierUI.Value need the same
rule, and three copies of it are what let the seven-versus-eight gap go
unnoticed once already.
Examples
iex> StatifierUI.Shape.duration?(%{days: 3, hours: 8})
true
iex> StatifierUI.Shape.duration?(%{"days" => 3})
false
Infers a t() shape from a predicator value.
Total over term(): anything outside the predicator value domain (a
tuple, a pid, a reference, an unrecognized struct) infers as :unknown
rather than raising.
Examples
iex> StatifierUI.Shape.infer(1999)
:integer
iex> StatifierUI.Shape.infer(%{"amount" => 1999})
{:map, %{"amount" => :integer}}
iex> StatifierUI.Shape.infer(["a", "b"])
{:list, :string}
Renders a t() shape as a short display label.
Options:
:max_keys- maximum map pairs shown before truncating to...(default4).:max_depth- maximum nesting depth rendered before a nested map or list collapses tomap{...}/list<...>(default3).
Truncation is a label-only concern; infer/1 itself recurses fully.
Examples
iex> StatifierUI.Shape.label(StatifierUI.Shape.infer(%{"amount" => 1999}))
"map{amount: integer}"
iex> StatifierUI.Shape.label(StatifierUI.Shape.infer(["a", "b"]))
"list<string>"
iex> shape = StatifierUI.Shape.infer(%{"amount" => 1999, "currency" => "usd"})
iex> StatifierUI.Shape.label(shape, max_keys: 1)
"map{amount: integer, ...}"