zod-to-x 1.2.1 → 1.3.0
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 +133 -10
- package/dist/core/ast_node.d.ts +10 -2
- package/dist/core/ast_node.js +139 -29
- package/dist/core/ast_types.d.ts +9 -6
- package/dist/core/errors.d.ts +9 -0
- package/dist/core/errors.js +24 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +1 -0
- package/dist/core/transpiler.d.ts +2 -8
- package/dist/core/transpiler.js +4 -25
- package/dist/lib/zod_ext.d.ts +2 -2
- package/dist/transpilers/cpp/runner.js +2 -4
- package/dist/transpilers/protobuf_v3/options.d.ts +6 -0
- package/dist/transpilers/protobuf_v3/options.js +9 -0
- package/dist/transpilers/protobuf_v3/runner.d.ts +2 -6
- package/dist/transpilers/protobuf_v3/runner.js +10 -17
- package/dist/transpilers/typescript/options.d.ts +5 -0
- package/dist/transpilers/typescript/options.js +9 -0
- package/dist/transpilers/typescript/runner.d.ts +2 -5
- package/dist/transpilers/typescript/runner.js +25 -17
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.js +16 -0
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -7,9 +7,11 @@
|
|
|
7
7
|
- [Why use `@zod-to-x`](#why-use-zod-to-x)
|
|
8
8
|
- [Installation](#installation)
|
|
9
9
|
- [Quick start](#quick-start)
|
|
10
|
+
- [Intersections and Unions](#intersections-and-unions)
|
|
10
11
|
- [Supported output languages](#supported-output-languages)
|
|
11
12
|
- [Mapping of supported Zod Types](#mapping-of-supported-zod-types)
|
|
12
13
|
- [Additional utils](#additional-utils)
|
|
14
|
+
- [Changelog](#changelog)
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
|
|
@@ -17,7 +19,7 @@
|
|
|
17
19
|
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. Here’s why it stands out:
|
|
18
20
|
|
|
19
21
|
1. **Centralized Data Definition**
|
|
20
|
-
Define your data structures in one place using the powerful [`@zod`](
|
|
22
|
+
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
23
|
|
|
22
24
|
2. **Multi-Language Compatibility**
|
|
23
25
|
Generate data models for TypeScript, Protobuf V3 and C++ (with languages like Golang on the roadmap). No more manually rewriting models for different platforms.
|
|
@@ -26,14 +28,14 @@ Generate data models for TypeScript, Protobuf V3 and C++ (with languages like Go
|
|
|
26
28
|
Automate the transpilation of data models to save time, reduce errors, and let your team focus on business logic instead of boilerplate code.
|
|
27
29
|
|
|
28
30
|
|
|
29
|
-
|
|
30
31
|
## Installation
|
|
31
|
-
### 1) Install [`@zod-to-x`](https://github.com/rroumenov/zod-to-x) and [`@zod`](
|
|
32
|
+
### 1) Install [`@zod-to-x`](https://github.com/rroumenov/zod-to-x) and [`@zod(*)`](https://github.com/colinhacks/zod) dependency.
|
|
32
33
|
```bash
|
|
33
|
-
npm install zod-to-x
|
|
34
|
+
npm install zod-to-x zod
|
|
34
35
|
```
|
|
36
|
+
(*) [`zod@3.22.0`](https://www.npmjs.com/package/zod/v/3.22.0) version or greather is required.
|
|
35
37
|
|
|
36
|
-
### 2) Extend Zod using the `extendZod` method after the first [`@zod`](
|
|
38
|
+
### 2) Extend Zod using the `extendZod` method after the first [`@zod`](https://github.com/colinhacks/zod) import:
|
|
37
39
|
```ts
|
|
38
40
|
import { z } from "zod";
|
|
39
41
|
import { extendZod } from "zod-to-x";
|
|
@@ -115,6 +117,124 @@ Example of supported schemas with its outputs can be found in the `test` folder:
|
|
|
115
117
|
|
|
116
118
|
|
|
117
119
|
|
|
120
|
+
## Intersections and Unions
|
|
121
|
+
Starting from `v1.3.0`, a best practices helper is enabled by default when handling data intersections and unions:
|
|
122
|
+
- Intersections and Unions can only be performed between ZodObject schemas.
|
|
123
|
+
- Discriminant unions shall be used instead of Unions.
|
|
124
|
+
|
|
125
|
+
These rules help ensure that each data model follows the single responsibility principle. Otherwise, an error will be thrown when building an `ASTNode`.
|
|
126
|
+
|
|
127
|
+
**NOTE**: You can disable these rules at your own risk by setting the `strict` flag to `false` when building the `ASTNode` data model. However, any unexpected behavior or issues resulting from this will not be supported.
|
|
128
|
+
|
|
129
|
+
### Expected outputs
|
|
130
|
+
- **For Intersections**: whenever possible, an intersection is transpiled into a struct/class that inherits from the intersected data models. Otherwise, a new struct/class is created, where attributes are the result of merging the intersected data models. Any shared key is overridden by the last matching type.
|
|
131
|
+
```ts
|
|
132
|
+
const DataA = z.object({ keyA: z.string(), keyC: z.string() }).zod2x("DataA");
|
|
133
|
+
const DataB = z.object({ keyB: z.string(), keyC: z.number() }).zod2x("DataB");
|
|
134
|
+
const Intersection = z.intersection(DataA, DataB).zod2x("Intersection");
|
|
135
|
+
|
|
136
|
+
// C++ case (with inheritance)
|
|
137
|
+
// struct Intersection : public DataA, public DataB {
|
|
138
|
+
// // Intersection fields are inherited from base structs.
|
|
139
|
+
// };
|
|
140
|
+
|
|
141
|
+
// Typescript case (with attribute merging)
|
|
142
|
+
// class Intersection {
|
|
143
|
+
// keyA: string;
|
|
144
|
+
// keyB: string;
|
|
145
|
+
// keyC: number; // Shared key overriden using the last type.
|
|
146
|
+
// };
|
|
147
|
+
```
|
|
148
|
+
- **For Unions**: whenever possible, a union is transpiled into a variant type composed of the united data models. Otherwise, a new struct/class is created, where attributes are the result of merging the intersected data models. Any common key is preserved as is (if only its requirement differs, it is changed to optional). Other keys are also set as optional.
|
|
149
|
+
```ts
|
|
150
|
+
const DataA = z.object({ keyA: z.string(), keyD: z.string() }).zod2x("DataA");
|
|
151
|
+
const DataB = z.object({ keyB: z.string(), keyD: z.string() }).zod2x("DataB");
|
|
152
|
+
const Intersection = z.intersection(DataA, DataB).zod2x("Intersection");
|
|
153
|
+
|
|
154
|
+
// C++ case (with variant type)
|
|
155
|
+
// using Intersection = std::variant<DataA, DataB>;
|
|
156
|
+
|
|
157
|
+
// Typescript case (with attributes merge)
|
|
158
|
+
// class Intersection {
|
|
159
|
+
// keyA?: string; // Different keys are set as optional
|
|
160
|
+
// keyB?: string;
|
|
161
|
+
// keyD: number; // Shared key preserved as is.
|
|
162
|
+
// };
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
### Tips for discriminated unions
|
|
168
|
+
To enhance data modeling and the serialization/deserialization of a discriminated union type, two key steps should be considered:
|
|
169
|
+
- Using `ZodEnum` or `ZodNativeEnum` the define the discriminator key options.
|
|
170
|
+
- Using `ZodLiteral` to define the specific value of the discriminator key.
|
|
171
|
+
|
|
172
|
+
Example of discriminant definition:
|
|
173
|
+
```ts
|
|
174
|
+
// Define message types
|
|
175
|
+
export const MsgType = z.enum(["TypeA", "TypeB"]).zod2x("MsgType");
|
|
176
|
+
|
|
177
|
+
// Define different message structures based on the 'msgType' value.
|
|
178
|
+
const MessageA = z
|
|
179
|
+
.object({
|
|
180
|
+
key: z.string(),
|
|
181
|
+
|
|
182
|
+
// Assign the type using the corresponding MsgType value and link it with 'zod2x'.
|
|
183
|
+
msgType: z.literal(MsgType.Values.TypeA).zod2x(MsgType),
|
|
184
|
+
})
|
|
185
|
+
.zod2x("MessageA");
|
|
186
|
+
|
|
187
|
+
const MessageB = z
|
|
188
|
+
.object({
|
|
189
|
+
otherKey: z.string(),
|
|
190
|
+
|
|
191
|
+
// Same process as MessageA.
|
|
192
|
+
msgType: z.literal(MsgType.Values.TypeB).zod2x(MsgType),
|
|
193
|
+
})
|
|
194
|
+
.zod2x("MessageB");
|
|
195
|
+
|
|
196
|
+
// Define the main Message type using ZodDiscriminatedUnion.
|
|
197
|
+
export const Message = z
|
|
198
|
+
.discriminatedUnion("msgType", [MessageA, MessageB])
|
|
199
|
+
.zod2x("Message");
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Example of C++ output:
|
|
203
|
+
```cpp
|
|
204
|
+
// Discriminated union with direct serialization/deserialization
|
|
205
|
+
inline void from_json(const json& j, Message& x) {
|
|
206
|
+
const auto& k = j.at("msgType").get<std::string>();
|
|
207
|
+
if (k == "TypeA") {
|
|
208
|
+
x = j.get<MessageA>();
|
|
209
|
+
}
|
|
210
|
+
else if (k == "TypeB") {
|
|
211
|
+
x = j.get<MessageB>();
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
throw std::runtime_error("Failed to deserialize Message: unknown format");
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
// Using a regular union or a discriminated union without the above approach:
|
|
221
|
+
// Fallback to try-catch for serialization/deserialization
|
|
222
|
+
inline void from_json(const json& j, Message& x) {
|
|
223
|
+
try {
|
|
224
|
+
x = j.get<MessageA>();
|
|
225
|
+
return;
|
|
226
|
+
} catch (const std::exception&) {
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
x = j.get<MessageB>();
|
|
230
|
+
return;
|
|
231
|
+
} catch (const std::exception&) {
|
|
232
|
+
throw std::runtime_error("Failed to deserialize Message: unknown format");
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
|
|
118
238
|
## Supported output languages
|
|
119
239
|
Common options:
|
|
120
240
|
- **header**: Text to add as a comment at the beginning of the output.
|
|
@@ -122,6 +242,10 @@ Common options:
|
|
|
122
242
|
- **includeComments**: Determines whether to include comments in the transpiled code. Defaults to `true`.
|
|
123
243
|
- **skipDiscriminatorNodes**: prevents the inclusion of `ZodEnum` or `ZodNativeEnum` schemas that are used solely as discriminator keys in a `ZodDiscriminatedUnion`. Defaults to `false`.
|
|
124
244
|
|
|
245
|
+
### 0) ASTNode
|
|
246
|
+
- Options:
|
|
247
|
+
- **strict**: When true, it will throw an error if a bad data modeling practice is detected. Default is `true`.
|
|
248
|
+
|
|
125
249
|
### 1) Typescript
|
|
126
250
|
- Options:
|
|
127
251
|
- **outType**: Output transpilation using Typescript interfaces or Classes. Defaults to `interface`.
|
|
@@ -132,7 +256,6 @@ Common options:
|
|
|
132
256
|
- **useCamelCase**: Protobuf follows the snake_case convention for field names, but camelCase can also be used. Defaults to `false`.
|
|
133
257
|
|
|
134
258
|
- Limitations:
|
|
135
|
-
- `oneof` fields support only unions of `ZodObject` schemas.
|
|
136
259
|
- `ZodTuple` is supported only for items of the same type.
|
|
137
260
|
|
|
138
261
|
|
|
@@ -144,9 +267,6 @@ Common options:
|
|
|
144
267
|
- **outType**: Output transpilation using C++ Structs or Classes. Defaults to `struct`.
|
|
145
268
|
- **skipSerialize**: Remove Nlohmann JSON serialization/deserialization. Defaults to `false`.
|
|
146
269
|
|
|
147
|
-
- Limitations:
|
|
148
|
-
- `ZodIntersection` is supported only for intersection of `ZodObject` schemas.
|
|
149
|
-
|
|
150
270
|
|
|
151
271
|
|
|
152
272
|
## Mapping of supported Zod Types
|
|
@@ -315,4 +435,7 @@ console.log(userJsonSchema);
|
|
|
315
435
|
// },
|
|
316
436
|
// "$schema": "http://json-schema.org/draft-07/schema#"
|
|
317
437
|
// }
|
|
318
|
-
```
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
## Changelog
|
|
441
|
+
View the changelog at [Releases](https://github.com/rroumenov/zod-to-x/releases).
|
package/dist/core/ast_node.d.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { ZodObject, ZodRawShape } from "zod";
|
|
2
2
|
import { ASTNodes } from "./ast_types";
|
|
3
|
+
interface IZod2AstOpt {
|
|
4
|
+
strict?: boolean;
|
|
5
|
+
}
|
|
3
6
|
export declare class Zod2Ast {
|
|
4
7
|
private nodes;
|
|
5
8
|
private discriminatorNodes;
|
|
6
9
|
private lazyPointers;
|
|
7
|
-
|
|
10
|
+
private warnings;
|
|
11
|
+
private opt;
|
|
12
|
+
constructor(opt?: IZod2AstOpt);
|
|
8
13
|
private _createDefinition;
|
|
9
14
|
private _getEnumValues;
|
|
10
|
-
private
|
|
15
|
+
private _intersectAstNodes;
|
|
16
|
+
private _unionAstNodes;
|
|
17
|
+
private _zodToAST;
|
|
11
18
|
build<T extends ZodRawShape>(schema: ZodObject<T>): ASTNodes;
|
|
12
19
|
}
|
|
20
|
+
export {};
|
package/dist/core/ast_node.js
CHANGED
|
@@ -2,11 +2,18 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Zod2Ast = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const logger_1 = require("../utils/logger");
|
|
6
|
+
const errors_1 = require("./errors");
|
|
5
7
|
class Zod2Ast {
|
|
6
|
-
constructor() {
|
|
8
|
+
constructor(opt = {}) {
|
|
9
|
+
var _a;
|
|
7
10
|
this.nodes = new Map();
|
|
8
11
|
this.discriminatorNodes = new Map();
|
|
9
12
|
this.lazyPointers = [];
|
|
13
|
+
this.warnings = [];
|
|
14
|
+
this.opt = {
|
|
15
|
+
strict: (_a = opt.strict) !== null && _a !== void 0 ? _a : true,
|
|
16
|
+
};
|
|
10
17
|
}
|
|
11
18
|
_createDefinition(ref, refType, discriminantValue) {
|
|
12
19
|
return { type: "definition", reference: ref, referenceType: refType, discriminantValue };
|
|
@@ -27,8 +34,53 @@ class Zod2Ast {
|
|
|
27
34
|
});
|
|
28
35
|
}
|
|
29
36
|
}
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
_intersectAstNodes(left, right) {
|
|
38
|
+
const leftData = this.nodes.get(left.reference);
|
|
39
|
+
const rightData = this.nodes.get(right.reference);
|
|
40
|
+
return {
|
|
41
|
+
properties: Object.assign(Object.assign({}, leftData.properties), rightData.properties),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
_unionAstNodes(options) {
|
|
45
|
+
const data = options.map((i) => this.nodes.get(i.reference));
|
|
46
|
+
return {
|
|
47
|
+
properties: data.reduce((acc, i, j) => {
|
|
48
|
+
var _a, _b;
|
|
49
|
+
for (const key in i.properties) {
|
|
50
|
+
if (acc[key]) {
|
|
51
|
+
acc[key] = structuredClone(acc[key]);
|
|
52
|
+
if (acc[key].type !== i.properties[key].type) {
|
|
53
|
+
this.warnings.push(`Merging properties with different types: ${acc[key].type} ` +
|
|
54
|
+
`(from ${(_a = data[j - 1]) === null || _a === void 0 ? void 0 : _a.name}) and ${i.properties[key].type} ` +
|
|
55
|
+
`(from ${i.name})`);
|
|
56
|
+
acc[key].type = i.properties[key].type;
|
|
57
|
+
}
|
|
58
|
+
if (acc[key].arrayDimension !== i.properties[key].arrayDimension) {
|
|
59
|
+
this.warnings.push(`Merging properties with different array dimensions: ` +
|
|
60
|
+
`${acc[key].arrayDimension} (from ${(_b = data[j - 1]) === null || _b === void 0 ? void 0 : _b.name}) and ` +
|
|
61
|
+
`${i.properties[key].arrayDimension} (from ${i.name})`);
|
|
62
|
+
acc[key].arrayDimension = Math.max(acc[key].arrayDimension || 0, i.properties[key].arrayDimension || 0);
|
|
63
|
+
}
|
|
64
|
+
if (acc[key].isNullable !== i.properties[key].isNullable) {
|
|
65
|
+
acc[key].isNullable = true;
|
|
66
|
+
}
|
|
67
|
+
if (acc[key].isOptional !== i.properties[key].isOptional) {
|
|
68
|
+
acc[key].isOptional = true;
|
|
69
|
+
}
|
|
70
|
+
if (i.properties[key].description) {
|
|
71
|
+
acc[key].description = i.properties[key].description;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
acc[key] = i.properties[key];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return acc;
|
|
79
|
+
}, {}),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
_zodToAST(schema, opt) {
|
|
83
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
32
84
|
const def = schema._def;
|
|
33
85
|
if (schema instanceof zod_1.ZodString) {
|
|
34
86
|
return {
|
|
@@ -67,15 +119,19 @@ class Zod2Ast {
|
|
|
67
119
|
};
|
|
68
120
|
}
|
|
69
121
|
else if (schema instanceof zod_1.ZodNullable) {
|
|
70
|
-
const subSchema = this.
|
|
122
|
+
const subSchema = this._zodToAST(def.innerType);
|
|
71
123
|
return Object.assign(Object.assign({ isNullable: true }, subSchema), { description: schema.description || subSchema.description });
|
|
72
124
|
}
|
|
73
125
|
else if (schema instanceof zod_1.ZodOptional) {
|
|
74
|
-
const subSchema = this.
|
|
126
|
+
const subSchema = this._zodToAST(def.innerType);
|
|
75
127
|
return Object.assign(Object.assign({ isOptional: true }, subSchema), { description: schema.description || subSchema.description });
|
|
76
128
|
}
|
|
129
|
+
else if (schema instanceof zod_1.ZodDefault) {
|
|
130
|
+
const subSchema = this._zodToAST(def.innerType);
|
|
131
|
+
return Object.assign(Object.assign({}, subSchema), { description: schema.description || subSchema.description });
|
|
132
|
+
}
|
|
77
133
|
else if (schema instanceof zod_1.ZodArray) {
|
|
78
|
-
const subSchema = this.
|
|
134
|
+
const subSchema = this._zodToAST(def.type);
|
|
79
135
|
return Object.assign(Object.assign({}, subSchema), { description: schema.description || subSchema.description, arrayDimension: Number.isInteger(subSchema.arrayDimension)
|
|
80
136
|
? ++subSchema.arrayDimension
|
|
81
137
|
: 1 });
|
|
@@ -83,7 +139,7 @@ class Zod2Ast {
|
|
|
83
139
|
else if (schema instanceof zod_1.ZodSet) {
|
|
84
140
|
return {
|
|
85
141
|
type: zod_1.ZodFirstPartyTypeKind.ZodSet,
|
|
86
|
-
value: this.
|
|
142
|
+
value: this._zodToAST(def.valueType),
|
|
87
143
|
description: schema.description,
|
|
88
144
|
};
|
|
89
145
|
}
|
|
@@ -93,7 +149,7 @@ class Zod2Ast {
|
|
|
93
149
|
if ((_c = def.zod2x) === null || _c === void 0 ? void 0 : _c.parentEnum) {
|
|
94
150
|
parentEnumName = (_e = (_d = def.zod2x) === null || _d === void 0 ? void 0 : _d.parentEnum._def.zod2x) === null || _e === void 0 ? void 0 : _e.typeName;
|
|
95
151
|
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.
|
|
152
|
+
this._zodToAST((_h = def.zod2x) === null || _h === void 0 ? void 0 : _h.parentEnum, { isInjectedEnum: true });
|
|
97
153
|
}
|
|
98
154
|
return {
|
|
99
155
|
type: zod_1.ZodFirstPartyTypeKind.ZodLiteral,
|
|
@@ -106,8 +162,8 @@ class Zod2Ast {
|
|
|
106
162
|
else if (schema instanceof zod_1.ZodRecord) {
|
|
107
163
|
return {
|
|
108
164
|
type: zod_1.ZodFirstPartyTypeKind.ZodRecord,
|
|
109
|
-
key: this.
|
|
110
|
-
value: this.
|
|
165
|
+
key: this._zodToAST(def.keyType),
|
|
166
|
+
value: this._zodToAST(def.valueType),
|
|
111
167
|
description: schema.description,
|
|
112
168
|
};
|
|
113
169
|
}
|
|
@@ -120,23 +176,27 @@ class Zod2Ast {
|
|
|
120
176
|
else if (schema instanceof zod_1.ZodTuple) {
|
|
121
177
|
return {
|
|
122
178
|
type: zod_1.ZodFirstPartyTypeKind.ZodTuple,
|
|
123
|
-
items: def.items.map(this.
|
|
179
|
+
items: def.items.map(this._zodToAST.bind(this)),
|
|
124
180
|
description: schema.description,
|
|
125
181
|
};
|
|
126
182
|
}
|
|
127
183
|
else if (schema instanceof zod_1.ZodMap) {
|
|
128
184
|
return {
|
|
129
185
|
type: zod_1.ZodFirstPartyTypeKind.ZodMap,
|
|
130
|
-
key: this.
|
|
131
|
-
value: this.
|
|
186
|
+
key: this._zodToAST(def.keyType),
|
|
187
|
+
value: this._zodToAST(def.valueType),
|
|
132
188
|
description: schema.description,
|
|
133
189
|
};
|
|
134
190
|
}
|
|
135
191
|
else if (schema instanceof zod_1.ZodNativeEnum || schema instanceof zod_1.ZodEnum) {
|
|
136
|
-
|
|
192
|
+
const name = (_j = def.zod2x) === null || _j === void 0 ? void 0 : _j.typeName;
|
|
193
|
+
if (!name) {
|
|
194
|
+
throw new errors_1.AstTypeNameDefinitionError("ZodEnum/ZodNativeEnum type must have a typeName. " +
|
|
195
|
+
"Use zod2x method to provide one.");
|
|
196
|
+
}
|
|
137
197
|
const item = {
|
|
138
198
|
type: def.typeName,
|
|
139
|
-
name
|
|
199
|
+
name,
|
|
140
200
|
values: this._getEnumValues(schema),
|
|
141
201
|
description: def.description,
|
|
142
202
|
};
|
|
@@ -156,16 +216,19 @@ class Zod2Ast {
|
|
|
156
216
|
return this._createDefinition(name, def.typeName);
|
|
157
217
|
}
|
|
158
218
|
else if (schema instanceof zod_1.ZodObject) {
|
|
159
|
-
|
|
219
|
+
const name = (_k = def.zod2x) === null || _k === void 0 ? void 0 : _k.typeName;
|
|
160
220
|
let discriminantValue = undefined;
|
|
221
|
+
if (!name) {
|
|
222
|
+
throw new errors_1.AstTypeNameDefinitionError("ZodObject type must have a typeName. Use zod2x method to provide one.");
|
|
223
|
+
}
|
|
161
224
|
if (!this.nodes.has(name)) {
|
|
162
225
|
const properties = {};
|
|
163
226
|
for (const key in def.shape()) {
|
|
164
|
-
properties[key] = this.
|
|
227
|
+
properties[key] = this._zodToAST(def.shape()[key]);
|
|
165
228
|
}
|
|
166
229
|
this.nodes.set(name, {
|
|
167
230
|
type: zod_1.ZodFirstPartyTypeKind.ZodObject,
|
|
168
|
-
name
|
|
231
|
+
name,
|
|
169
232
|
properties,
|
|
170
233
|
description: schema.description,
|
|
171
234
|
});
|
|
@@ -185,14 +248,34 @@ class Zod2Ast {
|
|
|
185
248
|
return this._createDefinition(name, def.typeName, discriminantValue);
|
|
186
249
|
}
|
|
187
250
|
else if (schema instanceof zod_1.ZodUnion || schema instanceof zod_1.ZodDiscriminatedUnion) {
|
|
188
|
-
|
|
251
|
+
const name = (_l = def.zod2x) === null || _l === void 0 ? void 0 : _l.typeName;
|
|
252
|
+
if (!name) {
|
|
253
|
+
throw new errors_1.AstTypeNameDefinitionError("ZodUnion/ZodDiscriminatedUnion type must have a typeName. " +
|
|
254
|
+
"Use zod2x method to provide one.");
|
|
255
|
+
}
|
|
189
256
|
const item = {
|
|
190
257
|
type: def.typeName,
|
|
191
|
-
name
|
|
192
|
-
options: def.options.map((i) => this.
|
|
258
|
+
name,
|
|
259
|
+
options: def.options.map((i) => this._zodToAST(i, { discriminantKey: def.discriminator })),
|
|
193
260
|
description: schema.description,
|
|
194
261
|
discriminantKey: def.discriminator,
|
|
195
262
|
};
|
|
263
|
+
if (!def.options.every((i) => i instanceof zod_1.ZodObject)) {
|
|
264
|
+
this.warnings.push("Union of non-object types is a bad data modeling practice, " +
|
|
265
|
+
"and could lead to unexpected results.");
|
|
266
|
+
}
|
|
267
|
+
else if (schema instanceof zod_1.ZodUnion) {
|
|
268
|
+
this.warnings.push("Using ZodUnion is a bad data modeling practice. " +
|
|
269
|
+
"Use ZodDiscriminatedUnion instead.");
|
|
270
|
+
item.newObject = {
|
|
271
|
+
name,
|
|
272
|
+
type: zod_1.ZodFirstPartyTypeKind.ZodObject,
|
|
273
|
+
properties: this._unionAstNodes(item.options).properties,
|
|
274
|
+
description: (schema.description ? `${schema.description} - ` : "") +
|
|
275
|
+
`Built from union of ` +
|
|
276
|
+
`${item.options.map((i) => i.reference).join(", ")}`,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
196
279
|
if (name && !this.nodes.has(name)) {
|
|
197
280
|
this.nodes.set(name, item);
|
|
198
281
|
return this._createDefinition(name, def.typeName);
|
|
@@ -200,28 +283,51 @@ class Zod2Ast {
|
|
|
200
283
|
return item;
|
|
201
284
|
}
|
|
202
285
|
else if (schema instanceof zod_1.ZodIntersection) {
|
|
203
|
-
|
|
286
|
+
const name = (_m = def.zod2x) === null || _m === void 0 ? void 0 : _m.typeName;
|
|
287
|
+
if (!name) {
|
|
288
|
+
throw new errors_1.AstTypeNameDefinitionError("ZodIntersection type must have a typeName. Use zod2x method to provide one.");
|
|
289
|
+
}
|
|
204
290
|
const item = {
|
|
205
291
|
type: zod_1.ZodFirstPartyTypeKind.ZodIntersection,
|
|
206
|
-
name
|
|
207
|
-
left: this.
|
|
208
|
-
right: this.
|
|
292
|
+
name,
|
|
293
|
+
left: this._zodToAST(def.left),
|
|
294
|
+
right: this._zodToAST(def.right),
|
|
209
295
|
description: schema.description,
|
|
210
296
|
};
|
|
297
|
+
if (def.left._def.typeName !== "ZodObject" || def.right._def.typeName !== "ZodObject") {
|
|
298
|
+
this.warnings.push("Intersection of non-object is a bad data modeling practice, " +
|
|
299
|
+
"and could lead to unexpected results.");
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
item.newObject = {
|
|
303
|
+
type: zod_1.ZodFirstPartyTypeKind.ZodObject,
|
|
304
|
+
name,
|
|
305
|
+
properties: this._intersectAstNodes(item.left, item.right).properties,
|
|
306
|
+
description: (schema.description ? `${schema.description} - ` : "") +
|
|
307
|
+
`Built from intersection of ` +
|
|
308
|
+
`${item.left.reference} and ` +
|
|
309
|
+
`${item.right.reference}`,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
211
312
|
if (name && !this.nodes.has(name)) {
|
|
212
313
|
this.nodes.set(name, item);
|
|
213
314
|
return this._createDefinition(name, def.typeName);
|
|
214
315
|
}
|
|
215
316
|
return item;
|
|
216
317
|
}
|
|
217
|
-
else
|
|
218
|
-
|
|
318
|
+
else {
|
|
319
|
+
logger_1.log.warn(`Unsupported Zod type: ${JSON.stringify(schema)}`);
|
|
320
|
+
return {
|
|
321
|
+
type: zod_1.ZodFirstPartyTypeKind.ZodAny,
|
|
322
|
+
description: `Unsupported Zod type: ${schema._def.typeName}`,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
219
325
|
}
|
|
220
326
|
build(schema) {
|
|
221
|
-
this.
|
|
327
|
+
this._zodToAST(schema);
|
|
222
328
|
while (this.lazyPointers.length > 0) {
|
|
223
329
|
const [pointer, schema] = this.lazyPointers.shift();
|
|
224
|
-
const lazyResolve = this.
|
|
330
|
+
const lazyResolve = this._zodToAST(schema);
|
|
225
331
|
Object.keys(pointer).forEach((key) => {
|
|
226
332
|
delete pointer[key];
|
|
227
333
|
});
|
|
@@ -229,9 +335,13 @@ class Zod2Ast {
|
|
|
229
335
|
pointer[key] = value;
|
|
230
336
|
});
|
|
231
337
|
}
|
|
338
|
+
if (this.opt.strict !== false && this.warnings.length > 0) {
|
|
339
|
+
throw new errors_1.AstNodeError(this.warnings.join("\n"));
|
|
340
|
+
}
|
|
232
341
|
return {
|
|
233
342
|
nodes: [...this.nodes.values()],
|
|
234
343
|
discriminatorNodes: [...this.discriminatorNodes.values()],
|
|
344
|
+
warnings: this.warnings,
|
|
235
345
|
};
|
|
236
346
|
}
|
|
237
347
|
}
|
package/dist/core/ast_types.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { ZodFirstPartyTypeKind } from "zod";
|
|
2
|
+
export type ASTCommon = {
|
|
3
|
+
arrayDimension?: number;
|
|
4
|
+
description?: string;
|
|
5
|
+
isNullable?: boolean;
|
|
6
|
+
isOptional?: boolean;
|
|
7
|
+
};
|
|
2
8
|
export type ASTLiteral = {
|
|
3
9
|
type: ZodFirstPartyTypeKind.ZodLiteral;
|
|
4
10
|
value: any;
|
|
@@ -50,6 +56,7 @@ export type ASTUnion = {
|
|
|
50
56
|
type: ZodFirstPartyTypeKind.ZodUnion;
|
|
51
57
|
name: string;
|
|
52
58
|
options: ASTNode[];
|
|
59
|
+
newObject?: ASTCommon & ASTObject;
|
|
53
60
|
};
|
|
54
61
|
export type ASTDiscriminatedUnion = {
|
|
55
62
|
type: ZodFirstPartyTypeKind.ZodDiscriminatedUnion;
|
|
@@ -62,12 +69,7 @@ export type ASTIntersection = {
|
|
|
62
69
|
name: string;
|
|
63
70
|
left: ASTNode;
|
|
64
71
|
right: ASTNode;
|
|
65
|
-
|
|
66
|
-
export type ASTCommon = {
|
|
67
|
-
arrayDimension?: number;
|
|
68
|
-
description?: string;
|
|
69
|
-
isNullable?: boolean;
|
|
70
|
-
isOptional?: boolean;
|
|
72
|
+
newObject?: ASTCommon & ASTObject;
|
|
71
73
|
};
|
|
72
74
|
export type ASTDefintion = ASTCommon & {
|
|
73
75
|
type: "definition";
|
|
@@ -91,4 +93,5 @@ export type TranspilerableTypes = ASTCommon & (ASTEnum | ASTNativeEnum | ASTObje
|
|
|
91
93
|
export type ASTNodes = {
|
|
92
94
|
nodes: TranspilerableTypes[];
|
|
93
95
|
discriminatorNodes: TranspilerableTypes[];
|
|
96
|
+
warnings: string[];
|
|
94
97
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare class AstTypeNameDefinitionError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export declare class AstNodeError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
export declare class NotTranspilerableTypeError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NotTranspilerableTypeError = exports.AstNodeError = exports.AstTypeNameDefinitionError = void 0;
|
|
4
|
+
class AstTypeNameDefinitionError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "TypeNameDefinitionError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.AstTypeNameDefinitionError = AstTypeNameDefinitionError;
|
|
11
|
+
class AstNodeError extends Error {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = "AstNodeError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.AstNodeError = AstNodeError;
|
|
18
|
+
class NotTranspilerableTypeError extends Error {
|
|
19
|
+
constructor(message) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = "NotTranspilerableTypeError";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.NotTranspilerableTypeError = NotTranspilerableTypeError;
|
package/dist/core/index.d.ts
CHANGED
package/dist/core/index.js
CHANGED
|
@@ -20,3 +20,4 @@ Object.defineProperty(exports, "Zod2Ast", { enumerable: true, get: function () {
|
|
|
20
20
|
__exportStar(require("./ast_types"), exports);
|
|
21
21
|
var transpiler_1 = require("./transpiler");
|
|
22
22
|
Object.defineProperty(exports, "Zod2X", { enumerable: true, get: function () { return transpiler_1.Zod2X; } });
|
|
23
|
+
__exportStar(require("./errors"), exports);
|
|
@@ -6,16 +6,12 @@ export interface IZodToXOpt extends Record<string, any> {
|
|
|
6
6
|
includeComments?: boolean;
|
|
7
7
|
skipDiscriminatorNodes?: boolean;
|
|
8
8
|
}
|
|
9
|
-
interface IInternalOpts {
|
|
10
|
-
enableCompositeTypes: boolean;
|
|
11
|
-
}
|
|
12
9
|
export declare abstract class Zod2X<T extends IZodToXOpt> {
|
|
13
10
|
protected output: string[];
|
|
14
11
|
protected indent: TIndentationLevels;
|
|
15
12
|
protected imports: Set<string>;
|
|
16
13
|
protected opt: Partial<T>;
|
|
17
|
-
|
|
18
|
-
protected constructor(inOpt: IInternalOpts, opt: Partial<T>);
|
|
14
|
+
protected constructor(opt: Partial<T>);
|
|
19
15
|
protected abstract runBefore(): void;
|
|
20
16
|
protected abstract runAfter(): void;
|
|
21
17
|
protected abstract getComment(data: string, indent?: string): string;
|
|
@@ -39,15 +35,13 @@ export declare abstract class Zod2X<T extends IZodToXOpt> {
|
|
|
39
35
|
protected abstract transpileStruct(data: ASTObject & ASTCommon): void;
|
|
40
36
|
protected abstract transpileUnion(data: (ASTUnion | ASTDiscriminatedUnion) & ASTCommon): void;
|
|
41
37
|
protected abstract transpileIntersection(data: ASTIntersection & ASTCommon): void;
|
|
42
|
-
protected isTranspilerable(token: TranspilerableTypes):
|
|
38
|
+
protected isTranspilerable(token: TranspilerableTypes): token is (ASTCommon & ASTUnion) | (ASTCommon & ASTDiscriminatedUnion) | (ASTCommon & ASTIntersection) | (ASTCommon & ASTObject) | (ASTCommon & ASTEnum) | (ASTCommon & ASTNativeEnum);
|
|
43
39
|
protected push0: (data: string) => number;
|
|
44
40
|
protected push1: (data: string) => number;
|
|
45
41
|
protected push2: (data: string) => number;
|
|
46
42
|
protected push3: (data: string) => number;
|
|
47
43
|
protected addComment(data?: string, indent?: string): void;
|
|
48
|
-
private _checkCompositeFlag;
|
|
49
44
|
protected getAttributeType(token: ASTNode | TranspilerableTypes): string;
|
|
50
45
|
private _transpileItem;
|
|
51
46
|
transpile(transpilerQueue: ASTNodes): string;
|
|
52
47
|
}
|
|
53
|
-
export {};
|
package/dist/core/transpiler.js
CHANGED
|
@@ -7,7 +7,7 @@ exports.Zod2X = void 0;
|
|
|
7
7
|
const zod_1 = require("zod");
|
|
8
8
|
const string_utils_1 = __importDefault(require("../utils/string_utils"));
|
|
9
9
|
class Zod2X {
|
|
10
|
-
constructor(
|
|
10
|
+
constructor(opt) {
|
|
11
11
|
this.push0 = (data) => this.output.push(`${this.indent[0]}${data}`);
|
|
12
12
|
this.push1 = (data) => this.output.push(`${this.indent[1]}${data}`);
|
|
13
13
|
this.push2 = (data) => this.output.push(`${this.indent[2]}${data}`);
|
|
@@ -16,28 +16,20 @@ class Zod2X {
|
|
|
16
16
|
this.imports = new Set();
|
|
17
17
|
this.indent = string_utils_1.default.getIndentationLevels(opt.indent || 4);
|
|
18
18
|
this.opt = opt;
|
|
19
|
-
this.inOpt = inOpt;
|
|
20
19
|
}
|
|
21
20
|
isTranspilerable(token) {
|
|
22
21
|
return (token.type === zod_1.ZodFirstPartyTypeKind.ZodEnum ||
|
|
23
22
|
token.type === zod_1.ZodFirstPartyTypeKind.ZodNativeEnum ||
|
|
24
23
|
token.type === zod_1.ZodFirstPartyTypeKind.ZodObject ||
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
token.type === zod_1.ZodFirstPartyTypeKind.ZodIntersection)));
|
|
24
|
+
token.type === zod_1.ZodFirstPartyTypeKind.ZodUnion ||
|
|
25
|
+
token.type === zod_1.ZodFirstPartyTypeKind.ZodDiscriminatedUnion ||
|
|
26
|
+
token.type === zod_1.ZodFirstPartyTypeKind.ZodIntersection);
|
|
29
27
|
}
|
|
30
28
|
addComment(data = "", indent = "") {
|
|
31
29
|
if (data && this.opt.includeComments) {
|
|
32
30
|
this.output.push(this.getComment(data, indent));
|
|
33
31
|
}
|
|
34
32
|
}
|
|
35
|
-
_checkCompositeFlag() {
|
|
36
|
-
if (!this.inOpt.enableCompositeTypes) {
|
|
37
|
-
throw new Error(`Composite Types cannot be performed for this output Language. ` +
|
|
38
|
-
`Add the missing 'typeName' to transpilerable schemas`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
33
|
getAttributeType(token) {
|
|
42
34
|
let varType = "";
|
|
43
35
|
if (this.isTranspilerable(token)) {
|
|
@@ -87,19 +79,6 @@ class Zod2X {
|
|
|
87
79
|
varType = this.getRecordType(key, value);
|
|
88
80
|
}
|
|
89
81
|
}
|
|
90
|
-
else if (!token.name &&
|
|
91
|
-
token.type === zod_1.ZodFirstPartyTypeKind.ZodIntersection) {
|
|
92
|
-
this._checkCompositeFlag();
|
|
93
|
-
const items = [token.left, token.right].map(this.getAttributeType.bind(this));
|
|
94
|
-
varType = this.getIntersectionType(items);
|
|
95
|
-
}
|
|
96
|
-
else if (!token.name &&
|
|
97
|
-
(token.type === zod_1.ZodFirstPartyTypeKind.ZodUnion ||
|
|
98
|
-
token.type === zod_1.ZodFirstPartyTypeKind.ZodDiscriminatedUnion)) {
|
|
99
|
-
this._checkCompositeFlag();
|
|
100
|
-
const items = token.options.map(this.getAttributeType.bind(this));
|
|
101
|
-
varType = this.getUnionType(items);
|
|
102
|
-
}
|
|
103
82
|
else {
|
|
104
83
|
console.log(" # Unknown attribute equivalent for ---> ", token.type);
|
|
105
84
|
}
|
package/dist/lib/zod_ext.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ declare module "zod" {
|
|
|
19
19
|
zod2x(this: ZodNativeEnum<T>, typeName: string): this;
|
|
20
20
|
zod2x(this: ZodNativeEnum<T>, opt: Pick<Zod2xMetadata, "typeName">): this;
|
|
21
21
|
}
|
|
22
|
-
interface ZodDiscriminatedUnion<Discriminator extends string, Options extends z.ZodDiscriminatedUnionOption<Discriminator>[]> {
|
|
22
|
+
interface ZodDiscriminatedUnion<Discriminator extends string, Options extends readonly z.ZodDiscriminatedUnionOption<Discriminator>[]> {
|
|
23
23
|
zod2x(this: ZodDiscriminatedUnion<Discriminator, Options>, typeName: string): this;
|
|
24
24
|
zod2x(this: ZodDiscriminatedUnion<Discriminator, Options>, opt: Pick<Zod2xMetadata, "typeName">): this;
|
|
25
25
|
}
|
|
@@ -36,4 +36,4 @@ declare module "zod" {
|
|
|
36
36
|
zod2x(this: ZodLiteral<T>, opt: Pick<Zod2xMetadata, "parentEnum">): this;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
export declare function extendZod(zod:
|
|
39
|
+
export declare function extendZod(zod: any): void;
|
|
@@ -13,9 +13,7 @@ const nlohmann_1 = require("./nlohmann");
|
|
|
13
13
|
const options_1 = require("./options");
|
|
14
14
|
class Zod2Cpp extends core_1.Zod2X {
|
|
15
15
|
constructor(opt = {}) {
|
|
16
|
-
super({
|
|
17
|
-
enableCompositeTypes: false,
|
|
18
|
-
}, Object.assign(Object.assign({}, options_1.defaultOpts), opt));
|
|
16
|
+
super(Object.assign(Object.assign({}, options_1.defaultOpts), opt));
|
|
19
17
|
this.getIntersectionType = () => {
|
|
20
18
|
return "";
|
|
21
19
|
};
|
|
@@ -144,7 +142,7 @@ class Zod2Cpp extends core_1.Zod2X {
|
|
|
144
142
|
data.left.referenceType === zod_1.ZodFirstPartyTypeKind.ZodObject &&
|
|
145
143
|
data.right.type === "definition" &&
|
|
146
144
|
data.right.referenceType === zod_1.ZodFirstPartyTypeKind.ZodObject)) {
|
|
147
|
-
throw new
|
|
145
|
+
throw new core_1.NotTranspilerableTypeError(`${data.name}: only intersection of ZodObjects is supported.`);
|
|
148
146
|
}
|
|
149
147
|
const leftType = this.getAttributeType(data.left);
|
|
150
148
|
const rightType = this.getAttributeType(data.right);
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { ASTCommon, ASTDiscriminatedUnion, ASTEnum, ASTIntersection, ASTNativeEnum, ASTObject, ASTUnion,
|
|
2
|
-
|
|
3
|
-
packageName?: string;
|
|
4
|
-
useCamelCase?: boolean;
|
|
5
|
-
}
|
|
1
|
+
import { ASTCommon, ASTDiscriminatedUnion, ASTEnum, ASTIntersection, ASTNativeEnum, ASTObject, ASTUnion, Zod2X } from "../../core";
|
|
2
|
+
import { IZod2ProtoV3Opt } from "./options";
|
|
6
3
|
export declare class Zod2ProtoV3 extends Zod2X<IZod2ProtoV3Opt> {
|
|
7
4
|
constructor(opt?: IZod2ProtoV3Opt);
|
|
8
5
|
protected getUnionType: () => string;
|
|
@@ -30,4 +27,3 @@ export declare class Zod2ProtoV3 extends Zod2X<IZod2ProtoV3Opt> {
|
|
|
30
27
|
protected runAfter(): void;
|
|
31
28
|
private _adaptField;
|
|
32
29
|
}
|
|
33
|
-
export {};
|
|
@@ -7,6 +7,7 @@ exports.Zod2ProtoV3 = void 0;
|
|
|
7
7
|
const case_1 = __importDefault(require("case"));
|
|
8
8
|
const core_1 = require("../../core");
|
|
9
9
|
const number_limits_1 = require("../../utils/number_limits");
|
|
10
|
+
const options_1 = require("./options");
|
|
10
11
|
const allowedKeyTypes = [
|
|
11
12
|
"int32",
|
|
12
13
|
"int64",
|
|
@@ -21,17 +22,9 @@ const allowedKeyTypes = [
|
|
|
21
22
|
"bool",
|
|
22
23
|
"string",
|
|
23
24
|
];
|
|
24
|
-
const defaultOpts = {
|
|
25
|
-
includeComments: true,
|
|
26
|
-
indent: 4,
|
|
27
|
-
useCamelCase: false,
|
|
28
|
-
skipDiscriminatorNodes: true,
|
|
29
|
-
};
|
|
30
25
|
class Zod2ProtoV3 extends core_1.Zod2X {
|
|
31
26
|
constructor(opt = {}) {
|
|
32
|
-
super({
|
|
33
|
-
enableCompositeTypes: true,
|
|
34
|
-
}, Object.assign(Object.assign({}, defaultOpts), opt));
|
|
27
|
+
super(Object.assign(Object.assign({}, options_1.defaultOpts), opt));
|
|
35
28
|
this.getUnionType = () => {
|
|
36
29
|
return "";
|
|
37
30
|
};
|
|
@@ -76,11 +69,11 @@ class Zod2ProtoV3 extends core_1.Zod2X {
|
|
|
76
69
|
return this.getArrayType(itemsType[0], 1);
|
|
77
70
|
}
|
|
78
71
|
else {
|
|
79
|
-
throw new
|
|
72
|
+
throw new core_1.NotTranspilerableTypeError("Protobuf v3 does not support mixed-type tuples. Consider defining a message type.");
|
|
80
73
|
}
|
|
81
74
|
};
|
|
82
75
|
this.getIntersectionType = (itemsType) => {
|
|
83
|
-
throw new
|
|
76
|
+
throw new core_1.NotTranspilerableTypeError("Protobuf v3 does not support intersection types directly.");
|
|
84
77
|
};
|
|
85
78
|
}
|
|
86
79
|
getArrayType(arrayType, arrayDeep) {
|
|
@@ -88,7 +81,7 @@ class Zod2ProtoV3 extends core_1.Zod2X {
|
|
|
88
81
|
return `repeated ${arrayType}`;
|
|
89
82
|
}
|
|
90
83
|
else {
|
|
91
|
-
throw new
|
|
84
|
+
throw new core_1.NotTranspilerableTypeError("Protobuf v3 does not support multidimensional arrays directly. " +
|
|
92
85
|
"You need to define nested message types for deeper arrays");
|
|
93
86
|
}
|
|
94
87
|
}
|
|
@@ -100,12 +93,12 @@ class Zod2ProtoV3 extends core_1.Zod2X {
|
|
|
100
93
|
return this.getNumberType(Number.isInteger(value), { min: value, max: value });
|
|
101
94
|
}
|
|
102
95
|
else {
|
|
103
|
-
throw new
|
|
96
|
+
throw new core_1.NotTranspilerableTypeError(`Protobuf v3 does not support Literals for this value type: ${value}`);
|
|
104
97
|
}
|
|
105
98
|
}
|
|
106
99
|
getMapType(keyType, valueType) {
|
|
107
100
|
if (!allowedKeyTypes.includes(keyType)) {
|
|
108
|
-
throw new
|
|
101
|
+
throw new core_1.NotTranspilerableTypeError(`Protobuf map keys must be an integral or string type, got '${keyType}'.`);
|
|
109
102
|
}
|
|
110
103
|
return `map<${keyType}, ${valueType}>`;
|
|
111
104
|
}
|
|
@@ -117,14 +110,14 @@ class Zod2ProtoV3 extends core_1.Zod2X {
|
|
|
117
110
|
this.push0(`enum ${data.name} {`);
|
|
118
111
|
data.values.forEach(([key, value], index) => {
|
|
119
112
|
if (Number.isInteger(key.at(0))) {
|
|
120
|
-
throw new
|
|
113
|
+
throw new core_1.NotTranspilerableTypeError(`Enumerate item name cannot start with number: ${key}`);
|
|
121
114
|
}
|
|
122
115
|
this.push1(`${key} = ${index};`);
|
|
123
116
|
});
|
|
124
117
|
this.push0("}\n");
|
|
125
118
|
}
|
|
126
119
|
transpileIntersection(data) {
|
|
127
|
-
throw new
|
|
120
|
+
throw new core_1.NotTranspilerableTypeError(`Protobuf does not support message intersections.`);
|
|
128
121
|
}
|
|
129
122
|
transpileStruct(data) {
|
|
130
123
|
this.addComment(data.description);
|
|
@@ -141,7 +134,7 @@ class Zod2ProtoV3 extends core_1.Zod2X {
|
|
|
141
134
|
this.addComment(data.description);
|
|
142
135
|
const attributesTypes = data.options.map(this.getAttributeType.bind(this));
|
|
143
136
|
if (attributesTypes.find((i) => i.startsWith("map<") || i.startsWith("repeated "))) {
|
|
144
|
-
throw new
|
|
137
|
+
throw new core_1.NotTranspilerableTypeError("Map and Repeated fields are not suported by Protobuf oneOf");
|
|
145
138
|
}
|
|
146
139
|
this.push0(`message ${data.name} {`);
|
|
147
140
|
this.push1(`oneof ${this._adaptField(data.name + "Oneof")} {`);
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { ASTCommon, ASTDiscriminatedUnion, ASTEnum, ASTIntersection, ASTNativeEnum, ASTObject, ASTUnion,
|
|
2
|
-
|
|
3
|
-
outType?: "interface" | "class";
|
|
4
|
-
}
|
|
1
|
+
import { ASTCommon, ASTDiscriminatedUnion, ASTEnum, ASTIntersection, ASTNativeEnum, ASTObject, ASTUnion, Zod2X } from "../../core";
|
|
2
|
+
import { IZod2TsOpt } from "./options";
|
|
5
3
|
export declare class Zod2Ts extends Zod2X<IZod2TsOpt> {
|
|
6
4
|
constructor(opt?: IZod2TsOpt);
|
|
7
5
|
protected runAfter(): void;
|
|
@@ -28,4 +26,3 @@ export declare class Zod2Ts extends Zod2X<IZod2TsOpt> {
|
|
|
28
26
|
private _transpileStructAsClass;
|
|
29
27
|
private _transpileMember;
|
|
30
28
|
}
|
|
31
|
-
export {};
|
|
@@ -6,17 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.Zod2Ts = void 0;
|
|
7
7
|
const case_1 = __importDefault(require("case"));
|
|
8
8
|
const core_1 = require("../../core");
|
|
9
|
-
const
|
|
10
|
-
includeComments: true,
|
|
11
|
-
indent: 4,
|
|
12
|
-
skipDiscriminatorNodes: false,
|
|
13
|
-
outType: "interface",
|
|
14
|
-
};
|
|
9
|
+
const options_1 = require("./options");
|
|
15
10
|
class Zod2Ts extends core_1.Zod2X {
|
|
16
11
|
constructor(opt = {}) {
|
|
17
|
-
super({
|
|
18
|
-
enableCompositeTypes: true,
|
|
19
|
-
}, Object.assign(Object.assign({}, defaultOpts), opt));
|
|
12
|
+
super(Object.assign(Object.assign({}, options_1.defaultOpts), opt));
|
|
20
13
|
this.getComment = (data, indent = "") => `${indent}// ${data}`;
|
|
21
14
|
this.getAnyType = () => "any";
|
|
22
15
|
this.getBooleanType = () => "boolean";
|
|
@@ -41,7 +34,7 @@ class Zod2Ts extends core_1.Zod2X {
|
|
|
41
34
|
}
|
|
42
35
|
getLiteralStringType(value, parentEnumNameKey) {
|
|
43
36
|
return parentEnumNameKey
|
|
44
|
-
? `${parentEnumNameKey[0]}.${parentEnumNameKey[1]}`
|
|
37
|
+
? `${parentEnumNameKey[0]}.${case_1.default.pascal(parentEnumNameKey[1])}`
|
|
45
38
|
: isNaN(Number(value))
|
|
46
39
|
? `"${value}"`
|
|
47
40
|
: value;
|
|
@@ -56,16 +49,24 @@ class Zod2Ts extends core_1.Zod2X {
|
|
|
56
49
|
this.addComment(data.description);
|
|
57
50
|
this.push0(`export enum ${data.name} {`);
|
|
58
51
|
data.values.forEach((i) => {
|
|
59
|
-
const
|
|
52
|
+
const key = case_1.default.pascal(i[0]);
|
|
53
|
+
const keyValue = isNaN(Number(key.at(0))) ? key : `"${key}"`;
|
|
60
54
|
const enumValue = typeof i[1] === "string" ? `"${i[1]}"` : `${i[1]}`;
|
|
61
55
|
this.push1(`${keyValue} = ${enumValue},`);
|
|
62
56
|
});
|
|
63
57
|
this.push0("}\n");
|
|
64
58
|
}
|
|
65
59
|
transpileIntersection(data) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
var _a;
|
|
61
|
+
if (this.opt.outType === "class" && data.newObject) {
|
|
62
|
+
this.addComment((_a = data.newObject) === null || _a === void 0 ? void 0 : _a.description);
|
|
63
|
+
this._transpileStructAsClass(data.newObject);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
this.addComment(data.description);
|
|
67
|
+
const attributesTypes = [data.left, data.right].map(this.getAttributeType.bind(this));
|
|
68
|
+
this.push0(`export type ${data.name} = ${this.getIntersectionType(attributesTypes)};\n`);
|
|
69
|
+
}
|
|
69
70
|
}
|
|
70
71
|
transpileStruct(data) {
|
|
71
72
|
this.addComment(data.description);
|
|
@@ -77,9 +78,16 @@ class Zod2Ts extends core_1.Zod2X {
|
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
transpileUnion(data) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
var _a;
|
|
82
|
+
if (this.opt.outType === "class" && data.newObject) {
|
|
83
|
+
this.addComment((_a = data.newObject) === null || _a === void 0 ? void 0 : _a.description);
|
|
84
|
+
this._transpileStructAsClass(data.newObject);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
this.addComment(data.description);
|
|
88
|
+
const attributesTypes = data.options.map(this.getAttributeType.bind(this));
|
|
89
|
+
this.push0(`export type ${data.name} = ${this.getUnionType(attributesTypes)};\n`);
|
|
90
|
+
}
|
|
83
91
|
}
|
|
84
92
|
_transpileStructuAsInterface(data) {
|
|
85
93
|
this.push0(`export interface ${data.name} {`);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.log = void 0;
|
|
4
|
+
const DEBUG = false;
|
|
5
|
+
function execute(fn) {
|
|
6
|
+
if (DEBUG) {
|
|
7
|
+
fn();
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.log = {
|
|
11
|
+
info: (...args) => execute(() => console.log(args)),
|
|
12
|
+
error: (...args) => execute(() => console.error(args)),
|
|
13
|
+
warn: (...args) => execute(() => console.warn(args)),
|
|
14
|
+
debug: (...args) => execute(() => console.debug(args)),
|
|
15
|
+
trace: (...args) => execute(() => console.trace(args)),
|
|
16
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zod-to-x",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Multi language types generation from Zod schemas.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -40,9 +40,11 @@
|
|
|
40
40
|
"lint-staged": {
|
|
41
41
|
"*.ts": "prettier --write"
|
|
42
42
|
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"zod": ">=3.22.3"
|
|
45
|
+
},
|
|
43
46
|
"dependencies": {
|
|
44
|
-
"case": "1.6.3"
|
|
45
|
-
"zod": "^3.23.8"
|
|
47
|
+
"case": "1.6.3"
|
|
46
48
|
},
|
|
47
49
|
"devDependencies": {
|
|
48
50
|
"@types/jest": "29.5.14",
|