@midwayjs/swagger 3.17.2 → 3.17.3
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/documentBuilder.js
CHANGED
|
@@ -95,6 +95,19 @@ class DocumentBuilder {
|
|
|
95
95
|
externalDocs,
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
|
+
else {
|
|
99
|
+
// update description and externalDocs
|
|
100
|
+
tags.forEach(tag => {
|
|
101
|
+
if (tag.name === name) {
|
|
102
|
+
if (description) {
|
|
103
|
+
tag.description = description;
|
|
104
|
+
}
|
|
105
|
+
if (externalDocs) {
|
|
106
|
+
tag.externalDocs = externalDocs;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
98
111
|
this.document.tags = tags;
|
|
99
112
|
return this;
|
|
100
113
|
}
|
|
@@ -373,6 +373,10 @@ export interface SwaggerOptions {
|
|
|
373
373
|
* 自定义路由过滤器
|
|
374
374
|
*/
|
|
375
375
|
routerFilter?: (url: string, options: RouterOption) => boolean;
|
|
376
|
+
/**
|
|
377
|
+
* Weather to generate the Tag for controller
|
|
378
|
+
*/
|
|
379
|
+
isGenerateTagForController?: boolean;
|
|
376
380
|
}
|
|
377
381
|
export interface MixDecoratorMetadata {
|
|
378
382
|
key: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RouterOption } from '@midwayjs/core';
|
|
2
2
|
import { Type } from './interfaces';
|
|
3
|
+
import { DocumentBuilder } from './documentBuilder';
|
|
3
4
|
export declare class SwaggerExplorer {
|
|
4
5
|
private swaggerConfig;
|
|
5
6
|
private documentBuilder;
|
|
@@ -8,18 +9,13 @@ export declare class SwaggerExplorer {
|
|
|
8
9
|
addGlobalPrefix(globalPrefix: string): void;
|
|
9
10
|
scanApp(): void;
|
|
10
11
|
getData(): Omit<import("./interfaces").OpenAPIObject, "paths">;
|
|
12
|
+
getDocumentBuilder(): DocumentBuilder;
|
|
11
13
|
protected generatePath(target: Type): void;
|
|
12
14
|
/**
|
|
13
15
|
* 构造 router 提取方法
|
|
14
16
|
*/
|
|
15
17
|
private generateRouteMethod;
|
|
16
18
|
getOperationId(controllerKey: string, webRouter: RouterOption): string;
|
|
17
|
-
/**
|
|
18
|
-
* 提取参数
|
|
19
|
-
* @param params
|
|
20
|
-
* @param p
|
|
21
|
-
*/
|
|
22
|
-
protected parseFromParamsToP(paramMeta: any, p: any): void;
|
|
23
19
|
/**
|
|
24
20
|
* 解析 ApiExtraModel
|
|
25
21
|
* @param clzz
|
package/dist/swaggerExplorer.js
CHANGED
|
@@ -96,13 +96,18 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
96
96
|
getData() {
|
|
97
97
|
return this.documentBuilder.build();
|
|
98
98
|
}
|
|
99
|
+
getDocumentBuilder() {
|
|
100
|
+
return this.documentBuilder;
|
|
101
|
+
}
|
|
99
102
|
generatePath(target) {
|
|
103
|
+
var _a;
|
|
100
104
|
// 获取控制器元数据
|
|
101
105
|
const excludeClassMeta = (0, core_1.getClassMetadata)(constants_1.DECORATORS.API_EXCLUDE_CONTROLLER, target);
|
|
102
106
|
if (excludeClassMeta && excludeClassMeta.disable) {
|
|
103
107
|
// 如果存在需要排除的控制器,则直接返回
|
|
104
108
|
return;
|
|
105
109
|
}
|
|
110
|
+
const isGenerateTagForController = (_a = this.swaggerConfig.isGenerateTagForController) !== null && _a !== void 0 ? _a : true;
|
|
106
111
|
// 解析额外的模型
|
|
107
112
|
this.parseExtraModel(target);
|
|
108
113
|
const metaForClass = (0, core_1.getClassMetadata)(constants_1.DECORATORS_CLASS_METADATA, target) || [];
|
|
@@ -118,33 +123,35 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
118
123
|
const controllerTags = [];
|
|
119
124
|
// 如果存在标签,则将其添加到文档构建器中
|
|
120
125
|
if (tags.length > 0) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
// this.documentBuilder.addTag(t.metadata);
|
|
126
|
-
}
|
|
126
|
+
strTags = parseTags(tags);
|
|
127
|
+
strTags.forEach(tag => {
|
|
128
|
+
addTag(tag, controllerTags);
|
|
129
|
+
});
|
|
127
130
|
}
|
|
128
131
|
else {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
(
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
if (isGenerateTagForController) {
|
|
133
|
+
// 如果不存在标签,则根据控制器选项生成标签
|
|
134
|
+
const tag = { name: '', description: '' };
|
|
135
|
+
if (prefix !== '/') {
|
|
136
|
+
tag.name =
|
|
137
|
+
(controllerOption === null || controllerOption === void 0 ? void 0 : controllerOption.routerOptions.tagName) ||
|
|
138
|
+
(/^\//.test(prefix) ? prefix.split('/')[1] : prefix);
|
|
139
|
+
tag.description =
|
|
140
|
+
(controllerOption === null || controllerOption === void 0 ? void 0 : controllerOption.routerOptions.description) || tag.name;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
tag.name = controllerOption === null || controllerOption === void 0 ? void 0 : controllerOption.routerOptions.tagName;
|
|
144
|
+
tag.description =
|
|
145
|
+
(controllerOption === null || controllerOption === void 0 ? void 0 : controllerOption.routerOptions.description) || tag.name;
|
|
146
|
+
}
|
|
147
|
+
// 如果标签名存在,则将其添加到文档构建器中
|
|
148
|
+
if (tag.name) {
|
|
149
|
+
strTags.push(tag.name);
|
|
150
|
+
addTag([tag.name, tag.description], controllerTags);
|
|
151
|
+
}
|
|
137
152
|
}
|
|
138
153
|
else {
|
|
139
|
-
|
|
140
|
-
tag.description =
|
|
141
|
-
(controllerOption === null || controllerOption === void 0 ? void 0 : controllerOption.routerOptions.description) || tag.name;
|
|
142
|
-
}
|
|
143
|
-
// 如果标签名存在,则将其添加到文档构建器中
|
|
144
|
-
if (tag.name) {
|
|
145
|
-
strTags.push(tag.name);
|
|
146
|
-
controllerTags.push([tag.name, tag.description]);
|
|
147
|
-
// this.documentBuilder.addTag(tag.name, tag.description);
|
|
154
|
+
// 否则不添加标签
|
|
148
155
|
}
|
|
149
156
|
}
|
|
150
157
|
// 获取路由信息
|
|
@@ -198,6 +205,12 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
198
205
|
if (paths[url][webRouter.requestMethod].tags.length === 0) {
|
|
199
206
|
paths[url][webRouter.requestMethod].tags = strTags;
|
|
200
207
|
}
|
|
208
|
+
else {
|
|
209
|
+
// 如果 tags 不在全局中,则添加
|
|
210
|
+
paths[url][webRouter.requestMethod].tags.forEach(tag => {
|
|
211
|
+
addTag(tag, controllerTags);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
201
214
|
// 过滤出扩展信息
|
|
202
215
|
const exts = metaForMethods.filter(item => item.key === constants_1.DECORATORS.API_EXTENSION &&
|
|
203
216
|
item.propertyName === webRouter.method);
|
|
@@ -242,9 +255,12 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
242
255
|
* 构造 router 提取方法
|
|
243
256
|
*/
|
|
244
257
|
generateRouteMethod(url, webRouter, paths, metaForMethods, routerArgs, headers, target) {
|
|
245
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
258
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
|
|
246
259
|
const operMeta = metaForMethods.filter(item => item.key === constants_1.DECORATORS.API_OPERATION &&
|
|
247
260
|
item.propertyName === webRouter.method)[0];
|
|
261
|
+
const routerTagsMeta = metaForMethods.filter(item => item.key === constants_1.DECORATORS.API_TAGS &&
|
|
262
|
+
item.propertyName === webRouter.method);
|
|
263
|
+
const routerTags = parseTags(routerTagsMeta);
|
|
248
264
|
let opts = paths[url];
|
|
249
265
|
if (!opts) {
|
|
250
266
|
opts = {};
|
|
@@ -255,11 +271,11 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
255
271
|
description: getNotEmptyValue((_b = operMeta === null || operMeta === void 0 ? void 0 : operMeta.metadata) === null || _b === void 0 ? void 0 : _b.description, webRouter.description),
|
|
256
272
|
operationId: ((_c = operMeta === null || operMeta === void 0 ? void 0 : operMeta.metadata) === null || _c === void 0 ? void 0 : _c.operationId) ||
|
|
257
273
|
this.getOperationId(target.name, webRouter),
|
|
258
|
-
tags: ((_d = operMeta === null || operMeta === void 0 ? void 0 : operMeta.metadata) === null || _d === void 0 ? void 0 : _d.tags)
|
|
274
|
+
tags: routerTags.length ? routerTags : (_e = (_d = operMeta === null || operMeta === void 0 ? void 0 : operMeta.metadata) === null || _d === void 0 ? void 0 : _d.tags) !== null && _e !== void 0 ? _e : [],
|
|
259
275
|
};
|
|
260
|
-
if (((
|
|
276
|
+
if (((_f = operMeta === null || operMeta === void 0 ? void 0 : operMeta.metadata) === null || _f === void 0 ? void 0 : _f.deprecated) != null) {
|
|
261
277
|
opts[webRouter.requestMethod].deprecated =
|
|
262
|
-
!!((
|
|
278
|
+
!!((_g = operMeta === null || operMeta === void 0 ? void 0 : operMeta.metadata) === null || _g === void 0 ? void 0 : _g.deprecated);
|
|
263
279
|
}
|
|
264
280
|
/**
|
|
265
281
|
* [{"key":"web:router_param","parameterIndex":1,"propertyName":"create","metadata":{"type":2}},
|
|
@@ -283,7 +299,7 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
283
299
|
param.metadata.schema['type'] = param.metadata.type;
|
|
284
300
|
delete param.metadata.type;
|
|
285
301
|
}
|
|
286
|
-
if (param.metadata.isArray
|
|
302
|
+
if (param.metadata.isArray) {
|
|
287
303
|
param.metadata.schema['items'] = {
|
|
288
304
|
type: param.metadata.schema['type'],
|
|
289
305
|
};
|
|
@@ -307,9 +323,9 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
307
323
|
parameters.push(p);
|
|
308
324
|
}
|
|
309
325
|
else if (p.in === 'body') {
|
|
310
|
-
p.content = (
|
|
326
|
+
p.content = (_h = p.content) !== null && _h !== void 0 ? _h : {};
|
|
311
327
|
if (Object.keys(p.content).length === 0) {
|
|
312
|
-
p.content[p.contentType || 'application/json'] = (
|
|
328
|
+
p.content[p.contentType || 'application/json'] = (_j = p.content[p.contentType || 'application/json']) !== null && _j !== void 0 ? _j : {
|
|
313
329
|
schema: p.schema,
|
|
314
330
|
};
|
|
315
331
|
}
|
|
@@ -319,20 +335,20 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
319
335
|
}
|
|
320
336
|
// if requestBody is already set, skip
|
|
321
337
|
opts[webRouter.requestMethod].requestBody =
|
|
322
|
-
(
|
|
338
|
+
(_k = opts[webRouter.requestMethod].requestBody) !== null && _k !== void 0 ? _k : {};
|
|
323
339
|
opts[webRouter.requestMethod].requestBody.description =
|
|
324
|
-
(
|
|
340
|
+
(_l = opts[webRouter.requestMethod].requestBody.description) !== null && _l !== void 0 ? _l : p.description;
|
|
325
341
|
opts[webRouter.requestMethod].requestBody.content =
|
|
326
|
-
(
|
|
342
|
+
(_m = opts[webRouter.requestMethod].requestBody.content) !== null && _m !== void 0 ? _m : p.content;
|
|
327
343
|
opts[webRouter.requestMethod].requestBody.required =
|
|
328
|
-
(
|
|
344
|
+
(_o = opts[webRouter.requestMethod].requestBody.required) !== null && _o !== void 0 ? _o : p.required;
|
|
329
345
|
}
|
|
330
346
|
}
|
|
331
347
|
for (const arg of args) {
|
|
332
348
|
const currentType = types[arg.parameterIndex];
|
|
333
349
|
const p = {
|
|
334
|
-
name: (
|
|
335
|
-
in: convertTypeToString((
|
|
350
|
+
name: (_p = arg === null || arg === void 0 ? void 0 : arg.metadata) === null || _p === void 0 ? void 0 : _p.propertyData,
|
|
351
|
+
in: convertTypeToString((_q = arg.metadata) === null || _q === void 0 ? void 0 : _q.type),
|
|
336
352
|
required: false,
|
|
337
353
|
};
|
|
338
354
|
const existsParam = parameters.find(item => {
|
|
@@ -374,7 +390,7 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
374
390
|
continue;
|
|
375
391
|
}
|
|
376
392
|
p.schema = {
|
|
377
|
-
type: convertSchemaType((
|
|
393
|
+
type: convertSchemaType((_r = currentType === null || currentType === void 0 ? void 0 : currentType.name) !== null && _r !== void 0 ? _r : currentType),
|
|
378
394
|
};
|
|
379
395
|
}
|
|
380
396
|
}
|
|
@@ -387,7 +403,7 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
387
403
|
continue;
|
|
388
404
|
}
|
|
389
405
|
// 这里兼容一下 @File()、@Files()、@Fields() 装饰器
|
|
390
|
-
if (((
|
|
406
|
+
if (((_s = arg.metadata) === null || _s === void 0 ? void 0 : _s.type) === core_1.RouteParamTypes.FILESSTREAM) {
|
|
391
407
|
p.content = {};
|
|
392
408
|
p.content[_1.BodyContentType.Multipart] = {
|
|
393
409
|
schema: {
|
|
@@ -405,7 +421,7 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
405
421
|
},
|
|
406
422
|
};
|
|
407
423
|
}
|
|
408
|
-
else if (((
|
|
424
|
+
else if (((_t = arg.metadata) === null || _t === void 0 ? void 0 : _t.type) === core_1.RouteParamTypes.FILESTREAM) {
|
|
409
425
|
p.content = {};
|
|
410
426
|
p.content[_1.BodyContentType.Multipart] = {
|
|
411
427
|
schema: {
|
|
@@ -435,7 +451,7 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
435
451
|
p.content = {
|
|
436
452
|
'text/plain': {
|
|
437
453
|
schema: {
|
|
438
|
-
type: convertSchemaType((
|
|
454
|
+
type: convertSchemaType((_u = currentType === null || currentType === void 0 ? void 0 : currentType.name) !== null && _u !== void 0 ? _u : currentType),
|
|
439
455
|
},
|
|
440
456
|
},
|
|
441
457
|
};
|
|
@@ -527,96 +543,6 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
527
543
|
getOperationId(controllerKey, webRouter) {
|
|
528
544
|
return this.operationIdFactory(controllerKey, webRouter);
|
|
529
545
|
}
|
|
530
|
-
/**
|
|
531
|
-
* 提取参数
|
|
532
|
-
* @param params
|
|
533
|
-
* @param p
|
|
534
|
-
*/
|
|
535
|
-
parseFromParamsToP(paramMeta, p) {
|
|
536
|
-
var _a, _b, _c;
|
|
537
|
-
if (paramMeta) {
|
|
538
|
-
const param = paramMeta.metadata;
|
|
539
|
-
if (param) {
|
|
540
|
-
p.description = param.description;
|
|
541
|
-
if (!p.name && param.name) {
|
|
542
|
-
p.name = param.name;
|
|
543
|
-
}
|
|
544
|
-
if (param.in === 'query') {
|
|
545
|
-
p.allowEmptyValue = param.allowEmptyValue || false;
|
|
546
|
-
}
|
|
547
|
-
if (typeof param.example !== undefined) {
|
|
548
|
-
p.example = param.example;
|
|
549
|
-
}
|
|
550
|
-
if (param.examples) {
|
|
551
|
-
p.examples = param.examples;
|
|
552
|
-
}
|
|
553
|
-
if (param.deprecated) {
|
|
554
|
-
p.deprecated = param.deprecated;
|
|
555
|
-
}
|
|
556
|
-
if (param.contentType) {
|
|
557
|
-
p.contentType = param.contentType;
|
|
558
|
-
}
|
|
559
|
-
p.in = (_a = param === null || param === void 0 ? void 0 : param.in) !== null && _a !== void 0 ? _a : p.in;
|
|
560
|
-
p.required = (_b = param === null || param === void 0 ? void 0 : param.required) !== null && _b !== void 0 ? _b : p.required;
|
|
561
|
-
if (p.in === 'query') {
|
|
562
|
-
p.style = 'form';
|
|
563
|
-
}
|
|
564
|
-
else if (p.in === 'path' || p.in === 'header') {
|
|
565
|
-
p.style = 'simple';
|
|
566
|
-
}
|
|
567
|
-
else if (p.in === 'cookie') {
|
|
568
|
-
p.style = 'form';
|
|
569
|
-
}
|
|
570
|
-
p.explode = p.style === 'form';
|
|
571
|
-
// response content
|
|
572
|
-
if (param === null || param === void 0 ? void 0 : param.content) {
|
|
573
|
-
p.content = param === null || param === void 0 ? void 0 : param.content;
|
|
574
|
-
}
|
|
575
|
-
if (param.schema) {
|
|
576
|
-
p.schema = param.schema;
|
|
577
|
-
}
|
|
578
|
-
else {
|
|
579
|
-
if (param.type) {
|
|
580
|
-
if (core_1.Types.isClass(param.type)) {
|
|
581
|
-
this.parseClzz(param.type);
|
|
582
|
-
p.schema = {
|
|
583
|
-
$ref: '#/components/schemas/' + param.type.name,
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
|
-
if (param.isArray) {
|
|
587
|
-
let ref;
|
|
588
|
-
if ((_c = p === null || p === void 0 ? void 0 : p.schema) === null || _c === void 0 ? void 0 : _c.$ref) {
|
|
589
|
-
ref = p.schema.$ref;
|
|
590
|
-
}
|
|
591
|
-
p.schema = {
|
|
592
|
-
type: 'array',
|
|
593
|
-
items: {
|
|
594
|
-
format: param.format,
|
|
595
|
-
},
|
|
596
|
-
};
|
|
597
|
-
if (ref) {
|
|
598
|
-
p.schema.items.$ref = ref;
|
|
599
|
-
}
|
|
600
|
-
else {
|
|
601
|
-
p.schema.items.type = convertSchemaType(param.type);
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
else {
|
|
605
|
-
if (!p.schema) {
|
|
606
|
-
p.schema = {
|
|
607
|
-
type: param.type ? convertSchemaType(param.type) : p.type,
|
|
608
|
-
format: param.format || p.format,
|
|
609
|
-
};
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
else if (param.format) {
|
|
614
|
-
p.schema.format = param.format;
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
546
|
/**
|
|
621
547
|
* 解析 ApiExtraModel
|
|
622
548
|
* @param clzz
|
|
@@ -1054,4 +980,35 @@ function parseTypeSchema(ref) {
|
|
|
1054
980
|
return ref;
|
|
1055
981
|
}
|
|
1056
982
|
}
|
|
983
|
+
function parseTags(tags) {
|
|
984
|
+
let strTags = [];
|
|
985
|
+
if (tags.length > 0) {
|
|
986
|
+
for (const t of tags) {
|
|
987
|
+
// 这里 metadata => string[]
|
|
988
|
+
strTags = strTags.concat(t.metadata);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
return strTags;
|
|
992
|
+
}
|
|
993
|
+
function addTag(newTag, tags = []) {
|
|
994
|
+
/**
|
|
995
|
+
* tag 结构
|
|
996
|
+
* ['name', 'description'] 或者 'name'
|
|
997
|
+
*/
|
|
998
|
+
if (
|
|
999
|
+
// 处理重复的标签
|
|
1000
|
+
tags.find(t => {
|
|
1001
|
+
if (Array.isArray(newTag)) {
|
|
1002
|
+
return t === newTag[0];
|
|
1003
|
+
}
|
|
1004
|
+
else {
|
|
1005
|
+
return t === newTag;
|
|
1006
|
+
}
|
|
1007
|
+
})) {
|
|
1008
|
+
// ignore
|
|
1009
|
+
}
|
|
1010
|
+
else {
|
|
1011
|
+
tags.push(newTag);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1057
1014
|
//# sourceMappingURL=swaggerExplorer.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midwayjs/swagger",
|
|
3
|
-
"version": "3.17.
|
|
3
|
+
"version": "3.17.3",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"typings": "index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"@midwayjs/core": "^3.17.1",
|
|
14
14
|
"@midwayjs/koa": "^3.17.1",
|
|
15
15
|
"@midwayjs/mock": "^3.17.1",
|
|
16
|
-
"@midwayjs/validate": "^3.17.
|
|
16
|
+
"@midwayjs/validate": "^3.17.3",
|
|
17
17
|
"swagger-ui-dist": "5.17.14"
|
|
18
18
|
},
|
|
19
19
|
"author": "Kurten Chan <chinkurten@gmail.com>",
|
|
@@ -27,5 +27,5 @@
|
|
|
27
27
|
"type": "git",
|
|
28
28
|
"url": "https://github.com/midwayjs/midway.git"
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "f4086c0e118673052202ffa92149aacd89e9ddc5"
|
|
31
31
|
}
|