zod-to-x 1.4.1 → 1.4.2
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 +71 -8
- package/dist/core/ast_node.d.ts +0 -9
- package/dist/core/ast_node.js +38 -48
- package/dist/core/ast_types.d.ts +28 -16
- package/dist/core/transpiler.d.ts +30 -9
- package/dist/core/transpiler.js +39 -27
- package/dist/core/zod_helpers.d.ts +7 -0
- package/dist/core/zod_helpers.js +25 -0
- package/dist/layered-modeling/layer.d.ts +4 -4
- package/dist/layered-modeling/layer.js +19 -1
- package/dist/lib/zod_ext.d.ts +41 -0
- package/dist/transpilers/cpp/options.js +0 -1
- package/dist/transpilers/cpp/runner.d.ts +1 -0
- package/dist/transpilers/cpp/runner.js +38 -2
- package/dist/transpilers/protobuf_v3/options.js +0 -1
- package/dist/transpilers/protobuf_v3/runner.d.ts +5 -0
- package/dist/transpilers/protobuf_v3/runner.js +14 -2
- package/dist/transpilers/typescript/options.js +0 -1
- package/dist/transpilers/typescript/runner.d.ts +4 -0
- package/dist/transpilers/typescript/runner.js +47 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -71,7 +71,7 @@ This extension appends a `zod2x` method to:
|
|
|
71
71
|
## Quick start
|
|
72
72
|
```ts
|
|
73
73
|
import { z } from "zod";
|
|
74
|
-
import { extendZod, Zod2Ast,
|
|
74
|
+
import { extendZod, Zod2Ast, Zod2XTranspilers } from "zod-to-x";
|
|
75
75
|
extendZod(z); // The extend step can be skipped if it has already been done.
|
|
76
76
|
|
|
77
77
|
/**
|
|
@@ -94,7 +94,7 @@ const visitorNodes = new Zod2Ast().build(VisitorSchema);
|
|
|
94
94
|
* 3) Generate types in the desired language.
|
|
95
95
|
* Depending on the transpiled language, data models can be generated using classes.
|
|
96
96
|
*/
|
|
97
|
-
const tsVisitorAsInterface: string = new Zod2Ts().transpile(visitorNodes);
|
|
97
|
+
const tsVisitorAsInterface: string = new Zod2XTranspilers.Zod2Ts().transpile(visitorNodes);
|
|
98
98
|
console.log(tsVisitorAsInterface)
|
|
99
99
|
// output:
|
|
100
100
|
// export interface Visitor {
|
|
@@ -105,7 +105,7 @@ console.log(tsVisitorAsInterface)
|
|
|
105
105
|
// comments?: string;
|
|
106
106
|
// }
|
|
107
107
|
|
|
108
|
-
const tsVisitorAsClass: string = new Zod2Ts({outType: "class"}).transpile(visitorNodes);
|
|
108
|
+
const tsVisitorAsClass: string = new Zod2XTranspilers.Zod2Ts({outType: "class"}).transpile(visitorNodes);
|
|
109
109
|
console.log(tsVisitorAsClass)
|
|
110
110
|
// output:
|
|
111
111
|
// export class Visitor {
|
|
@@ -255,9 +255,12 @@ inline void from_json(const json& j, Message& x) {
|
|
|
255
255
|
## Layered modeling
|
|
256
256
|
To improve Separation of Concerns (SoC), the Dependency Rule, and Maintainability, a new layer-based modeling approach was introduced in `v1.4.0`. This approach establishes relationships between models in separate files, which are transpiled into file imports. This feature provides a powerful tool not only for type systems with robust architectures, such as Clean, Hexagonal, or Layered, but also enforces their usage.
|
|
257
257
|
|
|
258
|
-
To achieve this,
|
|
258
|
+
To achieve this, new components are included:
|
|
259
259
|
- **Zod2XModel**: With layered modeling, data is defined using classes. Inheriting this abstract class provides metadata management to handle relationships and also simplifies transpilation by including a `transpile()` method that receives the target language class.
|
|
260
|
-
- **Layer**: A class decorator that defines class metadata, including a reference to the output file of the modeled data, a namespace under which its types are grouped, and an integer index representing the layer number. It can also be used as a decorator factory to define custom layers. Out of the box, four layers are provided: *Domain*, *Application*, *Infrastructure*, and *Presentation*.
|
|
260
|
+
- **Layer**: A class decorator that defines class metadata, including a reference to the output file of the modeled data, a namespace under which its types are grouped, and an integer index representing the layer number. It can also be used as a decorator factory to define custom layers. Out of the box, four layers are provided: *Domain*, *Application*, *Infrastructure*, and *Presentation*. Parameters:
|
|
261
|
+
- **namespace**: Defines the namespace under which the types are grouped.
|
|
262
|
+
- **file**: Specifies the expected output file where the transpiled types will be saved.
|
|
263
|
+
- **externalInheritance**: When a type from one layer is imported into another layer without modifications, it is transpiled as a new type inheriting from the imported type. This ensures type consistency across layers while maintaining reusability. See example (4) below. The default value is `true`.
|
|
261
264
|
- **Zod2XMixin**: A function that enables the creation of layers by extending multiple data models, thereby simplifying their definition and organization.
|
|
262
265
|
|
|
263
266
|
### Usage example
|
|
@@ -319,7 +322,7 @@ class UserDtos extends Zod2XModel {
|
|
|
319
322
|
}
|
|
320
323
|
|
|
321
324
|
const userDtos = new UserDtos();
|
|
322
|
-
console.log(userDtos.transpile(
|
|
325
|
+
console.log(userDtos.transpile(Zod2XTranspilers.Zod2Ts))
|
|
323
326
|
// Output:
|
|
324
327
|
// import * as USER from "./user.entity"; <--- Reusing models from other layers.
|
|
325
328
|
|
|
@@ -375,7 +378,7 @@ class UserDtos extends Zod2XMixin(
|
|
|
375
378
|
) {}
|
|
376
379
|
|
|
377
380
|
export const userDtos = new UserDtos();
|
|
378
|
-
console.log(userDtos.transpile(
|
|
381
|
+
console.log(userDtos.transpile(Zod2XTranspilers.Zod2Ts))
|
|
379
382
|
// Output (same as above):
|
|
380
383
|
// import * as USER from "./user.entity"; <--- Reusing models from other layers.
|
|
381
384
|
|
|
@@ -401,6 +404,67 @@ console.log(userDtos.transpile(Transpilers.Zod2Ts))
|
|
|
401
404
|
// }
|
|
402
405
|
```
|
|
403
406
|
|
|
407
|
+
4 - Difference of using **externalInheritance** (defaults) or not.
|
|
408
|
+
```ts
|
|
409
|
+
// Default output (externalInheritance = true)
|
|
410
|
+
@Application({ namespace: "USER_DTOS", file: "user.dtos" })
|
|
411
|
+
class UserDtos extends Zod2XModel {
|
|
412
|
+
|
|
413
|
+
createUserUseCaseDto = userModels.userEntity.omit({ id: true });
|
|
414
|
+
|
|
415
|
+
createUserUseCaseResultDto = userModels.userEntity;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Output:
|
|
419
|
+
// import * as USER from "./user.entity";
|
|
420
|
+
|
|
421
|
+
// export interface CreateUserUseCaseDto {
|
|
422
|
+
// name: string;
|
|
423
|
+
// email: string;
|
|
424
|
+
// age?: number;
|
|
425
|
+
// role: USER.UserRole;
|
|
426
|
+
// }
|
|
427
|
+
|
|
428
|
+
// export interface CreateUserUseCaseResultDto extends USER.UserEntity {}
|
|
429
|
+
|
|
430
|
+
// export interface UserDtos {
|
|
431
|
+
// createUserUseCaseDto: CreateUserUseCaseDto;
|
|
432
|
+
// createUserUseCaseResultDto: CreateUserUseCaseResultDto;
|
|
433
|
+
// }
|
|
434
|
+
|
|
435
|
+
// ---------------
|
|
436
|
+
// If `USER.UserEntity` were a Union or a Discriminated Union, the output would be a Type equivalent to `USER.UserEntity` rather than an Interface that extends it.
|
|
437
|
+
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
```ts
|
|
441
|
+
// Output without externalInheritance
|
|
442
|
+
@Application({ namespace: "USER_DTOS", file: "user.dtos", externalInheritance: false})
|
|
443
|
+
class UserDtos extends Zod2XModel {
|
|
444
|
+
|
|
445
|
+
createUserUseCaseDto = userModels.userEntity.omit({ id: true });
|
|
446
|
+
|
|
447
|
+
createUserUseCaseResultDto = userModels.userEntity;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Output:
|
|
451
|
+
// import * as USER from "./user.entity";
|
|
452
|
+
|
|
453
|
+
// export interface CreateUserUseCaseDto {
|
|
454
|
+
// name: string;
|
|
455
|
+
// email: string;
|
|
456
|
+
// age?: number;
|
|
457
|
+
// role: USER.UserRole;
|
|
458
|
+
// }
|
|
459
|
+
|
|
460
|
+
// export interface UserDtos {
|
|
461
|
+
// createUserUseCaseDto: CreateUserUseCaseDto;
|
|
462
|
+
// createUserUseCaseResultDto: USER.UserEntity;
|
|
463
|
+
// }
|
|
464
|
+
|
|
465
|
+
// ---------------
|
|
466
|
+
// In this case, the type of `createUserUseCaseResultDto` is inferred from the parent model (`UserDtos`), but there is no explicit definition of the type itself.
|
|
467
|
+
```
|
|
404
468
|
|
|
405
469
|
|
|
406
470
|
## Supported output languages
|
|
@@ -408,7 +472,6 @@ Common options:
|
|
|
408
472
|
- **header**: Text to add as a comment at the beginning of the output.
|
|
409
473
|
- **indent**: Number of spaces to use for indentation in the generated code. Defaults to 4 if not specified.
|
|
410
474
|
- **includeComments**: Determines whether to include comments in the transpiled code. Defaults to `true`.
|
|
411
|
-
- **skipDiscriminatorNodes**: prevents the inclusion of `ZodEnum` or `ZodNativeEnum` schemas that are used solely as discriminator keys in a `ZodDiscriminatedUnion`. Defaults to `false`.
|
|
412
475
|
|
|
413
476
|
### 0) ASTNode
|
|
414
477
|
- Options:
|
package/dist/core/ast_node.d.ts
CHANGED
|
@@ -23,14 +23,6 @@ export declare class Zod2Ast {
|
|
|
23
23
|
* Transpilerable nodes of current data model
|
|
24
24
|
*/
|
|
25
25
|
private nodes;
|
|
26
|
-
/**
|
|
27
|
-
* Transpilerable nodes of external data models (used for layered modeling)
|
|
28
|
-
*/
|
|
29
|
-
private externalNodes;
|
|
30
|
-
/**
|
|
31
|
-
* Additional transpilerable nodes supplied by ZodDiscriminatedUnion
|
|
32
|
-
*/
|
|
33
|
-
private discriminatorNodes;
|
|
34
26
|
/**
|
|
35
27
|
* Lazy schemas for further analysis
|
|
36
28
|
*/
|
|
@@ -87,7 +79,6 @@ export declare class Zod2Ast {
|
|
|
87
79
|
*/
|
|
88
80
|
private _unionAstNodes;
|
|
89
81
|
private _getNames;
|
|
90
|
-
private _getNode;
|
|
91
82
|
private _getEnumAst;
|
|
92
83
|
private _getObjectAst;
|
|
93
84
|
private _getUnionAst;
|
package/dist/core/ast_node.js
CHANGED
|
@@ -13,8 +13,6 @@ class Zod2Ast {
|
|
|
13
13
|
constructor(opt = {}) {
|
|
14
14
|
var _a;
|
|
15
15
|
this.nodes = new Map();
|
|
16
|
-
this.externalNodes = new Map();
|
|
17
|
-
this.discriminatorNodes = new Map();
|
|
18
16
|
this.lazyPointers = [];
|
|
19
17
|
this.warnings = [];
|
|
20
18
|
this.opt = Object.assign(Object.assign({}, opt), { strict: (_a = opt.strict) !== null && _a !== void 0 ? _a : true });
|
|
@@ -27,14 +25,20 @@ class Zod2Ast {
|
|
|
27
25
|
* @param layerMetadata
|
|
28
26
|
* @returns
|
|
29
27
|
*/
|
|
30
|
-
_getTranspilerableFile(itemName,
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
_getTranspilerableFile(itemName, metadata) {
|
|
29
|
+
var _a;
|
|
30
|
+
const layer = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.parentLayer) !== null && _a !== void 0 ? _a : metadata === null || metadata === void 0 ? void 0 : metadata.layer;
|
|
31
|
+
if (this.opt.layer && layer) {
|
|
32
|
+
if (this.opt.layer.index < layer.index) {
|
|
33
33
|
throw new errors_1.BadLayerDefinitionError(`${itemName}: Layer with number ${this.opt.layer.index} can only use models` +
|
|
34
|
-
`from the same or lower layer. Found layer with number ${
|
|
34
|
+
`from the same or lower layer. Found layer with number ${layer.index}`);
|
|
35
35
|
}
|
|
36
|
-
if (this.opt.layer.file !==
|
|
37
|
-
return {
|
|
36
|
+
if (this.opt.layer.file !== layer.file) {
|
|
37
|
+
return {
|
|
38
|
+
parentFile: layer.file,
|
|
39
|
+
parentNamespace: layer.namespace,
|
|
40
|
+
parentTypeName: metadata === null || metadata === void 0 ? void 0 : metadata.parentTypeName,
|
|
41
|
+
};
|
|
38
42
|
}
|
|
39
43
|
}
|
|
40
44
|
return {};
|
|
@@ -144,63 +148,51 @@ class Zod2Ast {
|
|
|
144
148
|
};
|
|
145
149
|
}
|
|
146
150
|
_getNames(schema, errorString) {
|
|
147
|
-
var _a
|
|
151
|
+
var _a;
|
|
148
152
|
const name = (_a = schema._zod2x) === null || _a === void 0 ? void 0 : _a.typeName;
|
|
149
153
|
if (!name) {
|
|
150
154
|
throw new errors_1.AstTypeNameDefinitionError(errorString);
|
|
151
155
|
}
|
|
152
|
-
return Object.assign({ name,
|
|
153
|
-
}
|
|
154
|
-
_getNode(fileName) {
|
|
155
|
-
return fileName ? this.externalNodes : this.nodes;
|
|
156
|
+
return Object.assign({ name, zodTypeName: schema._def.typeName }, this._getTranspilerableFile(name, schema._zod2x));
|
|
156
157
|
}
|
|
157
158
|
_getEnumAst(schema, opt) {
|
|
158
|
-
const { name,
|
|
159
|
+
const { name, zodTypeName, parentFile, parentNamespace, parentTypeName } = this._getNames(schema, "ZodEnum/ZodNativeEnum type must have a typeName. Use zod2x method to provide one.");
|
|
159
160
|
const item = {
|
|
160
|
-
type:
|
|
161
|
+
type: zodTypeName,
|
|
161
162
|
name,
|
|
162
163
|
values: this._getEnumValues(schema),
|
|
163
164
|
description: schema._def.description,
|
|
164
165
|
parentFile,
|
|
165
166
|
parentNamespace,
|
|
167
|
+
parentTypeName,
|
|
168
|
+
isFromDiscriminatedUnion: opt === null || opt === void 0 ? void 0 : opt.isInjectedEnum,
|
|
166
169
|
};
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if (!node.has(name) && !this.discriminatorNodes.has(name)) {
|
|
170
|
-
this.discriminatorNodes.set(name, item);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
if (!node.has(name)) {
|
|
175
|
-
node.set(name, item);
|
|
176
|
-
}
|
|
177
|
-
if (this.discriminatorNodes.has(name)) {
|
|
178
|
-
this.discriminatorNodes.delete(name);
|
|
179
|
-
}
|
|
170
|
+
if (!this.nodes.has(name)) {
|
|
171
|
+
this.nodes.set(name, item);
|
|
180
172
|
}
|
|
181
|
-
return this._createDefinition(name,
|
|
173
|
+
return this._createDefinition(name, zodTypeName, undefined, parentNamespace);
|
|
182
174
|
}
|
|
183
175
|
_getObjectAst(schema, opt) {
|
|
184
|
-
const { name,
|
|
176
|
+
const { name, zodTypeName, parentFile, parentNamespace, parentTypeName } = this._getNames(schema, "ZodObject type must have a typeName. Use zod2x method to provide one.");
|
|
185
177
|
let discriminantValue = undefined;
|
|
186
178
|
const shape = schema._def.shape();
|
|
187
|
-
|
|
188
|
-
if (!node.has(name)) {
|
|
179
|
+
if (!this.nodes.has(name)) {
|
|
189
180
|
const properties = {};
|
|
190
181
|
for (const key in shape) {
|
|
191
182
|
properties[key] = this._zodToAST(shape[key]);
|
|
192
183
|
}
|
|
193
|
-
|
|
184
|
+
this.nodes.set(name, {
|
|
194
185
|
type: zod_1.ZodFirstPartyTypeKind.ZodObject,
|
|
195
186
|
name,
|
|
196
187
|
properties,
|
|
197
188
|
description: schema.description,
|
|
198
189
|
parentFile,
|
|
199
190
|
parentNamespace,
|
|
191
|
+
parentTypeName,
|
|
200
192
|
});
|
|
201
193
|
}
|
|
202
194
|
if (opt === null || opt === void 0 ? void 0 : opt.discriminantKey) {
|
|
203
|
-
const item =
|
|
195
|
+
const item = this.nodes.get(name);
|
|
204
196
|
if (Object.keys(item.properties).includes(opt.discriminantKey)) {
|
|
205
197
|
const key = opt.discriminantKey;
|
|
206
198
|
if (item.properties[key].type === zod_1.ZodFirstPartyTypeKind.ZodLiteral) {
|
|
@@ -213,22 +205,22 @@ class Zod2Ast {
|
|
|
213
205
|
}
|
|
214
206
|
}
|
|
215
207
|
}
|
|
216
|
-
return this._createDefinition(name,
|
|
208
|
+
return this._createDefinition(name, zodTypeName, discriminantValue, parentTypeName ? undefined : parentNamespace);
|
|
217
209
|
}
|
|
218
210
|
_getUnionAst(schema) {
|
|
219
211
|
const def = schema._def;
|
|
220
212
|
const discriminator = schema instanceof zod_1.ZodDiscriminatedUnion ? schema._def.discriminator : undefined;
|
|
221
|
-
const { name,
|
|
213
|
+
const { name, zodTypeName, parentFile, parentNamespace, parentTypeName } = this._getNames(schema, "ZodUnion/ZodDiscriminatedUnion type must have a typeName. " +
|
|
222
214
|
"Use zod2x method to provide one.");
|
|
223
|
-
const node = this._getNode(parentFile);
|
|
224
215
|
const item = {
|
|
225
|
-
type:
|
|
216
|
+
type: zodTypeName,
|
|
226
217
|
name,
|
|
227
218
|
options: def.options.map((i) => this._zodToAST(i, { discriminantKey: discriminator })),
|
|
228
219
|
description: schema.description,
|
|
229
220
|
discriminantKey: discriminator,
|
|
230
221
|
parentFile,
|
|
231
222
|
parentNamespace,
|
|
223
|
+
parentTypeName,
|
|
232
224
|
};
|
|
233
225
|
if (!def.options.every((i) => i instanceof zod_1.ZodObject)) {
|
|
234
226
|
this.warnings.push("Union of non-object types is a bad data modeling practice, " +
|
|
@@ -246,15 +238,14 @@ class Zod2Ast {
|
|
|
246
238
|
`${item.options.map((i) => i.reference).join(", ")}`,
|
|
247
239
|
};
|
|
248
240
|
}
|
|
249
|
-
if (name && !
|
|
250
|
-
|
|
241
|
+
if (name && !this.nodes.has(name)) {
|
|
242
|
+
this.nodes.set(name, item);
|
|
251
243
|
}
|
|
252
|
-
return this._createDefinition(name,
|
|
244
|
+
return this._createDefinition(name, zodTypeName, undefined, parentTypeName ? undefined : parentNamespace);
|
|
253
245
|
}
|
|
254
246
|
_getIntersectionAst(schema) {
|
|
255
247
|
const def = schema._def;
|
|
256
|
-
const { name,
|
|
257
|
-
const node = this._getNode(parentFile);
|
|
248
|
+
const { name, zodTypeName, parentFile, parentNamespace, parentTypeName } = this._getNames(schema, "ZodIntersection type must have a typeName. Use zod2x method to provide one.");
|
|
258
249
|
const item = {
|
|
259
250
|
type: zod_1.ZodFirstPartyTypeKind.ZodIntersection,
|
|
260
251
|
name,
|
|
@@ -263,6 +254,7 @@ class Zod2Ast {
|
|
|
263
254
|
description: schema.description,
|
|
264
255
|
parentFile,
|
|
265
256
|
parentNamespace,
|
|
257
|
+
parentTypeName,
|
|
266
258
|
};
|
|
267
259
|
if (def.left._def.typeName !== "ZodObject" || def.right._def.typeName !== "ZodObject") {
|
|
268
260
|
this.warnings.push("Intersection of non-object is a bad data modeling practice, " +
|
|
@@ -279,10 +271,10 @@ class Zod2Ast {
|
|
|
279
271
|
`${item.right.reference}`,
|
|
280
272
|
};
|
|
281
273
|
}
|
|
282
|
-
if (name && !
|
|
283
|
-
|
|
274
|
+
if (name && !this.nodes.has(name)) {
|
|
275
|
+
this.nodes.set(name, item);
|
|
284
276
|
}
|
|
285
|
-
return this._createDefinition(name,
|
|
277
|
+
return this._createDefinition(name, zodTypeName, undefined, parentTypeName ? undefined : parentNamespace);
|
|
286
278
|
}
|
|
287
279
|
/**
|
|
288
280
|
* Build the AST node of provided Zod Schema
|
|
@@ -450,8 +442,6 @@ class Zod2Ast {
|
|
|
450
442
|
}
|
|
451
443
|
return {
|
|
452
444
|
nodes: this.nodes,
|
|
453
|
-
externalNodes: this.externalNodes,
|
|
454
|
-
discriminatorNodes: this.discriminatorNodes,
|
|
455
445
|
warnings: this.warnings,
|
|
456
446
|
};
|
|
457
447
|
}
|
package/dist/core/ast_types.d.ts
CHANGED
|
@@ -8,6 +8,19 @@ export type ASTCommon = {
|
|
|
8
8
|
isNullable?: boolean;
|
|
9
9
|
isOptional?: boolean;
|
|
10
10
|
};
|
|
11
|
+
export type ASTLayerMetadata = {
|
|
12
|
+
/**
|
|
13
|
+
* File where the transpilerable model is defined and the reference used to group imports.
|
|
14
|
+
* Used to generate import statements in the transpiled code.
|
|
15
|
+
*/
|
|
16
|
+
parentFile?: string;
|
|
17
|
+
parentNamespace?: string;
|
|
18
|
+
/**
|
|
19
|
+
* For Layered Modeling.
|
|
20
|
+
* Stores the used type from an external model. Used to create models inheritance.
|
|
21
|
+
*/
|
|
22
|
+
parentTypeName?: string;
|
|
23
|
+
};
|
|
11
24
|
/**
|
|
12
25
|
* AST (Abstract Syntax Tree) type for each Zod Schema that encapsulates
|
|
13
26
|
* additional information beyond just the schema type.
|
|
@@ -48,17 +61,25 @@ export type ASTEnum = {
|
|
|
48
61
|
type: ZodFirstPartyTypeKind.ZodEnum;
|
|
49
62
|
name: string;
|
|
50
63
|
values: [string, string | number][];
|
|
51
|
-
|
|
64
|
+
/**
|
|
65
|
+
* The enum is injected using zod2x method during ZodDiscriminatedUnion creation.
|
|
66
|
+
*/
|
|
67
|
+
isFromDiscriminatedUnion?: boolean;
|
|
68
|
+
} & ASTLayerMetadata;
|
|
52
69
|
export type ASTNativeEnum = {
|
|
53
70
|
type: ZodFirstPartyTypeKind.ZodNativeEnum;
|
|
54
71
|
name: string;
|
|
55
72
|
values: [string, string | number][];
|
|
56
|
-
|
|
73
|
+
/**
|
|
74
|
+
* The enum is injected using zod2x method during ZodDiscriminatedUnion creation.
|
|
75
|
+
*/
|
|
76
|
+
isFromDiscriminatedUnion?: boolean;
|
|
77
|
+
} & ASTLayerMetadata;
|
|
57
78
|
export type ASTObject = {
|
|
58
79
|
type: ZodFirstPartyTypeKind.ZodObject;
|
|
59
80
|
name: string;
|
|
60
81
|
properties: Record<string, ASTNode>;
|
|
61
|
-
};
|
|
82
|
+
} & ASTLayerMetadata;
|
|
62
83
|
export type ASTUnion = {
|
|
63
84
|
type: ZodFirstPartyTypeKind.ZodUnion;
|
|
64
85
|
name: string;
|
|
@@ -68,13 +89,13 @@ export type ASTUnion = {
|
|
|
68
89
|
* have a variant type or discriminated union cannot be used.
|
|
69
90
|
*/
|
|
70
91
|
newObject?: ASTCommon & ASTObject;
|
|
71
|
-
};
|
|
92
|
+
} & ASTLayerMetadata;
|
|
72
93
|
export type ASTDiscriminatedUnion = {
|
|
73
94
|
type: ZodFirstPartyTypeKind.ZodDiscriminatedUnion;
|
|
74
95
|
name: string;
|
|
75
96
|
options: ASTNode[];
|
|
76
97
|
discriminantKey?: string;
|
|
77
|
-
};
|
|
98
|
+
} & ASTLayerMetadata;
|
|
78
99
|
export type ASTIntersection = {
|
|
79
100
|
type: ZodFirstPartyTypeKind.ZodIntersection;
|
|
80
101
|
name: string;
|
|
@@ -85,7 +106,7 @@ export type ASTIntersection = {
|
|
|
85
106
|
* support multiple inheritance.
|
|
86
107
|
*/
|
|
87
108
|
newObject?: ASTCommon & ASTObject;
|
|
88
|
-
};
|
|
109
|
+
} & ASTLayerMetadata;
|
|
89
110
|
/**
|
|
90
111
|
* Represents a type definition in the AST. Used to reduce node size and identify
|
|
91
112
|
* schemas that can be referenced in a transpilation process.
|
|
@@ -119,17 +140,8 @@ export type ASTNode = ASTCommon & ({
|
|
|
119
140
|
/**
|
|
120
141
|
* Represents schemas that can be directly transpiled into types in other programming languages.
|
|
121
142
|
*/
|
|
122
|
-
export type TranspilerableTypes = ASTCommon & (ASTEnum | ASTNativeEnum | ASTObject | ASTUnion | ASTDiscriminatedUnion | ASTIntersection)
|
|
123
|
-
/**
|
|
124
|
-
* File where the transpilerable model is defined and the reference used to group imports.
|
|
125
|
-
* Used to generate import statements in the transpiled code.
|
|
126
|
-
*/
|
|
127
|
-
parentFile?: string;
|
|
128
|
-
parentNamespace?: string;
|
|
129
|
-
};
|
|
143
|
+
export type TranspilerableTypes = ASTCommon & (ASTEnum | ASTNativeEnum | ASTObject | ASTUnion | ASTDiscriminatedUnion | ASTIntersection);
|
|
130
144
|
export type ASTNodes = {
|
|
131
145
|
nodes: Map<string, TranspilerableTypes>;
|
|
132
|
-
externalNodes: Map<string, TranspilerableTypes>;
|
|
133
|
-
discriminatorNodes: Map<string, TranspilerableTypes>;
|
|
134
146
|
warnings: string[];
|
|
135
147
|
};
|
|
@@ -19,13 +19,6 @@ export interface IZodToXOpt extends Record<string, any> {
|
|
|
19
19
|
* Defaults to `true`.
|
|
20
20
|
*/
|
|
21
21
|
includeComments?: boolean;
|
|
22
|
-
/**
|
|
23
|
-
* When set to `true`, this option excludes discriminator enums from the output types.
|
|
24
|
-
* Specifically, it prevents the inclusion of `ZodEnum` or `ZodNativeEnum` schemas that are used
|
|
25
|
-
* solely as discriminator keys in a `ZodDiscriminatedUnion`. This helps avoid adding
|
|
26
|
-
* enum types to the generated output when unnecessary.
|
|
27
|
-
*/
|
|
28
|
-
skipDiscriminatorNodes?: boolean;
|
|
29
22
|
/**
|
|
30
23
|
* Every external type will be imported from the file where it is defined. Default: true
|
|
31
24
|
*/
|
|
@@ -39,7 +32,9 @@ export interface IZodToXOpt extends Record<string, any> {
|
|
|
39
32
|
export declare abstract class Zod2X<T extends IZodToXOpt> {
|
|
40
33
|
protected output: string[];
|
|
41
34
|
protected indent: TIndentationLevels;
|
|
35
|
+
protected preImports: Set<string>;
|
|
42
36
|
protected imports: Set<string>;
|
|
37
|
+
protected postImports: Set<string>;
|
|
43
38
|
protected opt: Partial<T>;
|
|
44
39
|
protected constructor(opt: Partial<T>);
|
|
45
40
|
/**
|
|
@@ -60,6 +55,15 @@ export declare abstract class Zod2X<T extends IZodToXOpt> {
|
|
|
60
55
|
* @param typeName
|
|
61
56
|
*/
|
|
62
57
|
protected abstract getTypeFromExternalNamespace(namespace: string, typeName: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* For Layered Modeling.
|
|
60
|
+
* If a property type is an imported type, without any modification, the transpiled type will be
|
|
61
|
+
* an inherited type from the imported type.
|
|
62
|
+
* @param name
|
|
63
|
+
* @param parentNamespace
|
|
64
|
+
* @param parentTypeName
|
|
65
|
+
*/
|
|
66
|
+
protected abstract addExtendedType(name: string, parentNamespace: string, parentTypeName: string): void;
|
|
63
67
|
/**
|
|
64
68
|
* Returns a comment.
|
|
65
69
|
*/
|
|
@@ -183,13 +187,30 @@ export declare abstract class Zod2X<T extends IZodToXOpt> {
|
|
|
183
187
|
* @returns A string representing the type in the target language.
|
|
184
188
|
*/
|
|
185
189
|
protected getAttributeType(token: ASTNode | TranspilerableTypes): string;
|
|
190
|
+
/**
|
|
191
|
+
* Adds an external type import to the transpiler's imports if the provided transpiled item
|
|
192
|
+
* is located into another file and namespace, and if the `useImports` option is not disabled.
|
|
193
|
+
*
|
|
194
|
+
* @param item - An object of type `TranspilerableTypes` containing information
|
|
195
|
+
* about the type to be imported, including its parent file and namespace.
|
|
196
|
+
* @returns `true` if the import was successfully added, otherwise `false`.
|
|
197
|
+
*/
|
|
198
|
+
protected addExternalTypeImport(item: TranspilerableTypes): boolean;
|
|
186
199
|
/**
|
|
187
200
|
* Transpiles a single item from the transpiler queue.
|
|
188
201
|
* @param item - The transpilerable type to transpile.
|
|
189
202
|
*/
|
|
190
203
|
private _transpileItem;
|
|
191
|
-
|
|
192
|
-
|
|
204
|
+
/**
|
|
205
|
+
* Constructs and returns an array of strings representing the header section
|
|
206
|
+
* of the transpiled output. The header may include custom comments, pre-imports,
|
|
207
|
+
* imports, and post-imports, depending on the provided options and internal state.
|
|
208
|
+
*
|
|
209
|
+
* Each section is separated by an empty string for readability.
|
|
210
|
+
*
|
|
211
|
+
* @returns An array of strings representing the header section.
|
|
212
|
+
*
|
|
213
|
+
*/
|
|
193
214
|
private _getHeader;
|
|
194
215
|
/**
|
|
195
216
|
* Transpiles a queue of AST nodes into the target language.
|
package/dist/core/transpiler.js
CHANGED
|
@@ -20,7 +20,9 @@ class Zod2X {
|
|
|
20
20
|
this.push2 = (data) => this.output.push(`${this.indent[2]}${data}`);
|
|
21
21
|
this.push3 = (data) => this.output.push(`${this.indent[3]}${data}`);
|
|
22
22
|
this.output = [];
|
|
23
|
+
this.preImports = new Set();
|
|
23
24
|
this.imports = new Set();
|
|
25
|
+
this.postImports = new Set();
|
|
24
26
|
this.indent = string_utils_1.default.getIndentationLevels(opt.indent || 4);
|
|
25
27
|
this.opt = opt;
|
|
26
28
|
}
|
|
@@ -104,6 +106,21 @@ class Zod2X {
|
|
|
104
106
|
}
|
|
105
107
|
return token.arrayDimension ? this.getArrayType(varType, token.arrayDimension) : varType;
|
|
106
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Adds an external type import to the transpiler's imports if the provided transpiled item
|
|
111
|
+
* is located into another file and namespace, and if the `useImports` option is not disabled.
|
|
112
|
+
*
|
|
113
|
+
* @param item - An object of type `TranspilerableTypes` containing information
|
|
114
|
+
* about the type to be imported, including its parent file and namespace.
|
|
115
|
+
* @returns `true` if the import was successfully added, otherwise `false`.
|
|
116
|
+
*/
|
|
117
|
+
addExternalTypeImport(item) {
|
|
118
|
+
if (item.parentFile && item.parentNamespace && this.opt.useImports !== false) {
|
|
119
|
+
this.imports.add(this.addImportFromFile(item.parentFile, item.parentNamespace));
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
107
124
|
/**
|
|
108
125
|
* Transpiles a single item from the transpiler queue.
|
|
109
126
|
* @param item - The transpilerable type to transpile.
|
|
@@ -127,35 +144,33 @@ class Zod2X {
|
|
|
127
144
|
throw new Error(`Unexpected type for transpilation: ${item.type}`);
|
|
128
145
|
}
|
|
129
146
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (i.parentFile && i.parentNamespace && !importData.has(i.parentFile)) {
|
|
141
|
-
importData.set(i.parentFile, i.parentNamespace);
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
importData.forEach((namespace, file) => {
|
|
145
|
-
this.imports.add(this.addImportFromFile(file, namespace));
|
|
146
|
-
});
|
|
147
|
-
}
|
|
147
|
+
/**
|
|
148
|
+
* Constructs and returns an array of strings representing the header section
|
|
149
|
+
* of the transpiled output. The header may include custom comments, pre-imports,
|
|
150
|
+
* imports, and post-imports, depending on the provided options and internal state.
|
|
151
|
+
*
|
|
152
|
+
* Each section is separated by an empty string for readability.
|
|
153
|
+
*
|
|
154
|
+
* @returns An array of strings representing the header section.
|
|
155
|
+
*
|
|
156
|
+
*/
|
|
148
157
|
_getHeader() {
|
|
149
|
-
var _a;
|
|
150
158
|
const header = [];
|
|
151
159
|
if (this.opt.header) {
|
|
152
160
|
header.push(...this.opt.header.split("\n").map((i) => this.getComment(i)));
|
|
161
|
+
header.push("");
|
|
162
|
+
}
|
|
163
|
+
if (this.preImports.size > 0) {
|
|
164
|
+
header.push(...this.preImports);
|
|
165
|
+
header.push("");
|
|
153
166
|
}
|
|
154
167
|
if (this.imports.size > 0) {
|
|
155
|
-
header.push(...this.imports);
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
168
|
+
header.push(...[...this.imports].sort());
|
|
169
|
+
header.push("");
|
|
170
|
+
}
|
|
171
|
+
if (this.postImports.size > 0) {
|
|
172
|
+
header.push(...this.postImports);
|
|
173
|
+
header.push("");
|
|
159
174
|
}
|
|
160
175
|
return header;
|
|
161
176
|
}
|
|
@@ -166,11 +181,8 @@ class Zod2X {
|
|
|
166
181
|
*/
|
|
167
182
|
transpile(transpilerQueue) {
|
|
168
183
|
this.runBefore();
|
|
169
|
-
|
|
184
|
+
transpilerQueue.nodes.forEach(this._transpileItem.bind(this));
|
|
170
185
|
this.runAfter();
|
|
171
|
-
if (this.opt.useImports === true) {
|
|
172
|
-
this._getImports(transpilerQueue.externalNodes);
|
|
173
|
-
}
|
|
174
186
|
this.output = [...this._getHeader(), ...this.output];
|
|
175
187
|
return this.output.join("\n");
|
|
176
188
|
}
|
|
@@ -1 +1,8 @@
|
|
|
1
|
+
import { ZodDiscriminatedUnion, ZodIntersection, ZodObject, ZodTypeAny, ZodUnion } from "zod";
|
|
1
2
|
export declare function isTranspilerableZodType(zodType: string): boolean;
|
|
3
|
+
export declare function isTranspiledExtendable(zodType: string): boolean;
|
|
4
|
+
export declare function cloneTranspiledExtendable(zodItem: ZodTypeAny): ZodUnion<any> | ZodDiscriminatedUnion<any, any> | ZodIntersection<any, any> | ZodObject<any, any, any, {
|
|
5
|
+
[x: string]: any;
|
|
6
|
+
}, {
|
|
7
|
+
[x: string]: any;
|
|
8
|
+
}>;
|
package/dist/core/zod_helpers.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isTranspilerableZodType = isTranspilerableZodType;
|
|
4
|
+
exports.isTranspiledExtendable = isTranspiledExtendable;
|
|
5
|
+
exports.cloneTranspiledExtendable = cloneTranspiledExtendable;
|
|
4
6
|
const zod_1 = require("zod");
|
|
5
7
|
function isTranspilerableZodType(zodType) {
|
|
6
8
|
return (zodType === zod_1.ZodFirstPartyTypeKind.ZodEnum ||
|
|
@@ -10,3 +12,26 @@ function isTranspilerableZodType(zodType) {
|
|
|
10
12
|
zodType === zod_1.ZodFirstPartyTypeKind.ZodDiscriminatedUnion ||
|
|
11
13
|
zodType === zod_1.ZodFirstPartyTypeKind.ZodIntersection);
|
|
12
14
|
}
|
|
15
|
+
function isTranspiledExtendable(zodType) {
|
|
16
|
+
return (zodType === zod_1.ZodFirstPartyTypeKind.ZodObject ||
|
|
17
|
+
zodType === zod_1.ZodFirstPartyTypeKind.ZodUnion ||
|
|
18
|
+
zodType === zod_1.ZodFirstPartyTypeKind.ZodDiscriminatedUnion ||
|
|
19
|
+
zodType === zod_1.ZodFirstPartyTypeKind.ZodIntersection);
|
|
20
|
+
}
|
|
21
|
+
function cloneTranspiledExtendable(zodItem) {
|
|
22
|
+
if (zodItem instanceof zod_1.ZodObject) {
|
|
23
|
+
return new zod_1.ZodObject(Object.assign({}, zodItem._def));
|
|
24
|
+
}
|
|
25
|
+
else if (zodItem instanceof zod_1.ZodUnion) {
|
|
26
|
+
return new zod_1.ZodUnion(Object.assign({}, zodItem._def));
|
|
27
|
+
}
|
|
28
|
+
else if (zodItem instanceof zod_1.ZodDiscriminatedUnion) {
|
|
29
|
+
return new zod_1.ZodDiscriminatedUnion(Object.assign({}, zodItem._def));
|
|
30
|
+
}
|
|
31
|
+
else if (zodItem instanceof zod_1.ZodIntersection) {
|
|
32
|
+
return new zod_1.ZodIntersection(Object.assign({}, zodItem._def));
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
throw new Error(`This type cannot be extended when transpiled: ${zodItem}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -55,7 +55,7 @@ export declare function Layer(opt: IZod2xLayerMetadata): <T extends {
|
|
|
55
55
|
*
|
|
56
56
|
* @returns The configured Domain layer.
|
|
57
57
|
*/
|
|
58
|
-
export declare function Domain(opt:
|
|
58
|
+
export declare function Domain(opt: Omit<IZod2xLayerMetadata, "index">): <T extends {
|
|
59
59
|
new (...args: any[]): {};
|
|
60
60
|
}>(constructor: T) => {
|
|
61
61
|
new (...args: any[]): {
|
|
@@ -76,7 +76,7 @@ export declare function Domain(opt: Pick<IZod2xLayerMetadata, "file" | "namespac
|
|
|
76
76
|
* @returns The result of invoking the `Layer` function with the provided options and
|
|
77
77
|
* the `APPLICATION` layer index.
|
|
78
78
|
*/
|
|
79
|
-
export declare function Application(opt:
|
|
79
|
+
export declare function Application(opt: Omit<IZod2xLayerMetadata, "index">): <T extends {
|
|
80
80
|
new (...args: any[]): {};
|
|
81
81
|
}>(constructor: T) => {
|
|
82
82
|
new (...args: any[]): {
|
|
@@ -97,7 +97,7 @@ export declare function Application(opt: Pick<IZod2xLayerMetadata, "file" | "nam
|
|
|
97
97
|
*
|
|
98
98
|
* @returns A configured Infrastructure layer.
|
|
99
99
|
*/
|
|
100
|
-
export declare function Infrastructure(opt:
|
|
100
|
+
export declare function Infrastructure(opt: Omit<IZod2xLayerMetadata, "index">): <T extends {
|
|
101
101
|
new (...args: any[]): {};
|
|
102
102
|
}>(constructor: T) => {
|
|
103
103
|
new (...args: any[]): {
|
|
@@ -115,7 +115,7 @@ export declare function Infrastructure(opt: Pick<IZod2xLayerMetadata, "file" | "
|
|
|
115
115
|
* - `name`: The name of the layer.
|
|
116
116
|
* @returns The configured Presentation layer.
|
|
117
117
|
*/
|
|
118
|
-
export declare function Presentation(opt:
|
|
118
|
+
export declare function Presentation(opt: Omit<IZod2xLayerMetadata, "index">): <T extends {
|
|
119
119
|
new (...args: any[]): {};
|
|
120
120
|
}>(constructor: T) => {
|
|
121
121
|
new (...args: any[]): {
|
|
@@ -81,17 +81,35 @@ function Layer(opt) {
|
|
|
81
81
|
zodItem["_zod2x"] = metadata;
|
|
82
82
|
}
|
|
83
83
|
else if (!metadata.typeName) {
|
|
84
|
+
// Only possible if `zod2xExtendable` is used.
|
|
84
85
|
metadata.typeName = name;
|
|
85
86
|
}
|
|
86
87
|
if (metadata.layer === undefined) {
|
|
88
|
+
// Metadata is set independently because typeName could already exist if
|
|
89
|
+
// zod2x was used before.
|
|
87
90
|
metadata.layer = opt;
|
|
88
91
|
}
|
|
92
|
+
if (opt.externalInheritance !== false &&
|
|
93
|
+
(0, zod_helpers_1.isTranspiledExtendable)(zodItem._def.typeName)) {
|
|
94
|
+
if (metadata.layer.file !== opt.file) {
|
|
95
|
+
// Type used from another layer. A new type is created inheriting the
|
|
96
|
+
// original type.
|
|
97
|
+
zodItem = (0, zod_helpers_1.cloneTranspiledExtendable)(zodItem);
|
|
98
|
+
zodItem._zod2x = {
|
|
99
|
+
parentLayer: metadata.layer,
|
|
100
|
+
parentTypeName: metadata.typeName,
|
|
101
|
+
layer: opt,
|
|
102
|
+
typeName: name,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return zodItem;
|
|
89
107
|
};
|
|
90
108
|
Object.getOwnPropertyNames(this).forEach((prop) => {
|
|
91
109
|
var _b, _c;
|
|
92
110
|
const zodType = (_c = (_b = this[prop]) === null || _b === void 0 ? void 0 : _b._def) === null || _c === void 0 ? void 0 : _c.typeName;
|
|
93
111
|
if ((0, zod_helpers_1.isTranspilerableZodType)(zodType)) {
|
|
94
|
-
setMetadata(case_1.default.pascal(prop), this[prop], opt);
|
|
112
|
+
this[prop] = setMetadata(case_1.default.pascal(prop), this[prop], opt);
|
|
95
113
|
}
|
|
96
114
|
});
|
|
97
115
|
}
|
package/dist/lib/zod_ext.d.ts
CHANGED
|
@@ -25,6 +25,35 @@ export interface IZod2xLayerMetadata {
|
|
|
25
25
|
* from layer 3.
|
|
26
26
|
*/
|
|
27
27
|
index: number;
|
|
28
|
+
/**
|
|
29
|
+
* Indicates if types inherited from other layers should be transpiled as extendable types and
|
|
30
|
+
* then used (true) or just used as imports (false).
|
|
31
|
+
*
|
|
32
|
+
* For example:
|
|
33
|
+
* // Definition
|
|
34
|
+
* class MyModels extends Zod2XModel {
|
|
35
|
+
* myType: ExternalNamespace.OtherType
|
|
36
|
+
* }
|
|
37
|
+
*
|
|
38
|
+
* Case true:
|
|
39
|
+
* // Output example for typescript:
|
|
40
|
+
* import * as ExternalNamespace from "external_file";
|
|
41
|
+
*
|
|
42
|
+
* interface MyType extends ExternalNamespace.OtherType {}
|
|
43
|
+
*
|
|
44
|
+
* interface MyModels {
|
|
45
|
+
* myType: MyType;
|
|
46
|
+
* }
|
|
47
|
+
*
|
|
48
|
+
* Case false:
|
|
49
|
+
* // Output example for typescript:
|
|
50
|
+
* import * as ExternalNamespace from "external_file";
|
|
51
|
+
*
|
|
52
|
+
* interface MyModels {
|
|
53
|
+
* myType: ExternalNamespace.OtherType;
|
|
54
|
+
* }
|
|
55
|
+
*/
|
|
56
|
+
externalInheritance?: boolean;
|
|
28
57
|
}
|
|
29
58
|
export interface IZod2xMetadata {
|
|
30
59
|
/**
|
|
@@ -36,7 +65,19 @@ export interface IZod2xMetadata {
|
|
|
36
65
|
* ZodDiscriminatedUnion schemas.
|
|
37
66
|
*/
|
|
38
67
|
parentEnum?: ZodEnum<any> | ZodNativeEnum<any>;
|
|
68
|
+
/**
|
|
69
|
+
* For Layered Modeling.
|
|
70
|
+
* The file where the schema is transpiled. Used to allow importing types from other files.
|
|
71
|
+
*/
|
|
39
72
|
layer?: IZod2xLayerMetadata;
|
|
73
|
+
/**
|
|
74
|
+
* For Layered Modeling.
|
|
75
|
+
* When a type of another file is used without modifying it, by default it is sustituted by
|
|
76
|
+
* the import without creating a new type. If wanted. it can be forced to create a new type
|
|
77
|
+
* which will be the extension of the original type if `zod2xExtendable` is used.
|
|
78
|
+
*/
|
|
79
|
+
parentTypeName?: string;
|
|
80
|
+
parentLayer?: IZod2xLayerMetadata;
|
|
40
81
|
}
|
|
41
82
|
declare module "zod" {
|
|
42
83
|
interface ZodType {
|
|
@@ -23,6 +23,7 @@ export declare class Zod2Cpp extends Zod2X<IZod2CppOpt> {
|
|
|
23
23
|
protected runBefore(): void;
|
|
24
24
|
protected addImportFromFile(filename: string, _: string): string;
|
|
25
25
|
protected getTypeFromExternalNamespace(namespace: string, typeName: string): string;
|
|
26
|
+
protected addExtendedType(name: string, parentNamespace: string, parentTypeName: string, isUnionOrDiscriminatedUnion?: boolean): void;
|
|
26
27
|
protected runAfter(): void;
|
|
27
28
|
protected getComment: (data: string, indent?: string) => string;
|
|
28
29
|
protected getDateType: () => string;
|
|
@@ -82,7 +82,6 @@ class Zod2Cpp extends core_1.Zod2X {
|
|
|
82
82
|
this._push2 = (item, data) => item.push(`${this.indent[2]}${data}`);
|
|
83
83
|
this._push3 = (item, data) => item.push(`${this.indent[3]}${data}`);
|
|
84
84
|
this._push4 = (item, data) => item.push(`${this.indent[4]}${data}`);
|
|
85
|
-
this.imports.add("#pragma once\n");
|
|
86
85
|
this.serializers = [];
|
|
87
86
|
this.useBoost = true;
|
|
88
87
|
this.lib = (0, libs_1.getLibs)(this.useBoost);
|
|
@@ -95,7 +94,23 @@ class Zod2Cpp extends core_1.Zod2X {
|
|
|
95
94
|
getTypeFromExternalNamespace(namespace, typeName) {
|
|
96
95
|
return `${namespace}::${typeName}`;
|
|
97
96
|
}
|
|
97
|
+
addExtendedType(name, parentNamespace, parentTypeName, isUnionOrDiscriminatedUnion) {
|
|
98
|
+
const extendedType = this.getTypeFromExternalNamespace(parentNamespace, parentTypeName);
|
|
99
|
+
if (isUnionOrDiscriminatedUnion) {
|
|
100
|
+
this.push0(`using ${name} = ${extendedType};\n`);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
if (this.opt.outType === "class") {
|
|
104
|
+
this.push0(`class ${name} : public ${extendedType} {};\n`);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
this.push0(`struct ${name} : public ${extendedType} {};\n`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
98
111
|
runAfter() {
|
|
112
|
+
this.preImports.add("#pragma once");
|
|
113
|
+
// Add the output inside the namespace
|
|
99
114
|
this.output = this.output.map((i) => `${this.indent[1]}${i}`);
|
|
100
115
|
this.output.unshift(`namespace ${this.opt.namespace} {`);
|
|
101
116
|
this.output.push("}");
|
|
@@ -111,7 +126,7 @@ class Zod2Cpp extends core_1.Zod2X {
|
|
|
111
126
|
this.output.push("}");
|
|
112
127
|
}
|
|
113
128
|
if (this.imports.has(this.lib.nlohmann)) {
|
|
114
|
-
this.
|
|
129
|
+
this.postImports.add(`${libs_1.USING.nlohmann}`);
|
|
115
130
|
}
|
|
116
131
|
}
|
|
117
132
|
/** Ex: std::vector<std::vector<TypeA>> */
|
|
@@ -151,6 +166,9 @@ class Zod2Cpp extends core_1.Zod2X {
|
|
|
151
166
|
* }
|
|
152
167
|
*/
|
|
153
168
|
transpileEnum(data) {
|
|
169
|
+
if (this.addExternalTypeImport(data)) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
154
172
|
this.addComment(data.description);
|
|
155
173
|
const serializeData = [];
|
|
156
174
|
this.push0(`enum class ${data.name}: int {`);
|
|
@@ -178,6 +196,12 @@ class Zod2Cpp extends core_1.Zod2X {
|
|
|
178
196
|
* }
|
|
179
197
|
*/
|
|
180
198
|
transpileIntersection(data) {
|
|
199
|
+
if (this.addExternalTypeImport(data)) {
|
|
200
|
+
if (data.parentTypeName) {
|
|
201
|
+
this.addExtendedType(data.name, data.parentNamespace, data.parentTypeName);
|
|
202
|
+
}
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
181
205
|
console.warn(`${data.name}: use zod's merge instead of intersection whenever possible.`);
|
|
182
206
|
console.warn(`${data.name}: no field name conflicts is assumed.`);
|
|
183
207
|
this.addComment(data.description);
|
|
@@ -208,6 +232,12 @@ class Zod2Cpp extends core_1.Zod2X {
|
|
|
208
232
|
}
|
|
209
233
|
/** Ex: using TypeC = boost::variant<TypeA, TypeB> */
|
|
210
234
|
transpileUnion(data) {
|
|
235
|
+
if (this.addExternalTypeImport(data)) {
|
|
236
|
+
if (data.parentTypeName) {
|
|
237
|
+
this.addExtendedType(data.name, data.parentNamespace, data.parentTypeName, true);
|
|
238
|
+
}
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
211
241
|
this.addComment(data.description);
|
|
212
242
|
const attributesData = data.options.map((i) => {
|
|
213
243
|
return {
|
|
@@ -221,6 +251,12 @@ class Zod2Cpp extends core_1.Zod2X {
|
|
|
221
251
|
this._createUnionDeserializer(data.name, attributesData, data.discriminantKey);
|
|
222
252
|
}
|
|
223
253
|
transpileStruct(data) {
|
|
254
|
+
if (this.addExternalTypeImport(data)) {
|
|
255
|
+
if (data.parentTypeName) {
|
|
256
|
+
this.addExtendedType(data.name, data.parentNamespace, data.parentTypeName);
|
|
257
|
+
}
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
224
260
|
this.addComment(data.description);
|
|
225
261
|
if (this.opt.outType === "class") {
|
|
226
262
|
this._transpileStructAsClass(data);
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { ASTCommon, ASTDiscriminatedUnion, ASTEnum, ASTIntersection, ASTNativeEnum, ASTObject, ASTUnion, Zod2X } from "../../core";
|
|
2
2
|
import { IZod2ProtoV3Opt } from "./options";
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated Zod2ProtoV3 will not be considered as a transpilerable programming language, but as
|
|
5
|
+
* another utility such as `zod2JsonSchemaDefinitions`.
|
|
6
|
+
*/
|
|
3
7
|
export declare class Zod2ProtoV3 extends Zod2X<IZod2ProtoV3Opt> {
|
|
4
8
|
constructor(opt?: IZod2ProtoV3Opt);
|
|
5
9
|
protected getUnionType: () => string;
|
|
6
10
|
protected addImportFromFile(filename: string, namespace: string): string;
|
|
7
11
|
protected getTypeFromExternalNamespace(namespace: string, typeName: string): string;
|
|
12
|
+
protected addExtendedType(name: string, parentNamespace: string, parentTypeName: string): void;
|
|
8
13
|
protected getComment: (data: string, indent?: string) => string;
|
|
9
14
|
protected getBooleanType: () => string;
|
|
10
15
|
protected getStringType: () => string;
|
|
@@ -22,6 +22,10 @@ const allowedKeyTypes = [
|
|
|
22
22
|
"bool",
|
|
23
23
|
"string",
|
|
24
24
|
];
|
|
25
|
+
/**
|
|
26
|
+
* @deprecated Zod2ProtoV3 will not be considered as a transpilerable programming language, but as
|
|
27
|
+
* another utility such as `zod2JsonSchemaDefinitions`.
|
|
28
|
+
*/
|
|
25
29
|
class Zod2ProtoV3 extends core_1.Zod2X {
|
|
26
30
|
constructor(opt = {}) {
|
|
27
31
|
super(Object.assign(Object.assign({}, options_1.defaultOpts), opt));
|
|
@@ -100,6 +104,10 @@ class Zod2ProtoV3 extends core_1.Zod2X {
|
|
|
100
104
|
// Zod2ProtoV3 does not support layered modeling.
|
|
101
105
|
return "";
|
|
102
106
|
}
|
|
107
|
+
addExtendedType(name, parentNamespace, parentTypeName) {
|
|
108
|
+
// Zod2ProtoV3 does not support layered modeling.
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
103
111
|
getArrayType(arrayType, arrayDeep) {
|
|
104
112
|
if (arrayDeep === 1) {
|
|
105
113
|
return `repeated ${arrayType}`;
|
|
@@ -130,6 +138,10 @@ class Zod2ProtoV3 extends core_1.Zod2X {
|
|
|
130
138
|
return this.getMapType(keyType, valueType);
|
|
131
139
|
}
|
|
132
140
|
transpileEnum(data) {
|
|
141
|
+
if (data.isFromDiscriminatedUnion === true) {
|
|
142
|
+
// Injected enum from ZodDiscriminatedUnion are not transpiled.
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
133
145
|
this.addComment(data.description);
|
|
134
146
|
this.push0(`enum ${data.name} {`);
|
|
135
147
|
data.values.forEach(([key, value], index) => {
|
|
@@ -195,9 +207,9 @@ class Zod2ProtoV3 extends core_1.Zod2X {
|
|
|
195
207
|
}
|
|
196
208
|
runBefore() {
|
|
197
209
|
var _a, _b;
|
|
198
|
-
this.
|
|
210
|
+
this.preImports.add(`syntax = "proto3";`);
|
|
199
211
|
if ((_a = this.opt) === null || _a === void 0 ? void 0 : _a.packageName) {
|
|
200
|
-
this.
|
|
212
|
+
this.preImports.add(`package ${(_b = this.opt) === null || _b === void 0 ? void 0 : _b.packageName};`);
|
|
201
213
|
}
|
|
202
214
|
}
|
|
203
215
|
runAfter() { }
|
|
@@ -6,6 +6,10 @@ export declare class Zod2Ts extends Zod2X<IZod2TsOpt> {
|
|
|
6
6
|
protected runBefore(): void;
|
|
7
7
|
protected addImportFromFile(filename: string, namespace: string): string;
|
|
8
8
|
protected getTypeFromExternalNamespace(namespace: string, typeName: string): string;
|
|
9
|
+
protected addExtendedType(name: string, parentNamespace: string, parentTypeName: string, opt?: {
|
|
10
|
+
isUnion?: boolean;
|
|
11
|
+
isDiscriminatedUnion?: boolean;
|
|
12
|
+
}): void;
|
|
9
13
|
protected getComment: (data: string, indent?: string) => string;
|
|
10
14
|
protected getAnyType: () => string;
|
|
11
15
|
protected getBooleanType: () => string;
|
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.Zod2Ts = void 0;
|
|
7
|
+
const zod_1 = require("zod");
|
|
7
8
|
const case_1 = __importDefault(require("case"));
|
|
8
9
|
const core_1 = require("../../core");
|
|
9
10
|
const options_1 = require("./options");
|
|
@@ -36,6 +37,28 @@ class Zod2Ts extends core_1.Zod2X {
|
|
|
36
37
|
getTypeFromExternalNamespace(namespace, typeName) {
|
|
37
38
|
return `${namespace}.${typeName}`;
|
|
38
39
|
}
|
|
40
|
+
addExtendedType(name, parentNamespace, parentTypeName, opt) {
|
|
41
|
+
const extendedType = this.getTypeFromExternalNamespace(parentNamespace, parentTypeName);
|
|
42
|
+
if (this.opt.outType === "class") {
|
|
43
|
+
if (opt === null || opt === void 0 ? void 0 : opt.isDiscriminatedUnion) {
|
|
44
|
+
this.push0(`export type ${name} = ${extendedType};\n`);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
this.push0(`export class ${name} extends ${extendedType} {}\n`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
if (opt === null || opt === void 0 ? void 0 : opt.isUnion) {
|
|
52
|
+
this.push0(`export type ${name} = ${extendedType};\n`);
|
|
53
|
+
}
|
|
54
|
+
else if (opt === null || opt === void 0 ? void 0 : opt.isDiscriminatedUnion) {
|
|
55
|
+
this.push0(`export type ${name} = ${extendedType};\n`);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
this.push0(`export interface ${name} extends ${extendedType} {}\n`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
39
62
|
/** Ex: Array<Array<TypeA[]>> */
|
|
40
63
|
getArrayType(arrayType, arrayDeep) {
|
|
41
64
|
let output = arrayType.includes("|") || arrayType.includes("&")
|
|
@@ -68,6 +91,9 @@ class Zod2Ts extends core_1.Zod2X {
|
|
|
68
91
|
* }
|
|
69
92
|
*/
|
|
70
93
|
transpileEnum(data) {
|
|
94
|
+
if (this.addExternalTypeImport(data)) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
71
97
|
this.addComment(data.description);
|
|
72
98
|
this.push0(`export enum ${data.name} {`);
|
|
73
99
|
data.values.forEach((i) => {
|
|
@@ -97,6 +123,12 @@ class Zod2Ts extends core_1.Zod2X {
|
|
|
97
123
|
* */
|
|
98
124
|
transpileIntersection(data) {
|
|
99
125
|
var _a;
|
|
126
|
+
if (this.addExternalTypeImport(data)) {
|
|
127
|
+
if (data.parentTypeName) {
|
|
128
|
+
this.addExtendedType(data.name, data.parentNamespace, data.parentTypeName);
|
|
129
|
+
}
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
100
132
|
if (this.opt.outType === "class" && data.newObject) {
|
|
101
133
|
this.addComment((_a = data.newObject) === null || _a === void 0 ? void 0 : _a.description);
|
|
102
134
|
this._transpileStructAsClass(data.newObject);
|
|
@@ -108,6 +140,12 @@ class Zod2Ts extends core_1.Zod2X {
|
|
|
108
140
|
}
|
|
109
141
|
}
|
|
110
142
|
transpileStruct(data) {
|
|
143
|
+
if (this.addExternalTypeImport(data)) {
|
|
144
|
+
if (data.parentTypeName) {
|
|
145
|
+
this.addExtendedType(data.name, data.parentNamespace, data.parentTypeName);
|
|
146
|
+
}
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
111
149
|
this.addComment(data.description);
|
|
112
150
|
if (this.opt.outType === "class") {
|
|
113
151
|
this._transpileStructAsClass(data);
|
|
@@ -133,6 +171,15 @@ class Zod2Ts extends core_1.Zod2X {
|
|
|
133
171
|
* */
|
|
134
172
|
transpileUnion(data) {
|
|
135
173
|
var _a;
|
|
174
|
+
if (this.addExternalTypeImport(data)) {
|
|
175
|
+
if (data.parentTypeName) {
|
|
176
|
+
this.addExtendedType(data.name, data.parentNamespace, data.parentTypeName, {
|
|
177
|
+
isUnion: data.type === zod_1.ZodFirstPartyTypeKind.ZodUnion,
|
|
178
|
+
isDiscriminatedUnion: data.type === zod_1.ZodFirstPartyTypeKind.ZodDiscriminatedUnion,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
136
183
|
if (this.opt.outType === "class" && data.newObject) {
|
|
137
184
|
this.addComment((_a = data.newObject) === null || _a === void 0 ? void 0 : _a.description);
|
|
138
185
|
this._transpileStructAsClass(data.newObject);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zod-to-x",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "Multi language types generation from Zod schemas.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
],
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc && tsc-alias",
|
|
11
|
+
"build:debug": "tsc --project tsconfig.dev.json && tsc-alias",
|
|
11
12
|
"format:check": "prettier --check .",
|
|
12
13
|
"test": "jest",
|
|
13
14
|
"test:cpp": "bash ./test/test_zod2cpp/test_cpp.sh",
|