@midwayjs/swagger 3.17.1 → 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.
@@ -13,5 +13,6 @@ exports.swagger = {
13
13
  ? render_1.renderSwaggerUIDist
14
14
  : render_1.renderSwaggerUIRemote,
15
15
  swaggerUIRenderOptions: {},
16
+ isGenerateTagForController: true,
16
17
  };
17
18
  //# sourceMappingURL=config.default.js.map
@@ -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
@@ -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
- for (const t of tags) {
122
- // 这里 metadata => string[]
123
- strTags = strTags.concat(t.metadata);
124
- controllerTags.push(Array.isArray(t.metadata) ? [t.metadata] : t.metadata);
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
- const tag = { name: '', description: '' };
131
- if (prefix !== '/') {
132
- tag.name =
133
- (controllerOption === null || controllerOption === void 0 ? void 0 : controllerOption.routerOptions.tagName) ||
134
- (/^\//.test(prefix) ? prefix.split('/')[1] : prefix);
135
- tag.description =
136
- (controllerOption === null || controllerOption === void 0 ? void 0 : controllerOption.routerOptions.description) || tag.name;
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
- tag.name = controllerOption === null || controllerOption === void 0 ? void 0 : controllerOption.routerOptions.tagName;
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 (((_e = operMeta === null || operMeta === void 0 ? void 0 : operMeta.metadata) === null || _e === void 0 ? void 0 : _e.deprecated) != null) {
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
- !!((_f = operMeta === null || operMeta === void 0 ? void 0 : operMeta.metadata) === null || _f === void 0 ? void 0 : _f.deprecated);
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 !== undefined) {
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 = (_g = p.content) !== null && _g !== void 0 ? _g : {};
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'] = (_h = p.content[p.contentType || 'application/json']) !== null && _h !== void 0 ? _h : {
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
- (_j = opts[webRouter.requestMethod].requestBody) !== null && _j !== void 0 ? _j : {};
338
+ (_k = opts[webRouter.requestMethod].requestBody) !== null && _k !== void 0 ? _k : {};
323
339
  opts[webRouter.requestMethod].requestBody.description =
324
- (_k = opts[webRouter.requestMethod].requestBody.description) !== null && _k !== void 0 ? _k : p.description;
340
+ (_l = opts[webRouter.requestMethod].requestBody.description) !== null && _l !== void 0 ? _l : p.description;
325
341
  opts[webRouter.requestMethod].requestBody.content =
326
- (_l = opts[webRouter.requestMethod].requestBody.content) !== null && _l !== void 0 ? _l : p.content;
342
+ (_m = opts[webRouter.requestMethod].requestBody.content) !== null && _m !== void 0 ? _m : p.content;
327
343
  opts[webRouter.requestMethod].requestBody.required =
328
- (_m = opts[webRouter.requestMethod].requestBody.required) !== null && _m !== void 0 ? _m : p.required;
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: (_o = arg === null || arg === void 0 ? void 0 : arg.metadata) === null || _o === void 0 ? void 0 : _o.propertyData,
335
- in: convertTypeToString((_p = arg.metadata) === null || _p === void 0 ? void 0 : _p.type),
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 => {
@@ -357,12 +373,13 @@ let SwaggerExplorer = class SwaggerExplorer {
357
373
  // 如果@Query()装饰的 是一个对象,则把该对象的子属性作为多个@Query参数
358
374
  const schema = this.documentBuilder.getSchema(currentType.name);
359
375
  Object.keys(schema.properties).forEach(pName => {
360
- var _a;
376
+ var _a, _b;
361
377
  const pp = {
362
378
  name: pName,
363
379
  in: p.in,
380
+ description: (_a = schema.properties[pName]) === null || _a === void 0 ? void 0 : _a.description,
364
381
  schema: schema.properties[pName],
365
- required: ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.includes(pName)) || false,
382
+ required: ((_b = schema.required) === null || _b === void 0 ? void 0 : _b.includes(pName)) || false,
366
383
  };
367
384
  parameters.push(pp);
368
385
  });
@@ -373,7 +390,7 @@ let SwaggerExplorer = class SwaggerExplorer {
373
390
  continue;
374
391
  }
375
392
  p.schema = {
376
- type: convertSchemaType((_q = currentType === null || currentType === void 0 ? void 0 : currentType.name) !== null && _q !== void 0 ? _q : currentType),
393
+ type: convertSchemaType((_r = currentType === null || currentType === void 0 ? void 0 : currentType.name) !== null && _r !== void 0 ? _r : currentType),
377
394
  };
378
395
  }
379
396
  }
@@ -386,7 +403,7 @@ let SwaggerExplorer = class SwaggerExplorer {
386
403
  continue;
387
404
  }
388
405
  // 这里兼容一下 @File()、@Files()、@Fields() 装饰器
389
- if (((_r = arg.metadata) === null || _r === void 0 ? void 0 : _r.type) === core_1.RouteParamTypes.FILESSTREAM) {
406
+ if (((_s = arg.metadata) === null || _s === void 0 ? void 0 : _s.type) === core_1.RouteParamTypes.FILESSTREAM) {
390
407
  p.content = {};
391
408
  p.content[_1.BodyContentType.Multipart] = {
392
409
  schema: {
@@ -404,7 +421,7 @@ let SwaggerExplorer = class SwaggerExplorer {
404
421
  },
405
422
  };
406
423
  }
407
- else if (((_s = arg.metadata) === null || _s === void 0 ? void 0 : _s.type) === core_1.RouteParamTypes.FILESTREAM) {
424
+ else if (((_t = arg.metadata) === null || _t === void 0 ? void 0 : _t.type) === core_1.RouteParamTypes.FILESTREAM) {
408
425
  p.content = {};
409
426
  p.content[_1.BodyContentType.Multipart] = {
410
427
  schema: {
@@ -434,7 +451,7 @@ let SwaggerExplorer = class SwaggerExplorer {
434
451
  p.content = {
435
452
  'text/plain': {
436
453
  schema: {
437
- type: convertSchemaType((_t = currentType === null || currentType === void 0 ? void 0 : currentType.name) !== null && _t !== void 0 ? _t : currentType),
454
+ type: convertSchemaType((_u = currentType === null || currentType === void 0 ? void 0 : currentType.name) !== null && _u !== void 0 ? _u : currentType),
438
455
  },
439
456
  },
440
457
  };
@@ -526,96 +543,6 @@ let SwaggerExplorer = class SwaggerExplorer {
526
543
  getOperationId(controllerKey, webRouter) {
527
544
  return this.operationIdFactory(controllerKey, webRouter);
528
545
  }
529
- /**
530
- * 提取参数
531
- * @param params
532
- * @param p
533
- */
534
- parseFromParamsToP(paramMeta, p) {
535
- var _a, _b, _c;
536
- if (paramMeta) {
537
- const param = paramMeta.metadata;
538
- if (param) {
539
- p.description = param.description;
540
- if (!p.name && param.name) {
541
- p.name = param.name;
542
- }
543
- if (param.in === 'query') {
544
- p.allowEmptyValue = param.allowEmptyValue || false;
545
- }
546
- if (typeof param.example !== undefined) {
547
- p.example = param.example;
548
- }
549
- if (param.examples) {
550
- p.examples = param.examples;
551
- }
552
- if (param.deprecated) {
553
- p.deprecated = param.deprecated;
554
- }
555
- if (param.contentType) {
556
- p.contentType = param.contentType;
557
- }
558
- p.in = (_a = param === null || param === void 0 ? void 0 : param.in) !== null && _a !== void 0 ? _a : p.in;
559
- p.required = (_b = param === null || param === void 0 ? void 0 : param.required) !== null && _b !== void 0 ? _b : p.required;
560
- if (p.in === 'query') {
561
- p.style = 'form';
562
- }
563
- else if (p.in === 'path' || p.in === 'header') {
564
- p.style = 'simple';
565
- }
566
- else if (p.in === 'cookie') {
567
- p.style = 'form';
568
- }
569
- p.explode = p.style === 'form';
570
- // response content
571
- if (param === null || param === void 0 ? void 0 : param.content) {
572
- p.content = param === null || param === void 0 ? void 0 : param.content;
573
- }
574
- if (param.schema) {
575
- p.schema = param.schema;
576
- }
577
- else {
578
- if (param.type) {
579
- if (core_1.Types.isClass(param.type)) {
580
- this.parseClzz(param.type);
581
- p.schema = {
582
- $ref: '#/components/schemas/' + param.type.name,
583
- };
584
- }
585
- if (param.isArray) {
586
- let ref;
587
- if ((_c = p === null || p === void 0 ? void 0 : p.schema) === null || _c === void 0 ? void 0 : _c.$ref) {
588
- ref = p.schema.$ref;
589
- }
590
- p.schema = {
591
- type: 'array',
592
- items: {
593
- format: param.format,
594
- },
595
- };
596
- if (ref) {
597
- p.schema.items.$ref = ref;
598
- }
599
- else {
600
- p.schema.items.type = convertSchemaType(param.type);
601
- }
602
- }
603
- else {
604
- if (!p.schema) {
605
- p.schema = {
606
- type: param.type ? convertSchemaType(param.type) : p.type,
607
- format: param.format || p.format,
608
- };
609
- }
610
- }
611
- }
612
- else if (param.format) {
613
- p.schema.format = param.format;
614
- }
615
- }
616
- }
617
- }
618
- }
619
546
  /**
620
547
  * 解析 ApiExtraModel
621
548
  * @param clzz
@@ -1053,4 +980,35 @@ function parseTypeSchema(ref) {
1053
980
  return ref;
1054
981
  }
1055
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
+ }
1056
1014
  //# sourceMappingURL=swaggerExplorer.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midwayjs/swagger",
3
- "version": "3.17.1",
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.1",
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": "824d8474a425b342fcd4480649c83677f846afb9"
30
+ "gitHead": "f4086c0e118673052202ffa92149aacd89e9ddc5"
31
31
  }