zod-to-x 1.2.0 → 1.2.1

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 CHANGED
@@ -14,36 +14,16 @@
14
14
 
15
15
 
16
16
  ## Why Use [`@zod-to-x`](https://github.com/rroumenov/zod-to-x)?
17
- In modern software development, managing data consistency across multiple layers and languages is a persistent challenge. [`@zod-to-x`](https://github.com/rroumenov/zod-to-x) tackles this problem head-on by enabling you to define your data models once, in a centralized and expressive way, and then effortlessly transpile these models into multiple programming languages. Here's why [`@zod-to-x`](https://github.com/rroumenov/zod-to-x) stands out:
17
+ Managing data consistency across multiple layers and languages is a common challenge in modern software development. [`@zod-to-x`](https://github.com/rroumenov/zod-to-x) solves this by allowing you to define your data models once and effortlessly transpile them into multiple programming languages. Heres why it stands out:
18
18
 
19
- 1. Centralized Data Definition
20
- With [`@zod-to-x`](https://github.com/rroumenov/zod-to-x), you define your data structures in one place using the powerful Zod library. This eliminates redundancy, reduces the risk of inconsistencies, and simplifies maintenance across your codebase.
19
+ 1. **Centralized Data Definition**
20
+ Define your data structures in one place using the powerful [`@zod`]((https://github.com/colinhacks/zod)) library. This eliminates redundancy, reduces inconsistencies, and simplifies maintenance across your entire codebase, all while allowing you to continue leveraging any npm package in the [`@zod`]((https://github.com/colinhacks/zod)) ecosystem like [`@zod-to-json-schema`](https://github.com/StefanTerdell/zod-to-json-schema)
21
21
 
22
- 2. Multi-Language Compatibility
23
- Gone are the days of manually rewriting data models for different platforms. [`@zod-to-x`](https://github.com/rroumenov/zod-to-x) lets you generate data types for:
22
+ 2. **Multi-Language Compatibility**
23
+ Generate data models for TypeScript, Protobuf V3 and C++ (with languages like Golang on the roadmap). No more manually rewriting models for different platforms.
24
24
 
25
- - TypeScript: Build strong, type-safe interfaces or classes for front-end and back-end applications.
26
- - Protobuf V3: Seamlessly integrate with gRPC and other Protobuf-based systems.
27
- - More Languages: Support for additional languages like C++ is on the roadmap.
28
-
29
- 3. Enhanced Productivity
30
- By automating the transpilation of data models, [`@zod-to-x`](https://github.com/rroumenov/zod-to-x) allows your team to focus on writing business logic instead of boilerplate code. Changes to schemas are propagated automatically, saving time and minimizing errors.
31
-
32
- 4. Built on Zod's Robust Ecosystem
33
- [`@zod-to-x`](https://github.com/rroumenov/zod-to-x) extends the capabilities of Zod, a popular and intuitive schema validation library. This means you can:
34
-
35
- - Leverage Zod's wide array of schema types and validations.
36
- - Maintain compatibility with existing Zod-based projects.
37
- - Easily integrate with tools like [`@zod-to-json-schema`](https://github.com/StefanTerdell/zod-to-json-schema).
38
-
39
- 5. Flexible Output Options
40
- Whether you need plain interfaces, full-fledged classes with constructors, or Protobuf definitions, [`@zod-to-x`](https://github.com/rroumenov/zod-to-x) can adapt to your specific needs with customizable output formats.
41
-
42
- 6. Transparent and Extendable
43
- The library is designed to be lightweight, transparent, and easy to integrate into existing workflows. Its extendable architecture ensures it can evolve to meet your project’s growing demands.
44
-
45
- 7. Ideal for Cross-Language Development
46
- If your application spans multiple languages—like a front-end in TypeScript, a back-end in Python, and microservices in Protobuf—[`@zod-to-x`](https://github.com/rroumenov/zod-to-x) simplifies the process of keeping data structures consistent across the stack.
25
+ 3. **Enhanced Productivity**
26
+ Automate the transpilation of data models to save time, reduce errors, and let your team focus on business logic instead of boilerplate code.
47
27
 
48
28
 
49
29
 
@@ -67,39 +47,36 @@ This extension appends a `zod2x` method to:
67
47
  - ZodUnion
68
48
  - ZodDiscriminatedUnion
69
49
  - ZodIntersection
50
+ - ZodLiteral
70
51
 
71
52
  ## Quick start
72
- ### 1) Define a data model using Zod schemas
73
53
  ```ts
74
54
  import { z } from "zod";
55
+ import { extendZod, Zod2Ast, Zod2Ts } from "zod-to-x";
56
+ extendZod(z); // The extend step can be skipped if it has already been done.
75
57
 
76
- // Skip the extend step if it has already been done.
77
- import { extendZod } from "zod-to-x";
78
- extendZod(z);
79
-
58
+ /**
59
+ * 1) Define a data model using Zod schemas
60
+ */
80
61
  const VisitorSchema = z.object({
81
62
  id: z.string().uuid(),
82
63
  name: z.string(),
83
64
  email: z.string().email(),
84
65
  visitDate: z.date(),
85
66
  comments: z.string().optional(),
86
- }).zod2x("Visitor"); // Add your expected output type name using the 'zod2x' method.
87
-
88
- ```
89
-
90
- ### 2) Build an AST node of the Zod schema
91
- ```ts
92
- import { Zod2Ast } from "zod-to-x";
67
+ }).zod2x("Visitor"); // Add your expected output type name using the 'zod2x' method.
93
68
 
69
+ /**
70
+ * 2) Build an AST node of the Zod schema
71
+ */
94
72
  const visitorNodes = new Zod2Ast().build(VisitorSchema);
95
- ```
96
73
 
97
- ### 3) Generate types in the desired language
98
- ```ts
99
- import { Zod2Ts } from "zod-to-x";
100
-
101
- const tsVisitor: string = new Zod2Ts().transpile(visitorNodes);
102
- console.log(tsVisitor)
74
+ /**
75
+ * 3) Generate types in the desired language.
76
+ * Depending on the transpiled language, data models can be generated using classes.
77
+ */
78
+ const tsVisitorAsInterface: string = new Zod2Ts().transpile(visitorNodes);
79
+ console.log(tsVisitorAsInterface)
103
80
  // output:
104
81
  // export interface Visitor {
105
82
  // id: string;
@@ -108,14 +85,9 @@ console.log(tsVisitor)
108
85
  // visitDate: Date;
109
86
  // comments?: string;
110
87
  // }
111
- ```
112
- Depending on the transpiled language, data models can be generated using classes:
113
-
114
- ```ts
115
- import { Zod2Ts } from "zod-to-x";
116
88
 
117
- const tsVisitor: string = new Zod2Ts({outType: "class"}).transpile(visitorNodes);
118
- console.log(tsVisitor)
89
+ const tsVisitorAsClass: string = new Zod2Ts({outType: "class"}).transpile(visitorNodes);
90
+ console.log(tsVisitorAsClass)
119
91
  // output:
120
92
  // export class Visitor {
121
93
  // id: string;
@@ -135,11 +107,11 @@ console.log(tsVisitor)
135
107
  ```
136
108
 
137
109
 
138
- A complete and more complex schema definition with its outputs can be found in the `test` folder:
139
- - [Zod Schemas](test/data)
110
+ Example of supported schemas with its outputs can be found in the `test` folder:
111
+ - [Zod Schemas](test/common)
140
112
  - [Typescript outputs](test/test_zod2ts)
141
113
  - [Protobuf V3 outputs](test/test_zod2proto3/)
142
- - [C++ 11 outputs](test/test_zod2cpp/)
114
+ - [C++ outputs](test/test_zod2cpp/)
143
115
 
144
116
 
145
117
 
@@ -150,29 +122,29 @@ Common options:
150
122
  - **includeComments**: Determines whether to include comments in the transpiled code. Defaults to `true`.
151
123
  - **skipDiscriminatorNodes**: prevents the inclusion of `ZodEnum` or `ZodNativeEnum` schemas that are used solely as discriminator keys in a `ZodDiscriminatedUnion`. Defaults to `false`.
152
124
 
153
- ### Typescript
154
- #### Options:
125
+ ### 1) Typescript
126
+ - Options:
155
127
  - **outType**: Output transpilation using Typescript interfaces or Classes. Defaults to `interface`.
156
128
 
157
- ### Protobuf V3
158
- #### Options:
129
+ ### 2) Protobuf V3
130
+ - Options:
159
131
  - **packageName**: Name of the protobuf file package.
160
132
  - **useCamelCase**: Protobuf follows the snake_case convention for field names, but camelCase can also be used. Defaults to `false`.
161
133
 
162
- #### Limitations:
134
+ - Limitations:
163
135
  - `oneof` fields support only unions of `ZodObject` schemas.
136
+ - `ZodTuple` is supported only for items of the same type.
164
137
 
165
138
 
166
- ### C++
167
- - `Nlohmann` dependency is used for data serialization/deserialization.
168
- - For *C++11*, `Boost` dependency is used. For *C++17* or newer, standard libraries are used.
169
- #### Options:
139
+ ### 3) C++
140
+ `Nlohmann` dependency is used for data serialization/deserialization. For *C++11*, `Boost` dependency is used. For *C++17* or newer, standard libraries are used.
141
+ - Options:
170
142
  - **includeNulls**: When serializing, include all values even if `null`. Defaults to `false`.
171
143
  - **namespace**: Name of the namespace containing the output code.
172
144
  - **outType**: Output transpilation using C++ Structs or Classes. Defaults to `struct`.
173
145
  - **skipSerialize**: Remove Nlohmann JSON serialization/deserialization. Defaults to `false`.
174
146
 
175
- #### Limitations:
147
+ - Limitations:
176
148
  - `ZodIntersection` is supported only for intersection of `ZodObject` schemas.
177
149
 
178
150
 
@@ -191,18 +163,19 @@ Common options:
191
163
  | `z.nativeEnum()` | Native `enum` | `enum` | `enum class T: int`
192
164
  | `z.array()` | `T[]` | `repeated` field | `std::vector<T>`
193
165
  | `z.set()` | `Set<T>` | `repeated` field | `std::set<T>`
194
- | `z.tuple()` | `[T1, T2, T3]` | `repeated` field <sup>(1)</sup> | `std::tuple<T1, T2, T3>`
166
+ | `z.tuple()` | `[T1, T2, T3]` | `repeated` field | `std::tuple<T1, T2, T3>`
195
167
  | `z.object()` | `interface` or `class` | `message` | `struct` or `class`
196
168
  | `z.record()` | `Record<string, T>` | `map<string, K>` | `std::unordered_map<T>`
197
169
  | `z.map()` | `Map<string, T>` | `map<string, K>` | `std::unordered_map<T>`
198
- | `z.union()` | `T1 \| T2` or `type` | `oneof` | `std::variant<T, K>` (`boost::variant<T, K>` for C++11)
199
- | `z.intersection()` <sup>(2)</sup>| `T1 & T2` or `type` | Not supported | `struct` or `class` with `inheritance`
170
+ | `z.union()` <sup>(2)</sup> | `T1 \| T2` or `type` | `oneof` | `std::variant<T, K>` (`boost::variant<T, K>` for C++11)
171
+ | `z.discriminatedUnion()`| `T1 \| T2` or `type` | `oneof` | `std::variant<T, K>` (`boost::variant<T, K>` for C++11)
172
+ | `z.intersection()` <sup>(1)</sup> | `T1 & T2` or `type` | Not supported | `struct` or `class` with `inheritance`
200
173
  | `z.any()` | `any` | `google.protobuf.Any` | `nlohmann::json`
201
174
  | `z.optional()` | `T \| undefined` | Not supported | `std::optional<T>` (`boost::optional<T>` for C++11)
202
175
  | `z.nullable()` | `T \| null` | Not supported | `std::optional<T>` (`boost::optional<T>` for C++11)
203
176
 
204
- <sup>(1)</sup> Only for tuple with items of the same type.
205
- <sup>(2)</sup> Consider to use Zod's merge instead of ZodIntersection when possible.
177
+ <sup>(1)</sup> Consider to use Zod's merge instead of ZodIntersection when possible.
178
+ <sup>(2)</sup> Consider to use ZodDiscriminatedUnion when possible. In languages like C++, deserialization is O(1) against the O(n) of the ZodUnion.
206
179
 
207
180
  ## Additional utils
208
181
  - `zod2JsonSchemaDefinitions`
@@ -28,7 +28,7 @@ class Zod2Ast {
28
28
  }
29
29
  }
30
30
  zodToAST(schema, opt) {
31
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
31
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
32
32
  const def = schema._def;
33
33
  if (schema instanceof zod_1.ZodString) {
34
34
  return {
@@ -88,10 +88,19 @@ class Zod2Ast {
88
88
  };
89
89
  }
90
90
  else if (schema instanceof zod_1.ZodLiteral) {
91
+ let parentEnumName = undefined;
92
+ let parentEnumKey = undefined;
93
+ if ((_c = def.zod2x) === null || _c === void 0 ? void 0 : _c.parentEnum) {
94
+ parentEnumName = (_e = (_d = def.zod2x) === null || _d === void 0 ? void 0 : _d.parentEnum._def.zod2x) === null || _e === void 0 ? void 0 : _e.typeName;
95
+ parentEnumKey = (_g = this._getEnumValues((_f = def.zod2x) === null || _f === void 0 ? void 0 : _f.parentEnum).find((i) => i[1] === def.value)) === null || _g === void 0 ? void 0 : _g[0];
96
+ this.zodToAST((_h = def.zod2x) === null || _h === void 0 ? void 0 : _h.parentEnum, { isInjectedEnum: true });
97
+ }
91
98
  return {
92
99
  type: zod_1.ZodFirstPartyTypeKind.ZodLiteral,
93
100
  value: def.value,
94
101
  description: schema.description,
102
+ parentEnumName,
103
+ parentEnumKey,
95
104
  };
96
105
  }
97
106
  else if (schema instanceof zod_1.ZodRecord) {
@@ -124,14 +133,14 @@ class Zod2Ast {
124
133
  };
125
134
  }
126
135
  else if (schema instanceof zod_1.ZodNativeEnum || schema instanceof zod_1.ZodEnum) {
127
- let name = (_c = def.zod2x) === null || _c === void 0 ? void 0 : _c.typeName;
136
+ let name = (_j = def.zod2x) === null || _j === void 0 ? void 0 : _j.typeName;
128
137
  const item = {
129
138
  type: def.typeName,
130
- name: (_d = def.zod2x) === null || _d === void 0 ? void 0 : _d.typeName,
139
+ name: (_k = def.zod2x) === null || _k === void 0 ? void 0 : _k.typeName,
131
140
  values: this._getEnumValues(schema),
132
141
  description: def.description,
133
142
  };
134
- if (opt === null || opt === void 0 ? void 0 : opt.isUnionDiscriminator) {
143
+ if (opt === null || opt === void 0 ? void 0 : opt.isInjectedEnum) {
135
144
  if (!this.nodes.has(name) && !this.discriminatorNodes.has(name)) {
136
145
  this.discriminatorNodes.set(name, item);
137
146
  }
@@ -147,42 +156,43 @@ class Zod2Ast {
147
156
  return this._createDefinition(name, def.typeName);
148
157
  }
149
158
  else if (schema instanceof zod_1.ZodObject) {
150
- let name = (_e = def.zod2x) === null || _e === void 0 ? void 0 : _e.typeName;
159
+ let name = (_l = def.zod2x) === null || _l === void 0 ? void 0 : _l.typeName;
151
160
  let discriminantValue = undefined;
152
161
  if (!this.nodes.has(name)) {
153
162
  const properties = {};
154
163
  for (const key in def.shape()) {
155
164
  properties[key] = this.zodToAST(def.shape()[key]);
156
- if ((opt === null || opt === void 0 ? void 0 : opt.discriminantKey) && key === (opt === null || opt === void 0 ? void 0 : opt.discriminantKey)) {
157
- if (properties[key].type === zod_1.ZodFirstPartyTypeKind.ZodLiteral) {
158
- discriminantValue = String(properties[key].value);
159
- }
160
- else {
161
- console.warn(`Consider to set '${key}' key of '${name}' as ZodLiteral`);
162
- }
163
- }
164
165
  }
165
166
  this.nodes.set(name, {
166
167
  type: zod_1.ZodFirstPartyTypeKind.ZodObject,
167
- name: (_f = def.zod2x) === null || _f === void 0 ? void 0 : _f.typeName,
168
+ name: (_m = def.zod2x) === null || _m === void 0 ? void 0 : _m.typeName,
168
169
  properties,
169
170
  description: schema.description,
170
171
  });
171
172
  }
173
+ if (opt === null || opt === void 0 ? void 0 : opt.discriminantKey) {
174
+ const item = this.nodes.get(name);
175
+ if (Object.keys(item.properties).includes(opt.discriminantKey)) {
176
+ const key = opt.discriminantKey;
177
+ if (item.properties[key].type === zod_1.ZodFirstPartyTypeKind.ZodLiteral) {
178
+ discriminantValue = String(item.properties[key].value);
179
+ }
180
+ else {
181
+ console.warn(`Consider to set '${key}' key of '${name}' as ZodLiteral`);
182
+ }
183
+ }
184
+ }
172
185
  return this._createDefinition(name, def.typeName, discriminantValue);
173
186
  }
174
187
  else if (schema instanceof zod_1.ZodUnion || schema instanceof zod_1.ZodDiscriminatedUnion) {
175
- let name = (_g = def.zod2x) === null || _g === void 0 ? void 0 : _g.typeName;
188
+ let name = (_o = def.zod2x) === null || _o === void 0 ? void 0 : _o.typeName;
176
189
  const item = {
177
190
  type: def.typeName,
178
- name: (_h = def.zod2x) === null || _h === void 0 ? void 0 : _h.typeName,
191
+ name: (_p = def.zod2x) === null || _p === void 0 ? void 0 : _p.typeName,
179
192
  options: def.options.map((i) => this.zodToAST(i, { discriminantKey: def.discriminator })),
180
193
  description: schema.description,
181
194
  discriminantKey: def.discriminator,
182
195
  };
183
- if ((_j = def.zod2x) === null || _j === void 0 ? void 0 : _j.discriminatorEnum) {
184
- this.zodToAST((_k = def.zod2x) === null || _k === void 0 ? void 0 : _k.discriminatorEnum, { isUnionDiscriminator: true });
185
- }
186
196
  if (name && !this.nodes.has(name)) {
187
197
  this.nodes.set(name, item);
188
198
  return this._createDefinition(name, def.typeName);
@@ -190,10 +200,10 @@ class Zod2Ast {
190
200
  return item;
191
201
  }
192
202
  else if (schema instanceof zod_1.ZodIntersection) {
193
- let name = (_l = def.zod2x) === null || _l === void 0 ? void 0 : _l.typeName;
203
+ let name = (_q = def.zod2x) === null || _q === void 0 ? void 0 : _q.typeName;
194
204
  const item = {
195
205
  type: zod_1.ZodFirstPartyTypeKind.ZodIntersection,
196
- name: (_m = def.zod2x) === null || _m === void 0 ? void 0 : _m.typeName,
206
+ name: (_r = def.zod2x) === null || _r === void 0 ? void 0 : _r.typeName,
197
207
  left: this.zodToAST(def.left),
198
208
  right: this.zodToAST(def.right),
199
209
  description: schema.description,
@@ -2,6 +2,8 @@ import { ZodFirstPartyTypeKind } from "zod";
2
2
  export type ASTLiteral = {
3
3
  type: ZodFirstPartyTypeKind.ZodLiteral;
4
4
  value: any;
5
+ parentEnumName?: string;
6
+ parentEnumKey?: string;
5
7
  };
6
8
  export type ASTNumber = {
7
9
  type: ZodFirstPartyTypeKind.ZodNumber;
@@ -25,7 +25,7 @@ export declare abstract class Zod2X<T extends IZodToXOpt> {
25
25
  min?: number;
26
26
  max?: number;
27
27
  }): string;
28
- protected abstract getLiteralStringType(value: string | number): string | number;
28
+ protected abstract getLiteralStringType(value: string | number, parentEnumNameKey?: [string, string]): string | number;
29
29
  protected abstract getAnyType(): string;
30
30
  protected abstract getDateType(): string;
31
31
  protected abstract getTupleType(itemsType: string[]): string;
@@ -59,7 +59,10 @@ class Zod2X {
59
59
  varType = this.getDateType();
60
60
  }
61
61
  else if (token.type === zod_1.ZodFirstPartyTypeKind.ZodLiteral) {
62
- varType = this.getLiteralStringType(token.value);
62
+ const parentEnum = token.parentEnumName && token.parentEnumKey
63
+ ? [token.parentEnumName, token.parentEnumKey]
64
+ : undefined;
65
+ varType = this.getLiteralStringType(token.value, parentEnum);
63
66
  }
64
67
  else if (token.type === zod_1.ZodFirstPartyTypeKind.ZodSet) {
65
68
  varType = this.getSetType(this.getAttributeType(token.value));
@@ -1,7 +1,7 @@
1
1
  import { EnumLike, UnknownKeysParam, z, ZodEnum, ZodNativeEnum, ZodRawShape, ZodTypeAny, ZodUnionOptions } from "zod";
2
2
  export interface Zod2xMetadata {
3
3
  typeName: string;
4
- discriminatorEnum?: ZodEnum<any> | ZodNativeEnum<any>;
4
+ parentEnum?: ZodEnum<any> | ZodNativeEnum<any>;
5
5
  }
6
6
  declare module "zod" {
7
7
  interface ZodTypeDef {
@@ -9,27 +9,31 @@ declare module "zod" {
9
9
  }
10
10
  interface ZodObject<T extends ZodRawShape, UnknownKeys extends UnknownKeysParam = UnknownKeysParam, Catchall extends ZodTypeAny = ZodTypeAny> {
11
11
  zod2x(this: ZodObject<T, UnknownKeys, Catchall>, typeName: string): this;
12
- zod2x(this: ZodObject<T, UnknownKeys, Catchall>, opt: Zod2xMetadata): this;
12
+ zod2x(this: ZodObject<T, UnknownKeys, Catchall>, opt: Pick<Zod2xMetadata, "typeName">): this;
13
13
  }
14
14
  interface ZodEnum<T extends [string, ...string[]]> {
15
15
  zod2x(this: ZodEnum<T>, typeName: string): this;
16
- zod2x(this: ZodEnum<T>, opt: Zod2xMetadata): this;
16
+ zod2x(this: ZodEnum<T>, opt: Pick<Zod2xMetadata, "typeName">): this;
17
17
  }
18
18
  interface ZodNativeEnum<T extends EnumLike = EnumLike> {
19
19
  zod2x(this: ZodNativeEnum<T>, typeName: string): this;
20
- zod2x(this: ZodNativeEnum<T>, opt: Zod2xMetadata): this;
20
+ zod2x(this: ZodNativeEnum<T>, opt: Pick<Zod2xMetadata, "typeName">): this;
21
21
  }
22
22
  interface ZodDiscriminatedUnion<Discriminator extends string, Options extends z.ZodDiscriminatedUnionOption<Discriminator>[]> {
23
23
  zod2x(this: ZodDiscriminatedUnion<Discriminator, Options>, typeName: string): this;
24
- zod2x(this: ZodDiscriminatedUnion<Discriminator, Options>, opt: Zod2xMetadata): this;
24
+ zod2x(this: ZodDiscriminatedUnion<Discriminator, Options>, opt: Pick<Zod2xMetadata, "typeName">): this;
25
25
  }
26
26
  interface ZodUnion<T extends ZodUnionOptions> {
27
27
  zod2x(this: ZodUnion<ZodUnionOptions>, typeName: string): this;
28
- zod2x(this: ZodUnion<ZodUnionOptions>, opt: Zod2xMetadata): this;
28
+ zod2x(this: ZodUnion<ZodUnionOptions>, opt: Pick<Zod2xMetadata, "typeName">): this;
29
29
  }
30
30
  interface ZodIntersection<T extends ZodTypeAny, U extends ZodTypeAny> {
31
31
  zod2x(this: ZodIntersection<T, U>, typeName: string): this;
32
- zod2x(this: ZodIntersection<T, U>, opt: Zod2xMetadata): this;
32
+ zod2x(this: ZodIntersection<T, U>, opt: Pick<Zod2xMetadata, "typeName">): this;
33
+ }
34
+ interface ZodLiteral<T extends ZodTypeAny> {
35
+ zod2x(this: ZodLiteral<T>, parentEnum: ZodNativeEnum | ZodEnum<any>): this;
36
+ zod2x(this: ZodLiteral<T>, opt: Pick<Zod2xMetadata, "parentEnum">): this;
33
37
  }
34
38
  }
35
39
  export declare function extendZod(zod: typeof z): void;
@@ -25,4 +25,11 @@ function extendZod(zod) {
25
25
  if (typeof zod.ZodIntersection.prototype.zod2x === "undefined") {
26
26
  zod.ZodIntersection.prototype.zod2x = getZod2XConstructor();
27
27
  }
28
+ if (typeof zod.ZodLiteral.prototype.zod2x === "undefined") {
29
+ zod.ZodLiteral.prototype.zod2x = function (opt) {
30
+ return new this.constructor(Object.assign(Object.assign({}, this._def), { zod2x: opt instanceof zod.ZodEnum || opt instanceof zod.ZodNativeEnum
31
+ ? { parentEnum: opt }
32
+ : opt }));
33
+ };
34
+ }
28
35
  }
@@ -1 +1 @@
1
- export declare function getNlohmannOptionalHelper(indent: number, useBoost?: boolean): string[];
1
+ export declare function getNlohmannOptionalHelper(indent: number, includeNulls: boolean, useBoost: boolean, namespace: string): string[];
@@ -1,11 +1,33 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getNlohmannOptionalHelper = getNlohmannOptionalHelper;
4
- function getNlohmannOptionalHelper(indent, useBoost) {
4
+ function getNlohmannOptionalHelper(indent, includeNulls, useBoost, namespace) {
5
5
  const optType = useBoost ? "boost::optional" : "std::optional";
6
+ const setOpt = includeNulls
7
+ ? [
8
+ `template <typename T>`,
9
+ `void set_opt(json& j, const std::string& key, const ${optType}<T>& opt) {`,
10
+ `${" ".repeat(indent)}if (opt) {`,
11
+ `${" ".repeat(indent * 2)}j[key] = *opt;`,
12
+ `${" ".repeat(indent)}}`,
13
+ `${" ".repeat(indent)}else {`,
14
+ `${" ".repeat(indent * 2)}j[key] = nullptr;`,
15
+ `${" ".repeat(indent)}}`,
16
+ `}`,
17
+ `#endif\n`,
18
+ ]
19
+ : [
20
+ `template <typename T>`,
21
+ `void set_opt(json& j, const std::string& key, const ${optType}<T>& opt) {`,
22
+ `${" ".repeat(indent)}if (opt) {`,
23
+ `${" ".repeat(indent * 2)}j[key] = *opt;`,
24
+ `${" ".repeat(indent)}}`,
25
+ `}`,
26
+ `#endif\n`,
27
+ ];
6
28
  return [
7
- "#ifndef NLOHMANN_OPTIONAL_HELPER_zodtocpp",
8
- "#define NLOHMANN_OPTIONAL_HELPER_zodtocpp",
29
+ `#ifndef NLOHMANN_OPTIONAL_HELPER_${namespace}`,
30
+ `#define NLOHMANN_OPTIONAL_HELPER_${namespace}`,
9
31
  "template <typename T>",
10
32
  `${optType}<T> get_opt(const json& j, const std::string& key) {`,
11
33
  `${" ".repeat(indent)}auto it = j.find(key);`,
@@ -14,12 +36,6 @@ function getNlohmannOptionalHelper(indent, useBoost) {
14
36
  `${" ".repeat(indent)}}`,
15
37
  `${" ".repeat(indent)}return ${optType}<T>();`,
16
38
  `}\n`,
17
- `template <typename T>`,
18
- `void set_opt(json& j, const std::string& key, const ${optType}<T>& opt) {`,
19
- `${" ".repeat(indent)}if (opt) {`,
20
- `${" ".repeat(indent * 2)}j[key] = *opt;`,
21
- `${" ".repeat(indent)}}`,
22
- `}`,
23
- `#endif\n`,
39
+ ...setOpt,
24
40
  ];
25
41
  }
@@ -32,7 +32,7 @@ export declare class Zod2Cpp extends Zod2X<IZod2CppOpt> {
32
32
  max?: number;
33
33
  }) => string;
34
34
  protected getArrayType(arrayType: string, arrayDeep: number): string;
35
- protected getLiteralStringType(value: string | number): string;
35
+ protected getLiteralStringType(value: string | number, parentEnumNameKey?: [string, string]): string;
36
36
  protected getMapType(keyType: string, valueType: string): string;
37
37
  protected getRecordType(keyType: string, valueType: string): string;
38
38
  protected _getOptional(type: string): string;
@@ -83,8 +83,8 @@ class Zod2Cpp extends core_1.Zod2X {
83
83
  this.imports.add(this.lib.nlohmann);
84
84
  this.output.push("");
85
85
  this.output.push(`namespace ${this.opt.namespace} {`);
86
- if (this.imports.has(this.lib.optional) && !this.opt.includeNulls) {
87
- this.serializers.unshift(...(0, nlohmann_1.getNlohmannOptionalHelper)(this.opt.indent, this.useBoost));
86
+ if (this.imports.has(this.lib.optional)) {
87
+ this.serializers.unshift(...(0, nlohmann_1.getNlohmannOptionalHelper)(this.opt.indent, this.opt.includeNulls === true, this.useBoost, this.opt.namespace));
88
88
  }
89
89
  this.serializers = this.serializers.map((i) => `${this.indent[1]}${i}`);
90
90
  this.output.push(...this.serializers);
@@ -102,13 +102,14 @@ class Zod2Cpp extends core_1.Zod2X {
102
102
  }
103
103
  return output;
104
104
  }
105
- getLiteralStringType(value) {
106
- return isNaN(Number(value))
105
+ getLiteralStringType(value, parentEnumNameKey) {
106
+ var _a;
107
+ return ((_a = parentEnumNameKey === null || parentEnumNameKey === void 0 ? void 0 : parentEnumNameKey[0]) !== null && _a !== void 0 ? _a : (isNaN(Number(value))
107
108
  ? this.getStringType()
108
109
  : this.getNumberType(Number.isInteger(value), {
109
110
  min: value,
110
111
  max: value,
111
- });
112
+ })));
112
113
  }
113
114
  getMapType(keyType, valueType) {
114
115
  this.imports.add(this.lib.map);
@@ -261,7 +262,7 @@ class Zod2Cpp extends core_1.Zod2X {
261
262
  _createStructSerializer(parent, childs) {
262
263
  this._push0(this.serializers, `inline void to_json(json& j, const ${parent}& x) {`);
263
264
  childs.forEach((i) => {
264
- if (i.required || this.opt.includeNulls === true) {
265
+ if (i.required) {
265
266
  this._push1(this.serializers, `j["${i.origName}"] = x.${i.snakeName};`);
266
267
  }
267
268
  else {
@@ -285,7 +286,7 @@ class Zod2Cpp extends core_1.Zod2X {
285
286
  _createClassSerializer(parent, childs) {
286
287
  this._push0(this.serializers, `inline void to_json(json& j, const ${parent}& x) {`);
287
288
  childs.forEach((i) => {
288
- if (i.required || this.opt.includeNulls === true) {
289
+ if (i.required) {
289
290
  this._push1(this.serializers, `j["${i.origName}"] = x.get_${i.snakeName}();`);
290
291
  }
291
292
  else {
@@ -17,7 +17,7 @@ export declare class Zod2Ts extends Zod2X<IZod2TsOpt> {
17
17
  protected getIntersectionType: (itemsType: string[]) => string;
18
18
  protected getNumberType: () => string;
19
19
  protected getArrayType(arrayType: string, arrayDeep: number): string;
20
- protected getLiteralStringType(value: string | number): string | number;
20
+ protected getLiteralStringType(value: string | number, parentEnumNameKey?: [string, string]): string | number;
21
21
  protected getMapType(keyType: string, valueType: string): string;
22
22
  protected getRecordType(keyType: string, valueType: string): string;
23
23
  protected transpileEnum(data: (ASTEnum | ASTNativeEnum) & ASTCommon): void;
@@ -39,8 +39,12 @@ class Zod2Ts extends core_1.Zod2X {
39
39
  }
40
40
  return output;
41
41
  }
42
- getLiteralStringType(value) {
43
- return isNaN(Number(value)) ? `"${value}"` : value;
42
+ getLiteralStringType(value, parentEnumNameKey) {
43
+ return parentEnumNameKey
44
+ ? `${parentEnumNameKey[0]}.${parentEnumNameKey[1]}`
45
+ : isNaN(Number(value))
46
+ ? `"${value}"`
47
+ : value;
44
48
  }
45
49
  getMapType(keyType, valueType) {
46
50
  return `Map<${keyType}, ${valueType}>`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zod-to-x",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Multi language types generation from Zod schemas.",
5
5
  "main": "dist/index.js",
6
6
  "files": [
@@ -10,6 +10,7 @@
10
10
  "build": "tsc && tsc-alias",
11
11
  "format:check": "prettier --check .",
12
12
  "test": "jest",
13
+ "test:cpp": "bash ./test/test_zod2cpp/test_cpp.sh",
13
14
  "ts-run": "ts-node -r tsconfig-paths/register",
14
15
  "prepare": "husky"
15
16
  },