A runtime registry of lexicons, keyed by NSID.
The registry backs Lexicon.Validator's cross-lexicon ref resolution:
a lexicon only needs to be registered for refs pointing at it (e.g. a
union variant com.example.foo#item) to fully validate.
State lives in :persistent_term — no process or supervision needed —
which suits the read-heavy, rarely-written profile of a schema cache.
For bigger dynamic sets (thousands of runtime-registered lexicons),
swap in a custom registry module via the validator's :registry opt;
any module implementing fetch/1 works.
Examples
{:ok, lexicon} = Exosphere.Lexicon.Parser.parse_file("my-lexicon.json")
:ok = Exosphere.Lexicon.Registry.register(lexicon)
{:ok, lexicon} = Exosphere.Lexicon.Registry.fetch("com.example.post")
:ok = Exosphere.Lexicon.Registry.validate(
"com.example.post", %{"$type" => "com.example.post", "text" => "hi"})
Summary
Functions
Fetch a registered lexicon by NSID.
All registered NSIDs, sorted.
Register every lexicon JSON file under dir (recursively).
Load every vendored lexicon under the application's priv/lexicons.
Register a lexicon: a parsed lexicon, a %Lexicon.Schema{} struct (as
from Schema.new/1 or Resolver.fetch/4), or a raw lexicon JSON map
(which is parsed and validated first).
Register many lexicons at once, stopping at the first error.
Whether an NSID is registered.
Clear the registry. Intended for tests and repl sessions.
Remove a lexicon from the registry.
Validate a value against a registered lexicon.
Validate a record map (with $type) against its registered lexicon.
Functions
@spec fetch(String.t()) :: {:ok, Exosphere.Lexicon.Parser.lexicon()} | :error
Fetch a registered lexicon by NSID.
@spec list() :: [String.t()]
All registered NSIDs, sorted.
Register every lexicon JSON file under dir (recursively).
Returns {:ok, nsids} or {:error, {path, reason}} for the first file
that fails to parse. Host applications can point this at their own
priv/lexicons.
Load every vendored lexicon under the application's priv/lexicons.
@spec register( Exosphere.Lexicon.Parser.lexicon() | Exosphere.Lexicon.Schema.t() | map() ) :: :ok | {:error, [{path :: String.t(), message :: String.t()}]}
Register a lexicon: a parsed lexicon, a %Lexicon.Schema{} struct (as
from Schema.new/1 or Resolver.fetch/4), or a raw lexicon JSON map
(which is parsed and validated first).
Later registrations for the same NSID replace earlier ones.
@spec register_all(Enumerable.t() | map()) :: :ok | {:error, term()}
Register many lexicons at once, stopping at the first error.
Accepts any enumerable of lexicons (parsed, %Schema{}, or raw JSON
maps) — including the %{nsid => lexicon} map returned by
Parser.parse_dir/1.
Whether an NSID is registered.
@spec reset() :: :ok
Clear the registry. Intended for tests and repl sessions.
@spec unregister(String.t()) :: :ok
Remove a lexicon from the registry.
@spec validate(String.t(), term(), keyword()) :: :ok | {:error, [{path :: String.t(), message :: String.t()}]}
Validate a value against a registered lexicon.
type is an NSID ("com.example.post") or NSID with fragment
("com.example.post#item"). Options are passed to Validator.validate/4.
With optimistic: true, an unregistered NSID passes without
validation, mirroring the PDS "fail-open" record-creation mode.
@spec validate_record(String.t(), term(), keyword()) :: :ok | {:error, [{path :: String.t(), message :: String.t()}]}
Validate a record map (with $type) against its registered lexicon.