@@ -4,6 +4,7 @@ import type {
44 ZodRawShape as Zod4RawShape ,
55 ZodTypeAny as Zod4TypeAny ,
66} from "zod" ;
7+ import zodToJsonSchema from "zod-to-json-schema" ;
78import type * as z3 from "zod/v3" ;
89export type StagehandZodSchema = Zod4TypeAny | z3 . ZodTypeAny ;
910
@@ -29,118 +30,12 @@ export const isZod3Schema = (
2930
3031export type JsonSchemaDocument = Record < string , unknown > ;
3132
32- // Manual converter for zod/v3 schemas to JSON Schema
33- function ZodToJsonSchema ( schema : z3 . ZodTypeAny ) : JsonSchemaDocument {
34- const _def = ( schema as unknown as { _def ?: Record < string , unknown > } ) . _def ;
3533
36- if ( ! _def ) {
37- return { type : "null" } ;
38- }
39-
40- const typeName = _def . typeName ;
41-
42- switch ( typeName ) {
43- case "ZodObject" : {
44- const shape =
45- typeof _def . shape === "function" ? _def . shape ( ) : _def . shape ;
46- const properties : Record < string , JsonSchemaDocument > = { } ;
47- const required : string [ ] = [ ] ;
48-
49- for ( const [ key , value ] of Object . entries (
50- shape as Record < string , z3 . ZodTypeAny > ,
51- ) ) {
52- properties [ key ] = ZodToJsonSchema ( value ) ;
53- // Check if field is not optional
54- const valueDef = ( value as unknown as { _def ?: { typeName ?: string } } )
55- . _def ;
56- if ( valueDef ?. typeName !== "ZodOptional" ) {
57- required . push ( key ) ;
58- }
59- }
60-
61- return {
62- type : "object" ,
63- properties,
64- required,
65- additionalProperties : _def . unknownKeys === "passthrough" ,
66- } ;
67- }
68-
69- case "ZodArray" : {
70- const itemType = _def . type as z3 . ZodTypeAny ;
71- return {
72- type : "array" ,
73- items : ZodToJsonSchema ( itemType ) ,
74- } ;
75- }
76-
77- case "ZodString" : {
78- const result : JsonSchemaDocument = { type : "string" } ;
79- // Check for URL validation
80- const checks = _def . checks as Array < { kind ?: string } > | undefined ;
81- if ( checks ) {
82- for ( const check of checks ) {
83- if ( check . kind === "url" ) {
84- result . format = "url" ;
85- break ;
86- }
87- }
88- }
89- return result ;
90- }
91-
92- case "ZodNumber" :
93- return { type : "number" } ;
94-
95- case "ZodBoolean" :
96- return { type : "boolean" } ;
97-
98- case "ZodOptional" :
99- return ZodToJsonSchema ( _def . innerType as z3 . ZodTypeAny ) ;
100-
101- case "ZodNullable" : {
102- const innerSchema = ZodToJsonSchema ( _def . innerType as z3 . ZodTypeAny ) ;
103- return {
104- ...innerSchema ,
105- nullable : true ,
106- } ;
107- }
108-
109- case "ZodEnum" :
110- return {
111- type : "string" ,
112- enum : _def . values ,
113- } ;
114-
115- case "ZodLiteral" :
116- return {
117- type : typeof _def . value ,
118- const : _def . value ,
119- } ;
120-
121- case "ZodUnion" :
122- return {
123- anyOf : ( _def . options as z3 . ZodTypeAny [ ] ) . map ( ( opt ) =>
124- ZodToJsonSchema ( opt ) ,
125- ) ,
126- } ;
127-
128- default :
129- console . warn ( `Unknown Zod type: ${ typeName } ` ) ;
130- return { type : "null" } ;
131- }
132- }
13334
13435export function toJsonSchema ( schema : StagehandZodSchema ) : JsonSchemaDocument {
135- // For v3 schemas, use manual converter
136- // Note: We can't use zod-to-json-schema for v3 schemas when zod v4 is installed
137- // because the library imports 'zod' (v4) and tries to access ZodFirstPartyTypeKind which doesn't exist in v4
36+
13837 if ( ! isZod4Schema ( schema ) ) {
139- const result = {
140- $schema : "http://json-schema.org/draft-07/schema#" ,
141- ...ZodToJsonSchema ( schema ) ,
142- } ;
143- return result ;
38+ return zodToJsonSchema ( schema ) ;
14439 }
14540
14641 // For v4 schemas, use built-in z.toJSONSchema() method
0 commit comments