zod-codegen 1.5.1 → 1.6.2

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.
Files changed (100) hide show
  1. package/.github/workflows/ci.yml +7 -1
  2. package/.github/workflows/release.yml +3 -3
  3. package/CHANGELOG.md +34 -0
  4. package/CONTRIBUTING.md +1 -1
  5. package/EXAMPLES.md +91 -12
  6. package/README.md +11 -4
  7. package/dist/scripts/add-js-extensions.d.ts +2 -0
  8. package/dist/scripts/add-js-extensions.d.ts.map +1 -0
  9. package/dist/scripts/add-js-extensions.js +66 -0
  10. package/dist/scripts/update-manifest.d.ts +14 -0
  11. package/dist/scripts/update-manifest.d.ts.map +1 -0
  12. package/dist/scripts/update-manifest.js +33 -0
  13. package/dist/src/assets/manifest.json +1 -1
  14. package/dist/src/cli.js +3 -3
  15. package/dist/src/generator.d.ts +46 -4
  16. package/dist/src/generator.d.ts.map +1 -1
  17. package/dist/src/generator.js +43 -1
  18. package/dist/src/interfaces/code-generator.d.ts +1 -1
  19. package/dist/src/interfaces/code-generator.d.ts.map +1 -1
  20. package/dist/src/services/code-generator.service.d.ts +5 -3
  21. package/dist/src/services/code-generator.service.d.ts.map +1 -1
  22. package/dist/src/services/code-generator.service.js +86 -20
  23. package/dist/src/services/file-reader.service.d.ts +2 -2
  24. package/dist/src/services/file-reader.service.d.ts.map +1 -1
  25. package/dist/src/services/file-writer.service.d.ts +1 -1
  26. package/dist/src/services/file-writer.service.d.ts.map +1 -1
  27. package/dist/src/services/import-builder.service.d.ts +1 -1
  28. package/dist/src/services/import-builder.service.d.ts.map +1 -1
  29. package/dist/src/services/type-builder.service.d.ts +1 -1
  30. package/dist/src/services/type-builder.service.d.ts.map +1 -1
  31. package/dist/src/types/generator-options.d.ts +1 -1
  32. package/dist/src/types/generator-options.d.ts.map +1 -1
  33. package/dist/src/utils/error-handler.d.ts +3 -2
  34. package/dist/src/utils/error-handler.d.ts.map +1 -1
  35. package/dist/src/utils/error-handler.js +4 -4
  36. package/dist/src/utils/reporter.d.ts +3 -2
  37. package/dist/src/utils/reporter.d.ts.map +1 -1
  38. package/dist/src/utils/reporter.js +7 -5
  39. package/dist/src/utils/signal-handler.d.ts +3 -2
  40. package/dist/src/utils/signal-handler.d.ts.map +1 -1
  41. package/dist/src/utils/signal-handler.js +4 -4
  42. package/examples/README.md +10 -1
  43. package/examples/petstore/README.md +6 -6
  44. package/examples/petstore/authenticated-usage.ts +1 -1
  45. package/examples/petstore/basic-usage.ts +1 -1
  46. package/examples/petstore/retry-handler-usage.ts +173 -0
  47. package/examples/petstore/server-variables-usage.ts +1 -1
  48. package/examples/petstore/type.ts +76 -53
  49. package/examples/pokeapi/README.md +3 -3
  50. package/examples/pokeapi/basic-usage.ts +1 -1
  51. package/examples/pokeapi/custom-client.ts +1 -1
  52. package/generated/type.ts +326 -0
  53. package/package.json +14 -19
  54. package/scripts/add-js-extensions.ts +79 -0
  55. package/scripts/update-manifest.ts +4 -2
  56. package/src/assets/manifest.json +1 -1
  57. package/src/cli.ts +7 -7
  58. package/src/generator.ts +51 -9
  59. package/src/interfaces/code-generator.ts +1 -1
  60. package/src/services/code-generator.service.ts +256 -122
  61. package/src/services/file-reader.service.ts +3 -3
  62. package/src/services/file-writer.service.ts +1 -1
  63. package/src/services/import-builder.service.ts +1 -1
  64. package/src/services/type-builder.service.ts +1 -1
  65. package/src/types/generator-options.ts +1 -1
  66. package/src/utils/error-handler.ts +6 -5
  67. package/src/utils/reporter.ts +6 -3
  68. package/src/utils/signal-handler.ts +10 -8
  69. package/tests/integration/cli-comprehensive.test.ts +123 -0
  70. package/tests/integration/cli.test.ts +2 -2
  71. package/tests/integration/error-scenarios.test.ts +240 -0
  72. package/tests/integration/snapshots.test.ts +131 -0
  73. package/tests/unit/code-generator-edge-cases.test.ts +551 -0
  74. package/tests/unit/code-generator.test.ts +385 -2
  75. package/tests/unit/file-reader.test.ts +16 -1
  76. package/tests/unit/generator.test.ts +19 -2
  77. package/tests/unit/naming-convention.test.ts +30 -1
  78. package/tests/unit/reporter.test.ts +63 -0
  79. package/tests/unit/type-builder.test.ts +131 -0
  80. package/tsconfig.json +3 -3
  81. package/dist/src/http/fetch-client.d.ts +0 -15
  82. package/dist/src/http/fetch-client.d.ts.map +0 -1
  83. package/dist/src/http/fetch-client.js +0 -140
  84. package/dist/src/polyfills/fetch.d.ts +0 -5
  85. package/dist/src/polyfills/fetch.d.ts.map +0 -1
  86. package/dist/src/polyfills/fetch.js +0 -18
  87. package/dist/src/types/http.d.ts +0 -25
  88. package/dist/src/types/http.d.ts.map +0 -1
  89. package/dist/src/types/http.js +0 -10
  90. package/dist/src/utils/manifest.d.ts +0 -8
  91. package/dist/src/utils/manifest.d.ts.map +0 -1
  92. package/dist/src/utils/manifest.js +0 -9
  93. package/dist/src/utils/tty.d.ts +0 -2
  94. package/dist/src/utils/tty.d.ts.map +0 -1
  95. package/dist/src/utils/tty.js +0 -3
  96. package/src/http/fetch-client.ts +0 -181
  97. package/src/polyfills/fetch.ts +0 -26
  98. package/src/types/http.ts +0 -35
  99. package/src/utils/manifest.ts +0 -17
  100. package/src/utils/tty.ts +0 -3
@@ -76,7 +76,7 @@ jobs:
76
76
  run: npm ci
77
77
 
78
78
  - name: Run security audit
79
- run: npm audit --audit-level=high
79
+ run: npm audit --audit-level=high --omit=dev
80
80
 
81
81
  build:
82
82
  name: Build & Package
@@ -137,6 +137,12 @@ jobs:
137
137
  - name: Build project
138
138
  run: npm run build
139
139
 
140
+ - name: Verify build output
141
+ run: |
142
+ test -f dist/src/cli.js || (echo "ERROR: dist/src/cli.js not found" && exit 1)
143
+ test -f dist/src/utils/reporter.js || (echo "ERROR: dist/src/utils/reporter.js not found" && exit 1)
144
+ echo "Build output verified successfully"
145
+
140
146
  - name: Preview semantic-release
141
147
  env:
142
148
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -44,12 +44,12 @@ jobs:
44
44
  - name: Run formatter check
45
45
  run: npm run format:check
46
46
 
47
- - name: Run tests with coverage
48
- run: npm run test:coverage
49
-
50
47
  - name: Build project
51
48
  run: npm run build
52
49
 
50
+ - name: Run tests with coverage
51
+ run: npm run test:coverage
52
+
53
53
  - name: Test CLI functionality
54
54
  run: |
55
55
  echo '{"openapi": "3.0.0", "info": {"title": "Test", "version": "1.0.0"}, "paths": {}}' > test-openapi.json
package/CHANGELOG.md CHANGED
@@ -1,3 +1,37 @@
1
+ ## <small>1.6.2 (2026-01-19)</small>
2
+
3
+ - 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)
4
+ - chore(deps): bump the dev-dependencies group across 1 directory with 5 updates (#57) ([30110fd](https://github.com/julienandreu/zod-codegen/commit/30110fd)), closes [#57](https://github.com/julienandreu/zod-codegen/issues/57)
5
+
6
+ ## <small>1.6.1 (2026-01-09)</small>
7
+
8
+ - Merge pull request #55 from julienandreu/fix/integration-tests-timeout ([1e48796](https://github.com/julienandreu/zod-codegen/commit/1e48796)), closes [#55](https://github.com/julienandreu/zod-codegen/issues/55)
9
+ - fix: remove npm build from integration tests to prevent timeouts ([1cfceac](https://github.com/julienandreu/zod-codegen/commit/1cfceac))
10
+
11
+ ## 1.6.0 (2026-01-09)
12
+
13
+ - Merge pull request #54 from julienandreu/feat/response-handling-policies ([3f99c8f](https://github.com/julienandreu/zod-codegen/commit/3f99c8f)), closes [#54](https://github.com/julienandreu/zod-codegen/issues/54)
14
+ - fix: add path mapping for zod-codegen/policies in examples ([d3dd5c9](https://github.com/julienandreu/zod-codegen/commit/d3dd5c9))
15
+ - fix: export policies from package.json ([c1a3344](https://github.com/julienandreu/zod-codegen/commit/c1a3344))
16
+ - fix: prevent duplicate method names for HEAD/OPTIONS with same operationId ([8c0b891](https://github.com/julienandreu/zod-codegen/commit/8c0b891))
17
+ - fix: remove invalid semver-diff override causing CI failure ([278db05](https://github.com/julienandreu/zod-codegen/commit/278db05))
18
+ - fix: remove unnecessary Promise.resolve in error handler ([d730ef4](https://github.com/julienandreu/zod-codegen/commit/d730ef4))
19
+ - fix: update example to use zod-codegen/policies import path ([c7e3b07](https://github.com/julienandreu/zod-codegen/commit/c7e3b07))
20
+ - fix: update TypeScript module resolution for Node.js ESM compatibility ([2d8f6a0](https://github.com/julienandreu/zod-codegen/commit/2d8f6a0))
21
+ - fix: use extensionless imports in TypeScript source files ([dc0698c](https://github.com/julienandreu/zod-codegen/commit/dc0698c))
22
+ - ci: add build output verification step to diagnose module resolution issue ([5174320](https://github.com/julienandreu/zod-codegen/commit/5174320))
23
+ - docs: fix examples documentation ([04d6db8](https://github.com/julienandreu/zod-codegen/commit/04d6db8))
24
+ - docs: update Node.js version requirement in CONTRIBUTING.md ([16cdc1e](https://github.com/julienandreu/zod-codegen/commit/16cdc1e))
25
+ - docs: update PR description with latest test count ([f2ef4a8](https://github.com/julienandreu/zod-codegen/commit/f2ef4a8))
26
+ - test: add comprehensive test suite to increase confidence ([48a7e2d](https://github.com/julienandreu/zod-codegen/commit/48a7e2d))
27
+ - test: add tests for buildBasicTypeFromSchema edge cases ([c567c51](https://github.com/julienandreu/zod-codegen/commit/c567c51))
28
+ - test: improve code coverage for code-generator.service.ts ([edbc92a](https://github.com/julienandreu/zod-codegen/commit/edbc92a))
29
+ - refactor: completely remove policy system ([7c6439a](https://github.com/julienandreu/zod-codegen/commit/7c6439a))
30
+ - refactor: implement quality improvements ([a5b1b14](https://github.com/julienandreu/zod-codegen/commit/a5b1b14))
31
+ - refactor: remove policies export, keep zod-codegen as dev-dependency ([4eae513](https://github.com/julienandreu/zod-codegen/commit/4eae513))
32
+ - refactor: remove unused code and improve Reporter ([51ae06a](https://github.com/julienandreu/zod-codegen/commit/51ae06a))
33
+ - feat: add response handling policies system ([ad98229](https://github.com/julienandreu/zod-codegen/commit/ad98229))
34
+
1
35
  ## <small>1.5.1 (2026-01-05)</small>
2
36
 
3
37
  - Merge pull request #52 from julienandreu/dependabot/npm_and_yarn/production-dependencies-3204786a64 ([c2fa562](https://github.com/julienandreu/zod-codegen/commit/c2fa562)), closes [#52](https://github.com/julienandreu/zod-codegen/issues/52)
package/CONTRIBUTING.md CHANGED
@@ -21,7 +21,7 @@ This project adheres to a code of conduct. By participating, you are expected to
21
21
 
22
22
  ### Prerequisites
23
23
 
24
- - Node.js >= 24.11.1
24
+ - Node.js >= 18.0.0
25
25
  - yarn
26
26
  - Git
27
27
 
package/EXAMPLES.md CHANGED
@@ -13,7 +13,7 @@ All examples below demonstrate how to extend the generated client class to add t
13
13
  ### Example: Adding Bearer Token Authentication
14
14
 
15
15
  ```typescript
16
- import {SwaggerPetstoreOpenAPI30, ClientOptions} from './generated/type.js';
16
+ import {SwaggerPetstoreOpenAPI30, ClientOptions} from './generated/type';
17
17
 
18
18
  class AuthenticatedPetstoreAPI extends SwaggerPetstoreOpenAPI30 {
19
19
  private accessToken: string | null = null;
@@ -69,7 +69,7 @@ void main();
69
69
  ### Example: Session Management with Token Refresh
70
70
 
71
71
  ```typescript
72
- import {SwaggerPetstoreOpenAPI30} from './generated/type.js';
72
+ import {SwaggerPetstoreOpenAPI30} from './generated/type';
73
73
 
74
74
  class SessionManagedPetstoreAPI extends SwaggerPetstoreOpenAPI30 {
75
75
  private accessToken: string | null = null;
@@ -132,7 +132,7 @@ class SessionManagedPetstoreAPI extends SwaggerPetstoreOpenAPI30 {
132
132
  If you need to pass custom headers for specific requests, you can extend the client and add helper methods:
133
133
 
134
134
  ```typescript
135
- import {SwaggerPetstoreOpenAPI30, ClientOptions} from './generated/type.js';
135
+ import {SwaggerPetstoreOpenAPI30, ClientOptions} from './generated/type';
136
136
 
137
137
  class CustomHeadersPetstoreAPI extends SwaggerPetstoreOpenAPI30 {
138
138
  constructor(options: ClientOptions = {}) {
@@ -159,7 +159,7 @@ class CustomHeadersPetstoreAPI extends SwaggerPetstoreOpenAPI30 {
159
159
  ### Example: API Key Authentication
160
160
 
161
161
  ```typescript
162
- import {SwaggerPetstoreOpenAPI30, ClientOptions} from './generated/type.js';
162
+ import {SwaggerPetstoreOpenAPI30, ClientOptions} from './generated/type';
163
163
 
164
164
  class ApiKeyAuthenticatedPetstoreAPI extends SwaggerPetstoreOpenAPI30 {
165
165
  constructor(options: ClientOptions & {apiKey: string}) {
@@ -185,7 +185,7 @@ class ApiKeyAuthenticatedPetstoreAPI extends SwaggerPetstoreOpenAPI30 {
185
185
  ### Example: Using AbortController for Request Cancellation
186
186
 
187
187
  ```typescript
188
- import {SwaggerPetstoreOpenAPI30, ClientOptions} from './generated/type.js';
188
+ import {SwaggerPetstoreOpenAPI30, ClientOptions} from './generated/type';
189
189
 
190
190
  class CancellablePetstoreAPI extends SwaggerPetstoreOpenAPI30 {
191
191
  constructor(options: ClientOptions = {}) {
@@ -220,7 +220,7 @@ client.cancelRequests();
220
220
  ### Example: Custom Credentials and CORS Mode
221
221
 
222
222
  ```typescript
223
- import {SwaggerPetstoreOpenAPI30, ClientOptions} from './generated/type.js';
223
+ import {SwaggerPetstoreOpenAPI30, ClientOptions} from './generated/type';
224
224
 
225
225
  class CustomCorsPetstoreAPI extends SwaggerPetstoreOpenAPI30 {
226
226
  constructor(options: ClientOptions = {}) {
@@ -249,7 +249,7 @@ grep
249
249
  Here's a comprehensive example showing how to combine CORS settings, custom User-Agent, and authentication:
250
250
 
251
251
  ```typescript
252
- import {SwaggerPetstoreOpenAPI30, ClientOptions} from './generated/type.js';
252
+ import {SwaggerPetstoreOpenAPI30, ClientOptions} from './generated/type';
253
253
 
254
254
  class FullyConfiguredPetstoreAPI extends SwaggerPetstoreOpenAPI30 {
255
255
  private accessToken: string | null = null;
@@ -315,7 +315,7 @@ const pets = await client.findPetsByStatus('available');
315
315
  You can also create different configurations for different environments:
316
316
 
317
317
  ```typescript
318
- import {SwaggerPetstoreOpenAPI30, ClientOptions} from './generated/type.js';
318
+ import {SwaggerPetstoreOpenAPI30, ClientOptions} from './generated/type';
319
319
 
320
320
  interface ClientConfig {
321
321
  userAgent?: string;
@@ -595,7 +595,7 @@ class RobustAPI extends YourAPI {
595
595
  ### Pattern 1: Simple Authentication
596
596
 
597
597
  ```typescript
598
- import {YourAPI, ClientOptions} from './generated/type.js';
598
+ import {YourAPI, ClientOptions} from './generated/type';
599
599
 
600
600
  class SimpleAuthAPI extends YourAPI {
601
601
  private token: string | null = null;
@@ -620,7 +620,7 @@ class SimpleAuthAPI extends YourAPI {
620
620
  ### Pattern 2: Multiple Headers
621
621
 
622
622
  ```typescript
623
- import {YourAPI, ClientOptions} from './generated/type.js';
623
+ import {YourAPI, ClientOptions} from './generated/type';
624
624
 
625
625
  class MultiHeaderAPI extends YourAPI {
626
626
  constructor(options: ClientOptions = {}) {
@@ -645,7 +645,7 @@ class MultiHeaderAPI extends YourAPI {
645
645
  ### Pattern 3: Conditional Options
646
646
 
647
647
  ```typescript
648
- import {YourAPI, ClientOptions} from './generated/type.js';
648
+ import {YourAPI, ClientOptions} from './generated/type';
649
649
 
650
650
  class ConditionalAPI extends YourAPI {
651
651
  constructor(options: ClientOptions = {}) {
@@ -702,7 +702,7 @@ return {
702
702
  **Solution**: Store token as instance property:
703
703
 
704
704
  ```typescript
705
- import {YourAPI, ClientOptions} from './generated/type.js';
705
+ import {YourAPI, ClientOptions} from './generated/type';
706
706
 
707
707
  class MyAPI extends YourAPI {
708
708
  private token: string | null = null; // ✅ Instance property
@@ -728,3 +728,82 @@ protected getBaseRequestOptions(): Partial<Omit<RequestInit, 'method' | 'body'>>
728
728
  // ✅ Correct return type
729
729
  }
730
730
  ```
731
+
732
+ ## Response Handling
733
+
734
+ The generated client includes a protected `handleResponse()` method that you can override to implement custom response handling logic such as retries, logging, and error transformation.
735
+
736
+ ### Understanding handleResponse
737
+
738
+ The `handleResponse()` method is called **before** error checking, allowing you to:
739
+
740
+ - Intercept responses and handle special cases
741
+ - Implement retry logic for specific status codes
742
+ - Log requests and responses
743
+ - Transform or modify responses
744
+
745
+ **Method Signature:**
746
+
747
+ ```typescript
748
+ protected async handleResponse<T>(
749
+ response: Response,
750
+ method: string,
751
+ path: string,
752
+ options: {
753
+ params?: Record<string, string | number | boolean>;
754
+ data?: unknown;
755
+ contentType?: string;
756
+ headers?: Record<string, string>;
757
+ },
758
+ ): Promise<Response>
759
+ ```
760
+
761
+ ### Example: Basic Retry Handler
762
+
763
+ ```typescript
764
+ import {SwaggerPetstoreOpenAPI30} from './generated/type';
765
+
766
+ class PetstoreClientWithRetry extends SwaggerPetstoreOpenAPI30 {
767
+ private retrying = false;
768
+
769
+ protected async handleResponse<T>(
770
+ response: Response,
771
+ method: string,
772
+ path: string,
773
+ options: {...},
774
+ ): Promise<Response> {
775
+ // Prevent infinite loops
776
+ if (this.retrying) {
777
+ return response;
778
+ }
779
+
780
+ // Handle 429 Too Many Requests
781
+ if (response.status === 429) {
782
+ const retryAfter = response.headers.get('Retry-After');
783
+ const delay = retryAfter ? parseInt(retryAfter, 10) * 1000 : 1000;
784
+
785
+ for (let attempt = 0; attempt < 3; attempt++) {
786
+ await new Promise((resolve) => setTimeout(resolve, delay * (attempt + 1)));
787
+
788
+ this.retrying = true;
789
+ try {
790
+ const retryResponse = await this.retryRequest(method, path, options);
791
+ if (retryResponse.ok) {
792
+ return retryResponse;
793
+ }
794
+ } finally {
795
+ this.retrying = false;
796
+ }
797
+ }
798
+ }
799
+
800
+ return response;
801
+ }
802
+
803
+ private async retryRequest(...): Promise<Response> {
804
+ // Reconstruct and make the request
805
+ }
806
+ }
807
+ ```
808
+
809
+ See [examples/petstore/retry-handler-usage.ts](./examples/petstore/retry-handler-usage.ts) for a complete example.
package/README.md CHANGED
@@ -20,6 +20,7 @@ A powerful TypeScript code generator that creates **Zod schemas** and **type-saf
20
20
  - **🛡️ Runtime Validation**: Built-in Zod validation for request/response data
21
21
  - **🌍 Form Support**: Supports both JSON and form-urlencoded request bodies
22
22
  - **🔐 Extensible**: Override `getBaseRequestOptions()` to add authentication, custom headers, CORS, and other fetch options
23
+ - **🔄 Response Handling**: Override `handleResponse()` to implement custom retry logic, logging, and error handling
23
24
  - **🌐 Server Configuration**: Full support for OpenAPI server variables and templating (e.g., `{environment}.example.com`)
24
25
  - **⚙️ Flexible Client Options**: Options-based constructor supporting server selection, variable overrides, and custom base URLs
25
26
 
@@ -145,7 +146,9 @@ The generator creates a single TypeScript file (`type.ts`) containing:
145
146
  - **API Client Class**: A type-safe client class with methods for each endpoint operation
146
147
  - **Server Configuration**: `serverConfigurations` array and `defaultBaseUrl` constant extracted from OpenAPI servers
147
148
  - **Client Options Type**: `ClientOptions` type for flexible server selection and variable overrides
148
- - **Protected Extension Point**: A `getBaseRequestOptions()` method that can be overridden for customization
149
+ - **Protected Extension Points**:
150
+ - `getBaseRequestOptions()` method for customizing request options
151
+ - `handleResponse()` method for response handling (retries, circuit breakers, etc.)
149
152
 
150
153
  ### Generated Client Structure
151
154
 
@@ -164,6 +167,9 @@ export class YourAPI {
164
167
  // Protected method - override to customize request options
165
168
  protected getBaseRequestOptions(): Partial<Omit<RequestInit, 'method' | 'body'>>;
166
169
 
170
+ // Protected method - override to handle responses (retries, circuit breakers, etc.)
171
+ protected async handleResponse<T>(response: Response, method: string, path: string, options: {...}): Promise<Response>;
172
+
167
173
  // Private method - handles all HTTP requests
168
174
  async #makeRequest<T>(method: string, path: string, options: {...}): Promise<T>;
169
175
 
@@ -289,7 +295,7 @@ export class UserAPI {
289
295
  **Usage:**
290
296
 
291
297
  ```typescript
292
- import {UserAPI, User} from './generated/type.js';
298
+ import {UserAPI, User} from './generated/type';
293
299
 
294
300
  // Use default server from OpenAPI spec
295
301
  const client = new UserAPI({});
@@ -310,7 +316,7 @@ The generated client includes a protected `getBaseRequestOptions()` method that
310
316
  #### Basic Authentication Example
311
317
 
312
318
  ```typescript
313
- import {UserAPI, ClientOptions} from './generated/type.js';
319
+ import {UserAPI, ClientOptions} from './generated/type';
314
320
 
315
321
  class AuthenticatedUserAPI extends UserAPI {
316
322
  private accessToken: string | null = null;
@@ -344,7 +350,7 @@ const user = await client.getUserById(123); // Includes Authorization header
344
350
  #### Complete Configuration Example
345
351
 
346
352
  ```typescript
347
- import {UserAPI, ClientOptions} from './generated/type.js';
353
+ import {UserAPI, ClientOptions} from './generated/type';
348
354
 
349
355
  class FullyConfiguredAPI extends UserAPI {
350
356
  private accessToken: string | null = null;
@@ -403,6 +409,7 @@ See [EXAMPLES.md](EXAMPLES.md) for comprehensive examples including:
403
409
  - CORS configuration
404
410
  - Request cancellation with AbortController
405
411
  - Environment-specific configurations
412
+ - Response handling with custom retry logic and error handling
406
413
 
407
414
  ## 📖 Examples
408
415
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=add-js-extensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-js-extensions.d.ts","sourceRoot":"","sources":["../../scripts/add-js-extensions.ts"],"names":[],"mappings":""}
@@ -0,0 +1,66 @@
1
+ import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
2
+ import { extname, join } from 'node:path';
3
+ /**
4
+ * Recursively finds all .js files in a directory
5
+ */
6
+ function findJsFiles(dir) {
7
+ const files = [];
8
+ const entries = readdirSync(dir);
9
+ for (const entry of entries) {
10
+ const fullPath = join(dir, entry);
11
+ const stat = statSync(fullPath);
12
+ if (stat.isDirectory()) {
13
+ files.push(...findJsFiles(fullPath));
14
+ }
15
+ else if (extname(entry) === '.js') {
16
+ files.push(fullPath);
17
+ }
18
+ }
19
+ return files;
20
+ }
21
+ /**
22
+ * Adds .js extensions to relative imports in a JavaScript file
23
+ */
24
+ function addJsExtensions(content) {
25
+ // Match relative imports: './something' or '../something' but not './something.js' or node: imports
26
+ // Handles both single and double quotes
27
+ // Also handles type imports: import type { ... } from './something'
28
+ const importRegex = /from\s+(['"])(\.\.?\/[^'"]+?)(['"])/g;
29
+ return content.replace(importRegex, (match, quote, importPath, endQuote) => {
30
+ // Skip if already has an extension
31
+ if (importPath.endsWith('.js') || importPath.endsWith('.json')) {
32
+ return match;
33
+ }
34
+ // Add .js extension
35
+ return `from ${quote}${importPath}.js${endQuote}`;
36
+ });
37
+ }
38
+ /**
39
+ * Main function to process all JavaScript files in dist/src
40
+ */
41
+ function main() {
42
+ const distDir = join(process.cwd(), 'dist', 'src');
43
+ try {
44
+ const jsFiles = findJsFiles(distDir);
45
+ if (jsFiles.length === 0) {
46
+ console.warn('No .js files found in dist/src');
47
+ process.exit(0);
48
+ }
49
+ let processedCount = 0;
50
+ for (const filePath of jsFiles) {
51
+ const content = readFileSync(filePath, 'utf-8');
52
+ const updatedContent = addJsExtensions(content);
53
+ if (content !== updatedContent) {
54
+ writeFileSync(filePath, updatedContent, 'utf-8');
55
+ processedCount++;
56
+ }
57
+ }
58
+ console.log(`✅ Added .js extensions to ${String(processedCount)} file(s)`);
59
+ process.exit(0);
60
+ }
61
+ catch (error) {
62
+ console.error('❌ Error processing files:', error);
63
+ process.exit(1);
64
+ }
65
+ }
66
+ main();
@@ -0,0 +1,14 @@
1
+ interface PackageJson {
2
+ name: string;
3
+ version: string;
4
+ description: string;
5
+ }
6
+ /**
7
+ * Type guard for the package.json object
8
+ *
9
+ * @param input Unknown input
10
+ * @returns true if the input is an event object
11
+ */
12
+ export declare function isPackageJson(input: unknown): input is PackageJson;
13
+ export {};
14
+ //# sourceMappingURL=update-manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-manifest.d.ts","sourceRoot":"","sources":["../../scripts/update-manifest.ts"],"names":[],"mappings":"AAKA,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAclE"}
@@ -0,0 +1,33 @@
1
+ import { readFileSync, writeFileSync } from 'node:fs';
2
+ import { dirname, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { z } from 'zod';
5
+ /**
6
+ * Type guard for the package.json object
7
+ *
8
+ * @param input Unknown input
9
+ * @returns true if the input is an event object
10
+ */
11
+ export function isPackageJson(input) {
12
+ const event = z
13
+ .object({
14
+ name: z.string(),
15
+ version: z.string(),
16
+ description: z.string(),
17
+ })
18
+ .strict()
19
+ .catchall(z.any())
20
+ .required();
21
+ const { success } = event.safeParse(input);
22
+ return success;
23
+ }
24
+ const __dirname = dirname(fileURLToPath(import.meta.url));
25
+ const sourcePath = resolve(__dirname, '..', 'package.json');
26
+ const data = JSON.parse(readFileSync(sourcePath, 'utf8'));
27
+ if (!isPackageJson(data)) {
28
+ process.exit(1);
29
+ }
30
+ const { name, version, description } = data;
31
+ const targetPath = resolve(__dirname, '..', 'src', 'assets', 'manifest.json');
32
+ writeFileSync(targetPath, JSON.stringify({ name, version, description }, null, 2));
33
+ process.exit(0);
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "zod-codegen",
3
- "version": "1.0.1",
3
+ "version": "1.5.0",
4
4
  "description": "A powerful TypeScript code generator that creates Zod schemas and type-safe clients from OpenAPI specifications"
5
5
  }
package/dist/src/cli.js CHANGED
@@ -37,12 +37,12 @@ if (!packageJsonPath) {
37
37
  }
38
38
  const packageData = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
39
39
  const { name, description, version } = packageData;
40
- const reporter = new Reporter(process.stdout);
40
+ const reporter = new Reporter(process.stdout, process.stderr);
41
41
  const startTime = process.hrtime.bigint();
42
42
  debug(`${name}:${String(process.pid)}`);
43
43
  loudRejection();
44
- handleSignals(process, startTime);
45
- handleErrors(process, startTime);
44
+ handleSignals(process, startTime, reporter);
45
+ handleErrors(process, startTime, reporter);
46
46
  const argv = yargs(hideBin(process.argv))
47
47
  .scriptName(name)
48
48
  .usage(`${description}\n\nUsage: $0 [options]`)
@@ -1,7 +1,34 @@
1
- import type { Reporter } from './utils/reporter.js';
2
- import type { GeneratorOptions } from './types/generator-options.js';
3
- export type { GeneratorOptions } from './types/generator-options.js';
4
- export type { NamingConvention, OperationDetails, OperationNameTransformer } from './utils/naming-convention.js';
1
+ import type { Reporter } from './utils/reporter';
2
+ import type { GeneratorOptions } from './types/generator-options';
3
+ export type { GeneratorOptions } from './types/generator-options';
4
+ export type { NamingConvention, OperationDetails, OperationNameTransformer } from './utils/naming-convention';
5
+ /**
6
+ * Main generator class for creating TypeScript code from OpenAPI specifications.
7
+ *
8
+ * This class orchestrates the code generation process:
9
+ * 1. Reads the OpenAPI specification file (local or remote)
10
+ * 2. Parses and validates the specification
11
+ * 3. Generates TypeScript code with Zod schemas and type-safe API client
12
+ * 4. Writes the generated code to the output directory
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import {Generator} from 'zod-codegen';
17
+ * import {Reporter} from './utils/reporter';
18
+ *
19
+ * const reporter = new Reporter(process.stdout, process.stderr);
20
+ * const generator = new Generator(
21
+ * 'my-app',
22
+ * '1.0.0',
23
+ * reporter,
24
+ * './openapi.yaml',
25
+ * './generated',
26
+ * {namingConvention: 'camelCase'}
27
+ * );
28
+ *
29
+ * const exitCode = await generator.run();
30
+ * ```
31
+ */
5
32
  export declare class Generator {
6
33
  private readonly _name;
7
34
  private readonly _version;
@@ -13,7 +40,22 @@ export declare class Generator {
13
40
  private readonly codeGenerator;
14
41
  private readonly fileWriter;
15
42
  private readonly outputPath;
43
+ /**
44
+ * Creates a new Generator instance.
45
+ *
46
+ * @param _name - The name of the application/library (used in generated file headers)
47
+ * @param _version - The version of the application/library (used in generated file headers)
48
+ * @param reporter - Reporter instance for logging messages and errors
49
+ * @param inputPath - Path or URL to the OpenAPI specification file
50
+ * @param _outputDir - Directory where generated files will be written
51
+ * @param options - Optional configuration for code generation
52
+ */
16
53
  constructor(_name: string, _version: string, reporter: Reporter, inputPath: string, _outputDir: string, options?: GeneratorOptions);
54
+ /**
55
+ * Executes the code generation process.
56
+ *
57
+ * @returns Promise that resolves to an exit code (0 for success, 1 for failure)
58
+ */
17
59
  run(): Promise<number>;
18
60
  private readFile;
19
61
  private parseFile;
@@ -1 +1 @@
1
- {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,qBAAqB,CAAC;AAElD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,8BAA8B,CAAC;AAMnE,YAAY,EAAC,gBAAgB,EAAC,MAAM,8BAA8B,CAAC;AACnE,YAAY,EAAC,gBAAgB,EAAE,gBAAgB,EAAE,wBAAwB,EAAC,MAAM,8BAA8B,CAAC;AAE/G,qBAAa,SAAS;IAQlB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAX7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA+B;IAC1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkC;IAC7D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiC;IAC/D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAwB;IACnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAGjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EACnC,OAAO,GAAE,gBAAqB;IAO1B,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;YAqBd,QAAQ;IAItB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,SAAS;CAGlB"}
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAE/C,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAMhE,YAAY,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAChE,YAAY,EAAC,gBAAgB,EAAE,gBAAgB,EAAE,wBAAwB,EAAC,MAAM,2BAA2B,CAAC;AAE5G;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,SAAS;IAkBlB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IArB7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA+B;IAC1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkC;IAC7D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiC;IAC/D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAwB;IACnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC;;;;;;;;;OASG;gBAEgB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EACnC,OAAO,GAAE,gBAAqB;IAOhC;;;;OAIG;IACG,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;YAqBd,QAAQ;IAItB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,SAAS;CAGlB"}
@@ -1,6 +1,33 @@
1
1
  import { OpenApiFileParserService, SyncFileReaderService } from './services/file-reader.service.js';
2
2
  import { TypeScriptCodeGeneratorService } from './services/code-generator.service.js';
3
3
  import { SyncFileWriterService } from './services/file-writer.service.js';
4
+ /**
5
+ * Main generator class for creating TypeScript code from OpenAPI specifications.
6
+ *
7
+ * This class orchestrates the code generation process:
8
+ * 1. Reads the OpenAPI specification file (local or remote)
9
+ * 2. Parses and validates the specification
10
+ * 3. Generates TypeScript code with Zod schemas and type-safe API client
11
+ * 4. Writes the generated code to the output directory
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import {Generator} from 'zod-codegen';
16
+ * import {Reporter} from './utils/reporter.js';
17
+ *
18
+ * const reporter = new Reporter(process.stdout, process.stderr);
19
+ * const generator = new Generator(
20
+ * 'my-app',
21
+ * '1.0.0',
22
+ * reporter,
23
+ * './openapi.yaml',
24
+ * './generated',
25
+ * {namingConvention: 'camelCase'}
26
+ * );
27
+ *
28
+ * const exitCode = await generator.run();
29
+ * ```
30
+ */
4
31
  export class Generator {
5
32
  _name;
6
33
  _version;
@@ -12,6 +39,16 @@ export class Generator {
12
39
  codeGenerator;
13
40
  fileWriter;
14
41
  outputPath;
42
+ /**
43
+ * Creates a new Generator instance.
44
+ *
45
+ * @param _name - The name of the application/library (used in generated file headers)
46
+ * @param _version - The version of the application/library (used in generated file headers)
47
+ * @param reporter - Reporter instance for logging messages and errors
48
+ * @param inputPath - Path or URL to the OpenAPI specification file
49
+ * @param _outputDir - Directory where generated files will be written
50
+ * @param options - Optional configuration for code generation
51
+ */
15
52
  constructor(_name, _version, reporter, inputPath, _outputDir, options = {}) {
16
53
  this._name = _name;
17
54
  this._version = _version;
@@ -22,6 +59,11 @@ export class Generator {
22
59
  this.outputPath = this.fileWriter.resolveOutputPath(this._outputDir);
23
60
  this.codeGenerator = new TypeScriptCodeGeneratorService(options);
24
61
  }
62
+ /**
63
+ * Executes the code generation process.
64
+ *
65
+ * @returns Promise that resolves to an exit code (0 for success, 1 for failure)
66
+ */
25
67
  async run() {
26
68
  try {
27
69
  const rawSource = await this.readFile();
@@ -38,7 +80,7 @@ export class Generator {
38
80
  else {
39
81
  this.reporter.error('❌ An unknown error occurred');
40
82
  }
41
- return Promise.resolve(1);
83
+ return 1;
42
84
  }
43
85
  }
44
86
  async readFile() {
@@ -1,4 +1,4 @@
1
- import type { OpenApiSpecType } from '../types/openapi.js';
1
+ import type { OpenApiSpecType } from '../types/openapi';
2
2
  export interface CodeGenerator {
3
3
  generate(spec: OpenApiSpecType): string;
4
4
  }
@@ -1 +1 @@
1
- {"version":3,"file":"code-generator.d.ts","sourceRoot":"","sources":["../../../src/interfaces/code-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,qBAAqB,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC3D;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,IAAI,OAAO,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC;CAC5C;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACpE"}
1
+ {"version":3,"file":"code-generator.d.ts","sourceRoot":"","sources":["../../../src/interfaces/code-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC3D;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,IAAI,OAAO,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC;CAC5C;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACpE"}