UNPKG

zod-to-x

Version:

Multi language types generation from Zod schemas.

251 lines (250 loc) 10 kB
"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 core_1 = require("../core"); const string_utils_1 = __importDefault(require("../utils/string_utils")); /** * 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) { /** * Returns a comment. */ this.getComment = (data, indent = "") => { return data .split("\n") .map((line) => `${indent}${this.commentKey} ${line}`) .join("\n"); }; // 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 (token instanceof core_1.ASTEnum || token instanceof core_1.ASTObject || token instanceof core_1.ASTUnion || token instanceof core_1.ASTIntersection); } /** * Determines if the given AST node represents an aliased type. * * @param token - The AST node to evaluate. * @returns `true` if the token is an instance of an aliased type, otherwise `false`. */ isAliasedType(token) { return (token instanceof core_1.ASTString || token instanceof core_1.ASTNumber || token instanceof core_1.ASTBoolean || token instanceof core_1.ASTLiteral || token instanceof core_1.ASTDate || token instanceof core_1.ASTAny || token instanceof core_1.ASTMap || token instanceof core_1.ASTSet || token instanceof core_1.ASTTuple || token instanceof core_1.ASTArray); } /** * 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) { var _a, _b, _c; let varType = ""; if (token instanceof core_1.ASTDefinition) { const template = this.getGenericTemplatesTranslation(token) || ""; if (this.opt.useImports === true && token.parentNamespace) { this.addExternalTypeImport({ parentNamespace: token.parentNamespace, parentFile: token.parentFile, }); if (token.aliasOf) { varType = token.name; } else { varType = this.getTypeFromExternalNamespace(token.parentNamespace, token.name); } } else { varType = token.name; } varType += template; } else if (this.isTranspilerable(token)) { varType = token.name; } else if (token instanceof core_1.ASTString) { varType = this.getStringType(); } else if (token instanceof core_1.ASTBoolean) { varType = this.getBooleanType(); } else if (token instanceof core_1.ASTAny) { varType = this.getAnyType(); } else if (token instanceof core_1.ASTDate) { varType = this.getDateType(); } else if (token instanceof core_1.ASTLiteral) { const parentEnum = token.parentEnumKey && token.parentEnum ? [this.getAttributeType(token.parentEnum), token.parentEnumKey] : undefined; varType = this.getLiteralStringType(token.value, parentEnum); } else if (token instanceof core_1.ASTSet) { varType = this.getSetType(this.getAttributeType(token.value)); } else if (token instanceof core_1.ASTNumber) { varType = this.getNumberType(((_a = token.constraints) === null || _a === void 0 ? void 0 : _a.isInt) === true, { min: (_b = token.constraints) === null || _b === void 0 ? void 0 : _b.min, max: (_c = token.constraints) === null || _c === void 0 ? void 0 : _c.max, }); } else if (token instanceof core_1.ASTTuple) { const tupleAttributeTypes = token.items.map(this.getAttributeType.bind(this)); varType = this.getTupleType(tupleAttributeTypes); } else if (token instanceof core_1.ASTMap) { const [key, value] = [token.key, token.value].map(this.getAttributeType.bind(this)); if (token.type === "map") { varType = this.getMapType(key, value); } else { varType = this.getRecordType(key, value); } } else if (token instanceof core_1.ASTGenericType) { varType = token.name; } else { console.log(" # Unknown attribute equivalent for ---> ", token.constructor.name); } return token.arrayDimension ? this.getArrayType(varType, token.arrayDimension) : varType; } /** * Determines whether a given type is an external type import. * * @param item - An object containing the `parentFile` and `parentNamespace` * properties of the type to evaluate. * @returns `true` if the type is an external type import; otherwise, `false`. */ isExternalTypeImport(item) { return (item.parentFile !== undefined && item.parentNamespace !== undefined && this.opt.useImports !== false); } /** * 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 (this.isExternalTypeImport(item)) { 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 instanceof core_1.ASTEnum) { this.transpileEnum(item); } else if (item instanceof core_1.ASTObject) { this.transpileStruct(item); } else if (item instanceof core_1.ASTUnion) { this.transpileUnion(item); } else if (item instanceof core_1.ASTIntersection) { this.transpileIntersection(item); } else if (this.isAliasedType(item)) { this.transpileAliasedType(item); } else if (item instanceof core_1.ASTCommon) { console.log(`Under construction: ${item.constructor.name}`); } else { throw new Error(`Unexpected item for transpilation: ${JSON.stringify(item)}`); } } /** * 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.getComment(this.opt.header)); 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;