Skip to content
中文

Schema snapshots and synchronous validation rules ​

The policy implementation follows.

ts
export function defineSchema<Value>(definition: SchemaAdapter<Value>): SchemaAdapter<Value> {
  return snapshotSchemaAdapter(definition);
}

export function fromParserSchema<Schema extends { parse(value: unknown): unknown }>(
  schema: Schema,
  options: { toJsonSchema(schema: Schema): JsonSchema },
): SchemaAdapter<ReturnType<Schema['parse']>> {
  return snapshotSchemaAdapter({
    jsonSchema: synchronous(options.toJsonSchema(schema), 'Schema conversion must be synchronous'),
    parse: schema.parse.bind(schema) as (value: unknown) => ReturnType<Schema['parse']>,
  });
}

export function fromJsonSchema<Value = unknown>(
  schema: JsonSchema,
  options: JsonSchemaOptions<Value>,
): SchemaAdapter<Value> {
  const jsonSchema = structuredClone(schema);
  freezeSchema(jsonSchema);
  const validate = synchronous(options.compile(jsonSchema), 'Schema compilers must be synchronous');
  if (typeof validate !== 'function')
    throw new TypeError('Schema compilers must return a validator');
  const error = options.error?.bind(options);
  return snapshotSchemaAdapter({
    jsonSchema,
    parse(value: unknown): Value {
      const valid = booleanResult(
        validate(value),
        'Schema validators must be synchronous',
        'Schema validators must return boolean',
      );
      if (!valid)
        throw (
          synchronous(
            error?.(value, validate.errors),
            'Schema error factories must be synchronous',
          ) ?? new TypeError('Input does not match JSON Schema')
        );
      return value as Value;
    },
  });
}

API reference, usage examples and developer guides.