# `Backplane.JsonSchema.ScopeScanner`

Scans raw schemas and containing documents to discover resource identifiers,
anchors, and local fragment references for the selected draft.

The resulting registry is used by `Backplane.JsonSchema.Compiler` to populate the `defs`
field in the compiled `Schema`, enabling reference resolution during validation.
Traversal is delegated to draft-specific scanners; Draft 2020-12 is the default.

## Examples

    iex> schema = %{
    ...>   "$id" => "https://example.com/schema",
    ...>   "$defs" => %{
    ...>     "user" => %{"$id" => "user", "type" => "object"}
    ...>   }
    ...> }
    iex> {registry, _refs} = Backplane.JsonSchema.ScopeScanner.scan_schema(schema)
    iex> Map.has_key?(registry, "https://example.com/schema")
    true
    iex> Map.has_key?(registry, "https://example.com/user")
    true

# `contextual_scan_result`

```elixir
@type contextual_scan_result() ::
  {registry(), MapSet.t(String.t()), resource_contexts()}
```

# `registry`

```elixir
@type registry() :: %{optional(String.t()) =&gt; map()}
```

Raw schema resources indexed by resolved URI.

# `resource_contexts`

```elixir
@type resource_contexts() :: %{
  optional(String.t()) =&gt; %{raw: term(), source_id: String.t() | nil}
}
```

# `scan_result`

```elixir
@type scan_result() :: {registry(), MapSet.t(String.t())}
```

The resource registry and local fragment references from the initial traversal.

# `scan_document`

```elixir
@spec scan_document(term(), String.t() | nil, keyword()) ::
  scan_result() | contextual_scan_result()
```

Scans maps and lists in a containing document for JSON Schema resource
identifiers and references.

This is intentionally broader than `scan_schema/1`: fragment compilation may receive
an OpenAPI document whose schema objects live under arbitrary paths such as
`components.schemas` or `paths.*.requestBody.content.*.schema`.
The `:draft` option controls Draft 7 `$ref` sibling and newer-keyword handling.
Draft 7 filtering applies in schema context, not to arbitrary document names.
Schema context is inferred from keyword value shapes or inherited from schema
slots. The compiler also passes the selected entry's decoded `:schema_path`
so annotation-only entry schemas do not depend on inference. Draft 7 registers
`$id` resources and collects `$ref` fragments only; `$anchor`, `$dynamicAnchor`,
and `$dynamicRef` never contribute metadata, even in unclassified document maps.
Draft 7 also discovers resources inside explicitly referenced pointer targets,
retaining the containing document or embedded resource as the pointer root.
Ancestor resource identities on explicit pointer or selected-entry routes remain
addressable without traversing unrelated ignored siblings.
Draft 2020-12 scans every map/list node without requiring roles or a selected
schema path. The compiler's `:with_resource_contexts` option has the same
three-element result as `scan_schema/2`.

# `scan_schema`

```elixir
@spec scan_schema(map() | boolean(), keyword()) ::
  scan_result() | contextual_scan_result()
```

Scans a known JSON Schema through draft-recognized subschema locations.

Returns a tuple `{registry, refs}` where:
- `registry` is a map of `{absolute_uri => raw_schema}`.
- `refs` is a MapSet of local fragment references found during the initial traversal.

The `:draft` option defaults to `"draft2020_12"`. Use `"draft7"` to ignore
`$ref` siblings and newer-draft annotations and scan tuple `additionalItems`.
Both drafts honor `:base_uri` as the initial URI for resolving resource IDs;
omitting it retains the default `nil` base. Draft 7 also expands the registry
through explicitly referenced pointer targets, including targets in other
registered resources. Ancestor `$id` resources crossed by those pointers are
registered as fallback identities without traversing their unrelated siblings or
annotations. Ordinary discovery retains precedence, and no external schemas are
loaded. Pointers awaiting a newly discovered resource are retried only
when the registry grows. Additional discovery does not add root-document aliases
to `refs`.

The compiler's `:with_resource_contexts` option adds a third tuple element
mapping each registered target to its lexical resource root and source ID.
This provenance is retained during discovery rather than inferred from a
potentially overwritten canonical URI later.

---

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