# `A2UICore.Pointer`
[🔗](https://github.com/a2ui-elixir/a2ui/blob/v0.1.1/umbrella/apps/a2ui_core/lib/a2ui_core/pointer.ex#L1)

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: `0` or non-zero-leading
  digits only (`"01"` is **not** an index).
* Maximum array index `10_000` guards against OOM/DoS by construction.

This module only handles pointer parsing/building; the store that
enforces traversal rules lives in `A2UICore.State.DataModel`.

# `token`
*since 0.1.0* 

```elixir
@type token() :: String.t()
```

One segment of a parsed pointer, as stored after unescape.

# `array_index?`
*since 0.1.0* 

```elixir
@spec array_index?(term()) :: boolean()
```

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.

# `build`
*since 0.1.0* 

```elixir
@spec build([token()]) :: String.t()
```

Builds an absolute pointer string from unescaped tokens (inverse of
`parse/1`).

# `forbidden_segments`
*since 0.1.0* 

```elixir
@spec forbidden_segments() :: MapSet.t(String.t())
```

The forbidden path segments (after unescaping), as a `MapSet`.

These guard against prototype pollution.

# `max_array_index`
*since 0.1.0* 

```elixir
@spec max_array_index() :: pos_integer()
```

The maximum allowed array index (inclusive).

# `parse`
*since 0.1.0* 

```elixir
@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"

# `resolve`
*since 0.1.0* 

```elixir
@spec resolve(String.t(), String.t() | nil) :: String.t()
```

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

---

*Consult [api-reference.md](api-reference.md) for complete listing*
