UNPKG

zod-to-x

Version:

Multi language types generation from Zod schemas.

245 lines (244 loc) 9.17 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Zod2Ts = void 0; const zod_1 = require("zod"); const case_1 = __importDefault(require("case")); const core_1 = require("../../core"); const options_1 = require("./options"); class Zod2Ts extends core_1.Zod2X { constructor(opt = {}) { super(Object.assign(Object.assign({}, options_1.defaultOpts), opt)); this.getComment = (data, indent = "") => `${indent}// ${data}`; this.getAnyType = () => "any"; this.getBooleanType = () => "boolean"; this.getDateType = () => "Date"; /** Ex: Set<TypeA> */ this.getSetType = (itemType) => `Set<${itemType}>`; this.getStringType = () => "string"; /** Ex: [TypeA, TypeB] */ this.getTupleType = (itemsType) => `[${itemsType.join(", ")}]`; /** Ex: TypeA | TypeB */ this.getUnionType = (itemsType) => itemsType.join(" | "); /** Ex: TypeA & TypeB */ this.getIntersectionType = (itemsType) => itemsType.join(" & "); this.getNumberType = () => "number"; } runAfter() { } runBefore() { } addImportFromFile(filename, namespace) { const filenameWithoutExtension = filename.endsWith(".ts") ? filename.slice(0, -3) : filename; return `import * as ${namespace} from "./${filenameWithoutExtension}";`; } getTypeFromExternalNamespace(namespace, typeName) { return `${namespace}.${typeName}`; } addExtendedType(name, parentNamespace, parentTypeName, opt) { const extendedType = this.getTypeFromExternalNamespace(parentNamespace, parentTypeName); if (this.opt.outType === "class") { if (opt === null || opt === void 0 ? void 0 : opt.isDiscriminatedUnion) { this.push0(`export type ${name} = ${extendedType};\n`); } else { this.push0(`export class ${name} extends ${extendedType} {}\n`); } } else { if (opt === null || opt === void 0 ? void 0 : opt.isUnion) { this.push0(`export type ${name} = ${extendedType};\n`); } else if (opt === null || opt === void 0 ? void 0 : opt.isDiscriminatedUnion) { this.push0(`export type ${name} = ${extendedType};\n`); } else { this.push0(`export interface ${name} extends ${extendedType} {}\n`); } } } /** Ex: Array<Array<TypeA[]>> */ getArrayType(arrayType, arrayDeep) { let output = arrayType.includes("|") || arrayType.includes("&") ? `(${arrayType})[]` : `${arrayType}[]`; for (let i = 0; i < arrayDeep - 1; i++) { output = `Array<${output}>`; } return output; } getLiteralStringType(value, parentEnumNameKey) { return parentEnumNameKey ? `${parentEnumNameKey[0]}.${case_1.default.pascal(parentEnumNameKey[1])}` : isNaN(Number(value)) ? `"${value}"` : value; } /** Ex: Map<TypeA, TypeB> */ getMapType(keyType, valueType) { return `Map<${keyType}, ${valueType}>`; } /** Ex: Record<TypeA, TypeB> */ getRecordType(keyType, valueType) { return `Record<${keyType}, ${valueType}>`; } /** Ex: * enum { * ItemKey1: 0, // case of nativeEnum * ItemKey2: "ItemValue2" // case of Enum * } */ transpileEnum(data) { if (this.addExternalTypeImport(data)) { return; } this.addComment(data.description); this.push0(`export enum ${data.name} {`); data.values.forEach((i) => { // If enum key starts with number, it is stored between quotes. const key = case_1.default.pascal(i[0]); const keyValue = isNaN(Number(key.at(0))) ? key : `"${key}"`; // Enum value is stored between quotes if not nativeEnum. const enumValue = typeof i[1] === "string" ? `"${i[1]}"` : `${i[1]}`; this.push1(`${keyValue} = ${enumValue},`); }); this.push0("}\n"); } /** Ex: * // Interface output * // Class output if non-object intersection * type TypeC = TypeA & TypeB * * // Class output all-object intersection * class TypeC { * ...attributesTypeA, * ...attributesTypeB * * constructor(data: TypeC) { * ...attributesAssignment * } * } * */ transpileIntersection(data) { var _a; if (this.addExternalTypeImport(data)) { if (data.parentTypeName) { this.addExtendedType(data.name, data.parentNamespace, data.parentTypeName); } return; } if (this.opt.outType === "class" && data.newObject) { this.addComment((_a = data.newObject) === null || _a === void 0 ? void 0 : _a.description); this._transpileStructAsClass(data.newObject); } else { this.addComment(data.description); const attributesTypes = [data.left, data.right].map(this.getAttributeType.bind(this)); this.push0(`export type ${data.name} = ${this.getIntersectionType(attributesTypes)};\n`); } } transpileStruct(data) { if (this.addExternalTypeImport(data)) { if (data.parentTypeName) { this.addExtendedType(data.name, data.parentNamespace, data.parentTypeName); } return; } this.addComment(data.description); if (this.opt.outType === "class") { this._transpileStructAsClass(data); } else { this._transpileStructuAsInterface(data); } } /** Ex: * // Interface output * // Class output for Discriminated Union or non-objects union * type TypeC = TypeA | TypeB * * // Class output for all-object Union * class TypeC { * ...attributesTypeA, * ...attributesTypeB * * constructor(data: TypeC) { * ...attributesAssignment * } * } * */ transpileUnion(data) { var _a; if (this.addExternalTypeImport(data)) { if (data.parentTypeName) { this.addExtendedType(data.name, data.parentNamespace, data.parentTypeName, { isUnion: data.type === zod_1.ZodFirstPartyTypeKind.ZodUnion, isDiscriminatedUnion: data.type === zod_1.ZodFirstPartyTypeKind.ZodDiscriminatedUnion, }); } return; } if (this.opt.outType === "class" && data.newObject) { this.addComment((_a = data.newObject) === null || _a === void 0 ? void 0 : _a.description); this._transpileStructAsClass(data.newObject); } else { this.addComment(data.description); const attributesTypes = data.options.map(this.getAttributeType.bind(this)); this.push0(`export type ${data.name} = ${this.getUnionType(attributesTypes)};\n`); } } /** Ex: * interface MyStruct { * att1: TypeA; * att2?: TypeB; * } * */ _transpileStructuAsInterface(data) { this.push0(`export interface ${data.name} {`); for (const [key, value] of Object.entries(data.properties)) { this._transpileMember(case_1.default.camel(key), value); } this.push0("}\n"); } /** Ex: * class MyStruct { * att1: TypeA; * att2?: TypeB; * * constructor(data: MyStruct) { * this.att1 = data.att1; * this.att2 = data.att2; * } * } * */ _transpileStructAsClass(data) { this.push0(`export class ${data.name} {`); const constructorBody = []; for (const [key, value] of Object.entries(data.properties)) { this._transpileMember(key, value); constructorBody.push(`this.${key} = data.${key};`); } this.push0(""); this.push1(`constructor(data: ${data.name}) {`); constructorBody.forEach((i) => this.push2(i)); this.push1("}"); this.push0("}\n"); } /** For Interface/Class attributes. * Ex: attribute1?: TypeA | null */ _transpileMember(memberName, memberNode) { const keyName = memberNode.isOptional ? `${memberName}?: ` : `${memberName}: `; const setNullable = memberNode.isNullable ? " | null" : ""; if (memberNode.description && !memberNode.reference && !this.isTranspilerable(memberNode)) { // Avoid duplicated descriptions for transpiled items. this.addComment(memberNode.description, `\n${this.indent[1]}`); } this.push1(`${keyName}${this.getAttributeType(memberNode)}${setNullable};`); } } exports.Zod2Ts = Zod2Ts;