RFC 6901 JSON Pointer parsing, building, and resolution.
Matches the reference implementation exactly:
"/"or""parse to the root (empty token list).- Empty segments are dropped, so
"//a///b//"⇔"/a/b". - Unescape order is
~1→/then~0→~(so"~01"decodes to"~1"). - Forbidden segments after unescaping:
"__proto__","constructor","prototype". - Array indices follow the RFC §4 numeric rule:
0or non-zero-leading digits only ("01"is not an index). - Maximum array index
10_000guards against OOM/DoS by construction.
This module only handles pointer parsing/building; the store that
enforces traversal rules lives in A2UICore.State.DataModel.
Summary
Functions
True if segment can be used as an array index per RFC 6901 §4 —
i.e. either "0" or a positive integer with no leading zeros.
Builds an absolute pointer string from unescaped tokens (inverse of
parse/1).
The forbidden path segments (after unescaping), as a MapSet.
The maximum allowed array index (inclusive).
Parses a pointer string into its segments, unescaping them.
Resolves path against context_path
Types
@type token() :: String.t()
One segment of a parsed pointer, as stored after unescape.
Functions
True if segment can be used as an array index per RFC 6901 §4 —
i.e. either "0" or a positive integer with no leading zeros.
Builds an absolute pointer string from unescaped tokens (inverse of
parse/1).
The forbidden path segments (after unescaping), as a MapSet.
These guard against prototype pollution.
@spec max_array_index() :: pos_integer()
The maximum allowed array index (inclusive).
@spec parse(term()) :: {:ok, [token()]} | {:error, A2UICore.Error.t()}
Parses a pointer string into its segments, unescaping them.
Returns {:ok, tokens} or {:error, %A2UICore.Error{}} with category
:data if a segment is in the forbidden set or path is invalid.
Examples
iex> A2UICore.Pointer.parse("/user/name")
{:ok, ["user", "name"]}
iex> A2UICore.Pointer.parse("/a~1b/~0c")
{:ok, ["a/b", "~c"]}
iex> A2UICore.Pointer.parse("/")
{:ok, []}
iex> A2UICore.Pointer.parse("")
{:ok, []}
iex> {:error, error} = A2UICore.Pointer.parse("/__proto__")
iex> error.category
:data
iex> error.code
"DATA_ERROR"
Resolves path against context_path:
resolve("/user", anything) → "/user"
resolve("name", "/user") → "/user/name"
resolve("name", "/") → "/name"
resolve("name", nil) → "/name"This is the simple client-scope join rule from the reference. The
collection-scope semantics are in A2UICore.Resolution.DataContext.