@globalart/zod-to-proto 1.0.11 → 1.0.12

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 CHANGED
@@ -38,7 +38,7 @@ const protobufFieldToType = ({ field }) => {
38
38
 
39
39
  //#endregion
40
40
  //#region src/traversers.ts
41
- const traverseArray = ({ key, value, messages, enums, typePrefix }) => {
41
+ const traverseArray = ({ key, value, messages, enums, typePrefix, parentKey }) => {
42
42
  const nestedValue = value instanceof zod.ZodArray ? value.element : value instanceof zod.ZodSet ? value.def.valueType : value.def.element;
43
43
  const singularKey = inflection.singularize(key);
44
44
  return traverseKey({
@@ -48,14 +48,15 @@ const traverseArray = ({ key, value, messages, enums, typePrefix }) => {
48
48
  enums,
49
49
  isOptional: false,
50
50
  isInArray: true,
51
- typePrefix
51
+ typePrefix,
52
+ parentKey: void 0
52
53
  }).map((field) => ({
53
54
  ...field,
54
55
  types: ["repeated", ...field.types],
55
56
  name: field.name.replace(singularKey, key)
56
57
  }));
57
58
  };
58
- const traverseMap = ({ key, value, messages, enums, typePrefix }) => {
59
+ const traverseMap = ({ key, value, messages, enums, typePrefix, parentKey }) => {
59
60
  const mapDef = value.def;
60
61
  const keyType = traverseKey({
61
62
  key: inflection.singularize(key),
@@ -64,7 +65,8 @@ const traverseMap = ({ key, value, messages, enums, typePrefix }) => {
64
65
  enums,
65
66
  isOptional: false,
66
67
  isInArray: true,
67
- typePrefix
68
+ typePrefix,
69
+ parentKey
68
70
  });
69
71
  const valueType = traverseKey({
70
72
  key: inflection.singularize(key),
@@ -73,7 +75,8 @@ const traverseMap = ({ key, value, messages, enums, typePrefix }) => {
73
75
  enums,
74
76
  isOptional: false,
75
77
  isInArray: true,
76
- typePrefix
78
+ typePrefix,
79
+ parentKey
77
80
  });
78
81
  if (!keyType[0] || keyType.length !== 1) return [];
79
82
  if (!valueType[0] || valueType.length !== 1) return [];
@@ -82,7 +85,7 @@ const traverseMap = ({ key, value, messages, enums, typePrefix }) => {
82
85
  name: key
83
86
  }];
84
87
  };
85
- const traverseRecord = ({ key, value, messages, enums, typePrefix }) => {
88
+ const traverseRecord = ({ key, value, messages, enums, typePrefix, parentKey }) => {
86
89
  const recordDef = value.def;
87
90
  const keyType = traverseKey({
88
91
  key: inflection.singularize(key),
@@ -91,7 +94,8 @@ const traverseRecord = ({ key, value, messages, enums, typePrefix }) => {
91
94
  enums,
92
95
  isOptional: false,
93
96
  isInArray: true,
94
- typePrefix
97
+ typePrefix,
98
+ parentKey
95
99
  });
96
100
  const valueType = traverseKey({
97
101
  key: inflection.singularize(key),
@@ -100,7 +104,8 @@ const traverseRecord = ({ key, value, messages, enums, typePrefix }) => {
100
104
  enums,
101
105
  isOptional: false,
102
106
  isInArray: true,
103
- typePrefix
107
+ typePrefix,
108
+ parentKey
104
109
  });
105
110
  if (!keyType[0] || keyType.length !== 1) return [];
106
111
  if (!valueType[0] || valueType.length !== 1) return [];
@@ -109,7 +114,7 @@ const traverseRecord = ({ key, value, messages, enums, typePrefix }) => {
109
114
  name: key
110
115
  }];
111
116
  };
112
- const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typePrefix }) => {
117
+ const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typePrefix, parentKey }) => {
113
118
  if (!value) return [];
114
119
  if (value instanceof zod.ZodOptional || value instanceof zod.ZodNullable) return traverseKey({
115
120
  key,
@@ -118,38 +123,44 @@ const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typeP
118
123
  enums,
119
124
  isOptional: true,
120
125
  isInArray,
121
- typePrefix
126
+ typePrefix,
127
+ parentKey
122
128
  });
123
129
  if (value instanceof zod.ZodArray || value instanceof zod.ZodSet) return traverseArray({
124
130
  key,
125
131
  value,
126
132
  messages,
127
133
  enums,
128
- typePrefix
134
+ typePrefix,
135
+ parentKey
129
136
  });
130
137
  if (value instanceof zod.ZodMap) return traverseMap({
131
138
  key,
132
139
  value,
133
140
  messages,
134
141
  enums,
135
- typePrefix
142
+ typePrefix,
143
+ parentKey
136
144
  });
137
145
  if (value instanceof zod.ZodRecord) return traverseRecord({
138
146
  key,
139
147
  value,
140
148
  messages,
141
149
  enums,
142
- typePrefix
150
+ typePrefix,
151
+ parentKey
143
152
  });
144
153
  const optional = isOptional && !isInArray ? "optional" : null;
145
154
  if (value instanceof zod.ZodObject) {
146
155
  let messageName = toPascalCase({ value: key });
156
+ if (parentKey) messageName = `${toPascalCase({ value: parentKey })}${messageName}`;
147
157
  if (typePrefix) messageName = `${typePrefix}${messageName}`;
148
158
  const nestedMessageFields = traverseSchema({
149
159
  schema: value,
150
160
  messages,
151
161
  enums,
152
- typePrefix
162
+ typePrefix,
163
+ parentKey: key
153
164
  });
154
165
  messages.set(messageName, nestedMessageFields);
155
166
  return [{
@@ -172,6 +183,7 @@ const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typeP
172
183
  if (value instanceof zod.ZodEnum) {
173
184
  const enumFields = value.options.map((option, index) => ` ${String(option)} = ${index};`).join("\n");
174
185
  let enumName = toPascalCase({ value: key });
186
+ if (parentKey) enumName = `${toPascalCase({ value: parentKey })}${enumName}`;
175
187
  if (typePrefix) enumName = `${typePrefix}${enumName}`;
176
188
  enums.set(enumName, [`enum ${enumName} {\n${enumFields}\n}`]);
177
189
  return [{
@@ -196,10 +208,13 @@ const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typeP
196
208
  enums,
197
209
  isOptional: false,
198
210
  isInArray,
199
- typePrefix
211
+ typePrefix,
212
+ parentKey
200
213
  });
201
214
  });
202
- const tupleMessageName = toPascalCase({ value: key });
215
+ let tupleMessageName = toPascalCase({ value: key });
216
+ if (parentKey) tupleMessageName = `${toPascalCase({ value: parentKey })}${tupleMessageName}`;
217
+ if (typePrefix) tupleMessageName = `${typePrefix}${tupleMessageName}`;
203
218
  messages.set(tupleMessageName, tupleFields.map((field, index) => ` ${field.types.join(" ")} ${field.name} = ${index + 1};`));
204
219
  return [{
205
220
  types: [optional, tupleMessageName],
@@ -209,7 +224,7 @@ const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typeP
209
224
  if (value instanceof zod.ZodType) return [];
210
225
  return [];
211
226
  };
212
- const traverseSchema = ({ schema, messages, enums, typePrefix }) => {
227
+ const traverseSchema = ({ schema, messages, enums, typePrefix, parentKey }) => {
213
228
  if (!schema || typeof schema !== "object" || !("def" in schema) || schema.constructor.name !== "ZodObject" && schema.def.type !== "object") return [];
214
229
  const zodObject = schema;
215
230
  return Object.entries(zodObject.shape).flatMap(([key, value]) => {
@@ -220,7 +235,8 @@ const traverseSchema = ({ schema, messages, enums, typePrefix }) => {
220
235
  enums,
221
236
  isOptional: false,
222
237
  isInArray: false,
223
- typePrefix
238
+ typePrefix,
239
+ parentKey
224
240
  });
225
241
  }).map((field, index) => `${protobufFieldToType({ field })} ${field.name} = ${index + 1};`);
226
242
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["ZodArray","ZodSet","ZodOptional","ZodNullable","ZodMap","ZodRecord","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 ZodRecord,\n ZodSet,\n ZodString,\n ZodTuple,\n ZodType,\n type ZodTypeAny,\n} from \"zod\";\nimport {\n ZodArrayDefinition,\n ZodMapDefinition,\n ZodRecordDefinition,\n type ProtobufField,\n} 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 unknown as ZodArrayDefinition).valueType\n : // @ts-expect-error\n (value.def as unknown as ZodArrayDefinition).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 as ZodMapDefinition;\n\n const keyType = traverseKey({\n key: inflection.singularize(key),\n value: mapDef.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: mapDef.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 traverseRecord = ({\n key,\n value,\n messages,\n enums,\n typePrefix,\n}: {\n key: string;\n value: ZodRecord;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}): ProtobufField[] => {\n const recordDef = value.def as unknown as ZodRecordDefinition;\n\n const keyType = traverseKey({\n key: inflection.singularize(key),\n value: recordDef.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: recordDef.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 if (value instanceof ZodRecord) {\n return traverseRecord({\n key,\n value: value as ZodRecord,\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, ZodObject, type ZodTypeAny } from \"zod\";\nimport type {\n ServiceDefinition,\n ServiceMethod,\n ServicesInput,\n ZodFunctionDefinition,\n ZodTupleDefinition,\n} 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 ZodFunctionDefinition;\n\n if (methodDef.type === \"function\") {\n const inputDef = methodDef.input;\n\n const args = (inputDef?.def as ZodTupleDefinition)?.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 = [servicesString, enumsString, messagesString]\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","ZodRecord","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 ZodRecord,\n ZodSet,\n ZodString,\n ZodTuple,\n ZodType,\n type ZodTypeAny,\n} from \"zod\";\nimport {\n ZodArrayDefinition,\n ZodMapDefinition,\n ZodRecordDefinition,\n type ProtobufField,\n} from \"./types\";\nimport { getNumberTypeName, toPascalCase, protobufFieldToType } from \"./utils\";\n\nexport const traverseArray = ({\n key,\n value,\n messages,\n enums,\n typePrefix,\n parentKey,\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 parentKey?: string;\n}): ProtobufField[] => {\n const nestedValue =\n value instanceof ZodArray\n ? value.element\n : value instanceof ZodSet\n ? (value.def as unknown as ZodArrayDefinition).valueType\n : // @ts-expect-error\n (value.def as unknown as ZodArrayDefinition).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 parentKey: undefined,\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 parentKey,\n}: {\n key: string;\n value: ZodMap<ZodTypeAny, ZodTypeAny>;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n parentKey?: string;\n}): ProtobufField[] => {\n const mapDef = value.def as ZodMapDefinition;\n\n const keyType = traverseKey({\n key: inflection.singularize(key),\n value: mapDef.keyType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n parentKey,\n });\n const valueType = traverseKey({\n key: inflection.singularize(key),\n value: mapDef.valueType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n parentKey,\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 traverseRecord = ({\n key,\n value,\n messages,\n enums,\n typePrefix,\n parentKey,\n}: {\n key: string;\n value: ZodRecord;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n parentKey?: string;\n}): ProtobufField[] => {\n const recordDef = value.def as unknown as ZodRecordDefinition;\n\n const keyType = traverseKey({\n key: inflection.singularize(key),\n value: recordDef.keyType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n parentKey,\n });\n const valueType = traverseKey({\n key: inflection.singularize(key),\n value: recordDef.valueType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n parentKey,\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 parentKey,\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 parentKey?: string;\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 parentKey,\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 parentKey,\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 parentKey,\n });\n }\n\n if (value instanceof ZodRecord) {\n return traverseRecord({\n key,\n value: value as ZodRecord,\n messages,\n enums,\n typePrefix,\n parentKey,\n });\n }\n\n const optional = isOptional && !isInArray ? \"optional\" : null;\n\n if (value instanceof ZodObject) {\n let messageName = toPascalCase({ value: key });\n if (parentKey) {\n const parentMessageName = toPascalCase({ value: parentKey });\n messageName = `${parentMessageName}${messageName}`;\n }\n if (typePrefix) {\n messageName = `${typePrefix}${messageName}`;\n }\n const nestedMessageFields = traverseSchema({\n schema: value,\n messages,\n enums,\n typePrefix,\n parentKey: key,\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 (parentKey) {\n const parentMessageName = toPascalCase({ value: parentKey });\n enumName = `${parentMessageName}${enumName}`;\n }\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 parentKey,\n });\n });\n\n let tupleMessageName = toPascalCase({ value: key });\n if (parentKey) {\n const parentMessageName = toPascalCase({ value: parentKey });\n tupleMessageName = `${parentMessageName}${tupleMessageName}`;\n }\n if (typePrefix) {\n tupleMessageName = `${typePrefix}${tupleMessageName}`;\n }\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 parentKey,\n}: {\n schema: ZodTypeAny;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n parentKey?: string;\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 parentKey,\n });\n });\n\n return fields.map(\n (field, index) =>\n `${protobufFieldToType({ field })} ${field.name} = ${index + 1};`\n );\n};\n","import { z, ZodObject, type ZodTypeAny } from \"zod\";\nimport type {\n ServiceDefinition,\n ServiceMethod,\n ServicesInput,\n ZodFunctionDefinition,\n ZodTupleDefinition,\n} 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 ZodFunctionDefinition;\n\n if (methodDef.type === \"function\") {\n const inputDef = methodDef.input;\n\n const args = (inputDef?.def as ZodTupleDefinition)?.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 = [servicesString, enumsString, messagesString]\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
@@ -14,7 +14,7 @@ const protobufFieldToType = ({ field }) => {
14
14
 
15
15
  //#endregion
16
16
  //#region src/traversers.ts
17
- const traverseArray = ({ key, value, messages, enums, typePrefix }) => {
17
+ const traverseArray = ({ key, value, messages, enums, typePrefix, parentKey }) => {
18
18
  const nestedValue = value instanceof ZodArray ? value.element : value instanceof ZodSet ? value.def.valueType : value.def.element;
19
19
  const singularKey = inflection.singularize(key);
20
20
  return traverseKey({
@@ -24,14 +24,15 @@ const traverseArray = ({ key, value, messages, enums, typePrefix }) => {
24
24
  enums,
25
25
  isOptional: false,
26
26
  isInArray: true,
27
- typePrefix
27
+ typePrefix,
28
+ parentKey: void 0
28
29
  }).map((field) => ({
29
30
  ...field,
30
31
  types: ["repeated", ...field.types],
31
32
  name: field.name.replace(singularKey, key)
32
33
  }));
33
34
  };
34
- const traverseMap = ({ key, value, messages, enums, typePrefix }) => {
35
+ const traverseMap = ({ key, value, messages, enums, typePrefix, parentKey }) => {
35
36
  const mapDef = value.def;
36
37
  const keyType = traverseKey({
37
38
  key: inflection.singularize(key),
@@ -40,7 +41,8 @@ const traverseMap = ({ key, value, messages, enums, typePrefix }) => {
40
41
  enums,
41
42
  isOptional: false,
42
43
  isInArray: true,
43
- typePrefix
44
+ typePrefix,
45
+ parentKey
44
46
  });
45
47
  const valueType = traverseKey({
46
48
  key: inflection.singularize(key),
@@ -49,7 +51,8 @@ const traverseMap = ({ key, value, messages, enums, typePrefix }) => {
49
51
  enums,
50
52
  isOptional: false,
51
53
  isInArray: true,
52
- typePrefix
54
+ typePrefix,
55
+ parentKey
53
56
  });
54
57
  if (!keyType[0] || keyType.length !== 1) return [];
55
58
  if (!valueType[0] || valueType.length !== 1) return [];
@@ -58,7 +61,7 @@ const traverseMap = ({ key, value, messages, enums, typePrefix }) => {
58
61
  name: key
59
62
  }];
60
63
  };
61
- const traverseRecord = ({ key, value, messages, enums, typePrefix }) => {
64
+ const traverseRecord = ({ key, value, messages, enums, typePrefix, parentKey }) => {
62
65
  const recordDef = value.def;
63
66
  const keyType = traverseKey({
64
67
  key: inflection.singularize(key),
@@ -67,7 +70,8 @@ const traverseRecord = ({ key, value, messages, enums, typePrefix }) => {
67
70
  enums,
68
71
  isOptional: false,
69
72
  isInArray: true,
70
- typePrefix
73
+ typePrefix,
74
+ parentKey
71
75
  });
72
76
  const valueType = traverseKey({
73
77
  key: inflection.singularize(key),
@@ -76,7 +80,8 @@ const traverseRecord = ({ key, value, messages, enums, typePrefix }) => {
76
80
  enums,
77
81
  isOptional: false,
78
82
  isInArray: true,
79
- typePrefix
83
+ typePrefix,
84
+ parentKey
80
85
  });
81
86
  if (!keyType[0] || keyType.length !== 1) return [];
82
87
  if (!valueType[0] || valueType.length !== 1) return [];
@@ -85,7 +90,7 @@ const traverseRecord = ({ key, value, messages, enums, typePrefix }) => {
85
90
  name: key
86
91
  }];
87
92
  };
88
- const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typePrefix }) => {
93
+ const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typePrefix, parentKey }) => {
89
94
  if (!value) return [];
90
95
  if (value instanceof ZodOptional || value instanceof ZodNullable) return traverseKey({
91
96
  key,
@@ -94,38 +99,44 @@ const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typeP
94
99
  enums,
95
100
  isOptional: true,
96
101
  isInArray,
97
- typePrefix
102
+ typePrefix,
103
+ parentKey
98
104
  });
99
105
  if (value instanceof ZodArray || value instanceof ZodSet) return traverseArray({
100
106
  key,
101
107
  value,
102
108
  messages,
103
109
  enums,
104
- typePrefix
110
+ typePrefix,
111
+ parentKey
105
112
  });
106
113
  if (value instanceof ZodMap) return traverseMap({
107
114
  key,
108
115
  value,
109
116
  messages,
110
117
  enums,
111
- typePrefix
118
+ typePrefix,
119
+ parentKey
112
120
  });
113
121
  if (value instanceof ZodRecord) return traverseRecord({
114
122
  key,
115
123
  value,
116
124
  messages,
117
125
  enums,
118
- typePrefix
126
+ typePrefix,
127
+ parentKey
119
128
  });
120
129
  const optional = isOptional && !isInArray ? "optional" : null;
121
130
  if (value instanceof ZodObject) {
122
131
  let messageName = toPascalCase({ value: key });
132
+ if (parentKey) messageName = `${toPascalCase({ value: parentKey })}${messageName}`;
123
133
  if (typePrefix) messageName = `${typePrefix}${messageName}`;
124
134
  const nestedMessageFields = traverseSchema({
125
135
  schema: value,
126
136
  messages,
127
137
  enums,
128
- typePrefix
138
+ typePrefix,
139
+ parentKey: key
129
140
  });
130
141
  messages.set(messageName, nestedMessageFields);
131
142
  return [{
@@ -148,6 +159,7 @@ const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typeP
148
159
  if (value instanceof ZodEnum) {
149
160
  const enumFields = value.options.map((option, index) => ` ${String(option)} = ${index};`).join("\n");
150
161
  let enumName = toPascalCase({ value: key });
162
+ if (parentKey) enumName = `${toPascalCase({ value: parentKey })}${enumName}`;
151
163
  if (typePrefix) enumName = `${typePrefix}${enumName}`;
152
164
  enums.set(enumName, [`enum ${enumName} {\n${enumFields}\n}`]);
153
165
  return [{
@@ -172,10 +184,13 @@ const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typeP
172
184
  enums,
173
185
  isOptional: false,
174
186
  isInArray,
175
- typePrefix
187
+ typePrefix,
188
+ parentKey
176
189
  });
177
190
  });
178
- const tupleMessageName = toPascalCase({ value: key });
191
+ let tupleMessageName = toPascalCase({ value: key });
192
+ if (parentKey) tupleMessageName = `${toPascalCase({ value: parentKey })}${tupleMessageName}`;
193
+ if (typePrefix) tupleMessageName = `${typePrefix}${tupleMessageName}`;
179
194
  messages.set(tupleMessageName, tupleFields.map((field, index) => ` ${field.types.join(" ")} ${field.name} = ${index + 1};`));
180
195
  return [{
181
196
  types: [optional, tupleMessageName],
@@ -185,7 +200,7 @@ const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typeP
185
200
  if (value instanceof ZodType) return [];
186
201
  return [];
187
202
  };
188
- const traverseSchema = ({ schema, messages, enums, typePrefix }) => {
203
+ const traverseSchema = ({ schema, messages, enums, typePrefix, parentKey }) => {
189
204
  if (!schema || typeof schema !== "object" || !("def" in schema) || schema.constructor.name !== "ZodObject" && schema.def.type !== "object") return [];
190
205
  const zodObject = schema;
191
206
  return Object.entries(zodObject.shape).flatMap(([key, value]) => {
@@ -196,7 +211,8 @@ const traverseSchema = ({ schema, messages, enums, typePrefix }) => {
196
211
  enums,
197
212
  isOptional: false,
198
213
  isInArray: false,
199
- typePrefix
214
+ typePrefix,
215
+ parentKey
200
216
  });
201
217
  }).map((field, index) => `${protobufFieldToType({ field })} ${field.name} = ${index + 1};`);
202
218
  };
@@ -1 +1 @@
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 ZodRecord,\n ZodSet,\n ZodString,\n ZodTuple,\n ZodType,\n type ZodTypeAny,\n} from \"zod\";\nimport {\n ZodArrayDefinition,\n ZodMapDefinition,\n ZodRecordDefinition,\n type ProtobufField,\n} 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 unknown as ZodArrayDefinition).valueType\n : // @ts-expect-error\n (value.def as unknown as ZodArrayDefinition).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 as ZodMapDefinition;\n\n const keyType = traverseKey({\n key: inflection.singularize(key),\n value: mapDef.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: mapDef.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 traverseRecord = ({\n key,\n value,\n messages,\n enums,\n typePrefix,\n}: {\n key: string;\n value: ZodRecord;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n}): ProtobufField[] => {\n const recordDef = value.def as unknown as ZodRecordDefinition;\n\n const keyType = traverseKey({\n key: inflection.singularize(key),\n value: recordDef.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: recordDef.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 if (value instanceof ZodRecord) {\n return traverseRecord({\n key,\n value: value as ZodRecord,\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, ZodObject, type ZodTypeAny } from \"zod\";\nimport type {\n ServiceDefinition,\n ServiceMethod,\n ServicesInput,\n ZodFunctionDefinition,\n ZodTupleDefinition,\n} 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 ZodFunctionDefinition;\n\n if (methodDef.type === \"function\") {\n const inputDef = methodDef.input;\n\n const args = (inputDef?.def as ZodTupleDefinition)?.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 = [servicesString, enumsString, messagesString]\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 ZodRecord,\n ZodSet,\n ZodString,\n ZodTuple,\n ZodType,\n type ZodTypeAny,\n} from \"zod\";\nimport {\n ZodArrayDefinition,\n ZodMapDefinition,\n ZodRecordDefinition,\n type ProtobufField,\n} from \"./types\";\nimport { getNumberTypeName, toPascalCase, protobufFieldToType } from \"./utils\";\n\nexport const traverseArray = ({\n key,\n value,\n messages,\n enums,\n typePrefix,\n parentKey,\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 parentKey?: string;\n}): ProtobufField[] => {\n const nestedValue =\n value instanceof ZodArray\n ? value.element\n : value instanceof ZodSet\n ? (value.def as unknown as ZodArrayDefinition).valueType\n : // @ts-expect-error\n (value.def as unknown as ZodArrayDefinition).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 parentKey: undefined,\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 parentKey,\n}: {\n key: string;\n value: ZodMap<ZodTypeAny, ZodTypeAny>;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n parentKey?: string;\n}): ProtobufField[] => {\n const mapDef = value.def as ZodMapDefinition;\n\n const keyType = traverseKey({\n key: inflection.singularize(key),\n value: mapDef.keyType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n parentKey,\n });\n const valueType = traverseKey({\n key: inflection.singularize(key),\n value: mapDef.valueType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n parentKey,\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 traverseRecord = ({\n key,\n value,\n messages,\n enums,\n typePrefix,\n parentKey,\n}: {\n key: string;\n value: ZodRecord;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n parentKey?: string;\n}): ProtobufField[] => {\n const recordDef = value.def as unknown as ZodRecordDefinition;\n\n const keyType = traverseKey({\n key: inflection.singularize(key),\n value: recordDef.keyType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n parentKey,\n });\n const valueType = traverseKey({\n key: inflection.singularize(key),\n value: recordDef.valueType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n parentKey,\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 parentKey,\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 parentKey?: string;\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 parentKey,\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 parentKey,\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 parentKey,\n });\n }\n\n if (value instanceof ZodRecord) {\n return traverseRecord({\n key,\n value: value as ZodRecord,\n messages,\n enums,\n typePrefix,\n parentKey,\n });\n }\n\n const optional = isOptional && !isInArray ? \"optional\" : null;\n\n if (value instanceof ZodObject) {\n let messageName = toPascalCase({ value: key });\n if (parentKey) {\n const parentMessageName = toPascalCase({ value: parentKey });\n messageName = `${parentMessageName}${messageName}`;\n }\n if (typePrefix) {\n messageName = `${typePrefix}${messageName}`;\n }\n const nestedMessageFields = traverseSchema({\n schema: value,\n messages,\n enums,\n typePrefix,\n parentKey: key,\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 (parentKey) {\n const parentMessageName = toPascalCase({ value: parentKey });\n enumName = `${parentMessageName}${enumName}`;\n }\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 parentKey,\n });\n });\n\n let tupleMessageName = toPascalCase({ value: key });\n if (parentKey) {\n const parentMessageName = toPascalCase({ value: parentKey });\n tupleMessageName = `${parentMessageName}${tupleMessageName}`;\n }\n if (typePrefix) {\n tupleMessageName = `${typePrefix}${tupleMessageName}`;\n }\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 parentKey,\n}: {\n schema: ZodTypeAny;\n messages: Map<string, string[]>;\n enums: Map<string, string[]>;\n typePrefix: string | null;\n parentKey?: string;\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 parentKey,\n });\n });\n\n return fields.map(\n (field, index) =>\n `${protobufFieldToType({ field })} ${field.name} = ${index + 1};`\n );\n};\n","import { z, ZodObject, type ZodTypeAny } from \"zod\";\nimport type {\n ServiceDefinition,\n ServiceMethod,\n ServicesInput,\n ZodFunctionDefinition,\n ZodTupleDefinition,\n} 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 ZodFunctionDefinition;\n\n if (methodDef.type === \"function\") {\n const inputDef = methodDef.input;\n\n const args = (inputDef?.def as ZodTupleDefinition)?.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 = [servicesString, enumsString, messagesString]\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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@globalart/zod-to-proto",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "author": {
5
5
  "name": "GlobalArt, Inc"
6
6
  },