@moostjs/swagger 0.3.10 → 0.3.12
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/dist/index.cjs +511 -525
- package/dist/index.d.ts +82 -94
- package/dist/index.mjs +511 -525
- package/package.json +7 -6
package/dist/index.cjs
CHANGED
|
@@ -22,7 +22,7 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
22
22
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
23
23
|
PERFORMANCE OF THIS SOFTWARE.
|
|
24
24
|
***************************************************************************** */
|
|
25
|
-
/* global Reflect, Promise */
|
|
25
|
+
/* global Reflect, Promise, SuppressedError, Symbol */
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
function __decorate(decorators, target, key, desc) {
|
|
@@ -40,467 +40,455 @@ function __metadata(metadataKey, metadataValue) {
|
|
|
40
40
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
function
|
|
44
|
-
|
|
45
|
-
return
|
|
46
|
-
|
|
47
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
48
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
49
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
50
|
-
});
|
|
51
|
-
}
|
|
43
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
44
|
+
var e = new Error(message);
|
|
45
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
46
|
+
};
|
|
52
47
|
|
|
53
|
-
function getSwaggerMate() {
|
|
54
|
-
return moost.getMoostMate();
|
|
48
|
+
function getSwaggerMate() {
|
|
49
|
+
return moost.getMoostMate();
|
|
55
50
|
}
|
|
56
51
|
|
|
57
|
-
const SwaggerTag = (tag) => getSwaggerMate().decorate('swaggerTags', tag, true);
|
|
58
|
-
const SwaggerExclude = () => getSwaggerMate().decorate('swaggerExclude', true);
|
|
59
|
-
const SwaggerDescription = (descr) => getSwaggerMate().decorate('swaggerDescription', descr);
|
|
60
|
-
function SwaggerResponse(code, opts) {
|
|
61
|
-
return getSwaggerMate().decorate((meta) => {
|
|
62
|
-
meta.swaggerResponses = meta.swaggerResponses || {};
|
|
63
|
-
const keyCode = typeof code === 'number' ? code : 0;
|
|
64
|
-
const opt = typeof code === 'number' ? opts : code;
|
|
65
|
-
const contentType = typeof opt.contentType === 'string' ? opt.contentType : '*/*';
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
meta.swaggerResponses[keyCode]
|
|
69
|
-
meta
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return meta;
|
|
81
|
-
});
|
|
52
|
+
const SwaggerTag = (tag) => getSwaggerMate().decorate('swaggerTags', tag, true);
|
|
53
|
+
const SwaggerExclude = () => getSwaggerMate().decorate('swaggerExclude', true);
|
|
54
|
+
const SwaggerDescription = (descr) => getSwaggerMate().decorate('swaggerDescription', descr);
|
|
55
|
+
function SwaggerResponse(code, opts) {
|
|
56
|
+
return getSwaggerMate().decorate((meta) => {
|
|
57
|
+
meta.swaggerResponses = meta.swaggerResponses || {};
|
|
58
|
+
const keyCode = typeof code === 'number' ? code : 0;
|
|
59
|
+
const opt = typeof code === 'number' ? opts : code;
|
|
60
|
+
const contentType = typeof opt.contentType === 'string' ? opt.contentType : '*/*';
|
|
61
|
+
const response = (['object', 'function'].includes(typeof opt.response) ? opt.response : opt);
|
|
62
|
+
meta.swaggerResponses[keyCode] = meta.swaggerResponses[keyCode] || {};
|
|
63
|
+
meta.swaggerResponses[keyCode][contentType] = response;
|
|
64
|
+
return meta;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function SwaggerRequestBody(opt) {
|
|
68
|
+
return getSwaggerMate().decorate((meta) => {
|
|
69
|
+
meta.swaggerRequestBody = meta.swaggerRequestBody || {};
|
|
70
|
+
const contentType = typeof opt.contentType === 'string' ? opt.contentType : 'application/json';
|
|
71
|
+
const response = (typeof opt.contentType === 'string' ? opt.response : opt);
|
|
72
|
+
meta.swaggerRequestBody[contentType] = response;
|
|
73
|
+
return meta;
|
|
74
|
+
});
|
|
82
75
|
}
|
|
83
76
|
|
|
84
|
-
function mapToSwaggerSpec(metadata, options, logger) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
},
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
let
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
responses =
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
responses =
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
let
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
let
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
case '
|
|
270
|
-
case '
|
|
271
|
-
case '
|
|
272
|
-
case '
|
|
273
|
-
case '
|
|
274
|
-
case '
|
|
275
|
-
case '
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
if (
|
|
302
|
-
return
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
case '
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
case '
|
|
400
|
-
case '
|
|
401
|
-
case '
|
|
402
|
-
case '
|
|
403
|
-
case '
|
|
404
|
-
|
|
405
|
-
case '
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
schema.
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
schema.
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
schema.
|
|
418
|
-
schema.
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
case '
|
|
439
|
-
|
|
440
|
-
schema.
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
PUT: 200,
|
|
487
|
-
POST: 201,
|
|
488
|
-
DELETE: 204,
|
|
489
|
-
};
|
|
490
|
-
return defaultStatusCodes[httpMethod.toUpperCase()] || 200;
|
|
77
|
+
function mapToSwaggerSpec(metadata, options, logger) {
|
|
78
|
+
const swaggerSpec = {
|
|
79
|
+
openapi: '3.0.0',
|
|
80
|
+
info: {
|
|
81
|
+
title: options?.title || 'API Documentation',
|
|
82
|
+
version: options?.version || '1.0.0',
|
|
83
|
+
},
|
|
84
|
+
paths: {},
|
|
85
|
+
tags: [],
|
|
86
|
+
components: {
|
|
87
|
+
schemas: globalSchemas,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
for (const controller of metadata) {
|
|
91
|
+
const cmeta = controller.meta;
|
|
92
|
+
if (cmeta?.swaggerExclude)
|
|
93
|
+
continue;
|
|
94
|
+
const controllerTags = cmeta?.swaggerTags || [];
|
|
95
|
+
for (const handler of controller.handlers) {
|
|
96
|
+
const hmeta = handler.meta;
|
|
97
|
+
const hh = handler.handler;
|
|
98
|
+
if (hh.type !== 'HTTP' || hmeta?.swaggerExclude || !handler.registeredAs.length)
|
|
99
|
+
continue;
|
|
100
|
+
const handlerPath = handler.registeredAs[0].path;
|
|
101
|
+
const handlerMethod = hh.method?.toLowerCase() || 'get';
|
|
102
|
+
const handlerDescription = hmeta?.description;
|
|
103
|
+
const handlerTags = [...controllerTags, ...(hmeta?.swaggerTags || [])];
|
|
104
|
+
if (!swaggerSpec.paths[handlerPath]) {
|
|
105
|
+
swaggerSpec.paths[handlerPath] = {};
|
|
106
|
+
}
|
|
107
|
+
let responses = undefined;
|
|
108
|
+
if (hmeta?.swaggerResponses) {
|
|
109
|
+
for (const [code, responseConfigs] of Object.entries(hmeta.swaggerResponses)) {
|
|
110
|
+
const newCode = code === '0' ? getDefaultStatusCode(handlerMethod) : code;
|
|
111
|
+
for (const [contentType, type] of Object.entries(responseConfigs)) {
|
|
112
|
+
let schema = undefined;
|
|
113
|
+
let zt = undefined;
|
|
114
|
+
if (type instanceof zod.z.ZodType) {
|
|
115
|
+
zt = type;
|
|
116
|
+
}
|
|
117
|
+
else if (typeof type === 'function') {
|
|
118
|
+
zt = zod.getZodType({
|
|
119
|
+
type,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (zt) {
|
|
123
|
+
const parsed = myParseZod(zt);
|
|
124
|
+
if (['ZodString', 'ZodNumber', 'ZodObject', 'ZodArray', 'ZodBoolean'].includes(parsed.$type)) {
|
|
125
|
+
schema = getSwaggerSchema(parsed);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (schema) {
|
|
129
|
+
responses = responses || {};
|
|
130
|
+
responses[newCode] = { content: { [contentType]: { schema } } };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else if (hmeta?.returnType) {
|
|
136
|
+
const parsed = myParseZod(zod.getZodType({
|
|
137
|
+
type: hmeta.returnType,
|
|
138
|
+
}));
|
|
139
|
+
if (['ZodString', 'ZodNumber', 'ZodObject', 'ZodArray', 'ZodBoolean'].includes(parsed.$type)) {
|
|
140
|
+
const schema = getSwaggerSchema(parsed);
|
|
141
|
+
if (schema) {
|
|
142
|
+
responses = responses || {};
|
|
143
|
+
responses[getDefaultStatusCode(handlerMethod)] = {
|
|
144
|
+
content: {
|
|
145
|
+
'*/*': {
|
|
146
|
+
schema,
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
let reqBodyRequired = true;
|
|
154
|
+
const bodyConfig = {};
|
|
155
|
+
if (hmeta?.swaggerRequestBody) {
|
|
156
|
+
for (const [contentType, type] of Object.entries(hmeta?.swaggerRequestBody)) {
|
|
157
|
+
let zt;
|
|
158
|
+
let schema;
|
|
159
|
+
if (type instanceof zod.z.ZodType) {
|
|
160
|
+
zt = type;
|
|
161
|
+
}
|
|
162
|
+
else if (typeof type === 'function') {
|
|
163
|
+
zt = zod.getZodType({
|
|
164
|
+
type,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
if (zt) {
|
|
168
|
+
const parsed = myParseZod(zt);
|
|
169
|
+
if (['ZodString', 'ZodNumber', 'ZodObject', 'ZodArray', 'ZodBoolean'].includes(parsed.$type)) {
|
|
170
|
+
schema = getSwaggerSchema(parsed);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
bodyConfig[contentType] = { schema };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
swaggerSpec.paths[handlerPath][handlerMethod] = {
|
|
177
|
+
summary: handlerDescription,
|
|
178
|
+
operationId: handlerMethod.toUpperCase() + '_' + handlerPath.replace(/\//g, '_').replace(/[\{\}]/g, '__').replace(/[^A-Za-z0-9]/g, '_'),
|
|
179
|
+
tags: handlerTags,
|
|
180
|
+
parameters: [],
|
|
181
|
+
responses,
|
|
182
|
+
};
|
|
183
|
+
const endpointSpec = swaggerSpec.paths[handlerPath][handlerMethod];
|
|
184
|
+
for (const paramName of handler.registeredAs[0].args) {
|
|
185
|
+
const paramIndex = handler.meta.params.findIndex(param => param.paramSource === 'ROUTE' && param.paramName === paramName);
|
|
186
|
+
const paramMeta = handler.meta.params[paramIndex];
|
|
187
|
+
let schema;
|
|
188
|
+
let parsed;
|
|
189
|
+
if (paramMeta) {
|
|
190
|
+
const zodType = zod.getZodTypeForProp({
|
|
191
|
+
type: controller.type,
|
|
192
|
+
key: handler.method,
|
|
193
|
+
index: paramIndex,
|
|
194
|
+
}, {
|
|
195
|
+
type: paramMeta.type,
|
|
196
|
+
additionalMeta: paramMeta,
|
|
197
|
+
}, undefined, logger);
|
|
198
|
+
parsed = myParseZod(zodType);
|
|
199
|
+
schema = getSwaggerSchema(parsed, true);
|
|
200
|
+
}
|
|
201
|
+
endpointSpec.parameters.push({
|
|
202
|
+
name: paramName,
|
|
203
|
+
in: 'path',
|
|
204
|
+
description: paramMeta ? paramMeta.description : undefined,
|
|
205
|
+
required: !paramMeta?.optional && !parsed?.$optional,
|
|
206
|
+
schema: schema || { type: 'string' },
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
for (let i = 0; i < handler.meta.params.length; i++) {
|
|
210
|
+
const paramMeta = handler.meta.params[i];
|
|
211
|
+
if (paramMeta.paramSource && ['QUERY_ITEM', 'QUERY'].includes(paramMeta.paramSource)) {
|
|
212
|
+
const zodType = zod.getZodTypeForProp({
|
|
213
|
+
type: controller.type,
|
|
214
|
+
key: handler.method,
|
|
215
|
+
index: i,
|
|
216
|
+
}, {
|
|
217
|
+
type: paramMeta.type,
|
|
218
|
+
additionalMeta: paramMeta,
|
|
219
|
+
}, undefined, logger);
|
|
220
|
+
const parsed = myParseZod(zodType);
|
|
221
|
+
const schema = getSwaggerSchema(parsed, true);
|
|
222
|
+
if (paramMeta.paramSource == 'QUERY_ITEM') {
|
|
223
|
+
endpointSpec.parameters.push({
|
|
224
|
+
name: paramMeta.paramName || '',
|
|
225
|
+
in: 'query',
|
|
226
|
+
description: paramMeta.description,
|
|
227
|
+
required: !paramMeta?.optional && !parsed?.$optional,
|
|
228
|
+
schema: schema || { type: 'string' },
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
else if (paramMeta.paramSource == 'QUERY') {
|
|
232
|
+
if (parsed.$type === 'ZodObject') {
|
|
233
|
+
for (const [key, value] of Object.entries(parsed.$inner)) {
|
|
234
|
+
const schema = getSwaggerSchema(value, true);
|
|
235
|
+
if (schema) {
|
|
236
|
+
const swaggerSchema = {
|
|
237
|
+
name: key,
|
|
238
|
+
in: 'query',
|
|
239
|
+
description: value.description,
|
|
240
|
+
required: !parsed.$optional && !value.$optional,
|
|
241
|
+
schema,
|
|
242
|
+
};
|
|
243
|
+
endpointSpec.parameters.push(swaggerSchema);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (paramMeta?.paramSource === 'BODY') {
|
|
250
|
+
const zodType = zod.getZodTypeForProp({
|
|
251
|
+
type: controller.type,
|
|
252
|
+
key: handler.method,
|
|
253
|
+
index: i,
|
|
254
|
+
}, {
|
|
255
|
+
type: paramMeta.type,
|
|
256
|
+
additionalMeta: paramMeta,
|
|
257
|
+
}, undefined, logger);
|
|
258
|
+
const parsed = myParseZod(zodType);
|
|
259
|
+
let contentType = '';
|
|
260
|
+
switch (parsed.$type) {
|
|
261
|
+
case 'ZodString':
|
|
262
|
+
case 'ZodNumber':
|
|
263
|
+
case 'ZodBigInt':
|
|
264
|
+
case 'ZodBoolean':
|
|
265
|
+
case 'ZodDate':
|
|
266
|
+
case 'ZodEnum':
|
|
267
|
+
case 'ZodNativeEnum':
|
|
268
|
+
case 'ZodLiteral':
|
|
269
|
+
contentType = 'text/plan';
|
|
270
|
+
break;
|
|
271
|
+
default: contentType = 'application/json';
|
|
272
|
+
}
|
|
273
|
+
if (!bodyConfig[contentType]) {
|
|
274
|
+
bodyConfig[contentType] = { schema: getSwaggerSchema(parsed) };
|
|
275
|
+
}
|
|
276
|
+
reqBodyRequired = !zodType.isOptional() && !paramMeta.optional;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (bodyConfig && Object.entries(bodyConfig).filter(e => !!e[1]).length > 0) {
|
|
280
|
+
swaggerSpec.paths[handlerPath][handlerMethod].requestBody = {
|
|
281
|
+
content: bodyConfig,
|
|
282
|
+
required: reqBodyRequired,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return swaggerSpec;
|
|
288
|
+
}
|
|
289
|
+
const globalSchemas = {};
|
|
290
|
+
function getSwaggerSchema(parsed, forParam) {
|
|
291
|
+
const zodType = parsed.$ref;
|
|
292
|
+
if (!forParam && zodType.__type_ref && globalSchemas[zodType.__type_ref.name])
|
|
293
|
+
return { $ref: `#/components/schemas/${zodType.__type_ref.name}` };
|
|
294
|
+
if (forParam && zodType.__type_ref && globalSchemas[zodType.__type_ref.name])
|
|
295
|
+
return globalSchemas[zodType.__type_ref.name];
|
|
296
|
+
const schema = {};
|
|
297
|
+
if (!forParam && zodType.__type_ref) {
|
|
298
|
+
globalSchemas[zodType.__type_ref.name] = schema;
|
|
299
|
+
}
|
|
300
|
+
function asString() {
|
|
301
|
+
schema.type = 'string';
|
|
302
|
+
if (parsed.$checks) {
|
|
303
|
+
const { regex } = parsed.$checks;
|
|
304
|
+
if (regex) {
|
|
305
|
+
schema.pattern = regex.source;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function asLiteral() {
|
|
310
|
+
if (parsed.$type === 'ZodLiteral') {
|
|
311
|
+
schema.type = 'string';
|
|
312
|
+
schema.enum = [parsed.$value];
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function asEnum() {
|
|
316
|
+
if (parsed.$type === 'ZodEnum') {
|
|
317
|
+
schema.type = 'string';
|
|
318
|
+
schema.enum = parsed.$value;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function asNativeEnum() {
|
|
322
|
+
if (parsed.$type === 'ZodNativeEnum') {
|
|
323
|
+
schema.type = 'string';
|
|
324
|
+
schema.enum = Object.keys(parsed.$value);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (forParam) {
|
|
328
|
+
switch (parsed.$type) {
|
|
329
|
+
case 'ZodAny':
|
|
330
|
+
case 'ZodUnknown':
|
|
331
|
+
case 'ZodString':
|
|
332
|
+
asString();
|
|
333
|
+
break;
|
|
334
|
+
case 'ZodNumber':
|
|
335
|
+
schema.type = 'number';
|
|
336
|
+
break;
|
|
337
|
+
case 'ZodBigInt':
|
|
338
|
+
schema.type = 'integer';
|
|
339
|
+
break;
|
|
340
|
+
case 'ZodBoolean':
|
|
341
|
+
schema.type = 'boolean';
|
|
342
|
+
break;
|
|
343
|
+
case 'ZodLiteral':
|
|
344
|
+
asLiteral();
|
|
345
|
+
break;
|
|
346
|
+
case 'ZodEnum':
|
|
347
|
+
asEnum();
|
|
348
|
+
break;
|
|
349
|
+
case 'ZodNativeEnum':
|
|
350
|
+
asNativeEnum();
|
|
351
|
+
break;
|
|
352
|
+
case 'ZodDate':
|
|
353
|
+
schema.type = 'string';
|
|
354
|
+
break;
|
|
355
|
+
case 'ZodNull':
|
|
356
|
+
schema.type = 'null';
|
|
357
|
+
break;
|
|
358
|
+
default: return undefined;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
switch (parsed.$type) {
|
|
363
|
+
case 'ZodString':
|
|
364
|
+
asString();
|
|
365
|
+
break;
|
|
366
|
+
case 'ZodNumber':
|
|
367
|
+
schema.type = 'number';
|
|
368
|
+
break;
|
|
369
|
+
case 'ZodBigInt':
|
|
370
|
+
schema.type = 'integer';
|
|
371
|
+
break;
|
|
372
|
+
case 'ZodBoolean':
|
|
373
|
+
schema.type = 'boolean';
|
|
374
|
+
break;
|
|
375
|
+
case 'ZodLiteral':
|
|
376
|
+
asLiteral();
|
|
377
|
+
break;
|
|
378
|
+
case 'ZodEnum':
|
|
379
|
+
asEnum();
|
|
380
|
+
break;
|
|
381
|
+
case 'ZodNativeEnum':
|
|
382
|
+
asNativeEnum();
|
|
383
|
+
break;
|
|
384
|
+
case 'ZodDate':
|
|
385
|
+
schema.type = 'string';
|
|
386
|
+
break;
|
|
387
|
+
case 'ZodNull':
|
|
388
|
+
schema.type = 'null';
|
|
389
|
+
break;
|
|
390
|
+
case 'ZodFunction':
|
|
391
|
+
case 'ZodSymbol':
|
|
392
|
+
case 'ZodUndefined':
|
|
393
|
+
case 'ZodUnknown':
|
|
394
|
+
case 'ZodNever':
|
|
395
|
+
case 'ZodVoid':
|
|
396
|
+
case 'ZodNaN':
|
|
397
|
+
return undefined;
|
|
398
|
+
case 'ZodArray':
|
|
399
|
+
schema.type = 'array';
|
|
400
|
+
schema.minItems = parsed.$checks?.minLength || undefined;
|
|
401
|
+
schema.maxItems = parsed.$checks?.maxLength || undefined;
|
|
402
|
+
schema.items = getSwaggerSchema(parsed.$inner);
|
|
403
|
+
break;
|
|
404
|
+
case 'ZodTuple':
|
|
405
|
+
schema.type = 'array';
|
|
406
|
+
schema.items = parsed.$inner.map(t => getSwaggerSchema(t)).filter(t => !!t);
|
|
407
|
+
break;
|
|
408
|
+
case 'ZodObject':
|
|
409
|
+
schema.type = 'object';
|
|
410
|
+
schema.properties = {};
|
|
411
|
+
schema.required = [];
|
|
412
|
+
if (zodType._def.unknownKeys === 'passthrough')
|
|
413
|
+
schema.additionalProperties = {};
|
|
414
|
+
for (const [key, val] of Object.entries(parsed.$inner)) {
|
|
415
|
+
const prop = getSwaggerSchema(val);
|
|
416
|
+
if (prop) {
|
|
417
|
+
schema.properties[key] = prop;
|
|
418
|
+
if (!val.$optional)
|
|
419
|
+
schema.required.push(key);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
break;
|
|
423
|
+
case 'ZodPromise':
|
|
424
|
+
case 'ZodRecord':
|
|
425
|
+
case 'ZodMap':
|
|
426
|
+
case 'ZodSet':
|
|
427
|
+
schema.type = 'object';
|
|
428
|
+
schema.properties = {};
|
|
429
|
+
schema.additionalProperties = parsed.$type === 'ZodRecord' ? {} : undefined;
|
|
430
|
+
break;
|
|
431
|
+
case 'ZodUnion':
|
|
432
|
+
case 'ZodDiscriminatedUnion':
|
|
433
|
+
schema.oneOf = parsed.$inner.map(t => getSwaggerSchema(t)).filter(t => !!t);
|
|
434
|
+
break;
|
|
435
|
+
case 'ZodIntersection':
|
|
436
|
+
schema.allOf = parsed.$inner.map(t => getSwaggerSchema(t)).filter(t => !!t);
|
|
437
|
+
break;
|
|
438
|
+
case 'ZodLazy':
|
|
439
|
+
return getSwaggerSchema(parsed.$get());
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
if (parsed.$nullable) {
|
|
443
|
+
schema.nullable = parsed.$nullable;
|
|
444
|
+
}
|
|
445
|
+
if (parsed.$ref._def.description) {
|
|
446
|
+
schema.description = parsed.$ref._def.description;
|
|
447
|
+
}
|
|
448
|
+
if (parsed.$checks) {
|
|
449
|
+
const checks = parsed.$checks;
|
|
450
|
+
if (parsed.$type === 'ZodString') {
|
|
451
|
+
if (typeof checks.min === 'number')
|
|
452
|
+
schema.minLength = checks.min;
|
|
453
|
+
if (typeof checks.max === 'number')
|
|
454
|
+
schema.maxLength = checks.max;
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
if (typeof checks.min === 'number')
|
|
458
|
+
schema.minimum = checks.min;
|
|
459
|
+
if (typeof checks.max === 'number')
|
|
460
|
+
schema.maximum = checks.max;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
if (!forParam && zodType.__type_ref) {
|
|
464
|
+
return { $ref: `#/components/schemas/${zodType.__type_ref.name}` };
|
|
465
|
+
}
|
|
466
|
+
return schema;
|
|
467
|
+
}
|
|
468
|
+
function myParseZod(schema) {
|
|
469
|
+
return zodParser.parseZodType(schema);
|
|
470
|
+
}
|
|
471
|
+
function getDefaultStatusCode(httpMethod) {
|
|
472
|
+
const defaultStatusCodes = {
|
|
473
|
+
GET: 200,
|
|
474
|
+
PUT: 200,
|
|
475
|
+
POST: 201,
|
|
476
|
+
DELETE: 204,
|
|
477
|
+
};
|
|
478
|
+
return defaultStatusCodes[httpMethod.toUpperCase()] || 200;
|
|
491
479
|
}
|
|
492
480
|
|
|
493
|
-
exports.SwaggerController = class SwaggerController {
|
|
494
|
-
constructor(title = 'Moost API') {
|
|
495
|
-
this.title = title;
|
|
496
|
-
this.assetPath = swaggerUiDist.getAbsoluteFSPath();
|
|
497
|
-
}
|
|
498
|
-
serveIndex(url, location, status) {
|
|
499
|
-
if (!url.endsWith('index.html') && !url.endsWith('/')) {
|
|
500
|
-
status.value = 302;
|
|
501
|
-
location.value = path.join(url, '/');
|
|
502
|
-
return '';
|
|
503
|
-
}
|
|
481
|
+
exports.SwaggerController = class SwaggerController {
|
|
482
|
+
constructor(title = 'Moost API') {
|
|
483
|
+
this.title = title;
|
|
484
|
+
this.assetPath = swaggerUiDist.getAbsoluteFSPath();
|
|
485
|
+
}
|
|
486
|
+
serveIndex(url, location, status) {
|
|
487
|
+
if (!url.endsWith('index.html') && !url.endsWith('/')) {
|
|
488
|
+
status.value = 302;
|
|
489
|
+
location.value = path.join(url, '/');
|
|
490
|
+
return '';
|
|
491
|
+
}
|
|
504
492
|
return `<!DOCTYPE html>
|
|
505
493
|
<html lang="en">
|
|
506
494
|
<head>
|
|
@@ -518,9 +506,9 @@ exports.SwaggerController = class SwaggerController {
|
|
|
518
506
|
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
|
|
519
507
|
<script src="./swagger-initializer.js" charset="UTF-8"> </script>
|
|
520
508
|
</body>
|
|
521
|
-
</html>`;
|
|
522
|
-
}
|
|
523
|
-
'swagger-initializer.js'() {
|
|
509
|
+
</html>`;
|
|
510
|
+
}
|
|
511
|
+
'swagger-initializer.js'() {
|
|
524
512
|
return `window.onload = function() {
|
|
525
513
|
window.ui = SwaggerUIBundle({
|
|
526
514
|
url: "./spec.json",
|
|
@@ -535,73 +523,71 @@ exports.SwaggerController = class SwaggerController {
|
|
|
535
523
|
],
|
|
536
524
|
layout: "BaseLayout"
|
|
537
525
|
});
|
|
538
|
-
};`;
|
|
539
|
-
}
|
|
540
|
-
'spec.json'() {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
eventHttp.Get(''),
|
|
566
|
-
eventHttp.
|
|
567
|
-
eventHttp.
|
|
568
|
-
eventHttp.
|
|
569
|
-
__param(
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
__metadata("design:
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
__metadata("design:
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
__metadata("design:
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
eventHttp.Get('swagger-ui
|
|
591
|
-
eventHttp.Get('
|
|
592
|
-
eventHttp.
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
__metadata("design:
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
__param(0, moost.Const('Moost API')),
|
|
604
|
-
__metadata("design:paramtypes", [Object])
|
|
526
|
+
};`;
|
|
527
|
+
}
|
|
528
|
+
async 'spec.json'() {
|
|
529
|
+
const logger = moost.useEventLogger('@moostjs/zod');
|
|
530
|
+
if (!this.spec) {
|
|
531
|
+
const { instantiate } = moost.useControllerContext();
|
|
532
|
+
const moost$1 = await instantiate(moost.Moost);
|
|
533
|
+
this.spec = mapToSwaggerSpec(moost$1.getControllersOverview(), { title: this.title }, logger);
|
|
534
|
+
}
|
|
535
|
+
return this.spec;
|
|
536
|
+
}
|
|
537
|
+
files(url) {
|
|
538
|
+
return this.serve(url.split('/').pop());
|
|
539
|
+
}
|
|
540
|
+
serve(path) {
|
|
541
|
+
return httpStatic.serveFile(path, {
|
|
542
|
+
baseDir: this.assetPath,
|
|
543
|
+
cacheControl: {
|
|
544
|
+
public: true,
|
|
545
|
+
maxAge: '1w',
|
|
546
|
+
},
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
__decorate([
|
|
551
|
+
eventHttp.Get(''),
|
|
552
|
+
eventHttp.Get('//'),
|
|
553
|
+
eventHttp.Get('index.html'),
|
|
554
|
+
eventHttp.SetHeader('content-type', 'text/html'),
|
|
555
|
+
__param(0, eventHttp.Url()),
|
|
556
|
+
__param(1, eventHttp.HeaderHook('location')),
|
|
557
|
+
__param(2, eventHttp.StatusHook()),
|
|
558
|
+
__metadata("design:type", Function),
|
|
559
|
+
__metadata("design:paramtypes", [String, Object, Object]),
|
|
560
|
+
__metadata("design:returntype", void 0)
|
|
561
|
+
], exports.SwaggerController.prototype, "serveIndex", null);
|
|
562
|
+
__decorate([
|
|
563
|
+
eventHttp.Get(),
|
|
564
|
+
eventHttp.SetHeader('content-type', 'application/javascript'),
|
|
565
|
+
__metadata("design:type", Function),
|
|
566
|
+
__metadata("design:paramtypes", []),
|
|
567
|
+
__metadata("design:returntype", void 0)
|
|
568
|
+
], exports.SwaggerController.prototype, "swagger-initializer.js", null);
|
|
569
|
+
__decorate([
|
|
570
|
+
eventHttp.Get(),
|
|
571
|
+
__metadata("design:type", Function),
|
|
572
|
+
__metadata("design:paramtypes", []),
|
|
573
|
+
__metadata("design:returntype", Promise)
|
|
574
|
+
], exports.SwaggerController.prototype, "spec.json", null);
|
|
575
|
+
__decorate([
|
|
576
|
+
eventHttp.Get('swagger-ui-bundle.*(js|js\\.map)'),
|
|
577
|
+
eventHttp.Get('swagger-ui-standalone-preset.*(js|js\\.map)'),
|
|
578
|
+
eventHttp.Get('swagger-ui.*(css|css\\.map)'),
|
|
579
|
+
eventHttp.Get('index.*(css|css\\.map)'),
|
|
580
|
+
__param(0, eventHttp.Url()),
|
|
581
|
+
__metadata("design:type", Function),
|
|
582
|
+
__metadata("design:paramtypes", [String]),
|
|
583
|
+
__metadata("design:returntype", void 0)
|
|
584
|
+
], exports.SwaggerController.prototype, "files", null);
|
|
585
|
+
exports.SwaggerController = __decorate([
|
|
586
|
+
SwaggerExclude(),
|
|
587
|
+
zod.ZodSkip(),
|
|
588
|
+
moost.Controller('api-docs'),
|
|
589
|
+
__param(0, moost.Const('Moost API')),
|
|
590
|
+
__metadata("design:paramtypes", [Object])
|
|
605
591
|
], exports.SwaggerController);
|
|
606
592
|
|
|
607
593
|
exports.SwaggerDescription = SwaggerDescription;
|