@mastra/schema-compat
Version:
Tool schema compatibility layer for Mastra.ai
199 lines (197 loc) • 7.31 kB
JavaScript
import { z } from 'zod/v4';
import zodToJsonSchemaOriginal from 'zod-to-json-schema';
// src/zod-to-json.ts
var PATCHED = /* @__PURE__ */ Symbol("__mastra_patched__");
function patchRecordSchemas(schema) {
if (!schema || typeof schema !== "object") return schema;
if (schema[PATCHED]) return schema;
schema[PATCHED] = true;
const def = schema._zod?.def;
if (def?.type === "record" && def.keyType && !def.valueType) {
def.valueType = def.keyType;
def.keyType = z.string();
}
if (!def) return schema;
if (def.type === "object" && def.shape) {
const shape = typeof def.shape === "function" ? def.shape() : def.shape;
for (const key of Object.keys(shape)) {
patchRecordSchemas(shape[key]);
}
}
if (def.type === "array" && def.element) {
patchRecordSchemas(def.element);
}
if (def.type === "union" && def.options) {
def.options.forEach(patchRecordSchemas);
}
if (def.type === "record") {
if (def.keyType) patchRecordSchemas(def.keyType);
if (def.valueType) patchRecordSchemas(def.valueType);
}
if (def.type === "intersection") {
if (def.left) patchRecordSchemas(def.left);
if (def.right) patchRecordSchemas(def.right);
}
if (def.type === "lazy") {
if (def.getter && typeof def.getter === "function") {
const originalGetter = def.getter;
def.getter = function() {
const innerSchema = originalGetter();
if (innerSchema) {
patchRecordSchemas(innerSchema);
}
return innerSchema;
};
}
}
if (def.innerType) {
patchRecordSchemas(def.innerType);
}
return schema;
}
function fixAnyOfNullable(schema) {
if (typeof schema !== "object" || schema === null) {
return schema;
}
const result = { ...schema };
if (result.anyOf && Array.isArray(result.anyOf) && result.anyOf.length === 2) {
const nullSchema = result.anyOf.find((s) => typeof s === "object" && s !== null && s.type === "null");
const otherSchema = result.anyOf.find((s) => typeof s === "object" && s !== null && s.type !== "null");
if (nullSchema && otherSchema && typeof otherSchema === "object" && otherSchema.type) {
const { anyOf, ...rest } = result;
const fixedRest = fixAnyOfNullable(rest);
const fixedOther = fixAnyOfNullable(otherSchema);
return {
...fixedRest,
...fixedOther,
type: Array.isArray(fixedOther.type) ? [...fixedOther.type, "null"] : [fixedOther.type, "null"]
};
}
}
if (result.properties && typeof result.properties === "object" && !Array.isArray(result.properties)) {
result.properties = Object.fromEntries(
Object.entries(result.properties).map(([key, value]) => {
const propSchema = value;
if (typeof propSchema === "object" && propSchema !== null && !Array.isArray(propSchema) && Object.keys(propSchema).length === 0) {
return [key, { type: ["string", "number", "boolean", "null"] }];
}
return [key, fixAnyOfNullable(propSchema)];
})
);
}
if (result.items) {
if (Array.isArray(result.items)) {
result.items = result.items.map((item) => fixAnyOfNullable(item));
} else {
result.items = fixAnyOfNullable(result.items);
}
}
if (result.anyOf && Array.isArray(result.anyOf)) {
result.anyOf = result.anyOf.map((s) => fixAnyOfNullable(s));
}
if (result.oneOf && Array.isArray(result.oneOf)) {
result.oneOf = result.oneOf.map((s) => fixAnyOfNullable(s));
}
if (result.allOf && Array.isArray(result.allOf)) {
result.allOf = result.allOf.map((s) => fixAnyOfNullable(s));
}
return result;
}
function ensureAllPropertiesRequired(schema) {
if (typeof schema !== "object" || schema === null) {
return schema;
}
const result = { ...schema };
if (result.type === "object" && result.properties) {
result.required = Object.keys(result.properties);
result.properties = Object.fromEntries(
Object.entries(result.properties).map(([key, value]) => [key, ensureAllPropertiesRequired(value)])
);
}
if (result.items) {
if (Array.isArray(result.items)) {
result.items = result.items.map((item) => ensureAllPropertiesRequired(item));
} else if (typeof result.items === "object") {
result.items = ensureAllPropertiesRequired(result.items);
}
}
if (result.additionalProperties && typeof result.additionalProperties === "object") {
result.additionalProperties = ensureAllPropertiesRequired(result.additionalProperties);
}
if (result.anyOf && Array.isArray(result.anyOf)) {
result.anyOf = result.anyOf.map((s) => ensureAllPropertiesRequired(s));
}
if (result.oneOf && Array.isArray(result.oneOf)) {
result.oneOf = result.oneOf.map((s) => ensureAllPropertiesRequired(s));
}
if (result.allOf && Array.isArray(result.allOf)) {
result.allOf = result.allOf.map((s) => ensureAllPropertiesRequired(s));
}
return result;
}
function prepareJsonSchemaForOpenAIStrictMode(schema) {
const withRequired = ensureAllPropertiesRequired(schema);
return ensureAdditionalPropertiesFalse(withRequired);
}
function ensureAdditionalPropertiesFalse(schema) {
if (typeof schema !== "object" || schema === null) {
return schema;
}
const result = { ...schema };
if (result.type === "object" || result.properties) {
result.additionalProperties = false;
}
if (result.properties) {
result.properties = Object.fromEntries(
Object.entries(result.properties).map(([key, value]) => [
key,
ensureAdditionalPropertiesFalse(value)
])
);
}
if (result.items) {
if (Array.isArray(result.items)) {
result.items = result.items.map((item) => ensureAdditionalPropertiesFalse(item));
} else if (typeof result.items === "object") {
result.items = ensureAdditionalPropertiesFalse(result.items);
}
}
if (result.anyOf && Array.isArray(result.anyOf)) {
result.anyOf = result.anyOf.map((s) => ensureAdditionalPropertiesFalse(s));
}
if (result.oneOf && Array.isArray(result.oneOf)) {
result.oneOf = result.oneOf.map((s) => ensureAdditionalPropertiesFalse(s));
}
if (result.allOf && Array.isArray(result.allOf)) {
result.allOf = result.allOf.map((s) => ensureAdditionalPropertiesFalse(s));
}
return result;
}
function zodToJsonSchema(zodSchema, target = "jsonSchema7", strategy = "relative") {
if (zodSchema?._zod) {
patchRecordSchemas(zodSchema);
const jsonSchema = z.toJSONSchema(zodSchema, {
unrepresentable: "any",
io: "input",
override: (ctx) => {
const def = ctx.zodSchema?._def || ctx.zodSchema?._zod?.def;
if (def && (def.typeName === "ZodDate" || def.type === "date")) {
ctx.jsonSchema.type = "string";
ctx.jsonSchema.format = "date-time";
}
if (def && (def.typeName === "ZodObject" || def.type === "object")) {
ctx.jsonSchema.additionalProperties = false;
}
}
});
return fixAnyOfNullable(jsonSchema);
} else {
return zodToJsonSchemaOriginal(zodSchema, {
$refStrategy: strategy,
target
});
}
}
export { ensureAllPropertiesRequired, patchRecordSchemas, prepareJsonSchemaForOpenAIStrictMode, zodToJsonSchema };
//# sourceMappingURL=chunk-QEM5W7OR.js.map
//# sourceMappingURL=chunk-QEM5W7OR.js.map