honk/validation/context

Types

Validation context that tracks state during validation

pub type ValidationContext {
  ValidationContext(
    lexicons: dict.Dict(String, types.LexiconDoc),
    path: String,
    current_lexicon_id: option.Option(String),
    reference_stack: set.Set(String),
    validator: fn(json.Json, json.Json, ValidationContext) -> Result(
      Nil,
      errors.ValidationError,
    ),
  )
}

Constructors

Builder for constructing ValidationContext

pub type ValidationContextBuilder {
  ValidationContextBuilder(
    lexicons: dict.Dict(String, types.LexiconDoc),
    validator: option.Option(
      fn(json.Json, json.Json, ValidationContext) -> Result(
        Nil,
        errors.ValidationError,
      ),
    ),
  )
}

Constructors

Values

pub fn build(
  builder: ValidationContextBuilder,
) -> Result(ValidationContext, errors.ValidationError)

Builds the final ValidationContext from the builder.

Creates a no-op validator if none was set via with_validator. Returns a ValidationContext ready for validating lexicons and data.

Example

let assert Ok(ctx) =
  context.builder()
  |> context.with_validator(field.dispatch_data_validation)
  |> context.with_lexicons([lexicon])
  |> context.build
pub fn builder() -> ValidationContextBuilder

Creates a new ValidationContextBuilder with default settings.

Use this to start building a validation context by chaining with with_lexicons, with_validator, and build.

Example

let assert Ok(ctx) =
  context.builder()
  |> context.with_validator(field.dispatch_data_validation)
  |> context.with_lexicons([my_lexicon])
  |> context.build
pub fn current_lexicon_id(
  ctx: ValidationContext,
) -> option.Option(String)

Returns the ID of the lexicon currently being validated.

Used for resolving local references (e.g., #post) which need to know which lexicon they belong to.

Example

case context.current_lexicon_id(ctx) {
  Some(id) -> // id is like "com.example.post"
  None -> // No lexicon context set
}
pub fn get_lexicon(
  ctx: ValidationContext,
  id: String,
) -> option.Option(types.LexiconDoc)

Retrieves a lexicon document by its NSID from the validation context.

Returns None if the lexicon is not found. Use this to access lexicon definitions when resolving references.

Example

case context.get_lexicon(ctx, "com.example.post") {
  Some(lexicon) -> // Use the lexicon
  None -> // Lexicon not found
}
pub fn has_reference(
  ctx: ValidationContext,
  reference: String,
) -> Bool

Checks if a reference is already in the reference stack.

Returns True if the reference is being validated, indicating a circular reference that would cause infinite recursion. Used to detect and prevent circular dependency errors.

Example

case context.has_reference(ctx, "#user") {
  True -> Error(errors.data_validation("Circular reference detected"))
  False -> // Safe to proceed with validation
}
pub fn parse_reference(
  ctx: ValidationContext,
  reference: String,
) -> Result(#(String, String), errors.ValidationError)

Parse a reference string into (lexicon_id, definition) Handles: #def, nsid#def, nsid

pub fn path(ctx: ValidationContext) -> String

Returns the current validation path within the data structure.

The path is used for generating detailed error messages that show exactly where in a nested structure validation failed.

Example

let current_path = context.path(ctx)
// Returns something like "defs.post.properties.text"
pub fn with_current_lexicon(
  ctx: ValidationContext,
  lexicon_id: String,
) -> ValidationContext

Creates a new context with a different current lexicon ID.

Used when validating cross-lexicon references to set the correct lexicon context for resolving local references.

Example

let ctx_with_lexicon =
  context.with_current_lexicon(ctx, "com.example.post")
pub fn with_lexicons(
  builder: ValidationContextBuilder,
  lexicons: List(json.Json),
) -> Result(ValidationContextBuilder, errors.ValidationError)

Adds a list of lexicon JSON documents to the builder.

Each lexicon must have an ‘id’ field (valid NSID) and a ‘defs’ object containing type definitions. Returns an error if any lexicon is invalid.

Example

let lexicon = json.object([
  #("lexicon", json.int(1)),
  #("id", json.string("com.example.post")),
  #("defs", json.object([...])),
])

let assert Ok(builder) =
  context.builder()
  |> context.with_lexicons([lexicon])
pub fn with_path(
  ctx: ValidationContext,
  segment: String,
) -> ValidationContext

Creates a new context with an updated path segment.

Used when traversing nested data structures during validation to maintain accurate error location information.

Example

let nested_ctx = context.with_path(ctx, "properties.name")
// New path might be "defs.user.properties.name"
pub fn with_reference(
  ctx: ValidationContext,
  reference: String,
) -> ValidationContext

Adds a reference to the reference stack for circular dependency detection.

Used internally during reference resolution to track which references are currently being validated. This prevents infinite loops when references form a cycle.

Example

let ctx_with_ref =
  context.with_reference(ctx, "com.example.post#user")
pub fn with_validator(
  builder: ValidationContextBuilder,
  validator: fn(json.Json, json.Json, ValidationContext) -> Result(
    Nil,
    errors.ValidationError,
  ),
) -> ValidationContextBuilder

Set the validator function Parameters: data (Json), schema (Json), ctx (ValidationContext)

Search Document