MCPcopy
hub / github.com/colinhacks/zod / convertSchema

Function convertSchema

packages/zod/src/v4/classic/from-json-schema.ts:533–625  ·  view source on GitHub ↗
(schema: JSONSchema.JSONSchema | boolean, ctx: ConversionContext)

Source from the content-addressed store, hash-verified

531}
532
533function convertSchema(schema: JSONSchema.JSONSchema | boolean, ctx: ConversionContext): ZodType {
534 if (typeof schema === "boolean") {
535 return schema ? z.any() : z.never();
536 }
537
538 // Convert base schema first (ignoring composition keywords)
539 let baseSchema = convertBaseSchema(schema, ctx);
540 const hasExplicitType = schema.type || schema.enum !== undefined || schema.const !== undefined;
541
542 // Process composition keywords LAST (they can appear together)
543 // Handle anyOf - wrap base schema with union
544 if (schema.anyOf && Array.isArray(schema.anyOf)) {
545 const options = schema.anyOf.map((s) => convertSchema(s, ctx));
546 const anyOfUnion = z.union(options as [ZodType, ZodType, ...ZodType[]]);
547 baseSchema = hasExplicitType ? z.intersection(baseSchema, anyOfUnion) : anyOfUnion;
548 }
549
550 // Handle oneOf - exclusive union (exactly one must match)
551 if (schema.oneOf && Array.isArray(schema.oneOf)) {
552 const options = schema.oneOf.map((s) => convertSchema(s, ctx));
553 const oneOfUnion = z.xor(options as [ZodType, ZodType, ...ZodType[]]);
554 baseSchema = hasExplicitType ? z.intersection(baseSchema, oneOfUnion) : oneOfUnion;
555 }
556
557 // Handle allOf - wrap base schema with intersection
558 if (schema.allOf && Array.isArray(schema.allOf)) {
559 if (schema.allOf.length === 0) {
560 baseSchema = hasExplicitType ? baseSchema : z.any();
561 } else {
562 let result = hasExplicitType ? baseSchema : convertSchema(schema.allOf[0]!, ctx);
563 const startIdx = hasExplicitType ? 0 : 1;
564 for (let i = startIdx; i < schema.allOf.length; i++) {
565 result = z.intersection(result, convertSchema(schema.allOf[i]!, ctx));
566 }
567 baseSchema = result;
568 }
569 }
570
571 // Handle nullable (OpenAPI 3.0)
572 if (schema.nullable === true && ctx.version === "openapi-3.0") {
573 baseSchema = z.nullable(baseSchema);
574 }
575
576 // Handle readOnly
577 if (schema.readOnly === true) {
578 baseSchema = z.readonly(baseSchema);
579 }
580
581 // Apply `default` so it wraps the fully-composed schema. This ensures
582 // `parse(undefined) -> default` works regardless of which branch of
583 // `convertBaseSchema` produced the inner schema (enum/const/not/typed/etc.).
584 if (schema.default !== undefined) {
585 baseSchema = baseSchema.default(schema.default);
586 }
587
588 // Collect non-description annotation metadata into the user-supplied
589 // registry. Description is handled separately below via `.describe()` to
590 // preserve the contract that `schema.description` reads from globalRegistry.

Callers 2

convertBaseSchemaFunction · 0.85
fromJSONSchemaFunction · 0.85

Calls 7

convertBaseSchemaFunction · 0.85
nullableMethod · 0.80
readonlyMethod · 0.80
defaultMethod · 0.80
hasMethod · 0.80
addMethod · 0.80
describeMethod · 0.80

Tested by

no test coverage detected