@midwayjs/swagger 3.0.0-beta.9 → 3.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2013 - Now midwayjs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # midwayjs swagger module
2
2
 
3
+ ## Thanks to [@nestjs/swagger](https://github.com/nestjs/swagger)
4
+
3
5
  [![Package Quality](http://npm.packagequality.com/shield/midway-core.svg)](http://packagequality.com/#?package=midway-core)
4
6
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/midwayjs/midway/pulls)
5
7
 
@@ -1,10 +1,18 @@
1
1
  import { ContentObject, ExamplesObject, ReferenceObject, RequestBodyObject, SchemaObject, SwaggerEnumType } from '../interfaces';
2
2
  declare type RequestBodyOptions = Omit<RequestBodyObject, 'content'>;
3
+ export declare enum BodyContentType {
4
+ FormUrlEncoded = "application/x-www-form-urlencoded",
5
+ JSON = "application/json",
6
+ Multipart = "multipart/form-data",
7
+ MultipartMixed = "multipart/mixed",
8
+ OctetStream = "application/octet-stream"
9
+ }
3
10
  interface ApiBodyMetadata extends RequestBodyOptions {
4
11
  type?: any;
5
12
  isArray?: boolean;
6
13
  enum?: SwaggerEnumType;
7
14
  content?: ContentObject;
15
+ contentType?: BodyContentType;
8
16
  }
9
17
  interface ApiBodySchemaHost extends RequestBodyOptions {
10
18
  schema: SchemaObject | ReferenceObject;
@@ -1,8 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ApiBody = void 0;
3
+ exports.ApiBody = exports.BodyContentType = void 0;
4
4
  const enum_utils_1 = require("../common/enum.utils");
5
5
  const helpers_1 = require("./helpers");
6
+ var BodyContentType;
7
+ (function (BodyContentType) {
8
+ BodyContentType["FormUrlEncoded"] = "application/x-www-form-urlencoded";
9
+ BodyContentType["JSON"] = "application/json";
10
+ BodyContentType["Multipart"] = "multipart/form-data";
11
+ BodyContentType["MultipartMixed"] = "multipart/mixed";
12
+ BodyContentType["OctetStream"] = "application/octet-stream";
13
+ })(BodyContentType = exports.BodyContentType || (exports.BodyContentType = {}));
6
14
  const defaultBodyMetadata = {
7
15
  type: String,
8
16
  required: true,
@@ -4,9 +4,7 @@ exports.ApiExcludeController = void 0;
4
4
  const decorator_1 = require("@midwayjs/decorator");
5
5
  const constants_1 = require("../constants");
6
6
  function ApiExcludeController(disable = true) {
7
- return (0, decorator_1.createCustomMethodDecorator)(constants_1.DECORATORS.API_EXCLUDE_CONTROLLER, [
8
- disable,
9
- ]);
7
+ return (0, decorator_1.createCustomMethodDecorator)(constants_1.DECORATORS.API_EXCLUDE_CONTROLLER, [disable], false);
10
8
  }
11
9
  exports.ApiExcludeController = ApiExcludeController;
12
10
  //# sourceMappingURL=api-exclude-controller.decorator.js.map
@@ -6,7 +6,7 @@ const constants_1 = require("../constants");
6
6
  function ApiExcludeEndpoint(disable = true) {
7
7
  return (0, decorator_1.createCustomMethodDecorator)(constants_1.DECORATORS.API_EXCLUDE_ENDPOINT, {
8
8
  disable,
9
- });
9
+ }, false);
10
10
  }
11
11
  exports.ApiExcludeEndpoint = ApiExcludeEndpoint;
12
12
  //# sourceMappingURL=api-exclude-endpoint.decorator.js.map
@@ -30,7 +30,7 @@ function ApiHeader(options) {
30
30
  if (descriptor) {
31
31
  return (0, helpers_1.createParamDecorator)(param, defaultHeaderOptions)(target, key, descriptor);
32
32
  }
33
- return (0, decorator_1.createCustomMethodDecorator)(constants_1.DECORATORS.API_HEADERS, param)(target, undefined, undefined);
33
+ return (0, decorator_1.createCustomMethodDecorator)(constants_1.DECORATORS.API_HEADERS, param, false)(target, undefined, undefined);
34
34
  };
35
35
  }
36
36
  exports.ApiHeader = ApiHeader;
@@ -10,7 +10,7 @@ function ApiOperation(options) {
10
10
  return (0, decorator_1.createCustomMethodDecorator)(constants_1.DECORATORS.API_OPERATION, {
11
11
  ...defaultOperationOptions,
12
12
  ...options,
13
- });
13
+ }, false);
14
14
  }
15
15
  exports.ApiOperation = ApiOperation;
16
16
  //# sourceMappingURL=api-operation.decorator.js.map
@@ -14,7 +14,6 @@ function createApiPropertyDecorator(options = {}) {
14
14
  options = {
15
15
  ...options,
16
16
  type,
17
- isArray,
18
17
  };
19
18
  if (isEnumArray(options)) {
20
19
  options.type = 'array';
@@ -30,10 +29,10 @@ function createApiPropertyDecorator(options = {}) {
30
29
  options.enum = enumValues;
31
30
  options.type = (0, enum_utils_1.getEnumType)(enumValues);
32
31
  }
33
- if (Array.isArray(options.type)) {
32
+ if (isArray) {
34
33
  options.type = 'array';
35
34
  options.items = {
36
- type: options.type[0],
35
+ type: type,
37
36
  };
38
37
  }
39
38
  return (0, helpers_1.createPropertyDecorator)(constants_1.DECORATORS.API_MODEL_PROPERTIES, options);
@@ -13,7 +13,7 @@ function ApiResponse(options) {
13
13
  const groupedMetadata = {
14
14
  [options.status || 'default']: options,
15
15
  };
16
- return (0, decorator_1.createCustomMethodDecorator)(constants_1.DECORATORS.API_RESPONSE, groupedMetadata);
16
+ return (0, decorator_1.createCustomMethodDecorator)(constants_1.DECORATORS.API_RESPONSE, groupedMetadata, false);
17
17
  }
18
18
  exports.ApiResponse = ApiResponse;
19
19
  const ApiOkResponse = (options = {}) => ApiResponse({
@@ -11,7 +11,7 @@ function ApiSecurity(name, requirements = []) {
11
11
  else {
12
12
  metadata = name;
13
13
  }
14
- return (0, decorator_1.createCustomMethodDecorator)(constants_1.DECORATORS.API_SECURITY, metadata);
14
+ return (0, decorator_1.createCustomMethodDecorator)(constants_1.DECORATORS.API_SECURITY, metadata, false);
15
15
  }
16
16
  exports.ApiSecurity = ApiSecurity;
17
17
  //# sourceMappingURL=api-security.decorator.js.map
@@ -4,18 +4,18 @@ exports.getSchemaPath = exports.getTypeIsArrayTuple = exports.createParamDecorat
4
4
  const decorator_1 = require("@midwayjs/decorator");
5
5
  const constants_1 = require("../constants");
6
6
  function createPropertyDecorator(metakey, metadata) {
7
- return (0, decorator_1.createCustomPropertyDecorator)(metakey, metadata);
7
+ return (0, decorator_1.createCustomPropertyDecorator)(metakey, metadata, false);
8
8
  }
9
9
  exports.createPropertyDecorator = createPropertyDecorator;
10
10
  function createMixedDecorator(metakey, metadata) {
11
- return (0, decorator_1.createCustomMethodDecorator)(metakey, metadata);
11
+ return (0, decorator_1.createCustomMethodDecorator)(metakey, metadata, false);
12
12
  }
13
13
  exports.createMixedDecorator = createMixedDecorator;
14
14
  function createParamDecorator(metadata, initial) {
15
15
  return (0, decorator_1.createCustomMethodDecorator)(constants_1.DECORATORS.API_PARAMETERS, {
16
16
  ...initial,
17
17
  ...metadata,
18
- });
18
+ }, false);
19
19
  }
20
20
  exports.createParamDecorator = createParamDecorator;
21
21
  function getTypeIsArrayTuple(input, isArrayFlag) {
@@ -9,9 +9,10 @@ export declare class DocumentBuilder {
9
9
  setLicense(name: string, url: string): this;
10
10
  addServer(url: string, description?: string, variables?: Record<string, ServerVariableObject>): this;
11
11
  setExternalDoc(description: string, url: string): this;
12
- setBasePath(path: string): this;
12
+ setBasePath(path: string | string[]): this;
13
13
  addPaths(paths: Record<string, PathItemObject>): this;
14
14
  addSchema(schema: Record<string, SchemaObject>): this;
15
+ getSchema(name: string): SchemaObject;
15
16
  addTag(name: string, description?: string, externalDocs?: ExternalDocumentationObject): this;
16
17
  addSecurity(name: string, options: SecuritySchemeObject): this;
17
18
  addSecurityRequirements(name: string | SecurityRequirementObject, requirements?: string[]): this;
@@ -20,6 +21,7 @@ export declare class DocumentBuilder {
20
21
  addApiKey(options?: SecuritySchemeObject, name?: string): this;
21
22
  addBasicAuth(options?: SecuritySchemeObject, name?: string): this;
22
23
  addCookieAuth(cookieName?: string, options?: SecuritySchemeObject, securityName?: string): this;
24
+ sortTags(): void;
23
25
  build(): Omit<OpenAPIObject, 'paths'>;
24
26
  }
25
27
  //# sourceMappingURL=documentBuilder.d.ts.map
@@ -77,6 +77,13 @@ class DocumentBuilder {
77
77
  Object.assign(this.document.components.schemas, schema);
78
78
  return this;
79
79
  }
80
+ getSchema(name) {
81
+ var _a, _b;
82
+ if ((_a = this.document.components) === null || _a === void 0 ? void 0 : _a.schemas) {
83
+ return (_b = this.document.components) === null || _b === void 0 ? void 0 : _b.schemas[name];
84
+ }
85
+ return undefined;
86
+ }
80
87
  addTag(name, description = '', externalDocs) {
81
88
  if (Array.isArray(name)) {
82
89
  const arr = name;
@@ -184,6 +191,23 @@ class DocumentBuilder {
184
191
  });
185
192
  return this;
186
193
  }
194
+ sortTags() {
195
+ const tags = this.document.tags;
196
+ this.document.tags = tags.sort((a, b) => {
197
+ const s1 = a.name;
198
+ const s2 = b.name;
199
+ const len = s1.length > s2.length ? s2.length : s1.length;
200
+ for (let i = 0; i < len; i++) {
201
+ if (s1.charCodeAt(i) > s2.charCodeAt(i)) {
202
+ return 1;
203
+ }
204
+ else if (s1.charCodeAt(i) < s2.charCodeAt(i)) {
205
+ return -1;
206
+ }
207
+ }
208
+ return 0;
209
+ });
210
+ }
187
211
  build() {
188
212
  return this.document;
189
213
  }
@@ -251,18 +251,94 @@ export interface SchemaObjectMetadata extends Omit<SchemaObject, 'type' | 'requi
251
251
  name?: string;
252
252
  enumName?: string;
253
253
  }
254
+ export declare type AuthType = 'basic' | 'bearer' | 'cookie' | 'oauth2' | 'apikey' | 'custom';
255
+ /**
256
+ * 继承自 https://swagger.io/specification/#security-scheme-object
257
+ */
258
+ export interface AuthOptions extends Omit<SecuritySchemeObject, 'type'> {
259
+ /**
260
+ * 验权类型
261
+ * basic => http basic 验证
262
+ * bearer => http jwt 验证
263
+ * cookie => cookie 方式验证
264
+ * oauth2 => 使用 oauth2
265
+ * apikey => apiKey
266
+ * custom => 自定义方式
267
+ */
268
+ authType: AuthType;
269
+ /**
270
+ * https://swagger.io/specification/#security-scheme-object type 字段
271
+ */
272
+ type?: SecuritySchemeType;
273
+ /**
274
+ * authType = cookie 时可以修改,通过 ApiCookie 装饰器关联的名称
275
+ */
276
+ securityName?: string;
277
+ /**
278
+ * authType = cookie 时可以修改,cookie 的名称
279
+ */
280
+ cookieName?: string;
281
+ }
282
+ /**
283
+ * see https://swagger.io/specification/
284
+ */
254
285
  export interface SwaggerOptions {
286
+ /**
287
+ * 默认值: My Project
288
+ * https://swagger.io/specification/#info-object title 字段
289
+ */
255
290
  title?: string;
291
+ /**
292
+ * 默认值: This is a swagger-ui for midwayjs project
293
+ * https://swagger.io/specification/#info-object description 字段
294
+ */
256
295
  description?: string;
296
+ /**
297
+ * 默认值: 1.0.0
298
+ * https://swagger.io/specification/#info-object version 字段
299
+ */
257
300
  version?: string;
258
- swaggerPath?: string;
301
+ /**
302
+ * https://swagger.io/specification/#info-object contact 字段
303
+ */
259
304
  contact?: ContactObject;
305
+ /**
306
+ * https://swagger.io/specification/#info-object license 字段
307
+ */
260
308
  license?: LicenseObject;
261
- basePath?: string;
309
+ /**
310
+ * https://swagger.io/specification/#info-object termsOfService 字段
311
+ */
262
312
  termsOfService?: string;
263
- externalDoc?: ExternalDocumentationObject;
313
+ /**
314
+ * https://swagger.io/specification/#openapi-object externalDocs 字段
315
+ */
316
+ externalDocs?: ExternalDocumentationObject;
317
+ /**
318
+ * https://swagger.io/specification/#openapi-object servers 字段
319
+ */
264
320
  servers?: Array<ServerObject>;
321
+ /**
322
+ * https://swagger.io/specification/#openapi-object tags 字段
323
+ */
265
324
  tags?: Array<TagObject>;
266
- auth?: SecuritySchemeObject;
325
+ /**
326
+ * 可以参考 https://swagger.io/specification/#security-scheme-object
327
+ */
328
+ auth?: AuthOptions | AuthOptions[];
329
+ /**
330
+ * api 的 根路径
331
+ */
332
+ basePath?: string | string[];
333
+ /**
334
+ * 默认值: /swagger-ui
335
+ * 访问 swagger ui 的路径
336
+ */
337
+ swaggerPath?: string;
338
+ /**
339
+ * 对路由 tag 进行 ascii 排序
340
+ * 可以使用 1-xxx、2-xxx、3-xxx 来定义 tag
341
+ */
342
+ tagSortable?: boolean;
267
343
  }
268
344
  //# sourceMappingURL=index.d.ts.map
@@ -13,12 +13,13 @@ exports.SwaggerExplorer = void 0;
13
13
  const decorator_1 = require("@midwayjs/decorator");
14
14
  const constants_1 = require("./constants");
15
15
  const documentBuilder_1 = require("./documentBuilder");
16
+ const _1 = require(".");
16
17
  let SwaggerExplorer = class SwaggerExplorer {
17
18
  constructor() {
18
19
  this.documentBuilder = new documentBuilder_1.DocumentBuilder();
19
20
  }
20
21
  async init() {
21
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4;
22
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _2, _3, _4, _5;
22
23
  this.documentBuilder.setTitle(this.swaggerConfig.title);
23
24
  this.documentBuilder.setVersion(this.swaggerConfig.version);
24
25
  this.documentBuilder.setDescription(this.swaggerConfig.description);
@@ -36,9 +37,9 @@ let SwaggerExplorer = class SwaggerExplorer {
36
37
  if (this.swaggerConfig.termsOfService) {
37
38
  this.documentBuilder.setTermsOfService(this.swaggerConfig.termsOfService);
38
39
  }
39
- if (((_q = this.swaggerConfig) === null || _q === void 0 ? void 0 : _q.externalDoc) &&
40
- typeof ((_r = this.swaggerConfig) === null || _r === void 0 ? void 0 : _r.externalDoc) === 'object') {
41
- this.documentBuilder.setExternalDoc((_t = (_s = this.swaggerConfig) === null || _s === void 0 ? void 0 : _s.externalDoc) === null || _t === void 0 ? void 0 : _t.description, (_v = (_u = this.swaggerConfig) === null || _u === void 0 ? void 0 : _u.externalDoc) === null || _v === void 0 ? void 0 : _v.url);
40
+ if (((_q = this.swaggerConfig) === null || _q === void 0 ? void 0 : _q.externalDocs) &&
41
+ typeof ((_r = this.swaggerConfig) === null || _r === void 0 ? void 0 : _r.externalDocs) === 'object') {
42
+ this.documentBuilder.setExternalDoc((_t = (_s = this.swaggerConfig) === null || _s === void 0 ? void 0 : _s.externalDocs) === null || _t === void 0 ? void 0 : _t.description, (_v = (_u = this.swaggerConfig) === null || _u === void 0 ? void 0 : _u.externalDocs) === null || _v === void 0 ? void 0 : _v.url);
42
43
  }
43
44
  if (((_w = this.swaggerConfig) === null || _w === void 0 ? void 0 : _w.servers) &&
44
45
  Array.isArray((_x = this.swaggerConfig) === null || _x === void 0 ? void 0 : _x.servers)) {
@@ -47,25 +48,29 @@ let SwaggerExplorer = class SwaggerExplorer {
47
48
  }
48
49
  }
49
50
  if (((_z = this.swaggerConfig) === null || _z === void 0 ? void 0 : _z.tags) && Array.isArray((_0 = this.swaggerConfig) === null || _0 === void 0 ? void 0 : _0.tags)) {
50
- for (const t of (_1 = this.swaggerConfig) === null || _1 === void 0 ? void 0 : _1.tags) {
51
+ for (const t of (_2 = this.swaggerConfig) === null || _2 === void 0 ? void 0 : _2.tags) {
51
52
  this.documentBuilder.addTag(t.name, t.description, t.externalDocs);
52
53
  }
53
54
  }
54
55
  // 设置 auth 类型
55
- if (Array.isArray((_2 = this.swaggerConfig) === null || _2 === void 0 ? void 0 : _2.auth)) {
56
- for (const a of (_3 = this.swaggerConfig) === null || _3 === void 0 ? void 0 : _3.auth) {
56
+ if (Array.isArray((_3 = this.swaggerConfig) === null || _3 === void 0 ? void 0 : _3.auth)) {
57
+ for (const a of (_4 = this.swaggerConfig) === null || _4 === void 0 ? void 0 : _4.auth) {
57
58
  this.setAuth(a);
58
59
  }
59
60
  }
60
61
  else {
61
- this.setAuth((_4 = this.swaggerConfig) === null || _4 === void 0 ? void 0 : _4.auth);
62
+ this.setAuth((_5 = this.swaggerConfig) === null || _5 === void 0 ? void 0 : _5.auth);
62
63
  }
63
64
  }
64
65
  scanApp() {
66
+ var _a;
65
67
  const routes = (0, decorator_1.listModule)(decorator_1.CONTROLLER_KEY);
66
68
  for (const route of routes) {
67
69
  this.generatePath(route);
68
70
  }
71
+ if ((_a = this.swaggerConfig) === null || _a === void 0 ? void 0 : _a.tagSortable) {
72
+ this.documentBuilder.sortTags();
73
+ }
69
74
  }
70
75
  getData() {
71
76
  return this.documentBuilder.build();
@@ -98,11 +103,12 @@ let SwaggerExplorer = class SwaggerExplorer {
98
103
  (controllerOption === null || controllerOption === void 0 ? void 0 : controllerOption.routerOptions.description) || tag.name;
99
104
  }
100
105
  else {
101
- tag.name = (controllerOption === null || controllerOption === void 0 ? void 0 : controllerOption.routerOptions.tagName) || 'default';
106
+ tag.name = controllerOption === null || controllerOption === void 0 ? void 0 : controllerOption.routerOptions.tagName;
102
107
  tag.description =
103
108
  (controllerOption === null || controllerOption === void 0 ? void 0 : controllerOption.routerOptions.description) || tag.name;
104
109
  }
105
110
  if (tag.name) {
111
+ strTags.push(tag.name);
106
112
  this.documentBuilder.addTag(tag.name, tag.description);
107
113
  }
108
114
  }
@@ -158,7 +164,7 @@ let SwaggerExplorer = class SwaggerExplorer {
158
164
  * 构造 router 提取方法
159
165
  */
160
166
  generateRouteMethod(url, webRouter, paths, metaForMethods, metaForParams, header, target) {
161
- var _a, _b, _c, _d, _e, _f, _g, _h;
167
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
162
168
  const operMeta = metaForMethods.filter(item => item.key === constants_1.DECORATORS.API_OPERATION &&
163
169
  item.propertyName === webRouter.method)[0];
164
170
  let opts = paths[url];
@@ -196,7 +202,7 @@ let SwaggerExplorer = class SwaggerExplorer {
196
202
  continue;
197
203
  }
198
204
  }
199
- if ((0, decorator_1.isClass)(currentType)) {
205
+ if (decorator_1.Types.isClass(currentType)) {
200
206
  this.parseClzz(currentType);
201
207
  p.schema = {
202
208
  $ref: '#/components/schemas/' + currentType.name,
@@ -209,16 +215,66 @@ let SwaggerExplorer = class SwaggerExplorer {
209
215
  }
210
216
  this.parseFromParamsToP(params[params.length - 1 - arg.parameterIndex], p);
211
217
  if (p.in === 'body') {
212
- const requestBody = {
213
- required: true,
214
- description: p.description || p.name,
215
- content: p.content || {
216
- 'application/json': {
217
- schema: p.schema,
218
+ // 这里兼容一下 @File()、@Files()、@Fields() 装饰器
219
+ if (((_j = arg.metadata) === null || _j === void 0 ? void 0 : _j.type) === decorator_1.RouteParamTypes.FILESSTREAM) {
220
+ p.schema = {
221
+ type: 'object',
222
+ properties: {
223
+ files: {
224
+ type: 'array',
225
+ items: {
226
+ type: 'string',
227
+ format: 'binary',
228
+ },
229
+ description: p.description,
230
+ },
218
231
  },
219
- },
220
- };
221
- opts[webRouter.requestMethod].requestBody = requestBody;
232
+ };
233
+ p.contentType = _1.BodyContentType.Multipart;
234
+ }
235
+ if (((_k = arg.metadata) === null || _k === void 0 ? void 0 : _k.type) === decorator_1.RouteParamTypes.FILESTREAM) {
236
+ p.schema = {
237
+ type: 'object',
238
+ properties: {
239
+ file: {
240
+ type: 'string',
241
+ format: 'binary',
242
+ description: p.description,
243
+ },
244
+ },
245
+ };
246
+ p.contentType = _1.BodyContentType.Multipart;
247
+ }
248
+ if (((_l = arg.metadata) === null || _l === void 0 ? void 0 : _l.type) === decorator_1.RouteParamTypes.FIELDS) {
249
+ if (p.schema['$ref']) {
250
+ // 展开各个字段属性
251
+ const name = p.schema['$ref'].replace('#/components/schemas/', '');
252
+ const schema = this.documentBuilder.getSchema(name);
253
+ delete p.schema['$ref'];
254
+ p.schema = JSON.parse(JSON.stringify(schema));
255
+ }
256
+ p.contentType = _1.BodyContentType.Multipart;
257
+ }
258
+ if (!p.content) {
259
+ p.content = {};
260
+ p.content[p.contentType || 'application/json'] = {
261
+ schema: p.schema,
262
+ };
263
+ }
264
+ if (!opts[webRouter.requestMethod].requestBody) {
265
+ const requestBody = {
266
+ required: true,
267
+ description: p.description || p.name,
268
+ content: p.content,
269
+ };
270
+ opts[webRouter.requestMethod].requestBody = requestBody;
271
+ }
272
+ else {
273
+ // 这里拼 schema properties 时肯定存在
274
+ Object.assign(opts[webRouter.requestMethod].requestBody.content[p.contentType]
275
+ .schema.properties, p.schema.properties);
276
+ }
277
+ delete p.contentType;
222
278
  delete p.content;
223
279
  // in body 不需要处理
224
280
  continue;
@@ -230,9 +286,9 @@ let SwaggerExplorer = class SwaggerExplorer {
230
286
  parameters.unshift(header);
231
287
  }
232
288
  opts[webRouter.requestMethod].parameters = parameters;
233
- opts[webRouter.requestMethod].responses = {};
234
289
  const responses = metaForMethods.filter(item => item.key === constants_1.DECORATORS.API_RESPONSE &&
235
290
  item.propertyName === webRouter.method);
291
+ const returnResponses = {};
236
292
  for (const r of responses) {
237
293
  const resp = r.metadata;
238
294
  const keys = Object.keys(resp);
@@ -240,7 +296,7 @@ let SwaggerExplorer = class SwaggerExplorer {
240
296
  // 这里是引用,赋值可以直接更改
241
297
  const tt = resp[k];
242
298
  if (tt.type) {
243
- if ((0, decorator_1.isClass)(tt.type)) {
299
+ if (decorator_1.Types.isClass(tt.type)) {
244
300
  this.parseClzz(tt.type);
245
301
  if (tt.isArray) {
246
302
  tt.content = {
@@ -279,7 +335,17 @@ let SwaggerExplorer = class SwaggerExplorer {
279
335
  delete tt.isArray;
280
336
  delete tt.format;
281
337
  }
282
- Object.assign(opts[webRouter.requestMethod].responses, resp);
338
+ Object.assign(returnResponses, resp);
339
+ }
340
+ if (Object.keys(returnResponses).length > 0) {
341
+ opts[webRouter.requestMethod].responses = returnResponses;
342
+ }
343
+ else {
344
+ opts[webRouter.requestMethod].responses = {
345
+ 200: {
346
+ description: 'OK',
347
+ },
348
+ };
283
349
  }
284
350
  paths[url] = opts;
285
351
  }
@@ -306,6 +372,9 @@ let SwaggerExplorer = class SwaggerExplorer {
306
372
  if (param.deprecated) {
307
373
  p.deprecated = param.deprecated;
308
374
  }
375
+ if (param.contentType) {
376
+ p.contentType = param.contentType;
377
+ }
309
378
  p.in = (_a = param === null || param === void 0 ? void 0 : param.in) !== null && _a !== void 0 ? _a : p.in;
310
379
  p.required = (_b = param === null || param === void 0 ? void 0 : param.required) !== null && _b !== void 0 ? _b : p.required;
311
380
  if (p.in === 'query') {
@@ -327,7 +396,7 @@ let SwaggerExplorer = class SwaggerExplorer {
327
396
  }
328
397
  else {
329
398
  if (param.type) {
330
- if ((0, decorator_1.isClass)(param.type)) {
399
+ if (decorator_1.Types.isClass(param.type)) {
331
400
  this.parseClzz(param.type);
332
401
  p.schema = {
333
402
  $ref: '#/components/schemas/' + param.type.name,
@@ -363,45 +432,65 @@ let SwaggerExplorer = class SwaggerExplorer {
363
432
  * @param clzz
364
433
  */
365
434
  parseClzz(clzz) {
435
+ if (this.documentBuilder.getSchema(clzz.name)) {
436
+ return;
437
+ }
366
438
  const props = (0, decorator_1.getClassMetadata)(decorator_1.INJECT_CUSTOM_PROPERTY, clzz);
439
+ const tt = {
440
+ type: 'object',
441
+ properties: {},
442
+ };
367
443
  if (props) {
368
- const tt = {
369
- type: 'object',
370
- properties: {},
371
- required: [],
372
- example: {},
373
- };
374
444
  Object.keys(props).forEach(key => {
375
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
376
- if ((_a = props[key].metadata) === null || _a === void 0 ? void 0 : _a.example) {
377
- tt.example[key] = (_b = props[key].metadata) === null || _b === void 0 ? void 0 : _b.example;
445
+ var _a, _b;
446
+ const metadata = props[key].metadata;
447
+ if (metadata === null || metadata === void 0 ? void 0 : metadata.example) {
448
+ if (!tt.example) {
449
+ tt.example = {};
450
+ }
451
+ tt.example[key] = metadata === null || metadata === void 0 ? void 0 : metadata.example;
452
+ delete metadata.example;
378
453
  }
379
- if (((_c = props[key].metadata) === null || _c === void 0 ? void 0 : _c.required) !== false) {
454
+ if ((metadata === null || metadata === void 0 ? void 0 : metadata.required) !== false) {
455
+ if (!tt.required) {
456
+ tt.required = [];
457
+ }
380
458
  tt.required.push(key);
459
+ delete metadata.required;
381
460
  }
382
- if ((_d = props[key].metadata) === null || _d === void 0 ? void 0 : _d.enum) {
461
+ if (metadata === null || metadata === void 0 ? void 0 : metadata.enum) {
383
462
  tt.properties[key] = {
384
- type: (_e = props[key].metadata) === null || _e === void 0 ? void 0 : _e.type,
385
- enum: (_f = props[key].metadata) === null || _f === void 0 ? void 0 : _f.enum,
386
- default: (_g = props[key].metadata) === null || _g === void 0 ? void 0 : _g.default,
463
+ type: metadata === null || metadata === void 0 ? void 0 : metadata.type,
464
+ enum: metadata === null || metadata === void 0 ? void 0 : metadata.enum,
465
+ default: metadata === null || metadata === void 0 ? void 0 : metadata.default,
387
466
  };
467
+ if (metadata === null || metadata === void 0 ? void 0 : metadata.description) {
468
+ tt.properties[key].description = metadata === null || metadata === void 0 ? void 0 : metadata.description;
469
+ }
388
470
  return;
389
471
  }
390
- if ((_j = (_h = props[key].metadata) === null || _h === void 0 ? void 0 : _h.items) === null || _j === void 0 ? void 0 : _j.enum) {
472
+ if ((_a = metadata === null || metadata === void 0 ? void 0 : metadata.items) === null || _a === void 0 ? void 0 : _a.enum) {
391
473
  tt.properties[key] = {
392
- type: (_k = props[key].metadata) === null || _k === void 0 ? void 0 : _k.type,
393
- items: (_l = props[key].metadata) === null || _l === void 0 ? void 0 : _l.items,
394
- default: (_m = props[key].metadata) === null || _m === void 0 ? void 0 : _m.default,
474
+ type: metadata === null || metadata === void 0 ? void 0 : metadata.type,
475
+ items: metadata === null || metadata === void 0 ? void 0 : metadata.items,
476
+ default: metadata === null || metadata === void 0 ? void 0 : metadata.default,
395
477
  };
478
+ if (metadata === null || metadata === void 0 ? void 0 : metadata.description) {
479
+ tt.properties[key].description = metadata === null || metadata === void 0 ? void 0 : metadata.description;
480
+ }
396
481
  return;
397
482
  }
398
- let currentType = (_o = props[key].metadata) === null || _o === void 0 ? void 0 : _o.type;
483
+ let isArray = false;
484
+ let currentType = metadata === null || metadata === void 0 ? void 0 : metadata.type;
485
+ metadata === null || metadata === void 0 ? true : delete metadata.type;
399
486
  if (currentType === 'array') {
400
- currentType = (_q = (_p = props[key].metadata) === null || _p === void 0 ? void 0 : _p.items) === null || _q === void 0 ? void 0 : _q.type;
487
+ isArray = true;
488
+ currentType = (_b = metadata === null || metadata === void 0 ? void 0 : metadata.items) === null || _b === void 0 ? void 0 : _b.type;
489
+ delete metadata.items;
401
490
  }
402
- if ((0, decorator_1.isClass)(currentType)) {
491
+ if (decorator_1.Types.isClass(currentType)) {
403
492
  this.parseClzz(currentType);
404
- if (((_r = props[key].metadata) === null || _r === void 0 ? void 0 : _r.type) === 'array') {
493
+ if (isArray) {
405
494
  tt.properties[key] = {
406
495
  type: 'array',
407
496
  items: {
@@ -416,27 +505,28 @@ let SwaggerExplorer = class SwaggerExplorer {
416
505
  }
417
506
  }
418
507
  else {
419
- if (((_s = props[key].metadata) === null || _s === void 0 ? void 0 : _s.type) === 'array') {
508
+ if (isArray) {
420
509
  tt.properties[key] = {
421
510
  type: 'array',
422
511
  items: {
423
- type: (0, decorator_1.getPropertyType)(clzz.prototype, key).name,
424
- format: (_t = props[key].metadata) === null || _t === void 0 ? void 0 : _t.format,
512
+ type: convertSchemaType((currentType === null || currentType === void 0 ? void 0 : currentType.name) || currentType),
425
513
  },
426
514
  };
427
515
  }
428
516
  else {
429
517
  tt.properties[key] = {
430
518
  type: (0, decorator_1.getPropertyType)(clzz.prototype, key).name,
431
- format: (_u = props[key].metadata) === null || _u === void 0 ? void 0 : _u.format,
519
+ format: metadata === null || metadata === void 0 ? void 0 : metadata.format,
432
520
  };
521
+ delete metadata.format;
433
522
  }
434
523
  }
435
- });
436
- this.documentBuilder.addSchema({
437
- [clzz.name]: tt,
524
+ Object.assign(tt.properties[key], metadata);
438
525
  });
439
526
  }
527
+ this.documentBuilder.addSchema({
528
+ [clzz.name]: tt,
529
+ });
440
530
  }
441
531
  /**
442
532
  * 授权验证
@@ -545,6 +635,9 @@ function convertTypeToString(type) {
545
635
  case decorator_1.RouteParamTypes.PARAM:
546
636
  return 'path';
547
637
  case decorator_1.RouteParamTypes.BODY:
638
+ case decorator_1.RouteParamTypes.FIELDS:
639
+ case decorator_1.RouteParamTypes.FILESSTREAM:
640
+ case decorator_1.RouteParamTypes.FILESTREAM:
548
641
  return 'body';
549
642
  default:
550
643
  return 'header';
@@ -561,7 +654,7 @@ function convertSchemaType(value) {
561
654
  case 'String':
562
655
  return 'string';
563
656
  default:
564
- return 'object';
657
+ return value;
565
658
  }
566
659
  }
567
660
  //# sourceMappingURL=swaggerExplorer.js.map
@@ -5,5 +5,6 @@ export declare class SwaggerMiddleware implements IMiddleware<IMidwayContext, Ne
5
5
  private swaggerExplorer;
6
6
  init(): Promise<void>;
7
7
  resolve(app: IMidwayApplication): (req: any, res: any, next: NextFunction) => Promise<any>;
8
+ static getName(): string;
8
9
  }
9
10
  //# sourceMappingURL=swaggerMiddleware.d.ts.map
@@ -100,6 +100,9 @@ let SwaggerMiddleware = class SwaggerMiddleware {
100
100
  };
101
101
  }
102
102
  }
103
+ static getName() {
104
+ return 'swagger';
105
+ }
103
106
  };
104
107
  __decorate([
105
108
  (0, decorator_1.Config)('swagger'),
package/index.d.ts CHANGED
@@ -3,6 +3,6 @@ export * from './dist/index';
3
3
 
4
4
  declare module '@midwayjs/core/dist/interface' {
5
5
  interface MidwayConfig {
6
- swagger: Partial<SwaggerOptions>;
6
+ swagger?: Partial<SwaggerOptions>;
7
7
  }
8
8
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midwayjs/swagger",
3
- "version": "3.0.0-beta.9",
3
+ "version": "3.0.0",
4
4
  "main": "dist/index",
5
5
  "typings": "index.d.ts",
6
6
  "files": [
@@ -8,24 +8,24 @@
8
8
  "dist/**/*.d.ts",
9
9
  "index.d.ts"
10
10
  ],
11
- "dependencies": { },
12
11
  "devDependencies": {
13
- "swagger-ui-dist": "^3.34.0",
14
- "@midwayjs/core": "^3.0.0-beta.9",
15
- "@midwayjs/decorator": "^3.0.0-beta.9",
16
- "@midwayjs/koa": "^3.0.0-beta.9",
17
- "@midwayjs/mock": "^3.0.0-beta.9"
12
+ "@midwayjs/core": "^3.0.0",
13
+ "@midwayjs/decorator": "^3.0.0",
14
+ "@midwayjs/koa": "^3.0.0",
15
+ "@midwayjs/mock": "^3.0.0",
16
+ "swagger-ui-dist": "4.2.1"
18
17
  },
19
18
  "author": "Kurten Chan <chinkurten@gmail.com>",
20
19
  "license": "MIT",
21
20
  "scripts": {
22
21
  "build": "tsc",
23
22
  "jest": "node --require=ts-node/register ../../node_modules/jest/bin/jest.js",
24
- "test": "node --require=ts-node/register ../../node_modules/.bin/jest",
25
- "cov": "node --require=ts-node/register ../../node_modules/.bin/jest --coverage --forceExit"
23
+ "test": "node --require=ts-node/register ../../node_modules/.bin/jest --runInBand",
24
+ "cov": "node --require=ts-node/register ../../node_modules/.bin/jest --runInBand --coverage --forceExit"
26
25
  },
27
26
  "repository": {
28
27
  "type": "git",
29
28
  "url": "https://github.com/midwayjs/midway.git"
30
- }
29
+ },
30
+ "gitHead": "55c26029bccf7bbb739fa1597e8f418dafa2caa0"
31
31
  }