zod-to-x
Version:
Multi language types generation from Zod schemas.
191 lines (190 loc) • 7.99 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Zod2X = void 0;
const zod_1 = require("zod");
const string_utils_1 = __importDefault(require("../utils/string_utils"));
const zod_helpers_1 = require("./zod_helpers");
/**
* Abstract base class for transpiling Zod schemas into other programming languages.
* Extend this class and implement the abstract methods to define how each Zod type
* should be converted to the target language's syntax.
*/
class Zod2X {
constructor(opt) {
// Push with indentation helpers
this.push0 = (data) => this.output.push(`${this.indent[0]}${data}`);
this.push1 = (data) => this.output.push(`${this.indent[1]}${data}`);
this.push2 = (data) => this.output.push(`${this.indent[2]}${data}`);
this.push3 = (data) => this.output.push(`${this.indent[3]}${data}`);
this.output = [];
this.preImports = new Set();
this.imports = new Set();
this.postImports = new Set();
this.indent = string_utils_1.default.getIndentationLevels(opt.indent || 4);
this.opt = opt;
}
/**
* Determines if the given type token can be transpiled into the target language.
* @param token - The type token to check.
* @returns `true` if the type is transpilerable; otherwise, `false`.
*/
isTranspilerable(token) {
return (0, zod_helpers_1.isTranspilerableZodType)(token.type);
}
/**
* Adds a comment to the transpiled output.
* @param data - The comment text to add.
* @param indent - Optional indentation to apply before the comment.
*/
addComment(data = "", indent = "") {
if (data && this.opt.includeComments) {
this.output.push(this.getComment(data, indent));
}
}
/**
* Retrieves the equivalent type representation of an AST node in the target language.
* @param token - The AST node or transpilerable type to convert.
* @returns A string representing the type in the target language.
*/
getAttributeType(token) {
let varType = "";
if (this.isTranspilerable(token)) {
varType = token.name;
}
else if (token.type === "definition") {
varType =
this.opt.useImports === true && token.parentNamespace
? this.getTypeFromExternalNamespace(token.parentNamespace, token.reference)
: token.reference;
}
else if (token.type === zod_1.ZodFirstPartyTypeKind.ZodString) {
varType = this.getStringType();
}
else if (token.type === zod_1.ZodFirstPartyTypeKind.ZodBoolean) {
varType = this.getBooleanType();
}
else if (token.type === zod_1.ZodFirstPartyTypeKind.ZodAny) {
varType = this.getAnyType();
}
else if (token.type === zod_1.ZodFirstPartyTypeKind.ZodDate) {
varType = this.getDateType();
}
else if (token.type === zod_1.ZodFirstPartyTypeKind.ZodLiteral) {
const parentEnum = token.parentEnumName && token.parentEnumKey
? [token.parentEnumName, token.parentEnumKey]
: undefined;
varType = this.getLiteralStringType(token.value, parentEnum);
}
else if (token.type === zod_1.ZodFirstPartyTypeKind.ZodSet) {
varType = this.getSetType(this.getAttributeType(token.value));
}
else if (token.type === zod_1.ZodFirstPartyTypeKind.ZodNumber) {
varType = this.getNumberType(token.constraints.isInt, {
min: token.constraints.min,
max: token.constraints.max,
});
}
else if (token.type === zod_1.ZodFirstPartyTypeKind.ZodTuple) {
const tupleAttributeTypes = token.items.map(this.getAttributeType.bind(this));
varType = this.getTupleType(tupleAttributeTypes);
}
else if (token.type === zod_1.ZodFirstPartyTypeKind.ZodMap ||
token.type === zod_1.ZodFirstPartyTypeKind.ZodRecord) {
const [key, value] = [token.key, token.value].map(this.getAttributeType.bind(this));
if (token.type === zod_1.ZodFirstPartyTypeKind.ZodMap) {
varType = this.getMapType(key, value);
}
else {
varType = this.getRecordType(key, value);
}
}
else {
console.log(" # Unknown attribute equivalent for ---> ", token.type);
}
return token.arrayDimension ? this.getArrayType(varType, token.arrayDimension) : varType;
}
/**
* Adds an external type import to the transpiler's imports if the provided transpiled item
* is located into another file and namespace, and if the `useImports` option is not disabled.
*
* @param item - An object of type `TranspilerableTypes` containing information
* about the type to be imported, including its parent file and namespace.
* @returns `true` if the import was successfully added, otherwise `false`.
*/
addExternalTypeImport(item) {
if (item.parentFile && item.parentNamespace && this.opt.useImports !== false) {
this.imports.add(this.addImportFromFile(item.parentFile, item.parentNamespace));
return true;
}
return false;
}
/**
* Transpiles a single item from the transpiler queue.
* @param item - The transpilerable type to transpile.
*/
_transpileItem(item) {
if (item.type === zod_1.ZodFirstPartyTypeKind.ZodEnum ||
item.type === zod_1.ZodFirstPartyTypeKind.ZodNativeEnum) {
this.transpileEnum(item);
}
else if (item.type === zod_1.ZodFirstPartyTypeKind.ZodObject) {
this.transpileStruct(item);
}
else if (item.type === zod_1.ZodFirstPartyTypeKind.ZodUnion ||
item.type === zod_1.ZodFirstPartyTypeKind.ZodDiscriminatedUnion) {
this.transpileUnion(item);
}
else if (item.type === zod_1.ZodFirstPartyTypeKind.ZodIntersection) {
this.transpileIntersection(item);
}
else {
throw new Error(`Unexpected type for transpilation: ${item.type}`);
}
}
/**
* Constructs and returns an array of strings representing the header section
* of the transpiled output. The header may include custom comments, pre-imports,
* imports, and post-imports, depending on the provided options and internal state.
*
* Each section is separated by an empty string for readability.
*
* @returns An array of strings representing the header section.
*
*/
_getHeader() {
const header = [];
if (this.opt.header) {
header.push(...this.opt.header.split("\n").map((i) => this.getComment(i)));
header.push("");
}
if (this.preImports.size > 0) {
header.push(...this.preImports);
header.push("");
}
if (this.imports.size > 0) {
header.push(...[...this.imports].sort());
header.push("");
}
if (this.postImports.size > 0) {
header.push(...this.postImports);
header.push("");
}
return header;
}
/**
* Transpiles a queue of AST nodes into the target language.
* @param transpilerQueue - An array of transpilerable types (AST nodes with names).
* @returns The transpiled code as a string.
*/
transpile(transpilerQueue) {
this.runBefore();
transpilerQueue.nodes.forEach(this._transpileItem.bind(this));
this.runAfter();
this.output = [...this._getHeader(), ...this.output];
return this.output.join("\n");
}
}
exports.Zod2X = Zod2X;