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.
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultOpts = void 0;
4
+ exports.defaultOpts = {
5
+ includeComments: true,
6
+ indent: 4,
7
+ useImports: true,
8
+ packageName: "models",
9
+ keepKeys: false,
10
+ useJsonTags: true,
11
+ };
@@ -0,0 +1,100 @@
1
+ import { ASTAliasedTypes, ASTEnum, ASTIntersection, ASTNode, ASTObject, ASTUnion, Zod2X } from "../../core";
2
+ import { IZod2GoOpt } from "./options";
3
+ /**
4
+ * Transpiler for Zod schemas to Go structs and types.
5
+ */
6
+ export declare class Zod2Go extends Zod2X<IZod2GoOpt> {
7
+ protected readonly commentKey = "//";
8
+ protected lib: {
9
+ timePackage: string;
10
+ jsonPackage: string;
11
+ fmtPackage: string;
12
+ };
13
+ constructor(opt?: IZod2GoOpt);
14
+ protected runBefore(): void;
15
+ protected runAfter(): void;
16
+ /**
17
+ * Consolidates all collected imports into a proper Go import block.
18
+ * Single import → `import "pkg"`, multiple → `import (\n\t"pkg"\n)`.
19
+ */
20
+ private _consolidateImports;
21
+ protected addImportFromFile(filename: string, namespace: string): string;
22
+ protected getTypeFromExternalNamespace(namespace: string, typeName: string): string;
23
+ protected addExtendedType(name: string, parentNamespace: string, aliasOf: string, opt?: {
24
+ type?: "union" | "alias";
25
+ isInternal?: boolean;
26
+ templates?: string;
27
+ declaredTemplates?: string;
28
+ }): void;
29
+ protected getGenericTemplatesTranslation(data: ASTNode): string | undefined;
30
+ /**
31
+ * Emits an alias/extension declaration early when a node references another layered type.
32
+ */
33
+ protected checkExtendedTypeInclusion(data: ASTNode, type?: "union" | "alias"): boolean;
34
+ protected getStringType: () => string;
35
+ protected getBooleanType: () => string;
36
+ protected getAnyType: () => string;
37
+ protected getDateType: () => string;
38
+ protected getNumberType: (isInt: boolean, range: {
39
+ min?: number;
40
+ max?: number;
41
+ }) => string;
42
+ protected getLiteralStringType(value: string | number | boolean, parentEnumNameKey?: [string, string]): string | number;
43
+ /** Ex: []TypeA, [][]TypeA */
44
+ protected getArrayType(arrayType: string, arrayDeep: number): string;
45
+ /** Ex: map[TypeA]struct{} */
46
+ protected getSetType: (itemType: string) => string;
47
+ /** Ex: map[KeyType]ValueType */
48
+ protected getMapType: (keyType: string, valueType: string) => string;
49
+ /** Ex: map[KeyType]ValueType */
50
+ protected getRecordType: (keyType: string, valueType: string) => string;
51
+ /** Go has no native tuple; use []any */
52
+ protected getTupleType: (_itemsType: string[]) => string;
53
+ /** Go has no native union; use any */
54
+ protected getUnionType: (_itemsType: string[]) => string;
55
+ /** Handled entirely in transpileIntersection via struct embedding */
56
+ protected getIntersectionType: () => string;
57
+ protected transpileAliasedType(data: ASTAliasedTypes): void;
58
+ /**
59
+ * Emit a Go enum using a typed string or int alias + const block.
60
+ *
61
+ * All-string values:
62
+ * type EnumItem string
63
+ * const (
64
+ * EnumItemEnum1 EnumItem = "Enum1"
65
+ * )
66
+ *
67
+ * All-int values:
68
+ * type EnumItem int
69
+ * const (
70
+ * EnumItemNativeEnum1 EnumItem = 1
71
+ * )
72
+ *
73
+ * Mixed (int + string): untyped constants with warning comment.
74
+ */
75
+ protected transpileEnum(data: ASTEnum): void;
76
+ /**
77
+ * Go union: emit `type Name any` with a comment listing possible types.
78
+ *
79
+ * For discriminated unions: emit a marker interface + marker stubs on each
80
+ * member type + an `UnmarshalXxx` helper that dispatches on the discriminant
81
+ * key using a `json.RawMessage` probe (uniform for string, bool, and number
82
+ * discriminant values).
83
+ */
84
+ protected transpileUnion(data: ASTUnion): void;
85
+ /**
86
+ * Go intersection: struct embedding.
87
+ *
88
+ * type IntersectionItem struct {
89
+ * ObjectItem
90
+ * OtherObjectItem
91
+ * }
92
+ */
93
+ protected transpileIntersection(data: ASTIntersection): void;
94
+ protected transpileStruct(data: ASTObject): void;
95
+ /** Render a Go struct body for an ASTObject. */
96
+ private _transpileStructBody;
97
+ /** Render a single struct field: `FieldName Type \`json:"key"\`` */
98
+ private _transpileMember;
99
+ private _buildJsonTag;
100
+ }
@@ -0,0 +1,399 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Zod2Go = void 0;
7
+ const case_1 = __importDefault(require("case"));
8
+ const core_1 = require("../../core");
9
+ const number_limits_1 = require("../../utils/number_limits");
10
+ const libs_1 = require("./libs");
11
+ const options_1 = require("./options");
12
+ /**
13
+ * Transpiler for Zod schemas to Go structs and types.
14
+ */
15
+ class Zod2Go extends core_1.Zod2X {
16
+ constructor(opt = {}) {
17
+ super(Object.assign(Object.assign({}, options_1.defaultOpts), opt));
18
+ this.commentKey = "//";
19
+ // ── Primitive type methods ──────────────────────────────────────────────
20
+ this.getStringType = () => "string";
21
+ this.getBooleanType = () => "bool";
22
+ this.getAnyType = () => "any";
23
+ this.getDateType = () => {
24
+ this.imports.add(this.lib.timePackage);
25
+ return "time.Time";
26
+ };
27
+ this.getNumberType = (isInt, range) => {
28
+ if (!isInt)
29
+ return "float64";
30
+ const min = range.min;
31
+ const max = range.max;
32
+ if (min !== undefined &&
33
+ max !== undefined &&
34
+ min >= number_limits_1.INT32_RANGES[0] &&
35
+ max <= number_limits_1.INT32_RANGES[1]) {
36
+ return "int32";
37
+ }
38
+ return "int64";
39
+ };
40
+ /** Ex: map[TypeA]struct{} */
41
+ this.getSetType = (itemType) => `map[${itemType}]struct{}`;
42
+ /** Ex: map[KeyType]ValueType */
43
+ this.getMapType = (keyType, valueType) => `map[${keyType}]${valueType}`;
44
+ /** Ex: map[KeyType]ValueType */
45
+ this.getRecordType = (keyType, valueType) => `map[${keyType}]${valueType}`;
46
+ /** Go has no native tuple; use []any */
47
+ this.getTupleType = (_itemsType) => "[]any";
48
+ /** Go has no native union; use any */
49
+ this.getUnionType = (_itemsType) => "any";
50
+ /** Handled entirely in transpileIntersection via struct embedding */
51
+ this.getIntersectionType = () => "";
52
+ this.lib = (0, libs_1.getLibs)();
53
+ }
54
+ runBefore() {
55
+ var _a;
56
+ this.preImports.add(`package ${(_a = this.opt.packageName) !== null && _a !== void 0 ? _a : "models"}`);
57
+ }
58
+ runAfter() {
59
+ this._consolidateImports();
60
+ }
61
+ /**
62
+ * Consolidates all collected imports into a proper Go import block.
63
+ * Single import → `import "pkg"`, multiple → `import (\n\t"pkg"\n)`.
64
+ */
65
+ _consolidateImports() {
66
+ if (this.imports.size === 0)
67
+ return;
68
+ const sorted = Array.from(this.imports).sort();
69
+ let block;
70
+ if (sorted.length === 1) {
71
+ block = `import ${sorted[0]}`;
72
+ }
73
+ else {
74
+ block = `import (\n${sorted.map((s) => `\t${s}`).join("\n")}\n)`;
75
+ }
76
+ // Replace the individual entries with the consolidated block
77
+ this.imports.clear();
78
+ this.imports.add(block);
79
+ }
80
+ addImportFromFile(filename, namespace) {
81
+ const base = filename.endsWith(".go") ? filename.slice(0, -3) : filename;
82
+ return `${namespace} "./${base}"`;
83
+ }
84
+ getTypeFromExternalNamespace(namespace, typeName) {
85
+ return `${namespace}.${typeName}`;
86
+ }
87
+ addExtendedType(name, parentNamespace, aliasOf, opt) {
88
+ var _a, _b;
89
+ const extendedType = (opt === null || opt === void 0 ? void 0 : opt.isInternal)
90
+ ? aliasOf
91
+ : this.getTypeFromExternalNamespace(parentNamespace, aliasOf);
92
+ const templates = (_a = opt === null || opt === void 0 ? void 0 : opt.templates) !== null && _a !== void 0 ? _a : "";
93
+ const declaredTemplates = (_b = opt === null || opt === void 0 ? void 0 : opt.declaredTemplates) !== null && _b !== void 0 ? _b : "";
94
+ if ((opt === null || opt === void 0 ? void 0 : opt.type) === "alias" || (opt === null || opt === void 0 ? void 0 : opt.type) === "union") {
95
+ this.push0(`type ${name}${declaredTemplates} = ${extendedType}${templates}\n`);
96
+ }
97
+ else {
98
+ // Struct embedding: type ChildName struct { ParentType }
99
+ this.push0(`type ${name}${declaredTemplates} struct {`);
100
+ this.push1(`${extendedType}${templates}`);
101
+ this.push0(`}\n`);
102
+ }
103
+ }
104
+ getGenericTemplatesTranslation(data) {
105
+ if ((data instanceof core_1.ASTObject || data instanceof core_1.ASTDefinition) &&
106
+ data.templatesTranslation.length > 0) {
107
+ return ("[" +
108
+ data.templatesTranslation
109
+ .map((t) => {
110
+ if (this.isExternalTypeImport(t)) {
111
+ this.addExternalTypeImport(t);
112
+ return this.getTypeFromExternalNamespace(t.parentNamespace, t.aliasOf);
113
+ }
114
+ else {
115
+ return t.aliasOf;
116
+ }
117
+ })
118
+ .join(", ") +
119
+ "]");
120
+ }
121
+ }
122
+ /**
123
+ * Emits an alias/extension declaration early when a node references another layered type.
124
+ */
125
+ checkExtendedTypeInclusion(data, type) {
126
+ const isStruct = data instanceof core_1.ASTObject ||
127
+ (data instanceof core_1.ASTIntersection && data.newObject !== undefined);
128
+ const translatedTemplates = this.getGenericTemplatesTranslation(data);
129
+ const templates = translatedTemplates || undefined;
130
+ // For declared-template fallback on the declared (definition) side
131
+ const declaredTemplates = !translatedTemplates && data instanceof core_1.ASTObject && data.templates.size > 0
132
+ ? `[${[...data.templates].map((t) => `${t} any`).join(", ")}]`
133
+ : undefined;
134
+ if (this.isExternalTypeImport(data)) {
135
+ if (data.aliasOf) {
136
+ this.addExtendedType(data.name, data.parentNamespace, data.aliasOf, {
137
+ type: isStruct ? undefined : type,
138
+ templates,
139
+ declaredTemplates,
140
+ });
141
+ this.addExternalTypeImport(data);
142
+ }
143
+ return true;
144
+ }
145
+ else if (data.aliasOf) {
146
+ this.addExtendedType(data.name, data.parentNamespace, data.aliasOf, {
147
+ type: isStruct ? undefined : type,
148
+ isInternal: true,
149
+ templates,
150
+ declaredTemplates,
151
+ });
152
+ return true;
153
+ }
154
+ return false;
155
+ }
156
+ getLiteralStringType(value, parentEnumNameKey) {
157
+ if (parentEnumNameKey) {
158
+ // Go constants cannot be used as types; use the parent enum type name
159
+ return parentEnumNameKey[0];
160
+ }
161
+ // Go has no literal types; return the underlying primitive type
162
+ if (typeof value === "boolean")
163
+ return "bool";
164
+ if (typeof value === "number")
165
+ return isNaN(value) ? "float64" : Number.isInteger(value) ? "int64" : "float64";
166
+ return "string";
167
+ }
168
+ // ── Composite type methods ──────────────────────────────────────────────
169
+ /** Ex: []TypeA, [][]TypeA */
170
+ getArrayType(arrayType, arrayDeep) {
171
+ let output = `[]${arrayType}`;
172
+ for (let i = 0; i < arrayDeep - 1; i++) {
173
+ output = `[]${output}`;
174
+ }
175
+ return output;
176
+ }
177
+ // ── Transpile methods ───────────────────────────────────────────────────
178
+ transpileAliasedType(data) {
179
+ if (this.checkExtendedTypeInclusion(data, "alias")) {
180
+ return;
181
+ }
182
+ this.addComment(data.description);
183
+ let extendedType;
184
+ if (data instanceof core_1.ASTArray) {
185
+ extendedType = this.getAttributeType(data.item);
186
+ }
187
+ else {
188
+ extendedType = this.getAttributeType(data);
189
+ }
190
+ this.push0(`type ${data.name} = ${extendedType}\n`);
191
+ }
192
+ /**
193
+ * Emit a Go enum using a typed string or int alias + const block.
194
+ *
195
+ * All-string values:
196
+ * type EnumItem string
197
+ * const (
198
+ * EnumItemEnum1 EnumItem = "Enum1"
199
+ * )
200
+ *
201
+ * All-int values:
202
+ * type EnumItem int
203
+ * const (
204
+ * EnumItemNativeEnum1 EnumItem = 1
205
+ * )
206
+ *
207
+ * Mixed (int + string): untyped constants with warning comment.
208
+ */
209
+ transpileEnum(data) {
210
+ if (this.checkExtendedTypeInclusion(data, "alias")) {
211
+ return;
212
+ }
213
+ this.addComment(data.description);
214
+ const allStrings = data.values.every(([, v]) => typeof v === "string");
215
+ const allInts = data.values.every(([, v]) => typeof v === "number");
216
+ if (allStrings) {
217
+ this.push0(`type ${data.name} string\n`);
218
+ this.push0(`const (`);
219
+ data.values.forEach(([key, value]) => {
220
+ const constName = `${data.name}${case_1.default.pascal(key)}`;
221
+ this.push1(`${constName} ${data.name} = "${value}"`);
222
+ });
223
+ this.push0(`)\n`);
224
+ }
225
+ else if (allInts) {
226
+ this.push0(`type ${data.name} int\n`);
227
+ this.push0(`const (`);
228
+ data.values.forEach(([key, value]) => {
229
+ const constName = `${data.name}${case_1.default.pascal(key)}`;
230
+ this.push1(`${constName} ${data.name} = ${value}`);
231
+ });
232
+ this.push0(`)\n`);
233
+ }
234
+ else {
235
+ // Mixed types — Go cannot express this as a single typed enum.
236
+ // Declare as `any` so struct fields can reference the type name.
237
+ this.push0(`type ${data.name} = any\n`);
238
+ this.output.push(`// ${data.name}: mixed-type enum — no single Go base type available`);
239
+ this.push0(`const (`);
240
+ data.values.forEach(([key, value]) => {
241
+ const constName = `${data.name}${case_1.default.pascal(key)}`;
242
+ const v = typeof value === "string" ? `"${value}"` : `${value}`;
243
+ this.push1(`${constName} = ${v}`);
244
+ });
245
+ this.push0(`)\n`);
246
+ }
247
+ }
248
+ /**
249
+ * Go union: emit `type Name any` with a comment listing possible types.
250
+ *
251
+ * For discriminated unions: emit a marker interface + marker stubs on each
252
+ * member type + an `UnmarshalXxx` helper that dispatches on the discriminant
253
+ * key using a `json.RawMessage` probe (uniform for string, bool, and number
254
+ * discriminant values).
255
+ */
256
+ transpileUnion(data) {
257
+ if (this.checkExtendedTypeInclusion(data, "union")) {
258
+ return;
259
+ }
260
+ this.addComment(data.description);
261
+ const optionNames = data.options.map(this.getAttributeType.bind(this));
262
+ if (data.discriminantKey) {
263
+ const methodName = `is${data.name}`;
264
+ this.push0(`// ${data.name} is a discriminated union on "${data.discriminantKey}".`);
265
+ this.push0(`// Possible types: ${optionNames.join(", ")}`);
266
+ this.push0(`type ${data.name} interface {`);
267
+ this.push1(`${methodName}()`);
268
+ this.push0(`}\n`);
269
+ // Marker stubs: one no-op method per member type so each satisfies the interface.
270
+ // For generic instantiations (e.g. "HttpSuccessfulResponse[SomeDtoResult]") we emit
271
+ // a generic receiver "func (t Base[T]) isXxx() {}" using the base type name only.
272
+ for (const name of optionNames) {
273
+ const bracketIdx = name.indexOf("[");
274
+ const receiver = bracketIdx !== -1 ? `${name.slice(0, bracketIdx)}[T]` : name;
275
+ this.push0(`func (t ${receiver}) ${methodName}() {}\n`);
276
+ }
277
+ // UnmarshalXxx helper — only when every member has a discriminant value in the AST.
278
+ const optionsData = data.options.map((opt, i) => {
279
+ var _a;
280
+ return ({
281
+ typeName: optionNames[i],
282
+ discriminantValue: (_a = opt.constraints) === null || _a === void 0 ? void 0 : _a.discriminantValue,
283
+ });
284
+ });
285
+ const allHaveDiscriminantValue = optionsData.every((o) => o.discriminantValue !== undefined);
286
+ if (allHaveDiscriminantValue) {
287
+ this.imports.add(this.lib.jsonPackage);
288
+ this.imports.add(this.lib.fmtPackage);
289
+ const probeField = data.discriminantKey.charAt(0).toUpperCase() + data.discriminantKey.slice(1);
290
+ this.push0(`// Unmarshal${data.name} deserializes JSON into the correct ${data.name} concrete type`);
291
+ this.push0(`// by probing the "${data.discriminantKey}" discriminant field.`);
292
+ this.push0(`func Unmarshal${data.name}(data []byte) (${data.name}, error) {`);
293
+ this.push1(`var probe struct {`);
294
+ this.push2(`${probeField} json.RawMessage \`json:"${data.discriminantKey}"\``);
295
+ this.push1(`}`);
296
+ this.push1(`if err := json.Unmarshal(data, &probe); err != nil {`);
297
+ this.push2(`return nil, err`);
298
+ this.push1(`}`);
299
+ this.push1(`switch string(probe.${probeField}) {`);
300
+ for (const opt of optionsData) {
301
+ const dv = opt.discriminantValue;
302
+ // Determine raw JSON representation of the case value.
303
+ // String literals appear in JSON with surrounding quotes ("Enum1" → "Enum1").
304
+ // Bool and number literals appear without quotes (true → true, 42 → 42).
305
+ const isStringLiteral = isNaN(Number(dv)) && dv !== "true" && dv !== "false";
306
+ const caseVal = isStringLiteral ? `\`"${dv}"\`` : `"${dv}"`;
307
+ this.push1(`case ${caseVal}:`);
308
+ this.push2(`var v ${opt.typeName}`);
309
+ this.push2(`if err := json.Unmarshal(data, &v); err != nil {`);
310
+ this.push3(`return nil, err`);
311
+ this.push2(`}`);
312
+ this.push2(`return v, nil`);
313
+ }
314
+ this.push1(`}`);
315
+ this.push1(`return nil, fmt.Errorf("failed to deserialize ${data.name}: unknown discriminator %s", string(probe.${probeField}))`);
316
+ this.push0(`}\n`);
317
+ }
318
+ }
319
+ else {
320
+ this.push0(`// ${data.name} is a union of: ${optionNames.join(", ")}`);
321
+ this.push0(`type ${data.name} = any\n`);
322
+ }
323
+ }
324
+ /**
325
+ * Go intersection: struct embedding.
326
+ *
327
+ * type IntersectionItem struct {
328
+ * ObjectItem
329
+ * OtherObjectItem
330
+ * }
331
+ */
332
+ transpileIntersection(data) {
333
+ if (this.checkExtendedTypeInclusion(data)) {
334
+ return;
335
+ }
336
+ this.addComment(data.description);
337
+ if (data.newObject) {
338
+ // Flatten the merged object into a plain struct
339
+ this._transpileStructBody(data.newObject);
340
+ }
341
+ else {
342
+ // Embed both sides
343
+ const leftType = this.getAttributeType(data.left);
344
+ const rightType = this.getAttributeType(data.right);
345
+ this.push0(`type ${data.name} struct {`);
346
+ this.push1(leftType);
347
+ this.push1(rightType);
348
+ this.push0(`}\n`);
349
+ }
350
+ }
351
+ transpileStruct(data) {
352
+ if (this.checkExtendedTypeInclusion(data)) {
353
+ return;
354
+ }
355
+ this.addComment(data.description);
356
+ this._transpileStructBody(data);
357
+ }
358
+ /** Render a Go struct body for an ASTObject. */
359
+ _transpileStructBody(data) {
360
+ const templateParams = data.templates.size > 0
361
+ ? `[${[...data.templates].map((t) => `${t} any`).join(", ")}]`
362
+ : "";
363
+ this.push0(`type ${data.name}${templateParams} struct {`);
364
+ const hasProperties = Object.keys(data.properties).length > 0;
365
+ if (!hasProperties) {
366
+ this.push0(`}\n`);
367
+ return;
368
+ }
369
+ for (const [key, value] of Object.entries(data.properties)) {
370
+ const fieldName = this.opt.keepKeys === true ? key : case_1.default.pascal(key);
371
+ this._transpileMember(fieldName, key, value);
372
+ }
373
+ this.push0(`}\n`);
374
+ }
375
+ /** Render a single struct field: `FieldName Type \`json:"key"\`` */
376
+ _transpileMember(fieldName, originalKey, memberNode) {
377
+ const isOptionalOrNullable = memberNode.isOptional || memberNode.isNullable;
378
+ let varType = this.getAttributeType(memberNode);
379
+ // Optional/nullable fields use pointer types
380
+ if (isOptionalOrNullable) {
381
+ // Avoid double-pointer for types already expressed as pointers/interfaces
382
+ if (!varType.startsWith("*") && varType !== "any") {
383
+ varType = `*${varType}`;
384
+ }
385
+ }
386
+ if (memberNode.description && !memberNode.name && !this.isTranspilerable(memberNode)) {
387
+ this.addComment(memberNode.description, `\n${this.indent[1]}`);
388
+ }
389
+ const tag = this._buildJsonTag(originalKey, isOptionalOrNullable !== null && isOptionalOrNullable !== void 0 ? isOptionalOrNullable : false);
390
+ this.push1(`${fieldName} ${varType}${tag}`);
391
+ }
392
+ _buildJsonTag(originalKey, omitempty) {
393
+ if (this.opt.useJsonTags === false)
394
+ return "";
395
+ const flags = omitempty ? `,omitempty` : "";
396
+ return ` \`json:"${originalKey}${flags}"\``;
397
+ }
398
+ }
399
+ exports.Zod2Go = Zod2Go;
@@ -1,3 +1,5 @@
1
1
  export { Zod2Ts } from "./typescript/runner";
2
2
  export { Zod2Cpp, Zod2Cpp17 } from "./cpp/runner";
3
3
  export { Zod2Py } from "./python/runner";
4
+ export { Zod2Go } from "./go/runner";
5
+ export { Zod2Dart } from "./dart/runner";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Zod2Py = exports.Zod2Cpp17 = exports.Zod2Cpp = exports.Zod2Ts = void 0;
3
+ exports.Zod2Dart = exports.Zod2Go = exports.Zod2Py = exports.Zod2Cpp17 = exports.Zod2Cpp = exports.Zod2Ts = void 0;
4
4
  var runner_1 = require("./typescript/runner");
5
5
  Object.defineProperty(exports, "Zod2Ts", { enumerable: true, get: function () { return runner_1.Zod2Ts; } });
6
6
  var runner_2 = require("./cpp/runner");
@@ -8,3 +8,7 @@ Object.defineProperty(exports, "Zod2Cpp", { enumerable: true, get: function () {
8
8
  Object.defineProperty(exports, "Zod2Cpp17", { enumerable: true, get: function () { return runner_2.Zod2Cpp17; } });
9
9
  var runner_3 = require("./python/runner");
10
10
  Object.defineProperty(exports, "Zod2Py", { enumerable: true, get: function () { return runner_3.Zod2Py; } });
11
+ var runner_4 = require("./go/runner");
12
+ Object.defineProperty(exports, "Zod2Go", { enumerable: true, get: function () { return runner_4.Zod2Go; } });
13
+ var runner_5 = require("./dart/runner");
14
+ Object.defineProperty(exports, "Zod2Dart", { enumerable: true, get: function () { return runner_5.Zod2Dart; } });
@@ -23,6 +23,7 @@ export declare class Zod2Py extends Zod2X<IZod2PyOpt> {
23
23
  };
24
24
  private baseSchemaAdded;
25
25
  private typeVars;
26
+ private pendingTypeVars;
26
27
  constructor(opt?: IZod2PyOpt);
27
28
  protected runAfter(): void;
28
29
  protected runBefore(): void;
@@ -31,6 +32,7 @@ export declare class Zod2Py extends Zod2X<IZod2PyOpt> {
31
32
  * This is the base class for all Pydantic models with shared configuration.
32
33
  */
33
34
  private _addBaseSchema;
35
+ private _flushPendingTypeVars;
34
36
  /**
35
37
  * Declares TypeVars that haven't been declared yet.
36
38
  * Adds them right before their first usage.
@@ -51,6 +53,11 @@ export declare class Zod2Py extends Zod2X<IZod2PyOpt> {
51
53
  isClass?: boolean;
52
54
  }): void;
53
55
  protected getGenericTemplatesTranslation(data: ASTNode): string | undefined;
56
+ /**
57
+ * Emits an alias/extension declaration early for layered references.
58
+ * It keeps concrete template translations and falls back to declared templates (e.g. [T])
59
+ * for aliases of generic templates.
60
+ */
54
61
  protected checkExtendedTypeInclusion(data: ASTNode, type?: "alias" | "union" | "d-union"): boolean;
55
62
  protected getAnyType: () => string;
56
63
  protected getBooleanType: () => string;
@@ -14,6 +14,7 @@ class Zod2Py extends core_1.Zod2X {
14
14
  this.commentKey = "#";
15
15
  this.baseSchemaAdded = false;
16
16
  this.typeVars = new Set();
17
+ this.pendingTypeVars = new Set();
17
18
  this.getAnyType = () => {
18
19
  this.imports.add(this.lib.anyType);
19
20
  return "Any";
@@ -51,6 +52,9 @@ class Zod2Py extends core_1.Zod2X {
51
52
  this.lib = (0, libs_1.getLibs)();
52
53
  }
53
54
  runAfter() {
55
+ if (!this.baseSchemaAdded) {
56
+ this._flushPendingTypeVars(true);
57
+ }
54
58
  this._consolidateImports();
55
59
  }
56
60
  runBefore() { }
@@ -76,6 +80,22 @@ class Zod2Py extends core_1.Zod2X {
76
80
  this.push2("use_enum_values=True");
77
81
  this.push1(")");
78
82
  this.push0("");
83
+ this._flushPendingTypeVars(false);
84
+ }
85
+ _flushPendingTypeVars(prepend) {
86
+ if (this.pendingTypeVars.size === 0)
87
+ return;
88
+ const pending = Array.from(this.pendingTypeVars);
89
+ const lines = pending.map((typeVar) => `${typeVar} = TypeVar('${typeVar}')`);
90
+ if (prepend) {
91
+ this.output = [...lines, "", ...this.output];
92
+ }
93
+ else {
94
+ lines.forEach((line) => this.push0(line));
95
+ this.push0("");
96
+ }
97
+ pending.forEach((typeVar) => this.typeVars.add(typeVar));
98
+ this.pendingTypeVars.clear();
79
99
  }
80
100
  /**
81
101
  * Declares TypeVars that haven't been declared yet.
@@ -83,10 +103,14 @@ class Zod2Py extends core_1.Zod2X {
83
103
  * Ex: T = TypeVar('T')
84
104
  */
85
105
  _declareNewTypeVars(templates) {
86
- const newTypeVars = Array.from(templates).filter((t) => !this.typeVars.has(t));
106
+ const newTypeVars = Array.from(templates).filter((t) => !this.typeVars.has(t) && !this.pendingTypeVars.has(t));
87
107
  if (newTypeVars.length === 0)
88
108
  return;
89
109
  this.imports.add(this.lib.typeVarType);
110
+ if (!this.baseSchemaAdded) {
111
+ newTypeVars.forEach((typeVar) => this.pendingTypeVars.add(typeVar));
112
+ return;
113
+ }
90
114
  newTypeVars.forEach((typeVar) => {
91
115
  this.push0(`${typeVar} = TypeVar('${typeVar}')`);
92
116
  this.typeVars.add(typeVar);
@@ -183,15 +207,28 @@ class Zod2Py extends core_1.Zod2X {
183
207
  "]");
184
208
  }
185
209
  }
210
+ /**
211
+ * Emits an alias/extension declaration early for layered references.
212
+ * It keeps concrete template translations and falls back to declared templates (e.g. [T])
213
+ * for aliases of generic templates.
214
+ */
186
215
  checkExtendedTypeInclusion(data, type) {
187
216
  // Determine if the aliased type is a class (ASTObject or ASTIntersection with newObject)
188
217
  const isClass = data instanceof core_1.ASTObject ||
189
218
  (data instanceof core_1.ASTIntersection && data.newObject !== undefined);
219
+ const declaredTemplatesFallback = data instanceof core_1.ASTObject && data.templates.size > 0 && this.isExternalTypeImport(data)
220
+ ? `[${[...data.templates].join(", ")}]`
221
+ : undefined;
222
+ const translatedTemplates = this.getGenericTemplatesTranslation(data);
223
+ const templates = translatedTemplates || declaredTemplatesFallback;
224
+ if (!translatedTemplates && data instanceof core_1.ASTObject && data.templates.size > 0) {
225
+ this._declareNewTypeVars(data.templates);
226
+ }
190
227
  if (this.isExternalTypeImport(data)) {
191
228
  if (data.aliasOf) {
192
229
  this.addExtendedType(data.name, data.parentNamespace, data.aliasOf, {
193
230
  type,
194
- templates: this.getGenericTemplatesTranslation(data),
231
+ templates,
195
232
  isClass,
196
233
  });
197
234
  this.addExternalTypeImport(data);
@@ -202,7 +239,7 @@ class Zod2Py extends core_1.Zod2X {
202
239
  this.addExtendedType(data.name, data.parentNamespace, data.aliasOf, {
203
240
  type,
204
241
  isInternal: true,
205
- templates: this.getGenericTemplatesTranslation(data),
242
+ templates,
206
243
  isClass,
207
244
  });
208
245
  return true;
@@ -11,8 +11,14 @@ export declare class Zod2Ts extends Zod2X<IZod2TsOpt> {
11
11
  type?: "union" | "d-union" | "alias";
12
12
  isInternal?: boolean;
13
13
  templates?: string;
14
+ declaredTemplates?: string;
14
15
  }): void;
15
16
  protected getGenericTemplatesTranslation(data: ASTNode): string | undefined;
17
+ /**
18
+ * Emits an alias/extension declaration early when a node references another layered type.
19
+ * It preserves concrete template translations and falls back to declared templates (e.g. <T>)
20
+ * for aliases of generic templates.
21
+ */
16
22
  protected checkExtendedTypeInclusion(data: ASTNode, type?: "alias" | "union" | "d-union"): boolean;
17
23
  protected getAnyType: () => string;
18
24
  protected getBooleanType: () => string;