zod-to-x
Version:
Multi language types generation from Zod schemas.
668 lines (667 loc) • 33 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Zod2Ast = void 0;
const core_1 = require("../core");
const zod_helpers_1 = require("../lib/zod_helpers");
const logger_1 = require("../utils/logger");
const errors_1 = require("./errors");
/**
* This class creates AST nodes used to transpile Zod Schemas to other languages.
* Simply create an instance and call build with a ZodObject to obtain a list with transpilerable
* nodes.
*/
class Zod2Ast {
constructor(opt = {}) {
var _a;
this.nodes = new Map();
this.lazyPointers = [];
this.warnings = [];
this.opt = Object.assign(Object.assign({}, opt), { strict: (_a = opt.strict) !== null && _a !== void 0 ? _a : true });
}
/**
* Determines if the current node is an "own property" based on the provided parent file.
*
* @param parentFile - The file path of the parent to compare against, if exist.
* @returns `true` if the node is an "own property"; otherwise, `false`.
*/
_isOwnProperty(parentFile) {
var _a;
return (this.opt.layer === undefined ||
parentFile === undefined ||
((_a = this.opt.layer) === null || _a === void 0 ? void 0 : _a.file) === parentFile);
}
/**
* Check if the layer of the item is compatible with the layer of the schema. If does and the
* transpilerable item is in a different file, it returns the file name.
*
* @param itemName
* @param metadata
* @returns
*/
_getTranspilerableFile(itemName, metadata) {
var _a, _b;
let layer;
if (this.opt.layer !== undefined && (metadata === null || metadata === void 0 ? void 0 : metadata.layer) !== undefined) {
if (Array.isArray(metadata.genericTypes)) {
// Check that all templates used with a generic type follows the layering rules
if (metadata.genericTypes.some((i) => this.opt.layer.index < i.layer.index)) {
throw new errors_1.BadLayerDefinitionError(`${itemName}: Layer with number ${this.opt.layer.index} can only use models` +
`from the same or lower layer. Review templates used for generic ` +
`type ${metadata.typeName}.`);
}
}
const templatesTranslation = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.genericTypes) === null || _a === void 0 ? void 0 : _a.map((i) => {
var _a, _b;
return ({
parentFile: ((_a = this.opt.layer) === null || _a === void 0 ? void 0 : _a.file) !== i.layer.file ? i.layer.file : undefined,
parentNamespace: ((_b = this.opt.layer) === null || _b === void 0 ? void 0 : _b.file) !== i.layer.file ? i.layer.namespace : undefined,
aliasOf: i.typeName,
});
});
if (metadata.layer.file === this.opt.layer.file) {
// Case 1: Only layer exists and belongs to the same file
// Case 2: Layer (belongs to same file) and parentLayer exist
// Behaviour: New type is created extending the parent layer (if any)
layer = (_b = metadata.parentLayer) !== null && _b !== void 0 ? _b : metadata.layer;
if (this.opt.layer.index < layer.index) {
throw new errors_1.BadLayerDefinitionError(`${itemName}: Layer with number ${this.opt.layer.index} can only use models` +
`from the same or lower layer. Found layer with number ${layer.index}`);
}
if (this.opt.layer.file !== layer.file) {
return {
parentFile: layer.file,
parentNamespace: layer.namespace,
aliasOf: metadata === null || metadata === void 0 ? void 0 : metadata.aliasOf,
templatesTranslation,
isGenericChild: metadata === null || metadata === void 0 ? void 0 : metadata.isGenericChild,
};
}
else {
return {
aliasOf: metadata === null || metadata === void 0 ? void 0 : metadata.aliasOf,
templatesTranslation,
isGenericChild: metadata === null || metadata === void 0 ? void 0 : metadata.isGenericChild,
};
}
}
else {
// Case 3: Only layer exists and belongs to a different file
// Case 4: Layer (belongs to different file) and parentLayer exist
// Behaviour: Type is imported from Layer file
layer = metadata.layer;
if (this.opt.layer.index < layer.index) {
throw new errors_1.BadLayerDefinitionError(`${itemName}: Layer with number ${this.opt.layer.index} can only use models` +
`from the same or lower layer. Found layer with number ${layer.index}`);
}
return {
parentFile: layer.file,
parentNamespace: layer.namespace,
aliasOf: undefined,
templatesTranslation,
isGenericChild: metadata === null || metadata === void 0 ? void 0 : metadata.isGenericChild,
};
}
}
return {};
}
/**
* Transpilerable items are treated as references in the AST
* @param node: AST node from which the definition will be created
* @param constraints - Constraints to be added to the definition
* @returns
*/
_createDefinition(node, constraints = {}, templatesTranslation = []) {
return new core_1.ASTDefinition({
name: node.name,
instanceType: node.constructor.name,
parentFile: node.parentFile,
parentNamespace: node.parentNamespace,
aliasOf: node.aliasOf,
templatesTranslation,
constraints: "constraints" in node
? Object.assign(Object.assign({}, node.constraints), constraints) : constraints,
});
}
/**
* Extracts and formats the enumeration values from a given ZodEnum or ZodNativeEnum schema.
* @param schema - A ZodEnum or ZodNativeEnum schema containing the enumeration values.
* @returns A list of key-value pairs where the key is a formatted string and the value
* is either a string or a number.
*/
_getEnumValues(schema) {
return Object.entries(schema.enum)
.filter(([key, _value]) => isNaN(Number(key)))
.map(([key, value]) => {
// Creates a string key if it starts with number.
key = isNaN(Number(key.at(0))) ? key : `"${key}"`;
return [key, value];
});
}
/**
* Intersects the properties of two Zod object schemas and returns the combined properties.
* Processes the Zod shapes directly instead of looking up cached AST nodes, ensuring that
* instantiated generic types (from useGenericType) are correctly resolved.
*
* @param left - The left Zod object schema.
* @param right - The right Zod object schema.
* @returns An object containing the combined properties of the left and right schemas.
*/
_intersectAstNodes(left, right) {
const properties = {};
for (const schema of [left, right]) {
const shape = schema.def.shape;
for (const key in shape) {
const prevWasRequired = properties[key] !== undefined && !properties[key].isOptional;
if (zod_helpers_1.ZodHelpers.isZodPromise(shape[key]) &&
zod_helpers_1.ZodHelpers.isZod2XGeneric(shape[key])) {
const templateKey = shape[key].unwrap().def.values[0];
properties[key] = new core_1.ASTGenericType(templateKey);
}
else {
properties[key] = this._zodToAST(shape[key]);
}
if (prevWasRequired && properties[key].isOptional) {
// In intersection, if a property is required in one schema and optional in
// another, it should be considered required.
properties[key].isOptional = false;
}
}
}
return { properties };
}
/**
* Merges multiple AST definitions into a single AST object containing combined properties.
* - Equal properties must have the same type and array dimension.
* - If a property is optional in one definition and required in another, it will be considered
* optional in the merged object.
* - If a property is nullable in one definition and non-nullable in another, it will be
* considered nullable in the merged object.
*
* @param options - An array of AST definitions to be merged.
* @returns An object containing the merged properties.
* @throws AstNodeError - If properties with different types or array dimensions are encountered.
*/
_unionAstNodes(options) {
let typeA, typeB;
const data = options.map((i) => this.nodes.get(i.name));
const properties = data.reduce((acc, i, j) => {
for (const key in i.properties) {
if (acc[key]) {
acc[key] = Object.assign(Object.create(Object.getPrototypeOf(acc[key])), acc[key]);
typeA = acc[key].constructor.name;
typeB = i.properties[key].constructor.name;
if (typeA !== typeB) {
this.warnings.push(`Merging properties with different types: ${typeA} ` +
`(from a previous variant) and ${typeB} ` +
`(from ${i.name})`);
}
if (acc[key].arrayDimension !== i.properties[key].arrayDimension) {
this.warnings.push(`Merging properties with different array dimensions: ` +
`${acc[key].arrayDimension} (from a previous variant) and ` +
`${i.properties[key].arrayDimension} (from ${i.name})`);
acc[key].arrayDimension = Math.max(acc[key].arrayDimension || 0, i.properties[key].arrayDimension || 0);
}
if (acc[key].isNullable !== i.properties[key].isNullable) {
acc[key].isNullable = true;
}
if (acc[key].isOptional !== i.properties[key].isOptional) {
acc[key].isOptional = true;
}
if (i.properties[key].description) {
acc[key].description = i.properties[key].description;
}
}
else {
acc[key] = i.properties[key]; // New property, just add it
}
}
return acc;
}, {});
for (const key in properties) {
if (!data.every((variant) => key in variant.properties)) {
// In Union, if a property is not present in all variants, it should be considered
// optional. Shallow-clone preserving prototype before mutating, to avoid corrupting
// the original cached AST node.
properties[key] = Object.assign(Object.create(Object.getPrototypeOf(properties[key])), properties[key]);
properties[key].isOptional = true;
}
}
return { properties };
}
/**
* Retrieves the name and associated transpilerable file information for a given Zod schema.
*
* @param schema - The Zod schema to extract the name and file information from.
*
* @returns An object containing the `name` of the schema and additional transpilerable file
* details.
*
* @throws AstTypeNameDefinitionError - If the schema does not have a `typeName` defined.
* This can occur if layered modeling is used with nested schema definitions or if the `zod2x`
* method is not used to provide a `typeName`. The error message includes details about the
* affected type properties.
*/
_getNames(schema) {
var _a, _b, _c;
const name = (_a = schema._zod2x) === null || _a === void 0 ? void 0 : _a.typeName;
if (!name) {
let itemProperties = ["Unknown type"];
if (zod_helpers_1.ZodHelpers.isZodObject(schema)) {
itemProperties = Object.keys(schema.def.shape);
}
else if (zod_helpers_1.ZodHelpers.isZodAnyUnionType(schema)) {
itemProperties = schema.def.options.map((i) => {
var _a;
return ((_a = i._zod2x) === null || _a === void 0 ? void 0 : _a.typeName) || i.def.type;
});
}
else if (zod_helpers_1.ZodHelpers.isZodIntersection(schema)) {
const left = schema.def.left;
const right = schema.def.right;
itemProperties = [
((_b = left._zod2x) === null || _b === void 0 ? void 0 : _b.typeName) || left.def.type,
((_c = right._zod2x) === null || _c === void 0 ? void 0 : _c.typeName) || right.def.type,
];
}
else if (zod_helpers_1.ZodHelpers.isZodEnum(schema)) {
itemProperties = this._getEnumValues(schema).map((i) => i[0]);
}
throw new errors_1.AstTypeNameDefinitionError(`${schema.def.type} type must have a typeName. If Layered modeling is used, ` +
`avoid nesting schemas definitions. Otherwise, use zod2x method to provide one. ` +
`Affected type properties: ${itemProperties.join(", ")}`);
}
return Object.assign({ name }, this._getTranspilerableFile(name, schema._zod2x));
}
/**
* Generates an Abstract Syntax Tree (AST) definition for a Zod enum schema.
*
* @param schema - The Zod enum schema to process.
* @param opt - Optional metadata for schema processing.
* - `isInjectedEnum` (optional): Indicates if the enum is part of a discriminated union.
*
* @returns The AST definition for the provided enum schema.
*/
_getEnumAst(schema, opt) {
var _a;
const { name, parentFile, parentNamespace, aliasOf } = this._getNames(schema);
const item = new core_1.ASTEnum({
name,
values: this._getEnumValues(schema),
description: (_a = schema.meta()) === null || _a === void 0 ? void 0 : _a.description,
parentFile,
parentNamespace,
aliasOf,
isFromDiscriminatedUnion: opt === null || opt === void 0 ? void 0 : opt.isInjectedEnum,
});
if (!this.nodes.has(name)) {
this.nodes.set(name, item);
}
return this._createDefinition(item);
}
/**
* Generates an abstract syntax tree (AST) definition for a Zod object schema.
*
* @param schema - The ZodObject schema to be converted into an AST definition.
* @param opt - Optional metadata for schema processing.
* - `discriminantKey`: A key used to determine the discriminant value for the schema.
*
* @returns The AST definition for the provided Zod object schema.
*/
_getObjectAst(schema, opt) {
var _a;
const { name, parentFile, parentNamespace, aliasOf, templatesTranslation, isGenericChild } = this._getNames(schema);
let discriminantValue = undefined;
const shape = schema.def.shape;
if (!this.nodes.has(name)) {
const properties = {};
const templates = new Set();
for (const key in shape) {
if (zod_helpers_1.ZodHelpers.isZodPromise(shape[key]) &&
zod_helpers_1.ZodHelpers.isZod2XGeneric(shape[key])) {
const templateKey = shape[key].unwrap().def.values[0];
properties[key] = new core_1.ASTGenericType(templateKey);
if (templates.has(templateKey)) {
throw new errors_1.AstTypeNameDefinitionError(`Duplicate template key found for model ${name}: ${templateKey}`);
}
templates.add(templateKey);
}
else {
properties[key] = this._zodToAST(shape[key]);
}
}
if (opt === null || opt === void 0 ? void 0 : opt.skipLayerClass) {
return {}; // Layer classes are not transpilerable
}
this.nodes.set(name, new core_1.ASTObject({
name,
properties,
description: (_a = schema.meta()) === null || _a === void 0 ? void 0 : _a.description,
parentFile,
parentNamespace,
aliasOf,
templates,
templatesTranslation: templatesTranslation || [],
}));
}
const item = this.nodes.get(name);
if (opt === null || opt === void 0 ? void 0 : opt.discriminantKey) {
if (Object.keys(item.properties).includes(opt.discriminantKey)) {
const key = opt.discriminantKey;
if (item.properties[key] instanceof core_1.ASTLiteral) {
/* Used for serialization purposes, it is parsed as string for
* convenience */
discriminantValue = item.properties[key].value.toString();
}
else {
console.warn(`Consider to set '${key}' key of '${name}' as ZodLiteral`);
}
}
}
return this._createDefinition(this.nodes.get(name), { discriminantValue }, isGenericChild ? undefined : templatesTranslation);
}
/**
* Generates an Abstract Syntax Tree (AST) definition for a Zod union schema.
*
* This method processes a Zod union schema and creates an `ASTUnion` object
* that represents the schema in an AST format. It handles both regular unions
* and discriminated unions, and provides warnings for certain bad data modeling
* practices, such as unions of non-object types or the use of `ZodUnion` instead
* of `ZodDiscriminatedUnion`.
*
* @param schema - The Zod union schema to be converted into an AST definition.
* This can be a regular union or a discriminated union.
*
* @returns The AST definition for the given Zod union schema.
*/
_getUnionAst(schema) {
var _a, _b, _c;
const def = schema.def;
const discriminator = zod_helpers_1.ZodHelpers.isZodDiscriminatedUnion(schema)
? schema._zod.def.discriminator
: undefined;
const { name, parentFile, parentNamespace, aliasOf } = this._getNames(schema);
const item = new core_1.ASTUnion({
name,
options: def.options.map((i) => this._zodToAST(i, { discriminantKey: discriminator })),
areAllObjects: def.options.every((i) => zod_helpers_1.ZodHelpers.isZodObject(i)),
description: (_a = schema.meta()) === null || _a === void 0 ? void 0 : _a.description,
discriminantKey: discriminator,
parentFile,
parentNamespace,
aliasOf,
});
if (!item.areAllObjects) {
if (this._isOwnProperty(parentFile)) {
this.warnings.push(`[affected type: ${name}] Union of non-object types is a bad data modeling ` +
"practice, and could lead to unexpected results. Avoid it, or disable " +
"strict mode if not possible.");
}
}
else if (zod_helpers_1.ZodHelpers.isZodUnion(schema)) {
if (this._isOwnProperty(parentFile)) {
this.warnings.push(`[affected type: ${name}] Using ZodUnion is a bad data modeling practice. ` +
"Use ZodDiscriminatedUnion instead, or disable strict mode if not possible.");
}
const unifiedProperties = this._unionAstNodes(item.options);
item.newObject = new core_1.ASTObject({
name,
properties: unifiedProperties.properties,
description: (((_b = schema.meta()) === null || _b === void 0 ? void 0 : _b.description) ? `${(_c = schema.meta()) === null || _c === void 0 ? void 0 : _c.description} - ` : "") +
`Built from union of ` +
`${item.options.map((i) => i.name).join(", ")}`,
templates: new Set(Object.values(unifiedProperties.properties)
.filter((i) => i instanceof core_1.ASTGenericType)
.map((i) => i.name)),
templatesTranslation: [],
});
}
if (name && !this.nodes.has(name)) {
this.nodes.set(name, item);
}
return this._createDefinition(item);
}
/**
* Processes a ZodIntersection schema and generates an ASTDefinition for it.
*
* @param schema - The ZodIntersection schema to process, which combines two Zod types.
*
* @returns An ASTDefinition representing the intersection of the two Zod types.
*/
_getIntersectionAst(schema) {
var _a, _b, _c;
const def = schema.def;
const { name, parentFile, parentNamespace, aliasOf } = this._getNames(schema);
const item = new core_1.ASTIntersection({
name,
left: this._zodToAST(def.left),
right: this._zodToAST(def.right),
areAllObjects: zod_helpers_1.ZodHelpers.isZodObject(def.left) &&
zod_helpers_1.ZodHelpers.isZodObject(def.right),
description: (_a = schema.meta()) === null || _a === void 0 ? void 0 : _a.description,
parentFile,
parentNamespace,
aliasOf,
});
if (!item.areAllObjects) {
if (this._isOwnProperty(parentFile)) {
this.warnings.push(`[affected type: ${name}] Intersection of non-object is a bad data modeling ` +
"practice, and could lead to unexpected results. Avoid it, or disable " +
"strict mode if not possible.");
}
}
else {
const intersectedProperties = this._intersectAstNodes(def.left, def.right);
item.newObject = new core_1.ASTObject({
name,
properties: intersectedProperties.properties,
description: (((_b = schema.meta()) === null || _b === void 0 ? void 0 : _b.description) ? `${(_c = schema.meta()) === null || _c === void 0 ? void 0 : _c.description} - ` : "") +
`Built from intersection of ` +
`${item.left.name} and ` +
`${item.right.name}`,
templates: new Set(Object.values(intersectedProperties.properties)
.filter((i) => i instanceof core_1.ASTGenericType)
.map((i) => i.name)),
templatesTranslation: [],
});
}
if (name && !this.nodes.has(name)) {
this.nodes.set(name, item);
}
return this._createDefinition(item);
}
/**
* Generates an AST (Abstract Syntax Tree) definition for a Zod array schema.
*
* @param schema - The Zod array schema to process.
* @param innerSchema - The AST type representing the inner schema of the array.
* @returns The AST definition for the array schema.
*/
_getArrayAst(schema, innerSchema) {
var _a;
const { name, parentFile, parentNamespace, aliasOf } = this._getNames(schema);
const item = new core_1.ASTArray({
name,
item: innerSchema,
description: (_a = schema.meta()) === null || _a === void 0 ? void 0 : _a.description,
parentFile,
parentNamespace,
aliasOf,
});
if (!this.nodes.has(name)) {
this.nodes.set(name, item);
}
return this._createDefinition(item);
}
_getAliasAst(schema, item) {
var _a;
if (((_a = schema._zod2x) === null || _a === void 0 ? void 0 : _a.typeName) === undefined || this.opt.skipBasicTypes === true) {
return item;
}
const { name, parentFile, parentNamespace, aliasOf } = this._getNames(schema);
item.name = name;
item.parentFile = parentFile;
item.parentNamespace = parentNamespace;
item.aliasOf = aliasOf;
if (!this.nodes.has(name)) {
this.nodes.set(name, item);
}
return this._createDefinition(item);
}
/**
* Build the AST node of provided Zod Schema
* @param schema
* @returns
*/
_zodToAST(schema, opt) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
if (zod_helpers_1.ZodHelpers.isZodString(schema)) {
return this._getAliasAst(schema, new core_1.ASTString({ description: (_a = schema.meta()) === null || _a === void 0 ? void 0 : _a.description }));
}
else if (zod_helpers_1.ZodHelpers.isZodAnyNumberType(schema)) {
return this._getAliasAst(schema, new core_1.ASTNumber({
description: (_b = schema.meta()) === null || _b === void 0 ? void 0 : _b.description,
constraints: zod_helpers_1.ZodHelpers.getZodNumberConstraints(schema),
}));
}
else if (zod_helpers_1.ZodHelpers.isZodBoolean(schema)) {
return this._getAliasAst(schema, new core_1.ASTBoolean({ description: (_c = schema.meta()) === null || _c === void 0 ? void 0 : _c.description }));
}
else if (zod_helpers_1.ZodHelpers.isZodDate(schema)) {
return this._getAliasAst(schema, new core_1.ASTDate({ description: (_d = schema.meta()) === null || _d === void 0 ? void 0 : _d.description }));
}
else if (zod_helpers_1.ZodHelpers.isZodAny(schema)) {
return this._getAliasAst(schema, new core_1.ASTAny({ description: (_e = schema.meta()) === null || _e === void 0 ? void 0 : _e.description }));
}
else if (zod_helpers_1.ZodHelpers.isZodNullable(schema)) {
const subSchema = this._zodToAST(schema.unwrap());
subSchema.isNullable = true;
subSchema.description = ((_f = schema.meta()) === null || _f === void 0 ? void 0 : _f.description) || subSchema.description;
return subSchema;
}
else if (zod_helpers_1.ZodHelpers.isZodOptional(schema)) {
const subSchema = this._zodToAST(schema.unwrap());
subSchema.isOptional = true;
subSchema.description = ((_g = schema.meta()) === null || _g === void 0 ? void 0 : _g.description) || subSchema.description;
return subSchema;
}
else if (zod_helpers_1.ZodHelpers.isZodDefault(schema)) {
const subSchema = this._zodToAST(schema.def.defaultValue());
subSchema.description = ((_h = schema.meta()) === null || _h === void 0 ? void 0 : _h.description) || subSchema.description;
return subSchema;
}
else if (zod_helpers_1.ZodHelpers.isZodArray(schema)) {
const isParentArray = (opt === null || opt === void 0 ? void 0 : opt.calledFromArray) !== true;
const subSchema = this._zodToAST(schema.element, { calledFromArray: true });
subSchema.description = ((_j = schema.meta()) === null || _j === void 0 ? void 0 : _j.description) || subSchema.description;
subSchema.arrayDimension = Number.isInteger(subSchema.arrayDimension)
? ++subSchema.arrayDimension
: 1;
if (isParentArray && ((_k = schema._zod2x) === null || _k === void 0 ? void 0 : _k.typeName)) {
return this._getArrayAst(schema, subSchema);
}
else {
return subSchema;
}
}
else if (zod_helpers_1.ZodHelpers.isZodSet(schema)) {
return this._getAliasAst(schema, new core_1.ASTSet({
value: this._zodToAST(schema.def.valueType),
description: (_l = schema.meta()) === null || _l === void 0 ? void 0 : _l.description,
}));
}
else if (zod_helpers_1.ZodHelpers.isZodLiteral(schema)) {
let parentEnum = undefined;
let parentEnumKey = undefined;
// TODO: Support multiple values
if ((_m = schema._zod2x) === null || _m === void 0 ? void 0 : _m.parentEnum) {
parentEnumKey = (_p = this._getEnumValues((_o = schema._zod2x) === null || _o === void 0 ? void 0 : _o.parentEnum).find((i) => i[1] === schema.def.values.at(0))) === null || _p === void 0 ? void 0 : _p[0];
parentEnum = this._zodToAST((_q = schema._zod2x) === null || _q === void 0 ? void 0 : _q.parentEnum, {
isInjectedEnum: true,
});
}
return new core_1.ASTLiteral({
value: schema.def.values.at(0), // TODO: Support multiple values
description: (_r = schema.meta()) === null || _r === void 0 ? void 0 : _r.description,
parentEnum: parentEnum,
parentEnumKey,
});
}
else if (zod_helpers_1.ZodHelpers.isZodAnyMapType(schema)) {
return this._getAliasAst(schema, new core_1.ASTMap({
type: zod_helpers_1.ZodHelpers.isZodRecord(schema) ? "record" : "map",
key: this._zodToAST(schema.keyType),
value: this._zodToAST(schema.valueType),
description: (_s = schema.meta()) === null || _s === void 0 ? void 0 : _s.description,
}));
}
else if (zod_helpers_1.ZodHelpers.isZodLazy(schema)) {
/** Lazy items use to be recursive schemas of its own, so the are trated as another
* definition */
const lazySchema = schema.def.getter();
const lazyPointer = this._createDefinition({ name: "pending" });
this.lazyPointers.push([lazyPointer, lazySchema]);
return lazyPointer;
}
else if (zod_helpers_1.ZodHelpers.isZodTuple(schema)) {
return this._getAliasAst(schema, new core_1.ASTTuple({
items: schema.def.items.map(this._zodToAST.bind(this)),
description: (_t = schema.meta()) === null || _t === void 0 ? void 0 : _t.description,
}));
/**
*
*
* Transpilerable items
*
*
* */
}
else if (zod_helpers_1.ZodHelpers.isZodEnum(schema)) {
return this._getEnumAst(schema, opt);
}
else if (zod_helpers_1.ZodHelpers.isZodObject(schema)) {
return this._getObjectAst(schema, opt);
}
else if (zod_helpers_1.ZodHelpers.isZodAnyUnionType(schema)) {
return this._getUnionAst(schema);
}
else if (zod_helpers_1.ZodHelpers.isZodIntersection(schema)) {
return this._getIntersectionAst(schema);
}
else {
logger_1.log.warn(`Unsupported Zod type: ${JSON.stringify(schema)}`);
return new core_1.ASTAny({
description: `Unsupported Zod type: ${schema.def.type}`,
});
}
}
/**
* Create the AST identifying the nodes that can be transpiled.
* @param schema
* @returns Transpilerable nodes.
*/
build(schema) {
var _a, _b, _c;
this._zodToAST(schema, {
skipLayerClass: ((_a = this.opt) === null || _a === void 0 ? void 0 : _a.layer) !== undefined && ((_c = (_b = this.opt) === null || _b === void 0 ? void 0 : _b.layer) === null || _c === void 0 ? void 0 : _c.skipLayerInterface) !== false,
});
while (this.lazyPointers.length > 0) {
const [pointer, schema] = this.lazyPointers.shift();
const lazyResolve = this._zodToAST(schema);
/** Pointer to the pending AST node is updated with the lazy resolve */
Object.keys(pointer).forEach((key) => {
delete pointer[key];
});
Object.entries(lazyResolve).forEach(([key, value]) => {
pointer[key] = value;
});
}
if (this.opt.strict !== false && this.warnings.length > 0) {
throw new errors_1.AstNodeError(this.warnings.join("\n"));
}
return {
nodes: this.nodes,
warnings: this.warnings,
};
}
}
exports.Zod2Ast = Zod2Ast;