json2zod
Version:
A CLI tool and library to convert JSON to Zod schemas with optional OpenAPI examples.
115 lines • 4.92 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateZodSchema = generateZodSchema;
/**
* Recursively infers the appropriate Zod type for a given JavaScript value.
* Conditionally includes an OpenAPI example based on the `addOpenApiExamples` setting.
*
* @param value The JavaScript value to infer the Zod type for.
* @param addOpenApiExamples A boolean indicating whether to add `.openapi({ example: ... })` calls.
* @returns A string representing the Zod type definition, potentially with an OpenAPI example.
*/
function inferZodType(value, addOpenApiExamples) {
const exampleValueString = JSON.stringify(value); // Stringify for use in example
let baseZodType;
switch (typeof value) {
case 'string':
baseZodType = 'z.string()';
break;
case 'number':
baseZodType = 'z.number()';
break;
case 'boolean':
baseZodType = 'z.boolean()';
break;
case 'object':
if (value === null) {
// Handle explicit null values
baseZodType = 'z.null()';
}
else if (Array.isArray(value)) {
// Handle arrays recursively
if (value.length > 0) {
// If array is not empty, infer the type of its first element
const innerType = inferZodType(value[0], addOpenApiExamples);
baseZodType = `z.array(${innerType})`;
}
else {
// If array is empty, default to array of any
baseZodType = `z.array(z.any())`;
}
}
else {
// Handle nested objects recursively
baseZodType = generateObjectSchemaString(value, addOpenApiExamples);
}
break;
default:
// Fallback for other types like 'undefined', 'symbol', 'bigint', 'function'
baseZodType = `z.any()`;
}
// Conditionally append the .openapi({ example: ... }) call
if (addOpenApiExamples) {
return `${baseZodType}.openapi({ example: ${exampleValueString} })`;
}
else {
return baseZodType;
}
}
/**
* Generates a Zod object schema string for a given JavaScript object.
* This function is called recursively for nested objects.
*
* @param obj The JavaScript object to generate the schema for.
* @param addOpenApiExamples A boolean indicating whether to add `.openapi({ example: ... })` calls.
* @returns A string representing the Zod object schema.
*/
function generateObjectSchemaString(obj, addOpenApiExamples) {
const schemaParts = [];
// Iterate over the properties of the object to build its schema
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
const value = obj[key];
// Recursively infer the Zod type for each property
schemaParts.push(` ${key}: ${inferZodType(value, addOpenApiExamples)}`);
}
}
return `z.object({\n${schemaParts.join(',\n')}\n})`;
}
/**
* Generates the complete Zod schema string from the initial input JSON data.
* This handles both single objects and arrays of objects at the top level.
*
* @param inputJson The parsed JSON object or array of objects to base the schema on.
* @param options Configuration options.
* @param options.addOpenApiExamples A boolean indicating whether to add `.openapi({ example: ... })` calls.
* Defaults to `false`.
* @returns A string containing the complete TypeScript code for the Zod schema.
*/
function generateZodSchema(inputJson, options) {
// Default to false for addOpenApiExamples if not provided
const addOpenApiExamples = options?.addOpenApiExamples ?? false;
let schemaBody; // This will hold the z.object(...) or z.array(z.object(...)) part
if (Array.isArray(inputJson)) {
if (inputJson.length === 0) {
// Handle empty top-level array
schemaBody = `z.array(z.object({}))`;
}
else {
// Generate schema for the first element and wrap it in z.array()
schemaBody = `z.array(${generateObjectSchemaString(inputJson[0], addOpenApiExamples)})`;
}
}
else if (typeof inputJson === 'object' && inputJson !== null) {
// Generate schema for a single top-level object
schemaBody = generateObjectSchemaString(inputJson, addOpenApiExamples);
}
else {
// Handle invalid top-level input type, returning z.any() as a fallback schema.
return `export const schema = z.any();`;
}
// The output string now *only* contains the schema definition.
// It is assumed that 'z' is globally available or imported by the consuming environment.
return `export const schema = ${schemaBody};`;
}
//# sourceMappingURL=generator.js.map