import { JsonSchema, Schema, SchemaRepresentation } from "effect" import { describe, it } from "vitest" import { assertFalse, assertTrue, deepStrictEqual, strictEqual } from "../../utils/assert.ts" const json = (annotations?: Schema.Annotations.Annotations) => { const representation = SchemaRepresentation.fromAST(Schema.Json.ast).representation return annotations === undefined ? representation : { ...representation, annotations: { ...("annotations" in representation ? representation.annotations : undefined), ...annotations } } } describe("fromJsonSchemaDocument", () => { function assertFromJsonSchema( input: { readonly schema: JsonSchema.JsonSchema readonly options?: { readonly onEnter?: ((js: JsonSchema.JsonSchema) => JsonSchema.JsonSchema) | undefined } }, expected: { readonly representation: SchemaRepresentation.Representation readonly references?: Record }, runtime?: string ) { const expectedDocument: SchemaRepresentation.Document = { representation: expected.representation, references: expected.references ?? {} } const jsonDocument = JsonSchema.fromSchemaDraft2020_12(input.schema) const document = SchemaRepresentation.fromJsonSchemaDocument(jsonDocument, input.options) deepStrictEqual(document, expectedDocument) const multiDocument = SchemaRepresentation.toMultiDocument(document) if (runtime !== undefined) { strictEqual(SchemaRepresentation.toCodeDocument(multiDocument).codes[0].runtime, runtime) } return document } it("{}", () => { assertFromJsonSchema( { schema: {} }, { representation: json() }, "Schema.Json" ) assertFromJsonSchema( { schema: { title: "a", description: "b", default: "c", examples: ["d"], readOnly: true, writeOnly: true } }, { representation: json({ title: "a", description: "b", default: "c", examples: ["d"], readOnly: true, writeOnly: true }) }, `Schema.Json.annotate({ "title": "a", "description": "b", "default": "c", "examples": ["d"], "readOnly": true, "writeOnly": true })` ) }) describe("const", () => { it("const: literal (string)", () => { assertFromJsonSchema( { schema: { const: "a" } }, { representation: { _tag: "Literal", literal: "a" } }, `Schema.Literal("a")` ) assertFromJsonSchema( { schema: { const: "a", description: "a" } }, { representation: { _tag: "Literal", literal: "a", annotations: { description: "a" } } }, `Schema.Literal("a").annotate({ "description": "a" })` ) }) it("const: literal (number)", () => { assertFromJsonSchema( { schema: { const: 1 } }, { representation: { _tag: "Literal", literal: 1 } }, `Schema.Literal(1)` ) }) it("const: literal (boolean)", () => { assertFromJsonSchema( { schema: { const: true } }, { representation: { _tag: "Literal", literal: true } }, `Schema.Literal(true)` ) }) it("const: null", () => { assertFromJsonSchema( { schema: { const: null } }, { representation: { _tag: "Null" } }, `Schema.Null` ) assertFromJsonSchema( { schema: { const: null, description: "a" } }, { representation: { _tag: "Null", annotations: { description: "a" } } }, `Schema.Null.annotate({ "description": "a" })` ) }) it("const: non-literal", () => { assertFromJsonSchema( { schema: { const: {} } }, { representation: json() }, `Schema.Json` ) }) }) describe("enum", () => { it("single enum (string)", () => { assertFromJsonSchema( { schema: { enum: ["a"] } }, { representation: { _tag: "Literal", literal: "a" } }, `Schema.Literal("a")` ) assertFromJsonSchema( { schema: { enum: ["a"], description: "a" } }, { representation: { _tag: "Literal", literal: "a", annotations: { description: "a" } } }, `Schema.Literal("a").annotate({ "description": "a" })` ) }) it("single enum (number)", () => { assertFromJsonSchema( { schema: { enum: [1] } }, { representation: { _tag: "Literal", literal: 1 } }, `Schema.Literal(1)` ) }) it("single enum (boolean)", () => { assertFromJsonSchema( { schema: { enum: [true] } }, { representation: { _tag: "Literal", literal: true } }, `Schema.Literal(true)` ) }) it("multiple enum (literals)", () => { assertFromJsonSchema( { schema: { enum: ["a", 1] } }, { representation: { _tag: "Union", types: [ { _tag: "Literal", literal: "a" }, { _tag: "Literal", literal: 1 } ], mode: "anyOf" } }, `Schema.Literals(["a", 1])` ) assertFromJsonSchema( { schema: { enum: ["a", 1], description: "a" } }, { representation: { _tag: "Union", types: [ { _tag: "Literal", literal: "a" }, { _tag: "Literal", literal: 1 } ], mode: "anyOf", annotations: { description: "a" } } }, `Schema.Literals(["a", 1]).annotate({ "description": "a" })` ) }) it("enum containing null", () => { assertFromJsonSchema( { schema: { enum: ["a", null] } }, { representation: { _tag: "Union", types: [ { _tag: "Literal", literal: "a" }, { _tag: "Null" } ], mode: "anyOf" } }, `Schema.Union([Schema.Literal("a"), Schema.Null])` ) }) }) it("anyOf", () => { assertFromJsonSchema( { schema: { anyOf: [{ const: "a" }, { enum: [1, 2] }] } }, { representation: { _tag: "Union", types: [ { _tag: "Literal", literal: "a" }, { _tag: "Union", types: [ { _tag: "Literal", literal: 1 }, { _tag: "Literal", literal: 2 } ], mode: "anyOf" } ], mode: "anyOf" } }, `Schema.Union([Schema.Literal("a"), Schema.Literals([1, 2])])` ) }) it("anyOf with siblings", () => { assertFromJsonSchema( { schema: { type: "object", properties: { id: { type: "string" } }, required: ["id"], anyOf: [ { properties: { a: { type: "string" } }, required: ["a"] }, { properties: { b: { type: "number" } }, required: ["b"] } ] } }, { representation: { _tag: "Union", types: [ { _tag: "Objects", propertySignatures: [ { name: "a", isOptional: false, isMutable: false, type: { _tag: "String", checks: [] } }, { name: "id", isOptional: false, isMutable: false, type: { _tag: "String", checks: [] } } ], indexSignatures: [{ parameter: { _tag: "String", checks: [] }, type: json() }], checks: [] }, { _tag: "Objects", propertySignatures: [ { name: "b", isOptional: false, isMutable: false, type: { _tag: "Number", checks: [{ _tag: "Filter", meta: { _tag: "isFinite" } }] } }, { name: "id", isOptional: false, isMutable: false, type: { _tag: "String", checks: [] } } ], indexSignatures: [{ parameter: { _tag: "String", checks: [] }, type: json() }], checks: [] } ], mode: "anyOf" } } ) }) it("oneOf", () => { assertFromJsonSchema( { schema: { oneOf: [{ const: "a" }, { enum: [1, 2] }] } }, { representation: { _tag: "Union", types: [ { _tag: "Literal", literal: "a" }, { _tag: "Union", types: [ { _tag: "Literal", literal: 1 }, { _tag: "Literal", literal: 2 } ], mode: "anyOf" } ], mode: "oneOf" } }, `Schema.Union([Schema.Literal("a"), Schema.Literals([1, 2])], { mode: "oneOf" })` ) }) it("oneOf with siblings", () => { assertFromJsonSchema( { schema: { type: "object", properties: { id: { type: "string" } }, required: ["id"], oneOf: [ { properties: { a: { type: "string" } }, required: ["a"] }, { properties: { b: { type: "number" } }, required: ["b"] } ] } }, { representation: { _tag: "Union", types: [ { _tag: "Objects", propertySignatures: [ { name: "a", isOptional: false, isMutable: false, type: { _tag: "String", checks: [] } }, { name: "id", isOptional: false, isMutable: false, type: { _tag: "String", checks: [] } } ], indexSignatures: [{ parameter: { _tag: "String", checks: [] }, type: json() }], checks: [] }, { _tag: "Objects", propertySignatures: [ { name: "b", isOptional: false, isMutable: false, type: { _tag: "Number", checks: [{ _tag: "Filter", meta: { _tag: "isFinite" } }] } }, { name: "id", isOptional: false, isMutable: false, type: { _tag: "String", checks: [] } } ], indexSignatures: [{ parameter: { _tag: "String", checks: [] }, type: json() }], checks: [] } ], mode: "oneOf" } } ) }) describe("type: null", () => { it("type only", () => { assertFromJsonSchema( { schema: { type: "null" } }, { representation: { _tag: "Null" } }, `Schema.Null` ) }) }) describe("type: string", () => { it("type only", () => { assertFromJsonSchema( { schema: { type: "string" } }, { representation: { _tag: "String", checks: [] } }, `Schema.String` ) }) describe("checks", () => { it("minLength", () => { assertFromJsonSchema( { schema: { type: "string", minLength: 1 } }, { representation: { _tag: "String", checks: [{ _tag: "Filter", meta: { _tag: "isMinLength", minLength: 1 } }] } }, `Schema.String.check(Schema.isMinLength(1))` ) }) it("maxLength", () => { assertFromJsonSchema( { schema: { type: "string", maxLength: 1 } }, { representation: { _tag: "String", checks: [{ _tag: "Filter", meta: { _tag: "isMaxLength", maxLength: 1 } }] } }, `Schema.String.check(Schema.isMaxLength(1))` ) }) it("pattern", () => { assertFromJsonSchema( { schema: { type: "string", pattern: "a*" } }, { representation: { _tag: "String", checks: [ { _tag: "Filter", meta: { _tag: "isPattern", regExp: new RegExp("a*") } } ] } }, `Schema.String.check(Schema.isPattern(new RegExp("a*")))` ) assertFromJsonSchema( { schema: { pattern: "a*" } }, { representation: { _tag: "String", checks: [ { _tag: "Filter", meta: { _tag: "isPattern", regExp: new RegExp("a*") } } ] } }, `Schema.String.check(Schema.isPattern(new RegExp("a*")))` ) }) }) }) describe("type: number", () => { it("type only", () => { assertFromJsonSchema( { schema: { type: "number" } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isFinite" } } ] } }, `Schema.Number.check(Schema.isFinite())` ) }) describe("checks", () => { it("minimum", () => { assertFromJsonSchema( { schema: { type: "number", minimum: 1 } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isFinite" } }, { _tag: "Filter", meta: { _tag: "isGreaterThanOrEqualTo", minimum: 1 } } ] } }, `Schema.Number.check(Schema.isFinite()).check(Schema.isGreaterThanOrEqualTo(1))` ) }) it("maximum", () => { assertFromJsonSchema( { schema: { type: "number", maximum: 1 } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isFinite" } }, { _tag: "Filter", meta: { _tag: "isLessThanOrEqualTo", maximum: 1 } } ] } }, `Schema.Number.check(Schema.isFinite()).check(Schema.isLessThanOrEqualTo(1))` ) }) it("exclusiveMinimum", () => { assertFromJsonSchema( { schema: { type: "number", exclusiveMinimum: 1 } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isFinite" } }, { _tag: "Filter", meta: { _tag: "isGreaterThan", exclusiveMinimum: 1 } } ] } }, `Schema.Number.check(Schema.isFinite()).check(Schema.isGreaterThan(1))` ) }) it("exclusiveMaximum", () => { assertFromJsonSchema( { schema: { type: "number", exclusiveMaximum: 1 } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isFinite" } }, { _tag: "Filter", meta: { _tag: "isLessThan", exclusiveMaximum: 1 } } ] } }, `Schema.Number.check(Schema.isFinite()).check(Schema.isLessThan(1))` ) }) it("multipleOf", () => { assertFromJsonSchema( { schema: { type: "number", multipleOf: 1 } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isFinite" } }, { _tag: "Filter", meta: { _tag: "isMultipleOf", divisor: 1 } } ] } }, `Schema.Number.check(Schema.isFinite()).check(Schema.isMultipleOf(1))` ) }) }) }) describe("type: integer", () => { it("type only", () => { assertFromJsonSchema( { schema: { type: "integer" } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isInt" } } ] } }, `Schema.Number.check(Schema.isInt())` ) }) describe("checks", () => { it("minimum", () => { assertFromJsonSchema( { schema: { type: "integer", minimum: 1 } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isInt" } }, { _tag: "Filter", meta: { _tag: "isGreaterThanOrEqualTo", minimum: 1 } } ] } }, `Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(1))` ) }) it("maximum", () => { assertFromJsonSchema( { schema: { type: "integer", maximum: 1 } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isInt" } }, { _tag: "Filter", meta: { _tag: "isLessThanOrEqualTo", maximum: 1 } } ] } }, `Schema.Number.check(Schema.isInt()).check(Schema.isLessThanOrEqualTo(1))` ) }) it("exclusiveMinimum", () => { assertFromJsonSchema( { schema: { type: "integer", exclusiveMinimum: 1 } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isInt" } }, { _tag: "Filter", meta: { _tag: "isGreaterThan", exclusiveMinimum: 1 } } ] } }, `Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(1))` ) }) it("exclusiveMaximum", () => { assertFromJsonSchema( { schema: { type: "integer", exclusiveMaximum: 1 } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isInt" } }, { _tag: "Filter", meta: { _tag: "isLessThan", exclusiveMaximum: 1 } } ] } }, `Schema.Number.check(Schema.isInt()).check(Schema.isLessThan(1))` ) }) it("multipleOf", () => { assertFromJsonSchema( { schema: { type: "integer", multipleOf: 1 } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isInt" } }, { _tag: "Filter", meta: { _tag: "isMultipleOf", divisor: 1 } } ] } }, `Schema.Number.check(Schema.isInt()).check(Schema.isMultipleOf(1))` ) }) }) }) describe("type: boolean", () => { it("type only", () => { assertFromJsonSchema( { schema: { type: "boolean" } }, { representation: { _tag: "Boolean" } }, `Schema.Boolean` ) }) }) describe("type: array", () => { it("type only", () => { assertFromJsonSchema( { schema: { type: "array" } }, { representation: { _tag: "Arrays", elements: [], rest: [json()], checks: [] } }, `Schema.Array(Schema.Json)` ) }) it("items", () => { assertFromJsonSchema( { schema: { type: "array", items: { type: "string" } } }, { representation: { _tag: "Arrays", elements: [], rest: [{ _tag: "String", checks: [] }], checks: [] } }, `Schema.Array(Schema.String)` ) }) it("prefixItems", () => { assertFromJsonSchema( { schema: { type: "array", prefixItems: [{ type: "string" }], maxItems: 1 } }, { representation: { _tag: "Arrays", elements: [ { isOptional: true, type: { _tag: "String", checks: [] } } ], rest: [], checks: [] } }, `Schema.Tuple([Schema.optionalKey(Schema.String)])` ) assertFromJsonSchema( { schema: { type: "array", prefixItems: [{ type: "string" }], minItems: 1, maxItems: 1 } }, { representation: { _tag: "Arrays", elements: [ { isOptional: false, type: { _tag: "String", checks: [] } } ], rest: [], checks: [] } }, `Schema.Tuple([Schema.String])` ) }) it("prefixItems & minItems", () => { assertFromJsonSchema( { schema: { type: "array", prefixItems: [{ type: "string" }], minItems: 1, items: { type: "number" } } }, { representation: { _tag: "Arrays", elements: [ { isOptional: false, type: { _tag: "String", checks: [] } } ], rest: [ { _tag: "Number", checks: [{ _tag: "Filter", meta: { _tag: "isFinite" } }] } ], checks: [] } }, `Schema.TupleWithRest(Schema.Tuple([Schema.String]), [Schema.Number.check(Schema.isFinite())])` ) }) describe("checks", () => { it("minItems", () => { assertFromJsonSchema( { schema: { type: "array", minItems: 1 } }, { representation: { _tag: "Arrays", elements: [], rest: [json()], checks: [{ _tag: "Filter", meta: { _tag: "isMinLength", minLength: 1 } }] } }, `Schema.Array(Schema.Json).check(Schema.isMinLength(1))` ) }) it("maxItems", () => { assertFromJsonSchema( { schema: { type: "array", maxItems: 1 } }, { representation: { _tag: "Arrays", elements: [], rest: [json()], checks: [{ _tag: "Filter", meta: { _tag: "isMaxLength", maxLength: 1 } }] } }, `Schema.Array(Schema.Json).check(Schema.isMaxLength(1))` ) }) it("uniqueItems", () => { assertFromJsonSchema( { schema: { type: "array", uniqueItems: true } }, { representation: { _tag: "Arrays", elements: [], rest: [json()], checks: [{ _tag: "Filter", meta: { _tag: "isUnique" } }] } }, `Schema.Array(Schema.Json).check(Schema.isUnique())` ) }) }) }) describe("type: object", () => { it("type only", () => { assertFromJsonSchema( { schema: { type: "object" } }, { representation: { _tag: "Objects", propertySignatures: [], indexSignatures: [ { parameter: { _tag: "String", checks: [] }, type: json() } ], checks: [] } }, `Schema.Record(Schema.String, Schema.Json)` ) assertFromJsonSchema( { schema: { type: "object", additionalProperties: false } }, { representation: { _tag: "Objects", propertySignatures: [], indexSignatures: [], checks: [] } }, `Schema.Struct({ })` ) }) it("additionalProperties", () => { assertFromJsonSchema( { schema: { type: "object", additionalProperties: { type: "boolean" } } }, { representation: { _tag: "Objects", propertySignatures: [], indexSignatures: [ { parameter: { _tag: "String", checks: [] }, type: { _tag: "Boolean" } } ], checks: [] } }, `Schema.Record(Schema.String, Schema.Boolean)` ) }) it("properties", () => { assertFromJsonSchema( { schema: { type: "object", properties: { a: { type: "string" }, b: { type: "string" } }, required: ["a"], additionalProperties: false } }, { representation: { _tag: "Objects", propertySignatures: [ { name: "a", type: { _tag: "String", checks: [] }, isOptional: false, isMutable: false }, { name: "b", type: { _tag: "String", checks: [] }, isOptional: true, isMutable: false } ], indexSignatures: [], checks: [] } }, `Schema.Struct({ "a": Schema.String, "b": Schema.optionalKey(Schema.String) })` ) }) it("properties & additionalProperties", () => { assertFromJsonSchema( { schema: { type: "object", properties: { a: { type: "string" } }, required: ["a"], additionalProperties: { type: "boolean" } } }, { representation: { _tag: "Objects", propertySignatures: [{ name: "a", type: { _tag: "String", checks: [] }, isOptional: false, isMutable: false }], indexSignatures: [ { parameter: { _tag: "String", checks: [] }, type: { _tag: "Boolean" } } ], checks: [] } }, `Schema.StructWithRest(Schema.Struct({ "a": Schema.String }), [Schema.Record(Schema.String, Schema.Boolean)])` ) }) it("patternProperties", () => { assertFromJsonSchema( { schema: { type: "object", patternProperties: { "a*": { type: "string" } }, additionalProperties: false } }, { representation: { _tag: "Objects", propertySignatures: [], indexSignatures: [ { parameter: { _tag: "String", checks: [{ _tag: "Filter", meta: { _tag: "isPattern", regExp: new RegExp("a*") } }] }, type: { _tag: "String", checks: [] } } ], checks: [] } }, `Schema.Record(Schema.String.check(Schema.isPattern(new RegExp("a*"))), Schema.String)` ) assertFromJsonSchema( { schema: { type: "object", patternProperties: { "a*": { type: "string" }, "b*": { type: "number" } }, additionalProperties: false } }, { representation: { _tag: "Objects", propertySignatures: [], indexSignatures: [ { parameter: { _tag: "String", checks: [{ _tag: "Filter", meta: { _tag: "isPattern", regExp: new RegExp("a*") } }] }, type: { _tag: "String", checks: [] } }, { parameter: { _tag: "String", checks: [{ _tag: "Filter", meta: { _tag: "isPattern", regExp: new RegExp("b*") } }] }, type: { _tag: "Number", checks: [{ _tag: "Filter", meta: { _tag: "isFinite" } }] } } ], checks: [] } }, `Schema.StructWithRest(Schema.Struct({ }), [Schema.Record(Schema.String.check(Schema.isPattern(new RegExp("a*"))), Schema.String), Schema.Record(Schema.String.check(Schema.isPattern(new RegExp("b*"))), Schema.Number.check(Schema.isFinite()))])` ) }) describe("checks", () => { it("minProperties", () => { assertFromJsonSchema( { schema: { type: "object", minProperties: 1 } }, { representation: { _tag: "Objects", propertySignatures: [], indexSignatures: [ { parameter: { _tag: "String", checks: [] }, type: json() } ], checks: [{ _tag: "Filter", meta: { _tag: "isMinProperties", minProperties: 1 } }] } }, `Schema.Record(Schema.String, Schema.Json).check(Schema.isMinProperties(1))` ) }) it("maxProperties", () => { assertFromJsonSchema( { schema: { type: "object", maxProperties: 1 } }, { representation: { _tag: "Objects", propertySignatures: [], indexSignatures: [ { parameter: { _tag: "String", checks: [] }, type: json() } ], checks: [{ _tag: "Filter", meta: { _tag: "isMaxProperties", maxProperties: 1 } }] } }, `Schema.Record(Schema.String, Schema.Json).check(Schema.isMaxProperties(1))` ) }) }) describe("propertyNames", () => { it("pattern", () => { assertFromJsonSchema( { schema: { type: "object", propertyNames: { pattern: "^[A-Z]" } } }, { representation: { _tag: "Objects", propertySignatures: [], indexSignatures: [ { parameter: { _tag: "String", checks: [] }, type: json() } ], checks: [{ _tag: "Filter", meta: { _tag: "isPropertyNames", propertyNames: { _tag: "String", checks: [{ _tag: "Filter", meta: { _tag: "isPattern", regExp: new RegExp("^[A-Z]") } }] } } }] } }, `Schema.Record(Schema.String, Schema.Json).check(Schema.isPropertyNames(Schema.String.check(Schema.isPattern(new RegExp("^[A-Z]")))))` ) }) it("false", () => { assertFromJsonSchema( { schema: { type: "object", propertyNames: false } }, { representation: { _tag: "Objects", propertySignatures: [], indexSignatures: [ { parameter: { _tag: "String", checks: [] }, type: json() } ], checks: [ { _tag: "Filter", meta: { _tag: "isPropertyNames", propertyNames: { _tag: "Never" } } } ] } }, `Schema.Record(Schema.String, Schema.Json).check(Schema.isPropertyNames(Schema.Never))` ) }) it("allOf combines checks", () => { assertFromJsonSchema( { schema: { allOf: [ { type: "object", propertyNames: { pattern: "^[A-Z]" } }, { type: "object", propertyNames: { minLength: 2 } } ] } }, { representation: { _tag: "Objects", propertySignatures: [], indexSignatures: [ { parameter: { _tag: "String", checks: [] }, type: json() } ], checks: [ { _tag: "Filter", meta: { _tag: "isPropertyNames", propertyNames: { _tag: "String", checks: [{ _tag: "Filter", meta: { _tag: "isPattern", regExp: new RegExp("^[A-Z]") } }] } } }, { _tag: "Filter", meta: { _tag: "isPropertyNames", propertyNames: { _tag: "String", checks: [{ _tag: "Filter", meta: { _tag: "isMinLength", minLength: 2 } }] } } } ] } }, `Schema.Record(Schema.String, Schema.Json).check(Schema.isPropertyNames(Schema.String.check(Schema.isPattern(new RegExp("^[A-Z]"))))).check(Schema.isPropertyNames(Schema.String.check(Schema.isMinLength(2))))` ) }) }) }) it("type: array of strings", () => { assertFromJsonSchema( { schema: { type: ["string", "null"] } }, { representation: { _tag: "Union", types: [{ _tag: "String", checks: [] }, { _tag: "Null" }], mode: "anyOf" } }, `Schema.Union([Schema.String, Schema.Null])` ) assertFromJsonSchema( { schema: { type: ["string", "null"], description: "a" } }, { representation: { _tag: "Union", types: [{ _tag: "String", checks: [] }, { _tag: "Null" }], mode: "anyOf", annotations: { description: "a" } } }, `Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "a" })` ) }) describe("$ref", () => { it("should create a Reference and a definition", () => { assertFromJsonSchema( { schema: { $ref: "#/$defs/A", $defs: { A: { type: "string" } } } }, { representation: { _tag: "Reference", $ref: "A" }, references: { A: { _tag: "String", checks: [] } } } ) }) it("should resolve the $ref if there are annotations", () => { assertFromJsonSchema( { schema: { $ref: "#/$defs/A", description: "a", $defs: { A: { type: "string" } } } }, { representation: { _tag: "String", checks: [], annotations: { description: "a" } }, references: { A: { _tag: "String", checks: [] } } } ) }) it("should resolve the $ref if there is an allOf", () => { assertFromJsonSchema( { schema: { allOf: [ { $ref: "#/$defs/A" }, { description: "a" } ], $defs: { A: { type: "string" } } } }, { representation: { _tag: "String", checks: [], annotations: { description: "a" } }, references: { A: { _tag: "String", checks: [] } } } ) }) it("recursive schema", () => { assertFromJsonSchema( { schema: { $ref: "#/$defs/A", $defs: { A: { "type": "object", "properties": { "name": { "type": "string" }, "children": { "type": "array", "items": { "$ref": "#/$defs/A" } } }, "required": [ "name", "children" ], "additionalProperties": false } } } }, { representation: { _tag: "Reference", $ref: "A" }, references: { A: { _tag: "Objects", propertySignatures: [ { name: "name", type: { _tag: "String", checks: [] }, isOptional: false, isMutable: false }, { name: "children", type: { _tag: "Arrays", elements: [], rest: [{ _tag: "Suspend", checks: [], thunk: { _tag: "Reference", $ref: "A" } }], checks: [] }, isOptional: false, isMutable: false } ], indexSignatures: [], checks: [] } } } ) }) }) describe("allOf", () => { it("resolves references on either side of an intersection", () => { const definition: JsonSchema.JsonSchema = { type: "string", minLength: 1 } const expected = { representation: { _tag: "String" as const, checks: [ { _tag: "Filter" as const, meta: { _tag: "isMinLength" as const, minLength: 1 } }, { _tag: "Filter" as const, meta: { _tag: "isMaxLength" as const, maxLength: 2 } } ] }, references: { A: { _tag: "String" as const, checks: [{ _tag: "Filter" as const, meta: { _tag: "isMinLength" as const, minLength: 1 } }] } } } for ( const schema of [ { $ref: "#/$defs/A", allOf: [{ type: "string", maxLength: 2 }], $defs: { A: definition } }, { allOf: [{ $ref: "#/$defs/A" }, { type: "string", maxLength: 2 }], $defs: { A: definition } } ] ) { assertFromJsonSchema({ schema }, expected) } }) it("preserves annotations on array and object intersections", () => { assertFromJsonSchema( { schema: { type: "array", allOf: [{ description: "a" }] } }, { representation: { _tag: "Arrays", elements: [], rest: [json()], checks: [], annotations: { description: "a" } } }, `Schema.Array(Schema.Json).annotate({ "description": "a" })` ) assertFromJsonSchema( { schema: { type: "object", additionalProperties: false, allOf: [{ description: "a" }] } }, { representation: { _tag: "Objects", propertySignatures: [], indexSignatures: [], checks: [], annotations: { description: "a" } } }, `Schema.Struct({ }).annotate({ "description": "a" })` ) }) it("returns Never when a union has no compatible member", () => { assertFromJsonSchema( { schema: { type: "string", allOf: [{ anyOf: [{ type: "number" }, { type: "boolean" }] }] } }, { representation: { _tag: "Never" } }, `Schema.Never` ) }) function assertLiteralRefinement( refinement: JsonSchema.JsonSchema, valid: string | number, invalid: string | number ) { for (const literal of [valid, invalid]) { for (const allOf of [[refinement, { const: literal }], [{ const: literal }, refinement]]) { const document = SchemaRepresentation.fromJsonSchemaDocument( JsonSchema.fromSchemaDraft2020_12({ allOf }) ) const is = Schema.is(SchemaRepresentation.toSchema(document)) if (literal === valid) { assertTrue(is(literal)) } else { assertFalse(is(literal)) } } } } describe("literal refinements", () => { const cases: ReadonlyArray< readonly [ name: string, refinement: JsonSchema.JsonSchema, valid: string | number, invalid: string | number ] > = [ ["minLength", { type: "string", minLength: 2 }, "ab", "a"], ["maxLength", { type: "string", maxLength: 1 }, "a", "ab"], ["pattern", { type: "string", pattern: "^a+$" }, "aa", "ab"], ["integer", { type: "integer" }, 1, 1.5], ["multipleOf", { type: "number", multipleOf: 0.1 }, 0.3, 0.31], [ "multipleOf beyond the toFixed precision limit", { type: "number", multipleOf: Number("1e-101") }, 0, Number("5e-102") ], ["multipleOf with a large scientific operand", { type: "number", multipleOf: 2 }, Number("1e21"), 1], [ "multipleOf with a nonzero subnormal remainder", { type: "number", multipleOf: Number("1e-323") }, 0, Number("1.042e-321") ], ["minimum", { type: "number", minimum: 1 }, 1, 0], ["maximum", { type: "number", maximum: 1 }, 1, 2], ["exclusiveMinimum", { type: "number", exclusiveMinimum: 1 }, 2, 1], ["exclusiveMaximum", { type: "number", exclusiveMaximum: 1 }, 0, 1], [ "filter group", { type: "number", allOf: [{ minimum: 1, maximum: 2, description: "range" }] }, 2, 0 ] ] for (const [name, refinement, valid, invalid] of cases) { it(name, () => { assertLiteralRefinement(refinement, valid, invalid) }) } it("filters enum members", () => { const expected = { representation: { _tag: "Union" as const, types: [{ _tag: "Literal" as const, literal: "ab" }], mode: "anyOf" as const } } for ( const [schema, member] of [ [{ type: "string", minLength: 2 }, { enum: ["a", "ab"] }], [{ enum: ["a", "ab"] }, { type: "string", minLength: 2 }] ] ) { assertFromJsonSchema( { schema: { ...schema, allOf: [member] } }, expected, `Schema.Literal("ab")` ) } }) }) it("no type", () => { assertFromJsonSchema( { schema: { allOf: [ { type: "string" } ] } }, { representation: { _tag: "String", checks: [] } }, `Schema.String` ) }) describe("type: string", () => { it("& minLength", () => { assertFromJsonSchema( { schema: { type: "string", allOf: [ { minLength: 1 } ] } }, { representation: { _tag: "String", checks: [ { _tag: "Filter", meta: { _tag: "isMinLength", minLength: 1 } } ] } }, `Schema.String.check(Schema.isMinLength(1))` ) }) it("& minLength + description", () => { assertFromJsonSchema( { schema: { type: "string", allOf: [ { minLength: 1, description: "b" } ] } }, { representation: { _tag: "String", checks: [ { _tag: "Filter", meta: { _tag: "isMinLength", minLength: 1 }, annotations: { description: "b" } } ] } }, `Schema.String.check(Schema.isMinLength(1, { "description": "b" }))` ) }) it("description & minLength", () => { assertFromJsonSchema( { schema: { type: "string", description: "a", allOf: [ { minLength: 1 } ] } }, { representation: { _tag: "String", checks: [ { _tag: "Filter", meta: { _tag: "isMinLength", minLength: 1 } } ], annotations: { description: "a" } } }, `Schema.String.annotate({ "description": "a" }).check(Schema.isMinLength(1))` ) }) it("description & description", () => { assertFromJsonSchema( { schema: { type: "string", description: "a", allOf: [ { description: "b" } ] } }, { representation: { _tag: "String", checks: [], annotations: { description: "b" } } }, `Schema.String.annotate({ "description": "b" })` ) }) it("description & minLength + description", () => { assertFromJsonSchema( { schema: { type: "string", description: "a", allOf: [ { minLength: 1, description: "b" } ] } }, { representation: { _tag: "String", checks: [ { _tag: "Filter", meta: { _tag: "isMinLength", minLength: 1 }, annotations: { description: "b" } } ], annotations: { description: "a" } } }, `Schema.String.annotate({ "description": "a" }).check(Schema.isMinLength(1, { "description": "b" }))` ) }) it("maxLength & minLength", () => { assertFromJsonSchema( { schema: { type: "string", maxLength: 2, allOf: [ { minLength: 1 } ] } }, { representation: { _tag: "String", checks: [ { _tag: "Filter", meta: { _tag: "isMaxLength", maxLength: 2 } }, { _tag: "Filter", meta: { _tag: "isMinLength", minLength: 1 } } ] } }, `Schema.String.check(Schema.isMaxLength(2)).check(Schema.isMinLength(1))` ) }) it("description + maxLength & minLength", () => { assertFromJsonSchema( { schema: { type: "string", description: "a", maxLength: 2, allOf: [ { minLength: 1 } ] } }, { representation: { _tag: "String", checks: [ { _tag: "Filter", meta: { _tag: "isMaxLength", maxLength: 2 } }, { _tag: "Filter", meta: { _tag: "isMinLength", minLength: 1 } } ], annotations: { description: "a" } } }, `Schema.String.annotate({ "description": "a" }).check(Schema.isMaxLength(2)).check(Schema.isMinLength(1))` ) }) it("description + maxLength & minLength + description", () => { assertFromJsonSchema( { schema: { type: "string", description: "a", maxLength: 2, allOf: [ { minLength: 1, description: "b" } ] } }, { representation: { _tag: "String", checks: [ { _tag: "Filter", meta: { _tag: "isMaxLength", maxLength: 2 } }, { _tag: "Filter", meta: { _tag: "isMinLength", minLength: 1 }, annotations: { description: "b" } } ], annotations: { description: "a" } } }, `Schema.String.annotate({ "description": "a" }).check(Schema.isMaxLength(2)).check(Schema.isMinLength(1, { "description": "b" }))` ) }) it("& minLength + maxLength", () => { assertFromJsonSchema( { schema: { type: "string", allOf: [ { minLength: 1, maxLength: 2 } ] } }, { representation: { _tag: "String", checks: [ { _tag: "Filter", meta: { _tag: "isMinLength", minLength: 1 } }, { _tag: "Filter", meta: { _tag: "isMaxLength", maxLength: 2 } } ] } }, `Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(2))` ) }) it("& minLength + maxLength + description", () => { assertFromJsonSchema( { schema: { type: "string", allOf: [ { minLength: 1, maxLength: 2, description: "b" } ] } }, { representation: { _tag: "String", checks: [ { _tag: "FilterGroup", checks: [ { _tag: "Filter", meta: { _tag: "isMinLength", minLength: 1 } }, { _tag: "Filter", meta: { _tag: "isMaxLength", maxLength: 2 } } ], annotations: { description: "b" } } ] } }, `Schema.String.check(Schema.makeFilterGroup([Schema.isMinLength(1), Schema.isMaxLength(2)], { "description": "b" }))` ) }) it("& (minLength & maxLength + description)", () => { assertFromJsonSchema( { schema: { type: "string", allOf: [ { minLength: 1, allOf: [{ maxLength: 2, description: "c" }] } ] } }, { representation: { _tag: "String", checks: [ { _tag: "Filter", meta: { _tag: "isMinLength", minLength: 1 } }, { _tag: "Filter", meta: { _tag: "isMaxLength", maxLength: 2 }, annotations: { description: "c" } } ] } }, `Schema.String.check(Schema.isMinLength(1)).check(Schema.isMaxLength(2, { "description": "c" }))` ) }) it("& (minLength + description & maxLength + description)", () => { assertFromJsonSchema( { schema: { type: "string", allOf: [ { minLength: 1, description: "b", allOf: [{ maxLength: 2, description: "c" }] } ] } }, { representation: { _tag: "String", checks: [ { _tag: "FilterGroup", checks: [ { _tag: "Filter", meta: { _tag: "isMinLength", minLength: 1 } }, { _tag: "Filter", meta: { _tag: "isMaxLength", maxLength: 2 }, annotations: { description: "c" } } ], annotations: { description: "b" } } ] } }, `Schema.String.check(Schema.makeFilterGroup([Schema.isMinLength(1), Schema.isMaxLength(2, { "description": "c" })], { "description": "b" }))` ) }) it("& string enum", () => { assertFromJsonSchema( { schema: { type: "string", allOf: [ { enum: ["a"] } ] } }, { representation: { _tag: "Literal", literal: "a" } }, `Schema.Literal("a")` ) assertFromJsonSchema( { schema: { type: "string", description: "a", allOf: [ { enum: ["a"], description: "b" } ] } }, { representation: { _tag: "Literal", literal: "a", annotations: { description: "b" } } }, `Schema.Literal("a").annotate({ "description": "b" })` ) assertFromJsonSchema( { schema: { type: "string", allOf: [ { enum: ["a", "b"] } ] } }, { representation: { _tag: "Union", types: [ { _tag: "Literal", literal: "a" }, { _tag: "Literal", literal: "b" } ], mode: "anyOf" } }, `Schema.Literals(["a", "b"])` ) }) it("& mixed enum", () => { assertFromJsonSchema( { schema: { type: "string", allOf: [ { enum: ["a", 1] } ] } }, { representation: { _tag: "Union", types: [ { _tag: "Literal", literal: "a" } ], mode: "anyOf" } }, `Schema.Literal("a")` ) }) }) describe("type: number", () => { it("number & integer", () => { assertFromJsonSchema( { schema: { type: "number", allOf: [ { type: "integer" } ] } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isFinite" } }, { _tag: "Filter", meta: { _tag: "isInt" } } ] } }, `Schema.Number.check(Schema.isFinite()).check(Schema.isInt())` ) }) it("number & integer & integer", () => { assertFromJsonSchema( { schema: { type: "number", allOf: [ { type: "integer", minimum: 2 }, { type: "integer", maximum: 2 } ] } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isFinite" } }, { _tag: "Filter", meta: { _tag: "isInt" } }, { _tag: "Filter", meta: { _tag: "isGreaterThanOrEqualTo", minimum: 2 } }, { _tag: "Filter", meta: { _tag: "isLessThanOrEqualTo", maximum: 2 } } ] } }, `Schema.Number.check(Schema.isFinite()).check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(2)).check(Schema.isLessThanOrEqualTo(2))` ) }) it("integer & number", () => { assertFromJsonSchema( { schema: { type: "integer", allOf: [ { type: "number" } ] } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isInt" } }, { _tag: "Filter", meta: { _tag: "isFinite" } } ] } }, `Schema.Number.check(Schema.isInt()).check(Schema.isFinite())` ) }) it("& (minimum + description & maximum + description)", () => { assertFromJsonSchema( { schema: { type: "number", allOf: [ { minimum: 1, description: "b", allOf: [{ maximum: 2, description: "c" }] } ] } }, { representation: { _tag: "Number", checks: [ { _tag: "Filter", meta: { _tag: "isFinite" } }, { _tag: "FilterGroup", checks: [ { _tag: "Filter", meta: { _tag: "isGreaterThanOrEqualTo", minimum: 1 } }, { _tag: "Filter", meta: { _tag: "isLessThanOrEqualTo", maximum: 2 }, annotations: { description: "c" } } ], annotations: { description: "b" } } ] } }, `Schema.Number.check(Schema.isFinite()).check(Schema.makeFilterGroup([Schema.isGreaterThanOrEqualTo(1), Schema.isLessThanOrEqualTo(2, { "description": "c" })], { "description": "b" }))` ) }) it("& number enum", () => { assertFromJsonSchema( { schema: { type: "number", allOf: [ { enum: [1] } ] } }, { representation: { _tag: "Literal", literal: 1 } }, `Schema.Literal(1)` ) assertFromJsonSchema( { schema: { type: "number", description: "a", allOf: [ { enum: [1], description: "b" } ] } }, { representation: { _tag: "Literal", literal: 1, annotations: { description: "b" } } }, `Schema.Literal(1).annotate({ "description": "b" })` ) assertFromJsonSchema( { schema: { type: "number", allOf: [ { enum: [1, 2] } ] } }, { representation: { _tag: "Union", types: [ { _tag: "Literal", literal: 1 }, { _tag: "Literal", literal: 2 } ], mode: "anyOf" } }, `Schema.Literals([1, 2])` ) }) }) describe("type: boolean", () => { it("& boolean enum", () => { assertFromJsonSchema( { schema: { type: "boolean", allOf: [ { enum: [true] } ] } }, { representation: { _tag: "Literal", literal: true } }, `Schema.Literal(true)` ) assertFromJsonSchema( { schema: { type: "boolean", description: "a", allOf: [ { enum: [true], description: "b" } ] } }, { representation: { _tag: "Literal", literal: true, annotations: { description: "b" } } }, `Schema.Literal(true).annotate({ "description": "b" })` ) }) }) describe("type: array", () => { function assertArrayAllOf( a: JsonSchema.JsonSchema, b: JsonSchema.JsonSchema, expected: Parameters[1], runtime: string, valid: ReadonlyArray, invalid: ReadonlyArray ) { for (const [schema, member] of [[a, b], [b, a]]) { const document = assertFromJsonSchema( { schema: { ...schema, allOf: [member] } }, expected, runtime ) const is = Schema.is(SchemaRepresentation.toSchema(document)) for (const value of valid) { assertTrue(is(value)) } for (const value of invalid) { assertFalse(is(value)) } } } it("uniqueItems & uniqueItems", () => { assertFromJsonSchema( { schema: { type: "array", uniqueItems: true, allOf: [ { uniqueItems: true } ] } }, { representation: { _tag: "Arrays", elements: [], rest: [json()], checks: [{ _tag: "Filter", meta: { _tag: "isUnique" } }] } }, `Schema.Array(Schema.Json).check(Schema.isUnique())` ) }) it("combines unequal open prefixes", () => { assertArrayAllOf( { type: "array", prefixItems: [{ type: "string" }], minItems: 1, items: { type: "string" } }, { type: "array", prefixItems: [{ type: "string" }, { const: "tail" }], minItems: 2, items: { type: "string" } }, { representation: { _tag: "Arrays", elements: [ { isOptional: false, type: { _tag: "String", checks: [] } }, { isOptional: false, type: { _tag: "Literal", literal: "tail" } } ], rest: [{ _tag: "String", checks: [] }], checks: [] } }, `Schema.TupleWithRest(Schema.Tuple([Schema.String, Schema.Literal("tail")]), [Schema.String])`, [["head", "tail"], ["head", "tail", "more"]], [["head"], ["head", "other"], ["head", "tail", 1]] ) }) it("truncates optional elements forbidden by a closed tuple", () => { assertArrayAllOf( { type: "array", prefixItems: [{ type: "string" }], minItems: 1, maxItems: 1 }, { type: "array", prefixItems: [{ type: "string" }, { type: "number" }], minItems: 1, maxItems: 2 }, { representation: { _tag: "Arrays", elements: [{ isOptional: false, type: { _tag: "String", checks: [] } }], rest: [], checks: [] } }, `Schema.Tuple([Schema.String])`, [["head"]], [[], ["head", 1]] ) }) it("returns Never when a closed tuple forbids a required element", () => { assertArrayAllOf( { type: "array", prefixItems: [{ type: "string" }], minItems: 1, maxItems: 1 }, { type: "array", prefixItems: [{ type: "string" }, { type: "number" }], minItems: 2, maxItems: 2 }, { representation: { _tag: "Never" } }, `Schema.Never`, [], [[], ["head"], ["head", 1]] ) }) it("combines an open rest with a closed rest", () => { assertArrayAllOf( { type: "array", prefixItems: [{ type: "string" }], minItems: 1, items: { type: "number" } }, { type: "array", prefixItems: [{ type: "string" }], minItems: 1, maxItems: 1 }, { representation: { _tag: "Arrays", elements: [{ isOptional: false, type: { _tag: "String", checks: [] } }], rest: [], checks: [] } }, `Schema.Tuple([Schema.String])`, [["head"]], [[], ["head", 1]] ) }) it("closes the tuple when the rest intersection is Never", () => { assertArrayAllOf( { type: "array", prefixItems: [{ type: "string" }], minItems: 1, items: { type: "string" } }, { type: "array", prefixItems: [{ type: "string" }], minItems: 1, items: { type: "number" } }, { representation: { _tag: "Arrays", elements: [{ isOptional: false, type: { _tag: "String", checks: [] } }], rest: [], checks: [] } }, `Schema.Tuple([Schema.String])`, [["head"]], [[], ["head", "tail"], ["head", 1]] ) }) it("rejects a required literal that fails rest refinements", () => { assertArrayAllOf( { type: "array", minItems: 1, items: { const: 0 } }, { type: "array", prefixItems: [{ type: "number", minimum: 1 }], minItems: 1, maxItems: 1 }, { representation: { _tag: "Never" } }, `Schema.Never`, [], [[], [0]] ) }) it("truncates an optional literal that fails rest refinements", () => { assertArrayAllOf( { type: "array", items: { const: 0 } }, { type: "array", prefixItems: [{ type: "number", minimum: 1 }], maxItems: 1 }, { representation: { _tag: "Arrays", elements: [], rest: [], checks: [] } }, `Schema.Tuple([])`, [[]], [[0]] ) }) it("preserves a literal that satisfies rest refinements", () => { assertArrayAllOf( { type: "array", minItems: 1, items: { const: 2 } }, { type: "array", prefixItems: [{ type: "number", minimum: 1 }], minItems: 1, maxItems: 1 }, { representation: { _tag: "Arrays", elements: [{ isOptional: false, type: { _tag: "Literal", literal: 2 } }], rest: [], checks: [{ _tag: "Filter", meta: { _tag: "isMinLength", minLength: 1 } }] } }, `Schema.Tuple([Schema.Literal(2)]).check(Schema.isMinLength(1))`, [[2]], [[], [0]] ) }) }) describe("type: object", () => { it("add properties", () => { assertFromJsonSchema( { schema: { type: "object", additionalProperties: false, allOf: [ { properties: { a: { type: "string" } } } ] } }, { representation: { _tag: "Objects", propertySignatures: [ { name: "a", type: { _tag: "String", checks: [] }, isOptional: true, isMutable: false } ], indexSignatures: [], checks: [] } }, `Schema.Struct({ "a": Schema.optionalKey(Schema.String) })` ) }) it("add additionalProperties", () => { assertFromJsonSchema( { schema: { type: "object", allOf: [ { additionalProperties: { type: "boolean" } } ] } }, { representation: { _tag: "Objects", propertySignatures: [], indexSignatures: [ { parameter: { _tag: "String", checks: [] }, type: { _tag: "Boolean" } } ], checks: [] } }, `Schema.Record(Schema.String, Schema.Boolean)` ) }) }) }) describe("options", () => { describe("onEnter", () => { it("additionalProperties false via onEnter", () => { assertFromJsonSchema( { schema: { type: "object", properties: { a: { type: "string" } }, required: ["a"] }, options: { onEnter: (js) => { if (js.type === "object" && js.additionalProperties === undefined) { return { ...js, additionalProperties: false } } return js } } }, { representation: { _tag: "Objects", propertySignatures: [ { name: "a", type: { _tag: "String", checks: [] }, isOptional: false, isMutable: false } ], indexSignatures: [], checks: [] } }, `Schema.Struct({ "a": Schema.String })` ) }) it("strips annotation keys via onEnter", () => { assertFromJsonSchema( { schema: { title: "a", description: "b", examples: ["d"] }, options: { onEnter: (js) => { const out = { ...js } delete out.examples return out } } }, { representation: json({ title: "a", description: "b" }) }, `Schema.Json.annotate({ "title": "a", "description": "b" })` ) }) it("filters annotations by predicate via onEnter", () => { assertFromJsonSchema( { schema: { title: "a", description: "b", examples: ["d"], default: "c" }, options: { onEnter: (js) => { const out: any = {} for (const [k, v] of Object.entries(js)) { if (k === "title" || k === "default" || k === "type") out[k] = v } return out } } }, { representation: json({ title: "a", default: "c" }) }, `Schema.Json.annotate({ "title": "a", "default": "c" })` ) }) it("default preserves all annotations", () => { assertFromJsonSchema( { schema: { title: "a", description: "b", default: "c", examples: ["d"] } }, { representation: json({ title: "a", description: "b", default: "c", examples: ["d"] }) }, `Schema.Json.annotate({ "title": "a", "description": "b", "default": "c", "examples": ["d"] })` ) }) }) }) })