UNPKG

zod-to-x

Version:

Multi language types generation from Zod schemas.

231 lines (230 loc) 9.18 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Zod2ProtoV3 = void 0; const case_1 = __importDefault(require("case")); const core_1 = require("../../core"); const number_limits_1 = require("../../utils/number_limits"); const options_1 = require("./options"); const allowedKeyTypes = [ "int32", "int64", "uint32", "uint64", "sint32", "sint64", "fixed32", "fixed64", "sfixed32", "sfixed64", "bool", "string", ]; /** * @deprecated Zod2ProtoV3 will not be considered as a transpilerable programming language, but as * another utility such as `zod2JsonSchemaDefinitions`. */ class Zod2ProtoV3 extends core_1.Zod2X { constructor(opt = {}) { super(Object.assign(Object.assign({}, options_1.defaultOpts), opt)); this.getUnionType = () => { /** Covered by "transpileUnion" method */ return ""; }; this.getComment = (data, indent = "") => `${indent}// ${data}`; this.getBooleanType = () => "bool"; this.getStringType = () => "string"; this.getNumberType = (isInt, range) => { if (!isInt) { return "double"; } if ((range === null || range === void 0 ? void 0 : range.min) >= number_limits_1.UINT32_RANGES[0]) { if ((range === null || range === void 0 ? void 0 : range.max) <= number_limits_1.UINT32_RANGES[1]) { return "uint32"; } else { return "uint64"; } } else { if ((range === null || range === void 0 ? void 0 : range.max) <= number_limits_1.INT32_RANGES[1] && (range === null || range === void 0 ? void 0 : range.min) >= number_limits_1.INT32_RANGES[0]) { return "int32"; } else { return "int64"; } } }; this.getAnyType = () => { this.imports.add(`import "google/protobuf/any.proto";`); return "google.protobuf.Any"; }; this.getDateType = () => { this.imports.add(`import "google/protobuf/timestamp.proto";`); return "google.protobuf.Timestamp"; }; this.getSetType = (itemType) => { return this.getArrayType(itemType, 1); }; /** * @description Determines the equivalent Protobuf type for a tuple based on its item types. * * Protobuf v3 does not directly support tuples. However, if all the types * in the tuple are identical, it can be represented as a `repeated` field * of that type. If the tuple contains mixed types, Protobuf cannot represent * it directly, and an alternative approach (e.g., defining a Protobuf message) * should be considered. * * @param itemsType - An array of strings representing the types of the tuple elements. * @returns A string representing the Protobuf type for the tuple. * If all tuple elements are of the same type, it returns a `repeated` field of that * type. * @throws NotTranspilerableTypeError if the tuple contains mixed types. */ this.getTupleType = (itemsType) => { const uniqueTypes = new Set(itemsType); if (uniqueTypes.size === 1) { return this.getArrayType(itemsType[0], 1); } else { throw new core_1.NotTranspilerableTypeError("Protobuf v3 does not support mixed-type tuples. Consider defining a message type."); } }; this.getIntersectionType = (itemsType) => { throw new core_1.NotTranspilerableTypeError("Protobuf v3 does not support intersection types directly."); }; } addImportFromFile(filename, namespace) { // Zod2ProtoV3 does not support layered modeling. return ""; } getTypeFromExternalNamespace(namespace, typeName) { // Zod2ProtoV3 does not support layered modeling. return ""; } addExtendedType(name, parentNamespace, parentTypeName) { // Zod2ProtoV3 does not support layered modeling. return; } getArrayType(arrayType, arrayDeep) { if (arrayDeep === 1) { return `repeated ${arrayType}`; } else { throw new core_1.NotTranspilerableTypeError("Protobuf v3 does not support multidimensional arrays directly. " + "You need to define nested message types for deeper arrays"); } } getLiteralStringType(value) { if (typeof value === "string") { return this.getStringType(); } else if (typeof value === "number") { return this.getNumberType(Number.isInteger(value), { min: value, max: value }); } else { throw new core_1.NotTranspilerableTypeError(`Protobuf v3 does not support Literals for this value type: ${value}`); } } getMapType(keyType, valueType) { if (!allowedKeyTypes.includes(keyType)) { throw new core_1.NotTranspilerableTypeError(`Protobuf map keys must be an integral or string type, got '${keyType}'.`); } return `map<${keyType}, ${valueType}>`; } getRecordType(keyType, valueType) { return this.getMapType(keyType, valueType); } transpileEnum(data) { if (data.isFromDiscriminatedUnion === true) { // Injected enum from ZodDiscriminatedUnion are not transpiled. return; } this.addComment(data.description); this.push0(`enum ${data.name} {`); data.values.forEach(([key, value], index) => { if (Number.isInteger(key.at(0))) { throw new core_1.NotTranspilerableTypeError(`Enumerate item name cannot start with number: ${key}`); } this.push1(`${key} = ${index};`); }); this.push0("}\n"); } transpileIntersection(data) { throw new core_1.NotTranspilerableTypeError(`Protobuf does not support message intersections.`); } transpileStruct(data) { this.addComment(data.description); this.push0(`message ${data.name} {`); Object.entries(data.properties).forEach(([key, value], index) => { if (value.description && !this.isTranspilerable(value)) { // Avoid duplicated descriptions for transpiled items. this.addComment(value.description, `\n${this.indent[1]}`); } this.push1(`${this.getAttributeType(value)} ${this._adaptField(key)} = ${index + 1};`); }); this.push0("}\n"); } /** * Transpiles a Zod union or discriminated union into a Protobuf-compatible `oneof` message. * * @limitations Currently supports `oneOf` for options that can be represented as a * Protobuf message or enum. Other types are not yet supported. * @param data The AST representation of a union or discriminated union, including its * common metadata. * @example * Input: * { * name: "UserContact", * options: ["EmailContact", "PhoneContact", "SocialContact"], * description: "Represents different ways to contact a user." * } * * Generated Output: * message UserContact { * oneof user_contact_oneof { * EmailContact email_contact = 1; * PhoneContact phone_contact = 2; * SocialContact social_contact = 3; * } * } */ transpileUnion(data) { this.addComment(data.description); const attributesTypes = data.options.map(this.getAttributeType.bind(this)); if (attributesTypes.find((i) => i.startsWith("map<") || i.startsWith("repeated "))) { throw new core_1.NotTranspilerableTypeError("Map and Repeated fields are not suported by Protobuf oneOf"); } this.push0(`message ${data.name} {`); this.push1(`oneof ${this._adaptField(data.name + "Oneof")} {`); attributesTypes.forEach((item, index) => { this.push2(`${item} ${this._adaptField(item)} = ${index + 1};`); }); this.push1(`}`); this.push0("}\n"); } runBefore() { var _a, _b; this.preImports.add(`syntax = "proto3";`); if ((_a = this.opt) === null || _a === void 0 ? void 0 : _a.packageName) { this.preImports.add(`package ${(_b = this.opt) === null || _b === void 0 ? void 0 : _b.packageName};`); } } runAfter() { } /** * Adapt field name according to user input. * @param fieldName * @returns */ _adaptField(fieldName) { if (this.opt.useCamelCase) { return case_1.default.camel(fieldName); } else { return case_1.default.snake(fieldName); } } } exports.Zod2ProtoV3 = Zod2ProtoV3;