@moostjs/swagger 0.3.9 → 0.3.11
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 +516 -525
- package/dist/index.mjs +516 -525
- package/package.json +6 -6
package/dist/index.mjs
CHANGED
|
@@ -20,7 +20,7 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
20
20
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
21
21
|
PERFORMANCE OF THIS SOFTWARE.
|
|
22
22
|
***************************************************************************** */
|
|
23
|
-
/* global Reflect, Promise */
|
|
23
|
+
/* global Reflect, Promise, SuppressedError, Symbol */
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
function __decorate(decorators, target, key, desc) {
|
|
@@ -38,467 +38,460 @@ function __metadata(metadataKey, metadataValue) {
|
|
|
38
38
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
return
|
|
44
|
-
|
|
45
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
46
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
47
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
48
|
-
});
|
|
49
|
-
}
|
|
41
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
42
|
+
var e = new Error(message);
|
|
43
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
44
|
+
};
|
|
50
45
|
|
|
51
|
-
function getSwaggerMate() {
|
|
52
|
-
return getMoostMate();
|
|
46
|
+
function getSwaggerMate() {
|
|
47
|
+
return getMoostMate();
|
|
53
48
|
}
|
|
54
49
|
|
|
55
|
-
const SwaggerTag = (tag) => getSwaggerMate().decorate('swaggerTags', tag, true);
|
|
56
|
-
const SwaggerExclude = () => getSwaggerMate().decorate('swaggerExclude', true);
|
|
57
|
-
const SwaggerDescription = (descr) => getSwaggerMate().decorate('swaggerDescription', descr);
|
|
58
|
-
function SwaggerResponse(code, opts) {
|
|
59
|
-
return getSwaggerMate().decorate((meta) => {
|
|
60
|
-
meta.swaggerResponses = meta.swaggerResponses || {};
|
|
61
|
-
const keyCode = typeof code === 'number' ? code : 0;
|
|
62
|
-
const opt = typeof code === 'number' ? opts : code;
|
|
63
|
-
const contentType = typeof opt.contentType === 'string' ? opt.contentType : '*/*';
|
|
64
|
-
// const description = typeof (opt as { description: string }).description === 'string' ? (opt as { description: string }).description : undefined
|
|
65
|
-
const response = (['object', 'function'].includes(typeof opt.response) ? opt.response : opt);
|
|
66
|
-
meta.swaggerResponses[keyCode] = meta.swaggerResponses[keyCode] || {};
|
|
67
|
-
meta.swaggerResponses[keyCode][contentType] = response;
|
|
68
|
-
// meta.swaggerResponses[keyCode].description = description
|
|
69
|
-
return meta;
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
function SwaggerRequestBody(opt) {
|
|
73
|
-
return getSwaggerMate().decorate((meta) => {
|
|
74
|
-
meta.swaggerRequestBody = meta.swaggerRequestBody || {};
|
|
75
|
-
const contentType = typeof opt.contentType === 'string' ? opt.contentType : 'application/json';
|
|
76
|
-
const response = (typeof opt.contentType === 'string' ? opt.response : opt);
|
|
77
|
-
meta.swaggerRequestBody[contentType] = response;
|
|
78
|
-
return meta;
|
|
79
|
-
});
|
|
50
|
+
const SwaggerTag = (tag) => getSwaggerMate().decorate('swaggerTags', tag, true);
|
|
51
|
+
const SwaggerExclude = () => getSwaggerMate().decorate('swaggerExclude', true);
|
|
52
|
+
const SwaggerDescription = (descr) => getSwaggerMate().decorate('swaggerDescription', descr);
|
|
53
|
+
function SwaggerResponse(code, opts) {
|
|
54
|
+
return getSwaggerMate().decorate((meta) => {
|
|
55
|
+
meta.swaggerResponses = meta.swaggerResponses || {};
|
|
56
|
+
const keyCode = typeof code === 'number' ? code : 0;
|
|
57
|
+
const opt = typeof code === 'number' ? opts : code;
|
|
58
|
+
const contentType = typeof opt.contentType === 'string' ? opt.contentType : '*/*';
|
|
59
|
+
// const description = typeof (opt as { description: string }).description === 'string' ? (opt as { description: string }).description : undefined
|
|
60
|
+
const response = (['object', 'function'].includes(typeof opt.response) ? opt.response : opt);
|
|
61
|
+
meta.swaggerResponses[keyCode] = meta.swaggerResponses[keyCode] || {};
|
|
62
|
+
meta.swaggerResponses[keyCode][contentType] = response;
|
|
63
|
+
// meta.swaggerResponses[keyCode].description = description
|
|
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
|
+
});
|
|
80
75
|
}
|
|
81
76
|
|
|
82
|
-
function mapToSwaggerSpec(metadata, options, logger) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
let
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
responses =
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
responses =
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
let
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
let
|
|
194
|
-
|
|
195
|
-
|
|
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
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
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
|
-
case '
|
|
268
|
-
case '
|
|
269
|
-
case '
|
|
270
|
-
case '
|
|
271
|
-
case '
|
|
272
|
-
case '
|
|
273
|
-
case '
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if (
|
|
300
|
-
return
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
case '
|
|
337
|
-
|
|
338
|
-
|
|
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
|
-
case '
|
|
398
|
-
case '
|
|
399
|
-
case '
|
|
400
|
-
case '
|
|
401
|
-
case '
|
|
402
|
-
|
|
403
|
-
case '
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
schema.
|
|
408
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
409
|
-
schema.
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
schema.
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
case '
|
|
434
|
-
case '
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
schema.
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
if (typeof checks.
|
|
462
|
-
schema.
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
if (typeof checks.
|
|
468
|
-
schema.
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
};
|
|
488
|
-
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 z.ZodType) {
|
|
115
|
+
zt = type;
|
|
116
|
+
}
|
|
117
|
+
else if (typeof type === 'function') {
|
|
118
|
+
zt = 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(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 z.ZodType) {
|
|
160
|
+
zt = type;
|
|
161
|
+
}
|
|
162
|
+
else if (typeof type === 'function') {
|
|
163
|
+
zt = 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 = 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 = 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 = 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 'ZodAny':
|
|
399
|
+
case 'ZodArray':
|
|
400
|
+
schema.type = 'array';
|
|
401
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
402
|
+
schema.minItems = parsed.$checks?.minLength || undefined;
|
|
403
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
404
|
+
schema.maxItems = parsed.$checks?.maxLength || undefined;
|
|
405
|
+
schema.items = getSwaggerSchema(parsed.$inner);
|
|
406
|
+
break;
|
|
407
|
+
case 'ZodTuple':
|
|
408
|
+
schema.type = 'array';
|
|
409
|
+
schema.items = parsed.$inner.map(t => getSwaggerSchema(t)).filter(t => !!t);
|
|
410
|
+
break;
|
|
411
|
+
case 'ZodObject':
|
|
412
|
+
schema.type = 'object';
|
|
413
|
+
schema.properties = {};
|
|
414
|
+
schema.required = [];
|
|
415
|
+
if (zodType._def.unknownKeys === 'passthrough')
|
|
416
|
+
schema.additionalProperties = {};
|
|
417
|
+
for (const [key, val] of Object.entries(parsed.$inner)) {
|
|
418
|
+
const prop = getSwaggerSchema(val);
|
|
419
|
+
if (prop) {
|
|
420
|
+
schema.properties[key] = prop;
|
|
421
|
+
if (!val.$optional)
|
|
422
|
+
schema.required.push(key);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
break;
|
|
426
|
+
case 'ZodPromise':
|
|
427
|
+
case 'ZodRecord':
|
|
428
|
+
case 'ZodMap':
|
|
429
|
+
case 'ZodSet':
|
|
430
|
+
schema.type = 'object';
|
|
431
|
+
schema.properties = {};
|
|
432
|
+
schema.additionalProperties = parsed.$type === 'ZodRecord' ? {} : undefined;
|
|
433
|
+
break;
|
|
434
|
+
case 'ZodUnion':
|
|
435
|
+
case 'ZodDiscriminatedUnion':
|
|
436
|
+
schema.oneOf = parsed.$inner.map(t => getSwaggerSchema(t)).filter(t => !!t);
|
|
437
|
+
break;
|
|
438
|
+
case 'ZodIntersection':
|
|
439
|
+
schema.allOf = parsed.$inner.map(t => getSwaggerSchema(t)).filter(t => !!t);
|
|
440
|
+
break;
|
|
441
|
+
case 'ZodLazy':
|
|
442
|
+
return getSwaggerSchema(parsed.$get());
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (parsed.$nullable) {
|
|
446
|
+
schema.nullable = parsed.$nullable;
|
|
447
|
+
}
|
|
448
|
+
if (parsed.$ref._def.description) {
|
|
449
|
+
schema.description = parsed.$ref._def.description;
|
|
450
|
+
}
|
|
451
|
+
if (parsed.$checks) {
|
|
452
|
+
const checks = parsed.$checks;
|
|
453
|
+
if (parsed.$type === 'ZodString') {
|
|
454
|
+
if (typeof checks.min === 'number')
|
|
455
|
+
schema.minLength = checks.min;
|
|
456
|
+
if (typeof checks.max === 'number')
|
|
457
|
+
schema.maxLength = checks.max;
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
if (typeof checks.min === 'number')
|
|
461
|
+
schema.minimum = checks.min;
|
|
462
|
+
if (typeof checks.max === 'number')
|
|
463
|
+
schema.maximum = checks.max;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
if (!forParam && zodType.__type_ref) {
|
|
467
|
+
return { $ref: `#/components/schemas/${zodType.__type_ref.name}` };
|
|
468
|
+
}
|
|
469
|
+
return schema;
|
|
470
|
+
}
|
|
471
|
+
function myParseZod(schema) {
|
|
472
|
+
return parseZodType(schema);
|
|
473
|
+
}
|
|
474
|
+
function getDefaultStatusCode(httpMethod) {
|
|
475
|
+
const defaultStatusCodes = {
|
|
476
|
+
GET: 200,
|
|
477
|
+
PUT: 200,
|
|
478
|
+
POST: 201,
|
|
479
|
+
DELETE: 204,
|
|
480
|
+
};
|
|
481
|
+
return defaultStatusCodes[httpMethod.toUpperCase()] || 200;
|
|
489
482
|
}
|
|
490
483
|
|
|
491
|
-
let SwaggerController = class SwaggerController {
|
|
492
|
-
constructor(title = 'Moost API') {
|
|
493
|
-
this.title = title;
|
|
494
|
-
this.assetPath = getAbsoluteFSPath();
|
|
495
|
-
}
|
|
496
|
-
serveIndex(url, location, status) {
|
|
497
|
-
if (!url.endsWith('index.html') && !url.endsWith('/')) {
|
|
498
|
-
status.value = 302;
|
|
499
|
-
location.value = join(url, '/');
|
|
500
|
-
return '';
|
|
501
|
-
}
|
|
484
|
+
let SwaggerController = class SwaggerController {
|
|
485
|
+
constructor(title = 'Moost API') {
|
|
486
|
+
this.title = title;
|
|
487
|
+
this.assetPath = getAbsoluteFSPath();
|
|
488
|
+
}
|
|
489
|
+
serveIndex(url, location, status) {
|
|
490
|
+
if (!url.endsWith('index.html') && !url.endsWith('/')) {
|
|
491
|
+
status.value = 302;
|
|
492
|
+
location.value = join(url, '/');
|
|
493
|
+
return '';
|
|
494
|
+
}
|
|
502
495
|
return `<!DOCTYPE html>
|
|
503
496
|
<html lang="en">
|
|
504
497
|
<head>
|
|
@@ -516,9 +509,9 @@ let SwaggerController = class SwaggerController {
|
|
|
516
509
|
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
|
|
517
510
|
<script src="./swagger-initializer.js" charset="UTF-8"> </script>
|
|
518
511
|
</body>
|
|
519
|
-
</html>`;
|
|
520
|
-
}
|
|
521
|
-
'swagger-initializer.js'() {
|
|
512
|
+
</html>`;
|
|
513
|
+
}
|
|
514
|
+
'swagger-initializer.js'() {
|
|
522
515
|
return `window.onload = function() {
|
|
523
516
|
window.ui = SwaggerUIBundle({
|
|
524
517
|
url: "./spec.json",
|
|
@@ -533,73 +526,71 @@ let SwaggerController = class SwaggerController {
|
|
|
533
526
|
],
|
|
534
527
|
layout: "BaseLayout"
|
|
535
528
|
});
|
|
536
|
-
};`;
|
|
537
|
-
}
|
|
538
|
-
'spec.json'() {
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
Get(''),
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
__param(
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
__metadata("design:
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
__metadata("design:
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
__metadata("design:
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
Get('swagger-ui
|
|
589
|
-
Get('
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
__metadata("design:
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
__param(0, Const('Moost API')),
|
|
602
|
-
__metadata("design:paramtypes", [Object])
|
|
529
|
+
};`;
|
|
530
|
+
}
|
|
531
|
+
async 'spec.json'() {
|
|
532
|
+
const logger = useEventLogger('@moostjs/zod');
|
|
533
|
+
if (!this.spec) {
|
|
534
|
+
const { instantiate } = useControllerContext();
|
|
535
|
+
const moost = await instantiate(Moost);
|
|
536
|
+
this.spec = mapToSwaggerSpec(moost.getControllersOverview(), { title: this.title }, logger);
|
|
537
|
+
}
|
|
538
|
+
return this.spec;
|
|
539
|
+
}
|
|
540
|
+
files(url) {
|
|
541
|
+
return this.serve(url.split('/').pop());
|
|
542
|
+
}
|
|
543
|
+
serve(path) {
|
|
544
|
+
return serveFile(path, {
|
|
545
|
+
baseDir: this.assetPath,
|
|
546
|
+
cacheControl: {
|
|
547
|
+
public: true,
|
|
548
|
+
maxAge: '1w',
|
|
549
|
+
},
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
__decorate([
|
|
554
|
+
Get(''),
|
|
555
|
+
Get('//'),
|
|
556
|
+
Get('index.html'),
|
|
557
|
+
SetHeader('content-type', 'text/html'),
|
|
558
|
+
__param(0, Url()),
|
|
559
|
+
__param(1, HeaderHook('location')),
|
|
560
|
+
__param(2, StatusHook()),
|
|
561
|
+
__metadata("design:type", Function),
|
|
562
|
+
__metadata("design:paramtypes", [String, Object, Object]),
|
|
563
|
+
__metadata("design:returntype", void 0)
|
|
564
|
+
], SwaggerController.prototype, "serveIndex", null);
|
|
565
|
+
__decorate([
|
|
566
|
+
Get(),
|
|
567
|
+
SetHeader('content-type', 'application/javascript'),
|
|
568
|
+
__metadata("design:type", Function),
|
|
569
|
+
__metadata("design:paramtypes", []),
|
|
570
|
+
__metadata("design:returntype", void 0)
|
|
571
|
+
], SwaggerController.prototype, "swagger-initializer.js", null);
|
|
572
|
+
__decorate([
|
|
573
|
+
Get(),
|
|
574
|
+
__metadata("design:type", Function),
|
|
575
|
+
__metadata("design:paramtypes", []),
|
|
576
|
+
__metadata("design:returntype", Promise)
|
|
577
|
+
], SwaggerController.prototype, "spec.json", null);
|
|
578
|
+
__decorate([
|
|
579
|
+
Get('swagger-ui-bundle.*(js|js\\.map)'),
|
|
580
|
+
Get('swagger-ui-standalone-preset.*(js|js\\.map)'),
|
|
581
|
+
Get('swagger-ui.*(css|css\\.map)'),
|
|
582
|
+
Get('index.*(css|css\\.map)'),
|
|
583
|
+
__param(0, Url()),
|
|
584
|
+
__metadata("design:type", Function),
|
|
585
|
+
__metadata("design:paramtypes", [String]),
|
|
586
|
+
__metadata("design:returntype", void 0)
|
|
587
|
+
], SwaggerController.prototype, "files", null);
|
|
588
|
+
SwaggerController = __decorate([
|
|
589
|
+
SwaggerExclude(),
|
|
590
|
+
ZodSkip(),
|
|
591
|
+
Controller('api-docs'),
|
|
592
|
+
__param(0, Const('Moost API')),
|
|
593
|
+
__metadata("design:paramtypes", [Object])
|
|
603
594
|
], SwaggerController);
|
|
604
595
|
|
|
605
596
|
export { SwaggerController, SwaggerDescription, SwaggerExclude, SwaggerRequestBody, SwaggerResponse, SwaggerTag, getSwaggerMate };
|