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 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, Zod2Ts } from "zod-to-x";
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, two new components are included:
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(Transpilers.Zod2Ts))
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(Transpilers.Zod2Ts))
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:
@@ -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;
@@ -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, layerMetadata) {
31
- if (this.opt.layer && layerMetadata) {
32
- if (this.opt.layer.index < layerMetadata.index) {
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 ${layerMetadata.index}`);
34
+ `from the same or lower layer. Found layer with number ${layer.index}`);
35
35
  }
36
- if (this.opt.layer.file !== layerMetadata.file) {
37
- return { parentFile: layerMetadata.file, parentNamespace: layerMetadata.namespace };
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, _b;
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, typeName: schema._def.typeName }, this._getTranspilerableFile(name, (_b = schema._zod2x) === null || _b === void 0 ? void 0 : _b.layer));
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, typeName, parentFile, parentNamespace } = this._getNames(schema, "ZodEnum/ZodNativeEnum type must have a typeName. Use zod2x method to provide one.");
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: typeName,
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
- const node = this._getNode(parentFile);
168
- if (opt === null || opt === void 0 ? void 0 : opt.isInjectedEnum) {
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, typeName, undefined, parentNamespace);
173
+ return this._createDefinition(name, zodTypeName, undefined, parentNamespace);
182
174
  }
183
175
  _getObjectAst(schema, opt) {
184
- const { name, typeName, parentFile, parentNamespace } = this._getNames(schema, "ZodObject type must have a typeName. Use zod2x method to provide one.");
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
- const node = this._getNode(parentFile);
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
- node.set(name, {
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 = node.get(name);
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, typeName, discriminantValue, parentNamespace);
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, typeName, parentFile, parentNamespace } = this._getNames(schema, "ZodUnion/ZodDiscriminatedUnion type must have a typeName. " +
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: typeName,
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 && !node.has(name)) {
250
- node.set(name, item);
241
+ if (name && !this.nodes.has(name)) {
242
+ this.nodes.set(name, item);
251
243
  }
252
- return this._createDefinition(name, typeName, undefined, parentNamespace);
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, typeName, parentFile, parentNamespace } = this._getNames(schema, "ZodIntersection type must have a typeName. Use zod2x method to provide one.");
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 && !node.has(name)) {
283
- node.set(name, item);
274
+ if (name && !this.nodes.has(name)) {
275
+ this.nodes.set(name, item);
284
276
  }
285
- return this._createDefinition(name, typeName, undefined, parentNamespace);
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
  }
@@ -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
- private _getTranspilerableNodes;
192
- private _getImports;
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.
@@ -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
- _getTranspilerableNodes(transpilerQueue) {
131
- return new Map([
132
- ...(this.opt.useImports === false ? transpilerQueue.externalNodes : []),
133
- ...(this.opt.skipDiscriminatorNodes !== true ? transpilerQueue.discriminatorNodes : []),
134
- ...transpilerQueue.nodes,
135
- ]);
136
- }
137
- _getImports(externalNodes) {
138
- const importData = new Map();
139
- externalNodes.forEach((i) => {
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
- if (!((_a = header.at(-1)) === null || _a === void 0 ? void 0 : _a.endsWith("\n"))) {
157
- header.push("");
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
- this._getTranspilerableNodes(transpilerQueue).forEach(this._transpileItem.bind(this));
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
+ }>;
@@ -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: Pick<IZod2xLayerMetadata, "file" | "namespace">): <T extends {
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: Pick<IZod2xLayerMetadata, "file" | "namespace">): <T extends {
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: Pick<IZod2xLayerMetadata, "file" | "namespace">): <T extends {
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: Pick<IZod2xLayerMetadata, "file" | "namespace">): <T extends {
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
  }
@@ -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 {
@@ -4,7 +4,6 @@ exports.defaultOpts = void 0;
4
4
  exports.defaultOpts = {
5
5
  includeComments: true,
6
6
  indent: 4,
7
- skipDiscriminatorNodes: false,
8
7
  useImports: true,
9
8
  namespace: "zodtocpp",
10
9
  outType: "struct",
@@ -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.imports.add(`\n${libs_1.USING.nlohmann}`);
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);
@@ -5,6 +5,5 @@ exports.defaultOpts = {
5
5
  includeComments: true,
6
6
  indent: 4,
7
7
  useCamelCase: false,
8
- skipDiscriminatorNodes: true, // Not required for protobuf files
9
8
  useImports: false, // Not required for protobuf files
10
9
  };
@@ -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.imports.add(`syntax = "proto3";\n`);
210
+ this.preImports.add(`syntax = "proto3";`);
199
211
  if ((_a = this.opt) === null || _a === void 0 ? void 0 : _a.packageName) {
200
- this.imports.add(`package ${(_b = this.opt) === null || _b === void 0 ? void 0 : _b.packageName};\n`);
212
+ this.preImports.add(`package ${(_b = this.opt) === null || _b === void 0 ? void 0 : _b.packageName};`);
201
213
  }
202
214
  }
203
215
  runAfter() { }
@@ -4,7 +4,6 @@ exports.defaultOpts = void 0;
4
4
  exports.defaultOpts = {
5
5
  includeComments: true,
6
6
  indent: 4,
7
- skipDiscriminatorNodes: false,
8
7
  useImports: true,
9
8
  outType: "interface",
10
9
  };
@@ -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.1",
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",