zod-codegen 1.6.2 → 1.6.3

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/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## <small>1.6.3 (2026-01-22)</small>
2
+
3
+ - fix: do not depend on inference anymore and build strict types all ar… (#60) ([b0b663e](https://github.com/julienandreu/zod-codegen/commit/b0b663e)), closes [#60](https://github.com/julienandreu/zod-codegen/issues/60)
4
+
1
5
  ## <small>1.6.2 (2026-01-19)</small>
2
6
 
3
7
  - fix: improve URL construction and filter undefined query params (#58) ([b9c3d32](https://github.com/julienandreu/zod-codegen/commit/b9c3d32)), closes [#58](https://github.com/julienandreu/zod-codegen/issues/58)
@@ -17,6 +17,27 @@ export declare class TypeScriptCodeGeneratorService implements CodeGenerator, Sc
17
17
  private buildAST;
18
18
  private buildSchemas;
19
19
  private buildSchemaTypeAliases;
20
+ /**
21
+ * Builds explicit TypeScript type declarations for all schemas.
22
+ * Returns interface declarations for object types and type aliases for other types.
23
+ */
24
+ private buildExplicitTypeDeclarations;
25
+ /**
26
+ * Converts an OpenAPI schema to a TypeScript type node.
27
+ */
28
+ private buildTypeNode;
29
+ /**
30
+ * Builds the base type node without nullable handling.
31
+ */
32
+ private buildBaseTypeNode;
33
+ /**
34
+ * Builds a TypeScript type literal for an object schema.
35
+ */
36
+ private buildObjectTypeLiteral;
37
+ /**
38
+ * Builds a TypeScript interface declaration for an object schema.
39
+ */
40
+ private buildInterfaceDeclaration;
20
41
  private buildClientClass;
21
42
  private buildConstructor;
22
43
  private buildGetBaseRequestOptionsMethod;
@@ -1 +1 @@
1
- {"version":3,"file":"code-generator.service.d.ts","sourceRoot":"","sources":["../../../src/services/code-generator.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,OAAO,KAAK,EAAC,aAAa,EAAE,aAAa,EAAC,MAAM,8BAA8B,CAAC;AAC/E,OAAO,KAAK,EAAmB,eAAe,EAAgB,MAAM,kBAAkB,CAAC;AACvF,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;AAWjE,qBAAa,8BAA+B,YAAW,aAAa,EAAE,aAAa;IACjF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAwC;IACtE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwD;IAChF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA+B;IAChE,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAuC;IAGhF,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,iBAAiB,CAAuB;gBAEpC,OAAO,GAAE,gBAAqB;IAK1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAGpB;IAEH,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM;IAMvC,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,UAAO,GAAG,EAAE,CAAC,cAAc,GAAG,EAAE,CAAC,UAAU;IA2BhF,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,YAAY;IA2CpB,OAAO,CAAC,sBAAsB;IAe9B,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,gBAAgB;IAmGxB,OAAO,CAAC,gCAAgC;IAwBxC,OAAO,CAAC,yBAAyB;IAuBjC,OAAO,CAAC,sBAAsB;IA8pB9B,OAAO,CAAC,kBAAkB;IAgE1B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAoC9B,OAAO,CAAC,mBAAmB;IAgH3B,OAAO,CAAC,mBAAmB;IA6D3B,OAAO,CAAC,qBAAqB;IAwF7B,OAAO,CAAC,gBAAgB;IA0CxB,OAAO,CAAC,iBAAiB;IAmCzB,OAAO,CAAC,iBAAiB;IA8BzB,OAAO,CAAC,eAAe;IAuDvB,OAAO,CAAC,wBAAwB;IA4IhC,OAAO,CAAC,gBAAgB;IAqBxB,OAAO,CAAC,6BAA6B;IAkPrC,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,aAAa;IAMrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAuFzB,OAAO,CAAC,WAAW;IA0CnB,OAAO,CAAC,aAAa;IAmjBrB,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,qBAAqB;IAe7B,OAAO,CAAC,oBAAoB;IAyE5B,OAAO,CAAC,8BAA8B;IActC,OAAO,CAAC,wBAAwB;IAyBhC,OAAO,CAAC,yBAAyB;IA8BjC,OAAO,CAAC,wBAAwB;IAYhC,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,kBAAkB;IA8B1B;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAmB3B;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAiFlC,OAAO,CAAC,eAAe;CAuCxB"}
1
+ {"version":3,"file":"code-generator.service.d.ts","sourceRoot":"","sources":["../../../src/services/code-generator.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,OAAO,KAAK,EAAC,aAAa,EAAE,aAAa,EAAC,MAAM,8BAA8B,CAAC;AAC/E,OAAO,KAAK,EAAmB,eAAe,EAAgB,MAAM,kBAAkB,CAAC;AACvF,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;AAWjE,qBAAa,8BAA+B,YAAW,aAAa,EAAE,aAAa;IACjF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAwC;IACtE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwD;IAChF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA+B;IAChE,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAuC;IAGhF,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,iBAAiB,CAAuB;gBAEpC,OAAO,GAAE,gBAAqB;IAK1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAGpB;IAEH,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM;IAMvC,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,UAAO,GAAG,EAAE,CAAC,cAAc,GAAG,EAAE,CAAC,UAAU;IA2BhF,OAAO,CAAC,QAAQ;IAuBhB,OAAO,CAAC,YAAY;IAmDpB,OAAO,CAAC,sBAAsB;IAK9B;;;OAGG;IACH,OAAO,CAAC,6BAA6B;IAkDrC;;OAEG;IACH,OAAO,CAAC,aAAa;IA2BrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA2EzB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAgB9B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAyBjC,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,gBAAgB;IAmGxB,OAAO,CAAC,gCAAgC;IAwBxC,OAAO,CAAC,yBAAyB;IAuBjC,OAAO,CAAC,sBAAsB;IA8pB9B,OAAO,CAAC,kBAAkB;IAgE1B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAoC9B,OAAO,CAAC,mBAAmB;IAgH3B,OAAO,CAAC,mBAAmB;IA6D3B,OAAO,CAAC,qBAAqB;IAwF7B,OAAO,CAAC,gBAAgB;IA0CxB,OAAO,CAAC,iBAAiB;IAmCzB,OAAO,CAAC,iBAAiB;IA8BzB,OAAO,CAAC,eAAe;IAuDvB,OAAO,CAAC,wBAAwB;IA4IhC,OAAO,CAAC,gBAAgB;IAqBxB,OAAO,CAAC,6BAA6B;IAkPrC,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,aAAa;IAMrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAuFzB,OAAO,CAAC,WAAW;IA0CnB,OAAO,CAAC,aAAa;IAmjBrB,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,qBAAqB;IAe7B,OAAO,CAAC,oBAAoB;IAyE5B,OAAO,CAAC,8BAA8B;IActC,OAAO,CAAC,wBAAwB;IAyBhC,OAAO,CAAC,yBAAyB;IA8BjC,OAAO,CAAC,wBAAwB;IAYhC,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,kBAAkB;IA8B1B;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAmB3B;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAiFlC,OAAO,CAAC,eAAe;CAuCxB"}
@@ -53,9 +53,12 @@ export class TypeScriptCodeGeneratorService {
53
53
  const schemaTypeAliases = this.buildSchemaTypeAliases(schemas);
54
54
  const serverConfig = this.buildServerConfiguration(openapi);
55
55
  const clientClass = this.buildClientClass(openapi, schemas);
56
+ const explicitTypeDeclarations = this.buildExplicitTypeDeclarations(openapi);
56
57
  return [
57
58
  this.createComment('Imports'),
58
59
  ...imports,
60
+ this.createComment('Explicit type declarations'),
61
+ ...explicitTypeDeclarations,
59
62
  this.createComment('Components schemas'),
60
63
  ...Object.values(schemas),
61
64
  ...schemaTypeAliases,
@@ -79,8 +82,11 @@ export class TypeScriptCodeGeneratorService {
79
82
  const schemaExpression = this.buildSchema(schema);
80
83
  // Clear context
81
84
  this.currentSchemaName = null;
85
+ const sanitizedName = this.typeBuilder.sanitizeIdentifier(name);
86
+ // Add type annotation: z.ZodType<Name>
87
+ const typeAnnotation = ts.factory.createTypeReferenceNode(ts.factory.createQualifiedName(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('ZodType')), [ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(sanitizedName), undefined)]);
82
88
  const variableStatement = ts.factory.createVariableStatement([ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], ts.factory.createVariableDeclarationList([
83
- ts.factory.createVariableDeclaration(ts.factory.createIdentifier(this.typeBuilder.sanitizeIdentifier(name)), undefined, undefined, schemaExpression),
89
+ ts.factory.createVariableDeclaration(ts.factory.createIdentifier(sanitizedName), undefined, typeAnnotation, schemaExpression),
84
90
  ], ts.NodeFlags.Const));
85
91
  return {
86
92
  ...schemaRegistered,
@@ -88,11 +94,157 @@ export class TypeScriptCodeGeneratorService {
88
94
  };
89
95
  }, {});
90
96
  }
91
- buildSchemaTypeAliases(schemas) {
92
- return Object.keys(schemas).map((name) => {
97
+ buildSchemaTypeAliases(_schemas) {
98
+ // Explicit type declarations are used instead of z.infer type exports
99
+ return [];
100
+ }
101
+ /**
102
+ * Builds explicit TypeScript type declarations for all schemas.
103
+ * Returns interface declarations for object types and type aliases for other types.
104
+ */
105
+ buildExplicitTypeDeclarations(openapi) {
106
+ const schemasEntries = Object.entries(openapi.components?.schemas ?? {});
107
+ const schemasMap = Object.fromEntries(schemasEntries);
108
+ const sortedSchemaNames = this.topologicalSort(schemasMap);
109
+ const statements = [];
110
+ for (const name of sortedSchemaNames) {
111
+ const schema = openapi.components?.schemas?.[name];
112
+ if (!schema)
113
+ continue;
93
114
  const sanitizedName = this.typeBuilder.sanitizeIdentifier(name);
94
- return ts.factory.createTypeAliasDeclaration([ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(sanitizedName), undefined, ts.factory.createTypeReferenceNode(ts.factory.createQualifiedName(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('infer')), [ts.factory.createTypeQueryNode(ts.factory.createIdentifier(sanitizedName), undefined)]));
115
+ const safeSchema = SchemaProperties.safeParse(schema);
116
+ if (!safeSchema.success) {
117
+ // Unknown schema type, create a type alias to unknown
118
+ statements.push(ts.factory.createTypeAliasDeclaration([ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(sanitizedName), undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)));
119
+ continue;
120
+ }
121
+ const schemaData = safeSchema.data;
122
+ const typeNode = this.buildTypeNode(schemaData);
123
+ // For object types with properties, create an interface
124
+ if (schemaData['type'] === 'object' && schemaData['properties']) {
125
+ statements.push(this.buildInterfaceDeclaration(sanitizedName, schemaData));
126
+ continue;
127
+ }
128
+ // For all other types (enums, arrays, unions, etc.), create a type alias
129
+ statements.push(ts.factory.createTypeAliasDeclaration([ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(sanitizedName), undefined, typeNode));
130
+ }
131
+ return statements;
132
+ }
133
+ /**
134
+ * Converts an OpenAPI schema to a TypeScript type node.
135
+ */
136
+ buildTypeNode(schema) {
137
+ const safeSchema = SchemaProperties.safeParse(schema);
138
+ if (!safeSchema.success) {
139
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
140
+ }
141
+ const prop = safeSchema.data;
142
+ // Handle $ref
143
+ if (this.isReference(prop)) {
144
+ const { $ref = '' } = Reference.parse(prop);
145
+ const refName = $ref.split('/').pop() ?? 'never';
146
+ const sanitizedRefName = this.typeBuilder.sanitizeIdentifier(refName);
147
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(sanitizedRefName), undefined);
148
+ }
149
+ // Handle nullable
150
+ const isNullable = prop['nullable'] === true;
151
+ const baseTypeNode = this.buildBaseTypeNode(prop);
152
+ if (isNullable) {
153
+ return ts.factory.createUnionTypeNode([baseTypeNode, ts.factory.createLiteralTypeNode(ts.factory.createNull())]);
154
+ }
155
+ return baseTypeNode;
156
+ }
157
+ /**
158
+ * Builds the base type node without nullable handling.
159
+ */
160
+ buildBaseTypeNode(prop) {
161
+ // Handle anyOf/oneOf (union types)
162
+ if (prop['anyOf'] && Array.isArray(prop['anyOf']) && prop['anyOf'].length > 0) {
163
+ const types = prop['anyOf'].map((s) => this.buildTypeNode(s));
164
+ return ts.factory.createUnionTypeNode(types);
165
+ }
166
+ if (prop['oneOf'] && Array.isArray(prop['oneOf']) && prop['oneOf'].length > 0) {
167
+ const types = prop['oneOf'].map((s) => this.buildTypeNode(s));
168
+ return ts.factory.createUnionTypeNode(types);
169
+ }
170
+ // Handle allOf (intersection types)
171
+ if (prop['allOf'] && Array.isArray(prop['allOf']) && prop['allOf'].length > 0) {
172
+ const types = prop['allOf'].map((s) => this.buildTypeNode(s));
173
+ return ts.factory.createIntersectionTypeNode(types);
174
+ }
175
+ // Handle enum
176
+ if (prop['enum'] && Array.isArray(prop['enum']) && prop['enum'].length > 0) {
177
+ const literalTypes = prop['enum'].map((val) => {
178
+ if (typeof val === 'string') {
179
+ return ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(val, true));
180
+ }
181
+ else if (typeof val === 'number') {
182
+ if (val < 0) {
183
+ return ts.factory.createLiteralTypeNode(ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, ts.factory.createNumericLiteral(String(Math.abs(val)))));
184
+ }
185
+ return ts.factory.createLiteralTypeNode(ts.factory.createNumericLiteral(String(val)));
186
+ }
187
+ else if (typeof val === 'boolean') {
188
+ return ts.factory.createLiteralTypeNode(val ? ts.factory.createTrue() : ts.factory.createFalse());
189
+ }
190
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
191
+ });
192
+ return ts.factory.createUnionTypeNode(literalTypes);
193
+ }
194
+ // Handle type-specific schemas
195
+ switch (prop['type']) {
196
+ case 'string':
197
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
198
+ case 'number':
199
+ case 'integer':
200
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
201
+ case 'boolean':
202
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
203
+ case 'array': {
204
+ const itemsType = prop['items']
205
+ ? this.buildTypeNode(prop['items'])
206
+ : ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
207
+ return ts.factory.createArrayTypeNode(itemsType);
208
+ }
209
+ case 'object': {
210
+ const properties = (prop['properties'] ?? {});
211
+ const requiredProps = (prop['required'] ?? []);
212
+ if (Object.keys(properties).length > 0) {
213
+ return this.buildObjectTypeLiteral(properties, requiredProps);
214
+ }
215
+ // Empty object or additionalProperties - use Record<string, unknown>
216
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Record'), [
217
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
218
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword),
219
+ ]);
220
+ }
221
+ default:
222
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
223
+ }
224
+ }
225
+ /**
226
+ * Builds a TypeScript type literal for an object schema.
227
+ */
228
+ buildObjectTypeLiteral(properties, requiredProps) {
229
+ const members = Object.entries(properties).map(([name, propSchema]) => {
230
+ const isRequired = requiredProps.includes(name);
231
+ const typeNode = this.buildTypeNode(propSchema);
232
+ return ts.factory.createPropertySignature(undefined, ts.factory.createIdentifier(name), isRequired ? undefined : ts.factory.createToken(ts.SyntaxKind.QuestionToken), typeNode);
233
+ });
234
+ return ts.factory.createTypeLiteralNode(members);
235
+ }
236
+ /**
237
+ * Builds a TypeScript interface declaration for an object schema.
238
+ */
239
+ buildInterfaceDeclaration(name, schema) {
240
+ const properties = (schema['properties'] ?? {});
241
+ const requiredProps = (schema['required'] ?? []);
242
+ const members = Object.entries(properties).map(([propName, propSchema]) => {
243
+ const isRequired = requiredProps.includes(propName);
244
+ const typeNode = this.buildTypeNode(propSchema);
245
+ return ts.factory.createPropertySignature(undefined, ts.factory.createIdentifier(propName), isRequired ? undefined : ts.factory.createToken(ts.SyntaxKind.QuestionToken), typeNode);
95
246
  });
247
+ return ts.factory.createInterfaceDeclaration([ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(name), undefined, undefined, members);
96
248
  }
97
249
  buildClientClass(openapi, schemas) {
98
250
  const clientName = this.generateClientName(openapi.info.title);
package/generated/type.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2
- // Built with zod-codegen@1.6.2
3
- // Latest edit: Mon, 19 Jan 2026 15:14:43 GMT
2
+ // Built with zod-codegen@1.6.3
3
+ // Latest edit: Thu, 22 Jan 2026 16:08:32 GMT
4
4
  // Source file: ./samples/swagger-petstore.yaml
5
5
  /* eslint-disable */
6
6
  // @ts-nocheck
@@ -10,9 +10,62 @@
10
10
  ;
11
11
  import { z } from 'zod';
12
12
 
13
+ // Explicit type declarations
14
+ ;
15
+ export interface Order {
16
+ id?: number;
17
+ petId?: number;
18
+ quantity?: number;
19
+ shipDate?: string;
20
+ status?: 'placed' | 'approved' | 'delivered';
21
+ complete?: boolean;
22
+ }
23
+ export interface Address {
24
+ street?: string;
25
+ city?: string;
26
+ state?: string;
27
+ zip?: string;
28
+ }
29
+ export interface Customer {
30
+ id?: number;
31
+ username?: string;
32
+ address?: Address[];
33
+ }
34
+ export interface Category {
35
+ id?: number;
36
+ name?: string;
37
+ }
38
+ export interface User {
39
+ id?: number;
40
+ username?: string;
41
+ firstName?: string;
42
+ lastName?: string;
43
+ email?: string;
44
+ password?: string;
45
+ phone?: string;
46
+ userStatus?: number;
47
+ }
48
+ export interface Tag {
49
+ id?: number;
50
+ name?: string;
51
+ }
52
+ export interface Pet {
53
+ id?: number;
54
+ name: string;
55
+ category?: Category;
56
+ photoUrls: string[];
57
+ tags?: Tag[];
58
+ status?: 'available' | 'pending' | 'sold';
59
+ }
60
+ export interface ApiResponse {
61
+ code?: number;
62
+ type?: string;
63
+ message?: string;
64
+ }
65
+
13
66
  // Components schemas
14
67
  ;
15
- export const Order = z.object({
68
+ export const Order: z.ZodType<Order> = z.object({
16
69
  id: z.number().int().optional(),
17
70
  petId: z.number().int().optional(),
18
71
  quantity: z.number().int().optional(),
@@ -22,22 +75,22 @@ export const Order = z.object({
22
75
  status: z.enum(['placed', 'approved', 'delivered']).optional(),
23
76
  complete: z.boolean().optional()
24
77
  });
25
- export const Address = z.object({
78
+ export const Address: z.ZodType<Address> = z.object({
26
79
  street: z.string().optional(),
27
80
  city: z.string().optional(),
28
81
  state: z.string().optional(),
29
82
  zip: z.string().optional()
30
83
  });
31
- export const Customer = z.object({
84
+ export const Customer: z.ZodType<Customer> = z.object({
32
85
  id: z.number().int().optional(),
33
86
  username: z.string().optional(),
34
87
  address: z.array(Address).optional()
35
88
  });
36
- export const Category = z.object({
89
+ export const Category: z.ZodType<Category> = z.object({
37
90
  id: z.number().int().optional(),
38
91
  name: z.string().optional()
39
92
  });
40
- export const User = z.object({
93
+ export const User: z.ZodType<User> = z.object({
41
94
  id: z.number().int().optional(),
42
95
  username: z.string().optional(),
43
96
  firstName: z.string().optional(),
@@ -47,11 +100,11 @@ export const User = z.object({
47
100
  phone: z.string().optional(),
48
101
  userStatus: z.number().int().optional()
49
102
  });
50
- export const Tag = z.object({
103
+ export const Tag: z.ZodType<Tag> = z.object({
51
104
  id: z.number().int().optional(),
52
105
  name: z.string().optional()
53
106
  });
54
- export const Pet = z.object({
107
+ export const Pet: z.ZodType<Pet> = z.object({
55
108
  id: z.number().int().optional(),
56
109
  name: z.string(),
57
110
  category: Category.optional(),
@@ -59,19 +112,11 @@ export const Pet = z.object({
59
112
  tags: z.array(Tag).optional(),
60
113
  status: z.enum(['available', 'pending', 'sold']).optional()
61
114
  });
62
- export const ApiResponse = z.object({
115
+ export const ApiResponse: z.ZodType<ApiResponse> = z.object({
63
116
  code: z.number().int().optional(),
64
117
  type: z.string().optional(),
65
118
  message: z.string().optional()
66
119
  });
67
- export type Order = z.infer<typeof Order>;
68
- export type Address = z.infer<typeof Address>;
69
- export type Customer = z.infer<typeof Customer>;
70
- export type Category = z.infer<typeof Category>;
71
- export type User = z.infer<typeof User>;
72
- export type Tag = z.infer<typeof Tag>;
73
- export type Pet = z.infer<typeof Pet>;
74
- export type ApiResponse = z.infer<typeof ApiResponse>;
75
120
  export const serverConfigurations = [{
76
121
  url: 'https://petstore3.swagger.io/api/v3'
77
122
  }];
package/package.json CHANGED
@@ -105,5 +105,5 @@
105
105
  "release": "semantic-release",
106
106
  "release:dry": "semantic-release --dry-run"
107
107
  },
108
- "version": "1.6.2"
108
+ "version": "1.6.3"
109
109
  }
@@ -75,9 +75,13 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
75
75
  const serverConfig = this.buildServerConfiguration(openapi);
76
76
  const clientClass = this.buildClientClass(openapi, schemas);
77
77
 
78
+ const explicitTypeDeclarations = this.buildExplicitTypeDeclarations(openapi);
79
+
78
80
  return [
79
81
  this.createComment('Imports'),
80
82
  ...imports,
83
+ this.createComment('Explicit type declarations'),
84
+ ...explicitTypeDeclarations,
81
85
  this.createComment('Components schemas'),
82
86
  ...Object.values(schemas),
83
87
  ...schemaTypeAliases,
@@ -108,14 +112,22 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
108
112
  // Clear context
109
113
  this.currentSchemaName = null;
110
114
 
115
+ const sanitizedName = this.typeBuilder.sanitizeIdentifier(name);
116
+
117
+ // Add type annotation: z.ZodType<Name>
118
+ const typeAnnotation = ts.factory.createTypeReferenceNode(
119
+ ts.factory.createQualifiedName(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('ZodType')),
120
+ [ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(sanitizedName), undefined)],
121
+ );
122
+
111
123
  const variableStatement = ts.factory.createVariableStatement(
112
124
  [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
113
125
  ts.factory.createVariableDeclarationList(
114
126
  [
115
127
  ts.factory.createVariableDeclaration(
116
- ts.factory.createIdentifier(this.typeBuilder.sanitizeIdentifier(name)),
117
- undefined,
128
+ ts.factory.createIdentifier(sanitizedName),
118
129
  undefined,
130
+ typeAnnotation,
119
131
  schemaExpression,
120
132
  ),
121
133
  ],
@@ -130,19 +142,218 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
130
142
  }, {});
131
143
  }
132
144
 
133
- private buildSchemaTypeAliases(schemas: Record<string, ts.VariableStatement>): ts.TypeAliasDeclaration[] {
134
- return Object.keys(schemas).map((name) => {
145
+ private buildSchemaTypeAliases(_schemas: Record<string, ts.VariableStatement>): ts.TypeAliasDeclaration[] {
146
+ // Explicit type declarations are used instead of z.infer type exports
147
+ return [];
148
+ }
149
+
150
+ /**
151
+ * Builds explicit TypeScript type declarations for all schemas.
152
+ * Returns interface declarations for object types and type aliases for other types.
153
+ */
154
+ private buildExplicitTypeDeclarations(openapi: OpenApiSpecType): ts.Statement[] {
155
+ const schemasEntries = Object.entries(openapi.components?.schemas ?? {});
156
+ const schemasMap = Object.fromEntries(schemasEntries);
157
+ const sortedSchemaNames = this.topologicalSort(schemasMap);
158
+
159
+ const statements: ts.Statement[] = [];
160
+
161
+ for (const name of sortedSchemaNames) {
162
+ const schema = openapi.components?.schemas?.[name];
163
+ if (!schema) continue;
164
+
135
165
  const sanitizedName = this.typeBuilder.sanitizeIdentifier(name);
136
- return ts.factory.createTypeAliasDeclaration(
137
- [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
138
- ts.factory.createIdentifier(sanitizedName),
139
- undefined,
140
- ts.factory.createTypeReferenceNode(
141
- ts.factory.createQualifiedName(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('infer')),
142
- [ts.factory.createTypeQueryNode(ts.factory.createIdentifier(sanitizedName), undefined)],
166
+ const safeSchema = SchemaProperties.safeParse(schema);
167
+
168
+ if (!safeSchema.success) {
169
+ // Unknown schema type, create a type alias to unknown
170
+ statements.push(
171
+ ts.factory.createTypeAliasDeclaration(
172
+ [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
173
+ ts.factory.createIdentifier(sanitizedName),
174
+ undefined,
175
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword),
176
+ ),
177
+ );
178
+ continue;
179
+ }
180
+
181
+ const schemaData = safeSchema.data;
182
+ const typeNode = this.buildTypeNode(schemaData);
183
+
184
+ // For object types with properties, create an interface
185
+ if (schemaData['type'] === 'object' && schemaData['properties']) {
186
+ statements.push(this.buildInterfaceDeclaration(sanitizedName, schemaData));
187
+ continue;
188
+ }
189
+
190
+ // For all other types (enums, arrays, unions, etc.), create a type alias
191
+ statements.push(
192
+ ts.factory.createTypeAliasDeclaration(
193
+ [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
194
+ ts.factory.createIdentifier(sanitizedName),
195
+ undefined,
196
+ typeNode,
143
197
  ),
144
198
  );
199
+ }
200
+
201
+ return statements;
202
+ }
203
+
204
+ /**
205
+ * Converts an OpenAPI schema to a TypeScript type node.
206
+ */
207
+ private buildTypeNode(schema: unknown): ts.TypeNode {
208
+ const safeSchema = SchemaProperties.safeParse(schema);
209
+ if (!safeSchema.success) {
210
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
211
+ }
212
+
213
+ const prop = safeSchema.data;
214
+
215
+ // Handle $ref
216
+ if (this.isReference(prop)) {
217
+ const {$ref = ''} = Reference.parse(prop);
218
+ const refName = $ref.split('/').pop() ?? 'never';
219
+ const sanitizedRefName = this.typeBuilder.sanitizeIdentifier(refName);
220
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(sanitizedRefName), undefined);
221
+ }
222
+
223
+ // Handle nullable
224
+ const isNullable = prop['nullable'] === true;
225
+ const baseTypeNode = this.buildBaseTypeNode(prop);
226
+
227
+ if (isNullable) {
228
+ return ts.factory.createUnionTypeNode([baseTypeNode, ts.factory.createLiteralTypeNode(ts.factory.createNull())]);
229
+ }
230
+
231
+ return baseTypeNode;
232
+ }
233
+
234
+ /**
235
+ * Builds the base type node without nullable handling.
236
+ */
237
+ private buildBaseTypeNode(prop: Record<string, unknown>): ts.TypeNode {
238
+ // Handle anyOf/oneOf (union types)
239
+ if (prop['anyOf'] && Array.isArray(prop['anyOf']) && prop['anyOf'].length > 0) {
240
+ const types = prop['anyOf'].map((s: unknown) => this.buildTypeNode(s));
241
+ return ts.factory.createUnionTypeNode(types);
242
+ }
243
+
244
+ if (prop['oneOf'] && Array.isArray(prop['oneOf']) && prop['oneOf'].length > 0) {
245
+ const types = prop['oneOf'].map((s: unknown) => this.buildTypeNode(s));
246
+ return ts.factory.createUnionTypeNode(types);
247
+ }
248
+
249
+ // Handle allOf (intersection types)
250
+ if (prop['allOf'] && Array.isArray(prop['allOf']) && prop['allOf'].length > 0) {
251
+ const types = prop['allOf'].map((s: unknown) => this.buildTypeNode(s));
252
+ return ts.factory.createIntersectionTypeNode(types);
253
+ }
254
+
255
+ // Handle enum
256
+ if (prop['enum'] && Array.isArray(prop['enum']) && prop['enum'].length > 0) {
257
+ const literalTypes = prop['enum'].map((val: unknown) => {
258
+ if (typeof val === 'string') {
259
+ return ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(val, true));
260
+ } else if (typeof val === 'number') {
261
+ if (val < 0) {
262
+ return ts.factory.createLiteralTypeNode(
263
+ ts.factory.createPrefixUnaryExpression(
264
+ ts.SyntaxKind.MinusToken,
265
+ ts.factory.createNumericLiteral(String(Math.abs(val))),
266
+ ),
267
+ );
268
+ }
269
+ return ts.factory.createLiteralTypeNode(ts.factory.createNumericLiteral(String(val)));
270
+ } else if (typeof val === 'boolean') {
271
+ return ts.factory.createLiteralTypeNode(val ? ts.factory.createTrue() : ts.factory.createFalse());
272
+ }
273
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
274
+ });
275
+ return ts.factory.createUnionTypeNode(literalTypes);
276
+ }
277
+
278
+ // Handle type-specific schemas
279
+ switch (prop['type']) {
280
+ case 'string':
281
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
282
+ case 'number':
283
+ case 'integer':
284
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
285
+ case 'boolean':
286
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
287
+ case 'array': {
288
+ const itemsType = prop['items']
289
+ ? this.buildTypeNode(prop['items'])
290
+ : ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
291
+ return ts.factory.createArrayTypeNode(itemsType);
292
+ }
293
+ case 'object': {
294
+ const properties = (prop['properties'] ?? {}) as Record<string, unknown>;
295
+ const requiredProps = (prop['required'] ?? []) as string[];
296
+
297
+ if (Object.keys(properties).length > 0) {
298
+ return this.buildObjectTypeLiteral(properties, requiredProps);
299
+ }
300
+
301
+ // Empty object or additionalProperties - use Record<string, unknown>
302
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Record'), [
303
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
304
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword),
305
+ ]);
306
+ }
307
+ default:
308
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Builds a TypeScript type literal for an object schema.
314
+ */
315
+ private buildObjectTypeLiteral(properties: Record<string, unknown>, requiredProps: string[]): ts.TypeLiteralNode {
316
+ const members = Object.entries(properties).map(([name, propSchema]) => {
317
+ const isRequired = requiredProps.includes(name);
318
+ const typeNode = this.buildTypeNode(propSchema);
319
+
320
+ return ts.factory.createPropertySignature(
321
+ undefined,
322
+ ts.factory.createIdentifier(name),
323
+ isRequired ? undefined : ts.factory.createToken(ts.SyntaxKind.QuestionToken),
324
+ typeNode,
325
+ );
145
326
  });
327
+
328
+ return ts.factory.createTypeLiteralNode(members);
329
+ }
330
+
331
+ /**
332
+ * Builds a TypeScript interface declaration for an object schema.
333
+ */
334
+ private buildInterfaceDeclaration(name: string, schema: Record<string, unknown>): ts.InterfaceDeclaration {
335
+ const properties = (schema['properties'] ?? {}) as Record<string, unknown>;
336
+ const requiredProps = (schema['required'] ?? []) as string[];
337
+
338
+ const members = Object.entries(properties).map(([propName, propSchema]) => {
339
+ const isRequired = requiredProps.includes(propName);
340
+ const typeNode = this.buildTypeNode(propSchema);
341
+
342
+ return ts.factory.createPropertySignature(
343
+ undefined,
344
+ ts.factory.createIdentifier(propName),
345
+ isRequired ? undefined : ts.factory.createToken(ts.SyntaxKind.QuestionToken),
346
+ typeNode,
347
+ );
348
+ });
349
+
350
+ return ts.factory.createInterfaceDeclaration(
351
+ [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
352
+ ts.factory.createIdentifier(name),
353
+ undefined,
354
+ undefined,
355
+ members,
356
+ );
146
357
  }
147
358
 
148
359
  private buildClientClass(
@@ -1085,4 +1085,309 @@ describe('TypeScriptCodeGeneratorService', () => {
1085
1085
  expect(code).toContain('https://{env}.example.com');
1086
1086
  });
1087
1087
  });
1088
+
1089
+ describe('explicit types', () => {
1090
+ it('should generate explicit interface for object schema', () => {
1091
+ const spec: OpenApiSpecType = {
1092
+ openapi: '3.0.0',
1093
+ info: {
1094
+ title: 'Test API',
1095
+ version: '1.0.0',
1096
+ },
1097
+ paths: {},
1098
+ components: {
1099
+ schemas: {
1100
+ Order: {
1101
+ type: 'object',
1102
+ properties: {
1103
+ id: {type: 'integer'},
1104
+ name: {type: 'string'},
1105
+ },
1106
+ required: ['id', 'name'],
1107
+ },
1108
+ },
1109
+ },
1110
+ };
1111
+
1112
+ const code = generator.generate(spec);
1113
+
1114
+ // Should generate explicit interface
1115
+ expect(code).toContain('export interface Order');
1116
+ expect(code).toContain('id: number');
1117
+ expect(code).toContain('name: string');
1118
+
1119
+ // Should add type annotation to schema
1120
+ expect(code).toContain('export const Order: z.ZodType<Order>');
1121
+
1122
+ // Should NOT generate z.infer type export
1123
+ expect(code).not.toContain('z.infer<typeof Order>');
1124
+ });
1125
+
1126
+ it('should generate type alias for enum schema', () => {
1127
+ const spec: OpenApiSpecType = {
1128
+ openapi: '3.0.0',
1129
+ info: {
1130
+ title: 'Test API',
1131
+ version: '1.0.0',
1132
+ },
1133
+ paths: {},
1134
+ components: {
1135
+ schemas: {
1136
+ Status: {
1137
+ type: 'string',
1138
+ enum: ['active', 'inactive', 'pending'],
1139
+ },
1140
+ },
1141
+ },
1142
+ };
1143
+
1144
+ const code = generator.generate(spec);
1145
+
1146
+ // Should generate type alias (not interface) for enum
1147
+ expect(code).toContain('export type Status');
1148
+ expect(code).toContain("'active'");
1149
+ expect(code).toContain("'inactive'");
1150
+ expect(code).toContain("'pending'");
1151
+
1152
+ // Should add type annotation to schema
1153
+ expect(code).toContain('export const Status: z.ZodType<Status>');
1154
+ });
1155
+
1156
+ it('should generate type alias for array schema', () => {
1157
+ const spec: OpenApiSpecType = {
1158
+ openapi: '3.0.0',
1159
+ info: {
1160
+ title: 'Test API',
1161
+ version: '1.0.0',
1162
+ },
1163
+ paths: {},
1164
+ components: {
1165
+ schemas: {
1166
+ Tags: {
1167
+ type: 'array',
1168
+ items: {type: 'string'},
1169
+ },
1170
+ },
1171
+ },
1172
+ };
1173
+
1174
+ const code = generator.generate(spec);
1175
+
1176
+ // Should generate type alias for array
1177
+ expect(code).toContain('export type Tags = string[]');
1178
+
1179
+ // Should add type annotation to schema
1180
+ expect(code).toContain('export const Tags: z.ZodType<Tags>');
1181
+ });
1182
+
1183
+ it('should handle nested objects with references', () => {
1184
+ const spec: OpenApiSpecType = {
1185
+ openapi: '3.0.0',
1186
+ info: {
1187
+ title: 'Test API',
1188
+ version: '1.0.0',
1189
+ },
1190
+ paths: {},
1191
+ components: {
1192
+ schemas: {
1193
+ User: {
1194
+ type: 'object',
1195
+ properties: {
1196
+ id: {type: 'integer'},
1197
+ profile: {$ref: '#/components/schemas/Profile'},
1198
+ },
1199
+ required: ['id'],
1200
+ },
1201
+ Profile: {
1202
+ type: 'object',
1203
+ properties: {
1204
+ name: {type: 'string'},
1205
+ },
1206
+ required: ['name'],
1207
+ },
1208
+ },
1209
+ },
1210
+ };
1211
+
1212
+ const code = generator.generate(spec);
1213
+
1214
+ // Should generate interfaces for both
1215
+ expect(code).toContain('export interface User');
1216
+ expect(code).toContain('export interface Profile');
1217
+
1218
+ // User should reference Profile type
1219
+ expect(code).toContain('profile?: Profile');
1220
+
1221
+ // Both should have type annotations
1222
+ expect(code).toContain('export const User: z.ZodType<User>');
1223
+ expect(code).toContain('export const Profile: z.ZodType<Profile>');
1224
+ });
1225
+
1226
+ it('should handle union types (anyOf)', () => {
1227
+ const spec: OpenApiSpecType = {
1228
+ openapi: '3.0.0',
1229
+ info: {
1230
+ title: 'Test API',
1231
+ version: '1.0.0',
1232
+ },
1233
+ paths: {},
1234
+ components: {
1235
+ schemas: {
1236
+ StringOrNumber: {
1237
+ anyOf: [{type: 'string'}, {type: 'number'}],
1238
+ },
1239
+ },
1240
+ },
1241
+ };
1242
+
1243
+ const code = generator.generate(spec);
1244
+
1245
+ // Should generate type alias for union
1246
+ expect(code).toContain('export type StringOrNumber = string | number');
1247
+
1248
+ // Should add type annotation to schema
1249
+ expect(code).toContain('export const StringOrNumber: z.ZodType<StringOrNumber>');
1250
+ });
1251
+
1252
+ it('should handle intersection types (allOf)', () => {
1253
+ const spec: OpenApiSpecType = {
1254
+ openapi: '3.0.0',
1255
+ info: {
1256
+ title: 'Test API',
1257
+ version: '1.0.0',
1258
+ },
1259
+ paths: {},
1260
+ components: {
1261
+ schemas: {
1262
+ Base: {
1263
+ type: 'object',
1264
+ properties: {
1265
+ id: {type: 'integer'},
1266
+ },
1267
+ required: ['id'],
1268
+ },
1269
+ Extended: {
1270
+ allOf: [
1271
+ {$ref: '#/components/schemas/Base'},
1272
+ {
1273
+ type: 'object',
1274
+ properties: {
1275
+ name: {type: 'string'},
1276
+ },
1277
+ },
1278
+ ],
1279
+ },
1280
+ },
1281
+ },
1282
+ };
1283
+
1284
+ const code = generator.generate(spec);
1285
+
1286
+ // Should generate interface for Base
1287
+ expect(code).toContain('export interface Base');
1288
+
1289
+ // Should generate type alias for Extended (intersection)
1290
+ expect(code).toContain('export type Extended = Base &');
1291
+
1292
+ // Should add type annotations to schemas
1293
+ expect(code).toContain('export const Base: z.ZodType<Base>');
1294
+ expect(code).toContain('export const Extended: z.ZodType<Extended>');
1295
+ });
1296
+
1297
+ it('should handle optional properties', () => {
1298
+ const spec: OpenApiSpecType = {
1299
+ openapi: '3.0.0',
1300
+ info: {
1301
+ title: 'Test API',
1302
+ version: '1.0.0',
1303
+ },
1304
+ paths: {},
1305
+ components: {
1306
+ schemas: {
1307
+ User: {
1308
+ type: 'object',
1309
+ properties: {
1310
+ id: {type: 'integer'},
1311
+ email: {type: 'string'},
1312
+ },
1313
+ required: ['id'],
1314
+ },
1315
+ },
1316
+ },
1317
+ };
1318
+
1319
+ const code = generator.generate(spec);
1320
+
1321
+ // id should be required (no ?)
1322
+ expect(code).toContain('id: number');
1323
+ // email should be optional (with ?)
1324
+ expect(code).toContain('email?: string');
1325
+ });
1326
+
1327
+ it('should handle circular dependencies', () => {
1328
+ const spec: OpenApiSpecType = {
1329
+ openapi: '3.0.0',
1330
+ info: {
1331
+ title: 'Test API',
1332
+ version: '1.0.0',
1333
+ },
1334
+ paths: {},
1335
+ components: {
1336
+ schemas: {
1337
+ Node: {
1338
+ type: 'object',
1339
+ properties: {
1340
+ id: {type: 'integer'},
1341
+ children: {
1342
+ type: 'array',
1343
+ items: {$ref: '#/components/schemas/Node'},
1344
+ },
1345
+ },
1346
+ required: ['id'],
1347
+ },
1348
+ },
1349
+ },
1350
+ };
1351
+
1352
+ const code = generator.generate(spec);
1353
+
1354
+ // Should generate interface with self-reference
1355
+ expect(code).toContain('export interface Node');
1356
+ expect(code).toContain('children?: Node[]');
1357
+
1358
+ // Should add type annotation to schema
1359
+ expect(code).toContain('export const Node: z.ZodType<Node>');
1360
+
1361
+ // Zod schema should use z.lazy for circular reference
1362
+ expect(code).toContain('z.lazy');
1363
+ });
1364
+
1365
+ it('should handle numeric enum types', () => {
1366
+ const spec: OpenApiSpecType = {
1367
+ openapi: '3.0.0',
1368
+ info: {
1369
+ title: 'Test API',
1370
+ version: '1.0.0',
1371
+ },
1372
+ paths: {},
1373
+ components: {
1374
+ schemas: {
1375
+ Priority: {
1376
+ type: 'integer',
1377
+ enum: [0, 1, 2],
1378
+ },
1379
+ },
1380
+ },
1381
+ };
1382
+
1383
+ const code = generator.generate(spec);
1384
+
1385
+ // Should generate type alias for numeric enum
1386
+ expect(code).toContain('export type Priority');
1387
+ expect(code).toMatch(/0\s*\|\s*1\s*\|\s*2/);
1388
+
1389
+ // Should add type annotation to schema
1390
+ expect(code).toContain('export const Priority: z.ZodType<Priority>');
1391
+ });
1392
+ });
1088
1393
  });