JSON Schema builders (alpha)
Offline schema-to-fixture generation, with independent Ajv validation, reproducible sessions, and the same immutable builder pipeline as the native adapters.
import { jsonSchemaAdapter, fromJsonSchema } from '@mimlet/json-schema';
const schema = {
type: 'object',
properties: {
id: { type: 'integer', minimum: 1 },
name: { type: 'string', minLength: 1 },
},
required: ['id', 'name'],
additionalProperties: false,
};
const provider = jsonSchemaAdapter(schema, { profile: 'random' });
const session = provider.session(42);
const users = fromJsonSchema(schema, { profile: 'random' });
const values = users.buildValidatedList(3, session);Runtime-loaded JSON does not prove a TypeScript application type: raw builders return unknown. fromStandardJsonSchema(schema) accepts an implementation of both Standard Schema v1 and Standard JSON Schema v1, generates its input representation, and retains the native input/output types. Native validation is called once for each validated fixture, after overrides and transformations. Opaque refinements can reject a fixture; they are not silently retried or repaired.
Supported generation path
The pinned provider is json-schema-faker@0.6.3, independently checked by ajv@8.20.0 plus ajv-formats@3.0.1. Draft-07, 2019-09, and 2020-12 use separate Ajv instances. Draft-07 tuples, dependencies, definitions, and reference-sibling semantics are normalized only in the provider copy; validation retains draft-07 semantics, including ignored reference siblings.
Standard type constraints, compositions, conditionals, explicit references, and collection/string/number constraints are accepted. Every returned candidate must pass the original validator. This is bounded sampling, not a complete solver; valid schemas can exhaust the sampling budget. Dynamic/recursive references, anchors, unknown vocabularies, extension keywords, and other unsupported keywords fail preparation explicitly rather than being silently dropped. The provider-unsafe __proto__ schema-map key is also rejected explicitly; the schema-free core does not have that provider restriction. Content metadata is treated as annotations, not an encoding or content-validation guarantee.
Profiles include boundary (valid candidates biased toward declared endpoints), minimal (required shape, not a proof of globally minimal values), random (optional-field variation), defaults, and examples. Defaults/examples are candidate preferences, never validation guarantees; an invalid candidate can fall back to ordinary sampling. Overrides are applied only after base generation and never participate in automatic retry/repair.
Use jsonSchemaAdapter to prepare and compile once. create(session) supplies fixtures; standard exposes the JSON validation contract; check and issues inspect candidates. identity includes schema/reference/configuration identities and exact provider versions. With no session, each call starts from seed 1. Caller-supplied sessions advance deterministically and preserve named isolation. The entire schema has one stream; field-stability across schema changes is not claimed. Snapshots contain generation state, not user callback implementations.
References and trust boundary
references is an explicit URI-to-schema dictionary. No remote resolver, network request, filesystem reader, or schema-derived executable configuration is installed. JSON data is copied before compilation and checked for cycles, accessors, symbols, non-JSON values, depth, size, and allocation limits. Supplied schemas are snapshots; mutating the original does not change an already prepared adapter.
Format extensions require paired pure synchronous validate and generate callbacks, plus an explicit formatsIdentity so callers can version replay inputs. They remain trusted executable code and may run repeatedly during generation. There is no promise to interrupt arbitrary callbacks or pathological regexes in this synchronous API. Use process isolation for hostile schema execution.
Limits bound preparation, attempts, native provider depth, output arrays/strings, and final output size. They do not constitute an OS sandbox or an exact memory bound inside a third-party provider. Exhaustion is not a proof of unsatisfiability. No schema rules are widened to make a candidate pass. Public declarations do not require DOM types even though the private provider's declarations reference them.
Individual package manifests are prepared for the coordinated alpha release; publication is a separate operation.
Custom providers and negative cases
provider: { id, generate(request) } accepts a versioned synchronous generation backend. It receives copied schema/reference data, the selected dialect/profile, a scoped session, and the attempt index. Every candidate still passes the original validator. Paired custom assertions use keywords and a versioned extensionIdentity; explicit annotations cannot replace built-in assertions.
adapter.negative(session, mutation, target) creates a valid base, invokes the mutation once, and reports the observed validation issues. Optional keyword, instancePath, and requireSingleIssue targets are checked rather than assumed. An accepted mutation is an error, not a negative fixture. Both positive and negative paths retain JSON/output budgets and reject asynchronous callbacks.
The reconciliation retains the existing input-conversion metadata rules and original-schema validation tests. Boundary hints narrow only a candidate copy; failed candidates may fall back to ordinary bounded sampling, so the boundary profile is not an exhaustive boundary-coverage certificate.