Visualize.Chart.Validator (Visualize v0.8.3)

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: 3})
{: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; URLs under the application's policy, generator names against the application's config :visualize, generators:.

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

validate/1 of a design with the URL policy of a read (spec/14 §10.3): the application's config :visualize, urls: [...] made stricter by urls: — http: true only where the application allows http:, a hosts list within the application's — and every generator's name checked against the modules of generators: and the application's config :visualize, generators: (spec/14 §3.13).

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 | :generator,
     term()}
  | {:arity, :generator, atom(), non_neg_integer()}
  | {:generated, :style | :color, atom(), term()}
  | {:ref_kind, atom(), atom()}
  | {:invalid_for, atom()}
  | {:same_name, 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()}
  | {:width, non_neg_integer(), non_neg_integer()}
  | {:rank, non_neg_integer()}
  | :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}
  | {:color_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; URLs under the application's policy, generator names against the application's config :visualize, generators:.

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).

validate(map, atom, opts)

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

validate/1 of a design with the URL policy of a read (spec/14 §10.3): the application's config :visualize, urls: [...] made stricter by urls: — http: true only where the application allows http:, a hosts list within the application's — and every generator's name checked against the modules of generators: and the application's config :visualize, generators: (spec/14 §3.13).

iex> design = %{version: 3, frames: %{main: %{kind: :cartesian}}}
iex> Visualize.Chart.Validator.validate(design, :design, urls: [hosts: ["tile.example"]])
:ok