zod-to-x 1.6.1-dev.0 → 1.8.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 +33 -9
- package/dist/core/ast_node.d.ts +1 -1
- package/dist/core/ast_node.js +47 -34
- package/dist/layered-modeling/layer.js +3 -1
- package/dist/layered-modeling/model.d.ts +2 -0
- package/dist/layered-modeling/model.js +1 -1
- package/dist/transpilers/cpp/runner.d.ts +15 -2
- package/dist/transpilers/cpp/runner.js +45 -8
- package/dist/transpilers/dart/libs.d.ts +6 -0
- package/dist/transpilers/dart/libs.js +11 -0
- package/dist/transpilers/dart/options.d.ts +21 -0
- package/dist/transpilers/dart/options.js +10 -0
- package/dist/transpilers/dart/runner.d.ts +149 -0
- package/dist/transpilers/dart/runner.js +624 -0
- package/dist/transpilers/go/libs.d.ts +8 -0
- package/dist/transpilers/go/libs.js +13 -0
- package/dist/transpilers/go/options.d.ts +17 -0
- package/dist/transpilers/go/options.js +11 -0
- package/dist/transpilers/go/runner.d.ts +100 -0
- package/dist/transpilers/go/runner.js +399 -0
- package/dist/transpilers/index.d.ts +2 -0
- package/dist/transpilers/index.js +5 -1
- package/dist/transpilers/python/runner.d.ts +7 -0
- package/dist/transpilers/python/runner.js +40 -3
- package/dist/transpilers/typescript/runner.d.ts +6 -0
- package/dist/transpilers/typescript/runner.js +22 -8
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -26,30 +26,38 @@
|
|
|
26
26
|
<img src="https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white" alt="TypeScript">
|
|
27
27
|
<img src="https://img.shields.io/badge/Python-3776AB?style=for-the-badge&logo=python&logoColor=white" alt="Python">
|
|
28
28
|
<img src="https://img.shields.io/badge/C++-00599C?style=for-the-badge&logo=cplusplus&logoColor=white" alt="C++">
|
|
29
|
+
<img src="https://img.shields.io/badge/Go-00ADD8?style=for-the-badge&logo=go&logoColor=white" alt="Go">
|
|
30
|
+
<img src="https://img.shields.io/badge/Dart-0175C2?style=for-the-badge&logo=dart&logoColor=white" alt="Dart">
|
|
29
31
|
<img src="https://img.shields.io/badge/Protobuf-4285F4?style=for-the-badge&logo=google&logoColor=white" alt="Protobuf">
|
|
30
32
|
</p>
|
|
31
33
|
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
## Table of contents
|
|
35
|
-
- [
|
|
37
|
+
- [Table of contents](#table-of-contents)
|
|
38
|
+
- [Why Use `@zod-to-x`?](#why-use-zod-to-x)
|
|
36
39
|
- [Installation](#installation)
|
|
40
|
+
- [1) Install `@zod-to-x` and `@zod(*)` dependency.](#1-install-zod-to-x-and-zod-dependency)
|
|
41
|
+
- [2) Extend Zod using the `extendZod` method after the first `@zod` import:](#2-extend-zod-using-the-extendzod-method-after-the-first-zod-import)
|
|
37
42
|
- [Quick start](#quick-start)
|
|
38
43
|
- [Intersections and Unions](#intersections-and-unions)
|
|
39
44
|
- [Expected outputs](#expected-outputs)
|
|
40
45
|
- [Tips for discriminated unions](#tips-for-discriminated-unions)
|
|
41
46
|
- [Layered modeling](#layered-modeling)
|
|
42
47
|
- [Usage example](#usage-example)
|
|
43
|
-
- [Custom
|
|
48
|
+
- [Custom Layers](#custom-layers)
|
|
44
49
|
- [Generic types](#generic-types)
|
|
45
50
|
- [Currently supported output languages](#currently-supported-output-languages)
|
|
46
|
-
- [
|
|
47
|
-
- [
|
|
48
|
-
- [
|
|
51
|
+
- [0) ASTNode](#0-astnode)
|
|
52
|
+
- [1) Typescript](#1-typescript)
|
|
53
|
+
- [2) Python](#2-python)
|
|
54
|
+
- [3) C++](#3-c)
|
|
55
|
+
- [4) Go](#4-go)
|
|
56
|
+
- [5) Dart](#5-dart)
|
|
49
57
|
- [Additional utils](#additional-utils)
|
|
50
|
-
- [
|
|
51
|
-
- [
|
|
52
|
-
- [Mapping of supported Zod Types by
|
|
58
|
+
- [1) `zod2JsonSchemaDefinitions`](#1-zod2jsonschemadefinitions)
|
|
59
|
+
- [2) `zod2ProtoV3`](#2-zod2protov3)
|
|
60
|
+
- [Mapping of supported Zod Types by Langauge](#mapping-of-supported-zod-types-by-langauge)
|
|
53
61
|
- [Considerations](#considerations)
|
|
54
62
|
|
|
55
63
|
|
|
@@ -61,7 +69,7 @@ Managing data consistency across multiple layers and languages is a common chall
|
|
|
61
69
|
Define your data structures in one place using the powerful [`@zod`](https://github.com/colinhacks/zod) library. This eliminates redundancy, reduces inconsistencies, and simplifies maintenance across your entire codebase, all while allowing you to continue leveraging any npm package in the [`@zod`](https://github.com/colinhacks/zod) ecosystem like [`@zod-to-json-schema`](https://github.com/StefanTerdell/zod-to-json-schema)
|
|
62
70
|
|
|
63
71
|
2. **Multi-Language Compatibility**
|
|
64
|
-
Generate data models for TypeScript, Python (Pydantic), C++, and Protobuf V3
|
|
72
|
+
Generate data models for TypeScript, Python (Pydantic), C++, Go, and Protobuf V3. No more manually rewriting models for different platforms.
|
|
65
73
|
|
|
66
74
|
3. **Enhanced Productivity**
|
|
67
75
|
Automate the transpilation of data models to save time, reduce errors, and let your team focus on business logic instead of boilerplate code.
|
|
@@ -647,6 +655,22 @@ Common options:
|
|
|
647
655
|
- **keepKeys**: Specifies whether property names should follow the C++ naming convention (false) or remain as originally defined (true). The default is `false`.
|
|
648
656
|
- [Examples](https://github.com/rroumenov/zod-to-x/blob/main/test/test_zod2cpp)
|
|
649
657
|
|
|
658
|
+
### 4) Go
|
|
659
|
+
Generates idiomatic Go structs with `encoding/json` struct tags. Requires Go 1.18+ for generic type support.
|
|
660
|
+
- Options:
|
|
661
|
+
- **packageName**: The Go package name for the generated file. Defaults to `"models"`.
|
|
662
|
+
- **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`.
|
|
663
|
+
- **useJsonTags**: Whether to emit `json:"fieldName"` struct tags. Defaults to `true`.
|
|
664
|
+
- [Examples](https://github.com/rroumenov/zod-to-x/blob/main/test/test_zod2go)
|
|
665
|
+
|
|
666
|
+
### 5) Dart
|
|
667
|
+
`json_annotation` + `json_serializable` are used for JSON serialization/deserialization. The `.g.dart` part file is generated externally by `dart run build_runner build`.
|
|
668
|
+
- Options:
|
|
669
|
+
- **keepKeys**: Specifies whether property names should follow the Dart naming convention (false) or remain as originally defined (true). The default is `false`.
|
|
670
|
+
- **useJsonSerialization**: When true (default), emits `@JsonSerializable()`, `@JsonEnum`, `@JsonKey` annotations and `fromJson`/`toJson` stubs. Requires `package:json_annotation`.
|
|
671
|
+
- **partFile**: Filename (without extension) for the `part '${partFile}.g.dart'` directive. Automatically set when using layered modeling. If omitted, no `part` directive is emitted.
|
|
672
|
+
- [Examples](https://github.com/rroumenov/zod-to-x/blob/main/test/test_zod2dart)
|
|
673
|
+
|
|
650
674
|
|
|
651
675
|
|
|
652
676
|
## Additional utils
|
package/dist/core/ast_node.d.ts
CHANGED
|
@@ -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
|
|
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
|
package/dist/core/ast_node.js
CHANGED
|
@@ -160,19 +160,25 @@ class Zod2Ast {
|
|
|
160
160
|
for (const schema of [left, right]) {
|
|
161
161
|
const shape = schema._def.shape();
|
|
162
162
|
for (const key in shape) {
|
|
163
|
+
const prevWasRequired = properties[key] !== undefined && !properties[key].isOptional;
|
|
163
164
|
if (zod_helpers_1.ZodHelpers.isZodPromise(shape[key]) && zod_helpers_1.ZodHelpers.isZod2XGeneric(shape[key])) {
|
|
164
165
|
properties[key] = new core_1.ASTGenericType(shape[key]._def.type.value);
|
|
165
166
|
}
|
|
166
167
|
else {
|
|
167
168
|
properties[key] = this._zodToAST(shape[key]);
|
|
168
169
|
}
|
|
170
|
+
if (prevWasRequired && properties[key].isOptional) {
|
|
171
|
+
// In intersection, if a property is required in one schema and optional in
|
|
172
|
+
// another, it should be considered required.
|
|
173
|
+
properties[key].isOptional = false;
|
|
174
|
+
}
|
|
169
175
|
}
|
|
170
176
|
}
|
|
171
177
|
return { properties };
|
|
172
178
|
}
|
|
173
179
|
/**
|
|
174
180
|
* Merges multiple AST definitions into a single AST object containing combined properties.
|
|
175
|
-
* - Equal properties
|
|
181
|
+
* - Equal properties must have the same type and array dimension.
|
|
176
182
|
* - If a property is optional in one definition and required in another, it will be considered
|
|
177
183
|
* optional in the merged object.
|
|
178
184
|
* - If a property is nullable in one definition and non-nullable in another, it will be
|
|
@@ -185,42 +191,49 @@ class Zod2Ast {
|
|
|
185
191
|
_unionAstNodes(options) {
|
|
186
192
|
let typeA, typeB;
|
|
187
193
|
const data = options.map((i) => this.nodes.get(i.name));
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
`${i.properties[key].arrayDimension} (from ${i.name})`);
|
|
205
|
-
acc[key].arrayDimension = Math.max(acc[key].arrayDimension || 0, i.properties[key].arrayDimension || 0);
|
|
206
|
-
}
|
|
207
|
-
if (acc[key].isNullable !== i.properties[key].isNullable) {
|
|
208
|
-
acc[key].isNullable = true;
|
|
209
|
-
}
|
|
210
|
-
if (acc[key].isOptional !== i.properties[key].isOptional) {
|
|
211
|
-
acc[key].isOptional = true;
|
|
212
|
-
}
|
|
213
|
-
if (i.properties[key].description) {
|
|
214
|
-
acc[key].description = i.properties[key].description;
|
|
215
|
-
}
|
|
194
|
+
const properties = data.reduce((acc, i, j) => {
|
|
195
|
+
for (const key in i.properties) {
|
|
196
|
+
if (acc[key]) {
|
|
197
|
+
acc[key] = Object.assign(Object.create(Object.getPrototypeOf(acc[key])), acc[key]);
|
|
198
|
+
typeA = acc[key].constructor.name;
|
|
199
|
+
typeB = i.properties[key].constructor.name;
|
|
200
|
+
if (typeA !== typeB) {
|
|
201
|
+
this.warnings.push(`Merging properties with different types: ${typeA} ` +
|
|
202
|
+
`(from a previous variant) and ${typeB} ` +
|
|
203
|
+
`(from ${i.name})`);
|
|
204
|
+
}
|
|
205
|
+
if (acc[key].arrayDimension !== i.properties[key].arrayDimension) {
|
|
206
|
+
this.warnings.push(`Merging properties with different array dimensions: ` +
|
|
207
|
+
`${acc[key].arrayDimension} (from a previous variant) and ` +
|
|
208
|
+
`${i.properties[key].arrayDimension} (from ${i.name})`);
|
|
209
|
+
acc[key].arrayDimension = Math.max(acc[key].arrayDimension || 0, i.properties[key].arrayDimension || 0);
|
|
216
210
|
}
|
|
217
|
-
|
|
218
|
-
acc[key] =
|
|
211
|
+
if (acc[key].isNullable !== i.properties[key].isNullable) {
|
|
212
|
+
acc[key].isNullable = true;
|
|
213
|
+
}
|
|
214
|
+
if (acc[key].isOptional !== i.properties[key].isOptional) {
|
|
215
|
+
acc[key].isOptional = true;
|
|
216
|
+
}
|
|
217
|
+
if (i.properties[key].description) {
|
|
218
|
+
acc[key].description = i.properties[key].description;
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
221
|
+
else {
|
|
222
|
+
acc[key] = i.properties[key]; // New property, just add it
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return acc;
|
|
226
|
+
}, {});
|
|
227
|
+
for (const key in properties) {
|
|
228
|
+
if (!data.every((variant) => key in variant.properties)) {
|
|
229
|
+
// In Union, if a property is not present in all variants, it should be considered
|
|
230
|
+
// optional. Shallow-clone preserving prototype before mutating, to avoid corrupting
|
|
231
|
+
// the original cached AST node.
|
|
232
|
+
properties[key] = Object.assign(Object.create(Object.getPrototypeOf(properties[key])), properties[key]);
|
|
233
|
+
properties[key].isOptional = true;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return { properties };
|
|
224
237
|
}
|
|
225
238
|
/**
|
|
226
239
|
* 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.
|
|
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
|
}
|
|
@@ -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
|
|
64
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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,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,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
|
+
}
|