Packages
jsv
0.2.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/ref.ex
defmodule JSV.Ref do
alias __MODULE__
alias JSV.RNS
@moduledoc """
Representation of a JSON Schema reference (`$ref` or `$dynamicRef`).
"""
defstruct ns: nil, kind: nil, fragment: nil, arg: nil, dynamic?: false
@type t :: %__MODULE__{}
@type ns :: binary | :root
@doc """
Creates a new reference from an URL, relative to the given namespace.
If the URL is absolute and its namespace is different from the given
namespace, returns an absolute URL.
"""
@spec parse(binary, ns) :: {:ok, t} | {:error, term}
def parse(url, current_ns) do
do_parse(url, current_ns, false)
end
@doc """
Like `parse/2` but flags the reference as dynamic.
"""
@spec parse_dynamic(binary, ns) :: {:ok, t} | {:error, term}
def parse_dynamic(url, current_ns) do
do_parse(url, current_ns, true)
end
defp do_parse(url, current_ns, dynamic?) do
uri = URI.parse(url)
{kind, normalized_fragment, arg} = parse_fragment(uri.fragment)
dynamic? = dynamic? and kind == :anchor
with {:ok, ns} <- RNS.derive(current_ns, url) do
{:ok, %Ref{ns: ns, kind: kind, fragment: normalized_fragment, arg: arg, dynamic?: dynamic?}}
end
end
defp parse_fragment(nil) do
{:top, nil, []}
end
defp parse_fragment("") do
{:top, nil, []}
end
defp parse_fragment("/") do
{:top, nil, []}
end
defp parse_fragment("/" <> path = fragment) do
{:pointer, fragment, parse_pointer(path)}
end
defp parse_fragment(anchor) do
{:anchor, anchor, anchor}
end
defp parse_pointer(raw_docpath) do
raw_docpath |> String.split("/") |> Enum.map(&parse_pointer_segment/1)
end
defp parse_pointer_segment(string) do
case Integer.parse(string) do
{int, ""} -> int
_ -> unescape_json_pointer(string)
end
end
defp unescape_json_pointer(str) do
str
|> String.replace("~1", "/")
|> String.replace("~0", "~")
|> URI.decode()
end
@doc """
Encodes the given string as a JSON representation of a JSON pointer, that is
with `~` as `~0` and `/` as `~1`.
"""
@spec escape_json_pointer(binary) :: binary
def escape_json_pointer(str) do
str
|> String.replace("~", "~0")
|> String.replace("/", "~1")
end
end