arela
Version:
AI-powered CTO with multi-agent orchestration, code summarization, visual testing (web + mobile) for blazing fast development.
121 lines (119 loc) • 4.67 kB
JavaScript
/**
* Generate Zod schemas from OpenAPI schemas for runtime validation
*/
export function generateSchemas(spec) {
let output = `/**
* Auto-generated Zod schemas from OpenAPI spec
* DO NOT EDIT - This file is generated by Arela
* @see https://zod.dev
*/
import { z } from 'zod';
`;
const schemas = spec.components?.schemas || {};
for (const [name, schema] of Object.entries(schemas)) {
output += generateZodSchema(name, schema, schemas);
output += '\n\n';
}
return output;
}
function generateZodSchema(name, schema, allSchemas) {
const zodType = schemaToZod(schema, allSchemas);
return `export const ${name}Schema = ${zodType};`;
}
export function schemaToZod(schema, allSchemas = {}) {
if (!schema)
return 'z.any()';
// Handle $ref
if (schema.$ref) {
const refName = schema.$ref.split('/').pop();
return `${refName}Schema`;
}
// Handle enum
if (schema.enum && schema.enum.length > 0) {
const values = schema.enum.map((e) => (typeof e === 'string' ? `'${e}'` : e));
return `z.enum([${values.join(', ')}])`;
}
// Handle oneOf, anyOf, allOf
if (schema.oneOf) {
return `z.union([${schema.oneOf.map((s) => schemaToZod(s, allSchemas)).join(', ')}])`;
}
if (schema.anyOf) {
return `z.union([${schema.anyOf.map((s) => schemaToZod(s, allSchemas)).join(', ')}])`;
}
if (schema.allOf) {
return `z.intersection(${schema.allOf.map((s) => schemaToZod(s, allSchemas)).join(', ')})`;
}
switch (schema.type) {
case 'string':
let stringSchema = 'z.string()';
if (schema.format === 'email')
stringSchema += '.email()';
if (schema.format === 'uuid')
stringSchema += '.uuid()';
if (schema.format === 'date')
stringSchema += '.datetime()';
if (schema.format === 'date-time')
stringSchema += '.datetime()';
if (schema.minLength !== undefined)
stringSchema += `.min(${schema.minLength})`;
if (schema.maxLength !== undefined)
stringSchema += `.max(${schema.maxLength})`;
return stringSchema;
case 'number':
let numberSchema = 'z.number()';
if (schema.minimum !== undefined)
numberSchema += `.min(${schema.minimum})`;
if (schema.maximum !== undefined)
numberSchema += `.max(${schema.maximum})`;
return numberSchema;
case 'integer':
let intSchema = 'z.number().int()';
if (schema.minimum !== undefined)
intSchema += `.min(${schema.minimum})`;
if (schema.maximum !== undefined)
intSchema += `.max(${schema.maximum})`;
return intSchema;
case 'boolean':
return 'z.boolean()';
case 'null':
return 'z.null()';
case 'array':
if (!schema.items)
return 'z.array(z.any())';
const itemSchema = schemaToZod(schema.items, allSchemas);
let arraySchema = `z.array(${itemSchema})`;
if (schema.minItems !== undefined)
arraySchema += `.min(${schema.minItems})`;
if (schema.maxItems !== undefined)
arraySchema += `.max(${schema.maxItems})`;
return arraySchema;
case 'object': {
if (schema.additionalProperties === false && !schema.properties) {
return 'z.object({})';
}
if (!schema.properties) {
return 'z.record(z.any())';
}
const required = schema.required || [];
const props = Object.entries(schema.properties)
.map(([key, val]) => {
const valSchema = schemaToZod(val, allSchemas);
const isRequired = required.includes(key);
return `${key}: ${isRequired ? valSchema : `${valSchema}.optional()`}`;
})
.join(',\n ');
let objectSchema = `z.object({\n ${props}\n})`;
if (schema.additionalProperties === true) {
objectSchema += '.passthrough()';
}
else if (typeof schema.additionalProperties === 'object') {
const additionalSchema = schemaToZod(schema.additionalProperties, allSchemas);
objectSchema += `.and(z.record(${additionalSchema}))`;
}
return objectSchema;
}
default:
return 'z.any()';
}
}
//# sourceMappingURL=schema-generator.js.map