@globalart/zod-to-proto 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +5 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +5 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -25,15 +25,6 @@ let inflection = require("inflection");
|
|
|
25
25
|
inflection = __toESM(inflection);
|
|
26
26
|
let zod = require("zod");
|
|
27
27
|
|
|
28
|
-
//#region src/types.ts
|
|
29
|
-
var UnsupportedTypeException = class extends Error {
|
|
30
|
-
constructor(type) {
|
|
31
|
-
super(`Unsupported type: ${type}`);
|
|
32
|
-
this.name = "UnsupportedTypeException";
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
//#endregion
|
|
37
28
|
//#region src/utils.ts
|
|
38
29
|
const getNumberTypeName = ({ value }) => {
|
|
39
30
|
return value.isInt ? "int32" : "double";
|
|
@@ -84,8 +75,8 @@ const traverseMap = ({ key, value, messages, enums, typePrefix }) => {
|
|
|
84
75
|
isInArray: true,
|
|
85
76
|
typePrefix
|
|
86
77
|
});
|
|
87
|
-
if (!keyType[0] || keyType.length !== 1)
|
|
88
|
-
if (!valueType[0] || valueType.length !== 1)
|
|
78
|
+
if (!keyType[0] || keyType.length !== 1) return [];
|
|
79
|
+
if (!valueType[0] || valueType.length !== 1) return [];
|
|
89
80
|
return [{
|
|
90
81
|
types: [`map<${protobufFieldToType({ field: keyType[0] })}, ${protobufFieldToType({ field: valueType[0] })}>`],
|
|
91
82
|
name: key
|
|
@@ -181,11 +172,11 @@ const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typeP
|
|
|
181
172
|
name: key
|
|
182
173
|
}];
|
|
183
174
|
}
|
|
184
|
-
if (value instanceof zod.ZodType)
|
|
185
|
-
|
|
175
|
+
if (value instanceof zod.ZodType) return [];
|
|
176
|
+
return [];
|
|
186
177
|
};
|
|
187
178
|
const traverseSchema = ({ schema, messages, enums, typePrefix }) => {
|
|
188
|
-
if (!schema || typeof schema !== "object" || !("_def" in schema) || schema.constructor.name !== "ZodObject" && schema._def.type !== "object")
|
|
179
|
+
if (!schema || typeof schema !== "object" || !("_def" in schema) || schema.constructor.name !== "ZodObject" && schema._def.type !== "object") return [];
|
|
189
180
|
const zodObject = schema;
|
|
190
181
|
return Object.entries(zodObject.shape).flatMap(([key, value]) => {
|
|
191
182
|
return traverseKey({
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["ZodArray","ZodSet","ZodOptional","ZodNullable","ZodMap","ZodObject","ZodString","ZodNumber","ZodBoolean","ZodEnum","ZodDate","ZodBigInt","ZodTuple","tupleFields: ProtobufField[]","ZodType","methods: ServiceMethod[]","z"],"sources":["../src/types.ts","../src/utils.ts","../src/traversers.ts","../src/service-generator.ts","../src/zod-to-protobuf.ts"],"sourcesContent":["import type { ZodObject, ZodTypeAny } from \"zod\";\n\nexport type ServicesInput =\n | ServiceDefinition[]\n | Record<string, ZodObject<any>>;\n\nexport interface ZodToProtobufOptions {\n packageName?: string;\n rootMessageName?: string;\n typePrefix?: string;\n services?: ServicesInput;\n skipRootMessage?: boolean;\n}\n\nexport interface ServiceMethod {\n name: string;\n request: ZodTypeAny;\n response: ZodTypeAny;\n streaming?: \"client\" | \"server\" | \"bidirectional\";\n}\n\nexport interface ServiceDefinition {\n name: string;\n methods: ServiceMethod[];\n}\n\nexport class UnsupportedTypeException extends Error {\n constructor(type: string) {\n super(`Unsupported type: ${type}`);\n this.name = \"UnsupportedTypeException\";\n }\n}\n\nexport interface ProtobufField {\n types: Array<string | null>;\n name: string;\n}\n","import { ZodNumber } from \"zod\";\nimport type { ProtobufField } from \"./types\";\n\nexport const getNumberTypeName = ({ value }: { value: ZodNumber }): string => {\n return value.isInt ? \"int32\" : \"double\";\n};\n\nexport const toPascalCase = ({ value }: { value: string }): string => {\n return value\n .split(\".\")\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\"\");\n};\n\nexport const protobufFieldToType = ({\n field,\n}: {\n field: ProtobufField;\n}): string => {\n return field.types.filter(Boolean).join(\" \");\n};\n","import * as inflection from \"inflection\";\nimport {\n ZodArray,\n ZodBigInt,\n ZodBoolean,\n ZodDate,\n ZodEnum,\n ZodMap,\n ZodNullable,\n ZodNumber,\n ZodObject,\n ZodOptional,\n ZodSet,\n ZodString,\n ZodTuple,\n ZodType,\n type ZodTypeAny,\n} from \"zod\";\nimport { UnsupportedTypeException, type ProtobufField } from \"./types\";\nimport { getNumberTypeName, toPascalCase, protobufFieldToType } from \"./utils\";\n\nexport const traverseArray = ({\n key,\n value,\n messages,\n enums,\n typePrefix,\n}: {\n key: string;\n value: ZodArray<ZodTypeAny> | ZodSet<ZodTypeAny>;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}): ProtobufField[] => {\n const nestedValue =\n value instanceof ZodArray\n ? value.element\n : value instanceof ZodSet\n ? (value._def as { valueType: ZodTypeAny }).valueType\n : // @ts-expect-error\n (value._def as { element?: ZodTypeAny }).element;\n\n const singularKey = inflection.singularize(key);\n const elementFields = traverseKey({\n key: singularKey,\n value: nestedValue,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n });\n return elementFields.map((field) => ({\n ...field,\n types: [\"repeated\", ...field.types],\n name: field.name.replace(singularKey, key),\n }));\n};\n\nexport const traverseMap = ({\n key,\n value,\n messages,\n enums,\n typePrefix,\n}: {\n key: string;\n value: ZodMap<ZodTypeAny, ZodTypeAny>;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}): ProtobufField[] => {\n const mapDef = (value._def || value.def) as {\n keyType?: ZodTypeAny;\n valueType?: ZodTypeAny;\n };\n\n const keyType = traverseKey({\n key: inflection.singularize(key),\n value:\n mapDef.keyType ||\n (value as ZodTypeAny & { keyType?: ZodTypeAny }).keyType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n });\n const valueType = traverseKey({\n key: inflection.singularize(key),\n value:\n mapDef.valueType ||\n (value as ZodTypeAny & { valueType?: ZodTypeAny }).valueType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n });\n\n if (!keyType[0] || keyType.length !== 1) {\n throw new UnsupportedTypeException(`${key} map key`);\n }\n\n if (!valueType[0] || valueType.length !== 1) {\n throw new UnsupportedTypeException(`${key} map value`);\n }\n\n const mapType = `map<${protobufFieldToType({ field: keyType[0] })}, ${protobufFieldToType({ field: valueType[0] })}>`;\n return [\n {\n types: [mapType],\n name: key,\n },\n ];\n};\n\nexport const traverseKey = ({\n key,\n value,\n messages,\n enums,\n isOptional,\n isInArray,\n typePrefix,\n}: {\n key: string;\n value: unknown;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n isOptional: boolean;\n isInArray: boolean;\n typePrefix: string | null;\n}): ProtobufField[] => {\n if (!value) {\n return [];\n }\n\n if (value instanceof ZodOptional || value instanceof ZodNullable) {\n return traverseKey({\n key,\n value: value.unwrap(),\n messages,\n enums,\n isOptional: true,\n isInArray,\n typePrefix,\n });\n }\n\n if (value instanceof ZodArray || value instanceof ZodSet) {\n return traverseArray({\n key,\n value: value as ZodArray<ZodTypeAny> | ZodSet<ZodTypeAny>,\n messages,\n enums,\n typePrefix,\n });\n }\n\n if (value instanceof ZodMap) {\n return traverseMap({\n key,\n value: value as ZodMap<ZodTypeAny, ZodTypeAny>,\n messages,\n enums,\n typePrefix,\n });\n }\n\n const optional = isOptional && !isInArray ? \"optional\" : null;\n\n if (value instanceof ZodObject) {\n let messageName = toPascalCase({ value: key });\n if (typePrefix) {\n messageName = `${typePrefix}${messageName}`;\n }\n const nestedMessageFields = traverseSchema({\n schema: value,\n messages,\n enums,\n typePrefix,\n });\n messages.set(messageName, nestedMessageFields);\n return [\n {\n types: [optional, messageName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodString) {\n return [\n {\n types: [optional, \"string\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodNumber) {\n const typeName = getNumberTypeName({ value });\n return [\n {\n types: [optional, typeName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodBoolean) {\n return [\n {\n types: [optional, \"bool\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodEnum) {\n const enumFields = value.options\n .map(\n (option: string | number, index: number) =>\n ` ${String(option)} = ${index};`\n )\n .join(\"\\n\");\n let enumName = toPascalCase({ value: key });\n if (typePrefix) {\n enumName = `${typePrefix}${enumName}`;\n }\n enums.set(enumName, [`enum ${enumName} {\\n${enumFields}\\n}`]);\n return [\n {\n types: [optional, enumName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodDate) {\n return [\n {\n types: [optional, \"string\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodBigInt) {\n return [\n {\n types: [optional, \"int64\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodTuple) {\n const tupleFields: ProtobufField[] = (\n value._def.items as ZodTypeAny[]\n ).flatMap((item: ZodTypeAny, index: number) => {\n return traverseKey({\n key: `${key}_${index}`,\n value: item,\n messages,\n enums,\n isOptional: false,\n isInArray,\n typePrefix,\n });\n });\n\n const tupleMessageName = toPascalCase({ value: key });\n messages.set(\n tupleMessageName,\n tupleFields.map(\n (field, index) =>\n ` ${field.types.join(\" \")} ${field.name} = ${index + 1};`\n )\n );\n return [\n {\n types: [optional, tupleMessageName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodType) {\n throw new UnsupportedTypeException(value.constructor.name);\n }\n\n throw new UnsupportedTypeException(typeof value);\n};\n\nexport const traverseSchema = ({\n schema,\n messages,\n enums,\n typePrefix,\n}: {\n schema: ZodTypeAny;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}): string[] => {\n if (\n !schema ||\n typeof schema !== \"object\" ||\n !(\"_def\" in schema) ||\n (schema.constructor.name !== \"ZodObject\" &&\n (schema._def as { type?: string }).type !== \"object\")\n ) {\n throw new UnsupportedTypeException(\n schema?.constructor?.name || typeof schema\n );\n }\n\n const zodObject = schema as ZodObject<any>;\n const fields = Object.entries(zodObject.shape).flatMap(([key, value]) => {\n return traverseKey({\n key,\n value,\n messages,\n enums,\n isOptional: false,\n isInArray: false,\n typePrefix,\n });\n });\n\n return fields.map(\n (field, index) =>\n `${protobufFieldToType({ field })} ${field.name} = ${index + 1};`\n );\n};\n","import { z, type ZodFunction, ZodObject, type ZodTypeAny } from \"zod\";\nimport type { ServiceDefinition, ServiceMethod, ServicesInput } from \"./types\";\nimport { toPascalCase } from \"./utils\";\nimport { traverseSchema } from \"./traversers\";\n\ninterface ServiceGenerationContext {\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}\n\nconst parseZodServiceSchema = (\n name: string,\n schema: ZodObject<Record<string, ZodTypeAny>>\n): ServiceDefinition => {\n const shape = schema.shape as Record<string, ZodTypeAny>;\n const methods: ServiceMethod[] = [];\n\n for (const [methodName, methodSchema] of Object.entries(shape)) {\n const methodDef = (methodSchema as ZodTypeAny)._def as {\n type?: string;\n input?: ZodTypeAny;\n output?: ZodTypeAny;\n };\n\n if (methodDef.type === \"function\") {\n const inputDef = methodDef.input as ZodTypeAny & {\n def?: { items?: ZodTypeAny[] };\n };\n\n const args = inputDef?.def?.items ?? [];\n const output = methodDef.output as ZodTypeAny;\n\n if (args.length > 0 && args[0] && output) {\n const request = args[0];\n const response = output;\n\n methods.push({\n name: methodName,\n request,\n response,\n });\n }\n }\n }\n\n return {\n name,\n methods,\n };\n};\n\nconst normalizeServices = (services: ServicesInput): ServiceDefinition[] => {\n if (Array.isArray(services)) {\n return services;\n }\n\n return Object.entries(services).map(([name, schema]) =>\n parseZodServiceSchema(name, schema)\n );\n};\n\nconst ensureZodObject = (\n schema: ZodTypeAny\n): ZodObject<Record<string, ZodTypeAny>> => {\n const schemaType =\n (schema._def as { type?: string }).type || schema.constructor.name;\n\n if (schemaType === \"object\" || schema.constructor.name === \"ZodObject\") {\n return schema as ZodObject<Record<string, ZodTypeAny>>;\n }\n\n return z.object({\n data: schema,\n });\n};\n\nconst generateRequestMessageName = (\n methodName: string,\n typePrefix: string | null\n): string => {\n const messageName = toPascalCase({ value: `${methodName}Request` });\n return typePrefix ? `${typePrefix}${messageName}` : messageName;\n};\n\nconst generateResponseMessageName = (\n methodName: string,\n typePrefix: string | null\n): string => {\n const messageName = toPascalCase({ value: `${methodName}Response` });\n return typePrefix ? `${typePrefix}${messageName}` : messageName;\n};\n\nconst processServiceMethod = (\n method: ServiceMethod,\n context: ServiceGenerationContext\n): { requestName: string; responseName: string } => {\n const { messages, enums, typePrefix } = context;\n\n const requestName = generateRequestMessageName(method.name, typePrefix);\n const responseName = generateResponseMessageName(method.name, typePrefix);\n\n if (!messages.has(requestName)) {\n const requestSchema = ensureZodObject(method.request);\n const requestFields = traverseSchema({\n schema: requestSchema,\n messages,\n enums,\n typePrefix,\n });\n messages.set(requestName, requestFields);\n }\n\n if (!messages.has(responseName)) {\n const responseSchema = ensureZodObject(method.response);\n const responseFields = traverseSchema({\n schema: responseSchema,\n messages,\n enums,\n typePrefix,\n });\n messages.set(responseName, responseFields);\n }\n\n return { requestName, responseName };\n};\n\nexport const generateServices = (\n services: ServicesInput,\n context: ServiceGenerationContext\n): string[] => {\n const normalizedServices = normalizeServices(services);\n\n return normalizedServices.map((service) => {\n const methods = service.methods.map((method) => {\n const { requestName, responseName } = processServiceMethod(\n method,\n context\n );\n\n const requestStreaming =\n method.streaming === \"client\" || method.streaming === \"bidirectional\";\n const responseStreaming =\n method.streaming === \"server\" || method.streaming === \"bidirectional\";\n\n const requestType = requestStreaming\n ? `stream ${requestName}`\n : requestName;\n const responseType = responseStreaming\n ? `stream ${responseName}`\n : responseName;\n\n return ` rpc ${toPascalCase({ value: method.name })}(${requestType}) returns (${responseType});`;\n });\n\n return `service ${toPascalCase({ value: service.name })} {\\n${methods.join(\"\\n\")}\\n}`;\n });\n};\n","import type { ZodTypeAny } from \"zod\";\nimport type { ZodToProtobufOptions } from \"./types\";\nimport { traverseSchema } from \"./traversers\";\nimport { generateServices } from \"./service-generator\";\n\nexport const zodToProtobuf = (\n schema?: ZodTypeAny,\n options: ZodToProtobufOptions = {}\n): string => {\n const {\n packageName = \"default\",\n rootMessageName = \"Message\",\n typePrefix = \"\",\n services,\n skipRootMessage = false,\n } = options;\n\n const messages = new Map<string, string[]>();\n const enums = new Map<string, string[]>();\n\n if (schema && !skipRootMessage) {\n const fields = traverseSchema({ schema, messages, enums, typePrefix });\n if (fields.length > 0) {\n const rootMessageKey = `${typePrefix}${rootMessageName}`;\n messages.set(rootMessageKey, fields);\n }\n }\n\n const context = {\n messages,\n enums,\n typePrefix: typePrefix || null,\n };\n\n const hasServices =\n services &&\n (Array.isArray(services)\n ? services.length > 0\n : Object.keys(services).length > 0);\n\n const servicesString = hasServices ? generateServices(services, context) : [];\n\n const enumsString = Array.from(enums.values()).map((enumDef) =>\n enumDef.join(\"\\n\")\n );\n\n const messagesString = Array.from(messages.entries()).map(\n ([name, fields]) =>\n `message ${name} {\\n${fields.map((field) => ` ${field}`).join(\"\\n\")}\\n}`\n );\n\n const content = [enumsString, messagesString, servicesString]\n .filter((strings) => !!strings.length)\n .map((strings) => strings.join(\"\\n\\n\"))\n .join(\"\\n\\n\");\n\n const protoDefinition = `\nsyntax = \"proto3\";\npackage ${packageName};\n\n${content}\n`;\n\n return protoDefinition.trim();\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["ZodArray","ZodSet","ZodOptional","ZodNullable","ZodMap","ZodObject","ZodString","ZodNumber","ZodBoolean","ZodEnum","ZodDate","ZodBigInt","ZodTuple","tupleFields: ProtobufField[]","ZodType","methods: ServiceMethod[]","z"],"sources":["../src/utils.ts","../src/traversers.ts","../src/service-generator.ts","../src/zod-to-protobuf.ts"],"sourcesContent":["import { ZodNumber } from \"zod\";\nimport type { ProtobufField } from \"./types\";\n\nexport const getNumberTypeName = ({ value }: { value: ZodNumber }): string => {\n return value.isInt ? \"int32\" : \"double\";\n};\n\nexport const toPascalCase = ({ value }: { value: string }): string => {\n return value\n .split(\".\")\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\"\");\n};\n\nexport const protobufFieldToType = ({\n field,\n}: {\n field: ProtobufField;\n}): string => {\n return field.types.filter(Boolean).join(\" \");\n};\n","import * as inflection from \"inflection\";\nimport {\n ZodArray,\n ZodBigInt,\n ZodBoolean,\n ZodDate,\n ZodEnum,\n ZodMap,\n ZodNullable,\n ZodNumber,\n ZodObject,\n ZodOptional,\n ZodSet,\n ZodString,\n ZodTuple,\n ZodType,\n type ZodTypeAny,\n} from \"zod\";\nimport { UnsupportedTypeException, type ProtobufField } from \"./types\";\nimport { getNumberTypeName, toPascalCase, protobufFieldToType } from \"./utils\";\n\nexport const traverseArray = ({\n key,\n value,\n messages,\n enums,\n typePrefix,\n}: {\n key: string;\n value: ZodArray<ZodTypeAny> | ZodSet<ZodTypeAny>;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}): ProtobufField[] => {\n const nestedValue =\n value instanceof ZodArray\n ? value.element\n : value instanceof ZodSet\n ? (value._def as { valueType: ZodTypeAny }).valueType\n : // @ts-expect-error\n (value._def as { element?: ZodTypeAny }).element;\n\n const singularKey = inflection.singularize(key);\n const elementFields = traverseKey({\n key: singularKey,\n value: nestedValue,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n });\n return elementFields.map((field) => ({\n ...field,\n types: [\"repeated\", ...field.types],\n name: field.name.replace(singularKey, key),\n }));\n};\n\nexport const traverseMap = ({\n key,\n value,\n messages,\n enums,\n typePrefix,\n}: {\n key: string;\n value: ZodMap<ZodTypeAny, ZodTypeAny>;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}): ProtobufField[] => {\n const mapDef = (value._def || value.def) as {\n keyType?: ZodTypeAny;\n valueType?: ZodTypeAny;\n };\n\n const keyType = traverseKey({\n key: inflection.singularize(key),\n value:\n mapDef.keyType ||\n (value as ZodTypeAny & { keyType?: ZodTypeAny }).keyType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n });\n const valueType = traverseKey({\n key: inflection.singularize(key),\n value:\n mapDef.valueType ||\n (value as ZodTypeAny & { valueType?: ZodTypeAny }).valueType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n });\n\n if (!keyType[0] || keyType.length !== 1) {\n return [];\n }\n\n if (!valueType[0] || valueType.length !== 1) {\n return [];\n }\n\n const mapType = `map<${protobufFieldToType({ field: keyType[0] })}, ${protobufFieldToType({ field: valueType[0] })}>`;\n return [\n {\n types: [mapType],\n name: key,\n },\n ];\n};\n\nexport const traverseKey = ({\n key,\n value,\n messages,\n enums,\n isOptional,\n isInArray,\n typePrefix,\n}: {\n key: string;\n value: unknown;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n isOptional: boolean;\n isInArray: boolean;\n typePrefix: string | null;\n}): ProtobufField[] => {\n if (!value) {\n return [];\n }\n\n if (value instanceof ZodOptional || value instanceof ZodNullable) {\n return traverseKey({\n key,\n value: value.unwrap(),\n messages,\n enums,\n isOptional: true,\n isInArray,\n typePrefix,\n });\n }\n\n if (value instanceof ZodArray || value instanceof ZodSet) {\n return traverseArray({\n key,\n value: value as ZodArray<ZodTypeAny> | ZodSet<ZodTypeAny>,\n messages,\n enums,\n typePrefix,\n });\n }\n\n if (value instanceof ZodMap) {\n return traverseMap({\n key,\n value: value as ZodMap<ZodTypeAny, ZodTypeAny>,\n messages,\n enums,\n typePrefix,\n });\n }\n\n const optional = isOptional && !isInArray ? \"optional\" : null;\n\n if (value instanceof ZodObject) {\n let messageName = toPascalCase({ value: key });\n if (typePrefix) {\n messageName = `${typePrefix}${messageName}`;\n }\n const nestedMessageFields = traverseSchema({\n schema: value,\n messages,\n enums,\n typePrefix,\n });\n messages.set(messageName, nestedMessageFields);\n return [\n {\n types: [optional, messageName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodString) {\n return [\n {\n types: [optional, \"string\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodNumber) {\n const typeName = getNumberTypeName({ value });\n return [\n {\n types: [optional, typeName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodBoolean) {\n return [\n {\n types: [optional, \"bool\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodEnum) {\n const enumFields = value.options\n .map(\n (option: string | number, index: number) =>\n ` ${String(option)} = ${index};`\n )\n .join(\"\\n\");\n let enumName = toPascalCase({ value: key });\n if (typePrefix) {\n enumName = `${typePrefix}${enumName}`;\n }\n enums.set(enumName, [`enum ${enumName} {\\n${enumFields}\\n}`]);\n return [\n {\n types: [optional, enumName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodDate) {\n return [\n {\n types: [optional, \"string\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodBigInt) {\n return [\n {\n types: [optional, \"int64\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodTuple) {\n const tupleFields: ProtobufField[] = (\n value._def.items as ZodTypeAny[]\n ).flatMap((item: ZodTypeAny, index: number) => {\n return traverseKey({\n key: `${key}_${index}`,\n value: item,\n messages,\n enums,\n isOptional: false,\n isInArray,\n typePrefix,\n });\n });\n\n const tupleMessageName = toPascalCase({ value: key });\n messages.set(\n tupleMessageName,\n tupleFields.map(\n (field, index) =>\n ` ${field.types.join(\" \")} ${field.name} = ${index + 1};`\n )\n );\n return [\n {\n types: [optional, tupleMessageName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodType) {\n return [];\n }\n\n return [];\n};\n\nexport const traverseSchema = ({\n schema,\n messages,\n enums,\n typePrefix,\n}: {\n schema: ZodTypeAny;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}): string[] => {\n if (\n !schema ||\n typeof schema !== \"object\" ||\n !(\"_def\" in schema) ||\n (schema.constructor.name !== \"ZodObject\" &&\n (schema._def as { type?: string }).type !== \"object\")\n ) {\n return [];\n }\n\n const zodObject = schema as ZodObject<any>;\n const fields = Object.entries(zodObject.shape).flatMap(([key, value]) => {\n return traverseKey({\n key,\n value,\n messages,\n enums,\n isOptional: false,\n isInArray: false,\n typePrefix,\n });\n });\n\n return fields.map(\n (field, index) =>\n `${protobufFieldToType({ field })} ${field.name} = ${index + 1};`\n );\n};\n","import { z, type ZodFunction, ZodObject, type ZodTypeAny } from \"zod\";\nimport type { ServiceDefinition, ServiceMethod, ServicesInput } from \"./types\";\nimport { toPascalCase } from \"./utils\";\nimport { traverseSchema } from \"./traversers\";\n\ninterface ServiceGenerationContext {\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}\n\nconst parseZodServiceSchema = (\n name: string,\n schema: ZodObject<Record<string, ZodTypeAny>>\n): ServiceDefinition => {\n const shape = schema.shape as Record<string, ZodTypeAny>;\n const methods: ServiceMethod[] = [];\n\n for (const [methodName, methodSchema] of Object.entries(shape)) {\n const methodDef = (methodSchema as ZodTypeAny)._def as {\n type?: string;\n input?: ZodTypeAny;\n output?: ZodTypeAny;\n };\n\n if (methodDef.type === \"function\") {\n const inputDef = methodDef.input as ZodTypeAny & {\n def?: { items?: ZodTypeAny[] };\n };\n\n const args = inputDef?.def?.items ?? [];\n const output = methodDef.output as ZodTypeAny;\n\n if (args.length > 0 && args[0] && output) {\n const request = args[0];\n const response = output;\n\n methods.push({\n name: methodName,\n request,\n response,\n });\n }\n }\n }\n\n return {\n name,\n methods,\n };\n};\n\nconst normalizeServices = (services: ServicesInput): ServiceDefinition[] => {\n if (Array.isArray(services)) {\n return services;\n }\n\n return Object.entries(services).map(([name, schema]) =>\n parseZodServiceSchema(name, schema)\n );\n};\n\nconst ensureZodObject = (\n schema: ZodTypeAny\n): ZodObject<Record<string, ZodTypeAny>> => {\n const schemaType =\n (schema._def as { type?: string }).type || schema.constructor.name;\n\n if (schemaType === \"object\" || schema.constructor.name === \"ZodObject\") {\n return schema as ZodObject<Record<string, ZodTypeAny>>;\n }\n\n return z.object({\n data: schema,\n });\n};\n\nconst generateRequestMessageName = (\n methodName: string,\n typePrefix: string | null\n): string => {\n const messageName = toPascalCase({ value: `${methodName}Request` });\n return typePrefix ? `${typePrefix}${messageName}` : messageName;\n};\n\nconst generateResponseMessageName = (\n methodName: string,\n typePrefix: string | null\n): string => {\n const messageName = toPascalCase({ value: `${methodName}Response` });\n return typePrefix ? `${typePrefix}${messageName}` : messageName;\n};\n\nconst processServiceMethod = (\n method: ServiceMethod,\n context: ServiceGenerationContext\n): { requestName: string; responseName: string } => {\n const { messages, enums, typePrefix } = context;\n\n const requestName = generateRequestMessageName(method.name, typePrefix);\n const responseName = generateResponseMessageName(method.name, typePrefix);\n\n if (!messages.has(requestName)) {\n const requestSchema = ensureZodObject(method.request);\n const requestFields = traverseSchema({\n schema: requestSchema,\n messages,\n enums,\n typePrefix,\n });\n messages.set(requestName, requestFields);\n }\n\n if (!messages.has(responseName)) {\n const responseSchema = ensureZodObject(method.response);\n const responseFields = traverseSchema({\n schema: responseSchema,\n messages,\n enums,\n typePrefix,\n });\n messages.set(responseName, responseFields);\n }\n\n return { requestName, responseName };\n};\n\nexport const generateServices = (\n services: ServicesInput,\n context: ServiceGenerationContext\n): string[] => {\n const normalizedServices = normalizeServices(services);\n\n return normalizedServices.map((service) => {\n const methods = service.methods.map((method) => {\n const { requestName, responseName } = processServiceMethod(\n method,\n context\n );\n\n const requestStreaming =\n method.streaming === \"client\" || method.streaming === \"bidirectional\";\n const responseStreaming =\n method.streaming === \"server\" || method.streaming === \"bidirectional\";\n\n const requestType = requestStreaming\n ? `stream ${requestName}`\n : requestName;\n const responseType = responseStreaming\n ? `stream ${responseName}`\n : responseName;\n\n return ` rpc ${toPascalCase({ value: method.name })}(${requestType}) returns (${responseType});`;\n });\n\n return `service ${toPascalCase({ value: service.name })} {\\n${methods.join(\"\\n\")}\\n}`;\n });\n};\n","import type { ZodTypeAny } from \"zod\";\nimport type { ZodToProtobufOptions } from \"./types\";\nimport { traverseSchema } from \"./traversers\";\nimport { generateServices } from \"./service-generator\";\n\nexport const zodToProtobuf = (\n schema?: ZodTypeAny,\n options: ZodToProtobufOptions = {}\n): string => {\n const {\n packageName = \"default\",\n rootMessageName = \"Message\",\n typePrefix = \"\",\n services,\n skipRootMessage = false,\n } = options;\n\n const messages = new Map<string, string[]>();\n const enums = new Map<string, string[]>();\n\n if (schema && !skipRootMessage) {\n const fields = traverseSchema({ schema, messages, enums, typePrefix });\n if (fields.length > 0) {\n const rootMessageKey = `${typePrefix}${rootMessageName}`;\n messages.set(rootMessageKey, fields);\n }\n }\n\n const context = {\n messages,\n enums,\n typePrefix: typePrefix || null,\n };\n\n const hasServices =\n services &&\n (Array.isArray(services)\n ? services.length > 0\n : Object.keys(services).length > 0);\n\n const servicesString = hasServices ? generateServices(services, context) : [];\n\n const enumsString = Array.from(enums.values()).map((enumDef) =>\n enumDef.join(\"\\n\")\n );\n\n const messagesString = Array.from(messages.entries()).map(\n ([name, fields]) =>\n `message ${name} {\\n${fields.map((field) => ` ${field}`).join(\"\\n\")}\\n}`\n );\n\n const content = [enumsString, messagesString, servicesString]\n .filter((strings) => !!strings.length)\n .map((strings) => strings.join(\"\\n\\n\"))\n .join(\"\\n\\n\");\n\n const protoDefinition = `\nsyntax = \"proto3\";\npackage ${packageName};\n\n${content}\n`;\n\n return protoDefinition.trim();\n};\n"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
import * as inflection from "inflection";
|
|
2
2
|
import { ZodArray, ZodBigInt, ZodBoolean, ZodDate, ZodEnum, ZodMap, ZodNullable, ZodNumber, ZodObject, ZodOptional, ZodSet, ZodString, ZodTuple, ZodType, z } from "zod";
|
|
3
3
|
|
|
4
|
-
//#region src/types.ts
|
|
5
|
-
var UnsupportedTypeException = class extends Error {
|
|
6
|
-
constructor(type) {
|
|
7
|
-
super(`Unsupported type: ${type}`);
|
|
8
|
-
this.name = "UnsupportedTypeException";
|
|
9
|
-
}
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
//#endregion
|
|
13
4
|
//#region src/utils.ts
|
|
14
5
|
const getNumberTypeName = ({ value }) => {
|
|
15
6
|
return value.isInt ? "int32" : "double";
|
|
@@ -60,8 +51,8 @@ const traverseMap = ({ key, value, messages, enums, typePrefix }) => {
|
|
|
60
51
|
isInArray: true,
|
|
61
52
|
typePrefix
|
|
62
53
|
});
|
|
63
|
-
if (!keyType[0] || keyType.length !== 1)
|
|
64
|
-
if (!valueType[0] || valueType.length !== 1)
|
|
54
|
+
if (!keyType[0] || keyType.length !== 1) return [];
|
|
55
|
+
if (!valueType[0] || valueType.length !== 1) return [];
|
|
65
56
|
return [{
|
|
66
57
|
types: [`map<${protobufFieldToType({ field: keyType[0] })}, ${protobufFieldToType({ field: valueType[0] })}>`],
|
|
67
58
|
name: key
|
|
@@ -157,11 +148,11 @@ const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typeP
|
|
|
157
148
|
name: key
|
|
158
149
|
}];
|
|
159
150
|
}
|
|
160
|
-
if (value instanceof ZodType)
|
|
161
|
-
|
|
151
|
+
if (value instanceof ZodType) return [];
|
|
152
|
+
return [];
|
|
162
153
|
};
|
|
163
154
|
const traverseSchema = ({ schema, messages, enums, typePrefix }) => {
|
|
164
|
-
if (!schema || typeof schema !== "object" || !("_def" in schema) || schema.constructor.name !== "ZodObject" && schema._def.type !== "object")
|
|
155
|
+
if (!schema || typeof schema !== "object" || !("_def" in schema) || schema.constructor.name !== "ZodObject" && schema._def.type !== "object") return [];
|
|
165
156
|
const zodObject = schema;
|
|
166
157
|
return Object.entries(zodObject.shape).flatMap(([key, value]) => {
|
|
167
158
|
return traverseKey({
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["tupleFields: ProtobufField[]","methods: ServiceMethod[]"],"sources":["../src/types.ts","../src/utils.ts","../src/traversers.ts","../src/service-generator.ts","../src/zod-to-protobuf.ts"],"sourcesContent":["import type { ZodObject, ZodTypeAny } from \"zod\";\n\nexport type ServicesInput =\n | ServiceDefinition[]\n | Record<string, ZodObject<any>>;\n\nexport interface ZodToProtobufOptions {\n packageName?: string;\n rootMessageName?: string;\n typePrefix?: string;\n services?: ServicesInput;\n skipRootMessage?: boolean;\n}\n\nexport interface ServiceMethod {\n name: string;\n request: ZodTypeAny;\n response: ZodTypeAny;\n streaming?: \"client\" | \"server\" | \"bidirectional\";\n}\n\nexport interface ServiceDefinition {\n name: string;\n methods: ServiceMethod[];\n}\n\nexport class UnsupportedTypeException extends Error {\n constructor(type: string) {\n super(`Unsupported type: ${type}`);\n this.name = \"UnsupportedTypeException\";\n }\n}\n\nexport interface ProtobufField {\n types: Array<string | null>;\n name: string;\n}\n","import { ZodNumber } from \"zod\";\nimport type { ProtobufField } from \"./types\";\n\nexport const getNumberTypeName = ({ value }: { value: ZodNumber }): string => {\n return value.isInt ? \"int32\" : \"double\";\n};\n\nexport const toPascalCase = ({ value }: { value: string }): string => {\n return value\n .split(\".\")\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\"\");\n};\n\nexport const protobufFieldToType = ({\n field,\n}: {\n field: ProtobufField;\n}): string => {\n return field.types.filter(Boolean).join(\" \");\n};\n","import * as inflection from \"inflection\";\nimport {\n ZodArray,\n ZodBigInt,\n ZodBoolean,\n ZodDate,\n ZodEnum,\n ZodMap,\n ZodNullable,\n ZodNumber,\n ZodObject,\n ZodOptional,\n ZodSet,\n ZodString,\n ZodTuple,\n ZodType,\n type ZodTypeAny,\n} from \"zod\";\nimport { UnsupportedTypeException, type ProtobufField } from \"./types\";\nimport { getNumberTypeName, toPascalCase, protobufFieldToType } from \"./utils\";\n\nexport const traverseArray = ({\n key,\n value,\n messages,\n enums,\n typePrefix,\n}: {\n key: string;\n value: ZodArray<ZodTypeAny> | ZodSet<ZodTypeAny>;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}): ProtobufField[] => {\n const nestedValue =\n value instanceof ZodArray\n ? value.element\n : value instanceof ZodSet\n ? (value._def as { valueType: ZodTypeAny }).valueType\n : // @ts-expect-error\n (value._def as { element?: ZodTypeAny }).element;\n\n const singularKey = inflection.singularize(key);\n const elementFields = traverseKey({\n key: singularKey,\n value: nestedValue,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n });\n return elementFields.map((field) => ({\n ...field,\n types: [\"repeated\", ...field.types],\n name: field.name.replace(singularKey, key),\n }));\n};\n\nexport const traverseMap = ({\n key,\n value,\n messages,\n enums,\n typePrefix,\n}: {\n key: string;\n value: ZodMap<ZodTypeAny, ZodTypeAny>;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}): ProtobufField[] => {\n const mapDef = (value._def || value.def) as {\n keyType?: ZodTypeAny;\n valueType?: ZodTypeAny;\n };\n\n const keyType = traverseKey({\n key: inflection.singularize(key),\n value:\n mapDef.keyType ||\n (value as ZodTypeAny & { keyType?: ZodTypeAny }).keyType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n });\n const valueType = traverseKey({\n key: inflection.singularize(key),\n value:\n mapDef.valueType ||\n (value as ZodTypeAny & { valueType?: ZodTypeAny }).valueType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n });\n\n if (!keyType[0] || keyType.length !== 1) {\n throw new UnsupportedTypeException(`${key} map key`);\n }\n\n if (!valueType[0] || valueType.length !== 1) {\n throw new UnsupportedTypeException(`${key} map value`);\n }\n\n const mapType = `map<${protobufFieldToType({ field: keyType[0] })}, ${protobufFieldToType({ field: valueType[0] })}>`;\n return [\n {\n types: [mapType],\n name: key,\n },\n ];\n};\n\nexport const traverseKey = ({\n key,\n value,\n messages,\n enums,\n isOptional,\n isInArray,\n typePrefix,\n}: {\n key: string;\n value: unknown;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n isOptional: boolean;\n isInArray: boolean;\n typePrefix: string | null;\n}): ProtobufField[] => {\n if (!value) {\n return [];\n }\n\n if (value instanceof ZodOptional || value instanceof ZodNullable) {\n return traverseKey({\n key,\n value: value.unwrap(),\n messages,\n enums,\n isOptional: true,\n isInArray,\n typePrefix,\n });\n }\n\n if (value instanceof ZodArray || value instanceof ZodSet) {\n return traverseArray({\n key,\n value: value as ZodArray<ZodTypeAny> | ZodSet<ZodTypeAny>,\n messages,\n enums,\n typePrefix,\n });\n }\n\n if (value instanceof ZodMap) {\n return traverseMap({\n key,\n value: value as ZodMap<ZodTypeAny, ZodTypeAny>,\n messages,\n enums,\n typePrefix,\n });\n }\n\n const optional = isOptional && !isInArray ? \"optional\" : null;\n\n if (value instanceof ZodObject) {\n let messageName = toPascalCase({ value: key });\n if (typePrefix) {\n messageName = `${typePrefix}${messageName}`;\n }\n const nestedMessageFields = traverseSchema({\n schema: value,\n messages,\n enums,\n typePrefix,\n });\n messages.set(messageName, nestedMessageFields);\n return [\n {\n types: [optional, messageName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodString) {\n return [\n {\n types: [optional, \"string\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodNumber) {\n const typeName = getNumberTypeName({ value });\n return [\n {\n types: [optional, typeName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodBoolean) {\n return [\n {\n types: [optional, \"bool\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodEnum) {\n const enumFields = value.options\n .map(\n (option: string | number, index: number) =>\n ` ${String(option)} = ${index};`\n )\n .join(\"\\n\");\n let enumName = toPascalCase({ value: key });\n if (typePrefix) {\n enumName = `${typePrefix}${enumName}`;\n }\n enums.set(enumName, [`enum ${enumName} {\\n${enumFields}\\n}`]);\n return [\n {\n types: [optional, enumName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodDate) {\n return [\n {\n types: [optional, \"string\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodBigInt) {\n return [\n {\n types: [optional, \"int64\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodTuple) {\n const tupleFields: ProtobufField[] = (\n value._def.items as ZodTypeAny[]\n ).flatMap((item: ZodTypeAny, index: number) => {\n return traverseKey({\n key: `${key}_${index}`,\n value: item,\n messages,\n enums,\n isOptional: false,\n isInArray,\n typePrefix,\n });\n });\n\n const tupleMessageName = toPascalCase({ value: key });\n messages.set(\n tupleMessageName,\n tupleFields.map(\n (field, index) =>\n ` ${field.types.join(\" \")} ${field.name} = ${index + 1};`\n )\n );\n return [\n {\n types: [optional, tupleMessageName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodType) {\n throw new UnsupportedTypeException(value.constructor.name);\n }\n\n throw new UnsupportedTypeException(typeof value);\n};\n\nexport const traverseSchema = ({\n schema,\n messages,\n enums,\n typePrefix,\n}: {\n schema: ZodTypeAny;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}): string[] => {\n if (\n !schema ||\n typeof schema !== \"object\" ||\n !(\"_def\" in schema) ||\n (schema.constructor.name !== \"ZodObject\" &&\n (schema._def as { type?: string }).type !== \"object\")\n ) {\n throw new UnsupportedTypeException(\n schema?.constructor?.name || typeof schema\n );\n }\n\n const zodObject = schema as ZodObject<any>;\n const fields = Object.entries(zodObject.shape).flatMap(([key, value]) => {\n return traverseKey({\n key,\n value,\n messages,\n enums,\n isOptional: false,\n isInArray: false,\n typePrefix,\n });\n });\n\n return fields.map(\n (field, index) =>\n `${protobufFieldToType({ field })} ${field.name} = ${index + 1};`\n );\n};\n","import { z, type ZodFunction, ZodObject, type ZodTypeAny } from \"zod\";\nimport type { ServiceDefinition, ServiceMethod, ServicesInput } from \"./types\";\nimport { toPascalCase } from \"./utils\";\nimport { traverseSchema } from \"./traversers\";\n\ninterface ServiceGenerationContext {\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}\n\nconst parseZodServiceSchema = (\n name: string,\n schema: ZodObject<Record<string, ZodTypeAny>>\n): ServiceDefinition => {\n const shape = schema.shape as Record<string, ZodTypeAny>;\n const methods: ServiceMethod[] = [];\n\n for (const [methodName, methodSchema] of Object.entries(shape)) {\n const methodDef = (methodSchema as ZodTypeAny)._def as {\n type?: string;\n input?: ZodTypeAny;\n output?: ZodTypeAny;\n };\n\n if (methodDef.type === \"function\") {\n const inputDef = methodDef.input as ZodTypeAny & {\n def?: { items?: ZodTypeAny[] };\n };\n\n const args = inputDef?.def?.items ?? [];\n const output = methodDef.output as ZodTypeAny;\n\n if (args.length > 0 && args[0] && output) {\n const request = args[0];\n const response = output;\n\n methods.push({\n name: methodName,\n request,\n response,\n });\n }\n }\n }\n\n return {\n name,\n methods,\n };\n};\n\nconst normalizeServices = (services: ServicesInput): ServiceDefinition[] => {\n if (Array.isArray(services)) {\n return services;\n }\n\n return Object.entries(services).map(([name, schema]) =>\n parseZodServiceSchema(name, schema)\n );\n};\n\nconst ensureZodObject = (\n schema: ZodTypeAny\n): ZodObject<Record<string, ZodTypeAny>> => {\n const schemaType =\n (schema._def as { type?: string }).type || schema.constructor.name;\n\n if (schemaType === \"object\" || schema.constructor.name === \"ZodObject\") {\n return schema as ZodObject<Record<string, ZodTypeAny>>;\n }\n\n return z.object({\n data: schema,\n });\n};\n\nconst generateRequestMessageName = (\n methodName: string,\n typePrefix: string | null\n): string => {\n const messageName = toPascalCase({ value: `${methodName}Request` });\n return typePrefix ? `${typePrefix}${messageName}` : messageName;\n};\n\nconst generateResponseMessageName = (\n methodName: string,\n typePrefix: string | null\n): string => {\n const messageName = toPascalCase({ value: `${methodName}Response` });\n return typePrefix ? `${typePrefix}${messageName}` : messageName;\n};\n\nconst processServiceMethod = (\n method: ServiceMethod,\n context: ServiceGenerationContext\n): { requestName: string; responseName: string } => {\n const { messages, enums, typePrefix } = context;\n\n const requestName = generateRequestMessageName(method.name, typePrefix);\n const responseName = generateResponseMessageName(method.name, typePrefix);\n\n if (!messages.has(requestName)) {\n const requestSchema = ensureZodObject(method.request);\n const requestFields = traverseSchema({\n schema: requestSchema,\n messages,\n enums,\n typePrefix,\n });\n messages.set(requestName, requestFields);\n }\n\n if (!messages.has(responseName)) {\n const responseSchema = ensureZodObject(method.response);\n const responseFields = traverseSchema({\n schema: responseSchema,\n messages,\n enums,\n typePrefix,\n });\n messages.set(responseName, responseFields);\n }\n\n return { requestName, responseName };\n};\n\nexport const generateServices = (\n services: ServicesInput,\n context: ServiceGenerationContext\n): string[] => {\n const normalizedServices = normalizeServices(services);\n\n return normalizedServices.map((service) => {\n const methods = service.methods.map((method) => {\n const { requestName, responseName } = processServiceMethod(\n method,\n context\n );\n\n const requestStreaming =\n method.streaming === \"client\" || method.streaming === \"bidirectional\";\n const responseStreaming =\n method.streaming === \"server\" || method.streaming === \"bidirectional\";\n\n const requestType = requestStreaming\n ? `stream ${requestName}`\n : requestName;\n const responseType = responseStreaming\n ? `stream ${responseName}`\n : responseName;\n\n return ` rpc ${toPascalCase({ value: method.name })}(${requestType}) returns (${responseType});`;\n });\n\n return `service ${toPascalCase({ value: service.name })} {\\n${methods.join(\"\\n\")}\\n}`;\n });\n};\n","import type { ZodTypeAny } from \"zod\";\nimport type { ZodToProtobufOptions } from \"./types\";\nimport { traverseSchema } from \"./traversers\";\nimport { generateServices } from \"./service-generator\";\n\nexport const zodToProtobuf = (\n schema?: ZodTypeAny,\n options: ZodToProtobufOptions = {}\n): string => {\n const {\n packageName = \"default\",\n rootMessageName = \"Message\",\n typePrefix = \"\",\n services,\n skipRootMessage = false,\n } = options;\n\n const messages = new Map<string, string[]>();\n const enums = new Map<string, string[]>();\n\n if (schema && !skipRootMessage) {\n const fields = traverseSchema({ schema, messages, enums, typePrefix });\n if (fields.length > 0) {\n const rootMessageKey = `${typePrefix}${rootMessageName}`;\n messages.set(rootMessageKey, fields);\n }\n }\n\n const context = {\n messages,\n enums,\n typePrefix: typePrefix || null,\n };\n\n const hasServices =\n services &&\n (Array.isArray(services)\n ? services.length > 0\n : Object.keys(services).length > 0);\n\n const servicesString = hasServices ? generateServices(services, context) : [];\n\n const enumsString = Array.from(enums.values()).map((enumDef) =>\n enumDef.join(\"\\n\")\n );\n\n const messagesString = Array.from(messages.entries()).map(\n ([name, fields]) =>\n `message ${name} {\\n${fields.map((field) => ` ${field}`).join(\"\\n\")}\\n}`\n );\n\n const content = [enumsString, messagesString, servicesString]\n .filter((strings) => !!strings.length)\n .map((strings) => strings.join(\"\\n\\n\"))\n .join(\"\\n\\n\");\n\n const protoDefinition = `\nsyntax = \"proto3\";\npackage ${packageName};\n\n${content}\n`;\n\n return protoDefinition.trim();\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["tupleFields: ProtobufField[]","methods: ServiceMethod[]"],"sources":["../src/utils.ts","../src/traversers.ts","../src/service-generator.ts","../src/zod-to-protobuf.ts"],"sourcesContent":["import { ZodNumber } from \"zod\";\nimport type { ProtobufField } from \"./types\";\n\nexport const getNumberTypeName = ({ value }: { value: ZodNumber }): string => {\n return value.isInt ? \"int32\" : \"double\";\n};\n\nexport const toPascalCase = ({ value }: { value: string }): string => {\n return value\n .split(\".\")\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\"\");\n};\n\nexport const protobufFieldToType = ({\n field,\n}: {\n field: ProtobufField;\n}): string => {\n return field.types.filter(Boolean).join(\" \");\n};\n","import * as inflection from \"inflection\";\nimport {\n ZodArray,\n ZodBigInt,\n ZodBoolean,\n ZodDate,\n ZodEnum,\n ZodMap,\n ZodNullable,\n ZodNumber,\n ZodObject,\n ZodOptional,\n ZodSet,\n ZodString,\n ZodTuple,\n ZodType,\n type ZodTypeAny,\n} from \"zod\";\nimport { UnsupportedTypeException, type ProtobufField } from \"./types\";\nimport { getNumberTypeName, toPascalCase, protobufFieldToType } from \"./utils\";\n\nexport const traverseArray = ({\n key,\n value,\n messages,\n enums,\n typePrefix,\n}: {\n key: string;\n value: ZodArray<ZodTypeAny> | ZodSet<ZodTypeAny>;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}): ProtobufField[] => {\n const nestedValue =\n value instanceof ZodArray\n ? value.element\n : value instanceof ZodSet\n ? (value._def as { valueType: ZodTypeAny }).valueType\n : // @ts-expect-error\n (value._def as { element?: ZodTypeAny }).element;\n\n const singularKey = inflection.singularize(key);\n const elementFields = traverseKey({\n key: singularKey,\n value: nestedValue,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n });\n return elementFields.map((field) => ({\n ...field,\n types: [\"repeated\", ...field.types],\n name: field.name.replace(singularKey, key),\n }));\n};\n\nexport const traverseMap = ({\n key,\n value,\n messages,\n enums,\n typePrefix,\n}: {\n key: string;\n value: ZodMap<ZodTypeAny, ZodTypeAny>;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}): ProtobufField[] => {\n const mapDef = (value._def || value.def) as {\n keyType?: ZodTypeAny;\n valueType?: ZodTypeAny;\n };\n\n const keyType = traverseKey({\n key: inflection.singularize(key),\n value:\n mapDef.keyType ||\n (value as ZodTypeAny & { keyType?: ZodTypeAny }).keyType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n });\n const valueType = traverseKey({\n key: inflection.singularize(key),\n value:\n mapDef.valueType ||\n (value as ZodTypeAny & { valueType?: ZodTypeAny }).valueType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n });\n\n if (!keyType[0] || keyType.length !== 1) {\n return [];\n }\n\n if (!valueType[0] || valueType.length !== 1) {\n return [];\n }\n\n const mapType = `map<${protobufFieldToType({ field: keyType[0] })}, ${protobufFieldToType({ field: valueType[0] })}>`;\n return [\n {\n types: [mapType],\n name: key,\n },\n ];\n};\n\nexport const traverseKey = ({\n key,\n value,\n messages,\n enums,\n isOptional,\n isInArray,\n typePrefix,\n}: {\n key: string;\n value: unknown;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n isOptional: boolean;\n isInArray: boolean;\n typePrefix: string | null;\n}): ProtobufField[] => {\n if (!value) {\n return [];\n }\n\n if (value instanceof ZodOptional || value instanceof ZodNullable) {\n return traverseKey({\n key,\n value: value.unwrap(),\n messages,\n enums,\n isOptional: true,\n isInArray,\n typePrefix,\n });\n }\n\n if (value instanceof ZodArray || value instanceof ZodSet) {\n return traverseArray({\n key,\n value: value as ZodArray<ZodTypeAny> | ZodSet<ZodTypeAny>,\n messages,\n enums,\n typePrefix,\n });\n }\n\n if (value instanceof ZodMap) {\n return traverseMap({\n key,\n value: value as ZodMap<ZodTypeAny, ZodTypeAny>,\n messages,\n enums,\n typePrefix,\n });\n }\n\n const optional = isOptional && !isInArray ? \"optional\" : null;\n\n if (value instanceof ZodObject) {\n let messageName = toPascalCase({ value: key });\n if (typePrefix) {\n messageName = `${typePrefix}${messageName}`;\n }\n const nestedMessageFields = traverseSchema({\n schema: value,\n messages,\n enums,\n typePrefix,\n });\n messages.set(messageName, nestedMessageFields);\n return [\n {\n types: [optional, messageName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodString) {\n return [\n {\n types: [optional, \"string\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodNumber) {\n const typeName = getNumberTypeName({ value });\n return [\n {\n types: [optional, typeName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodBoolean) {\n return [\n {\n types: [optional, \"bool\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodEnum) {\n const enumFields = value.options\n .map(\n (option: string | number, index: number) =>\n ` ${String(option)} = ${index};`\n )\n .join(\"\\n\");\n let enumName = toPascalCase({ value: key });\n if (typePrefix) {\n enumName = `${typePrefix}${enumName}`;\n }\n enums.set(enumName, [`enum ${enumName} {\\n${enumFields}\\n}`]);\n return [\n {\n types: [optional, enumName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodDate) {\n return [\n {\n types: [optional, \"string\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodBigInt) {\n return [\n {\n types: [optional, \"int64\"],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodTuple) {\n const tupleFields: ProtobufField[] = (\n value._def.items as ZodTypeAny[]\n ).flatMap((item: ZodTypeAny, index: number) => {\n return traverseKey({\n key: `${key}_${index}`,\n value: item,\n messages,\n enums,\n isOptional: false,\n isInArray,\n typePrefix,\n });\n });\n\n const tupleMessageName = toPascalCase({ value: key });\n messages.set(\n tupleMessageName,\n tupleFields.map(\n (field, index) =>\n ` ${field.types.join(\" \")} ${field.name} = ${index + 1};`\n )\n );\n return [\n {\n types: [optional, tupleMessageName],\n name: key,\n },\n ];\n }\n\n if (value instanceof ZodType) {\n return [];\n }\n\n return [];\n};\n\nexport const traverseSchema = ({\n schema,\n messages,\n enums,\n typePrefix,\n}: {\n schema: ZodTypeAny;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}): string[] => {\n if (\n !schema ||\n typeof schema !== \"object\" ||\n !(\"_def\" in schema) ||\n (schema.constructor.name !== \"ZodObject\" &&\n (schema._def as { type?: string }).type !== \"object\")\n ) {\n return [];\n }\n\n const zodObject = schema as ZodObject<any>;\n const fields = Object.entries(zodObject.shape).flatMap(([key, value]) => {\n return traverseKey({\n key,\n value,\n messages,\n enums,\n isOptional: false,\n isInArray: false,\n typePrefix,\n });\n });\n\n return fields.map(\n (field, index) =>\n `${protobufFieldToType({ field })} ${field.name} = ${index + 1};`\n );\n};\n","import { z, type ZodFunction, ZodObject, type ZodTypeAny } from \"zod\";\nimport type { ServiceDefinition, ServiceMethod, ServicesInput } from \"./types\";\nimport { toPascalCase } from \"./utils\";\nimport { traverseSchema } from \"./traversers\";\n\ninterface ServiceGenerationContext {\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}\n\nconst parseZodServiceSchema = (\n name: string,\n schema: ZodObject<Record<string, ZodTypeAny>>\n): ServiceDefinition => {\n const shape = schema.shape as Record<string, ZodTypeAny>;\n const methods: ServiceMethod[] = [];\n\n for (const [methodName, methodSchema] of Object.entries(shape)) {\n const methodDef = (methodSchema as ZodTypeAny)._def as {\n type?: string;\n input?: ZodTypeAny;\n output?: ZodTypeAny;\n };\n\n if (methodDef.type === \"function\") {\n const inputDef = methodDef.input as ZodTypeAny & {\n def?: { items?: ZodTypeAny[] };\n };\n\n const args = inputDef?.def?.items ?? [];\n const output = methodDef.output as ZodTypeAny;\n\n if (args.length > 0 && args[0] && output) {\n const request = args[0];\n const response = output;\n\n methods.push({\n name: methodName,\n request,\n response,\n });\n }\n }\n }\n\n return {\n name,\n methods,\n };\n};\n\nconst normalizeServices = (services: ServicesInput): ServiceDefinition[] => {\n if (Array.isArray(services)) {\n return services;\n }\n\n return Object.entries(services).map(([name, schema]) =>\n parseZodServiceSchema(name, schema)\n );\n};\n\nconst ensureZodObject = (\n schema: ZodTypeAny\n): ZodObject<Record<string, ZodTypeAny>> => {\n const schemaType =\n (schema._def as { type?: string }).type || schema.constructor.name;\n\n if (schemaType === \"object\" || schema.constructor.name === \"ZodObject\") {\n return schema as ZodObject<Record<string, ZodTypeAny>>;\n }\n\n return z.object({\n data: schema,\n });\n};\n\nconst generateRequestMessageName = (\n methodName: string,\n typePrefix: string | null\n): string => {\n const messageName = toPascalCase({ value: `${methodName}Request` });\n return typePrefix ? `${typePrefix}${messageName}` : messageName;\n};\n\nconst generateResponseMessageName = (\n methodName: string,\n typePrefix: string | null\n): string => {\n const messageName = toPascalCase({ value: `${methodName}Response` });\n return typePrefix ? `${typePrefix}${messageName}` : messageName;\n};\n\nconst processServiceMethod = (\n method: ServiceMethod,\n context: ServiceGenerationContext\n): { requestName: string; responseName: string } => {\n const { messages, enums, typePrefix } = context;\n\n const requestName = generateRequestMessageName(method.name, typePrefix);\n const responseName = generateResponseMessageName(method.name, typePrefix);\n\n if (!messages.has(requestName)) {\n const requestSchema = ensureZodObject(method.request);\n const requestFields = traverseSchema({\n schema: requestSchema,\n messages,\n enums,\n typePrefix,\n });\n messages.set(requestName, requestFields);\n }\n\n if (!messages.has(responseName)) {\n const responseSchema = ensureZodObject(method.response);\n const responseFields = traverseSchema({\n schema: responseSchema,\n messages,\n enums,\n typePrefix,\n });\n messages.set(responseName, responseFields);\n }\n\n return { requestName, responseName };\n};\n\nexport const generateServices = (\n services: ServicesInput,\n context: ServiceGenerationContext\n): string[] => {\n const normalizedServices = normalizeServices(services);\n\n return normalizedServices.map((service) => {\n const methods = service.methods.map((method) => {\n const { requestName, responseName } = processServiceMethod(\n method,\n context\n );\n\n const requestStreaming =\n method.streaming === \"client\" || method.streaming === \"bidirectional\";\n const responseStreaming =\n method.streaming === \"server\" || method.streaming === \"bidirectional\";\n\n const requestType = requestStreaming\n ? `stream ${requestName}`\n : requestName;\n const responseType = responseStreaming\n ? `stream ${responseName}`\n : responseName;\n\n return ` rpc ${toPascalCase({ value: method.name })}(${requestType}) returns (${responseType});`;\n });\n\n return `service ${toPascalCase({ value: service.name })} {\\n${methods.join(\"\\n\")}\\n}`;\n });\n};\n","import type { ZodTypeAny } from \"zod\";\nimport type { ZodToProtobufOptions } from \"./types\";\nimport { traverseSchema } from \"./traversers\";\nimport { generateServices } from \"./service-generator\";\n\nexport const zodToProtobuf = (\n schema?: ZodTypeAny,\n options: ZodToProtobufOptions = {}\n): string => {\n const {\n packageName = \"default\",\n rootMessageName = \"Message\",\n typePrefix = \"\",\n services,\n skipRootMessage = false,\n } = options;\n\n const messages = new Map<string, string[]>();\n const enums = new Map<string, string[]>();\n\n if (schema && !skipRootMessage) {\n const fields = traverseSchema({ schema, messages, enums, typePrefix });\n if (fields.length > 0) {\n const rootMessageKey = `${typePrefix}${rootMessageName}`;\n messages.set(rootMessageKey, fields);\n }\n }\n\n const context = {\n messages,\n enums,\n typePrefix: typePrefix || null,\n };\n\n const hasServices =\n services &&\n (Array.isArray(services)\n ? services.length > 0\n : Object.keys(services).length > 0);\n\n const servicesString = hasServices ? generateServices(services, context) : [];\n\n const enumsString = Array.from(enums.values()).map((enumDef) =>\n enumDef.join(\"\\n\")\n );\n\n const messagesString = Array.from(messages.entries()).map(\n ([name, fields]) =>\n `message ${name} {\\n${fields.map((field) => ` ${field}`).join(\"\\n\")}\\n}`\n );\n\n const content = [enumsString, messagesString, servicesString]\n .filter((strings) => !!strings.length)\n .map((strings) => strings.join(\"\\n\\n\"))\n .join(\"\\n\\n\");\n\n const protoDefinition = `\nsyntax = \"proto3\";\npackage ${packageName};\n\n${content}\n`;\n\n return protoDefinition.trim();\n};\n"],"mappings":"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"}
|