@globalart/zod-to-proto 1.0.3 → 1.0.5

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/README.md ADDED
@@ -0,0 +1,294 @@
1
+ # @globalart/zod-to-proto
2
+
3
+ A library for converting Zod schemas to Protobuf definitions. Automatically generates `.proto` files from Zod validation schemas, including support for gRPC services.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @globalart/zod-to-proto zod
9
+ ```
10
+
11
+ or
12
+
13
+ ```bash
14
+ yarn add @globalart/zod-to-proto zod
15
+ ```
16
+
17
+ or
18
+
19
+ ```bash
20
+ pnpm add @globalart/zod-to-proto zod
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ### Basic Usage
26
+
27
+ ```typescript
28
+ import { zodToProtobuf } from "@globalart/zod-to-proto";
29
+ import { z } from "zod";
30
+
31
+ const schema = z.object({
32
+ name: z.string(),
33
+ age: z.number(),
34
+ email: z.string().email(),
35
+ });
36
+
37
+ const protoDefinition = zodToProtobuf(schema, {
38
+ packageName: "user.service",
39
+ });
40
+
41
+ console.log(protoDefinition);
42
+ ```
43
+
44
+ Output:
45
+
46
+ ```protobuf
47
+ syntax = "proto3";
48
+ package user.service;
49
+
50
+ message Message {
51
+ string name = 1;
52
+ int32 age = 2;
53
+ string email = 3;
54
+ }
55
+ ```
56
+
57
+ ### Generating gRPC Services
58
+
59
+ ```typescript
60
+ import { zodToProtobuf } from "@globalart/zod-to-proto";
61
+ import { z } from "zod";
62
+
63
+ const protoDefinition = zodToProtobuf(z.object(), {
64
+ packageName: "user.service",
65
+ services: [
66
+ {
67
+ name: "UserService",
68
+ methods: [
69
+ {
70
+ name: "getUser",
71
+ request: z.object({
72
+ id: z.string(),
73
+ }),
74
+ response: z.object({
75
+ name: z.string(),
76
+ age: z.number(),
77
+ email: z.string(),
78
+ }),
79
+ },
80
+ {
81
+ name: "createUser",
82
+ request: z.object({
83
+ name: z.string(),
84
+ age: z.number(),
85
+ email: z.string(),
86
+ }),
87
+ response: z.object({
88
+ id: z.string(),
89
+ success: z.boolean(),
90
+ }),
91
+ },
92
+ ],
93
+ },
94
+ ],
95
+ });
96
+
97
+ console.log(protoDefinition);
98
+ ```
99
+
100
+ Output:
101
+
102
+ ```protobuf
103
+ syntax = "proto3";
104
+ package user.service;
105
+
106
+ message GetUserRequest {
107
+ string id = 1;
108
+ }
109
+
110
+ message GetUserResponse {
111
+ string name = 1;
112
+ int32 age = 2;
113
+ string email = 3;
114
+ }
115
+
116
+ message CreateUserRequest {
117
+ string name = 1;
118
+ int32 age = 2;
119
+ string email = 3;
120
+ }
121
+
122
+ message CreateUserResponse {
123
+ string id = 1;
124
+ bool success = 2;
125
+ }
126
+
127
+ service UserService {
128
+ rpc getUser(GetUserRequest) returns (GetUserResponse);
129
+ rpc createUser(CreateUserRequest) returns (CreateUserResponse);
130
+ }
131
+ ```
132
+
133
+ ## API
134
+
135
+ ### `zodToProtobuf(schema?, options?)`
136
+
137
+ Converts a Zod schema to a Protobuf definition.
138
+
139
+ #### Parameters
140
+
141
+ - `schema` (optional): `ZodTypeAny` - Root Zod schema to convert
142
+ - `options` (optional): `ZodToProtobufOptions` - Configuration options
143
+
144
+ #### Options
145
+
146
+ ```typescript
147
+ interface ZodToProtobufOptions {
148
+ packageName?: string; // Protobuf package name (default: "default")
149
+ rootMessageName?: string; // Root message name (default: "Message")
150
+ typePrefix?: string; // Prefix for message and enum types
151
+ services?: ServiceDefinition[]; // gRPC service definitions
152
+ skipRootMessage?: boolean; // Skip root message generation
153
+ }
154
+ ```
155
+
156
+ #### Service Definition
157
+
158
+ ```typescript
159
+ interface ServiceDefinition {
160
+ name: string; // Service name
161
+ methods: ServiceMethod[];
162
+ }
163
+
164
+ interface ServiceMethod {
165
+ name: string; // Method name
166
+ request: ZodTypeAny; // Request Zod schema
167
+ response: ZodTypeAny; // Response Zod schema
168
+ streaming?: "client" | "server" | "bidirectional"; // Streaming type (optional)
169
+ }
170
+ ```
171
+
172
+ ## Supported Zod Types
173
+
174
+ ### Basic Types
175
+
176
+ - `z.string()` → `string`
177
+ - `z.number()` → `int32` (or `int64`, `float`, `double` depending on validation)
178
+ - `z.boolean()` → `bool`
179
+ - `z.bigint()` → `int64`
180
+ - `z.date()` → `string`
181
+
182
+ ### Collections
183
+
184
+ - `z.array()` → `repeated`
185
+ - `z.set()` → `repeated`
186
+ - `z.map()` → `map<keyType, valueType>`
187
+ - `z.tuple()` → nested message
188
+
189
+ ### Complex Types
190
+
191
+ - `z.object()` → nested message
192
+ - `z.enum()` → `enum`
193
+ - `z.optional()` → `optional`
194
+ - `z.nullable()` → `optional`
195
+
196
+ ### Examples
197
+
198
+ ```typescript
199
+ import { zodToProtobuf } from "@globalart/zod-to-proto";
200
+ import { z } from "zod";
201
+
202
+ const schema = z.object({
203
+ id: z.string(),
204
+ tags: z.array(z.string()),
205
+ metadata: z.map(z.string(), z.number()),
206
+ status: z.enum(["active", "inactive", "pending"]),
207
+ profile: z.object({
208
+ firstName: z.string(),
209
+ lastName: z.string(),
210
+ age: z.number().optional(),
211
+ }),
212
+ coordinates: z.tuple([z.number(), z.number()]),
213
+ });
214
+
215
+ const protoDefinition = zodToProtobuf(schema, {
216
+ packageName: "example",
217
+ });
218
+ ```
219
+
220
+ ## Usage Examples
221
+
222
+ ### With Custom Type Prefix
223
+
224
+ ```typescript
225
+ const protoDefinition = zodToProtobuf(schema, {
226
+ packageName: "api.v1",
227
+ typePrefix: "ApiV1",
228
+ rootMessageName: "User",
229
+ });
230
+ ```
231
+
232
+ ### With Streaming Methods
233
+
234
+ ```typescript
235
+ const protoDefinition = zodToProtobuf(z.object(), {
236
+ packageName: "chat.service",
237
+ services: [
238
+ {
239
+ name: "ChatService",
240
+ methods: [
241
+ {
242
+ name: "sendMessage",
243
+ request: z.object({ message: z.string() }),
244
+ response: z.object({ success: z.boolean() }),
245
+ },
246
+ {
247
+ name: "streamMessages",
248
+ request: z.object({ roomId: z.string() }),
249
+ response: z.object({ message: z.string() }),
250
+ streaming: "server",
251
+ },
252
+ {
253
+ name: "chat",
254
+ request: z.object({ message: z.string() }),
255
+ response: z.object({ message: z.string() }),
256
+ streaming: "bidirectional",
257
+ },
258
+ ],
259
+ },
260
+ ],
261
+ });
262
+ ```
263
+
264
+ ### Without Root Message
265
+
266
+ ```typescript
267
+ const protoDefinition = zodToProtobuf(schema, {
268
+ packageName: "example",
269
+ skipRootMessage: true,
270
+ services: [
271
+ {
272
+ name: "ExampleService",
273
+ methods: [
274
+ {
275
+ name: "doSomething",
276
+ request: z.object({ input: z.string() }),
277
+ response: z.object({ output: z.string() }),
278
+ },
279
+ ],
280
+ },
281
+ ],
282
+ });
283
+ ```
284
+
285
+ ## Limitations
286
+
287
+ - Only the types listed above are supported
288
+ - Unsupported types will throw `UnsupportedTypeException`
289
+ - Nested objects are automatically converted to separate messages
290
+ - Enum values are converted to numbers starting from 0
291
+
292
+ ## License
293
+
294
+ MIT
package/dist/index.cjs CHANGED
@@ -242,9 +242,9 @@ const generateServices = (services, context) => {
242
242
  const responseStreaming = method.streaming === "server" || method.streaming === "bidirectional";
243
243
  const requestType = requestStreaming ? `stream ${requestName}` : requestName;
244
244
  const responseType = responseStreaming ? `stream ${responseName}` : responseName;
245
- return ` rpc ${method.name}(${requestType}) returns (${responseType});`;
245
+ return ` rpc ${toPascalCase({ value: method.name })}(${requestType}) returns (${responseType});`;
246
246
  });
247
- return `service ${service.name} {\n${methods.join("\n")}\n}`;
247
+ return `service ${toPascalCase({ value: service.name })} {\n${methods.join("\n")}\n}`;
248
248
  });
249
249
  };
250
250
 
@@ -285,6 +285,5 @@ ${[
285
285
  };
286
286
 
287
287
  //#endregion
288
- exports.UnsupportedTypeException = UnsupportedTypeException;
289
288
  exports.zodToProtobuf = zodToProtobuf;
290
289
  //# sourceMappingURL=index.cjs.map
@@ -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"],"sources":["../src/types.ts","../src/utils.ts","../src/traversers.ts","../src/service-generator.ts","../src/zod-to-protobuf.ts"],"sourcesContent":["import type { ZodTypeAny } from 'zod'\n\nexport interface ZodToProtobufOptions {\n\tpackageName?: string\n\trootMessageName?: string\n\ttypePrefix?: string\n\tservices?: ServiceDefinition[]\n\tskipRootMessage?: boolean\n}\n\nexport interface ServiceMethod {\n\tname: string\n\trequest: ZodTypeAny\n\tresponse: ZodTypeAny\n\tstreaming?: 'client' | 'server' | 'bidirectional'\n}\n\nexport interface ServiceDefinition {\n\tname: string\n\tmethods: ServiceMethod[]\n}\n\nexport class UnsupportedTypeException extends Error {\n\tconstructor(type: string) {\n\t\tsuper(`Unsupported type: ${type}`)\n\t\tthis.name = 'UnsupportedTypeException'\n\t}\n}\n\nexport interface ProtobufField {\n\ttypes: Array<string | null>\n\tname: string\n}\n\n","import { ZodNumber } from 'zod'\nimport type { ProtobufField } from './types'\n\nexport const getNumberTypeName = ({ value }: { value: ZodNumber }): string => {\n\treturn value.isInt ? 'int32' : 'double'\n}\n\nexport const toPascalCase = ({ value }: { value: string }): string => {\n\treturn value\n\t\t.split('.')\n\t\t.map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n\t\t.join('')\n}\n\nexport const protobufFieldToType = ({ field }: { field: ProtobufField }): string => {\n\treturn field.types.filter(Boolean).join(' ')\n}\n\n","import * as inflection from 'inflection'\nimport {\n\tZodArray,\n\tZodBigInt,\n\tZodBoolean,\n\tZodDate,\n\tZodEnum,\n\tZodMap,\n\tZodNullable,\n\tZodNumber,\n\tZodObject,\n\tZodOptional,\n\tZodSet,\n\tZodString,\n\tZodTuple,\n\tZodType,\n\ttype ZodTypeAny\n} from 'zod'\nimport { UnsupportedTypeException, type ProtobufField } from './types'\nimport { getNumberTypeName, toPascalCase, protobufFieldToType } from './utils'\n\nexport const traverseArray = ({\n\tkey,\n\tvalue,\n\tmessages,\n\tenums,\n\ttypePrefix\n}: {\n\tkey: string\n\tvalue: ZodArray<ZodTypeAny> | ZodSet<ZodTypeAny>\n\tmessages: Map<string, string[]>\n\tenums: Map<string, string[]>\n\ttypePrefix: string | null\n}): ProtobufField[] => {\n\tconst nestedValue =\n\t\tvalue instanceof ZodArray\n\t\t\t? value.element\n\t\t\t: value instanceof ZodSet\n\t\t\t\t? (value._def as { valueType: ZodTypeAny }).valueType\n\t\t\t\t: // @ts-expect-error\n\t\t\t\t\t(value._def as { element?: ZodTypeAny }).element\n\n\tconst singularKey = inflection.singularize(key)\n\tconst elementFields = traverseKey({\n\t\tkey: singularKey,\n\t\tvalue: nestedValue,\n\t\tmessages,\n\t\tenums,\n\t\tisOptional: false,\n\t\tisInArray: true,\n\t\ttypePrefix\n\t})\n\treturn elementFields.map((field) => ({\n\t\t...field,\n\t\ttypes: ['repeated', ...field.types],\n\t\tname: field.name.replace(singularKey, key)\n\t}))\n}\n\nexport const traverseMap = ({\n\tkey,\n\tvalue,\n\tmessages,\n\tenums,\n\ttypePrefix\n}: {\n\tkey: string\n\tvalue: ZodMap<ZodTypeAny, ZodTypeAny>\n\tmessages: Map<string, string[]>\n\tenums: Map<string, string[]>\n\ttypePrefix: string | null\n}): ProtobufField[] => {\n\tconst keyType = traverseKey({\n\t\tkey: `${key}Key`,\n\t\tvalue: value._def.keyType,\n\t\tmessages,\n\t\tenums,\n\t\tisOptional: false,\n\t\tisInArray: true,\n\t\ttypePrefix\n\t})\n\tconst valueType = traverseKey({\n\t\tkey: `${key}Value`,\n\t\tvalue: value._def.valueType,\n\t\tmessages,\n\t\tenums,\n\t\tisOptional: false,\n\t\tisInArray: true,\n\t\ttypePrefix\n\t})\n\n\tif (!keyType[0] || keyType.length !== 1) {\n\t\tthrow new UnsupportedTypeException(`${key} map key`)\n\t}\n\n\tif (!valueType[0] || valueType.length !== 1) {\n\t\tthrow new UnsupportedTypeException(`${key} map value`)\n\t}\n\n\tconst mapType = `map<${protobufFieldToType({ field: keyType[0] })}, ${protobufFieldToType({ field: valueType[0] })}>`\n\treturn [\n\t\t{\n\t\t\ttypes: [mapType],\n\t\t\tname: key\n\t\t}\n\t]\n}\n\nexport const traverseKey = ({\n\tkey,\n\tvalue,\n\tmessages,\n\tenums,\n\tisOptional,\n\tisInArray,\n\ttypePrefix\n}: {\n\tkey: string\n\tvalue: unknown\n\tmessages: Map<string, string[]>\n\tenums: Map<string, string[]>\n\tisOptional: boolean\n\tisInArray: boolean\n\ttypePrefix: string | null\n}): ProtobufField[] => {\n\tif (value instanceof ZodOptional || value instanceof ZodNullable) {\n\t\treturn traverseKey({\n\t\t\tkey,\n\t\t\tvalue: value.unwrap(),\n\t\t\tmessages,\n\t\t\tenums,\n\t\t\tisOptional: true,\n\t\t\tisInArray,\n\t\t\ttypePrefix\n\t\t})\n\t}\n\n\tif (value instanceof ZodArray || value instanceof ZodSet) {\n\t\treturn traverseArray({\n\t\t\tkey,\n\t\t\tvalue: value as ZodArray<ZodTypeAny> | ZodSet<ZodTypeAny>,\n\t\t\tmessages,\n\t\t\tenums,\n\t\t\ttypePrefix\n\t\t})\n\t}\n\n\tif (value instanceof ZodMap) {\n\t\treturn traverseMap({\n\t\t\tkey,\n\t\t\tvalue: value as ZodMap<ZodTypeAny, ZodTypeAny>,\n\t\t\tmessages,\n\t\t\tenums,\n\t\t\ttypePrefix\n\t\t})\n\t}\n\n\tconst optional = isOptional && !isInArray ? 'optional' : null\n\n\tif (value instanceof ZodObject) {\n\t\tlet messageName = toPascalCase({ value: key })\n\t\tif (typePrefix) {\n\t\t\tmessageName = `${typePrefix}${messageName}`\n\t\t}\n\t\tconst nestedMessageFields = traverseSchema({\n\t\t\tschema: value,\n\t\t\tmessages,\n\t\t\tenums,\n\t\t\ttypePrefix\n\t\t})\n\t\tmessages.set(messageName, nestedMessageFields)\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, messageName],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodString) {\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, 'string'],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodNumber) {\n\t\tconst typeName = getNumberTypeName({ value })\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, typeName],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodBoolean) {\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, 'bool'],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodEnum) {\n\t\tconst enumFields = value.options\n\t\t\t.map(\n\t\t\t\t(option: string | number, index: number) =>\n\t\t\t\t\t` ${String(option)} = ${index};`\n\t\t\t)\n\t\t\t.join('\\n')\n\t\tlet enumName = toPascalCase({ value: key })\n\t\tif (typePrefix) {\n\t\t\tenumName = `${typePrefix}${enumName}`\n\t\t}\n\t\tenums.set(enumName, [`enum ${enumName} {\\n${enumFields}\\n}`])\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, enumName],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodDate) {\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, 'string'],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodBigInt) {\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, 'int64'],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodTuple) {\n\t\tconst tupleFields: ProtobufField[] = (\n\t\t\tvalue._def.items as ZodTypeAny[]\n\t\t).flatMap((item: ZodTypeAny, index: number) => {\n\t\t\treturn traverseKey({\n\t\t\t\tkey: `${key}_${index}`,\n\t\t\t\tvalue: item,\n\t\t\t\tmessages,\n\t\t\t\tenums,\n\t\t\t\tisOptional: false,\n\t\t\t\tisInArray,\n\t\t\t\ttypePrefix\n\t\t\t})\n\t\t})\n\n\t\tconst tupleMessageName = toPascalCase({ value: key })\n\t\tmessages.set(\n\t\t\ttupleMessageName,\n\t\t\ttupleFields.map(\n\t\t\t\t(field, index) =>\n\t\t\t\t\t` ${field.types.join(' ')} ${field.name} = ${index + 1};`\n\t\t\t)\n\t\t)\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, tupleMessageName],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodType) {\n\t\tthrow new UnsupportedTypeException(value.constructor.name)\n\t}\n\n\tthrow new UnsupportedTypeException(typeof value)\n}\n\nexport const traverseSchema = ({\n\tschema,\n\tmessages,\n\tenums,\n\ttypePrefix\n}: {\n\tschema: ZodTypeAny\n\tmessages: Map<string, string[]>\n\tenums: Map<string, string[]>\n\ttypePrefix: string | null\n}): string[] => {\n\tif (!(schema instanceof ZodObject)) {\n\t\tthrow new UnsupportedTypeException(schema.constructor.name)\n\t}\n\n\tconst fields = Object.entries(schema.shape).flatMap(([key, value]) => {\n\t\treturn traverseKey({\n\t\t\tkey,\n\t\t\tvalue,\n\t\t\tmessages,\n\t\t\tenums,\n\t\t\tisOptional: false,\n\t\t\tisInArray: false,\n\t\t\ttypePrefix\n\t\t})\n\t})\n\n\treturn fields.map(\n\t\t(field, index) =>\n\t\t\t`${protobufFieldToType({ field })} ${field.name} = ${index + 1};`\n\t)\n}\n\n","import type { ZodTypeAny } from 'zod'\nimport type { ServiceDefinition, ServiceMethod } from './types'\nimport { toPascalCase } from './utils'\nimport { traverseSchema } from './traversers'\n\ninterface ServiceGenerationContext {\n\tmessages: Map<string, string[]>\n\tenums: Map<string, string[]>\n\ttypePrefix: string | null\n}\n\nconst generateRequestMessageName = (methodName: string, typePrefix: string | null): string => {\n\tconst messageName = toPascalCase({ value: `${methodName}Request` })\n\treturn typePrefix ? `${typePrefix}${messageName}` : messageName\n}\n\nconst generateResponseMessageName = (methodName: string, typePrefix: string | null): string => {\n\tconst messageName = toPascalCase({ value: `${methodName}Response` })\n\treturn typePrefix ? `${typePrefix}${messageName}` : messageName\n}\n\nconst processServiceMethod = (\n\tmethod: ServiceMethod,\n\tcontext: ServiceGenerationContext\n): { requestName: string; responseName: string } => {\n\tconst { messages, enums, typePrefix } = context\n\n\tconst requestName = generateRequestMessageName(method.name, typePrefix)\n\tconst responseName = generateResponseMessageName(method.name, typePrefix)\n\n\tif (!messages.has(requestName)) {\n\t\tconst requestFields = traverseSchema({\n\t\t\tschema: method.request,\n\t\t\tmessages,\n\t\t\tenums,\n\t\t\ttypePrefix\n\t\t})\n\t\tmessages.set(requestName, requestFields)\n\t}\n\n\tif (!messages.has(responseName)) {\n\t\tconst responseFields = traverseSchema({\n\t\t\tschema: method.response,\n\t\t\tmessages,\n\t\t\tenums,\n\t\t\ttypePrefix\n\t\t})\n\t\tmessages.set(responseName, responseFields)\n\t}\n\n\treturn { requestName, responseName }\n}\n\nexport const generateServices = (\n\tservices: ServiceDefinition[],\n\tcontext: ServiceGenerationContext\n): string[] => {\n\treturn services.map((service) => {\n\t\tconst methods = service.methods.map((method) => {\n\t\t\tconst { requestName, responseName } = processServiceMethod(method, context)\n\n\t\t\tconst requestStreaming = method.streaming === 'client' || method.streaming === 'bidirectional'\n\t\t\tconst responseStreaming = method.streaming === 'server' || method.streaming === 'bidirectional'\n\n\t\t\tconst requestType = requestStreaming ? `stream ${requestName}` : requestName\n\t\t\tconst responseType = responseStreaming ? `stream ${responseName}` : responseName\n\n\t\t\treturn ` rpc ${method.name}(${requestType}) returns (${responseType});`\n\t\t})\n\n\t\treturn `service ${service.name} {\\n${methods.join('\\n')}\\n}`\n\t})\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 if (services.length > 0) {\n generateServices(services, context);\n }\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 servicesString =\n services.length > 0 ? generateServices(services, context) : [];\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"],"sources":["../src/types.ts","../src/utils.ts","../src/traversers.ts","../src/service-generator.ts","../src/zod-to-protobuf.ts"],"sourcesContent":["import type { ZodTypeAny } from \"zod\";\n\nexport interface ZodToProtobufOptions {\n packageName?: string;\n rootMessageName?: string;\n typePrefix?: string;\n services?: ServiceDefinition[];\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 keyType = traverseKey({\n key: `${key}Key`,\n value: value._def.keyType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n });\n const valueType = traverseKey({\n key: `${key}Value`,\n value: value._def.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 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 (!(schema instanceof ZodObject)) {\n throw new UnsupportedTypeException(schema.constructor.name);\n }\n\n const fields = Object.entries(schema.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 type { ZodTypeAny } from \"zod\";\nimport type { ServiceDefinition, ServiceMethod } 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 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 requestFields = traverseSchema({\n schema: method.request,\n messages,\n enums,\n typePrefix,\n });\n messages.set(requestName, requestFields);\n }\n\n if (!messages.has(responseName)) {\n const responseFields = traverseSchema({\n schema: method.response,\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: ServiceDefinition[],\n context: ServiceGenerationContext\n): string[] => {\n return services.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 if (services.length > 0) {\n generateServices(services, context);\n }\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 servicesString =\n services.length > 0 ? generateServices(services, context) : [];\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsBA,IAAa,2BAAb,cAA8C,MAAM;CAClD,YAAY,MAAc;AACxB,QAAM,qBAAqB,OAAO;AAClC,OAAK,OAAO;;;;;;ACtBhB,MAAa,qBAAqB,EAAE,YAA0C;AAC5E,QAAO,MAAM,QAAQ,UAAU;;AAGjC,MAAa,gBAAgB,EAAE,YAAuC;AACpE,QAAO,MACJ,MAAM,IAAI,CACV,KAAK,SAAS,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,CAAC,CAC3D,KAAK,GAAG;;AAGb,MAAa,uBAAuB,EAClC,YAGY;AACZ,QAAO,MAAM,MAAM,OAAO,QAAQ,CAAC,KAAK,IAAI;;;;;ACE9C,MAAa,iBAAiB,EAC5B,KACA,OACA,UACA,OACA,iBAOqB;CACrB,MAAM,cACJ,iBAAiBA,eACb,MAAM,UACN,iBAAiBC,aACd,MAAM,KAAmC,YAEzC,MAAM,KAAkC;CAEjD,MAAM,cAAc,WAAW,YAAY,IAAI;AAU/C,QATsB,YAAY;EAChC,KAAK;EACL,OAAO;EACP;EACA;EACA,YAAY;EACZ,WAAW;EACX;EACD,CAAC,CACmB,KAAK,WAAW;EACnC,GAAG;EACH,OAAO,CAAC,YAAY,GAAG,MAAM,MAAM;EACnC,MAAM,MAAM,KAAK,QAAQ,aAAa,IAAI;EAC3C,EAAE;;AAGL,MAAa,eAAe,EAC1B,KACA,OACA,UACA,OACA,iBAOqB;CACrB,MAAM,UAAU,YAAY;EAC1B,KAAK,GAAG,IAAI;EACZ,OAAO,MAAM,KAAK;EAClB;EACA;EACA,YAAY;EACZ,WAAW;EACX;EACD,CAAC;CACF,MAAM,YAAY,YAAY;EAC5B,KAAK,GAAG,IAAI;EACZ,OAAO,MAAM,KAAK;EAClB;EACA;EACA,YAAY;EACZ,WAAW;EACX;EACD,CAAC;AAEF,KAAI,CAAC,QAAQ,MAAM,QAAQ,WAAW,EACpC,OAAM,IAAI,yBAAyB,GAAG,IAAI,UAAU;AAGtD,KAAI,CAAC,UAAU,MAAM,UAAU,WAAW,EACxC,OAAM,IAAI,yBAAyB,GAAG,IAAI,YAAY;AAIxD,QAAO,CACL;EACE,OAAO,CAHK,OAAO,oBAAoB,EAAE,OAAO,QAAQ,IAAI,CAAC,CAAC,IAAI,oBAAoB,EAAE,OAAO,UAAU,IAAI,CAAC,CAAC,GAG/F;EAChB,MAAM;EACP,CACF;;AAGH,MAAa,eAAe,EAC1B,KACA,OACA,UACA,OACA,YACA,WACA,iBASqB;AACrB,KAAI,iBAAiBC,mBAAe,iBAAiBC,gBACnD,QAAO,YAAY;EACjB;EACA,OAAO,MAAM,QAAQ;EACrB;EACA;EACA,YAAY;EACZ;EACA;EACD,CAAC;AAGJ,KAAI,iBAAiBH,gBAAY,iBAAiBC,WAChD,QAAO,cAAc;EACnB;EACO;EACP;EACA;EACA;EACD,CAAC;AAGJ,KAAI,iBAAiBG,WACnB,QAAO,YAAY;EACjB;EACO;EACP;EACA;EACA;EACD,CAAC;CAGJ,MAAM,WAAW,cAAc,CAAC,YAAY,aAAa;AAEzD,KAAI,iBAAiBC,eAAW;EAC9B,IAAI,cAAc,aAAa,EAAE,OAAO,KAAK,CAAC;AAC9C,MAAI,WACF,eAAc,GAAG,aAAa;EAEhC,MAAM,sBAAsB,eAAe;GACzC,QAAQ;GACR;GACA;GACA;GACD,CAAC;AACF,WAAS,IAAI,aAAa,oBAAoB;AAC9C,SAAO,CACL;GACE,OAAO,CAAC,UAAU,YAAY;GAC9B,MAAM;GACP,CACF;;AAGH,KAAI,iBAAiBC,cACnB,QAAO,CACL;EACE,OAAO,CAAC,UAAU,SAAS;EAC3B,MAAM;EACP,CACF;AAGH,KAAI,iBAAiBC,cAEnB,QAAO,CACL;EACE,OAAO,CAAC,UAHK,kBAAkB,EAAE,OAAO,CAAC,CAGd;EAC3B,MAAM;EACP,CACF;AAGH,KAAI,iBAAiBC,eACnB,QAAO,CACL;EACE,OAAO,CAAC,UAAU,OAAO;EACzB,MAAM;EACP,CACF;AAGH,KAAI,iBAAiBC,aAAS;EAC5B,MAAM,aAAa,MAAM,QACtB,KACE,QAAyB,UACxB,OAAO,OAAO,OAAO,CAAC,KAAK,MAAM,GACpC,CACA,KAAK,KAAK;EACb,IAAI,WAAW,aAAa,EAAE,OAAO,KAAK,CAAC;AAC3C,MAAI,WACF,YAAW,GAAG,aAAa;AAE7B,QAAM,IAAI,UAAU,CAAC,QAAQ,SAAS,MAAM,WAAW,KAAK,CAAC;AAC7D,SAAO,CACL;GACE,OAAO,CAAC,UAAU,SAAS;GAC3B,MAAM;GACP,CACF;;AAGH,KAAI,iBAAiBC,YACnB,QAAO,CACL;EACE,OAAO,CAAC,UAAU,SAAS;EAC3B,MAAM;EACP,CACF;AAGH,KAAI,iBAAiBC,cACnB,QAAO,CACL;EACE,OAAO,CAAC,UAAU,QAAQ;EAC1B,MAAM;EACP,CACF;AAGH,KAAI,iBAAiBC,cAAU;EAC7B,MAAMC,cACJ,MAAM,KAAK,MACX,SAAS,MAAkB,UAAkB;AAC7C,UAAO,YAAY;IACjB,KAAK,GAAG,IAAI,GAAG;IACf,OAAO;IACP;IACA;IACA,YAAY;IACZ;IACA;IACD,CAAC;IACF;EAEF,MAAM,mBAAmB,aAAa,EAAE,OAAO,KAAK,CAAC;AACrD,WAAS,IACP,kBACA,YAAY,KACT,OAAO,UACN,KAAK,MAAM,MAAM,KAAK,IAAI,CAAC,GAAG,MAAM,KAAK,KAAK,QAAQ,EAAE,GAC3D,CACF;AACD,SAAO,CACL;GACE,OAAO,CAAC,UAAU,iBAAiB;GACnC,MAAM;GACP,CACF;;AAGH,KAAI,iBAAiBC,YACnB,OAAM,IAAI,yBAAyB,MAAM,YAAY,KAAK;AAG5D,OAAM,IAAI,yBAAyB,OAAO,MAAM;;AAGlD,MAAa,kBAAkB,EAC7B,QACA,UACA,OACA,iBAMc;AACd,KAAI,EAAE,kBAAkBT,eACtB,OAAM,IAAI,yBAAyB,OAAO,YAAY,KAAK;AAe7D,QAZe,OAAO,QAAQ,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,WAAW;AACpE,SAAO,YAAY;GACjB;GACA;GACA;GACA;GACA,YAAY;GACZ,WAAW;GACX;GACD,CAAC;GACF,CAEY,KACX,OAAO,UACN,GAAG,oBAAoB,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,KAAK,KAAK,QAAQ,EAAE,GAClE;;;;;AC9SH,MAAM,8BACJ,YACA,eACW;CACX,MAAM,cAAc,aAAa,EAAE,OAAO,GAAG,WAAW,UAAU,CAAC;AACnE,QAAO,aAAa,GAAG,aAAa,gBAAgB;;AAGtD,MAAM,+BACJ,YACA,eACW;CACX,MAAM,cAAc,aAAa,EAAE,OAAO,GAAG,WAAW,WAAW,CAAC;AACpE,QAAO,aAAa,GAAG,aAAa,gBAAgB;;AAGtD,MAAM,wBACJ,QACA,YACkD;CAClD,MAAM,EAAE,UAAU,OAAO,eAAe;CAExC,MAAM,cAAc,2BAA2B,OAAO,MAAM,WAAW;CACvE,MAAM,eAAe,4BAA4B,OAAO,MAAM,WAAW;AAEzE,KAAI,CAAC,SAAS,IAAI,YAAY,EAAE;EAC9B,MAAM,gBAAgB,eAAe;GACnC,QAAQ,OAAO;GACf;GACA;GACA;GACD,CAAC;AACF,WAAS,IAAI,aAAa,cAAc;;AAG1C,KAAI,CAAC,SAAS,IAAI,aAAa,EAAE;EAC/B,MAAM,iBAAiB,eAAe;GACpC,QAAQ,OAAO;GACf;GACA;GACA;GACD,CAAC;AACF,WAAS,IAAI,cAAc,eAAe;;AAG5C,QAAO;EAAE;EAAa;EAAc;;AAGtC,MAAa,oBACX,UACA,YACa;AACb,QAAO,SAAS,KAAK,YAAY;EAC/B,MAAM,UAAU,QAAQ,QAAQ,KAAK,WAAW;GAC9C,MAAM,EAAE,aAAa,iBAAiB,qBACpC,QACA,QACD;GAED,MAAM,mBACJ,OAAO,cAAc,YAAY,OAAO,cAAc;GACxD,MAAM,oBACJ,OAAO,cAAc,YAAY,OAAO,cAAc;GAExD,MAAM,cAAc,mBAChB,UAAU,gBACV;GACJ,MAAM,eAAe,oBACjB,UAAU,iBACV;AAEJ,UAAO,WAAW,aAAa,EAAE,OAAO,OAAO,MAAM,CAAC,CAAC,GAAG,YAAY,aAAa,aAAa;IAChG;AAEF,SAAO,WAAW,aAAa,EAAE,OAAO,QAAQ,MAAM,CAAC,CAAC,MAAM,QAAQ,KAAK,KAAK,CAAC;GACjF;;;;;ACjFJ,MAAa,iBACX,QACA,UAAgC,EAAE,KACvB;CACX,MAAM,EACJ,cAAc,WACd,kBAAkB,WAClB,aAAa,IACb,WAAW,EAAE,EACb,kBAAkB,UAChB;CAEJ,MAAM,2BAAW,IAAI,KAAuB;CAC5C,MAAM,wBAAQ,IAAI,KAAuB;AAEzC,KAAI,UAAU,CAAC,iBAAiB;EAC9B,MAAM,SAAS,eAAe;GAAE;GAAQ;GAAU;GAAO;GAAY,CAAC;AACtE,MAAI,OAAO,SAAS,GAAG;GACrB,MAAM,iBAAiB,GAAG,aAAa;AACvC,YAAS,IAAI,gBAAgB,OAAO;;;CAIxC,MAAM,UAAU;EACd;EACA;EACA,YAAY,cAAc;EAC3B;AAED,KAAI,SAAS,SAAS,EACpB,kBAAiB,UAAU,QAAQ;AA2BrC,QAPwB;;UAEhB,YAAY;;EAPJ;EAZI,MAAM,KAAK,MAAM,QAAQ,CAAC,CAAC,KAAK,YAClD,QAAQ,KAAK,KAAK,CACnB;EAEsB,MAAM,KAAK,SAAS,SAAS,CAAC,CAAC,KACnD,CAAC,MAAM,YACN,WAAW,KAAK,MAAM,OAAO,KAAK,UAAU,OAAO,QAAQ,CAAC,KAAK,KAAK,CAAC,KAC1E;EAGC,SAAS,SAAS,IAAI,iBAAiB,UAAU,QAAQ,GAAG,EAAE;EAEH,CAC1D,QAAQ,YAAY,CAAC,CAAC,QAAQ,OAAO,CACrC,KAAK,YAAY,QAAQ,KAAK,OAAO,CAAC,CACtC,KAAK,OAAO,CAMP;EAGe,MAAM"}
package/dist/index.d.cts CHANGED
@@ -12,18 +12,15 @@ interface ServiceMethod {
12
12
  name: string;
13
13
  request: ZodTypeAny;
14
14
  response: ZodTypeAny;
15
- streaming?: 'client' | 'server' | 'bidirectional';
15
+ streaming?: "client" | "server" | "bidirectional";
16
16
  }
17
17
  interface ServiceDefinition {
18
18
  name: string;
19
19
  methods: ServiceMethod[];
20
20
  }
21
- declare class UnsupportedTypeException extends Error {
22
- constructor(type: string);
23
- }
24
21
  //#endregion
25
22
  //#region src/zod-to-protobuf.d.ts
26
23
  declare const zodToProtobuf: (schema?: ZodTypeAny, options?: ZodToProtobufOptions) => string;
27
24
  //#endregion
28
- export { type ServiceDefinition, type ServiceMethod, UnsupportedTypeException, type ZodToProtobufOptions, zodToProtobuf };
25
+ export { zodToProtobuf };
29
26
  //# sourceMappingURL=index.d.cts.map
package/dist/index.d.mts CHANGED
@@ -12,18 +12,15 @@ interface ServiceMethod {
12
12
  name: string;
13
13
  request: ZodTypeAny;
14
14
  response: ZodTypeAny;
15
- streaming?: 'client' | 'server' | 'bidirectional';
15
+ streaming?: "client" | "server" | "bidirectional";
16
16
  }
17
17
  interface ServiceDefinition {
18
18
  name: string;
19
19
  methods: ServiceMethod[];
20
20
  }
21
- declare class UnsupportedTypeException extends Error {
22
- constructor(type: string);
23
- }
24
21
  //#endregion
25
22
  //#region src/zod-to-protobuf.d.ts
26
23
  declare const zodToProtobuf: (schema?: ZodTypeAny, options?: ZodToProtobufOptions) => string;
27
24
  //#endregion
28
- export { type ServiceDefinition, type ServiceMethod, UnsupportedTypeException, type ZodToProtobufOptions, zodToProtobuf };
25
+ export { zodToProtobuf };
29
26
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -218,9 +218,9 @@ const generateServices = (services, context) => {
218
218
  const responseStreaming = method.streaming === "server" || method.streaming === "bidirectional";
219
219
  const requestType = requestStreaming ? `stream ${requestName}` : requestName;
220
220
  const responseType = responseStreaming ? `stream ${responseName}` : responseName;
221
- return ` rpc ${method.name}(${requestType}) returns (${responseType});`;
221
+ return ` rpc ${toPascalCase({ value: method.name })}(${requestType}) returns (${responseType});`;
222
222
  });
223
- return `service ${service.name} {\n${methods.join("\n")}\n}`;
223
+ return `service ${toPascalCase({ value: service.name })} {\n${methods.join("\n")}\n}`;
224
224
  });
225
225
  };
226
226
 
@@ -261,5 +261,5 @@ ${[
261
261
  };
262
262
 
263
263
  //#endregion
264
- export { UnsupportedTypeException, zodToProtobuf };
264
+ export { zodToProtobuf };
265
265
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["tupleFields: ProtobufField[]"],"sources":["../src/types.ts","../src/utils.ts","../src/traversers.ts","../src/service-generator.ts","../src/zod-to-protobuf.ts"],"sourcesContent":["import type { ZodTypeAny } from 'zod'\n\nexport interface ZodToProtobufOptions {\n\tpackageName?: string\n\trootMessageName?: string\n\ttypePrefix?: string\n\tservices?: ServiceDefinition[]\n\tskipRootMessage?: boolean\n}\n\nexport interface ServiceMethod {\n\tname: string\n\trequest: ZodTypeAny\n\tresponse: ZodTypeAny\n\tstreaming?: 'client' | 'server' | 'bidirectional'\n}\n\nexport interface ServiceDefinition {\n\tname: string\n\tmethods: ServiceMethod[]\n}\n\nexport class UnsupportedTypeException extends Error {\n\tconstructor(type: string) {\n\t\tsuper(`Unsupported type: ${type}`)\n\t\tthis.name = 'UnsupportedTypeException'\n\t}\n}\n\nexport interface ProtobufField {\n\ttypes: Array<string | null>\n\tname: string\n}\n\n","import { ZodNumber } from 'zod'\nimport type { ProtobufField } from './types'\n\nexport const getNumberTypeName = ({ value }: { value: ZodNumber }): string => {\n\treturn value.isInt ? 'int32' : 'double'\n}\n\nexport const toPascalCase = ({ value }: { value: string }): string => {\n\treturn value\n\t\t.split('.')\n\t\t.map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n\t\t.join('')\n}\n\nexport const protobufFieldToType = ({ field }: { field: ProtobufField }): string => {\n\treturn field.types.filter(Boolean).join(' ')\n}\n\n","import * as inflection from 'inflection'\nimport {\n\tZodArray,\n\tZodBigInt,\n\tZodBoolean,\n\tZodDate,\n\tZodEnum,\n\tZodMap,\n\tZodNullable,\n\tZodNumber,\n\tZodObject,\n\tZodOptional,\n\tZodSet,\n\tZodString,\n\tZodTuple,\n\tZodType,\n\ttype ZodTypeAny\n} from 'zod'\nimport { UnsupportedTypeException, type ProtobufField } from './types'\nimport { getNumberTypeName, toPascalCase, protobufFieldToType } from './utils'\n\nexport const traverseArray = ({\n\tkey,\n\tvalue,\n\tmessages,\n\tenums,\n\ttypePrefix\n}: {\n\tkey: string\n\tvalue: ZodArray<ZodTypeAny> | ZodSet<ZodTypeAny>\n\tmessages: Map<string, string[]>\n\tenums: Map<string, string[]>\n\ttypePrefix: string | null\n}): ProtobufField[] => {\n\tconst nestedValue =\n\t\tvalue instanceof ZodArray\n\t\t\t? value.element\n\t\t\t: value instanceof ZodSet\n\t\t\t\t? (value._def as { valueType: ZodTypeAny }).valueType\n\t\t\t\t: // @ts-expect-error\n\t\t\t\t\t(value._def as { element?: ZodTypeAny }).element\n\n\tconst singularKey = inflection.singularize(key)\n\tconst elementFields = traverseKey({\n\t\tkey: singularKey,\n\t\tvalue: nestedValue,\n\t\tmessages,\n\t\tenums,\n\t\tisOptional: false,\n\t\tisInArray: true,\n\t\ttypePrefix\n\t})\n\treturn elementFields.map((field) => ({\n\t\t...field,\n\t\ttypes: ['repeated', ...field.types],\n\t\tname: field.name.replace(singularKey, key)\n\t}))\n}\n\nexport const traverseMap = ({\n\tkey,\n\tvalue,\n\tmessages,\n\tenums,\n\ttypePrefix\n}: {\n\tkey: string\n\tvalue: ZodMap<ZodTypeAny, ZodTypeAny>\n\tmessages: Map<string, string[]>\n\tenums: Map<string, string[]>\n\ttypePrefix: string | null\n}): ProtobufField[] => {\n\tconst keyType = traverseKey({\n\t\tkey: `${key}Key`,\n\t\tvalue: value._def.keyType,\n\t\tmessages,\n\t\tenums,\n\t\tisOptional: false,\n\t\tisInArray: true,\n\t\ttypePrefix\n\t})\n\tconst valueType = traverseKey({\n\t\tkey: `${key}Value`,\n\t\tvalue: value._def.valueType,\n\t\tmessages,\n\t\tenums,\n\t\tisOptional: false,\n\t\tisInArray: true,\n\t\ttypePrefix\n\t})\n\n\tif (!keyType[0] || keyType.length !== 1) {\n\t\tthrow new UnsupportedTypeException(`${key} map key`)\n\t}\n\n\tif (!valueType[0] || valueType.length !== 1) {\n\t\tthrow new UnsupportedTypeException(`${key} map value`)\n\t}\n\n\tconst mapType = `map<${protobufFieldToType({ field: keyType[0] })}, ${protobufFieldToType({ field: valueType[0] })}>`\n\treturn [\n\t\t{\n\t\t\ttypes: [mapType],\n\t\t\tname: key\n\t\t}\n\t]\n}\n\nexport const traverseKey = ({\n\tkey,\n\tvalue,\n\tmessages,\n\tenums,\n\tisOptional,\n\tisInArray,\n\ttypePrefix\n}: {\n\tkey: string\n\tvalue: unknown\n\tmessages: Map<string, string[]>\n\tenums: Map<string, string[]>\n\tisOptional: boolean\n\tisInArray: boolean\n\ttypePrefix: string | null\n}): ProtobufField[] => {\n\tif (value instanceof ZodOptional || value instanceof ZodNullable) {\n\t\treturn traverseKey({\n\t\t\tkey,\n\t\t\tvalue: value.unwrap(),\n\t\t\tmessages,\n\t\t\tenums,\n\t\t\tisOptional: true,\n\t\t\tisInArray,\n\t\t\ttypePrefix\n\t\t})\n\t}\n\n\tif (value instanceof ZodArray || value instanceof ZodSet) {\n\t\treturn traverseArray({\n\t\t\tkey,\n\t\t\tvalue: value as ZodArray<ZodTypeAny> | ZodSet<ZodTypeAny>,\n\t\t\tmessages,\n\t\t\tenums,\n\t\t\ttypePrefix\n\t\t})\n\t}\n\n\tif (value instanceof ZodMap) {\n\t\treturn traverseMap({\n\t\t\tkey,\n\t\t\tvalue: value as ZodMap<ZodTypeAny, ZodTypeAny>,\n\t\t\tmessages,\n\t\t\tenums,\n\t\t\ttypePrefix\n\t\t})\n\t}\n\n\tconst optional = isOptional && !isInArray ? 'optional' : null\n\n\tif (value instanceof ZodObject) {\n\t\tlet messageName = toPascalCase({ value: key })\n\t\tif (typePrefix) {\n\t\t\tmessageName = `${typePrefix}${messageName}`\n\t\t}\n\t\tconst nestedMessageFields = traverseSchema({\n\t\t\tschema: value,\n\t\t\tmessages,\n\t\t\tenums,\n\t\t\ttypePrefix\n\t\t})\n\t\tmessages.set(messageName, nestedMessageFields)\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, messageName],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodString) {\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, 'string'],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodNumber) {\n\t\tconst typeName = getNumberTypeName({ value })\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, typeName],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodBoolean) {\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, 'bool'],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodEnum) {\n\t\tconst enumFields = value.options\n\t\t\t.map(\n\t\t\t\t(option: string | number, index: number) =>\n\t\t\t\t\t` ${String(option)} = ${index};`\n\t\t\t)\n\t\t\t.join('\\n')\n\t\tlet enumName = toPascalCase({ value: key })\n\t\tif (typePrefix) {\n\t\t\tenumName = `${typePrefix}${enumName}`\n\t\t}\n\t\tenums.set(enumName, [`enum ${enumName} {\\n${enumFields}\\n}`])\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, enumName],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodDate) {\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, 'string'],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodBigInt) {\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, 'int64'],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodTuple) {\n\t\tconst tupleFields: ProtobufField[] = (\n\t\t\tvalue._def.items as ZodTypeAny[]\n\t\t).flatMap((item: ZodTypeAny, index: number) => {\n\t\t\treturn traverseKey({\n\t\t\t\tkey: `${key}_${index}`,\n\t\t\t\tvalue: item,\n\t\t\t\tmessages,\n\t\t\t\tenums,\n\t\t\t\tisOptional: false,\n\t\t\t\tisInArray,\n\t\t\t\ttypePrefix\n\t\t\t})\n\t\t})\n\n\t\tconst tupleMessageName = toPascalCase({ value: key })\n\t\tmessages.set(\n\t\t\ttupleMessageName,\n\t\t\ttupleFields.map(\n\t\t\t\t(field, index) =>\n\t\t\t\t\t` ${field.types.join(' ')} ${field.name} = ${index + 1};`\n\t\t\t)\n\t\t)\n\t\treturn [\n\t\t\t{\n\t\t\t\ttypes: [optional, tupleMessageName],\n\t\t\t\tname: key\n\t\t\t}\n\t\t]\n\t}\n\n\tif (value instanceof ZodType) {\n\t\tthrow new UnsupportedTypeException(value.constructor.name)\n\t}\n\n\tthrow new UnsupportedTypeException(typeof value)\n}\n\nexport const traverseSchema = ({\n\tschema,\n\tmessages,\n\tenums,\n\ttypePrefix\n}: {\n\tschema: ZodTypeAny\n\tmessages: Map<string, string[]>\n\tenums: Map<string, string[]>\n\ttypePrefix: string | null\n}): string[] => {\n\tif (!(schema instanceof ZodObject)) {\n\t\tthrow new UnsupportedTypeException(schema.constructor.name)\n\t}\n\n\tconst fields = Object.entries(schema.shape).flatMap(([key, value]) => {\n\t\treturn traverseKey({\n\t\t\tkey,\n\t\t\tvalue,\n\t\t\tmessages,\n\t\t\tenums,\n\t\t\tisOptional: false,\n\t\t\tisInArray: false,\n\t\t\ttypePrefix\n\t\t})\n\t})\n\n\treturn fields.map(\n\t\t(field, index) =>\n\t\t\t`${protobufFieldToType({ field })} ${field.name} = ${index + 1};`\n\t)\n}\n\n","import type { ZodTypeAny } from 'zod'\nimport type { ServiceDefinition, ServiceMethod } from './types'\nimport { toPascalCase } from './utils'\nimport { traverseSchema } from './traversers'\n\ninterface ServiceGenerationContext {\n\tmessages: Map<string, string[]>\n\tenums: Map<string, string[]>\n\ttypePrefix: string | null\n}\n\nconst generateRequestMessageName = (methodName: string, typePrefix: string | null): string => {\n\tconst messageName = toPascalCase({ value: `${methodName}Request` })\n\treturn typePrefix ? `${typePrefix}${messageName}` : messageName\n}\n\nconst generateResponseMessageName = (methodName: string, typePrefix: string | null): string => {\n\tconst messageName = toPascalCase({ value: `${methodName}Response` })\n\treturn typePrefix ? `${typePrefix}${messageName}` : messageName\n}\n\nconst processServiceMethod = (\n\tmethod: ServiceMethod,\n\tcontext: ServiceGenerationContext\n): { requestName: string; responseName: string } => {\n\tconst { messages, enums, typePrefix } = context\n\n\tconst requestName = generateRequestMessageName(method.name, typePrefix)\n\tconst responseName = generateResponseMessageName(method.name, typePrefix)\n\n\tif (!messages.has(requestName)) {\n\t\tconst requestFields = traverseSchema({\n\t\t\tschema: method.request,\n\t\t\tmessages,\n\t\t\tenums,\n\t\t\ttypePrefix\n\t\t})\n\t\tmessages.set(requestName, requestFields)\n\t}\n\n\tif (!messages.has(responseName)) {\n\t\tconst responseFields = traverseSchema({\n\t\t\tschema: method.response,\n\t\t\tmessages,\n\t\t\tenums,\n\t\t\ttypePrefix\n\t\t})\n\t\tmessages.set(responseName, responseFields)\n\t}\n\n\treturn { requestName, responseName }\n}\n\nexport const generateServices = (\n\tservices: ServiceDefinition[],\n\tcontext: ServiceGenerationContext\n): string[] => {\n\treturn services.map((service) => {\n\t\tconst methods = service.methods.map((method) => {\n\t\t\tconst { requestName, responseName } = processServiceMethod(method, context)\n\n\t\t\tconst requestStreaming = method.streaming === 'client' || method.streaming === 'bidirectional'\n\t\t\tconst responseStreaming = method.streaming === 'server' || method.streaming === 'bidirectional'\n\n\t\t\tconst requestType = requestStreaming ? `stream ${requestName}` : requestName\n\t\t\tconst responseType = responseStreaming ? `stream ${responseName}` : responseName\n\n\t\t\treturn ` rpc ${method.name}(${requestType}) returns (${responseType});`\n\t\t})\n\n\t\treturn `service ${service.name} {\\n${methods.join('\\n')}\\n}`\n\t})\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 if (services.length > 0) {\n generateServices(services, context);\n }\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 servicesString =\n services.length > 0 ? generateServices(services, context) : [];\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[]"],"sources":["../src/types.ts","../src/utils.ts","../src/traversers.ts","../src/service-generator.ts","../src/zod-to-protobuf.ts"],"sourcesContent":["import type { ZodTypeAny } from \"zod\";\n\nexport interface ZodToProtobufOptions {\n packageName?: string;\n rootMessageName?: string;\n typePrefix?: string;\n services?: ServiceDefinition[];\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 keyType = traverseKey({\n key: `${key}Key`,\n value: value._def.keyType,\n messages,\n enums,\n isOptional: false,\n isInArray: true,\n typePrefix,\n });\n const valueType = traverseKey({\n key: `${key}Value`,\n value: value._def.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 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 (!(schema instanceof ZodObject)) {\n throw new UnsupportedTypeException(schema.constructor.name);\n }\n\n const fields = Object.entries(schema.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 type { ZodTypeAny } from \"zod\";\nimport type { ServiceDefinition, ServiceMethod } 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 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 requestFields = traverseSchema({\n schema: method.request,\n messages,\n enums,\n typePrefix,\n });\n messages.set(requestName, requestFields);\n }\n\n if (!messages.has(responseName)) {\n const responseFields = traverseSchema({\n schema: method.response,\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: ServiceDefinition[],\n context: ServiceGenerationContext\n): string[] => {\n return services.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 if (services.length > 0) {\n generateServices(services, context);\n }\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 servicesString =\n services.length > 0 ? generateServices(services, context) : [];\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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@globalart/zod-to-proto",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "author": {
5
5
  "name": "GlobalArt, Inc"
6
6
  },
@@ -11,12 +11,20 @@
11
11
  "README.md",
12
12
  "LICENSE"
13
13
  ],
14
- "main": "./dist/index.js",
15
- "module": "./dist/index.js",
16
- "types": "./dist/index.d.ts",
14
+ "main": "./dist/index.cjs",
15
+ "module": "./dist/index.mjs",
16
+ "types": "./dist/index.d.cts",
17
17
  "exports": {
18
- ".": "./dist/index.js",
19
- "./package.json": "./package.json"
18
+ ".": {
19
+ "import": {
20
+ "types": "./dist/index.d.mts",
21
+ "default": "./dist/index.mjs"
22
+ },
23
+ "require": {
24
+ "types": "./dist/index.d.cts",
25
+ "default": "./dist/index.cjs"
26
+ }
27
+ }
20
28
  },
21
29
  "scripts": {
22
30
  "format": "prettier --write \"**/*.ts\"",