/** * JsonSchema contains a set of combinators to build a subset * of [JSON Schema](https://json-schema.org/) in typescript. * It also includes an instance of Schemable that is useful * for describing a Schema to an external system. * * @module JSON Schema * @since 2.0.0 */ import "./_dnt.polyfills.js"; import type { Kind, Out } from "./kind.js"; import type { Literal, Schemable } from "./schemable.js"; import type { Flatmappable } from "./flatmappable.js"; import type { NonEmptyArray } from "./array.js"; import type { ReadonlyRecord } from "./record.js"; import type { State } from "./state.js"; /** * Represents an unknown JSON Schema * * @since 2.0.0 */ export type JsonSchemaUnknown = ReadonlyRecord; /** * Represents boolean in JSON Schema * * @since 2.0.0 */ export type JsonSchemaBoolean = { readonly type: "boolean"; }; /** * Represents null in JSON Schema * * @since 2.0.0 */ export type JsonSchemaNull = { readonly type: "null"; }; /** * Represents null in JSON Schema * * @since 2.0.0 */ export type JsonSchemaEnum = { readonly enum: NonEmptyArray; }; /** * Represents an intersection of Schemas in JSON Schema * * @since 2.0.0 */ export type JsonSchemaAllOf = { readonly allOf: NonEmptyArray; }; /** * Represents a union of Schemas in JSON Schema * * @since 2.0.0 */ export type JsonSchemaAnyOf = { readonly anyOf: NonEmptyArray; }; /** * Represents an exclusive union of Schemas in JSON Schema * * @since 2.0.0 */ export type JsonSchemaOneOf = { readonly oneOf: NonEmptyArray; }; /** * Represents a reference to another Schema in JSON Schema, generally * useful for recursion or brevity. * * @since 2.0.0 */ export type JsonSchemaRef = { readonly $ref: string; }; /** * Represents string in JSON Schema * * @since 2.0.0 */ export type JsonSchemaString = { readonly type: "string"; readonly enum?: NonEmptyArray; readonly minLength?: number; readonly maxLength?: number; }; /** * Represents number(float or integer) in JSON Schema * * @since 2.0.0 */ export type JsonSchemaNumber = { readonly type: "integer"; readonly enum?: NonEmptyArray; } | { readonly type: "number"; readonly enum?: NonEmptyArray; }; /** * Represents string Date in JSON Schema * * @since 2.0.0 */ export type JsonSchemaDate = { readonly type: "string"; readonly format: "date"; }; /** * Represents a struct in JSON Schema * * @since 2.0.0 */ export type JsonSchemaObject = { readonly type: "object"; readonly properties: Record; readonly required?: NonEmptyArray; readonly additionalProperties?: false | JsonSchema; }; /** * Represents an array or tuple in JSON Schema * * @since 2.0.0 */ export type JsonSchemaArray = { readonly type: "array"; readonly items: JsonSchema | NonEmptyArray; readonly additionalItems?: JsonSchema; }; /** * Represents a collection of Schemas that can be * referenced by a $ref in JSON Schema * * @since 2.0.0 */ export type JsonSchemaDefinitions = ReadonlyRecord; /** * Represents a recursive JSON Schema * * @since 2.0.0 */ export type JsonSchema = { definitions?: JsonSchemaDefinitions; } & (JsonSchemaUnknown | JsonSchemaString | JsonSchemaNumber | JsonSchemaDate | JsonSchemaObject | JsonSchemaArray | JsonSchemaBoolean | JsonSchemaNull | JsonSchemaEnum | JsonSchemaAllOf | JsonSchemaAnyOf | JsonSchemaOneOf | JsonSchemaRef); /** * JsonBuilder is a wrapper over State, used to construct a JsonSchema * combinator by combinator. In this way it can also be used as * a Schemable to create a JsonSchema that matches a Decoder. * * Currently, the JsonSchema only supports a subset of the full * JSON Schema. There are no refinements or formats aside from * the basic types and Date. * * @since 2.0.0 */ export type JsonBuilder<_> = State; /** * Given a JsonBuilder this type will unwrap T for use in * type level programming. * * @since 2.0.0 */ export type TypeOf = T extends JsonBuilder ? A : never; /** * The Kind substitution scheme for JsonBuilder. * * @since 2.0.0 */ export interface KindJsonBuilder extends Kind { readonly kind: JsonBuilder>; } /** * @since 2.0.0 */ export declare const FlatmappableJsonBuilder: Flatmappable; /** * @since 2.0.0 */ export declare const sequenceArray: []>(...ua: VS) => JsonBuilder<{ [K in keyof VS]: VS[K] extends JsonBuilder ? A : never; }>; /** * @since 2.0.0 */ export declare const sequenceRecord: >>>(values: import("./record.js").NonEmptyRecord) => JsonBuilder<{ [K in keyof VS]: VS[K] extends JsonBuilder ? A : never; }>; /** * @since 2.0.0 */ export declare const wrap: (a: A) => JsonBuilder; /** * @since 2.0.0 */ export declare const apply: (ta: JsonBuilder) => (tfai: JsonBuilder<(value: A) => I>) => JsonBuilder; /** * @since 2.0.0 */ export declare const map: (fai: (value: A) => I) => (ta: JsonBuilder) => JsonBuilder; /** * @since 2.0.0 */ export declare const flatmap: (fati: (a: A) => JsonBuilder) => (ta: JsonBuilder) => JsonBuilder; /** * Creates a JsonBuilder of an unknown type * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * const schema = J.print(J.unknown()); // schema === {} * ``` * * @since 2.0.0 */ export declare function unknown(): JsonBuilder; /** * Creates a JsonBuilder of an string type * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // schema === { type: "string" } * const schema = J.print(J.string()); * ``` * * @since 2.0.0 */ export declare function string(): JsonBuilder; /** * Creates a JsonBuilder of an number type * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // schema === { type: "number" } * const schema = J.print(J.number()); * ``` * * @since 2.0.0 */ export declare function number(): JsonBuilder; /** * Creates a JsonBuilder of an boolean type * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // schema === { type: "boolean" } * const schema = J.print(J.boolean()); * ``` * * @since 2.0.0 */ export declare function boolean(): JsonBuilder; /** * Creates a JsonBuilder of an date type * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // schema === { type: "string", format: "date" } * const schema = J.print(J.date()); * ``` * * @since 2.0.0 */ export declare function date(): JsonBuilder; /** * Creates a JsonBuilder over a tuple of literals * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // schema === { enum: [1, 2, "hello"] } * const schema = J.print(J.literal(1, 2, "hello")); * ``` * * @since 2.0.0 */ export declare function literal>(...literals: A): JsonBuilder; /** * Creates a JsonBuilder that makes the given builder * nullable * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // schema === { anyOf: [ { enum: [ 1 ] }, { type: "null" } ] } * const schema = J.print(J.nullable(J.literal(1))); * ``` * * @since 2.0.0 */ export declare function nullable(or: JsonBuilder): JsonBuilder; /** * Creates a JsonBuilder that makes the given builder * undefinable * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // schema === { anyOf: [ { enum: [ 1 ] }, {} ] } * const schema = J.print(J.undefinable(J.literal(1))); * ``` * * @since 2.0.0 */ export declare function undefinable(or: JsonBuilder): JsonBuilder; /** * Creates a JsonBuilder of a Record with string keys and values * that match the supplied JsonBuilder * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // schema === { type: "object", properties: {}, additionalProperties: { type: "number" } } * const schema = J.print(J.record(J.number())); * ``` * * @since 2.0.0 */ export declare function record(codomain: JsonBuilder): JsonBuilder>; /** * Creates a JsonBuilder of an Array with values * that match the supplied JsonBuilder * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // schema === { type: "array", items: { type: "number" } } * const schema = J.print(J.array(J.number())); * ``` * * @since 2.0.0 */ export declare function array(item: JsonBuilder): JsonBuilder>; /** * Creates a JsonBuilder of a tuple with values * that match the supplied JsonBuilders * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // schema === { type: "array", items: [ * // { type: "number" }, * // { type: "string" } * // ] } * const schema = J.print(J.tuple(J.number(), J.string())); * ``` * * @since 2.0.0 */ export declare function tuple(...items: { [K in keyof A]: JsonBuilder; }): JsonBuilder<{ [K in keyof A]: A[K]; }>; /** * Creates a JsonBuilder of a struct with values * and keys that match the supplied JsonBuilders * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // { * // type: "object", * // properties: { num: { type: "number" }, str: { type: "string" } }, * // required: [ "num", "str" ] * // } * const schema = J.print(J.struct({ * num: J.number(), * str: J.string() * })); * ``` * * @since 2.0.0 */ export declare function struct(items: { [K in keyof A]: JsonBuilder; }): JsonBuilder<{ readonly [K in keyof A]: A[K]; }>; /** * Creates a JsonBuilder of a partial with values * and keys that match the supplied JsonBuilders * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // { * // type: "object", * // properties: { num: { type: "number" }, str: { type: "string" } }, * // } * const schema = J.print(J.partial({ * num: J.number(), * str: J.string() * })); * ``` * * @since 2.0.0 */ export declare function partial(items: { readonly [K in keyof A]: JsonBuilder; }): JsonBuilder<{ [K in keyof A]?: A[K]; }>; /** * Creates a JsonBuilder that intersects two JsonBuilders * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // { * // "allOf": [ * // { * // "type": "object", * // "properties": { * // "num": { * // "type": "number" * // } * // }, * // "required": [ * // "num" * // ] * // }, * // { * // "type": "object", * // "properties": { * // "str": { * // "type": "string" * // } * // } * // } * // ] * // } * * const schema = pipe( * J.struct({ num: J.number() }), * J.intersect(J.partial({ str: J.string() })), * J.print, * ); * ``` * * @since 2.0.0 */ export declare function intersect(and: JsonBuilder): (ta: JsonBuilder) => JsonBuilder; /** * Creates a JsonBuilder that unions two JsonBuilders * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // { * // "anyOf": [ * // { * // "type": "object", * // "properties": { * // "num": { * // "type": "number" * // } * // }, * // "required": [ * // "num" * // ] * // }, * // { * // "type": "object", * // "properties": { * // "str": { * // "type": "string" * // } * // } * // } * // ] * // } * * const schema = pipe( * J.struct({ num: J.number() }), * J.union(J.partial({ str: J.string() })), * J.print, * ); * ``` * * @since 2.0.0 */ export declare function union(or: JsonBuilder): (ta: JsonBuilder) => JsonBuilder; /** * Creates a lazy JsonBuilder, which is useful for creating * recursive JSON Schemas, mutual or otherwise. A limitation * of typescript means that the type must be defined outside * of the JsonBuilder and manually annotated * * @example * ```ts * import * as J from "./json_schema.ts"; * import { pipe } from "./fn.ts"; * * // { * // "$ref": "#/definitions/Person", * // "definitions": { * // "Person": { * // "type": "object", * // "properties": { * // "age": { * // "type": "number" * // }, * // "children": { * // "type": "array", * // "items": { * // "$ref": "#/definitions/Person" * // } * // }, * // "name": { * // "type": "string" * // } * // }, * // "required": [ * // "age", * // "children", * // "name" * // ] * // } * // } * // } * * type Person = { * readonly name: string; * readonly age: number; * readonly children: ReadonlyArray; * }; * * const Person: J.JsonBuilder = J.lazy("Person", () => * J.struct({ * name: J.string(), * age: J.number(), * children: J.array(Person), * })); * * const schema = J.print(Person); * ``` * * @since 2.0.0 */ export declare function lazy(id: string, fn: () => JsonBuilder): JsonBuilder; /** * Collapse a JsonBuilder into a JsonSchema that can be logged * or used as output for a webserver or a file. * * @example * ```ts * import * as J from "./json_schema.ts"; * * console.log(J.print(J.string())); // Logs { type: "string" } * ``` * * @since 2.0.0 */ export declare function print(jsonschema: JsonBuilder): JsonSchema; /** * An instance of Schemable for use with a Schema. * * @example * ```ts * import * as J from "./json_schema.ts"; * import * as S from "./schemable.ts"; * * // Let's start with a recursive type structure * type Tree = { * readonly tag: 'Tree'; * readonly value: A; * readonly forest: ReadonlyArray>; * } * * // Next we can create a generic Schema (non-JSON) for Tree * const TreeSchema: S.Schema> = S.schema(s => * s.lazy("Tree", () => s.struct({ * tag: s.literal("Tree"), * value: s.string(), * forest: s.array(TreeSchema(s)), * })) * ); * * // Then we can derive a JsonBuilder from the generic Schema * const TreeJsonBuilder = TreeSchema(J.SchemableJsonBuilder); * * // Lastly, we can pull an actual JSON Schema from the JsonBuilder * const TreeJsonSchema = J.print(TreeJsonBuilder); * * // { * // "$ref": "#/definitions/Tree", * // "definitions": { * // "Tree": { * // "type": "object", * // "properties": { * // "forest": { * // "type": "array", * // "items": { * // "$ref": "#/definitions/Tree" * // } * // }, * // "tag": { * // "enum": [ * // "Tree" * // ] * // }, * // "value": { * // "type": "string" * // } * // }, * // "required": [ * // "forest", * // "tag", * // "value" * // ] * // } * // } * // } * ``` * * @since 2.0.0 */ export declare const SchemableJsonBuilder: Schemable;