Packages
jsv
0.15.0
0.21.2
0.21.1
0.21.0
0.20.0
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.3
0.18.2
0.18.1
0.18.0
0.17.1
0.17.0
0.16.0
0.15.2
0.15.1
0.15.0
0.14.0
0.13.1
0.13.0
0.12.0
0.11.5
0.11.4
0.11.3
retired
0.11.2
0.11.1
0.11.0
0.10.1
0.10.0
0.9.0
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.0
0.5.1
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
A JSON Schema Validator with complete support for the latest specifications.
Current section
Files
Jump to
Current section
Files
lib/jsv/key.ex
defmodule JSV.Key do
alias JSV.Ref
@moduledoc """
Helpers around the different key formats used in the resolver, builder and
validator states to index sub schemas, referenced schemas, anchor or meta
schemas.
For instance:
* We have a `{"$ref": "http://some-schema/#$defs/order"}` JSON schema.
* The builder will build the `$ref` keyword as a key: `{:pointer,
"http://some-schema/", ["$defs","order"]}`.
* The builder, via the resolver, will fetch `http://some-schema/`, store it
locally and build validators. Those validators will be stored under the same
key (`{:pointer, "http://some-schema/", ["$defs","order"]}`) in the root
schema.
* When the validator will validate the reference, it will fetch that key from
the root schema and apply the retrieved validators to the data.
"""
@type pointer :: {:pointer, binary, [binary]}
@type anchor :: {:anchor, binary, binary}
@type dynamic_anchor :: {:dynamic_anchor, binary, binary}
@type ns :: Ref.ns()
@type t :: ns | anchor | dynamic_anchor | pointer
@doc """
Creates a new key from an external or local reference.
"""
@spec of(ns | Ref.t()) :: t
def of(namespace_or_ref)
def of(binary) when is_binary(binary) do
binary
end
def of(:root) do
:root
end
def of(%Ref{} = ref) do
of_ref(ref)
end
defp of_ref(%{dynamic?: true, ns: ns, kind: :anchor} = ref) do
%{arg: arg} = ref
for_dynamic_anchor(ns, arg)
end
defp of_ref(%{dynamic?: false} = ref) do
%Ref{kind: kind, ns: ns, arg: arg} = ref
case kind do
:top -> ns
:pointer -> for_pointer(ns, arg)
:anchor -> for_anchor(ns, arg)
end
end
@doc "Returns a pointer type key."
@spec for_pointer(ns, [binary()]) :: pointer()
def for_pointer(ns, arg) when is_list(arg) do
{:pointer, ns, arg}
end
@doc "Returns an anchor type key."
@spec for_anchor(ns, binary) :: anchor()
def for_anchor(ns, arg) when is_binary(arg) do
{:anchor, ns, arg}
end
@doc "Returns a dynamic anchor type key."
@spec for_dynamic_anchor(ns, binary) :: dynamic_anchor()
def for_dynamic_anchor(ns, arg) when is_binary(arg) do
{:dynamic_anchor, ns, arg}
end
@doc "Returns the namespace of the key."
@spec namespace_of(t) :: ns
def namespace_of(binary) when is_binary(binary) do
binary
end
def namespace_of(:root) do
:root
end
def namespace_of({:anchor, ns, _}) do
ns
end
def namespace_of({:dynamic_anchor, ns, _}) do
ns
end
def namespace_of({:pointer, ns, _}) do
ns
end
@doc """
Returns a string representation of the key, in a URL/JSON pointer format,
as chardata.
"""
@spec to_iodata(t) :: IO.chardata()
def to_iodata(bin) when is_binary(bin) do
bin
end
def to_iodata(:root) do
[""]
end
def to_iodata({:pointer, ns, [_ | _] = path}) do
[ns_to_iodata(ns), "#/" | Enum.map_intersperse(path, "/", &to_iodata_segment/1)]
end
def to_iodata({:dynamic_anchor, ns, anchor}) do
[ns_to_iodata(ns), "#/", anchor]
end
def to_iodata({:anchor, ns, anchor}) do
[ns_to_iodata(ns), "#/", anchor]
end
defp ns_to_iodata(:root) do
""
end
defp ns_to_iodata(bin) when is_binary(bin) do
bin
end
defp to_iodata_segment(bin) when is_binary(bin) do
bin
end
defp to_iodata_segment(n) when is_integer(n) do
Integer.to_string(n)
end
end