zod-codegen 1.2.0 → 1.2.1

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,8 @@
1
+ ## <small>1.2.1 (2025-11-19)</small>
2
+
3
+ - Merge pull request #33 from julienandreu/fix/add-z-infer-to-response-types ([a14d81c](https://github.com/julienandreu/zod-codegen/commit/a14d81c)), closes [#33](https://github.com/julienandreu/zod-codegen/issues/33)
4
+ - fix: add z.infer to response types in generated methods ([c45ac77](https://github.com/julienandreu/zod-codegen/commit/c45ac77))
5
+
1
6
  ## 1.2.0 (2025-11-19)
2
7
 
3
8
  - Merge pull request #31 from julienandreu/dependabot/npm_and_yarn/dev-dependencies-1dd8918b9f ([97ebb65](https://github.com/julienandreu/zod-codegen/commit/97ebb65)), closes [#31](https://github.com/julienandreu/zod-codegen/issues/31)
@@ -516,9 +516,36 @@ export class TypeScriptCodeGeneratorService {
516
516
  }
517
517
  const responseSchema = response.content['application/json'].schema;
518
518
  const typeName = this.getSchemaTypeName(responseSchema, schemas);
519
- return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [
520
- ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(typeName), undefined),
521
- ]);
519
+ const inferredType = this.wrapTypeWithZInfer(typeName, schemas);
520
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [inferredType]);
521
+ }
522
+ wrapTypeWithZInfer(typeName, schemas) {
523
+ // Primitive types and Record types don't need z.infer
524
+ const primitiveTypes = ['string', 'number', 'boolean', 'unknown'];
525
+ if (primitiveTypes.includes(typeName) || typeName.startsWith('Record<')) {
526
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(typeName), undefined);
527
+ }
528
+ // Handle array types like "Pet[]"
529
+ if (typeName.endsWith('[]')) {
530
+ const itemTypeName = typeName.slice(0, -2);
531
+ const sanitizedItemTypeName = this.typeBuilder.sanitizeIdentifier(itemTypeName);
532
+ // Check if the item type is a custom schema
533
+ if (schemas[sanitizedItemTypeName]) {
534
+ // Return z.infer<typeof ItemType>[]
535
+ const zInferType = ts.factory.createTypeReferenceNode(ts.factory.createQualifiedName(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('infer')), [ts.factory.createTypeQueryNode(ts.factory.createIdentifier(sanitizedItemTypeName), undefined)]);
536
+ return ts.factory.createArrayTypeNode(zInferType);
537
+ }
538
+ // If it's a primitive array, return as-is
539
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(typeName), undefined);
540
+ }
541
+ // Handle custom schema types
542
+ const sanitizedTypeName = this.typeBuilder.sanitizeIdentifier(typeName);
543
+ if (schemas[sanitizedTypeName]) {
544
+ // Return z.infer<typeof TypeName>
545
+ return ts.factory.createTypeReferenceNode(ts.factory.createQualifiedName(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('infer')), [ts.factory.createTypeQueryNode(ts.factory.createIdentifier(sanitizedTypeName), undefined)]);
546
+ }
547
+ // Fallback: return as-is if we can't determine
548
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(typeName), undefined);
522
549
  }
523
550
  buildServerConfiguration(openapi) {
524
551
  const servers = openapi.servers;
@@ -1,6 +1,6 @@
1
1
  // THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2
- // Built with zod-codegen@1.0.1
3
- // Latest edit: Thu, 13 Nov 2025 13:36:35 GMT
2
+ // Built with zod-codegen@1.1.2
3
+ // Latest edit: Wed, 19 Nov 2025 16:26:25 GMT
4
4
  // Source file: ./samples/swagger-petstore.yaml
5
5
  /* eslint-disable */
6
6
  // @ts-nocheck
@@ -144,73 +144,209 @@ export class SwaggerPetstoreOpenAPI30 {
144
144
  if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
145
145
  return await response.json();
146
146
  }
147
- async addPet(body: Pet): Promise<Pet> {
147
+ /**
148
+ * Add a new pet to the store
149
+ * @param body Create a new pet in the store
150
+ * @returns {z.infer<typeof Pet>}
151
+ */
152
+ async addPet(body: Pet): Promise<z.infer<typeof Pet>> {
148
153
  return Pet.parse(
149
154
  await this.#makeRequest('POST', '/pet', {data: body, contentType: 'application/x-www-form-urlencoded'}),
150
155
  );
151
156
  }
152
- async updatePet(body: Pet): Promise<Pet> {
157
+ /**
158
+ * Update an existing pet
159
+ *
160
+ * Update an existing pet by Id
161
+ * @param body Update an existent pet in the store
162
+ * @returns {z.infer<typeof Pet>}
163
+ */
164
+ async updatePet(body: Pet): Promise<z.infer<typeof Pet>> {
153
165
  return Pet.parse(
154
166
  await this.#makeRequest('PUT', '/pet', {data: body, contentType: 'application/x-www-form-urlencoded'}),
155
167
  );
156
168
  }
157
- async findPetsByStatus(status?: string): Promise<Pet[]> {
169
+ /**
170
+ * Finds Pets by status
171
+ *
172
+ * Multiple status values can be provided with comma separated strings
173
+ *
174
+ * @param status Status values that need to be considered for filter
175
+ * @returns {z.infer<typeof Pet>[]}
176
+ */
177
+ async findPetsByStatus(status?: string): Promise<z.infer<typeof Pet>[]> {
158
178
  return await this.#makeRequest('GET', '/pet/findByStatus', {params: {status: status}});
159
179
  }
160
- async findPetsByTags(tags?: string[]): Promise<Pet[]> {
180
+ /**
181
+ * Finds Pets by tags
182
+ *
183
+ * Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.
184
+ *
185
+ * @param tags Tags to filter by
186
+ * @returns {z.infer<typeof Pet>[]}
187
+ */
188
+ async findPetsByTags(tags?: string[]): Promise<z.infer<typeof Pet>[]> {
161
189
  return await this.#makeRequest('GET', '/pet/findByTags', {params: {tags: tags}});
162
190
  }
163
- async getPetById(petId: number): Promise<Pet> {
191
+ /**
192
+ * Find pet by ID
193
+ *
194
+ * Returns a single pet
195
+ *
196
+ * @param petId ID of pet to return
197
+ * @returns {z.infer<typeof Pet>}
198
+ */
199
+ async getPetById(petId: number): Promise<z.infer<typeof Pet>> {
164
200
  return Pet.parse(await this.#makeRequest('GET', `/pet/${petId}`, {}));
165
201
  }
202
+ /**
203
+ * Updates a pet in the store with form data
204
+ *
205
+ * @param petId ID of pet that needs to be updated
206
+ * @param name Name of pet that needs to be updated
207
+ * @param status Status of pet that needs to be updated
208
+ * @returns {void}
209
+ */
166
210
  async updatePetWithForm(petId: number, name?: string, status?: string): Promise<void> {
167
211
  return await this.#makeRequest('POST', `/pet/${petId}`, {params: {name: name, status: status}});
168
212
  }
213
+ /**
214
+ * Deletes a pet
215
+ *
216
+ * delete a pet
217
+ *
218
+ * @param api_key
219
+ * @param petId Pet id to delete
220
+ * @returns {void}
221
+ */
169
222
  async deletePet(petId: number): Promise<void> {
170
223
  return await this.#makeRequest('DELETE', `/pet/${petId}`, {});
171
224
  }
172
- async uploadFile(petId: number, additionalMetadata?: string): Promise<ApiResponse> {
225
+ /**
226
+ * uploads an image
227
+ *
228
+ * @param petId ID of pet to update
229
+ * @param additionalMetadata Additional Metadata
230
+ * @param body
231
+ * @returns {z.infer<typeof ApiResponse>}
232
+ */
233
+ async uploadFile(petId: number, additionalMetadata?: string): Promise<z.infer<typeof ApiResponse>> {
173
234
  return ApiResponse.parse(
174
235
  await this.#makeRequest('POST', `/pet/${petId}/uploadImage`, {params: {additionalMetadata: additionalMetadata}}),
175
236
  );
176
237
  }
238
+ /**
239
+ * Returns pet inventories by status
240
+ *
241
+ * Returns a map of status codes to quantities
242
+ * @returns {Record<string, unknown>}
243
+ */
177
244
  async getInventory(): Promise<Record<string, unknown>> {
178
245
  return await this.#makeRequest('GET', '/store/inventory', {});
179
246
  }
180
- async placeOrder(body?: Order): Promise<Order> {
247
+ /**
248
+ * Place an order for a pet
249
+ *
250
+ * Place a new order in the store
251
+ * @param body
252
+ * @returns {z.infer<typeof Order>}
253
+ */
254
+ async placeOrder(body?: Order): Promise<z.infer<typeof Order>> {
181
255
  return Order.parse(
182
256
  await this.#makeRequest('POST', '/store/order', {data: body, contentType: 'application/x-www-form-urlencoded'}),
183
257
  );
184
258
  }
185
- async getOrderById(orderId: number): Promise<Order> {
259
+ /**
260
+ * Find purchase order by ID
261
+ *
262
+ * For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.
263
+ *
264
+ * @param orderId ID of order that needs to be fetched
265
+ * @returns {z.infer<typeof Order>}
266
+ */
267
+ async getOrderById(orderId: number): Promise<z.infer<typeof Order>> {
186
268
  return Order.parse(await this.#makeRequest('GET', `/store/order/${orderId}`, {}));
187
269
  }
270
+ /**
271
+ * Delete purchase order by ID
272
+ *
273
+ * For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
274
+ *
275
+ * @param orderId ID of the order that needs to be deleted
276
+ * @returns {void}
277
+ */
188
278
  async deleteOrder(orderId: number): Promise<void> {
189
279
  return await this.#makeRequest('DELETE', `/store/order/${orderId}`, {});
190
280
  }
191
- async createUser(body?: User): Promise<User> {
281
+ /**
282
+ * Create user
283
+ *
284
+ * This can only be done by the logged in user.
285
+ * @param body Created user object
286
+ * @returns {z.infer<typeof User>}
287
+ */
288
+ async createUser(body?: User): Promise<z.infer<typeof User>> {
192
289
  return User.parse(
193
290
  await this.#makeRequest('POST', '/user', {data: body, contentType: 'application/x-www-form-urlencoded'}),
194
291
  );
195
292
  }
196
- async createUsersWithListInput(body?: User[]): Promise<User> {
293
+ /**
294
+ * Creates list of users with given input array
295
+ * @param body
296
+ * @returns {z.infer<typeof User>}
297
+ */
298
+ async createUsersWithListInput(body?: User[]): Promise<z.infer<typeof User>> {
197
299
  return User.parse(await this.#makeRequest('POST', '/user/createWithList', {data: body}));
198
300
  }
301
+ /**
302
+ * Logs user into the system
303
+ *
304
+ * @param username The user name for login
305
+ * @param password The password for login in clear text
306
+ * @returns {string}
307
+ */
199
308
  async loginUser(username?: string, password?: string): Promise<string> {
200
309
  return await this.#makeRequest('GET', '/user/login', {params: {username: username, password: password}});
201
310
  }
311
+ /**
312
+ * Logs out current logged in user session
313
+ * @returns {void}
314
+ */
202
315
  async logoutUser(): Promise<void> {
203
316
  return await this.#makeRequest('GET', '/user/logout', {});
204
317
  }
205
- async getUserByName(username: string): Promise<User> {
318
+ /**
319
+ * Get user by user name
320
+ *
321
+ * @param username The name that needs to be fetched. Use user1 for testing.
322
+ * @returns {z.infer<typeof User>}
323
+ */
324
+ async getUserByName(username: string): Promise<z.infer<typeof User>> {
206
325
  return User.parse(await this.#makeRequest('GET', `/user/${username}`, {}));
207
326
  }
327
+ /**
328
+ * Update user
329
+ *
330
+ * This can only be done by the logged in user.
331
+ *
332
+ * @param username name that need to be deleted
333
+ * @param body Update an existent user in the store
334
+ * @returns {void}
335
+ */
208
336
  async updateUser(username: string, body?: User): Promise<void> {
209
337
  return await this.#makeRequest('PUT', `/user/${username}`, {
210
338
  data: body,
211
339
  contentType: 'application/x-www-form-urlencoded',
212
340
  });
213
341
  }
342
+ /**
343
+ * Delete user
344
+ *
345
+ * This can only be done by the logged in user.
346
+ *
347
+ * @param username The name that needs to be deleted
348
+ * @returns {void}
349
+ */
214
350
  async deleteUser(username: string): Promise<void> {
215
351
  return await this.#makeRequest('DELETE', `/user/${username}`, {});
216
352
  }
package/package.json CHANGED
@@ -110,5 +110,5 @@
110
110
  "release": "semantic-release",
111
111
  "release:dry": "semantic-release --dry-run"
112
112
  },
113
- "version": "1.2.0"
113
+ "version": "1.2.1"
114
114
  }
@@ -1264,10 +1264,48 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1264
1264
 
1265
1265
  const responseSchema = response.content['application/json'].schema;
1266
1266
  const typeName = this.getSchemaTypeName(responseSchema, schemas);
1267
+ const inferredType = this.wrapTypeWithZInfer(typeName, schemas);
1267
1268
 
1268
- return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [
1269
- ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(typeName), undefined),
1270
- ]);
1269
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [inferredType]);
1270
+ }
1271
+
1272
+ private wrapTypeWithZInfer(typeName: string, schemas: Record<string, ts.VariableStatement>): ts.TypeNode {
1273
+ // Primitive types and Record types don't need z.infer
1274
+ const primitiveTypes = ['string', 'number', 'boolean', 'unknown'];
1275
+ if (primitiveTypes.includes(typeName) || typeName.startsWith('Record<')) {
1276
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(typeName), undefined);
1277
+ }
1278
+
1279
+ // Handle array types like "Pet[]"
1280
+ if (typeName.endsWith('[]')) {
1281
+ const itemTypeName = typeName.slice(0, -2);
1282
+ const sanitizedItemTypeName = this.typeBuilder.sanitizeIdentifier(itemTypeName);
1283
+
1284
+ // Check if the item type is a custom schema
1285
+ if (schemas[sanitizedItemTypeName]) {
1286
+ // Return z.infer<typeof ItemType>[]
1287
+ const zInferType = ts.factory.createTypeReferenceNode(
1288
+ ts.factory.createQualifiedName(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('infer')),
1289
+ [ts.factory.createTypeQueryNode(ts.factory.createIdentifier(sanitizedItemTypeName), undefined)],
1290
+ );
1291
+ return ts.factory.createArrayTypeNode(zInferType);
1292
+ }
1293
+ // If it's a primitive array, return as-is
1294
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(typeName), undefined);
1295
+ }
1296
+
1297
+ // Handle custom schema types
1298
+ const sanitizedTypeName = this.typeBuilder.sanitizeIdentifier(typeName);
1299
+ if (schemas[sanitizedTypeName]) {
1300
+ // Return z.infer<typeof TypeName>
1301
+ return ts.factory.createTypeReferenceNode(
1302
+ ts.factory.createQualifiedName(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('infer')),
1303
+ [ts.factory.createTypeQueryNode(ts.factory.createIdentifier(sanitizedTypeName), undefined)],
1304
+ );
1305
+ }
1306
+
1307
+ // Fallback: return as-is if we can't determine
1308
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(typeName), undefined);
1271
1309
  }
1272
1310
 
1273
1311
  private buildServerConfiguration(openapi: OpenApiSpecType): ts.Statement[] {