zod-codegen 1.6.3 → 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.
- package/.github/workflows/ci.yml +50 -48
- package/.github/workflows/release.yml +13 -3
- package/.husky/commit-msg +1 -1
- package/.husky/pre-commit +1 -1
- package/.lintstagedrc.json +5 -1
- package/.nvmrc +1 -1
- package/.prettierrc.json +12 -5
- package/CHANGELOG.md +11 -0
- package/CONTRIBUTING.md +12 -12
- package/EXAMPLES.md +135 -57
- package/PERFORMANCE.md +4 -4
- package/README.md +87 -64
- package/SECURITY.md +1 -1
- package/dist/src/cli.js +11 -18
- package/dist/src/generator.d.ts +2 -2
- package/dist/src/generator.d.ts.map +1 -1
- package/dist/src/generator.js +5 -3
- package/dist/src/interfaces/code-generator.d.ts.map +1 -1
- package/dist/src/services/code-generator.service.d.ts +3 -1
- package/dist/src/services/code-generator.service.d.ts.map +1 -1
- package/dist/src/services/code-generator.service.js +236 -219
- package/dist/src/services/file-reader.service.d.ts.map +1 -1
- package/dist/src/services/file-reader.service.js +1 -1
- package/dist/src/services/file-writer.service.d.ts.map +1 -1
- package/dist/src/services/file-writer.service.js +2 -2
- package/dist/src/services/import-builder.service.d.ts.map +1 -1
- package/dist/src/services/import-builder.service.js +3 -3
- package/dist/src/services/type-builder.service.d.ts.map +1 -1
- package/dist/src/types/generator-options.d.ts.map +1 -1
- package/dist/src/types/openapi.d.ts.map +1 -1
- package/dist/src/types/openapi.js +20 -20
- package/dist/src/utils/error-handler.d.ts.map +1 -1
- package/dist/src/utils/naming-convention.d.ts.map +1 -1
- package/dist/src/utils/naming-convention.js +6 -3
- package/dist/src/utils/signal-handler.d.ts.map +1 -1
- package/dist/tests/integration/cli-comprehensive.test.d.ts +2 -0
- package/dist/tests/integration/cli-comprehensive.test.d.ts.map +1 -0
- package/dist/tests/integration/cli-comprehensive.test.js +110 -0
- package/dist/tests/integration/cli.test.d.ts +2 -0
- package/dist/tests/integration/cli.test.d.ts.map +1 -0
- package/dist/tests/integration/cli.test.js +25 -0
- package/dist/tests/integration/error-scenarios.test.d.ts +2 -0
- package/dist/tests/integration/error-scenarios.test.d.ts.map +1 -0
- package/dist/tests/integration/error-scenarios.test.js +169 -0
- package/dist/tests/integration/snapshots.test.d.ts +2 -0
- package/dist/tests/integration/snapshots.test.d.ts.map +1 -0
- package/dist/tests/integration/snapshots.test.js +100 -0
- package/dist/tests/unit/code-generator-edge-cases.test.d.ts +2 -0
- package/dist/tests/unit/code-generator-edge-cases.test.d.ts.map +1 -0
- package/dist/tests/unit/code-generator-edge-cases.test.js +506 -0
- package/dist/tests/unit/code-generator.test.d.ts +2 -0
- package/dist/tests/unit/code-generator.test.d.ts.map +1 -0
- package/dist/tests/unit/code-generator.test.js +1364 -0
- package/dist/tests/unit/file-reader.test.d.ts +2 -0
- package/dist/tests/unit/file-reader.test.d.ts.map +1 -0
- package/dist/tests/unit/file-reader.test.js +125 -0
- package/dist/tests/unit/generator.test.d.ts +2 -0
- package/dist/tests/unit/generator.test.d.ts.map +1 -0
- package/dist/tests/unit/generator.test.js +119 -0
- package/dist/tests/unit/naming-convention.test.d.ts +2 -0
- package/dist/tests/unit/naming-convention.test.d.ts.map +1 -0
- package/dist/tests/unit/naming-convention.test.js +256 -0
- package/dist/tests/unit/reporter.test.d.ts +2 -0
- package/dist/tests/unit/reporter.test.d.ts.map +1 -0
- package/dist/tests/unit/reporter.test.js +44 -0
- package/dist/tests/unit/type-builder.test.d.ts +2 -0
- package/dist/tests/unit/type-builder.test.d.ts.map +1 -0
- package/dist/tests/unit/type-builder.test.js +108 -0
- package/dist/vitest.config.d.ts.map +1 -1
- package/dist/vitest.config.js +10 -20
- package/eslint.config.mjs +38 -28
- package/examples/.gitkeep +1 -1
- package/examples/README.md +4 -2
- package/examples/petstore/README.md +18 -17
- package/examples/petstore/{type.ts → api.ts} +158 -74
- package/examples/petstore/authenticated-usage.ts +6 -4
- package/examples/petstore/basic-usage.ts +4 -3
- package/examples/petstore/error-handling-usage.ts +84 -0
- package/examples/petstore/retry-handler-usage.ts +11 -18
- package/examples/petstore/server-variables-usage.ts +10 -10
- package/examples/pokeapi/README.md +8 -8
- package/examples/pokeapi/api.ts +218 -0
- package/examples/pokeapi/basic-usage.ts +3 -2
- package/examples/pokeapi/custom-client.ts +5 -4
- package/package.json +17 -21
- package/src/cli.ts +20 -25
- package/src/generator.ts +13 -11
- package/src/interfaces/code-generator.ts +1 -1
- package/src/services/code-generator.service.ts +799 -1120
- package/src/services/file-reader.service.ts +6 -5
- package/src/services/file-writer.service.ts +7 -7
- package/src/services/import-builder.service.ts +9 -13
- package/src/services/type-builder.service.ts +8 -19
- package/src/types/generator-options.ts +1 -1
- package/src/types/openapi.ts +22 -22
- package/src/utils/error-handler.ts +2 -2
- package/src/utils/naming-convention.ts +13 -10
- package/src/utils/reporter.ts +2 -2
- package/src/utils/signal-handler.ts +7 -8
- package/tests/integration/cli-comprehensive.test.ts +38 -32
- package/tests/integration/cli.test.ts +5 -5
- package/tests/integration/error-scenarios.test.ts +20 -26
- package/tests/integration/snapshots.test.ts +19 -23
- package/tests/unit/code-generator-edge-cases.test.ts +133 -133
- package/tests/unit/code-generator.test.ts +431 -330
- package/tests/unit/file-reader.test.ts +14 -14
- package/tests/unit/generator.test.ts +30 -18
- package/tests/unit/naming-convention.test.ts +27 -27
- package/tests/unit/type-builder.test.ts +2 -2
- package/tsconfig.json +5 -3
- package/vitest.config.ts +11 -21
- package/dist/scripts/update-manifest.d.ts +0 -14
- package/dist/scripts/update-manifest.d.ts.map +0 -1
- package/dist/scripts/update-manifest.js +0 -33
- package/dist/src/assets/manifest.json +0 -5
- package/examples/pokeapi/type.ts +0 -109
- package/generated/type.ts +0 -371
- package/scripts/update-manifest.ts +0 -49
- package/src/assets/manifest.json +0 -5
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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
|
-
|
|
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 {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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
|
-
|
|
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, '
|
|
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, '
|
|
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, '
|
|
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, '
|
|
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, '
|
|
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/);
|