Skip to content

toJsonSchema config, cyclic discriminated union fixes#1425

Merged
ssalbdivad merged 65 commits intomainfrom
json-2
Apr 16, 2025
Merged

toJsonSchema config, cyclic discriminated union fixes#1425
ssalbdivad merged 65 commits intomainfrom
json-2

Conversation

@ssalbdivad
Copy link
Member

@ssalbdivad ssalbdivad commented Apr 16, 2025

toJsonSchema config

Some ArkType features don't have JSON Schema equivalents. By default, toJsonSchema() will throw in these cases.

This behavior can be configured granularly to match your needs.

const T = type({
	"[symbol]": "string",
	birthday: "Date"
})

const schema = T.toJsonSchema({
	fallback: {
		// ✅ the "default" key is a fallback for any non-explicitly handled code
		// ✅ ctx includes "base" (represents the schema being generated) and other code-specific props
		// ✅ returning `ctx.base` will effectively ignore the incompatible constraint
		default: ctx => ctx.base,
		// handle specific incompatibilities granularly
		date: ctx => ({
			...ctx.base,
			type: "string",
			format: "date-time",
			description: ctx.after ? `after ${ctx.after}` : "anytime"
		})
	}
})

const result = {
	$schema: "https://json-schema.org/draft/2020-12/schema",
	type: "object",
	properties: {
		// Date instance is now a date-time string as specified by the `date` handler
		birthday: { type: "string", format: "date-time", description: "anytime" }
	},
	required: ["birthday"]
	// symbolic index signature ignored as specified by the `default` handler
}

a default handler can also be specified at the root of a fallback config:

const T = type({
	"[symbol]": "string",
	birthday: "Date"
})

//--- cut ---

const schema = T.toJsonSchema({
	// "just make it work"
	fallback: ctx => ctx.base
})

These options can also be set at a global or scope-level.

Fallback Codes

This is the full list of configurable reasons toJsonSchema() can fail.

Code Description
arrayObject arrays with object properties
arrayPostfix arrays with postfix elements
defaultValue non-serializable default value
domain non-serializable type keyword (always bigint or symbol)
morph transformation
patternIntersection multiple regex constraints
predicate custom narrow function
proto non-serializable instanceof
symbolKey symbolic key on an object
unit non-serializable === reference (e.g. undefined)
date a Date instance (supercedes proto for Dates )

cyclic types can now be converted to JSON Schema

// previously this threw
const schema = type("object.json").toJsonSchema()

// now generates the following schema
const result = {
	$ref: "#/$defs/intersection11",
	$defs: {
		intersection11: {
			type: "object",
			additionalProperties: { $ref: "#/$defs/jsonData1" }
		},
		jsonData1: {
			anyOf: [
				{ $ref: "#/$defs/intersection11" },
				{ type: "number" },
				{ type: "string" },
				{ type: "boolean" },
				{ type: "null" }
			]
		}
	}
}

temporarily disable discrimination for cyclic unions

This addresses multiple issues while we work on a permanent solution for accurately discriminating cyclic unions, tracked here.

addresses inference issues on some n-ary APIs like type.or outside the default scope (see the PR- thanks @simonwkla) 🎊

Addresses #1188 #1209 #1087 #1110 #1284 #1379 #1227

@ssalbdivad ssalbdivad moved this from To do to Implemented in arktypeio Apr 16, 2025
@ssalbdivad ssalbdivad merged commit 94da5f5 into main Apr 16, 2025
6 checks passed
@ssalbdivad ssalbdivad deleted the json-2 branch April 16, 2025 14:30
@github-project-automation github-project-automation bot moved this from Implemented to Done (merged or closed) in arktypeio Apr 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done (merged or closed)

Development

Successfully merging this pull request may close these issues.

A few toJsonSchema requests Circular scope compilation bug

1 participant