# `JSV.Validator`
[🔗](https://github.com/lud/jsv/blob/v0.18.3/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(),
  opts: term(),
  schema_path: term(),
  scope: 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(), keyword()) ::
  context()
```

# `error?`

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

Returns whether the given context contains errors.

# `flat_errors`

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

# `list_evaluaded`

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

# `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()
```

# `to_error`

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

# `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()
) ::
  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`.

# `validate_ref`

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

# `with_error`
*macro* 

---

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