zod-codegen 1.6.3 → 1.7.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/.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 +17 -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 +2 -0
- package/dist/src/services/file-reader.service.d.ts.map +1 -1
- package/dist/src/services/file-reader.service.js +25 -11
- 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 +123 -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 +153 -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 +35 -15
- 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 +53 -31
- 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 +58 -18
- 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
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { TypeScriptCodeGeneratorService } from '../../src/services/code-generator.service';
|
|
3
|
+
describe('TypeScriptCodeGeneratorService - Edge Cases', () => {
|
|
4
|
+
let generator;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
generator = new TypeScriptCodeGeneratorService();
|
|
7
|
+
});
|
|
8
|
+
describe('buildBasicTypeFromSchema edge cases', () => {
|
|
9
|
+
it('should handle unknown type in default case', () => {
|
|
10
|
+
const spec = {
|
|
11
|
+
openapi: '3.0.0',
|
|
12
|
+
info: {
|
|
13
|
+
title: 'Test API',
|
|
14
|
+
version: '1.0.0'
|
|
15
|
+
},
|
|
16
|
+
paths: {},
|
|
17
|
+
components: {
|
|
18
|
+
schemas: {
|
|
19
|
+
UnknownType: {
|
|
20
|
+
anyOf: [{ type: 'custom' }]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const code = generator.generate(spec);
|
|
26
|
+
expect(code).toContain('z.unknown()');
|
|
27
|
+
});
|
|
28
|
+
it('should handle unknown type directly in schema (not in logical operator)', () => {
|
|
29
|
+
const spec = {
|
|
30
|
+
openapi: '3.0.0',
|
|
31
|
+
info: {
|
|
32
|
+
title: 'Test API',
|
|
33
|
+
version: '1.0.0'
|
|
34
|
+
},
|
|
35
|
+
paths: {},
|
|
36
|
+
components: {
|
|
37
|
+
schemas: {
|
|
38
|
+
DirectUnknownType: {
|
|
39
|
+
type: 'custom'
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const code = generator.generate(spec);
|
|
45
|
+
expect(code).toContain('z.unknown()');
|
|
46
|
+
expect(code).toContain('DirectUnknownType');
|
|
47
|
+
});
|
|
48
|
+
it('should handle object type with properties in buildBasicTypeFromSchema path', () => {
|
|
49
|
+
// Test the path where buildObjectTypeFromSchema is called with properties
|
|
50
|
+
// This happens when SchemaProperties.parse fails but schema has type: 'object'
|
|
51
|
+
// We need to create a scenario where parse fails but type property exists
|
|
52
|
+
// Since SchemaProperties is very permissive, we'll use a non-object value
|
|
53
|
+
// that gets coerced or handled specially
|
|
54
|
+
const spec = {
|
|
55
|
+
openapi: '3.0.0',
|
|
56
|
+
info: {
|
|
57
|
+
title: 'Test API',
|
|
58
|
+
version: '1.0.0'
|
|
59
|
+
},
|
|
60
|
+
paths: {},
|
|
61
|
+
components: {
|
|
62
|
+
schemas: {
|
|
63
|
+
ObjectWithPropsViaBasic: {
|
|
64
|
+
// Use oneOf with a schema that will fail parse but has type
|
|
65
|
+
oneOf: [
|
|
66
|
+
// Create an object that fails SchemaProperties validation
|
|
67
|
+
// by having invalid nested structure that causes parse to fail
|
|
68
|
+
// but still has the type property accessible
|
|
69
|
+
(() => {
|
|
70
|
+
const obj = { type: 'object', properties: { name: { type: 'string' } } };
|
|
71
|
+
// Make it fail parse by adding circular reference or invalid structure
|
|
72
|
+
// Actually, let's try making properties invalid in a way that causes top-level parse to fail
|
|
73
|
+
obj.properties = new Proxy({}, {
|
|
74
|
+
get() {
|
|
75
|
+
throw new Error('Proxy error');
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
return obj;
|
|
79
|
+
})()
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
// This might throw, but let's see
|
|
86
|
+
try {
|
|
87
|
+
const code = generator.generate(spec);
|
|
88
|
+
expect(code).toBeTruthy();
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Expected if proxy causes issues
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
it('should handle schema without type property', () => {
|
|
95
|
+
const spec = {
|
|
96
|
+
openapi: '3.0.0',
|
|
97
|
+
info: {
|
|
98
|
+
title: 'Test API',
|
|
99
|
+
version: '1.0.0'
|
|
100
|
+
},
|
|
101
|
+
paths: {},
|
|
102
|
+
components: {
|
|
103
|
+
schemas: {
|
|
104
|
+
NoType: {
|
|
105
|
+
anyOf: [{}]
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const code = generator.generate(spec);
|
|
111
|
+
expect(code).toContain('z.unknown()');
|
|
112
|
+
});
|
|
113
|
+
it('should handle null schema', () => {
|
|
114
|
+
const spec = {
|
|
115
|
+
openapi: '3.0.0',
|
|
116
|
+
info: {
|
|
117
|
+
title: 'Test API',
|
|
118
|
+
version: '1.0.0'
|
|
119
|
+
},
|
|
120
|
+
paths: {},
|
|
121
|
+
components: {
|
|
122
|
+
schemas: {
|
|
123
|
+
NullSchema: {
|
|
124
|
+
anyOf: [null]
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const code = generator.generate(spec);
|
|
130
|
+
// Should handle gracefully
|
|
131
|
+
expect(code).toBeTruthy();
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
describe('buildObjectTypeFromSchema edge cases', () => {
|
|
135
|
+
it('should handle object with empty properties in logical operators', () => {
|
|
136
|
+
const spec = {
|
|
137
|
+
openapi: '3.0.0',
|
|
138
|
+
info: {
|
|
139
|
+
title: 'Test API',
|
|
140
|
+
version: '1.0.0'
|
|
141
|
+
},
|
|
142
|
+
paths: {},
|
|
143
|
+
components: {
|
|
144
|
+
schemas: {
|
|
145
|
+
EmptyObject: {
|
|
146
|
+
anyOf: [{ type: 'object', properties: {} }]
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
const code = generator.generate(spec);
|
|
152
|
+
// Empty object should fallback to record type
|
|
153
|
+
expect(code).toContain('z.record');
|
|
154
|
+
});
|
|
155
|
+
it('should handle object with properties in logical operators', () => {
|
|
156
|
+
const spec = {
|
|
157
|
+
openapi: '3.0.0',
|
|
158
|
+
info: {
|
|
159
|
+
title: 'Test API',
|
|
160
|
+
version: '1.0.0'
|
|
161
|
+
},
|
|
162
|
+
paths: {},
|
|
163
|
+
components: {
|
|
164
|
+
schemas: {
|
|
165
|
+
ObjectWithProps: {
|
|
166
|
+
anyOf: [
|
|
167
|
+
{
|
|
168
|
+
type: 'object',
|
|
169
|
+
properties: {
|
|
170
|
+
name: { type: 'string' },
|
|
171
|
+
age: { type: 'number' }
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
const code = generator.generate(spec);
|
|
180
|
+
expect(code).toContain('name');
|
|
181
|
+
expect(code).toContain('age');
|
|
182
|
+
});
|
|
183
|
+
it('should handle object type directly in schema (not in logical operator)', () => {
|
|
184
|
+
const spec = {
|
|
185
|
+
openapi: '3.0.0',
|
|
186
|
+
info: {
|
|
187
|
+
title: 'Test API',
|
|
188
|
+
version: '1.0.0'
|
|
189
|
+
},
|
|
190
|
+
paths: {},
|
|
191
|
+
components: {
|
|
192
|
+
schemas: {
|
|
193
|
+
DirectObject: {
|
|
194
|
+
type: 'object',
|
|
195
|
+
properties: {
|
|
196
|
+
name: { type: 'string' },
|
|
197
|
+
age: { type: 'number' }
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
const code = generator.generate(spec);
|
|
204
|
+
expect(code).toContain('name');
|
|
205
|
+
expect(code).toContain('age');
|
|
206
|
+
expect(code).toContain('DirectObject');
|
|
207
|
+
});
|
|
208
|
+
it('should handle object type with empty properties directly in schema', () => {
|
|
209
|
+
const spec = {
|
|
210
|
+
openapi: '3.0.0',
|
|
211
|
+
info: {
|
|
212
|
+
title: 'Test API',
|
|
213
|
+
version: '1.0.0'
|
|
214
|
+
},
|
|
215
|
+
paths: {},
|
|
216
|
+
components: {
|
|
217
|
+
schemas: {
|
|
218
|
+
EmptyDirectObject: {
|
|
219
|
+
type: 'object',
|
|
220
|
+
properties: {}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
const code = generator.generate(spec);
|
|
226
|
+
// Empty object should fallback to record type
|
|
227
|
+
expect(code).toContain('z.record');
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
describe('buildArrayTypeFromSchema edge cases', () => {
|
|
231
|
+
it('should handle array without items in logical operators', () => {
|
|
232
|
+
const spec = {
|
|
233
|
+
openapi: '3.0.0',
|
|
234
|
+
info: {
|
|
235
|
+
title: 'Test API',
|
|
236
|
+
version: '1.0.0'
|
|
237
|
+
},
|
|
238
|
+
paths: {},
|
|
239
|
+
components: {
|
|
240
|
+
schemas: {
|
|
241
|
+
ArrayNoItems: {
|
|
242
|
+
anyOf: [{ type: 'array' }]
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
const code = generator.generate(spec);
|
|
248
|
+
expect(code).toContain('z.array');
|
|
249
|
+
expect(code).toContain('z.unknown()');
|
|
250
|
+
});
|
|
251
|
+
it('should handle array with items in logical operators', () => {
|
|
252
|
+
const spec = {
|
|
253
|
+
openapi: '3.0.0',
|
|
254
|
+
info: {
|
|
255
|
+
title: 'Test API',
|
|
256
|
+
version: '1.0.0'
|
|
257
|
+
},
|
|
258
|
+
paths: {},
|
|
259
|
+
components: {
|
|
260
|
+
schemas: {
|
|
261
|
+
ArrayWithItems: {
|
|
262
|
+
anyOf: [
|
|
263
|
+
{
|
|
264
|
+
type: 'array',
|
|
265
|
+
items: { type: 'string' }
|
|
266
|
+
}
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
const code = generator.generate(spec);
|
|
273
|
+
expect(code).toContain('z.array');
|
|
274
|
+
expect(code).toContain('z.string()');
|
|
275
|
+
});
|
|
276
|
+
it('should handle array type directly in schema (not in logical operator)', () => {
|
|
277
|
+
const spec = {
|
|
278
|
+
openapi: '3.0.0',
|
|
279
|
+
info: {
|
|
280
|
+
title: 'Test API',
|
|
281
|
+
version: '1.0.0'
|
|
282
|
+
},
|
|
283
|
+
paths: {},
|
|
284
|
+
components: {
|
|
285
|
+
schemas: {
|
|
286
|
+
DirectArray: {
|
|
287
|
+
type: 'array',
|
|
288
|
+
items: { type: 'string' }
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
const code = generator.generate(spec);
|
|
294
|
+
expect(code).toContain('z.array');
|
|
295
|
+
expect(code).toContain('z.string()');
|
|
296
|
+
expect(code).toContain('DirectArray');
|
|
297
|
+
});
|
|
298
|
+
it('should handle array type without items directly in schema', () => {
|
|
299
|
+
const spec = {
|
|
300
|
+
openapi: '3.0.0',
|
|
301
|
+
info: {
|
|
302
|
+
title: 'Test API',
|
|
303
|
+
version: '1.0.0'
|
|
304
|
+
},
|
|
305
|
+
paths: {},
|
|
306
|
+
components: {
|
|
307
|
+
schemas: {
|
|
308
|
+
DirectArrayNoItems: {
|
|
309
|
+
type: 'array'
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
const code = generator.generate(spec);
|
|
315
|
+
expect(code).toContain('z.array');
|
|
316
|
+
expect(code).toContain('DirectArrayNoItems');
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
describe('Complex nested logical operators', () => {
|
|
320
|
+
it('should handle nested anyOf within allOf', () => {
|
|
321
|
+
const spec = {
|
|
322
|
+
openapi: '3.0.0',
|
|
323
|
+
info: {
|
|
324
|
+
title: 'Test API',
|
|
325
|
+
version: '1.0.0'
|
|
326
|
+
},
|
|
327
|
+
paths: {},
|
|
328
|
+
components: {
|
|
329
|
+
schemas: {
|
|
330
|
+
NestedLogical: {
|
|
331
|
+
allOf: [
|
|
332
|
+
{
|
|
333
|
+
anyOf: [{ type: 'string' }, { type: 'number' }]
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
type: 'object',
|
|
337
|
+
properties: {
|
|
338
|
+
id: { type: 'string' }
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
]
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
const code = generator.generate(spec);
|
|
347
|
+
expect(code).toContain('z.intersection');
|
|
348
|
+
expect(code).toContain('z.union');
|
|
349
|
+
});
|
|
350
|
+
it('should handle not operator with complex schema', () => {
|
|
351
|
+
const spec = {
|
|
352
|
+
openapi: '3.0.0',
|
|
353
|
+
info: {
|
|
354
|
+
title: 'Test API',
|
|
355
|
+
version: '1.0.0'
|
|
356
|
+
},
|
|
357
|
+
paths: {},
|
|
358
|
+
components: {
|
|
359
|
+
schemas: {
|
|
360
|
+
NotComplex: {
|
|
361
|
+
not: {
|
|
362
|
+
type: 'object',
|
|
363
|
+
properties: {
|
|
364
|
+
forbidden: { type: 'string' }
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
const code = generator.generate(spec);
|
|
372
|
+
// The not operator uses z.any.refine() pattern
|
|
373
|
+
expect(code).toContain('z.any');
|
|
374
|
+
expect(code).toContain('refine');
|
|
375
|
+
expect(code).toMatch(/forbidden|Value must not match/);
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
describe('buildSchemaFromLogicalOperator edge cases', () => {
|
|
379
|
+
it('should handle unknown type in default case of buildSchemaFromLogicalOperator', () => {
|
|
380
|
+
const spec = {
|
|
381
|
+
openapi: '3.0.0',
|
|
382
|
+
info: {
|
|
383
|
+
title: 'Test API',
|
|
384
|
+
version: '1.0.0'
|
|
385
|
+
},
|
|
386
|
+
paths: {},
|
|
387
|
+
components: {
|
|
388
|
+
schemas: {
|
|
389
|
+
UnknownTypeInLogical: {
|
|
390
|
+
anyOf: [
|
|
391
|
+
{
|
|
392
|
+
type: 'custom' // Unknown type that hits default case
|
|
393
|
+
}
|
|
394
|
+
]
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
const code = generator.generate(spec);
|
|
400
|
+
expect(code).toContain('z.unknown()');
|
|
401
|
+
});
|
|
402
|
+
it('should handle buildObjectTypeFromSchema with empty properties', () => {
|
|
403
|
+
const spec = {
|
|
404
|
+
openapi: '3.0.0',
|
|
405
|
+
info: {
|
|
406
|
+
title: 'Test API',
|
|
407
|
+
version: '1.0.0'
|
|
408
|
+
},
|
|
409
|
+
paths: {},
|
|
410
|
+
components: {
|
|
411
|
+
schemas: {
|
|
412
|
+
EmptyObjectInLogical: {
|
|
413
|
+
anyOf: [
|
|
414
|
+
{
|
|
415
|
+
type: 'object',
|
|
416
|
+
properties: {}
|
|
417
|
+
}
|
|
418
|
+
]
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
const code = generator.generate(spec);
|
|
424
|
+
// Should fallback to record type when properties are empty
|
|
425
|
+
expect(code).toContain('z.record');
|
|
426
|
+
});
|
|
427
|
+
it('should handle buildObjectTypeFromSchema with properties', () => {
|
|
428
|
+
const spec = {
|
|
429
|
+
openapi: '3.0.0',
|
|
430
|
+
info: {
|
|
431
|
+
title: 'Test API',
|
|
432
|
+
version: '1.0.0'
|
|
433
|
+
},
|
|
434
|
+
paths: {},
|
|
435
|
+
components: {
|
|
436
|
+
schemas: {
|
|
437
|
+
ObjectWithPropsInLogical: {
|
|
438
|
+
anyOf: [
|
|
439
|
+
{
|
|
440
|
+
type: 'object',
|
|
441
|
+
properties: {
|
|
442
|
+
name: { type: 'string' },
|
|
443
|
+
value: { type: 'number' }
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
const code = generator.generate(spec);
|
|
452
|
+
expect(code).toContain('name');
|
|
453
|
+
expect(code).toContain('value');
|
|
454
|
+
expect(code).toContain('z.object');
|
|
455
|
+
});
|
|
456
|
+
it('should handle buildArrayTypeFromSchema without items', () => {
|
|
457
|
+
const spec = {
|
|
458
|
+
openapi: '3.0.0',
|
|
459
|
+
info: {
|
|
460
|
+
title: 'Test API',
|
|
461
|
+
version: '1.0.0'
|
|
462
|
+
},
|
|
463
|
+
paths: {},
|
|
464
|
+
components: {
|
|
465
|
+
schemas: {
|
|
466
|
+
ArrayNoItemsInLogical: {
|
|
467
|
+
anyOf: [
|
|
468
|
+
{
|
|
469
|
+
type: 'array'
|
|
470
|
+
// No items property
|
|
471
|
+
}
|
|
472
|
+
]
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
const code = generator.generate(spec);
|
|
478
|
+
expect(code).toContain('z.array');
|
|
479
|
+
});
|
|
480
|
+
it('should handle buildArrayTypeFromSchema with items', () => {
|
|
481
|
+
const spec = {
|
|
482
|
+
openapi: '3.0.0',
|
|
483
|
+
info: {
|
|
484
|
+
title: 'Test API',
|
|
485
|
+
version: '1.0.0'
|
|
486
|
+
},
|
|
487
|
+
paths: {},
|
|
488
|
+
components: {
|
|
489
|
+
schemas: {
|
|
490
|
+
ArrayWithItemsInLogical: {
|
|
491
|
+
anyOf: [
|
|
492
|
+
{
|
|
493
|
+
type: 'array',
|
|
494
|
+
items: { type: 'string' }
|
|
495
|
+
}
|
|
496
|
+
]
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
const code = generator.generate(spec);
|
|
502
|
+
expect(code).toContain('z.array');
|
|
503
|
+
expect(code).toContain('z.string()');
|
|
504
|
+
});
|
|
505
|
+
});
|
|
506
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-generator.test.d.ts","sourceRoot":"","sources":["../../../tests/unit/code-generator.test.ts"],"names":[],"mappings":""}
|