gargamelle
Typed JSON decoding and JSON Schema 2020-12 emission from one definition.
Parse JSON with parse, then call validate or decode. Validation never
invokes user converters; decoding invokes them only after structural success.
Converters are trusted application code: exceptions are operational failures.
JavaScript is the supported target; Node 24 is the verified runtime.
Types
JSON syntax or nonfinite-number admission failure.
pub type AdmissionError {
AdmissionError(String)
}
Constructors
-
AdmissionError(String)
An invalid definition, constraint, default, or reference graph.
pub type ConstructionError {
ConstructionError(String)
}
Constructors
-
ConstructionError(String)
A structural validation failure. path is a JSON Pointer (empty at the root).
branches contains indexed union errors and matches identifies matching
branches. Categories and diagnostic wording may evolve before version 1.0.
pub type DataError {
DataError(
category: String,
path: String,
missing_key: option.Option(String),
branches: List(#(Int, List(DataError))),
matches: List(Int),
)
}
Constructors
-
DataError( category: String, path: String, missing_key: option.Option(String), branches: List(#(Int, List(DataError))), matches: List(Int), )
A structural acceptance contract paired with a typed conversion function.
pub opaque type Definition(a)
A finite numeric endpoint. Inclusive endpoints accept equality.
pub type NumberBound {
Inclusive(Float)
Exclusive(Float)
}
Constructors
-
Inclusive(Float) -
Exclusive(Float)
Treatment of undeclared record keys. Closed rejects them; Open accepts
them but omits them from the constructed output.
pub type Policy {
Closed
Open
}
Constructors
-
Closed -
Open
An unfinished record consuming a curried constructor one field at a time.
pub opaque type Record(a)
An unfinished exact-length tuple consuming a curried constructor by position.
pub opaque type Tuple(a)
An admitted JSON value. Construct values through parse; arbitrary runtime
objects cannot enter the validation boundary.
pub opaque type Value
Values
pub fn any_of(
defs: List(Definition(a)),
) -> Result(Definition(a), ConstructionError)
Accept one or more matching branches and decode with the first matching branch in list order. Empty unions fail construction.
pub fn array(def: Definition(a)) -> Definition(List(a))
Accept homogeneous arrays and decode every element in input order.
pub fn boolean_constant(v: Bool) -> Definition(Bool)
Accept exactly this boolean.
pub fn bounds(
def: Definition(a),
lower: option.Option(Int),
upper: option.Option(Int),
) -> Result(Definition(a), ConstructionError)
Intersect inclusive integer bounds, Unicode code-point string lengths,
homogeneous array lengths or dictionary key counts. None leaves a side
unbounded. Unsupported definitions and invalid intervals fail construction.
pub fn contains(
def: Definition(a),
matching: Definition(b),
minimum: Int,
maximum: option.Option(Int),
) -> Result(Definition(a), ConstructionError)
Require between minimum and maximum structurally matching array items. Preserve the original decoder; matching-definition converters never run.
pub fn decode(
def: Definition(a),
value: Value,
) -> Result(a, List(DataError))
Validate first, then construct the typed output. Invalid input returns data errors without running converters. Exceptions from trusted callbacks propagate.
pub fn defaulted(
r: Record(fn(a) -> b),
name: String,
child: Definition(a),
value: Value,
) -> Result(Record(b), ConstructionError)
Add a field with an admitted JSON default validated during construction. When absent, decode the default with the child converter. A present invalid value still fails; defaults do not mutate the input or bypass validation.
pub fn description(
def: Definition(a),
s: String,
) -> Definition(a)
Add a schema description without changing validation or decoding.
pub fn dictionary(
def: Definition(a),
) -> Definition(List(#(String, a)))
Accept objects whose values satisfy the child definition. Decode to a Gleam list of key/value pairs, preserving original keys rather than a JS object.
pub fn element(
t: Tuple(fn(a) -> b),
child: Definition(a),
) -> Tuple(b)
Append one required position, consuming one constructor argument.
pub fn emit_json(def: Definition(a)) -> Value
Emit a JSON Schema 2020-12 document as Gargamelle’s opaque Value, not
gleam/json.Json. Unfinished or conflicting reference graphs fail operationally.
pub fn emit_text(def: Definition(a)) -> String
Emit canonical JSON Schema 2020-12 text, including finite local references.
pub fn exclude(
def: Definition(a),
forbidden: Definition(b),
) -> Definition(a)
Reject input accepted by a forbidden structural definition. Preserve the base output; forbidden-definition converters never run.
pub fn finish(r: Record(a), policy: Policy) -> Definition(a)
Finish a typed record with the chosen undeclared-key policy.
pub fn finish_tuple(t: Tuple(a)) -> Definition(a)
Close a tuple. Short arrays and extra positions are rejected.
pub fn if_then(
def: Definition(a),
condition: Definition(b),
consequence: Definition(c),
) -> Definition(a)
Validate the consequence only when the structural condition accepts input. Retain the base output; condition/consequence converters never run.
pub fn if_then_else(
def: Definition(a),
condition: Definition(b),
consequence: Definition(c),
alternative: Definition(d),
) -> Definition(a)
Validate exactly the selected structural branch, retaining the base decoder.
pub fn integer_constant(
v: Int,
) -> Result(Definition(Int), ConstructionError)
Accept exactly this safe integer; reject constants outside the safe range.
pub fn map(def: Definition(a), f: fn(a) -> b) -> Definition(b)
Transform decoded output without changing schema acceptance. The callback runs only during successful decoding and must return the declared output type.
pub fn named(
name: String,
def: Definition(a),
) -> Result(Definition(a), ConstructionError)
Name a definition for local $defs/$ref reuse. Names must start with an
ASCII letter and contain only ASCII letters, digits, underscores or hyphens.
Conflicting names fail when the composed graph is validated or emitted.
pub fn nullable(
def: Definition(a),
) -> Definition(option.Option(a))
Accept null as None, or decode the child as Some. This does not make
a record field optional.
pub fn number() -> Definition(Float)
Decode any admitted finite IEEE-754 number to Float, including integers. JSON parsing may round or underflow; decoding preserves the parsed value.
pub fn number_bounds(
def: Definition(Float),
lower: option.Option(NumberBound),
upper: option.Option(NumberBound),
) -> Result(Definition(Float), ConstructionError)
Intersect a number definition’s interval with finite inclusive/exclusive bounds. Reject inverted intervals and exclusive equal endpoints.
pub fn one_of(
defs: List(Definition(a)),
) -> Result(Definition(a), ConstructionError)
Accept exactly one structurally matching branch and decode with it. Overlapping matches are rejected. Empty unions fail construction.
pub fn optional(
r: Record(fn(option.Option(a)) -> b),
name: String,
child: Definition(a),
) -> Result(Record(b), ConstructionError)
Add an optional field, consuming an Option(a) constructor argument.
Absence is None; present values must satisfy the child, including null.
pub fn parse(text: String) -> Result(Value, AdmissionError)
Admit JSON text without invoking a definition or converter. Duplicate object keys use the parser’s last value; numeric values use IEEE-754 binary64.
pub fn pattern(
def: Definition(String),
p: String,
) -> Result(Definition(String), ConstructionError)
Intersect an unanchored ECMAScript Unicode regular expression with a string definition. Anchor explicitly for whole-string matching. Invalid expressions and unsupported underlying definitions fail construction.
pub fn property_names(
def: Definition(a),
keys: Definition(String),
) -> Result(Definition(a), ConstructionError)
Constrain every own object key without changing decoded values or keys. The key definition is used for validation only; its converter never runs.
pub fn record(constructor: a) -> Record(a)
Start a record with a curried constructor. Each field consumes one argument;
call finish after supplying all fields. Multi-argument constructors need currying.
pub fn recursive(
name: String,
build: fn(Definition(a)) -> Result(
Definition(a),
ConstructionError,
),
) -> Result(Definition(a), ConstructionError)
Build a guarded self-recursive definition. The builder runs once with a typed definition placeholder, never an invented decoded value.
pub fn recursive_pair(
first_name: String,
second_name: String,
build: fn(Definition(a), Definition(b)) -> Result(
#(Definition(a), Definition(b)),
ConstructionError,
),
) -> Result(#(Definition(a), Definition(b)), ConstructionError)
Build two mutually recursive definitions with distinct names and independent output types. References may cross only through guarded data structure edges.
pub fn required(
r: Record(fn(a) -> b),
name: String,
child: Definition(a),
) -> Result(Record(b), ConstructionError)
Add a required field. Duplicate field names fail construction.
pub fn safe_integer() -> Definition(Int)
Accept integral numbers between -9007199254740991 and 9007199254740991.
pub fn string_constant(v: String) -> Definition(String)
Accept exactly this string.
pub fn string_enum(
values: List(String),
) -> Result(Definition(String), ConstructionError)
Accept one of the supplied strings. Empty or duplicate alternatives fail construction.
pub fn tagged(
discriminator: String,
variants: List(Variant(a)),
) -> Result(Definition(a), ConstructionError)
Construct a discriminated union of record variants. Empty lists, duplicate tags and fields redeclaring the discriminator are construction errors.
pub fn title(def: Definition(a), s: String) -> Definition(a)
Add a schema title without changing validation or decoding.
pub fn tuple(constructor: a) -> Tuple(a)
Start an exact-length positional array with a curried typed constructor.
pub fn unique_items(
def: Definition(List(a)),
) -> Result(Definition(List(a)), ConstructionError)
Require structurally distinct JSON items in a direct homogeneous array definition. Uniqueness is checked before mapping, not on decoded outputs.
pub fn validate(
def: Definition(a),
value: Value,
) -> Result(Nil, List(DataError))
Validate an admitted value without invoking constructors or map callbacks. Unfinished/conflicting reference graphs and resource exhaustion are operational failures rather than data errors.
pub fn value_text(value: Value) -> String
Serialize an admitted value as canonical JSON text. Negative zero becomes 0.
pub fn variant(
tag: String,
r: Record(a),
policy: Policy,
) -> Variant(a)
Finish a tagged record branch. Do not declare the discriminator as a field.
pub fn variant_description(
v: Variant(a),
s: String,
) -> Variant(a)
Describe a tagged branch without changing its acceptance contract.