@geekmidas/schema 0.1.0 → 1.0.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.
Files changed (51) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/{conversion-BJGLAqtd.mjs → conversion-CIBtqJkS.mjs} +20 -2
  3. package/dist/conversion-CIBtqJkS.mjs.map +1 -0
  4. package/dist/{conversion-CFlFrSru.cjs → conversion-Cf9R-jGc.cjs} +25 -1
  5. package/dist/conversion-Cf9R-jGc.cjs.map +1 -0
  6. package/dist/{conversion-CH_EmflL.d.cts → conversion-JY1Wixil.d.cts} +11 -2
  7. package/dist/conversion-JY1Wixil.d.cts.map +1 -0
  8. package/dist/{conversion-DUyZYTWO.d.mts → conversion-e4k9rTxy.d.mts} +11 -2
  9. package/dist/conversion-e4k9rTxy.d.mts.map +1 -0
  10. package/dist/conversion.cjs +2 -1
  11. package/dist/conversion.d.cts +2 -2
  12. package/dist/conversion.d.mts +2 -2
  13. package/dist/conversion.mjs +2 -2
  14. package/dist/index.cjs +1 -1
  15. package/dist/index.d.cts +3 -3
  16. package/dist/index.d.mts +3 -3
  17. package/dist/index.mjs +1 -1
  18. package/dist/{openapi-DR4_PG-e.d.cts → openapi-Aeb_1e9T.d.cts} +3 -1
  19. package/dist/openapi-Aeb_1e9T.d.cts.map +1 -0
  20. package/dist/openapi-DH5yCqKh.mjs.map +1 -1
  21. package/dist/openapi-DVvLYx-8.cjs.map +1 -1
  22. package/dist/{openapi-j01kFjpI.d.mts → openapi-Dxc4FuMP.d.mts} +3 -1
  23. package/dist/openapi-Dxc4FuMP.d.mts.map +1 -0
  24. package/dist/openapi.d.cts +1 -1
  25. package/dist/openapi.d.mts +1 -1
  26. package/dist/parser.cjs.map +1 -1
  27. package/dist/parser.d.cts +3 -1
  28. package/dist/parser.d.cts.map +1 -0
  29. package/dist/parser.d.mts +3 -1
  30. package/dist/parser.d.mts.map +1 -0
  31. package/dist/parser.mjs.map +1 -1
  32. package/dist/{types-ByLHeRGs.d.mts → types-D7ZRea_7.d.cts} +3 -1
  33. package/dist/types-D7ZRea_7.d.cts.map +1 -0
  34. package/dist/{types-DfcgE7cO.d.cts → types-o4dOkvCd.d.mts} +3 -1
  35. package/dist/types-o4dOkvCd.d.mts.map +1 -0
  36. package/dist/types.d.cts +1 -1
  37. package/dist/types.d.mts +1 -1
  38. package/package.json +1 -1
  39. package/src/__benchmarks__/conversion.bench.ts +67 -67
  40. package/src/__tests__/conversion.spec.ts +440 -257
  41. package/src/__tests__/openapi.spec.ts +390 -390
  42. package/src/__tests__/parser.spec.ts +202 -202
  43. package/src/conversion.ts +179 -154
  44. package/src/index.ts +8 -9
  45. package/src/openapi.ts +49 -49
  46. package/src/parser.ts +11 -11
  47. package/src/types.ts +16 -16
  48. package/tsconfig.json +9 -0
  49. package/tsdown.config.ts +1 -1
  50. package/dist/conversion-BJGLAqtd.mjs.map +0 -1
  51. package/dist/conversion-CFlFrSru.cjs.map +0 -1
@@ -1,396 +1,396 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import {
3
- type ComponentCollector,
4
- buildOpenApiSchema,
5
- createComponentCollector,
3
+ buildOpenApiSchema,
4
+ type ComponentCollector,
5
+ createComponentCollector,
6
6
  } from '../openapi';
7
7
 
8
8
  describe('OpenAPI Schema', () => {
9
- describe('createComponentCollector', () => {
10
- it('should create a component collector', () => {
11
- const collector = createComponentCollector();
12
-
13
- expect(collector).toHaveProperty('schemas');
14
- expect(collector).toHaveProperty('addSchema');
15
- expect(collector).toHaveProperty('getReference');
16
- expect(collector.schemas).toEqual({});
17
- });
18
-
19
- it('should add schema to collector', () => {
20
- const collector = createComponentCollector();
21
-
22
- collector.addSchema('User', {
23
- type: 'object',
24
- properties: {
25
- name: { type: 'string' },
26
- },
27
- });
28
-
29
- expect(collector.schemas).toHaveProperty('User');
30
- expect(collector.schemas.User).toEqual({
31
- type: 'object',
32
- properties: {
33
- name: { type: 'string' },
34
- },
35
- });
36
- });
37
-
38
- it('should get reference to schema', () => {
39
- const collector = createComponentCollector();
40
-
41
- const reference = collector.getReference('User');
42
-
43
- expect(reference).toEqual({ $ref: '#/components/schemas/User' });
44
- });
45
-
46
- it('should add multiple schemas', () => {
47
- const collector = createComponentCollector();
48
-
49
- collector.addSchema('User', {
50
- type: 'object',
51
- properties: { name: { type: 'string' } },
52
- });
53
-
54
- collector.addSchema('Post', {
55
- type: 'object',
56
- properties: { title: { type: 'string' } },
57
- });
58
-
59
- expect(Object.keys(collector.schemas)).toHaveLength(2);
60
- expect(collector.schemas).toHaveProperty('User');
61
- expect(collector.schemas).toHaveProperty('Post');
62
- });
63
-
64
- it('should overwrite existing schema with same name', () => {
65
- const collector = createComponentCollector();
66
-
67
- collector.addSchema('User', {
68
- type: 'object',
69
- properties: { name: { type: 'string' } },
70
- });
71
-
72
- collector.addSchema('User', {
73
- type: 'object',
74
- properties: { email: { type: 'string' } },
75
- });
76
-
77
- expect(collector.schemas.User.properties).toHaveProperty('email');
78
- expect(collector.schemas.User.properties).not.toHaveProperty('name');
79
- });
80
-
81
- it('should handle complex nested schemas', () => {
82
- const collector = createComponentCollector();
83
-
84
- collector.addSchema('User', {
85
- type: 'object',
86
- properties: {
87
- name: { type: 'string' },
88
- address: {
89
- type: 'object',
90
- properties: {
91
- street: { type: 'string' },
92
- city: { type: 'string' },
93
- },
94
- },
95
- },
96
- });
97
-
98
- expect(collector.schemas.User.properties?.address).toBeDefined();
99
- });
100
- });
101
-
102
- describe('buildOpenApiSchema', () => {
103
- it('should build OpenAPI schema with default options', async () => {
104
- const mockEndpoint = {
105
- async toOpenApi3Route(collector?: ComponentCollector) {
106
- return {
107
- '/users': {
108
- get: {
109
- operationId: 'getUsers',
110
- responses: {
111
- '200': {
112
- description: 'Success',
113
- },
114
- },
115
- },
116
- },
117
- };
118
- },
119
- };
120
-
121
- const doc = await buildOpenApiSchema([mockEndpoint]);
122
-
123
- expect(doc).toHaveProperty('openapi', '3.0.0');
124
- expect(doc).toHaveProperty('info');
125
- expect(doc.info).toEqual({
126
- title: 'API',
127
- version: '1.0.0',
128
- });
129
- expect(doc).toHaveProperty('paths');
130
- expect(doc.paths).toHaveProperty('/users');
131
- });
132
-
133
- it('should build OpenAPI schema with custom options', async () => {
134
- const mockEndpoint = {
135
- async toOpenApi3Route(collector?: ComponentCollector) {
136
- return {
137
- '/posts': {
138
- get: {
139
- operationId: 'getPosts',
140
- responses: {
141
- '200': {
142
- description: 'Success',
143
- },
144
- },
145
- },
146
- },
147
- };
148
- },
149
- };
150
-
151
- const doc = await buildOpenApiSchema([mockEndpoint], {
152
- title: 'My API',
153
- version: '2.0.0',
154
- description: 'API Description',
155
- });
156
-
157
- expect(doc.info).toEqual({
158
- title: 'My API',
159
- version: '2.0.0',
160
- description: 'API Description',
161
- });
162
- });
163
-
164
- it('should merge multiple endpoints into paths', async () => {
165
- const endpoint1 = {
166
- async toOpenApi3Route(collector?: ComponentCollector) {
167
- return {
168
- '/users': {
169
- get: {
170
- operationId: 'getUsers',
171
- responses: { '200': { description: 'Success' } },
172
- },
173
- },
174
- };
175
- },
176
- };
177
-
178
- const endpoint2 = {
179
- async toOpenApi3Route(collector?: ComponentCollector) {
180
- return {
181
- '/posts': {
182
- get: {
183
- operationId: 'getPosts',
184
- responses: { '200': { description: 'Success' } },
185
- },
186
- },
187
- };
188
- },
189
- };
190
-
191
- const doc = await buildOpenApiSchema([endpoint1, endpoint2]);
192
-
193
- expect(Object.keys(doc.paths)).toHaveLength(2);
194
- expect(doc.paths).toHaveProperty('/users');
195
- expect(doc.paths).toHaveProperty('/posts');
196
- });
197
-
198
- it('should merge multiple methods for same path', async () => {
199
- const endpoint1 = {
200
- async toOpenApi3Route(collector?: ComponentCollector) {
201
- return {
202
- '/users': {
203
- get: {
204
- operationId: 'getUsers',
205
- responses: { '200': { description: 'Success' } },
206
- },
207
- },
208
- };
209
- },
210
- };
211
-
212
- const endpoint2 = {
213
- async toOpenApi3Route(collector?: ComponentCollector) {
214
- return {
215
- '/users': {
216
- post: {
217
- operationId: 'createUser',
218
- responses: { '201': { description: 'Created' } },
219
- },
220
- },
221
- };
222
- },
223
- };
224
-
225
- const doc = await buildOpenApiSchema([endpoint1, endpoint2]);
226
-
227
- expect(doc.paths['/users']).toHaveProperty('get');
228
- expect(doc.paths['/users']).toHaveProperty('post');
229
- });
230
-
231
- it('should add components when schemas are collected', async () => {
232
- const mockEndpoint = {
233
- async toOpenApi3Route(collector?: ComponentCollector) {
234
- if (collector) {
235
- collector.addSchema('User', {
236
- type: 'object',
237
- properties: {
238
- name: { type: 'string' },
239
- },
240
- });
241
- }
242
-
243
- return {
244
- '/users': {
245
- get: {
246
- operationId: 'getUsers',
247
- responses: {
248
- '200': {
249
- description: 'Success',
250
- content: {
251
- 'application/json': {
252
- schema: collector?.getReference('User'),
253
- },
254
- },
255
- },
256
- },
257
- },
258
- },
259
- };
260
- },
261
- };
262
-
263
- const doc = await buildOpenApiSchema([mockEndpoint]);
264
-
265
- expect(doc).toHaveProperty('components');
266
- expect(doc.components).toHaveProperty('schemas');
267
- expect(doc.components?.schemas).toHaveProperty('User');
268
- });
269
-
270
- it('should not add components when no schemas collected', async () => {
271
- const mockEndpoint = {
272
- async toOpenApi3Route(collector?: ComponentCollector) {
273
- return {
274
- '/health': {
275
- get: {
276
- operationId: 'healthCheck',
277
- responses: {
278
- '200': {
279
- description: 'Healthy',
280
- },
281
- },
282
- },
283
- },
284
- };
285
- },
286
- };
287
-
288
- const doc = await buildOpenApiSchema([mockEndpoint]);
289
-
290
- expect(doc).not.toHaveProperty('components');
291
- });
292
-
293
- it('should handle empty endpoints array', async () => {
294
- const doc = await buildOpenApiSchema([]);
295
-
296
- expect(doc.paths).toEqual({});
297
- expect(doc).not.toHaveProperty('components');
298
- });
299
-
300
- it('should handle endpoints with parameters', async () => {
301
- const mockEndpoint = {
302
- async toOpenApi3Route(collector?: ComponentCollector) {
303
- return {
304
- '/users/{id}': {
305
- get: {
306
- operationId: 'getUserById',
307
- parameters: [
308
- {
309
- name: 'id',
310
- in: 'path',
311
- required: true,
312
- schema: { type: 'string' },
313
- },
314
- ],
315
- responses: {
316
- '200': {
317
- description: 'Success',
318
- },
319
- },
320
- },
321
- },
322
- };
323
- },
324
- };
325
-
326
- const doc = await buildOpenApiSchema([mockEndpoint]);
327
-
328
- expect(doc.paths['/users/{id}']?.get?.parameters).toBeDefined();
329
- expect(doc.paths['/users/{id}']?.get?.parameters).toHaveLength(1);
330
- });
331
-
332
- it('should handle endpoints with request body', async () => {
333
- const mockEndpoint = {
334
- async toOpenApi3Route(collector?: ComponentCollector) {
335
- return {
336
- '/users': {
337
- post: {
338
- operationId: 'createUser',
339
- requestBody: {
340
- required: true,
341
- content: {
342
- 'application/json': {
343
- schema: {
344
- type: 'object',
345
- properties: {
346
- name: { type: 'string' },
347
- },
348
- },
349
- },
350
- },
351
- },
352
- responses: {
353
- '201': {
354
- description: 'Created',
355
- },
356
- },
357
- },
358
- },
359
- };
360
- },
361
- };
362
-
363
- const doc = await buildOpenApiSchema([mockEndpoint]);
364
-
365
- expect(doc.paths['/users']?.post?.requestBody).toBeDefined();
366
- });
367
-
368
- it('should handle endpoints with multiple response codes', async () => {
369
- const mockEndpoint = {
370
- async toOpenApi3Route(collector?: ComponentCollector) {
371
- return {
372
- '/users': {
373
- get: {
374
- operationId: 'getUsers',
375
- responses: {
376
- '200': { description: 'Success' },
377
- '400': { description: 'Bad Request' },
378
- '401': { description: 'Unauthorized' },
379
- '500': { description: 'Server Error' },
380
- },
381
- },
382
- },
383
- };
384
- },
385
- };
386
-
387
- const doc = await buildOpenApiSchema([mockEndpoint]);
388
-
389
- const responses = doc.paths['/users']?.get?.responses;
390
- expect(responses).toHaveProperty('200');
391
- expect(responses).toHaveProperty('400');
392
- expect(responses).toHaveProperty('401');
393
- expect(responses).toHaveProperty('500');
394
- });
395
- });
9
+ describe('createComponentCollector', () => {
10
+ it('should create a component collector', () => {
11
+ const collector = createComponentCollector();
12
+
13
+ expect(collector).toHaveProperty('schemas');
14
+ expect(collector).toHaveProperty('addSchema');
15
+ expect(collector).toHaveProperty('getReference');
16
+ expect(collector.schemas).toEqual({});
17
+ });
18
+
19
+ it('should add schema to collector', () => {
20
+ const collector = createComponentCollector();
21
+
22
+ collector.addSchema('User', {
23
+ type: 'object',
24
+ properties: {
25
+ name: { type: 'string' },
26
+ },
27
+ });
28
+
29
+ expect(collector.schemas).toHaveProperty('User');
30
+ expect(collector.schemas.User).toEqual({
31
+ type: 'object',
32
+ properties: {
33
+ name: { type: 'string' },
34
+ },
35
+ });
36
+ });
37
+
38
+ it('should get reference to schema', () => {
39
+ const collector = createComponentCollector();
40
+
41
+ const reference = collector.getReference('User');
42
+
43
+ expect(reference).toEqual({ $ref: '#/components/schemas/User' });
44
+ });
45
+
46
+ it('should add multiple schemas', () => {
47
+ const collector = createComponentCollector();
48
+
49
+ collector.addSchema('User', {
50
+ type: 'object',
51
+ properties: { name: { type: 'string' } },
52
+ });
53
+
54
+ collector.addSchema('Post', {
55
+ type: 'object',
56
+ properties: { title: { type: 'string' } },
57
+ });
58
+
59
+ expect(Object.keys(collector.schemas)).toHaveLength(2);
60
+ expect(collector.schemas).toHaveProperty('User');
61
+ expect(collector.schemas).toHaveProperty('Post');
62
+ });
63
+
64
+ it('should overwrite existing schema with same name', () => {
65
+ const collector = createComponentCollector();
66
+
67
+ collector.addSchema('User', {
68
+ type: 'object',
69
+ properties: { name: { type: 'string' } },
70
+ });
71
+
72
+ collector.addSchema('User', {
73
+ type: 'object',
74
+ properties: { email: { type: 'string' } },
75
+ });
76
+
77
+ expect(collector.schemas.User.properties).toHaveProperty('email');
78
+ expect(collector.schemas.User.properties).not.toHaveProperty('name');
79
+ });
80
+
81
+ it('should handle complex nested schemas', () => {
82
+ const collector = createComponentCollector();
83
+
84
+ collector.addSchema('User', {
85
+ type: 'object',
86
+ properties: {
87
+ name: { type: 'string' },
88
+ address: {
89
+ type: 'object',
90
+ properties: {
91
+ street: { type: 'string' },
92
+ city: { type: 'string' },
93
+ },
94
+ },
95
+ },
96
+ });
97
+
98
+ expect(collector.schemas.User.properties?.address).toBeDefined();
99
+ });
100
+ });
101
+
102
+ describe('buildOpenApiSchema', () => {
103
+ it('should build OpenAPI schema with default options', async () => {
104
+ const mockEndpoint = {
105
+ async toOpenApi3Route(_collector?: ComponentCollector) {
106
+ return {
107
+ '/users': {
108
+ get: {
109
+ operationId: 'getUsers',
110
+ responses: {
111
+ '200': {
112
+ description: 'Success',
113
+ },
114
+ },
115
+ },
116
+ },
117
+ };
118
+ },
119
+ };
120
+
121
+ const doc = await buildOpenApiSchema([mockEndpoint]);
122
+
123
+ expect(doc).toHaveProperty('openapi', '3.0.0');
124
+ expect(doc).toHaveProperty('info');
125
+ expect(doc.info).toEqual({
126
+ title: 'API',
127
+ version: '1.0.0',
128
+ });
129
+ expect(doc).toHaveProperty('paths');
130
+ expect(doc.paths).toHaveProperty('/users');
131
+ });
132
+
133
+ it('should build OpenAPI schema with custom options', async () => {
134
+ const mockEndpoint = {
135
+ async toOpenApi3Route(_collector?: ComponentCollector) {
136
+ return {
137
+ '/posts': {
138
+ get: {
139
+ operationId: 'getPosts',
140
+ responses: {
141
+ '200': {
142
+ description: 'Success',
143
+ },
144
+ },
145
+ },
146
+ },
147
+ };
148
+ },
149
+ };
150
+
151
+ const doc = await buildOpenApiSchema([mockEndpoint], {
152
+ title: 'My API',
153
+ version: '2.0.0',
154
+ description: 'API Description',
155
+ });
156
+
157
+ expect(doc.info).toEqual({
158
+ title: 'My API',
159
+ version: '2.0.0',
160
+ description: 'API Description',
161
+ });
162
+ });
163
+
164
+ it('should merge multiple endpoints into paths', async () => {
165
+ const endpoint1 = {
166
+ async toOpenApi3Route(_collector?: ComponentCollector) {
167
+ return {
168
+ '/users': {
169
+ get: {
170
+ operationId: 'getUsers',
171
+ responses: { '200': { description: 'Success' } },
172
+ },
173
+ },
174
+ };
175
+ },
176
+ };
177
+
178
+ const endpoint2 = {
179
+ async toOpenApi3Route(_collector?: ComponentCollector) {
180
+ return {
181
+ '/posts': {
182
+ get: {
183
+ operationId: 'getPosts',
184
+ responses: { '200': { description: 'Success' } },
185
+ },
186
+ },
187
+ };
188
+ },
189
+ };
190
+
191
+ const doc = await buildOpenApiSchema([endpoint1, endpoint2]);
192
+
193
+ expect(Object.keys(doc.paths)).toHaveLength(2);
194
+ expect(doc.paths).toHaveProperty('/users');
195
+ expect(doc.paths).toHaveProperty('/posts');
196
+ });
197
+
198
+ it('should merge multiple methods for same path', async () => {
199
+ const endpoint1 = {
200
+ async toOpenApi3Route(_collector?: ComponentCollector) {
201
+ return {
202
+ '/users': {
203
+ get: {
204
+ operationId: 'getUsers',
205
+ responses: { '200': { description: 'Success' } },
206
+ },
207
+ },
208
+ };
209
+ },
210
+ };
211
+
212
+ const endpoint2 = {
213
+ async toOpenApi3Route(_collector?: ComponentCollector) {
214
+ return {
215
+ '/users': {
216
+ post: {
217
+ operationId: 'createUser',
218
+ responses: { '201': { description: 'Created' } },
219
+ },
220
+ },
221
+ };
222
+ },
223
+ };
224
+
225
+ const doc = await buildOpenApiSchema([endpoint1, endpoint2]);
226
+
227
+ expect(doc.paths['/users']).toHaveProperty('get');
228
+ expect(doc.paths['/users']).toHaveProperty('post');
229
+ });
230
+
231
+ it('should add components when schemas are collected', async () => {
232
+ const mockEndpoint = {
233
+ async toOpenApi3Route(collector?: ComponentCollector) {
234
+ if (collector) {
235
+ collector.addSchema('User', {
236
+ type: 'object',
237
+ properties: {
238
+ name: { type: 'string' },
239
+ },
240
+ });
241
+ }
242
+
243
+ return {
244
+ '/users': {
245
+ get: {
246
+ operationId: 'getUsers',
247
+ responses: {
248
+ '200': {
249
+ description: 'Success',
250
+ content: {
251
+ 'application/json': {
252
+ schema: collector?.getReference('User'),
253
+ },
254
+ },
255
+ },
256
+ },
257
+ },
258
+ },
259
+ };
260
+ },
261
+ };
262
+
263
+ const doc = await buildOpenApiSchema([mockEndpoint]);
264
+
265
+ expect(doc).toHaveProperty('components');
266
+ expect(doc.components).toHaveProperty('schemas');
267
+ expect(doc.components?.schemas).toHaveProperty('User');
268
+ });
269
+
270
+ it('should not add components when no schemas collected', async () => {
271
+ const mockEndpoint = {
272
+ async toOpenApi3Route(_collector?: ComponentCollector) {
273
+ return {
274
+ '/health': {
275
+ get: {
276
+ operationId: 'healthCheck',
277
+ responses: {
278
+ '200': {
279
+ description: 'Healthy',
280
+ },
281
+ },
282
+ },
283
+ },
284
+ };
285
+ },
286
+ };
287
+
288
+ const doc = await buildOpenApiSchema([mockEndpoint]);
289
+
290
+ expect(doc).not.toHaveProperty('components');
291
+ });
292
+
293
+ it('should handle empty endpoints array', async () => {
294
+ const doc = await buildOpenApiSchema([]);
295
+
296
+ expect(doc.paths).toEqual({});
297
+ expect(doc).not.toHaveProperty('components');
298
+ });
299
+
300
+ it('should handle endpoints with parameters', async () => {
301
+ const mockEndpoint = {
302
+ async toOpenApi3Route(_collector?: ComponentCollector) {
303
+ return {
304
+ '/users/{id}': {
305
+ get: {
306
+ operationId: 'getUserById',
307
+ parameters: [
308
+ {
309
+ name: 'id',
310
+ in: 'path',
311
+ required: true,
312
+ schema: { type: 'string' },
313
+ },
314
+ ],
315
+ responses: {
316
+ '200': {
317
+ description: 'Success',
318
+ },
319
+ },
320
+ },
321
+ },
322
+ };
323
+ },
324
+ };
325
+
326
+ const doc = await buildOpenApiSchema([mockEndpoint]);
327
+
328
+ expect(doc.paths['/users/{id}']?.get?.parameters).toBeDefined();
329
+ expect(doc.paths['/users/{id}']?.get?.parameters).toHaveLength(1);
330
+ });
331
+
332
+ it('should handle endpoints with request body', async () => {
333
+ const mockEndpoint = {
334
+ async toOpenApi3Route(_collector?: ComponentCollector) {
335
+ return {
336
+ '/users': {
337
+ post: {
338
+ operationId: 'createUser',
339
+ requestBody: {
340
+ required: true,
341
+ content: {
342
+ 'application/json': {
343
+ schema: {
344
+ type: 'object',
345
+ properties: {
346
+ name: { type: 'string' },
347
+ },
348
+ },
349
+ },
350
+ },
351
+ },
352
+ responses: {
353
+ '201': {
354
+ description: 'Created',
355
+ },
356
+ },
357
+ },
358
+ },
359
+ };
360
+ },
361
+ };
362
+
363
+ const doc = await buildOpenApiSchema([mockEndpoint]);
364
+
365
+ expect(doc.paths['/users']?.post?.requestBody).toBeDefined();
366
+ });
367
+
368
+ it('should handle endpoints with multiple response codes', async () => {
369
+ const mockEndpoint = {
370
+ async toOpenApi3Route(_collector?: ComponentCollector) {
371
+ return {
372
+ '/users': {
373
+ get: {
374
+ operationId: 'getUsers',
375
+ responses: {
376
+ '200': { description: 'Success' },
377
+ '400': { description: 'Bad Request' },
378
+ '401': { description: 'Unauthorized' },
379
+ '500': { description: 'Server Error' },
380
+ },
381
+ },
382
+ },
383
+ };
384
+ },
385
+ };
386
+
387
+ const doc = await buildOpenApiSchema([mockEndpoint]);
388
+
389
+ const responses = doc.paths['/users']?.get?.responses;
390
+ expect(responses).toHaveProperty('200');
391
+ expect(responses).toHaveProperty('400');
392
+ expect(responses).toHaveProperty('401');
393
+ expect(responses).toHaveProperty('500');
394
+ });
395
+ });
396
396
  });