# `JSV.Validator`
[🔗](https://github.com/lud/jsv/blob/v0.23.0/lib/jsv/validator.ex#L1)

This is the home of the recursive validation logic.

The validator is called on the root schema, and may be called by vocabulary
implementations to validate sub parts of the data built withing each
vocabulary module.

# `context`

```elixir
@type context() :: %JSV.Validator.ValidationContext{
  cast_stacks: term(),
  data_path: term(),
  errors: term(),
  eval_path: term(),
  evaluated: term(),
  feature_cast: term(),
  feature_unevaluated: term(),
  opts: term(),
  schema_path: term(),
  scope: term(),
  seen_refs: term(),
  validators: term()
}
```

# `eval_sub_path`

```elixir
@type eval_sub_path() :: JSV.Builder.path_segment() | [JSV.Builder.path_segment()]
```

# `result`

```elixir
@type result() :: {:ok, term(), context()} | {:error, context()}
```

# `validator`

```elixir
@type validator() :: JSV.Subschema.t() | JSV.BooleanSchema.t() | {:alias_of, binary()}
```

# `validators`

```elixir
@type validators() :: %{required(JSV.Key.t()) =&gt; validator()}
```

# `context`

```elixir
@spec context(
  %{required(JSV.Key.t()) =&gt; validator()},
  JSV.Key.t(),
  map(),
  boolean(),
  boolean()
) ::
  context()
```

Returns a new validation context targeting the given entrypoint key in the
validators map, with the given validation options.

The two flags enable the tracking machinery for casts and for evaluated
properties and items. They are computed at build time so schemas that use
neither feature validate without the tracking overhead.

# `error?`

```elixir
@spec error?(context()) :: boolean()
```

Returns whether the given context contains errors.

# `flat_errors`

```elixir
@spec flat_errors(context()) :: [JSV.Validator.Error.t()]
```

Returns all errors collected in the context as a flat list.

# `list_evaluaded`

```elixir
@spec list_evaluaded(context()) :: [String.t() | integer()]
```

Lists the object keys and array indices of the data that were evaluated in
the current evaluation frame. Used by vocabulary implementations to support
the `unevaluatedProperties` and `unevaluatedItems` keywords.

# `merge_tracked`

```elixir
@spec merge_tracked(context(), context()) :: context()
```

Merges tracking data from the sub context into the main context. This is
useful to keep information defined by subschemas for the same data level as
the parent schema. Such sub schemas are defined with oneOf/allOf/... or $ref.

Tracking data:

* Evaluated paths, to work with unevaluated properties/items
* Cast functions (defschema,defcast)

# `reduce`

```elixir
@spec reduce(Enumerable.t(), term(), context(), function()) :: result()
```

Reduce over an enum with two accumulators, a user one, and the context.

* The callback is called with `item, acc, vctx` for all items in the enum,
  regardless of previously returned values. Returning and error tuple does not
  stop the iteration.
* When returning `{:ok, value, vctx}`, `value` will be the new user
  accumulator, and the new context is carried on.
* When returning `{:error, vctx}`, the current accumulator is not changed, but
  the new returned context with errors is still carried on.
* Returning an ok tuple after an error tuple on a previous item does not
  remove the errors from the context struct.

The final return value is `{:ok, acc, vctx}` if all calls of the callback
returned an OK tuple, `{:error, vctx}` otherwise.

This is useful to call all possible validators for a given piece of data,
collecting all possible errors without stopping, but still returning an error
in the end if some error arose.

# `return`

```elixir
@spec return(term(), context()) :: result()
```

Returns the validation result for the given data, as `{:ok, data, vctx}`
when the context holds no errors, `{:error, vctx}` otherwise.

# `to_error`

```elixir
@spec to_error(context()) :: JSV.ValidationError.t()
```

Builds a `JSV.ValidationError` exception from the errors collected in the
context.

# `validate`

```elixir
@spec validate(term(), validator(), context()) :: result()
```

Validate the given data with the given validator. The validator is typically a
sub-part of a `JSV.Root` struct built with `JSV.build/2` such as a
`JSV.Subschema` struct.

# `validate_as`

```elixir
@spec validate_as(term(), eval_sub_path(), validator(), context()) :: result()
```

Validates data with a sub part of the schema, for instance `if`, `then` or
`else`. Data path will not change in the context.

See `validate_in/5` to validate sub terms of the data.

# `validate_detach`

```elixir
@spec validate_detach(term(), eval_sub_path(), validator(), context()) :: result()
```

Validate the data with the given validators but separate the current
evaluation context during the validation.

Currently evaluated properties or items will not be seen as evaluated during
the validation by the given `subschema`.

# `validate_in`

```elixir
@spec validate_in(
  term(),
  JSV.Builder.path_segment(),
  eval_sub_path(),
  validator(),
  context(),
  JSV.ErrorFormatter.level()
) :: result()
```

Validates a sub term of the data, identified by `key`, which can be a property
name (a string), or an array index (an integer).

See `validate_as/4` to validate the same data point with a nested keyword. For
instance `if`, `then` or `else`.

The `boolean_schema_level` argument sets the level of the error returned when
`subvalidators` is the `false` schema. Keywords that report their own error
for the rejected property or item, with a message naming it, should lower it
to `JSV.ErrorFormatter.level_parent_reported/0`.

# `validate_key`

```elixir
@spec validate_key(
  binary(),
  eval_sub_path(),
  validator(),
  context(),
  JSV.ErrorFormatter.level()
) ::
  result()
```

Validates a property name of the data, as `validate_in/6` does for property
values, but without flagging the property as evaluated.

This is used by the `propertyNames` keyword, which does not evaluate the
property values and must not affect `unevaluatedProperties`.

# `validate_ref`

```elixir
@spec validate_ref(term(), JSV.Key.t(), eval_sub_path(), context()) :: result()
```

Validates the data against the subschema referenced by the given key.

A reference that is already being evaluated with the same data is an
infinite recursion, in that case the data is considered valid, as per JSON
Schema core 9.4.1.

# `with_error`
*macro* 

Adds an error of the given `kind` to the validation context and returns the
updated context. The calling module is registered as the error formatter.

The `args` are a keyword list or map of values used when formatting the
error message, generally the values extracted from the schema keyword and
the reason of the failure.

---

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