zod-codegen 1.6.2 → 1.7.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.
Files changed (119) hide show
  1. package/.github/workflows/ci.yml +50 -48
  2. package/.github/workflows/release.yml +13 -3
  3. package/.husky/commit-msg +1 -1
  4. package/.husky/pre-commit +1 -1
  5. package/.lintstagedrc.json +5 -1
  6. package/.nvmrc +1 -1
  7. package/.prettierrc.json +12 -5
  8. package/CHANGELOG.md +15 -0
  9. package/CONTRIBUTING.md +12 -12
  10. package/EXAMPLES.md +135 -57
  11. package/PERFORMANCE.md +4 -4
  12. package/README.md +87 -64
  13. package/SECURITY.md +1 -1
  14. package/dist/src/cli.js +11 -18
  15. package/dist/src/generator.d.ts +2 -2
  16. package/dist/src/generator.d.ts.map +1 -1
  17. package/dist/src/generator.js +5 -3
  18. package/dist/src/interfaces/code-generator.d.ts.map +1 -1
  19. package/dist/src/services/code-generator.service.d.ts +24 -1
  20. package/dist/src/services/code-generator.service.d.ts.map +1 -1
  21. package/dist/src/services/code-generator.service.js +385 -216
  22. package/dist/src/services/file-reader.service.d.ts.map +1 -1
  23. package/dist/src/services/file-reader.service.js +1 -1
  24. package/dist/src/services/file-writer.service.d.ts.map +1 -1
  25. package/dist/src/services/file-writer.service.js +2 -2
  26. package/dist/src/services/import-builder.service.d.ts.map +1 -1
  27. package/dist/src/services/import-builder.service.js +3 -3
  28. package/dist/src/services/type-builder.service.d.ts.map +1 -1
  29. package/dist/src/types/generator-options.d.ts.map +1 -1
  30. package/dist/src/types/openapi.d.ts.map +1 -1
  31. package/dist/src/types/openapi.js +20 -20
  32. package/dist/src/utils/error-handler.d.ts.map +1 -1
  33. package/dist/src/utils/naming-convention.d.ts.map +1 -1
  34. package/dist/src/utils/naming-convention.js +6 -3
  35. package/dist/src/utils/signal-handler.d.ts.map +1 -1
  36. package/dist/tests/integration/cli-comprehensive.test.d.ts +2 -0
  37. package/dist/tests/integration/cli-comprehensive.test.d.ts.map +1 -0
  38. package/dist/tests/integration/cli-comprehensive.test.js +110 -0
  39. package/dist/tests/integration/cli.test.d.ts +2 -0
  40. package/dist/tests/integration/cli.test.d.ts.map +1 -0
  41. package/dist/tests/integration/cli.test.js +25 -0
  42. package/dist/tests/integration/error-scenarios.test.d.ts +2 -0
  43. package/dist/tests/integration/error-scenarios.test.d.ts.map +1 -0
  44. package/dist/tests/integration/error-scenarios.test.js +169 -0
  45. package/dist/tests/integration/snapshots.test.d.ts +2 -0
  46. package/dist/tests/integration/snapshots.test.d.ts.map +1 -0
  47. package/dist/tests/integration/snapshots.test.js +100 -0
  48. package/dist/tests/unit/code-generator-edge-cases.test.d.ts +2 -0
  49. package/dist/tests/unit/code-generator-edge-cases.test.d.ts.map +1 -0
  50. package/dist/tests/unit/code-generator-edge-cases.test.js +506 -0
  51. package/dist/tests/unit/code-generator.test.d.ts +2 -0
  52. package/dist/tests/unit/code-generator.test.d.ts.map +1 -0
  53. package/dist/tests/unit/code-generator.test.js +1364 -0
  54. package/dist/tests/unit/file-reader.test.d.ts +2 -0
  55. package/dist/tests/unit/file-reader.test.d.ts.map +1 -0
  56. package/dist/tests/unit/file-reader.test.js +125 -0
  57. package/dist/tests/unit/generator.test.d.ts +2 -0
  58. package/dist/tests/unit/generator.test.d.ts.map +1 -0
  59. package/dist/tests/unit/generator.test.js +119 -0
  60. package/dist/tests/unit/naming-convention.test.d.ts +2 -0
  61. package/dist/tests/unit/naming-convention.test.d.ts.map +1 -0
  62. package/dist/tests/unit/naming-convention.test.js +256 -0
  63. package/dist/tests/unit/reporter.test.d.ts +2 -0
  64. package/dist/tests/unit/reporter.test.d.ts.map +1 -0
  65. package/dist/tests/unit/reporter.test.js +44 -0
  66. package/dist/tests/unit/type-builder.test.d.ts +2 -0
  67. package/dist/tests/unit/type-builder.test.d.ts.map +1 -0
  68. package/dist/tests/unit/type-builder.test.js +108 -0
  69. package/dist/vitest.config.d.ts.map +1 -1
  70. package/dist/vitest.config.js +10 -20
  71. package/eslint.config.mjs +38 -28
  72. package/examples/.gitkeep +1 -1
  73. package/examples/README.md +4 -2
  74. package/examples/petstore/README.md +18 -17
  75. package/examples/petstore/{type.ts → api.ts} +158 -74
  76. package/examples/petstore/authenticated-usage.ts +6 -4
  77. package/examples/petstore/basic-usage.ts +4 -3
  78. package/examples/petstore/error-handling-usage.ts +84 -0
  79. package/examples/petstore/retry-handler-usage.ts +11 -18
  80. package/examples/petstore/server-variables-usage.ts +10 -10
  81. package/examples/pokeapi/README.md +8 -8
  82. package/examples/pokeapi/api.ts +218 -0
  83. package/examples/pokeapi/basic-usage.ts +3 -2
  84. package/examples/pokeapi/custom-client.ts +5 -4
  85. package/package.json +17 -21
  86. package/src/cli.ts +20 -25
  87. package/src/generator.ts +13 -11
  88. package/src/interfaces/code-generator.ts +1 -1
  89. package/src/services/code-generator.service.ts +989 -1099
  90. package/src/services/file-reader.service.ts +6 -5
  91. package/src/services/file-writer.service.ts +7 -7
  92. package/src/services/import-builder.service.ts +9 -13
  93. package/src/services/type-builder.service.ts +8 -19
  94. package/src/types/generator-options.ts +1 -1
  95. package/src/types/openapi.ts +22 -22
  96. package/src/utils/error-handler.ts +2 -2
  97. package/src/utils/naming-convention.ts +13 -10
  98. package/src/utils/reporter.ts +2 -2
  99. package/src/utils/signal-handler.ts +7 -8
  100. package/tests/integration/cli-comprehensive.test.ts +38 -32
  101. package/tests/integration/cli.test.ts +5 -5
  102. package/tests/integration/error-scenarios.test.ts +20 -26
  103. package/tests/integration/snapshots.test.ts +19 -23
  104. package/tests/unit/code-generator-edge-cases.test.ts +133 -133
  105. package/tests/unit/code-generator.test.ts +674 -268
  106. package/tests/unit/file-reader.test.ts +14 -14
  107. package/tests/unit/generator.test.ts +30 -18
  108. package/tests/unit/naming-convention.test.ts +27 -27
  109. package/tests/unit/type-builder.test.ts +2 -2
  110. package/tsconfig.json +5 -3
  111. package/vitest.config.ts +11 -21
  112. package/dist/scripts/update-manifest.d.ts +0 -14
  113. package/dist/scripts/update-manifest.d.ts.map +0 -1
  114. package/dist/scripts/update-manifest.js +0 -33
  115. package/dist/src/assets/manifest.json +0 -5
  116. package/examples/pokeapi/type.ts +0 -109
  117. package/generated/type.ts +0 -326
  118. package/scripts/update-manifest.ts +0 -49
  119. package/src/assets/manifest.json +0 -5
@@ -1,10 +1,9 @@
1
- import {describe, expect, it, vi, beforeEach, afterEach} from 'vitest';
2
- import {Generator} from '../../src/generator';
3
- import {Reporter} from '../../src/utils/reporter';
4
- import {readFileSync, existsSync, mkdirSync, rmSync, writeFileSync} from 'node:fs';
5
- import {join} from 'node:path';
6
- import {fileURLToPath} from 'node:url';
7
- import {dirname} from 'node:path';
1
+ import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
5
+ import { Generator } from '../../src/generator';
6
+ import { Reporter } from '../../src/utils/reporter';
8
7
 
9
8
  const __dirname = dirname(fileURLToPath(import.meta.url));
10
9
  const testOutputDir = join(__dirname, '../../test-output-errors');
@@ -17,13 +16,14 @@ describe('Error Scenarios', () => {
17
16
 
18
17
  beforeEach(() => {
19
18
  if (existsSync(testOutputDir)) {
20
- rmSync(testOutputDir, {recursive: true, force: true});
19
+ rmSync(testOutputDir, { recursive: true, force: true });
21
20
  }
22
- mkdirSync(testOutputDir, {recursive: true});
21
+
22
+ mkdirSync(testOutputDir, { recursive: true });
23
23
 
24
24
  mockReporter = {
25
25
  log: logSpy,
26
- error: errorSpy,
26
+ error: errorSpy
27
27
  } as unknown as Reporter;
28
28
 
29
29
  logSpy.mockClear();
@@ -32,7 +32,7 @@ describe('Error Scenarios', () => {
32
32
 
33
33
  afterEach(() => {
34
34
  if (existsSync(testOutputDir)) {
35
- rmSync(testOutputDir, {recursive: true, force: true});
35
+ rmSync(testOutputDir, { recursive: true, force: true });
36
36
  }
37
37
  });
38
38
 
@@ -44,7 +44,7 @@ describe('Error Scenarios', () => {
44
44
 
45
45
  expect(exitCode).toBe(1);
46
46
  expect(errorSpy).toHaveBeenCalled();
47
- expect(errorSpy.mock.calls[0][0]).toContain('Error');
47
+ expect(String(errorSpy.mock.calls[0]?.[0] ?? '')).toContain('Error');
48
48
  });
49
49
 
50
50
  it('should handle network errors when fetching URL', async () => {
@@ -52,13 +52,7 @@ describe('Error Scenarios', () => {
52
52
  const mockFetch = vi.fn().mockRejectedValue(new Error('Network error'));
53
53
  global.fetch = mockFetch;
54
54
 
55
- generator = new Generator(
56
- 'test-app',
57
- '1.0.0',
58
- mockReporter,
59
- 'https://example.com/nonexistent.json',
60
- testOutputDir,
61
- );
55
+ generator = new Generator('test-app', '1.0.0', mockReporter, 'https://example.com/nonexistent.json', testOutputDir);
62
56
 
63
57
  const exitCode = await generator.run();
64
58
 
@@ -75,7 +69,7 @@ describe('Error Scenarios', () => {
75
69
  ok: false,
76
70
  status: 500,
77
71
  statusText: 'Internal Server Error',
78
- text: async () => 'Error response',
72
+ text: async () => 'Error response'
79
73
  } as Response);
80
74
  global.fetch = mockFetch;
81
75
 
@@ -86,7 +80,7 @@ describe('Error Scenarios', () => {
86
80
  expect(exitCode).toBe(1);
87
81
  expect(errorSpy).toHaveBeenCalled();
88
82
  // Error should mention the HTTP error or parsing failure
89
- const errorMessage = errorSpy.mock.calls[0][0] as string;
83
+ const errorMessage = (errorSpy.mock.calls[0]?.[0] ?? '') as string;
90
84
  expect(errorMessage).toMatch(/500|Error|Failed/);
91
85
 
92
86
  global.fetch = originalFetch;
@@ -128,7 +122,7 @@ info:
128
122
  title: Test API
129
123
  version: 1.0.0
130
124
  paths: {}
131
- `,
125
+ `
132
126
  );
133
127
 
134
128
  generator = new Generator('test-app', '1.0.0', mockReporter, invalidFile, testOutputDir);
@@ -146,7 +140,7 @@ paths: {}
146
140
  `
147
141
  openapi: 3.0.0
148
142
  paths: {}
149
- `,
143
+ `
150
144
  );
151
145
 
152
146
  generator = new Generator('test-app', '1.0.0', mockReporter, invalidFile, testOutputDir);
@@ -162,7 +156,7 @@ paths: {}
162
156
  it('should handle write permission errors gracefully', async () => {
163
157
  // Create a read-only directory (on Unix systems)
164
158
  const readOnlyDir = join(testOutputDir, 'readonly');
165
- mkdirSync(readOnlyDir, {recursive: true});
159
+ mkdirSync(readOnlyDir, { recursive: true });
166
160
  // Note: chmod doesn't work the same way on all systems, so this test
167
161
  // might need to be adjusted based on the environment
168
162
 
@@ -198,7 +192,7 @@ info:
198
192
  title: Test API
199
193
  version: 1.0.0
200
194
  paths: {}
201
- `,
195
+ `
202
196
  );
203
197
 
204
198
  generator = new Generator('test-app', '1.0.0', mockReporter, noPathsFile, testOutputDir);
@@ -226,7 +220,7 @@ paths:
226
220
  responses:
227
221
  '200':
228
222
  description: Success
229
- `,
223
+ `
230
224
  );
231
225
 
232
226
  generator = new Generator('test-app', '1.0.0', mockReporter, noComponentsFile, testOutputDir);
@@ -1,11 +1,9 @@
1
- import {describe, expect, it} from 'vitest';
2
- import {Generator} from '../../src/generator';
3
- import {Reporter} from '../../src/utils/reporter';
4
- import {readFileSync, existsSync, mkdirSync, rmSync, writeFileSync} from 'node:fs';
5
- import {join} from 'node:path';
6
- import {fileURLToPath} from 'node:url';
7
- import {dirname} from 'node:path';
8
- import {execSync} from 'node:child_process';
1
+ import { existsSync, mkdirSync, readFileSync, rmSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { describe, expect, it } from 'vitest';
5
+ import { Generator } from '../../src/generator';
6
+ import { Reporter } from '../../src/utils/reporter';
9
7
 
10
8
  const __dirname = dirname(fileURLToPath(import.meta.url));
11
9
  const testOutputDir = join(__dirname, '../../test-output-snapshots');
@@ -16,14 +14,15 @@ describe('Generated Code Snapshots', () => {
16
14
 
17
15
  beforeEach(() => {
18
16
  if (existsSync(testOutputDir)) {
19
- rmSync(testOutputDir, {recursive: true, force: true});
17
+ rmSync(testOutputDir, { recursive: true, force: true });
20
18
  }
21
- mkdirSync(testOutputDir, {recursive: true});
19
+
20
+ mkdirSync(testOutputDir, { recursive: true });
22
21
  });
23
22
 
24
23
  afterEach(() => {
25
24
  if (existsSync(testOutputDir)) {
26
- rmSync(testOutputDir, {recursive: true, force: true});
25
+ rmSync(testOutputDir, { recursive: true, force: true });
27
26
  }
28
27
  });
29
28
 
@@ -34,7 +33,7 @@ describe('Generated Code Snapshots', () => {
34
33
  const exitCode = await generator.run();
35
34
  expect(exitCode).toBe(0);
36
35
 
37
- const outputFile = join(testOutputDir, 'type.ts');
36
+ const outputFile = join(testOutputDir, 'api.ts');
38
37
  expect(existsSync(outputFile)).toBe(true);
39
38
 
40
39
  const content = readFileSync(outputFile, 'utf-8');
@@ -49,6 +48,9 @@ describe('Generated Code Snapshots', () => {
49
48
  expect(content).toContain('async addPet');
50
49
  expect(content).toContain('protected getBaseRequestOptions');
51
50
  expect(content).toContain('protected async handleResponse');
51
+ expect(content).toContain('class ResponseValidationError<T> extends Error');
52
+ expect(content).toContain('Pet.safeParse(response)');
53
+ expect(content).toContain('new ResponseValidationError<Pet>');
52
54
  });
53
55
 
54
56
  it('should generate syntactically valid TypeScript code', async () => {
@@ -56,7 +58,7 @@ describe('Generated Code Snapshots', () => {
56
58
 
57
59
  await generator.run();
58
60
 
59
- const outputFile = join(testOutputDir, 'type.ts');
61
+ const outputFile = join(testOutputDir, 'api.ts');
60
62
  const content = readFileSync(outputFile, 'utf-8');
61
63
 
62
64
  // Verify basic TypeScript syntax
@@ -78,7 +80,7 @@ describe('Generated Code Snapshots', () => {
78
80
 
79
81
  await generator.run();
80
82
 
81
- const outputFile = join(testOutputDir, 'type.ts');
83
+ const outputFile = join(testOutputDir, 'api.ts');
82
84
  const content = readFileSync(outputFile, 'utf-8');
83
85
 
84
86
  // Verify logical operators are generated correctly
@@ -93,17 +95,11 @@ describe('Generated Code Snapshots', () => {
93
95
 
94
96
  describe('server-variables-example.yaml', () => {
95
97
  it('should generate server configuration with variables', async () => {
96
- generator = new Generator(
97
- 'test-app',
98
- '1.0.0',
99
- reporter,
100
- './samples/server-variables-example.yaml',
101
- testOutputDir,
102
- );
98
+ generator = new Generator('test-app', '1.0.0', reporter, './samples/server-variables-example.yaml', testOutputDir);
103
99
 
104
100
  await generator.run();
105
101
 
106
- const outputFile = join(testOutputDir, 'type.ts');
102
+ const outputFile = join(testOutputDir, 'api.ts');
107
103
  const content = readFileSync(outputFile, 'utf-8');
108
104
 
109
105
  // Verify server variables are handled
@@ -120,7 +116,7 @@ describe('Generated Code Snapshots', () => {
120
116
 
121
117
  await generator.run();
122
118
 
123
- const outputFile = join(testOutputDir, 'type.ts');
119
+ const outputFile = join(testOutputDir, 'api.ts');
124
120
  const content = readFileSync(outputFile, 'utf-8');
125
121
 
126
122
  expect(content).toMatch(/export (default )?class/);