zod-to-x 1.4.0 → 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 +133 -15
- 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/index.d.ts +1 -0
- package/dist/layered-modeling/index.js +1 -0
- package/dist/layered-modeling/layer.d.ts +4 -4
- package/dist/layered-modeling/layer.js +19 -1
- package/dist/layered-modeling/model.d.ts +3 -3
- package/dist/layered-modeling/model.js +2 -2
- package/dist/layered-modeling/model_mixin.d.ts +30 -0
- package/dist/layered-modeling/model_mixin.js +60 -0
- 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
|
@@ -3,15 +3,14 @@
|
|
|
3
3
|
<em style="font-size: smaller;">Image generated using Canvas AI.</em>
|
|
4
4
|
</p>
|
|
5
5
|
<p align="center">
|
|
6
|
-
<a href="https://github.com/rroumenov/zod-to-x/releases" target="_blank"
|
|
7
|
-
<
|
|
8
|
-
View Changelog
|
|
9
|
-
</button>
|
|
6
|
+
<a href="https://github.com/rroumenov/zod-to-x/releases" target="_blank">
|
|
7
|
+
<img src="https://img.shields.io/badge/View%20Changelog-brightgreen?style=for-the-badge" alt="View Changelog">
|
|
10
8
|
</a>
|
|
11
|
-
<a href="https://playcode.io/2277071" target="_blank" style="
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
<a href="https://playcode.io/2277071" target="_blank" style="margin-left: 10px;">
|
|
10
|
+
<img src="https://img.shields.io/badge/Try%20it%20on%20Playcode-blue?style=for-the-badge" alt="Try it on Playcode">
|
|
11
|
+
</a>
|
|
12
|
+
<a href="https://github.com/rroumenov/zod-to-x/issues" target="_blank" style="margin-left: 10px;">
|
|
13
|
+
<img src="https://img.shields.io/badge/Need%20Help%3F-orange?style=for-the-badge" alt="Need Help?">
|
|
15
14
|
</a>
|
|
16
15
|
</p>
|
|
17
16
|
|
|
@@ -72,7 +71,7 @@ This extension appends a `zod2x` method to:
|
|
|
72
71
|
## Quick start
|
|
73
72
|
```ts
|
|
74
73
|
import { z } from "zod";
|
|
75
|
-
import { extendZod, Zod2Ast,
|
|
74
|
+
import { extendZod, Zod2Ast, Zod2XTranspilers } from "zod-to-x";
|
|
76
75
|
extendZod(z); // The extend step can be skipped if it has already been done.
|
|
77
76
|
|
|
78
77
|
/**
|
|
@@ -95,7 +94,7 @@ const visitorNodes = new Zod2Ast().build(VisitorSchema);
|
|
|
95
94
|
* 3) Generate types in the desired language.
|
|
96
95
|
* Depending on the transpiled language, data models can be generated using classes.
|
|
97
96
|
*/
|
|
98
|
-
const tsVisitorAsInterface: string = new Zod2Ts().transpile(visitorNodes);
|
|
97
|
+
const tsVisitorAsInterface: string = new Zod2XTranspilers.Zod2Ts().transpile(visitorNodes);
|
|
99
98
|
console.log(tsVisitorAsInterface)
|
|
100
99
|
// output:
|
|
101
100
|
// export interface Visitor {
|
|
@@ -106,7 +105,7 @@ console.log(tsVisitorAsInterface)
|
|
|
106
105
|
// comments?: string;
|
|
107
106
|
// }
|
|
108
107
|
|
|
109
|
-
const tsVisitorAsClass: string = new Zod2Ts({outType: "class"}).transpile(visitorNodes);
|
|
108
|
+
const tsVisitorAsClass: string = new Zod2XTranspilers.Zod2Ts({outType: "class"}).transpile(visitorNodes);
|
|
110
109
|
console.log(tsVisitorAsClass)
|
|
111
110
|
// output:
|
|
112
111
|
// export class Visitor {
|
|
@@ -256,9 +255,13 @@ inline void from_json(const json& j, Message& x) {
|
|
|
256
255
|
## Layered modeling
|
|
257
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.
|
|
258
257
|
|
|
259
|
-
To achieve this,
|
|
258
|
+
To achieve this, new components are included:
|
|
260
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.
|
|
261
|
-
- **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`.
|
|
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
|
|
264
267
|
1. Define a Domain model, such as a User entity:
|
|
@@ -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
|
|
|
@@ -347,13 +350,128 @@ console.log(userDtos.transpile(Transpilers.Zod2Ts))
|
|
|
347
350
|
```
|
|
348
351
|
**(*)** Any modification of an existing model (in this case, `userEntity`) will lose the relation with that model, but not its children. In the case of the `CreateUserUseCaseDto` type, the `role` field will remain linked to the existing one in the `user.entity` file.
|
|
349
352
|
|
|
353
|
+
3 - Are your models too large? Simplify them!
|
|
354
|
+
If you are dealing with complex models whose definitions are too extensive, split them into multiple classes and then combine them using `Zod2XMixin` as shown below:
|
|
355
|
+
```ts
|
|
356
|
+
// Sub-models do not require a layer decorator; it is applied automatically when inherited by the main model.
|
|
357
|
+
|
|
358
|
+
// Sub-model 1
|
|
359
|
+
class CreateUserUseCaseDto {
|
|
360
|
+
createUserUseCaseDto = userModels.userEntity.omit({ id: true });
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Sub-model 2
|
|
364
|
+
class CreateUserUseCaseResultDto {
|
|
365
|
+
createUserUseCaseResultDto = userModels.userEntity
|
|
366
|
+
.omit({ role: true })
|
|
367
|
+
.extend({
|
|
368
|
+
createdAt: z.date(),
|
|
369
|
+
updatedAt: z.date(),
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Main model
|
|
374
|
+
@Application({ namespace: "USER_DTOS", file: "user.dtos" })
|
|
375
|
+
class UserDtos extends Zod2XMixin(
|
|
376
|
+
[CreateUserUseCaseDto, CreateUserUseCaseResultDto], // Inherit the desired sub-models.
|
|
377
|
+
Zod2XModel // Zod2XModel must still be the base class.
|
|
378
|
+
) {}
|
|
379
|
+
|
|
380
|
+
export const userDtos = new UserDtos();
|
|
381
|
+
console.log(userDtos.transpile(Zod2XTranspilers.Zod2Ts))
|
|
382
|
+
// Output (same as above):
|
|
383
|
+
// import * as USER from "./user.entity"; <--- Reusing models from other layers.
|
|
384
|
+
|
|
385
|
+
// export interface CreateUserUseCaseDto {
|
|
386
|
+
// name: string;
|
|
387
|
+
// email: string;
|
|
388
|
+
// age?: number;
|
|
389
|
+
// role: USER.UserRole;
|
|
390
|
+
// }
|
|
391
|
+
|
|
392
|
+
// export interface CreateUserUseCaseResultDto {
|
|
393
|
+
// id: string;
|
|
394
|
+
// name: string;
|
|
395
|
+
// email: string;
|
|
396
|
+
// age?: number;
|
|
397
|
+
// createdAt: Date;
|
|
398
|
+
// updatedAt: Date;
|
|
399
|
+
// }
|
|
400
|
+
|
|
401
|
+
// export interface UserDtos {
|
|
402
|
+
// createUserUseCaseDto: CreateUserUseCaseDto;
|
|
403
|
+
// createUserUseCaseResultDto: CreateUserUseCaseResultDto;
|
|
404
|
+
// }
|
|
405
|
+
```
|
|
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
|
+
```
|
|
468
|
+
|
|
350
469
|
|
|
351
470
|
## Supported output languages
|
|
352
471
|
Common options:
|
|
353
472
|
- **header**: Text to add as a comment at the beginning of the output.
|
|
354
473
|
- **indent**: Number of spaces to use for indentation in the generated code. Defaults to 4 if not specified.
|
|
355
474
|
- **includeComments**: Determines whether to include comments in the transpiled code. Defaults to `true`.
|
|
356
|
-
- **skipDiscriminatorNodes**: prevents the inclusion of `ZodEnum` or `ZodNativeEnum` schemas that are used solely as discriminator keys in a `ZodDiscriminatedUnion`. Defaults to `false`.
|
|
357
475
|
|
|
358
476
|
### 0) ASTNode
|
|
359
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.
|