@globalart/zod-to-proto 1.0.1 → 1.0.3

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 ADDED
@@ -0,0 +1,290 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ let inflection = require("inflection");
25
+ inflection = __toESM(inflection);
26
+ let zod = require("zod");
27
+
28
+ //#region src/types.ts
29
+ var UnsupportedTypeException = class extends Error {
30
+ constructor(type) {
31
+ super(`Unsupported type: ${type}`);
32
+ this.name = "UnsupportedTypeException";
33
+ }
34
+ };
35
+
36
+ //#endregion
37
+ //#region src/utils.ts
38
+ const getNumberTypeName = ({ value }) => {
39
+ return value.isInt ? "int32" : "double";
40
+ };
41
+ const toPascalCase = ({ value }) => {
42
+ return value.split(".").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
43
+ };
44
+ const protobufFieldToType = ({ field }) => {
45
+ return field.types.filter(Boolean).join(" ");
46
+ };
47
+
48
+ //#endregion
49
+ //#region src/traversers.ts
50
+ const traverseArray = ({ key, value, messages, enums, typePrefix }) => {
51
+ const nestedValue = value instanceof zod.ZodArray ? value.element : value instanceof zod.ZodSet ? value._def.valueType : value._def.element;
52
+ const singularKey = inflection.singularize(key);
53
+ return traverseKey({
54
+ key: singularKey,
55
+ value: nestedValue,
56
+ messages,
57
+ enums,
58
+ isOptional: false,
59
+ isInArray: true,
60
+ typePrefix
61
+ }).map((field) => ({
62
+ ...field,
63
+ types: ["repeated", ...field.types],
64
+ name: field.name.replace(singularKey, key)
65
+ }));
66
+ };
67
+ const traverseMap = ({ key, value, messages, enums, typePrefix }) => {
68
+ const keyType = traverseKey({
69
+ key: `${key}Key`,
70
+ value: value._def.keyType,
71
+ messages,
72
+ enums,
73
+ isOptional: false,
74
+ isInArray: true,
75
+ typePrefix
76
+ });
77
+ const valueType = traverseKey({
78
+ key: `${key}Value`,
79
+ value: value._def.valueType,
80
+ messages,
81
+ enums,
82
+ isOptional: false,
83
+ isInArray: true,
84
+ typePrefix
85
+ });
86
+ if (!keyType[0] || keyType.length !== 1) throw new UnsupportedTypeException(`${key} map key`);
87
+ if (!valueType[0] || valueType.length !== 1) throw new UnsupportedTypeException(`${key} map value`);
88
+ return [{
89
+ types: [`map<${protobufFieldToType({ field: keyType[0] })}, ${protobufFieldToType({ field: valueType[0] })}>`],
90
+ name: key
91
+ }];
92
+ };
93
+ const traverseKey = ({ key, value, messages, enums, isOptional, isInArray, typePrefix }) => {
94
+ if (value instanceof zod.ZodOptional || value instanceof zod.ZodNullable) return traverseKey({
95
+ key,
96
+ value: value.unwrap(),
97
+ messages,
98
+ enums,
99
+ isOptional: true,
100
+ isInArray,
101
+ typePrefix
102
+ });
103
+ if (value instanceof zod.ZodArray || value instanceof zod.ZodSet) return traverseArray({
104
+ key,
105
+ value,
106
+ messages,
107
+ enums,
108
+ typePrefix
109
+ });
110
+ if (value instanceof zod.ZodMap) return traverseMap({
111
+ key,
112
+ value,
113
+ messages,
114
+ enums,
115
+ typePrefix
116
+ });
117
+ const optional = isOptional && !isInArray ? "optional" : null;
118
+ if (value instanceof zod.ZodObject) {
119
+ let messageName = toPascalCase({ value: key });
120
+ if (typePrefix) messageName = `${typePrefix}${messageName}`;
121
+ const nestedMessageFields = traverseSchema({
122
+ schema: value,
123
+ messages,
124
+ enums,
125
+ typePrefix
126
+ });
127
+ messages.set(messageName, nestedMessageFields);
128
+ return [{
129
+ types: [optional, messageName],
130
+ name: key
131
+ }];
132
+ }
133
+ if (value instanceof zod.ZodString) return [{
134
+ types: [optional, "string"],
135
+ name: key
136
+ }];
137
+ if (value instanceof zod.ZodNumber) return [{
138
+ types: [optional, getNumberTypeName({ value })],
139
+ name: key
140
+ }];
141
+ if (value instanceof zod.ZodBoolean) return [{
142
+ types: [optional, "bool"],
143
+ name: key
144
+ }];
145
+ if (value instanceof zod.ZodEnum) {
146
+ const enumFields = value.options.map((option, index) => ` ${String(option)} = ${index};`).join("\n");
147
+ let enumName = toPascalCase({ value: key });
148
+ if (typePrefix) enumName = `${typePrefix}${enumName}`;
149
+ enums.set(enumName, [`enum ${enumName} {\n${enumFields}\n}`]);
150
+ return [{
151
+ types: [optional, enumName],
152
+ name: key
153
+ }];
154
+ }
155
+ if (value instanceof zod.ZodDate) return [{
156
+ types: [optional, "string"],
157
+ name: key
158
+ }];
159
+ if (value instanceof zod.ZodBigInt) return [{
160
+ types: [optional, "int64"],
161
+ name: key
162
+ }];
163
+ if (value instanceof zod.ZodTuple) {
164
+ const tupleFields = value._def.items.flatMap((item, index) => {
165
+ return traverseKey({
166
+ key: `${key}_${index}`,
167
+ value: item,
168
+ messages,
169
+ enums,
170
+ isOptional: false,
171
+ isInArray,
172
+ typePrefix
173
+ });
174
+ });
175
+ const tupleMessageName = toPascalCase({ value: key });
176
+ messages.set(tupleMessageName, tupleFields.map((field, index) => ` ${field.types.join(" ")} ${field.name} = ${index + 1};`));
177
+ return [{
178
+ types: [optional, tupleMessageName],
179
+ name: key
180
+ }];
181
+ }
182
+ if (value instanceof zod.ZodType) throw new UnsupportedTypeException(value.constructor.name);
183
+ throw new UnsupportedTypeException(typeof value);
184
+ };
185
+ const traverseSchema = ({ schema, messages, enums, typePrefix }) => {
186
+ if (!(schema instanceof zod.ZodObject)) throw new UnsupportedTypeException(schema.constructor.name);
187
+ return Object.entries(schema.shape).flatMap(([key, value]) => {
188
+ return traverseKey({
189
+ key,
190
+ value,
191
+ messages,
192
+ enums,
193
+ isOptional: false,
194
+ isInArray: false,
195
+ typePrefix
196
+ });
197
+ }).map((field, index) => `${protobufFieldToType({ field })} ${field.name} = ${index + 1};`);
198
+ };
199
+
200
+ //#endregion
201
+ //#region src/service-generator.ts
202
+ const generateRequestMessageName = (methodName, typePrefix) => {
203
+ const messageName = toPascalCase({ value: `${methodName}Request` });
204
+ return typePrefix ? `${typePrefix}${messageName}` : messageName;
205
+ };
206
+ const generateResponseMessageName = (methodName, typePrefix) => {
207
+ const messageName = toPascalCase({ value: `${methodName}Response` });
208
+ return typePrefix ? `${typePrefix}${messageName}` : messageName;
209
+ };
210
+ const processServiceMethod = (method, context) => {
211
+ const { messages, enums, typePrefix } = context;
212
+ const requestName = generateRequestMessageName(method.name, typePrefix);
213
+ const responseName = generateResponseMessageName(method.name, typePrefix);
214
+ if (!messages.has(requestName)) {
215
+ const requestFields = traverseSchema({
216
+ schema: method.request,
217
+ messages,
218
+ enums,
219
+ typePrefix
220
+ });
221
+ messages.set(requestName, requestFields);
222
+ }
223
+ if (!messages.has(responseName)) {
224
+ const responseFields = traverseSchema({
225
+ schema: method.response,
226
+ messages,
227
+ enums,
228
+ typePrefix
229
+ });
230
+ messages.set(responseName, responseFields);
231
+ }
232
+ return {
233
+ requestName,
234
+ responseName
235
+ };
236
+ };
237
+ const generateServices = (services, context) => {
238
+ return services.map((service) => {
239
+ const methods = service.methods.map((method) => {
240
+ const { requestName, responseName } = processServiceMethod(method, context);
241
+ const requestStreaming = method.streaming === "client" || method.streaming === "bidirectional";
242
+ const responseStreaming = method.streaming === "server" || method.streaming === "bidirectional";
243
+ const requestType = requestStreaming ? `stream ${requestName}` : requestName;
244
+ const responseType = responseStreaming ? `stream ${responseName}` : responseName;
245
+ return ` rpc ${method.name}(${requestType}) returns (${responseType});`;
246
+ });
247
+ return `service ${service.name} {\n${methods.join("\n")}\n}`;
248
+ });
249
+ };
250
+
251
+ //#endregion
252
+ //#region src/zod-to-protobuf.ts
253
+ const zodToProtobuf = (schema, options = {}) => {
254
+ const { packageName = "default", rootMessageName = "Message", typePrefix = "", services = [], skipRootMessage = false } = options;
255
+ const messages = /* @__PURE__ */ new Map();
256
+ const enums = /* @__PURE__ */ new Map();
257
+ if (schema && !skipRootMessage) {
258
+ const fields = traverseSchema({
259
+ schema,
260
+ messages,
261
+ enums,
262
+ typePrefix
263
+ });
264
+ if (fields.length > 0) {
265
+ const rootMessageKey = `${typePrefix}${rootMessageName}`;
266
+ messages.set(rootMessageKey, fields);
267
+ }
268
+ }
269
+ const context = {
270
+ messages,
271
+ enums,
272
+ typePrefix: typePrefix || null
273
+ };
274
+ if (services.length > 0) generateServices(services, context);
275
+ return `
276
+ syntax = "proto3";
277
+ package ${packageName};
278
+
279
+ ${[
280
+ Array.from(enums.values()).map((enumDef) => enumDef.join("\n")),
281
+ Array.from(messages.entries()).map(([name, fields]) => `message ${name} {\n${fields.map((field) => ` ${field}`).join("\n")}\n}`),
282
+ services.length > 0 ? generateServices(services, context) : []
283
+ ].filter((strings) => !!strings.length).map((strings) => strings.join("\n\n")).join("\n\n")}
284
+ `.trim();
285
+ };
286
+
287
+ //#endregion
288
+ exports.UnsupportedTypeException = UnsupportedTypeException;
289
+ exports.zodToProtobuf = zodToProtobuf;
290
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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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"}
@@ -0,0 +1,29 @@
1
+ import { ZodTypeAny } from "zod";
2
+
3
+ //#region src/types.d.ts
4
+ interface ZodToProtobufOptions {
5
+ packageName?: string;
6
+ rootMessageName?: string;
7
+ typePrefix?: string;
8
+ services?: ServiceDefinition[];
9
+ skipRootMessage?: boolean;
10
+ }
11
+ interface ServiceMethod {
12
+ name: string;
13
+ request: ZodTypeAny;
14
+ response: ZodTypeAny;
15
+ streaming?: 'client' | 'server' | 'bidirectional';
16
+ }
17
+ interface ServiceDefinition {
18
+ name: string;
19
+ methods: ServiceMethod[];
20
+ }
21
+ declare class UnsupportedTypeException extends Error {
22
+ constructor(type: string);
23
+ }
24
+ //#endregion
25
+ //#region src/zod-to-protobuf.d.ts
26
+ declare const zodToProtobuf: (schema?: ZodTypeAny, options?: ZodToProtobufOptions) => string;
27
+ //#endregion
28
+ export { type ServiceDefinition, type ServiceMethod, UnsupportedTypeException, type ZodToProtobufOptions, zodToProtobuf };
29
+ //# sourceMappingURL=index.d.cts.map
package/dist/index.d.mts CHANGED
@@ -25,4 +25,5 @@ declare class UnsupportedTypeException extends Error {
25
25
  //#region src/zod-to-protobuf.d.ts
26
26
  declare const zodToProtobuf: (schema?: ZodTypeAny, options?: ZodToProtobufOptions) => string;
27
27
  //#endregion
28
- export { type ServiceDefinition, type ServiceMethod, UnsupportedTypeException, type ZodToProtobufOptions, zodToProtobuf };
28
+ export { type ServiceDefinition, type ServiceMethod, UnsupportedTypeException, type ZodToProtobufOptions, zodToProtobuf };
29
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -261,4 +261,5 @@ ${[
261
261
  };
262
262
 
263
263
  //#endregion
264
- export { UnsupportedTypeException, zodToProtobuf };
264
+ export { UnsupportedTypeException, zodToProtobuf };
265
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@globalart/zod-to-proto",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "author": {
5
5
  "name": "GlobalArt, Inc"
6
6
  },
@@ -29,7 +29,7 @@
29
29
  "publish:dev": "npm publish --access public --tag dev",
30
30
  "publish:npm": "release-it --config ../../.release-it.json"
31
31
  },
32
- "description": "OpenID Connect strategy for GlobalArt SSO integration",
32
+ "description": "Convert Zod schemas to Protobuf definitions",
33
33
  "devDependencies": {
34
34
  "@types/express": "^5.0.0",
35
35
  "@types/node": "^24.9.1",