zod-to-x 2.2.1-dev.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,29 +28,37 @@
28
28
  <img src="https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white" alt="TypeScript">
29
29
  <img src="https://img.shields.io/badge/Python-3776AB?style=for-the-badge&logo=python&logoColor=white" alt="Python">
30
30
  <img src="https://img.shields.io/badge/C++-00599C?style=for-the-badge&logo=cplusplus&logoColor=white" alt="C++">
31
+ <img src="https://img.shields.io/badge/Go-00ADD8?style=for-the-badge&logo=go&logoColor=white" alt="Go">
32
+ <img src="https://img.shields.io/badge/Dart-0175C2?style=for-the-badge&logo=dart&logoColor=white" alt="Dart">
31
33
  <img src="https://img.shields.io/badge/Protobuf-4285F4?style=for-the-badge&logo=google&logoColor=white" alt="Protobuf">
32
34
  </p>
33
35
 
34
36
 
35
37
 
36
38
  ## Table of contents
37
- - [Why use `@zod-to-x`](#why-use-zod-to-x)
39
+ - [Table of contents](#table-of-contents)
40
+ - [Why Use `@zod-to-x`?](#why-use-zod-to-x)
38
41
  - [Installation](#installation)
42
+ - [1) Install `@zod-to-x` and `@zod(*)` dependency.](#1-install-zod-to-x-and-zod-dependency)
43
+ - [2) Extend Zod using the `extendZod` method after the first `@zod` import:](#2-extend-zod-using-the-extendzod-method-after-the-first-zod-import)
39
44
  - [Quick start](#quick-start)
40
45
  - [Intersections and Unions](#intersections-and-unions)
41
46
  - [Expected outputs](#expected-outputs)
42
47
  - [Tips for discriminated unions](#tips-for-discriminated-unions)
43
48
  - [Layered modeling](#layered-modeling)
44
49
  - [Usage example](#usage-example)
45
- - [Custom layers](#custom-layers)
50
+ - [Custom Layers](#custom-layers)
46
51
  - [Generic types](#generic-types)
47
52
  - [Currently supported output languages](#currently-supported-output-languages)
48
- - [Typescript](#1-typescript)
49
- - [Python](#2-python) <sup>*(new)*</sup>
50
- - [C++](#3-c)
53
+ - [0) ASTNode](#0-astnode)
54
+ - [1) Typescript](#1-typescript)
55
+ - [2) Python](#2-python)
56
+ - [3) C++](#3-c)
57
+ - [4) Go](#4-go)
58
+ - [5) Dart](#5-dart)
51
59
  - [Additional utils](#additional-utils)
52
- - [Protobuf V3 generation](#2-zod2protov3)
53
- - [Mapping of supported Zod Types by Language](#mapping-of-supported-zod-types-by-langauge)
60
+ - [1) `zod2ProtoV3`](#1-zod2protov3)
61
+ - [Mapping of supported Zod Types by Langauge](#mapping-of-supported-zod-types-by-langauge)
54
62
  - [Considerations](#considerations)
55
63
 
56
64
 
@@ -62,7 +70,7 @@ Managing data consistency across multiple layers and languages is a common chall
62
70
  Define your data structures in one place using the powerful [`@zod`](https://github.com/colinhacks/zod) library. This eliminates redundancy, reduces inconsistencies, and simplifies maintenance across your entire codebase, all while allowing you to continue leveraging any npm package in the [`@zod`](https://github.com/colinhacks/zod) ecosystem.
63
71
 
64
72
  2. **Multi-Language Compatibility**
65
- Generate data models for TypeScript, Python (Pydantic), C++, and Protobuf V3 (with languages like Golang on the roadmap). No more manually rewriting models for different platforms.
73
+ Generate data models for TypeScript, Python (Pydantic), C++, Go, and Protobuf V3. No more manually rewriting models for different platforms.
66
74
 
67
75
  3. **Enhanced Productivity**
68
76
  Automate the transpilation of data models to save time, reduce errors, and let your team focus on business logic instead of boilerplate code.
@@ -628,6 +636,22 @@ Common options:
628
636
  - **keepKeys**: Specifies whether property names should follow the C++ naming convention (false) or remain as originally defined (true). The default is `false`.
629
637
  - [Examples](https://github.com/rroumenov/zod-to-x/blob/main/test/test_zod2cpp)
630
638
 
639
+ ### 4) Go
640
+ Generates idiomatic Go structs with `encoding/json` struct tags. Requires Go 1.18+ for generic type support.
641
+ - Options:
642
+ - **packageName**: The Go package name for the generated file. Defaults to `"models"`.
643
+ - **keepKeys**: Specifies whether field names should remain as originally defined (true) or be converted to exported PascalCase with the original name used in the JSON tag (false). The default is `false`.
644
+ - **useJsonTags**: Whether to emit `json:"fieldName"` struct tags. Defaults to `true`.
645
+ - [Examples](https://github.com/rroumenov/zod-to-x/blob/main/test/test_zod2go)
646
+
647
+ ### 5) Dart
648
+ `json_annotation` + `json_serializable` are used for JSON serialization/deserialization. The `.g.dart` part file is generated externally by `dart run build_runner build`.
649
+ - Options:
650
+ - **keepKeys**: Specifies whether property names should follow the Dart naming convention (false) or remain as originally defined (true). The default is `false`.
651
+ - **useJsonSerialization**: When true (default), emits `@JsonSerializable()`, `@JsonEnum`, `@JsonKey` annotations and `fromJson`/`toJson` stubs. Requires `package:json_annotation`.
652
+ - **partFile**: Filename (without extension) for the `part '${partFile}.g.dart'` directive. Automatically set when using layered modeling. If omitted, no `part` directive is emitted.
653
+ - [Examples](https://github.com/rroumenov/zod-to-x/blob/main/test/test_zod2dart)
654
+
631
655
 
632
656
 
633
657
  ## Additional utils
@@ -82,7 +82,7 @@ export declare class Zod2Ast {
82
82
  private _intersectAstNodes;
83
83
  /**
84
84
  * Merges multiple AST definitions into a single AST object containing combined properties.
85
- * - Equal properties mush have the same type and array dimension.
85
+ * - Equal properties must have the same type and array dimension.
86
86
  * - If a property is optional in one definition and required in another, it will be considered
87
87
  * optional in the merged object.
88
88
  * - If a property is nullable in one definition and non-nullable in another, it will be
@@ -151,6 +151,7 @@ class Zod2Ast {
151
151
  for (const schema of [left, right]) {
152
152
  const shape = schema.def.shape;
153
153
  for (const key in shape) {
154
+ const prevWasRequired = properties[key] !== undefined && !properties[key].isOptional;
154
155
  if (zod_helpers_1.ZodHelpers.isZodPromise(shape[key]) &&
155
156
  zod_helpers_1.ZodHelpers.isZod2XGeneric(shape[key])) {
156
157
  const templateKey = shape[key].unwrap().def.values[0];
@@ -159,13 +160,18 @@ class Zod2Ast {
159
160
  else {
160
161
  properties[key] = this._zodToAST(shape[key]);
161
162
  }
163
+ if (prevWasRequired && properties[key].isOptional) {
164
+ // In intersection, if a property is required in one schema and optional in
165
+ // another, it should be considered required.
166
+ properties[key].isOptional = false;
167
+ }
162
168
  }
163
169
  }
164
170
  return { properties };
165
171
  }
166
172
  /**
167
173
  * Merges multiple AST definitions into a single AST object containing combined properties.
168
- * - Equal properties mush have the same type and array dimension.
174
+ * - Equal properties must have the same type and array dimension.
169
175
  * - If a property is optional in one definition and required in another, it will be considered
170
176
  * optional in the merged object.
171
177
  * - If a property is nullable in one definition and non-nullable in another, it will be
@@ -178,42 +184,49 @@ class Zod2Ast {
178
184
  _unionAstNodes(options) {
179
185
  let typeA, typeB;
180
186
  const data = options.map((i) => this.nodes.get(i.name));
181
- return {
182
- properties: data.reduce((acc, i, j) => {
183
- var _a, _b;
184
- for (const key in i.properties) {
185
- if (acc[key]) {
186
- acc[key] = structuredClone(acc[key]);
187
- typeA = acc[key].constructor.name;
188
- typeB = i.properties[key].constructor.name;
189
- if (typeA !== typeB) {
190
- this.warnings.push(`Merging properties with different types: ${typeA} ` +
191
- `(from ${(_a = data[j - 1]) === null || _a === void 0 ? void 0 : _a.name}) and ${typeB} ` +
192
- `(from ${i.name})`);
193
- }
194
- if (acc[key].arrayDimension !== i.properties[key].arrayDimension) {
195
- this.warnings.push(`Merging properties with different array dimensions: ` +
196
- `${acc[key].arrayDimension} (from ${(_b = data[j - 1]) === null || _b === void 0 ? void 0 : _b.name}) and ` +
197
- `${i.properties[key].arrayDimension} (from ${i.name})`);
198
- acc[key].arrayDimension = Math.max(acc[key].arrayDimension || 0, i.properties[key].arrayDimension || 0);
199
- }
200
- if (acc[key].isNullable !== i.properties[key].isNullable) {
201
- acc[key].isNullable = true;
202
- }
203
- if (acc[key].isOptional !== i.properties[key].isOptional) {
204
- acc[key].isOptional = true;
205
- }
206
- if (i.properties[key].description) {
207
- acc[key].description = i.properties[key].description;
208
- }
187
+ const properties = data.reduce((acc, i, j) => {
188
+ for (const key in i.properties) {
189
+ if (acc[key]) {
190
+ acc[key] = Object.assign(Object.create(Object.getPrototypeOf(acc[key])), acc[key]);
191
+ typeA = acc[key].constructor.name;
192
+ typeB = i.properties[key].constructor.name;
193
+ if (typeA !== typeB) {
194
+ this.warnings.push(`Merging properties with different types: ${typeA} ` +
195
+ `(from a previous variant) and ${typeB} ` +
196
+ `(from ${i.name})`);
197
+ }
198
+ if (acc[key].arrayDimension !== i.properties[key].arrayDimension) {
199
+ this.warnings.push(`Merging properties with different array dimensions: ` +
200
+ `${acc[key].arrayDimension} (from a previous variant) and ` +
201
+ `${i.properties[key].arrayDimension} (from ${i.name})`);
202
+ acc[key].arrayDimension = Math.max(acc[key].arrayDimension || 0, i.properties[key].arrayDimension || 0);
209
203
  }
210
- else {
211
- acc[key] = i.properties[key];
204
+ if (acc[key].isNullable !== i.properties[key].isNullable) {
205
+ acc[key].isNullable = true;
206
+ }
207
+ if (acc[key].isOptional !== i.properties[key].isOptional) {
208
+ acc[key].isOptional = true;
209
+ }
210
+ if (i.properties[key].description) {
211
+ acc[key].description = i.properties[key].description;
212
212
  }
213
213
  }
214
- return acc;
215
- }, {}),
216
- };
214
+ else {
215
+ acc[key] = i.properties[key]; // New property, just add it
216
+ }
217
+ }
218
+ return acc;
219
+ }, {});
220
+ for (const key in properties) {
221
+ if (!data.every((variant) => key in variant.properties)) {
222
+ // In Union, if a property is not present in all variants, it should be considered
223
+ // optional. Shallow-clone preserving prototype before mutating, to avoid corrupting
224
+ // the original cached AST node.
225
+ properties[key] = Object.assign(Object.create(Object.getPrototypeOf(properties[key])), properties[key]);
226
+ properties[key].isOptional = true;
227
+ }
228
+ }
229
+ return { properties };
217
230
  }
218
231
  /**
219
232
  * Retrieves the name and associated transpilerable file information for a given Zod schema.
@@ -99,7 +99,9 @@ function Layer(opt) {
99
99
  layer: opt,
100
100
  typeName: name,
101
101
  // Generics associated to parent, but related to current type.
102
- genericTypes: metadata.genericTypes,
102
+ genericTypes: metadata.isGenericChild === false
103
+ ? metadata.genericTypes
104
+ : undefined,
103
105
  isGenericChild: true,
104
106
  };
105
107
  }
@@ -44,5 +44,7 @@ export declare class Zod2XModel {
44
44
  transpile(target: Target<"Zod2Cpp17">, opt?: TargetOpt<"Zod2Cpp17">, astOpt?: AstOpt): string;
45
45
  transpile(target: Target<"Zod2Ts">, opt?: TargetOpt<"Zod2Ts">, astOpt?: AstOpt): string;
46
46
  transpile(target: Target<"Zod2Py">, opt?: TargetOpt<"Zod2Py">, astOpt?: AstOpt): string;
47
+ transpile(target: Target<"Zod2Go">, opt?: TargetOpt<"Zod2Go">, astOpt?: AstOpt): string;
48
+ transpile(target: Target<"Zod2Dart">, opt?: TargetOpt<"Zod2Dart">, astOpt?: AstOpt): string;
47
49
  }
48
50
  export {};
@@ -59,7 +59,7 @@ class Zod2XModel {
59
59
  return this.astNodes;
60
60
  }
61
61
  transpile(target, opt = {}, astOpt) {
62
- const transpilerInstance = new target(Object.assign(Object.assign({}, opt), { namespace: this.getLayerMetadata().namespace }));
62
+ const transpilerInstance = new target(Object.assign(Object.assign({}, opt), { namespace: this.getLayerMetadata().namespace, partFile: this.getLayerMetadata().file }));
63
63
  return transpilerInstance.transpile(this.getAstNode(astOpt));
64
64
  }
65
65
  }
@@ -214,6 +214,11 @@ function createGenericType(name) {
214
214
  function useGenericType(genObj, childrens, skipLazy) {
215
215
  const builder = () => {
216
216
  let extended = genObj;
217
+ // Zod 4's extend() doesn't copy meta() (unlike Zod 3 which spread _def).
218
+ // Capture it once so it can be restored after each extend call.
219
+ // The description (e.g. "GenericUserEntity") is used by transpilers to
220
+ // identify the base generic class for cross-layer type aliases.
221
+ const genObjMeta = genObj.meta();
217
222
  for (const [key, property] of Object.entries(genObj.shape)) {
218
223
  if (ZodHelpers.isZod2XGeneric(property)) {
219
224
  const childType = childrens[key];
@@ -222,6 +227,9 @@ function useGenericType(genObj, childrens, skipLazy) {
222
227
  }
223
228
  const zod2xMeta = structuredClone(extended._zod2x);
224
229
  extended = extended.extend({ [key]: childType });
230
+ if (genObjMeta && Object.keys(genObjMeta).length > 0) {
231
+ extended = extended.meta(Object.assign({}, genObjMeta));
232
+ }
225
233
  extended._zod2x = zod2xMeta;
226
234
  extended._zod2x.isGenericChild = false;
227
235
  if (!Array.isArray(extended._zod2x.genericTypes)) {
@@ -28,8 +28,15 @@ export declare class Zod2Cpp extends Zod2X<IZod2CppOpt> {
28
28
  type?: "union" | "alias";
29
29
  isInternal?: boolean;
30
30
  templates?: string;
31
+ templateDefinition?: string;
32
+ templateList?: string;
31
33
  }): void;
32
34
  protected getGenericTemplatesTranslation(data: ASTNode): string | undefined;
35
+ /**
36
+ * Emits an alias/extension declaration early for layered references.
37
+ * It keeps concrete template translations and falls back to declared templates (e.g. <T>)
38
+ * for aliases of generic templates.
39
+ */
33
40
  protected checkExtendedTypeInclusion(data: ASTNode, type?: "union" | "alias"): boolean;
34
41
  protected runAfter(): void;
35
42
  protected getDateType: () => string;
@@ -60,8 +67,14 @@ export declare class Zod2Cpp extends Zod2X<IZod2CppOpt> {
60
67
  protected getMapType(keyType: string, valueType: string): string;
61
68
  protected getRecordType(keyType: string, valueType: string): string;
62
69
  protected _getOptional(type: string): string;
63
- protected _addExtendedTypeSerializer(typeName: string, parentNamespace: string): void;
64
- protected _addExtendedTypeDeserializer(typeName: string, parentNamespace: string): void;
70
+ protected _addExtendedTypeSerializer(typeName: string, parentNamespace: string, opt?: {
71
+ templateDefinition?: string;
72
+ templateList?: string;
73
+ }): void;
74
+ protected _addExtendedTypeDeserializer(typeName: string, parentNamespace: string, opt?: {
75
+ templateDefinition?: string;
76
+ templateList?: string;
77
+ }): void;
65
78
  protected transpileAliasedType(data: ASTAliasedTypes): void;
66
79
  /** Ex:
67
80
  * enum class EnumA: int {
@@ -100,6 +100,9 @@ class Zod2Cpp extends core_1.Zod2X {
100
100
  ? aliasOf
101
101
  : this.getTypeFromExternalNamespace(parentNamespace, aliasOf);
102
102
  const templates = (_a = opt === null || opt === void 0 ? void 0 : opt.templates) !== null && _a !== void 0 ? _a : "";
103
+ if (opt === null || opt === void 0 ? void 0 : opt.templateDefinition) {
104
+ this.push0(opt.templateDefinition);
105
+ }
103
106
  if ((opt === null || opt === void 0 ? void 0 : opt.type) === "union" || (opt === null || opt === void 0 ? void 0 : opt.type) === "alias") {
104
107
  this.push0(`using ${name} = ${extendedType}${templates};\n`);
105
108
  }
@@ -112,8 +115,14 @@ class Zod2Cpp extends core_1.Zod2X {
112
115
  }
113
116
  }
114
117
  if ((opt === null || opt === void 0 ? void 0 : opt.type) !== "alias" && parentNamespace !== undefined) {
115
- this._addExtendedTypeSerializer(name, parentNamespace);
116
- this._addExtendedTypeDeserializer(name, parentNamespace);
118
+ this._addExtendedTypeSerializer(name, parentNamespace, {
119
+ templateDefinition: opt === null || opt === void 0 ? void 0 : opt.templateDefinition,
120
+ templateList: opt === null || opt === void 0 ? void 0 : opt.templateList,
121
+ });
122
+ this._addExtendedTypeDeserializer(name, parentNamespace, {
123
+ templateDefinition: opt === null || opt === void 0 ? void 0 : opt.templateDefinition,
124
+ templateList: opt === null || opt === void 0 ? void 0 : opt.templateList,
125
+ });
117
126
  }
118
127
  }
119
128
  getGenericTemplatesTranslation(data) {
@@ -134,12 +143,28 @@ class Zod2Cpp extends core_1.Zod2X {
134
143
  ">");
135
144
  }
136
145
  }
146
+ /**
147
+ * Emits an alias/extension declaration early for layered references.
148
+ * It keeps concrete template translations and falls back to declared templates (e.g. <T>)
149
+ * for aliases of generic templates.
150
+ */
137
151
  checkExtendedTypeInclusion(data, type) {
152
+ const templatesMeta = data instanceof core_1.ASTObject && data.templates.size > 0
153
+ ? this._getTemplates(data.templates)
154
+ : undefined;
155
+ const translatedTemplates = this.getGenericTemplatesTranslation(data);
156
+ const templates = translatedTemplates || (templatesMeta === null || templatesMeta === void 0 ? void 0 : templatesMeta.templateList);
157
+ const templateList = translatedTemplates ? undefined : templatesMeta === null || templatesMeta === void 0 ? void 0 : templatesMeta.templateList;
158
+ const templateDefinition = translatedTemplates
159
+ ? undefined
160
+ : templatesMeta === null || templatesMeta === void 0 ? void 0 : templatesMeta.templateDefinition;
138
161
  if (this.isExternalTypeImport(data)) {
139
162
  if (data.aliasOf) {
140
163
  this.addExtendedType(data.name, data.parentNamespace, data.aliasOf, {
141
164
  type,
142
- templates: this.getGenericTemplatesTranslation(data),
165
+ templates,
166
+ templateDefinition,
167
+ templateList,
143
168
  });
144
169
  this.addExternalTypeImport(data);
145
170
  }
@@ -149,7 +174,9 @@ class Zod2Cpp extends core_1.Zod2X {
149
174
  this.addExtendedType(data.name, data.parentNamespace, data.aliasOf, {
150
175
  type,
151
176
  isInternal: true,
152
- templates: this.getGenericTemplatesTranslation(data),
177
+ templates,
178
+ templateDefinition,
179
+ templateList,
153
180
  });
154
181
  return true;
155
182
  }
@@ -205,13 +232,23 @@ class Zod2Cpp extends core_1.Zod2X {
205
232
  this.imports.add(this.lib.optional);
206
233
  return `boost::optional<${type}>`;
207
234
  }
208
- _addExtendedTypeSerializer(typeName, parentNamespace) {
209
- this._push0(this.serializers, `inline void to_json(${nlohmann_1.NLOHMANN}& j, const ${typeName}& x) {`);
235
+ _addExtendedTypeSerializer(typeName, parentNamespace, opt) {
236
+ var _a;
237
+ if (opt === null || opt === void 0 ? void 0 : opt.templateDefinition) {
238
+ this._push0(this.serializers, opt.templateDefinition);
239
+ }
240
+ const typeNameWithTemplates = `${typeName}${(_a = opt === null || opt === void 0 ? void 0 : opt.templateList) !== null && _a !== void 0 ? _a : ""}`;
241
+ this._push0(this.serializers, `inline void to_json(${nlohmann_1.NLOHMANN}& j, const ${typeNameWithTemplates}& x) {`);
210
242
  this._push1(this.serializers, `${parentNamespace}::to_json(j, x);`);
211
243
  this._push0(this.serializers, "}\n");
212
244
  }
213
- _addExtendedTypeDeserializer(typeName, parentNamespace) {
214
- this._push0(this.serializers, `inline void from_json(const ${nlohmann_1.NLOHMANN}& j, ${typeName}& x) {`);
245
+ _addExtendedTypeDeserializer(typeName, parentNamespace, opt) {
246
+ var _a;
247
+ if (opt === null || opt === void 0 ? void 0 : opt.templateDefinition) {
248
+ this._push0(this.serializers, opt.templateDefinition);
249
+ }
250
+ const typeNameWithTemplates = `${typeName}${(_a = opt === null || opt === void 0 ? void 0 : opt.templateList) !== null && _a !== void 0 ? _a : ""}`;
251
+ this._push0(this.serializers, `inline void from_json(const ${nlohmann_1.NLOHMANN}& j, ${typeNameWithTemplates}& x) {`);
215
252
  this._push1(this.serializers, `${parentNamespace}::from_json(j, x);`);
216
253
  this._push0(this.serializers, "}\n");
217
254
  }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Dart package imports for json_annotation / json_serializable.
3
+ */
4
+ export declare function getLibs(): {
5
+ jsonAnnotation: string;
6
+ };
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getLibs = getLibs;
4
+ /**
5
+ * Dart package imports for json_annotation / json_serializable.
6
+ */
7
+ function getLibs() {
8
+ return {
9
+ jsonAnnotation: "import 'package:json_annotation/json_annotation.dart';",
10
+ };
11
+ }
@@ -0,0 +1,21 @@
1
+ import { IZodToXOpt } from "../../core";
2
+ export interface IZod2DartOpt extends IZodToXOpt {
3
+ /**
4
+ * By default (false), class property names are converted to camelCase following Dart
5
+ * conventions. If set to true, the original property names are preserved as-is.
6
+ */
7
+ keepKeys?: boolean;
8
+ /**
9
+ * When true (default), emits `@JsonSerializable()` annotations, `@JsonEnum`, `@JsonKey`,
10
+ * and `fromJson`/`toJson` delegation stubs. Requires `package:json_annotation`.
11
+ * The `.g.dart` part file is generated externally by `dart run build_runner build`.
12
+ */
13
+ useJsonSerialization?: boolean;
14
+ /**
15
+ * Filename (without extension) used for the `part '${partFile}.g.dart';` directive.
16
+ * When using layered modeling, this is automatically set to the layer's `file` metadata.
17
+ * If omitted, no `part` directive is emitted.
18
+ */
19
+ partFile?: string;
20
+ }
21
+ export declare const defaultOpts: IZod2DartOpt;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultOpts = void 0;
4
+ exports.defaultOpts = {
5
+ indent: 2,
6
+ includeComments: true,
7
+ useImports: true,
8
+ keepKeys: false,
9
+ useJsonSerialization: true,
10
+ };
@@ -0,0 +1,149 @@
1
+ import { ASTAliasedTypes, ASTEnum, ASTIntersection, ASTNode, ASTNodes, ASTObject, ASTUnion, Zod2X } from "../../core";
2
+ import { IZod2DartOpt } from "./options";
3
+ /**
4
+ * Transpiler for Zod schemas to Dart classes using package:json_annotation.
5
+ *
6
+ * The `.g.dart` part file is NOT generated by this transpiler — it must be produced
7
+ * externally via `dart run build_runner build`.
8
+ */
9
+ export declare class Zod2Dart extends Zod2X<IZod2DartOpt> {
10
+ protected readonly commentKey = "//";
11
+ protected lib: {
12
+ jsonAnnotation: string;
13
+ };
14
+ /**
15
+ * Maps a local struct/class name to the discriminated union names it participates in.
16
+ * Populated by a pre-scan of the AST before the normal transpile pass.
17
+ */
18
+ private _unionMembers;
19
+ /**
20
+ * Names of locally-defined discriminated union abstract classes.
21
+ * Used to emit @JsonKey(fromJson/toJson) when such a type appears as a field.
22
+ */
23
+ private _discriminatedUnionTypes;
24
+ /**
25
+ * Names of typedef-emitted types (alias, union typedef, struct extends).
26
+ * When these appear as field types in @JsonSerializable classes, we emit
27
+ * @JsonKey(fromJson: TypeName.fromJson) to prevent json_serializable from
28
+ * following the typedef chain and referencing transitive imports.
29
+ */
30
+ private _typedefNames;
31
+ /**
32
+ * Maps a disc union typedef name (e.g. "NewDiscriminatedUnionItem") to the
33
+ * fromJson function name of the underlying entity-level union
34
+ * (e.g. "discriminatedUnionItemFromJson").
35
+ * Populated during pre-scan when an ASTUnion node has aliasOf set.
36
+ */
37
+ private _discriminatedUnionDelegateFromJson;
38
+ /**
39
+ * Unified set of type names needing custom @JsonKey annotations.
40
+ * - Discriminated union types: fromJson = <camelName>FromJson (local function)
41
+ * - Typedef types: fromJson = _<camelName>FromJson (standalone wrapper)
42
+ * - TypedefList: list fromJson/toJson helpers
43
+ * _toJson helpers are emitted in runAfter() for all entries.
44
+ */
45
+ private _usedCustomFromJsonTypes;
46
+ /**
47
+ * Maps a type name (e.g. "GenericUserEntity") to its full Dart type with
48
+ * template args (e.g. "GenericUserEntity<SomeDtoResult>"). Used in runAfter()
49
+ * to generate helpers with correct generic return types and factory calls.
50
+ */
51
+ private _usedCustomFromJsonFullTypes;
52
+ /**
53
+ * Maps a typedef name to its full extended type (the right-hand side of the
54
+ * typedef). E.g. "AdminUserEntity" → "GenericUserEntity<AdminUserMetadata>".
55
+ * Populated in addExtendedType() when the extended type has generic args.
56
+ * Used in runAfter() to generate 2-arg fromJson calls for generic classes.
57
+ */
58
+ private _typedefToExtendedType;
59
+ constructor(opt?: IZod2DartOpt);
60
+ /**
61
+ * Overrides transpile() to pre-scan discriminated union memberships before the normal pass.
62
+ * This allows transpileStruct() to emit `implements UnionName` on member classes.
63
+ */
64
+ transpile(transpilerQueue: ASTNodes): string;
65
+ protected runBefore(): void;
66
+ protected runAfter(): void;
67
+ protected addImportFromFile(filename: string, _namespace: string): string;
68
+ protected getTypeFromExternalNamespace(_namespace: string, typeName: string): string;
69
+ protected getGenericTemplatesTranslation(data: ASTNode): string | undefined;
70
+ /**
71
+ * Emits an alias/extension declaration for cross-layer references.
72
+ */
73
+ protected checkExtendedTypeInclusion(data: ASTNode, type?: "union" | "alias"): boolean;
74
+ protected addExtendedType(name: string, parentNamespace: string, aliasOf: string, opt?: {
75
+ type?: "union" | "alias";
76
+ isInternal?: boolean;
77
+ templates?: string;
78
+ declaredTemplates?: string;
79
+ }): void;
80
+ protected getStringType: () => string;
81
+ protected getBooleanType: () => string;
82
+ protected getAnyType: () => string;
83
+ protected getDateType: () => string;
84
+ protected getNumberType(isInt: boolean, _range: {
85
+ min?: number;
86
+ max?: number;
87
+ }): string;
88
+ /**
89
+ * Returns the Dart type for a literal value.
90
+ * Dart has no structural literal types, so we return the underlying primitive type.
91
+ * When a parent enum is provided, returns the enum type name (not a member expression),
92
+ * since Dart enum members cannot be used as types.
93
+ */
94
+ protected getLiteralStringType(value: string | number | boolean, parentEnumNameKey?: [string, string]): string | number;
95
+ /** Ex: List<List<T>> for 2D array */
96
+ protected getArrayType(arrayType: string, arrayDeep: number): string;
97
+ /** Ex: Set<T> */
98
+ protected getSetType: (itemType: string) => string;
99
+ /** Ex: Map<K, V> */
100
+ protected getMapType: (keyType: string, valueType: string) => string;
101
+ /** Ex: Map<String, V> (record key is always String) */
102
+ protected getRecordType: (keyType: string, valueType: string) => string;
103
+ /** Ex: (T1, T2, T3) — Dart 3 positional record type */
104
+ protected getTupleType: (itemsType: string[]) => string;
105
+ /** Dart has no native union type; use Object */
106
+ protected getUnionType: (_itemsType: string[]) => string;
107
+ /** Dart has no native intersection type; use Object */
108
+ protected getIntersectionType: (_itemsType: string[]) => string;
109
+ protected transpileAliasedType(data: ASTAliasedTypes): void;
110
+ /**
111
+ * Emits a Dart enhanced enum with a typed `value` field and `@JsonEnum` annotation.
112
+ *
113
+ * All-string values:
114
+ * @JsonEnum(valueField: 'value')
115
+ * enum EnumItem {
116
+ * enum1('Enum1'),
117
+ * enum2('Enum2');
118
+ *
119
+ * const EnumItem(this.value);
120
+ * final String value;
121
+ * }
122
+ *
123
+ * Mixed (int + string): typedef alias with comment.
124
+ */
125
+ protected transpileEnum(data: ASTEnum): void;
126
+ protected transpileStruct(data: ASTObject): void;
127
+ /**
128
+ * Dart intersection:
129
+ * - If the AST produced a merged `newObject`, emit it as a flat class.
130
+ * - Otherwise emit a typedef alias to Object with a comment.
131
+ */
132
+ protected transpileIntersection(data: ASTIntersection): void;
133
+ /**
134
+ * Dart union:
135
+ * - Non-discriminated: typedef alias to Object with a comment listing member types.
136
+ * - Discriminated: abstract base class + factory unmarshal function using Dart 3 switch.
137
+ */
138
+ protected transpileUnion(data: ASTUnion): void;
139
+ /** Renders the full body of a Dart class for an ASTObject. */
140
+ private _transpileStructBody;
141
+ /** Renders a single class field declaration with optional `@JsonKey` annotation. */
142
+ private _transpileMember;
143
+ /**
144
+ * Emits `fromJson` factory and `toJson` method delegation stubs.
145
+ * For generic classes, extra `fromJsonT` / `toJsonT` function parameters are added
146
+ * as required by `json_serializable` with `genericArgumentFactories: true`.
147
+ */
148
+ private _emitFromToJson;
149
+ }