README

Betterlol/moon_zod/core does not have a README file

#
SchemaResult

type SchemaResult = Result[Json, Array[ValidationError]]

Result type returned by Schema::parse. Ok(json) on success, Err(errors) with all collected errors on failure.

#
ConstraintInfo

pub(all) struct ConstraintInfo {
min_value : Double
max_value : Double
format : String
pattern : String
is_int : Bool
is_positive : Bool
is_negative : Bool
multiple_of : Double
custom_messages : Array[String]
}

Unified constraint information extracted from Rule annotations. This data structure consolidates all constraint metadata across different types.

#
ObjectMode

pub(all) enum ObjectMode {
Passthrough
Strict
Strip
} derive(
Debug
)

Object validation mode.

#
Rule

pub(all) struct Rule {
check : (Json) -> Bool
message : String
annotation : Json
} derive(
Debug
)

A single validation rule: a predicate + error message + optional JSON Schema annotation.

#
Schema

pub(all) struct Schema {
schema_type : SchemaType
rules : Array[Rule]
description : String
required_error : String
invalid_type_error : String
name : String
brand : String
} derive(
Debug
)

A schema defines the shape and constraints of JSON data.

#
Schema::brand

fn Schema::brand(self : Schema, text : String) -> Schema

Assign a brand to a schema for nominal typing. Branded schemas carry a type-level marker that distinguishes structurally identical schemas (e.g., UserId vs string). The brand is rendered in prompt and JSON Schema exports.

#
Schema::cuid

fn Schema::cuid(self : Schema, msg? : String) -> Schema

Require the string to be a valid CUID (25 chars, starts with 'c', alphanumeric).

#
Schema::datetime

fn Schema::datetime(self : Schema, msg? : String) -> Schema

Require the string to be a valid ISO 8601 datetime.

#
Schema::default

fn Schema::default(self : Schema, value : Json) -> Schema

Provide a default value when the input is null. Rules chained after .default() are pushed through to the inner schema via append_rule.

#
Schema::describe

fn Schema::describe(self : Schema, text : String) -> Schema

Attach a human-readable description to a schema. The description is rendered by schema_to_prompt() alongside type and constraints, helping LLMs understand the semantic meaning of each field.

#
Schema::email

fn Schema::email(self : Schema, msg? : String) -> Schema

Require the string to be a valid email.

#
Schema::endsWith

fn Schema::endsWith(self : Schema, suffix : String, msg? : String) -> Schema

Require the string to end with the given suffix.

#
Schema::extend_with

fn Schema::extend_with(self : Schema, extension : Map[String, Schema]) -> Schema

Extend an object schema with additional fields. Fields in extension override fields with the same name in the base schema.

#
Schema::finite

fn Schema::finite(self : Schema, msg? : String) -> Schema

Require the number to be finite (reject Infinity and NaN).

#
Schema::includes

fn Schema::includes(self : Schema, substring : String, msg? : String) -> Schema

Require the string to contain the given substring.

#
Schema::int

fn Schema::int(self : Schema, msg? : String) -> Schema

Require the number to be an integer (no fractional part).

#
Schema::intersect

fn Schema::intersect(self : Schema, other : Schema) -> Schema

Combine two schemas with intersection (both must match). Equivalent to intersection([self, other]).

#
Schema::invalid_type_error

fn Schema::invalid_type_error(self : Schema, text : String) -> Schema

Override the error message when the input type does not match.

#
Schema::ip

fn Schema::ip(self : Schema, msg? : String) -> Schema

Require the string to be a valid IPv4 or IPv6 address.

#
Schema::ipv4

fn Schema::ipv4(self : Schema, msg? : String) -> Schema

Require the string to be a valid IPv4 address.

#
Schema::ipv6

fn Schema::ipv6(self : Schema, msg? : String) -> Schema

Require the string to be a valid IPv6 address.

#
Schema::length

fn Schema::length(self : Schema, n : Int, msg? : String) -> Schema

Require the string or array to have exactly n items.

#
Schema::max

fn Schema::max(self : Schema, n : Int, msg? : String) -> Schema

Require the string length to be at most n.

#
Schema::merge

fn Schema::merge(self : Schema, other : Schema) -> Schema

Merge two object schemas. Fields from other override fields with the same name in self. The merged schema inherits the right schema's object mode.

#
Schema::message

fn Schema::message(self : Schema, text : String) -> Schema

Override the error message of the last rule in the chain. Peels through OptionalType / DefaultType / TransformType wrappers to find the base schema with the rules array.

Example

string().min(2).message("姓名至少需要 2 个字符")

#
Schema::min

fn Schema::min(self : Schema, n : Int, msg? : String) -> Schema

Require the string length to be at least n.

#
Schema::multipleOf

fn Schema::multipleOf(self : Schema, n : Int, msg? : String) -> Schema

Require the number to be a multiple of n.

#
Schema::name

fn Schema::name(self : Schema, text : String) -> Schema

Give a schema a name for export. When used with schema_to_prompt_named(), named schemas are extracted as separate interface/type definitions in the generated prompt, supporting Object and Enum types.

#
Schema::negative

fn Schema::negative(self : Schema, msg? : String) -> Schema

Require the number to be negative (< 0).

#
Schema::nonempty

fn Schema::nonempty(self : Schema, msg? : String) -> Schema

Require the string to be non-empty (or array to be non-empty).

#
Schema::omit

fn Schema::omit(self : Schema, keys : Array[String]) -> Schema

Omit the specified fields from an object schema. Returns a new object schema with the same mode (Strip/Passthrough/Strict).

Example

let s = object({"a": string(), "b": number()}).omit(["b"]) s.parse(json) // validates only field "a"

#
Schema::optional

fn Schema::optional(self : Schema) -> Schema

Make a field optional: null or missing values pass validation. Rules chained after .optional() are pushed through to the inner schema via append_rule, so string().optional().min(3) works correctly.

#
Schema::parse

fn Schema::parse(self : Schema, json : Json, path? : String) -> Result[Json, Array[ValidationError]]

Validate json against this schema. Public API — accepts an optional root path string. Internally converts to a mutable path stack to avoid string allocations on the success path.

#
Schema::parse_array

fn Schema::parse_array(self : Schema, element_schema : Schema, json : Json, path_stack : Array[String]) -> Result[Json, Array[ValidationError]]

#
Schema::parse_default

fn Schema::parse_default(_self : Schema, inner : Schema, default_val : Json, json : Json, path_stack : Array[String]) -> Result[Json, Array[ValidationError]]

#
Schema::parse_enum

fn Schema::parse_enum(_self : Schema, values : Array[String], json : Json, path_stack : Array[String]) -> Result[Json, Array[ValidationError]]

#
Schema::parse_intersection

fn Schema::parse_intersection(_self : Schema, schemas : Array[Schema], json : Json, path_stack : Array[String]) -> Result[Json, Array[ValidationError]]

#
Schema::parse_literal

fn Schema::parse_literal(_self : Schema, expected : Json, json : Json, path_stack : Array[String]) -> Result[Json, Array[ValidationError]]

#
Schema::parse_object

fn Schema::parse_object(self : Schema, spec : Map[String, Schema], mode : ObjectMode, json : Json, path_stack : Array[String]) -> Result[Json, Array[ValidationError]]

#
Schema::parse_optional

fn Schema::parse_optional(_self : Schema, inner : Schema, json : Json, path_stack : Array[String]) -> Result[Json, Array[ValidationError]]

#
Schema::parse_preprocess

fn Schema::parse_preprocess(self : Schema, closure : TransformClosure, inner : Schema, json : Json, path_stack : Array[String]) -> Result[Json, Array[ValidationError]]

#
Schema::parse_transform

fn Schema::parse_transform(_self : Schema, inner : Schema, closure : TransformClosure, json : Json, path_stack : Array[String]) -> Result[Json, Array[ValidationError]]

#
Schema::parse_tuple

fn Schema::parse_tuple(self : Schema, items : Array[Schema], json : Json, path_stack : Array[String]) -> Result[Json, Array[ValidationError]]

#
Schema::parse_union

fn Schema::parse_union(_self : Schema, schemas : Array[Schema], json : Json, path_stack : Array[String]) -> Result[Json, Array[ValidationError]]

#
Schema::partial

fn Schema::partial(self : Schema) -> Schema

Make all fields of an object schema optional. Useful for partial updates (e.g., PATCH operations). Existing optional fields remain optional.

Example

let s = object({"name": string(), "age": number()}).partial() s.parse(json) // all fields are now optional

#
Schema::passthrough

fn Schema::passthrough(self : Schema) -> Schema

Allow fields not defined in the schema spec.

#
Schema::pick

fn Schema::pick(self : Schema, keys : Array[String]) -> Schema

Select only the specified fields from an object schema. Returns a new object schema with the same mode (Strip/Passthrough/Strict). Keys not present in the original spec are silently ignored.

Example

let s = object({"a": string(), "b": number()}).pick(["a"]) s.parse(json) // validates only field "a"

#
Schema::positive

fn Schema::positive(self : Schema, msg? : String) -> Schema

Require the number to be positive (> 0).

#
Schema::refine

fn Schema::refine(self : Schema, check : (Json) -> Bool, message : String) -> Schema

Add a custom validation rule.

check is a predicate on the JSON value; message is the error message shown when the predicate returns false.

#
Schema::regex

fn Schema::regex(self : Schema, pattern : String, msg? : String) -> Schema

Require the string to match the given regex pattern.

#
Schema::required_error

fn Schema::required_error(self : Schema, text : String) -> Schema

Override the error message when a required field is missing. Only effective when this schema is used as an object field value.

#
Schema::safe

fn Schema::safe(self : Schema, msg? : String) -> Schema

Require the number to be a safe integer (within ±2^53-1).

#
Schema::startsWith

fn Schema::startsWith(self : Schema, prefix : String, msg? : String) -> Schema

Require the string to start with the given prefix.

#
Schema::strict

fn Schema::strict(self : Schema) -> Schema

Reject fields not defined in the schema spec.

#
Schema::strip

fn Schema::strip(self : Schema) -> Schema

Silently strip extra fields not defined in the schema spec. This is the default mode.

#
Schema::to_lower

fn Schema::to_lower(self : Schema) -> Schema

Convert the string to lowercase.

#
Schema::to_upper

fn Schema::to_upper(self : Schema) -> Schema

Convert the string to uppercase.

#
Schema::transform

fn Schema::transform(self : Schema, f : (Json) -> Result[Json, String]) -> Schema

Apply a transformation function to the validated JSON value.

The schema is first validated normally. If validation succeeds, f is called with the validated JSON. The transform can modify the value or return an error.

Rules chained after .transform() are applied to the transformed value.

Example

let s = string().transform(fn(json) {
match json {
String(s) => Ok(Json::string(s + "!"))
_ => Err("expected string")
}
})

#
Schema::trim

fn Schema::trim(self : Schema) -> Schema

Trim leading and trailing whitespace from the string.

#
Schema::ulid

fn Schema::ulid(self : Schema, msg? : String) -> Schema

Require the string to be a valid ULID (26 chars, Crockford Base32).

#
Schema::url

fn Schema::url(self : Schema, msg? : String) -> Schema

Require the string to be a valid URL with http:// or https:// scheme.

#
Schema::uuid

fn Schema::uuid(self : Schema, msg? : String) -> Schema

Require the string to be a valid UUID v4. Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx

#
SchemaType

pub(all) enum SchemaType {
StringType
NumberType
BooleanType
NullType
AnyType
UnknownType
ObjectType(Map[String, Schema], ObjectMode)
ArrayType(Schema)
TupleType(Array[Schema])
OptionalType(Schema)
DefaultType(Schema, Json)
EnumType(Array[String])
UnionType(Array[Schema])
IntersectionType(Array[Schema])
PreprocessType(TransformClosure, Schema)
TransformType(Schema, TransformClosure)
LiteralType(Json)
} derive(
Debug
)

Internal tag for runtime type dispatch.

#
TransformClosure

pub(all) struct TransformClosure {
f : (Json) -> Result[Json, String]
} derive(
Debug
)

Internal wrapper for a transform function stored in TransformType.

#
ValidationError

pub(all) struct ValidationError {
path : String
message : String
got : Json
}

Represents a single validation failure.

path is the field path (e.g. "name", "address.city"). message describes what went wrong. got is the actual JSON value that failed validation.

#
ValidationError::to_string

fn ValidationError::to_string(self : ValidationError) -> String

Format a validation error as a human-readable string. Uses Debug for the received value to avoid Show deprecation.

#
any

fn any(required_error? : String, invalid_type_error? : String) -> Schema

Create a schema that accepts any JSON value.

#
append_rule

fn append_rule(schema : Schema, check : (Json) -> Bool, message : String) -> Schema

Append a rule through decoration wrappers.

#
append_rule_with_annotation

fn append_rule_with_annotation(schema : Schema, check : (Json) -> Bool, message : String, annotation : Json) -> Schema

Append a rule with a JSON Schema annotation fragment. The annotation is merged into the JSON Schema output when to_json_schema() is called, enabling constraint export (minLength, maximum, pattern, etc.).

#
array

fn array(element_schema : Schema, required_error? : String, invalid_type_error? : String) -> Schema

Create a schema that validates JSON arrays.

Each element in the array is validated against element_schema.

#
bigint

fn bigint(required_error? : String, invalid_type_error? : String) -> Schema

Create a schema that validates JSON integer values as big integers.

This is a convenience alias for number().int() that expresses semantic intent. Useful for financial amounts, large IDs, and other scenarios where the semantic type is "big integer" rather than "number that is an integer".

#
boolean

fn boolean(required_error? : String, invalid_type_error? : String) -> Schema

Create a schema that validates JSON booleans.

#
collect_named_schemas

fn collect_named_schemas(schema : Schema) -> Array[Schema]

Collect all named schemas from the input schema tree.

#
collect_named_schemas_impl

fn collect_named_schemas_impl(schema : Schema, visited : Array[String], result : Array[Schema]) -> Unit

#
constraint_comment

fn constraint_comment(schema : Schema) -> String

Extract and format constraint comment for a schema (without description). Dispatches to type-appropriate formatter based on the unwrapped schema type.

#
constraint_info_default

fn constraint_info_default() -> ConstraintInfo

Create a default empty ConstraintInfo

#
constraint_info_to_array_comment

fn constraint_info_to_array_comment(info : ConstraintInfo) -> String

Convert ConstraintInfo to prompt comment string for arrays.

#
constraint_info_to_fallback_comment

fn constraint_info_to_fallback_comment(info : ConstraintInfo) -> String

Convert ConstraintInfo to prompt comment string (fallback for unknown types).

#
constraint_info_to_number_comment

fn constraint_info_to_number_comment(info : ConstraintInfo) -> String

Convert ConstraintInfo to prompt comment string for numbers.

#
constraint_info_to_string_comment

fn constraint_info_to_string_comment(info : ConstraintInfo) -> String

Convert ConstraintInfo to prompt comment string for strings.

#
dfs_topo_sort

fn dfs_topo_sort(name : String, deps_list : Array[(String, Array[String])], visited : Array[(String, Int)], sorted : Array[Schema], schema_map : Array[Schema]) -> Unit

DFS for topological sorting. Adds schemas to sorted list in dependency order.

#
enum_values

fn enum_values(values : Array[String], required_error? : String, invalid_type_error? : String) -> Schema

Create a schema that accepts one of a fixed set of string values.

#
escape_function_name

fn escape_function_name(name : String) -> String

escape a string to be a valid MoonBit function name (lowercase first letter, valid identifier).

#
escape_ident

fn escape_ident(name : String) -> String

escape a string to be a valid MoonBit identifier by replacing invalid characters with underscores.

#
escape_mbt_string

fn escape_mbt_string(s : String) -> String

Escape a string for use in MoonBit code, handling backslashes, quotes, newlines, and tabs.

#
escape_type_name

fn escape_type_name(name : String) -> String

escape a string to be a valid MoonBit type name (uppercase first letter, valid identifier).

#
escape_variable_name

fn escape_variable_name(name : String) -> String

escape a string to be a valid MoonBit variable name (lowercase first letter, valid identifier).

#
extract_constraints

fn extract_constraints(rules : Array[Rule]) -> ConstraintInfo

Extract all constraint information from a Rule array. Unified extraction that works across all types.

#
filter_named_schemas

fn filter_named_schemas(all_named : Array[Schema], include_names : Array[String]?) -> Array[Schema]

Filter named schemas based on include_names optional parameter. If include_names is None, returns all schemas. If Some(names), returns only schemas whose names are in the list.

#
find_schema_dependencies

fn find_schema_dependencies(schema : Schema, schema_map : Array[Schema]) -> Array[String]

Find all named schema dependencies within a schema.

#
find_schema_dependencies_impl

fn find_schema_dependencies_impl(schema : Schema, schema_map : Array[Schema], deps : Array[String], visited_names : Array[String]) -> Unit

#
format_double_simple

fn format_double_simple(v : Double) -> String

Format a Double as a string, stripping ".0" for whole numbers.

#
format_path

fn format_path(stack : Array[String]) -> String

#
indent_str

fn indent_str(n : Int) -> String

Generate n * 2 spaces.

#
inner_type

fn inner_type(t : SchemaType) -> SchemaType

Peel OptionalType / DefaultType wrappers to find the effective base type.

#
intersection

fn intersection(schemas : Array[Schema], required_error? : String, invalid_type_error? : String) -> Schema

Create a schema that requires all given schemas to match (intersection / and). For objects, fields from all schemas are merged into one.

#
is_keyword

fn is_keyword(name : String) -> Bool

Check if a name is a reserved keyword in MoonBit.

#
is_optional_schema

fn is_optional_schema(s : Schema) -> Bool

#
join_parts

fn join_parts(parts : Array[String]) -> String

Join constraint parts with ", ".

#
json_infer_schema

fn json_infer_schema(json : Json) -> Schema

Generate a schema from a JSON value. Simple heuristics are used to infer types and constraints from the value.

#
literal

fn literal(value : Json, required_error? : String, invalid_type_error? : String) -> Schema

Create a schema that accepts a specific literal JSON value. The value must match exactly (String, Number, Boolean, or Null).

Example

let schema = @moon_zod.literal(Json::string("hello"))
schema.parse(Json::string("hello")) // Ok
schema.parse(Json::string("world")) // Err

#
null

fn null(required_error? : String, invalid_type_error? : String) -> Schema

Create a schema that validates JSON null.

#
number

fn number(required_error? : String, invalid_type_error? : String) -> Schema

Create a schema that validates JSON numbers.

#
object

fn object(spec : Map[String, Schema], required_error? : String, invalid_type_error? : String) -> Schema

Create a schema that validates JSON objects.

Each key in spec defines a required field and its schema. By default, extra fields in the input JSON are silently stripped (Strip mode). Use .passthrough() to allow extra fields, or .strict() to reject them.

#
parse_json

fn parse_json(input : String) -> Json

#
peel_optional

fn peel_optional(schema : Schema) -> Schema

Peel OptionalType / DefaultType wrappers to check optionality.

#
preprocess

fn preprocess(f : (Json) -> Result[Json, String], inner : Schema, required_error? : String, invalid_type_error? : String) -> Schema

Preprocess a JSON value before validating it with inner.

This is the inverse order of .transform(): f runs on raw input first, then the returned JSON value is validated against inner.

#
string

fn string(required_error? : String, invalid_type_error? : String) -> Schema

Create a schema that validates JSON strings.

#
sub_index

fn sub_index(path : String, i : Int) -> String

#
sub_path

fn sub_path(path : String, name : String) -> String

#
topological_sort_schemas

fn topological_sort_schemas(named_schemas : Array[Schema]) -> Array[Schema]

Topologically sort named schemas so dependents come before dependees.

#
tuple

fn tuple(items : Array[Schema], required_error? : String, invalid_type_error? : String) -> Schema

Create a schema that validates fixed-length JSON arrays.

Each item in items validates the array element at the same index.

#
union

fn union(schemas : Array[Schema], required_error? : String, invalid_type_error? : String) -> Schema

Create a schema that accepts any of the given schemas (union / or). Schemas are tried in order; the first match succeeds.

#
unknown

fn unknown(required_error? : String, invalid_type_error? : String) -> Schema

Create a schema that accepts any JSON value as unknown.

Runtime behavior matches any(); the distinction is semantic for consumers.

#
unwrap_schema

fn unwrap_schema(schema : Schema) -> Schema

Peel OptionalType / DefaultType / TransformType wrappers to find the innermost schema that carries the actual rules.

#
value_in_array

fn value_in_array(value : String, arr : Array[String]) -> Bool

Check if a value is in an array of strings.

#
visited_contains

fn visited_contains(visited_list : Array[(String, Int)], name : String) -> Bool

Helper: check if a name is in visited list

#
visited_get_status

fn visited_get_status(visited_list : Array[(String, Int)], name : String) -> Int

Helper: get status from visited list (0 = unvisited by default)

#
visited_set_status

fn visited_set_status(visited_list : Array[(String, Int)], name : String, status : Int) -> Unit

Helper: set status in visited list