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
-
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, ), )
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
-
ValidationContextBuilder( lexicons: dict.Dict(String, types.LexiconDoc), validator: option.Option( fn(json.Json, json.Json, ValidationContext) -> Result( Nil, errors.ValidationError, ), ), )
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)