Visualize.Chart.Validator (Visualize v0.4.1)

Copy Markdown View Source

Validates a design map against the schema (spec/14 §10).

validate/1 walks the map with Visualize.Chart.Schema and returns every fault it finds as {path, reason}: the path is the list of keys and indexes from the design to the faulty value, [:marks, 1, :channels, :y], and the reason one of the terms of spec/14 §10.1. References — scales, styles, sources, variables, fields, theme slots — resolve against the design itself, so a design is self-contained or it does not validate. format/1 renders an error as a line a person reads.

Examples

iex> Visualize.Chart.Validator.validate(%{version: 2})
{:error, [{[:frames], :required}]}
iex> Visualize.Chart.Validator.format({[:marks, 1, :channels, :y], :required})
"marks[1].channels.y: is required"

Summary

Types

Keys and list indexes from the design to a value; [] is the design. A path into a parsed JSON document refused before it was decoded holds the document's key strings (spec/14 §9.2), which format_path/1 spells alike.

Why a value is at fault (spec/14 §10.1).

Functions

One error as path: reason in words; the path in marks[1].channels.y form.

A path as a person reads it — design for the root, else frame.scales.x, marks[0].channels — the one spelling every error, node label and rendered data-node uses (spec/14 §4.7, §18.5).

:ok, or every fault of the design ordered by path.

:ok, or every fault of a fragment read as a kind — per-kind validity (spec/14 §19.8).

Types

error()

@type error() :: {path(), reason()}

path()

@type path() :: [atom() | String.t() | non_neg_integer()]

Keys and list indexes from the design to a value; [] is the design. A path into a parsed JSON document refused before it was decoded holds the document's key strings (spec/14 §9.2), which format_path/1 spells alike.

reason()

@type reason() ::
  :required
  | :unknown_key
  | {:type, Visualize.Chart.Schema.type()}
  | {:enum, [atom()]}
  | {:undeclared, :scale | :style | :source | :var | :field | :slot | :paint,
     term()}
  | {:ref_kind, atom(), atom()}
  | {:invalid_for, atom()}
  | {:unsupported_version, term()}
  | {:newer_schema, pos_integer(), pos_integer()}
  | {:limit, Visualize.Chart.Limits.name(), pos_integer(), number()}
  | {:json, String.t()}
  | {:missing_dependency, :jason}
  | {:unknown_theme, atom()}
  | {:unresolved, :var, atom()}
  | {:var_binding, atom()}
  | {:unbound, :source, atom()}
  | {:missing_field, atom()}
  | :conflict
  | :cycle
  | {:cycle, [term()]}
  | {:template, :unterminated | {:hole, String.t()}}
  | :many_kinds
  | :sweep
  | :radius
  | {:zone, String.t(), Visualize.Scale.Time.zone_error()}
  | {:unit, term(), Visualize.Unit.reason()}
  | {:quantity, Visualize.Quantity.t(), Visualize.Unit.code()}
  | {:sync, :frame_kind | :x_scale, atom() | nil}
  | {:brush, :frame_kind | :x_scale, atom() | nil}
  | {:colour_map, atom()}
  | {:polarity, :range}
  | {:tiles, :projection, atom()}
  | {:tiles, :attribution | :url | :subdomains}
  | {:outside_domain, atom(),
     number() | {:column, atom(), :number | :text | :time}}
  | {:feeds_domain, atom(), number()}
  | {:contract, String.t()}
  | {:undeclared_field, atom(), atom()}
  | {:missing_attribute, atom(), atom(), atom()}
  | {:schema_type, atom(), atom(), atom()}
  | {:type_mismatch, atom(), atom(), :time | :number | :category, atom()}
  | {:no_schema, atom()}
  | {:unknown_schema, term(), String.t()}
  | {:describe, term(), term()}
  | {:schema_version, term(), String.t(), String.t()}

Why a value is at fault (spec/14 §10.1).

Functions

format(arg)

@spec format(error()) :: String.t()

One error as path: reason in words; the path in marks[1].channels.y form.

format_path(path)

@spec format_path(path()) :: String.t()

A path as a person reads it — design for the root, else frame.scales.x, marks[0].channels — the one spelling every error, node label and rendered data-node uses (spec/14 §4.7, §18.5).

iex> Visualize.Chart.Validator.format_path([:marks, 0, :channels])
"marks[0].channels"
iex> Visualize.Chart.Validator.format_path([])
"design"

validate(map)

@spec validate(term()) :: :ok | {:error, [error(), ...]}

:ok, or every fault of the design ordered by path.

validate(map, kind)

@spec validate(term(), atom()) :: :ok | {:error, [error(), ...]}

:ok, or every fault of a fragment read as a kind — per-kind validity (spec/14 §19.8).

A design is validated whole. A composite must be %{composite: %{uses, vars}} and nothing else, its uses sites. Any other kind is the singular body under its key — %{style: %{…}}, %{frames: %{main: %{…}}} — walked with that kind's schema and no design around it, so a reference to a scale, style, source, variable or field the fragment does not declare is not a fault: a fragment is a piece, and what it refers to is bound where it is composed. A fragment whose one key is not the kind's is refused as {:type, {:node, kind}}. A board, %{board: map}, is read by its own reader, Visualize.Board.from_map/1, every fault under [:board | path] (spec/14 §22.1).