11import * as z from "zod" ;
22
3- const SchemaUnparsed = z . unknown ( ) . brand ( "SchemaUnparsed" ) ;
3+ const SchemaUnparsed = z
4+ . record ( z . string ( ) , z . unknown ( ) )
5+ . brand ( "SchemaUnparsed" ) ;
6+ type Unparsed = z . infer < typeof SchemaUnparsed > ;
47
58const Primitive = z . union ( [ z . string ( ) , z . number ( ) , z . boolean ( ) ] ) ;
69
@@ -11,6 +14,9 @@ const BaseSchema = z.object({
1114 // `default` can only be on `string`, `number` and `boolean`
1215 default : Primitive . nullish ( ) ,
1316
17+ // `example` can be on any schema
18+ example : z . unknown ( ) ,
19+
1420 // `description` and `deprecated` can be on any schema
1521 description : z . string ( ) . optional ( ) ,
1622 deprecated : z . boolean ( ) . optional ( ) ,
@@ -191,7 +197,10 @@ const SchemaSchemaOneOf = BaseSchema.extend({ oneOf: z.array(SchemaUnparsed) })
191197
192198const SchemaSchemaAllOf = BaseSchema . extend ( {
193199 type : z . literal ( "object" ) . optional ( ) ,
194- allOf : z . tuple ( [ SchemaUnparsed , SchemaUnparsed ] ) ,
200+ allOf : z . union ( [
201+ z . tuple ( [ SchemaUnparsed ] ) ,
202+ z . tuple ( [ SchemaUnparsed , SchemaUnparsed ] ) ,
203+ ] ) ,
195204} )
196205 . strict ( )
197206 . transform ( ( s ) => ( { ...s , __schema : "allOf" as const } ) ) ;
@@ -225,6 +234,10 @@ const SchemaSchema = z.union([
225234
226235type Schema = z . infer < typeof SchemaSchema > ;
227236
237+ function parseUnparsed ( schema : Unparsed ) {
238+ return SchemaSchema . parse ( schema satisfies Unparsed ) ;
239+ }
240+
228241type ConvertResult = { readonly zodSchema : string ; readonly refs : string [ ] } ;
229242
230243function convertToZod ( schema : Schema , prefix : string = "" ) : ConvertResult {
@@ -245,7 +258,7 @@ function convertToZod(schema: Schema, prefix: string = ""): ConvertResult {
245258 }
246259 case "oneOf" : {
247260 const subResults = schema . oneOf . map ( ( item ) =>
248- convertToZod ( SchemaSchema . parse ( item ) , prefix ) ,
261+ convertToZod ( parseUnparsed ( item ) , prefix ) ,
249262 ) ;
250263 const zodSchemas = subResults . map ( ( r ) => r . zodSchema ) ;
251264 const allRefs = new Set < string > ( ) ;
@@ -256,14 +269,14 @@ function convertToZod(schema: Schema, prefix: string = ""): ConvertResult {
256269 } as const ;
257270 }
258271 case "allOf" : {
259- const leftPart = convertToZod (
260- SchemaSchema . parse ( schema . allOf [ 0 ] ) ,
261- prefix ,
262- ) ;
263- const rightPart = convertToZod (
264- SchemaSchema . parse ( schema . allOf [ 1 ] ) ,
265- prefix ,
266- ) ;
272+ const leftPart = convertToZod ( parseUnparsed ( schema . allOf [ 0 ] ) , prefix ) ;
273+ if ( ! schema . allOf [ 1 ] ) {
274+ return {
275+ zodSchema : leftPart . zodSchema ,
276+ refs : leftPart . refs ,
277+ } as const ;
278+ }
279+ const rightPart = convertToZod ( parseUnparsed ( schema . allOf [ 1 ] ) , prefix ) ;
267280 const allRefs = new Set ( [ ...leftPart . refs , ...rightPart . refs ] ) ;
268281 return {
269282 zodSchema : `z.intersection(${ leftPart . zodSchema } , ${ rightPart . zodSchema } )` ,
@@ -356,7 +369,7 @@ function convertToZod(schema: Schema, prefix: string = ""): ConvertResult {
356369 }
357370 case "additionalProperties" : {
358371 const { zodSchema : valueSchemaStr , refs } = convertToZod (
359- SchemaSchema . parse ( schema . additionalProperties ) ,
372+ parseUnparsed ( schema . additionalProperties ) ,
360373 prefix ,
361374 ) ;
362375 return {
@@ -371,7 +384,7 @@ function convertToZod(schema: Schema, prefix: string = ""): ConvertResult {
371384 const allRefs = new Set < string > ( ) ;
372385 for ( const [ k , v ] of Object . entries ( props ) ) {
373386 const { zodSchema : sch , refs : propRefs } = convertToZod (
374- SchemaSchema . parse ( v ) ,
387+ parseUnparsed ( v ) ,
375388 prefix ,
376389 ) ;
377390 propRefs . forEach ( ( r ) => allRefs . add ( r ) ) ;
@@ -399,7 +412,7 @@ function convertToZod(schema: Schema, prefix: string = ""): ConvertResult {
399412 return { zodSchema : "z.array(z.unknown())" , refs : [ ] } as const ;
400413 }
401414 const { zodSchema : itemSchema , refs : itemRefs } = convertToZod (
402- SchemaSchema . parse ( items ) ,
415+ parseUnparsed ( items ) ,
403416 prefix ,
404417 ) ;
405418 let zodSchemaStr : string ;
@@ -438,7 +451,9 @@ function convertToZod(schema: Schema, prefix: string = ""): ConvertResult {
438451 }
439452 } catch ( e ) {
440453 if ( e instanceof z . ZodError ) {
441- console . error ( `Error while converting ${ schema . __schema } ` ) ;
454+ console . error ( `Error while converting '${ schema . __schema } '` ) ;
455+ console . error ( schema ) ;
456+ console . error ( JSON . stringify ( schema , null , 2 ) ) ;
442457 console . error ( z . prettifyError ( e ) ) ;
443458 }
444459 throw e ;
0 commit comments