@trapi/swagger 1.0.0-alpha.11 → 1.0.0-alpha.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/config/index.d.ts +2 -2
  2. package/dist/config/index.js +24 -24
  3. package/dist/config/type.d.ts +82 -82
  4. package/dist/config/type.js +8 -8
  5. package/dist/config/utils.d.ts +2 -2
  6. package/dist/config/utils.js +53 -53
  7. package/dist/constants.d.ts +14 -14
  8. package/dist/constants.js +26 -26
  9. package/dist/generator/abstract.d.ts +34 -34
  10. package/dist/generator/abstract.js +251 -251
  11. package/dist/generator/index.d.ts +4 -4
  12. package/dist/generator/index.js +26 -26
  13. package/dist/generator/module.d.ts +13 -13
  14. package/dist/generator/module.js +34 -34
  15. package/dist/generator/v2/index.d.ts +1 -1
  16. package/dist/generator/v2/index.js +23 -23
  17. package/dist/generator/v2/module.d.ts +24 -24
  18. package/dist/generator/v2/module.js +516 -516
  19. package/dist/generator/v3/index.d.ts +1 -1
  20. package/dist/generator/v3/index.js +23 -23
  21. package/dist/generator/v3/module.d.ts +29 -29
  22. package/dist/generator/v3/module.js +498 -498
  23. package/dist/index.d.ts +7 -7
  24. package/dist/index.js +29 -29
  25. package/dist/metadata.d.ts +3 -3
  26. package/dist/metadata.js +13 -13
  27. package/dist/schema/constants.d.ts +27 -27
  28. package/dist/schema/constants.js +39 -39
  29. package/dist/schema/index.d.ts +4 -4
  30. package/dist/schema/index.js +26 -26
  31. package/dist/schema/type.d.ts +138 -138
  32. package/dist/schema/type.js +8 -8
  33. package/dist/schema/v2/constants.d.ts +7 -7
  34. package/dist/schema/v2/constants.js +17 -17
  35. package/dist/schema/v2/index.d.ts +2 -2
  36. package/dist/schema/v2/index.js +24 -24
  37. package/dist/schema/v2/type.d.ts +115 -115
  38. package/dist/schema/v2/type.js +8 -8
  39. package/dist/schema/v3/constants.d.ts +6 -6
  40. package/dist/schema/v3/constants.js +16 -16
  41. package/dist/schema/v3/index.d.ts +2 -2
  42. package/dist/schema/v3/index.js +24 -24
  43. package/dist/schema/v3/type.d.ts +158 -158
  44. package/dist/schema/v3/type.js +8 -8
  45. package/dist/type.d.ts +48 -48
  46. package/dist/type.js +8 -8
  47. package/dist/utils/character.d.ts +2 -2
  48. package/dist/utils/character.js +20 -20
  49. package/dist/utils/index.d.ts +4 -4
  50. package/dist/utils/index.js +26 -26
  51. package/dist/utils/object.d.ts +1 -1
  52. package/dist/utils/object.js +14 -14
  53. package/dist/utils/path.d.ts +1 -1
  54. package/dist/utils/path.js +20 -20
  55. package/dist/utils/value.d.ts +1 -1
  56. package/dist/utils/value.js +25 -25
  57. package/package.json +4 -4
@@ -1,499 +1,499 @@
1
- "use strict";
2
- /*
3
- * Copyright (c) 2021-2023.
4
- * Author Peter Placzek (tada5hi)
5
- * For the full copyright and license information,
6
- * view the LICENSE file that was distributed with this source code.
7
- */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.V3Generator = void 0;
10
- const metadata_1 = require("@trapi/metadata");
11
- const node_url_1 = require("node:url");
12
- const smob_1 = require("smob");
13
- const schema_1 = require("../../schema");
14
- const utils_1 = require("../../utils");
15
- const abstract_1 = require("../abstract");
16
- class V3Generator extends abstract_1.AbstractSpecGenerator {
17
- async build() {
18
- if (typeof this.spec !== 'undefined') {
19
- return this.spec;
20
- }
21
- let spec = {
22
- components: this.buildComponents(),
23
- info: this.buildInfo(),
24
- openapi: '3.1.0',
25
- paths: this.buildPaths(),
26
- servers: this.buildServers(),
27
- tags: [],
28
- };
29
- if (this.config.specificationExtra) {
30
- spec = (0, smob_1.merge)(spec, this.config.specificationExtra);
31
- }
32
- this.spec = spec;
33
- await this.save();
34
- return spec;
35
- }
36
- buildComponents() {
37
- const components = {
38
- examples: {},
39
- headers: {},
40
- parameters: {},
41
- requestBodies: {},
42
- responses: {},
43
- schemas: this.buildSchemasForReferenceTypes((output, referenceType) => {
44
- if (referenceType.deprecated) {
45
- output.deprecated = true;
46
- }
47
- }),
48
- securitySchemes: {},
49
- };
50
- if (this.config.securityDefinitions) {
51
- components.securitySchemes = V3Generator.translateSecurityDefinitions(this.config.securityDefinitions);
52
- }
53
- return components;
54
- }
55
- static translateSecurityDefinitions(securityDefinitions) {
56
- const output = {};
57
- const keys = Object.keys(securityDefinitions);
58
- for (let i = 0; i < keys.length; i++) {
59
- const securityDefinition = securityDefinitions[keys[i]];
60
- switch (securityDefinition.type) {
61
- case 'http':
62
- output[keys[i]] = securityDefinition;
63
- break;
64
- case 'oauth2':
65
- output[keys[i]] = securityDefinition;
66
- break;
67
- case 'apiKey':
68
- output[keys[i]] = securityDefinition;
69
- break;
70
- }
71
- }
72
- return output;
73
- }
74
- buildPaths() {
75
- const output = {};
76
- for (let i = 0; i < this.metadata.controllers.length; i++) {
77
- const controller = this.metadata.controllers[i];
78
- for (let j = 0; j < controller.methods.length; j++) {
79
- const method = controller.methods[j];
80
- if (method.hidden) {
81
- continue;
82
- }
83
- let path = (0, utils_1.removeFinalCharacter)((0, utils_1.removeDuplicateSlashes)(`/${controller.path}/${method.path}`), '/');
84
- path = (0, utils_1.normalizePathParameters)(path);
85
- output[path] = output[path] || {};
86
- output[path][method.method] = this.buildMethod(controller.name, method);
87
- }
88
- }
89
- return output;
90
- }
91
- buildMethod(controllerName, method) {
92
- const output = this.buildOperation(controllerName, method);
93
- output.description = method.description;
94
- output.summary = method.summary;
95
- output.tags = method.tags;
96
- // Use operationId tag otherwise fallback to generate. Warning: This doesn't check uniqueness.
97
- output.operationId = method.operationId || output.operationId;
98
- if (method.deprecated) {
99
- output.deprecated = method.deprecated;
100
- }
101
- if (method.security) {
102
- output.security = method.security;
103
- }
104
- const parameters = this.groupParameters(method.parameters);
105
- output.parameters = [
106
- ...(parameters[metadata_1.ParameterSource.QUERY_PROP] || []),
107
- ...(parameters[metadata_1.ParameterSource.HEADER] || []),
108
- ...(parameters[metadata_1.ParameterSource.PATH] || []),
109
- ...(parameters[metadata_1.ParameterSource.COOKIE] || []),
110
- ]
111
- .map((p) => this.buildParameter(p));
112
- // ignore ParameterSource.QUERY!
113
- const bodyParams = parameters[metadata_1.ParameterSource.BODY] || [];
114
- const formParams = parameters[metadata_1.ParameterSource.FORM_DATA] || [];
115
- if (bodyParams.length > 1) {
116
- throw new Error('Only one body parameter allowed per controller method.');
117
- }
118
- if (bodyParams.length > 0 && formParams.length > 0) {
119
- throw new Error('Either body parameter or form parameters allowed per controller method - not both.');
120
- }
121
- const bodyPropParams = parameters[metadata_1.ParameterSource.BODY_PROP] || [];
122
- if (bodyPropParams.length > 0) {
123
- if (bodyParams.length === 0) {
124
- bodyParams.push({
125
- in: metadata_1.ParameterSource.BODY,
126
- name: 'body',
127
- description: '',
128
- parameterName: bodyPropParams[0].parameterName || 'body',
129
- required: true,
130
- type: {
131
- typeName: metadata_1.TypeName.NESTED_OBJECT_LITERAL,
132
- properties: [],
133
- },
134
- validators: {},
135
- deprecated: false,
136
- });
137
- }
138
- if ((0, metadata_1.isNestedObjectLiteralType)(bodyParams[0].type)) {
139
- for (let i = 0; i < bodyPropParams.length; i++) {
140
- bodyParams[0].type.properties.push({
141
- default: bodyPropParams[i].default,
142
- validators: bodyPropParams[i].validators,
143
- description: bodyPropParams[i].description,
144
- name: bodyPropParams[i].name,
145
- type: bodyPropParams[i].type,
146
- required: bodyPropParams[i].required,
147
- deprecated: bodyPropParams[i].deprecated,
148
- });
149
- }
150
- }
151
- }
152
- if (bodyParams.length > 0) {
153
- output.requestBody = this.buildRequestBody(bodyParams[0]);
154
- }
155
- else if (formParams.length > 0) {
156
- output.requestBody = this.buildRequestBodyWithFormData(formParams);
157
- }
158
- for (let i = 0; i < method.extensions.length; i++) {
159
- output[method.extensions[i].key] = method.extensions[i].value;
160
- }
161
- return output;
162
- }
163
- buildRequestBodyWithFormData(parameters) {
164
- const required = [];
165
- const properties = {};
166
- const keys = Object.keys(parameters);
167
- for (let i = 0; i < parameters.length; i++) {
168
- const { schema } = this.buildMediaType(parameters[keys[i]]);
169
- properties[parameters[keys[i]].name] = schema;
170
- if (parameters[keys[i]].required) {
171
- required.push(parameters[keys[i]].name);
172
- }
173
- }
174
- return {
175
- required: required.length > 0,
176
- content: {
177
- 'multipart/form-data': {
178
- schema: {
179
- type: schema_1.DataTypeName.OBJECT,
180
- properties,
181
- // An empty list required: [] is not valid.
182
- // If all properties are optional, do not specify the required keyword.
183
- ...(required && required.length && { required }),
184
- },
185
- },
186
- },
187
- };
188
- }
189
- buildRequestBody(parameter) {
190
- const mediaType = this.buildMediaType(parameter);
191
- return {
192
- description: parameter.description,
193
- required: parameter.required,
194
- content: {
195
- 'application/json': mediaType,
196
- },
197
- };
198
- }
199
- buildMediaType(parameter) {
200
- return {
201
- schema: this.getSchemaForType(parameter.type),
202
- examples: this.transformParameterExamples(parameter),
203
- };
204
- }
205
- buildResponses(input) {
206
- const output = {};
207
- for (let i = 0; i < input.length; i++) {
208
- const res = input[i];
209
- const name = res.status || 'default';
210
- output[name] = {
211
- description: res.description,
212
- };
213
- if (res.schema &&
214
- !(0, metadata_1.isVoidType)(res.schema)) {
215
- const examples = {};
216
- if (res.examples &&
217
- res.examples.length > 0) {
218
- for (let i = 0; i < res.examples.length; i++) {
219
- const label = res.examples[i].label || `example${i + 1}`;
220
- examples[label] = {
221
- value: res.examples[i].value,
222
- };
223
- }
224
- }
225
- output[name].content = output[name].content || {};
226
- const contentTypes = res.produces || ['application/json'];
227
- for (let i = 0; i < contentTypes.length; i++) {
228
- output[name].content[contentTypes[i]] = {
229
- schema: this.getSchemaForType(res.schema),
230
- examples,
231
- };
232
- }
233
- }
234
- if (res.headers) {
235
- const headers = {};
236
- if ((0, metadata_1.isRefObjectType)(res.headers)) {
237
- headers[res.headers.refName] = {
238
- schema: this.getSchemaForReferenceType(res.headers),
239
- description: res.headers.description,
240
- };
241
- }
242
- else if ((0, metadata_1.isNestedObjectLiteralType)(res.headers)) {
243
- res.headers.properties.forEach((each) => {
244
- headers[each.name] = {
245
- schema: this.getSchemaForType(each.type),
246
- description: each.description,
247
- required: each.required,
248
- };
249
- });
250
- }
251
- output[res.name].headers = headers;
252
- }
253
- }
254
- return output;
255
- }
256
- buildOperation(controllerName, method) {
257
- const operation = {
258
- operationId: this.getOperationId(method.name),
259
- responses: this.buildResponses(method.responses),
260
- };
261
- if (method.description) {
262
- operation.description = method.description;
263
- }
264
- if (method.security) {
265
- operation.security = method.security;
266
- }
267
- if (method.deprecated) {
268
- operation.deprecated = method.deprecated;
269
- }
270
- return operation;
271
- }
272
- transformParameterSource(source) {
273
- if (source === metadata_1.ParameterSource.COOKIE) {
274
- return schema_1.ParameterSourceV3.COOKIE;
275
- }
276
- if (source === metadata_1.ParameterSource.HEADER) {
277
- return schema_1.ParameterSourceV3.HEADER;
278
- }
279
- if (source === metadata_1.ParameterSource.PATH) {
280
- return schema_1.ParameterSourceV3.PATH;
281
- }
282
- if (source === metadata_1.ParameterSource.QUERY_PROP || source === metadata_1.ParameterSource.QUERY) {
283
- return schema_1.ParameterSourceV3.QUERY;
284
- }
285
- return undefined;
286
- }
287
- buildParameter(input) {
288
- const sourceIn = this.transformParameterSource(input.in);
289
- if (!sourceIn) {
290
- throw new Error(`The parameter source "${input.in}" is not valid for generating a document.`);
291
- }
292
- const parameter = {
293
- allowEmptyValue: false,
294
- deprecated: false,
295
- description: input.description,
296
- in: sourceIn,
297
- name: input.name,
298
- required: input.required,
299
- schema: {
300
- default: input.default,
301
- format: undefined,
302
- ...this.transformValidators(input.validators),
303
- },
304
- };
305
- if (input.deprecated) {
306
- parameter.deprecated = true;
307
- }
308
- const parameterType = this.getSchemaForType(input.type);
309
- if (parameterType.format) {
310
- parameter.schema.format = parameterType.format;
311
- }
312
- if (parameterType.$ref) {
313
- parameter.schema = parameterType;
314
- return parameter;
315
- }
316
- if ((0, metadata_1.isAnyType)(input.type)) {
317
- parameter.schema.type = schema_1.DataTypeName.STRING;
318
- }
319
- else {
320
- if (parameterType.type) {
321
- parameter.schema.type = parameterType.type;
322
- }
323
- parameter.schema.items = parameterType.items;
324
- parameter.schema.enum = parameterType.enum;
325
- }
326
- parameter.examples = this.transformParameterExamples(input);
327
- return parameter;
328
- }
329
- transformParameterExamples(parameter) {
330
- const output = {};
331
- if (parameter.examples &&
332
- parameter.examples.length > 0) {
333
- for (let i = 0; i < parameter.examples.length; i++) {
334
- const label = parameter.examples[i].label || `example${i + 1}`;
335
- output[label] = {
336
- value: parameter.examples[i].value,
337
- };
338
- }
339
- }
340
- return output;
341
- }
342
- buildServers() {
343
- const servers = [];
344
- for (let i = 0; i < this.config.servers.length; i++) {
345
- const url = new node_url_1.URL(this.config.servers[i].url, 'http://localhost:3000/');
346
- servers.push({
347
- url: `${url.protocol}//${url.host}${url.pathname || ''}`,
348
- ...(this.config.servers[i].description ? { description: this.config.servers[i].description } : {}),
349
- });
350
- }
351
- return servers;
352
- }
353
- buildSchemaForRefObject(input) {
354
- const required = input.properties
355
- .filter((p) => p.required && !this.isUndefinedProperty(p))
356
- .map((p) => p.name);
357
- const schema = {
358
- description: input.description,
359
- properties: this.buildProperties(input.properties),
360
- required: required && required.length > 0 ? Array.from(new Set(required)) : undefined,
361
- type: 'object',
362
- };
363
- if (input.additionalProperties) {
364
- schema.additionalProperties = this.getSchemaForType(input.additionalProperties);
365
- }
366
- if (input.example) {
367
- schema.example = input.example;
368
- }
369
- return schema;
370
- }
371
- buildSchemaForRefEnum(referenceType) {
372
- const type = this.decideEnumType(referenceType.members);
373
- const typesUsed = this.determineTypesUsedInEnum(referenceType.members);
374
- if (typesUsed.length === 1) {
375
- const schema = {
376
- description: referenceType.description,
377
- enum: referenceType.members,
378
- type,
379
- };
380
- if (typeof referenceType.memberNames !== undefined &&
381
- referenceType.members.length === referenceType.memberNames.length) {
382
- schema['x-enum-varnames'] = referenceType.memberNames;
383
- }
384
- return schema;
385
- }
386
- const schema = {
387
- description: referenceType.description,
388
- anyOf: [],
389
- };
390
- for (let i = 0; i < typesUsed.length; i++) {
391
- schema.anyOf.push({
392
- type: typesUsed[i],
393
- enum: referenceType.members.filter((e) => typeof e === typesUsed[i]),
394
- });
395
- }
396
- return schema;
397
- }
398
- buildSchemaForRefAlias(referenceType) {
399
- const swaggerType = this.getSchemaForType(referenceType.type);
400
- const format = referenceType.format;
401
- return {
402
- ...swaggerType,
403
- default: referenceType.default || swaggerType.default,
404
- example: referenceType.example,
405
- format: format || swaggerType.format,
406
- description: referenceType.description,
407
- ...this.transformValidators(referenceType.validators),
408
- };
409
- }
410
- buildProperties(properties) {
411
- const output = {};
412
- properties.forEach((property) => {
413
- const swaggerType = this.getSchemaForType(property.type);
414
- swaggerType.description = property.description;
415
- swaggerType.example = property.example;
416
- swaggerType.format = property.format || swaggerType.format;
417
- if (!swaggerType.$ref) {
418
- swaggerType.default = property.default;
419
- }
420
- if (property.deprecated) {
421
- swaggerType.deprecated = true;
422
- }
423
- const extensions = this.transformExtensions(property.extensions);
424
- const validators = this.transformValidators(property.validators);
425
- output[property.name] = {
426
- ...swaggerType,
427
- ...validators,
428
- ...extensions,
429
- };
430
- });
431
- return output;
432
- }
433
- getSchemaForIntersectionType(type) {
434
- return { allOf: type.members.map((x) => this.getSchemaForType(x)) };
435
- }
436
- getSchemaForEnumType(enumType) {
437
- const type = this.decideEnumType(enumType.members);
438
- const nullable = !!enumType.members.includes(null);
439
- return {
440
- type,
441
- enum: enumType.members.map((member) => (0, utils_1.transformValueTo)(type, member)),
442
- nullable,
443
- };
444
- }
445
- getSchemaForReferenceType(referenceType) {
446
- return {
447
- $ref: `#/components/schemas/${referenceType.refName}`,
448
- };
449
- }
450
- getSchemaForUnionType(type) {
451
- const members = [];
452
- let nullable = false;
453
- const enumMembers = {};
454
- for (let i = 0; i < type.members.length; i++) {
455
- const member = type.members[i];
456
- if ((0, metadata_1.isEnumType)(member)) {
457
- for (let j = 0; j < member.members.length; j++) {
458
- const memberChild = member.members[j];
459
- if (memberChild === null || memberChild === undefined) {
460
- nullable = true;
461
- continue;
462
- }
463
- const typeOf = typeof memberChild;
464
- if (typeOf === 'string' || typeOf === 'number' || typeOf === 'boolean') {
465
- enumMembers[typeOf] = enumMembers[typeOf] || [];
466
- enumMembers[typeOf].push(memberChild);
467
- }
468
- }
469
- }
470
- if (!(0, metadata_1.isAnyType)(member) &&
471
- !(0, metadata_1.isUndefinedType)(member) &&
472
- !(0, metadata_1.isEnumType)(member)) {
473
- members.push(member);
474
- }
475
- }
476
- const schemas = [];
477
- for (let i = 0; i < members.length; i++) {
478
- schemas.push(this.getSchemaForType(members[i]));
479
- }
480
- const enumMembersKeys = Object.keys(enumMembers);
481
- for (let i = 0; i < enumMembersKeys.length; i++) {
482
- const enumType = {
483
- typeName: 'enum',
484
- members: enumMembers[enumMembersKeys[i]],
485
- };
486
- schemas.push(this.getSchemaForEnumType(enumType));
487
- }
488
- if (schemas.length === 1) {
489
- const schema = schemas[0];
490
- if (schema.$ref) {
491
- return { allOf: [schema], nullable };
492
- }
493
- return { ...schema, nullable };
494
- }
495
- return { anyOf: schemas, ...(nullable ? { nullable } : {}) };
496
- }
497
- }
498
- exports.V3Generator = V3Generator;
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2021-2023.
4
+ * Author Peter Placzek (tada5hi)
5
+ * For the full copyright and license information,
6
+ * view the LICENSE file that was distributed with this source code.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.V3Generator = void 0;
10
+ const metadata_1 = require("@trapi/metadata");
11
+ const node_url_1 = require("node:url");
12
+ const smob_1 = require("smob");
13
+ const schema_1 = require("../../schema");
14
+ const utils_1 = require("../../utils");
15
+ const abstract_1 = require("../abstract");
16
+ class V3Generator extends abstract_1.AbstractSpecGenerator {
17
+ async build() {
18
+ if (typeof this.spec !== 'undefined') {
19
+ return this.spec;
20
+ }
21
+ let spec = {
22
+ components: this.buildComponents(),
23
+ info: this.buildInfo(),
24
+ openapi: '3.1.0',
25
+ paths: this.buildPaths(),
26
+ servers: this.buildServers(),
27
+ tags: [],
28
+ };
29
+ if (this.config.specificationExtra) {
30
+ spec = (0, smob_1.merge)(spec, this.config.specificationExtra);
31
+ }
32
+ this.spec = spec;
33
+ await this.save();
34
+ return spec;
35
+ }
36
+ buildComponents() {
37
+ const components = {
38
+ examples: {},
39
+ headers: {},
40
+ parameters: {},
41
+ requestBodies: {},
42
+ responses: {},
43
+ schemas: this.buildSchemasForReferenceTypes((output, referenceType) => {
44
+ if (referenceType.deprecated) {
45
+ output.deprecated = true;
46
+ }
47
+ }),
48
+ securitySchemes: {},
49
+ };
50
+ if (this.config.securityDefinitions) {
51
+ components.securitySchemes = V3Generator.translateSecurityDefinitions(this.config.securityDefinitions);
52
+ }
53
+ return components;
54
+ }
55
+ static translateSecurityDefinitions(securityDefinitions) {
56
+ const output = {};
57
+ const keys = Object.keys(securityDefinitions);
58
+ for (let i = 0; i < keys.length; i++) {
59
+ const securityDefinition = securityDefinitions[keys[i]];
60
+ switch (securityDefinition.type) {
61
+ case 'http':
62
+ output[keys[i]] = securityDefinition;
63
+ break;
64
+ case 'oauth2':
65
+ output[keys[i]] = securityDefinition;
66
+ break;
67
+ case 'apiKey':
68
+ output[keys[i]] = securityDefinition;
69
+ break;
70
+ }
71
+ }
72
+ return output;
73
+ }
74
+ buildPaths() {
75
+ const output = {};
76
+ for (let i = 0; i < this.metadata.controllers.length; i++) {
77
+ const controller = this.metadata.controllers[i];
78
+ for (let j = 0; j < controller.methods.length; j++) {
79
+ const method = controller.methods[j];
80
+ if (method.hidden) {
81
+ continue;
82
+ }
83
+ let path = (0, utils_1.removeFinalCharacter)((0, utils_1.removeDuplicateSlashes)(`/${controller.path}/${method.path}`), '/');
84
+ path = (0, utils_1.normalizePathParameters)(path);
85
+ output[path] = output[path] || {};
86
+ output[path][method.method] = this.buildMethod(controller.name, method);
87
+ }
88
+ }
89
+ return output;
90
+ }
91
+ buildMethod(controllerName, method) {
92
+ const output = this.buildOperation(controllerName, method);
93
+ output.description = method.description;
94
+ output.summary = method.summary;
95
+ output.tags = method.tags;
96
+ // Use operationId tag otherwise fallback to generate. Warning: This doesn't check uniqueness.
97
+ output.operationId = method.operationId || output.operationId;
98
+ if (method.deprecated) {
99
+ output.deprecated = method.deprecated;
100
+ }
101
+ if (method.security) {
102
+ output.security = method.security;
103
+ }
104
+ const parameters = this.groupParameters(method.parameters);
105
+ output.parameters = [
106
+ ...(parameters[metadata_1.ParameterSource.QUERY_PROP] || []),
107
+ ...(parameters[metadata_1.ParameterSource.HEADER] || []),
108
+ ...(parameters[metadata_1.ParameterSource.PATH] || []),
109
+ ...(parameters[metadata_1.ParameterSource.COOKIE] || []),
110
+ ]
111
+ .map((p) => this.buildParameter(p));
112
+ // ignore ParameterSource.QUERY!
113
+ const bodyParams = parameters[metadata_1.ParameterSource.BODY] || [];
114
+ const formParams = parameters[metadata_1.ParameterSource.FORM_DATA] || [];
115
+ if (bodyParams.length > 1) {
116
+ throw new Error('Only one body parameter allowed per controller method.');
117
+ }
118
+ if (bodyParams.length > 0 && formParams.length > 0) {
119
+ throw new Error('Either body parameter or form parameters allowed per controller method - not both.');
120
+ }
121
+ const bodyPropParams = parameters[metadata_1.ParameterSource.BODY_PROP] || [];
122
+ if (bodyPropParams.length > 0) {
123
+ if (bodyParams.length === 0) {
124
+ bodyParams.push({
125
+ in: metadata_1.ParameterSource.BODY,
126
+ name: 'body',
127
+ description: '',
128
+ parameterName: bodyPropParams[0].parameterName || 'body',
129
+ required: true,
130
+ type: {
131
+ typeName: metadata_1.TypeName.NESTED_OBJECT_LITERAL,
132
+ properties: [],
133
+ },
134
+ validators: {},
135
+ deprecated: false,
136
+ });
137
+ }
138
+ if ((0, metadata_1.isNestedObjectLiteralType)(bodyParams[0].type)) {
139
+ for (let i = 0; i < bodyPropParams.length; i++) {
140
+ bodyParams[0].type.properties.push({
141
+ default: bodyPropParams[i].default,
142
+ validators: bodyPropParams[i].validators,
143
+ description: bodyPropParams[i].description,
144
+ name: bodyPropParams[i].name,
145
+ type: bodyPropParams[i].type,
146
+ required: bodyPropParams[i].required,
147
+ deprecated: bodyPropParams[i].deprecated,
148
+ });
149
+ }
150
+ }
151
+ }
152
+ if (bodyParams.length > 0) {
153
+ output.requestBody = this.buildRequestBody(bodyParams[0]);
154
+ }
155
+ else if (formParams.length > 0) {
156
+ output.requestBody = this.buildRequestBodyWithFormData(formParams);
157
+ }
158
+ for (let i = 0; i < method.extensions.length; i++) {
159
+ output[method.extensions[i].key] = method.extensions[i].value;
160
+ }
161
+ return output;
162
+ }
163
+ buildRequestBodyWithFormData(parameters) {
164
+ const required = [];
165
+ const properties = {};
166
+ const keys = Object.keys(parameters);
167
+ for (let i = 0; i < parameters.length; i++) {
168
+ const { schema } = this.buildMediaType(parameters[keys[i]]);
169
+ properties[parameters[keys[i]].name] = schema;
170
+ if (parameters[keys[i]].required) {
171
+ required.push(parameters[keys[i]].name);
172
+ }
173
+ }
174
+ return {
175
+ required: required.length > 0,
176
+ content: {
177
+ 'multipart/form-data': {
178
+ schema: {
179
+ type: schema_1.DataTypeName.OBJECT,
180
+ properties,
181
+ // An empty list required: [] is not valid.
182
+ // If all properties are optional, do not specify the required keyword.
183
+ ...(required && required.length && { required }),
184
+ },
185
+ },
186
+ },
187
+ };
188
+ }
189
+ buildRequestBody(parameter) {
190
+ const mediaType = this.buildMediaType(parameter);
191
+ return {
192
+ description: parameter.description,
193
+ required: parameter.required,
194
+ content: {
195
+ 'application/json': mediaType,
196
+ },
197
+ };
198
+ }
199
+ buildMediaType(parameter) {
200
+ return {
201
+ schema: this.getSchemaForType(parameter.type),
202
+ examples: this.transformParameterExamples(parameter),
203
+ };
204
+ }
205
+ buildResponses(input) {
206
+ const output = {};
207
+ for (let i = 0; i < input.length; i++) {
208
+ const res = input[i];
209
+ const name = res.status || 'default';
210
+ output[name] = {
211
+ description: res.description,
212
+ };
213
+ if (res.schema &&
214
+ !(0, metadata_1.isVoidType)(res.schema)) {
215
+ const examples = {};
216
+ if (res.examples &&
217
+ res.examples.length > 0) {
218
+ for (let i = 0; i < res.examples.length; i++) {
219
+ const label = res.examples[i].label || `example${i + 1}`;
220
+ examples[label] = {
221
+ value: res.examples[i].value,
222
+ };
223
+ }
224
+ }
225
+ output[name].content = output[name].content || {};
226
+ const contentTypes = res.produces || ['application/json'];
227
+ for (let i = 0; i < contentTypes.length; i++) {
228
+ output[name].content[contentTypes[i]] = {
229
+ schema: this.getSchemaForType(res.schema),
230
+ examples,
231
+ };
232
+ }
233
+ }
234
+ if (res.headers) {
235
+ const headers = {};
236
+ if ((0, metadata_1.isRefObjectType)(res.headers)) {
237
+ headers[res.headers.refName] = {
238
+ schema: this.getSchemaForReferenceType(res.headers),
239
+ description: res.headers.description,
240
+ };
241
+ }
242
+ else if ((0, metadata_1.isNestedObjectLiteralType)(res.headers)) {
243
+ res.headers.properties.forEach((each) => {
244
+ headers[each.name] = {
245
+ schema: this.getSchemaForType(each.type),
246
+ description: each.description,
247
+ required: each.required,
248
+ };
249
+ });
250
+ }
251
+ output[res.name].headers = headers;
252
+ }
253
+ }
254
+ return output;
255
+ }
256
+ buildOperation(controllerName, method) {
257
+ const operation = {
258
+ operationId: this.getOperationId(method.name),
259
+ responses: this.buildResponses(method.responses),
260
+ };
261
+ if (method.description) {
262
+ operation.description = method.description;
263
+ }
264
+ if (method.security) {
265
+ operation.security = method.security;
266
+ }
267
+ if (method.deprecated) {
268
+ operation.deprecated = method.deprecated;
269
+ }
270
+ return operation;
271
+ }
272
+ transformParameterSource(source) {
273
+ if (source === metadata_1.ParameterSource.COOKIE) {
274
+ return schema_1.ParameterSourceV3.COOKIE;
275
+ }
276
+ if (source === metadata_1.ParameterSource.HEADER) {
277
+ return schema_1.ParameterSourceV3.HEADER;
278
+ }
279
+ if (source === metadata_1.ParameterSource.PATH) {
280
+ return schema_1.ParameterSourceV3.PATH;
281
+ }
282
+ if (source === metadata_1.ParameterSource.QUERY_PROP || source === metadata_1.ParameterSource.QUERY) {
283
+ return schema_1.ParameterSourceV3.QUERY;
284
+ }
285
+ return undefined;
286
+ }
287
+ buildParameter(input) {
288
+ const sourceIn = this.transformParameterSource(input.in);
289
+ if (!sourceIn) {
290
+ throw new Error(`The parameter source "${input.in}" is not valid for generating a document.`);
291
+ }
292
+ const parameter = {
293
+ allowEmptyValue: false,
294
+ deprecated: false,
295
+ description: input.description,
296
+ in: sourceIn,
297
+ name: input.name,
298
+ required: input.required,
299
+ schema: {
300
+ default: input.default,
301
+ format: undefined,
302
+ ...this.transformValidators(input.validators),
303
+ },
304
+ };
305
+ if (input.deprecated) {
306
+ parameter.deprecated = true;
307
+ }
308
+ const parameterType = this.getSchemaForType(input.type);
309
+ if (parameterType.format) {
310
+ parameter.schema.format = parameterType.format;
311
+ }
312
+ if (parameterType.$ref) {
313
+ parameter.schema = parameterType;
314
+ return parameter;
315
+ }
316
+ if ((0, metadata_1.isAnyType)(input.type)) {
317
+ parameter.schema.type = schema_1.DataTypeName.STRING;
318
+ }
319
+ else {
320
+ if (parameterType.type) {
321
+ parameter.schema.type = parameterType.type;
322
+ }
323
+ parameter.schema.items = parameterType.items;
324
+ parameter.schema.enum = parameterType.enum;
325
+ }
326
+ parameter.examples = this.transformParameterExamples(input);
327
+ return parameter;
328
+ }
329
+ transformParameterExamples(parameter) {
330
+ const output = {};
331
+ if (parameter.examples &&
332
+ parameter.examples.length > 0) {
333
+ for (let i = 0; i < parameter.examples.length; i++) {
334
+ const label = parameter.examples[i].label || `example${i + 1}`;
335
+ output[label] = {
336
+ value: parameter.examples[i].value,
337
+ };
338
+ }
339
+ }
340
+ return output;
341
+ }
342
+ buildServers() {
343
+ const servers = [];
344
+ for (let i = 0; i < this.config.servers.length; i++) {
345
+ const url = new node_url_1.URL(this.config.servers[i].url, 'http://localhost:3000/');
346
+ servers.push({
347
+ url: `${url.protocol}//${url.host}${url.pathname || ''}`,
348
+ ...(this.config.servers[i].description ? { description: this.config.servers[i].description } : {}),
349
+ });
350
+ }
351
+ return servers;
352
+ }
353
+ buildSchemaForRefObject(input) {
354
+ const required = input.properties
355
+ .filter((p) => p.required && !this.isUndefinedProperty(p))
356
+ .map((p) => p.name);
357
+ const schema = {
358
+ description: input.description,
359
+ properties: this.buildProperties(input.properties),
360
+ required: required && required.length > 0 ? Array.from(new Set(required)) : undefined,
361
+ type: 'object',
362
+ };
363
+ if (input.additionalProperties) {
364
+ schema.additionalProperties = this.getSchemaForType(input.additionalProperties);
365
+ }
366
+ if (input.example) {
367
+ schema.example = input.example;
368
+ }
369
+ return schema;
370
+ }
371
+ buildSchemaForRefEnum(referenceType) {
372
+ const type = this.decideEnumType(referenceType.members);
373
+ const typesUsed = this.determineTypesUsedInEnum(referenceType.members);
374
+ if (typesUsed.length === 1) {
375
+ const schema = {
376
+ description: referenceType.description,
377
+ enum: referenceType.members,
378
+ type,
379
+ };
380
+ if (typeof referenceType.memberNames !== undefined &&
381
+ referenceType.members.length === referenceType.memberNames.length) {
382
+ schema['x-enum-varnames'] = referenceType.memberNames;
383
+ }
384
+ return schema;
385
+ }
386
+ const schema = {
387
+ description: referenceType.description,
388
+ anyOf: [],
389
+ };
390
+ for (let i = 0; i < typesUsed.length; i++) {
391
+ schema.anyOf.push({
392
+ type: typesUsed[i],
393
+ enum: referenceType.members.filter((e) => typeof e === typesUsed[i]),
394
+ });
395
+ }
396
+ return schema;
397
+ }
398
+ buildSchemaForRefAlias(referenceType) {
399
+ const swaggerType = this.getSchemaForType(referenceType.type);
400
+ const format = referenceType.format;
401
+ return {
402
+ ...swaggerType,
403
+ default: referenceType.default || swaggerType.default,
404
+ example: referenceType.example,
405
+ format: format || swaggerType.format,
406
+ description: referenceType.description,
407
+ ...this.transformValidators(referenceType.validators),
408
+ };
409
+ }
410
+ buildProperties(properties) {
411
+ const output = {};
412
+ properties.forEach((property) => {
413
+ const swaggerType = this.getSchemaForType(property.type);
414
+ swaggerType.description = property.description;
415
+ swaggerType.example = property.example;
416
+ swaggerType.format = property.format || swaggerType.format;
417
+ if (!swaggerType.$ref) {
418
+ swaggerType.default = property.default;
419
+ }
420
+ if (property.deprecated) {
421
+ swaggerType.deprecated = true;
422
+ }
423
+ const extensions = this.transformExtensions(property.extensions);
424
+ const validators = this.transformValidators(property.validators);
425
+ output[property.name] = {
426
+ ...swaggerType,
427
+ ...validators,
428
+ ...extensions,
429
+ };
430
+ });
431
+ return output;
432
+ }
433
+ getSchemaForIntersectionType(type) {
434
+ return { allOf: type.members.map((x) => this.getSchemaForType(x)) };
435
+ }
436
+ getSchemaForEnumType(enumType) {
437
+ const type = this.decideEnumType(enumType.members);
438
+ const nullable = !!enumType.members.includes(null);
439
+ return {
440
+ type,
441
+ enum: enumType.members.map((member) => (0, utils_1.transformValueTo)(type, member)),
442
+ nullable,
443
+ };
444
+ }
445
+ getSchemaForReferenceType(referenceType) {
446
+ return {
447
+ $ref: `#/components/schemas/${referenceType.refName}`,
448
+ };
449
+ }
450
+ getSchemaForUnionType(type) {
451
+ const members = [];
452
+ let nullable = false;
453
+ const enumMembers = {};
454
+ for (let i = 0; i < type.members.length; i++) {
455
+ const member = type.members[i];
456
+ if ((0, metadata_1.isEnumType)(member)) {
457
+ for (let j = 0; j < member.members.length; j++) {
458
+ const memberChild = member.members[j];
459
+ if (memberChild === null || memberChild === undefined) {
460
+ nullable = true;
461
+ continue;
462
+ }
463
+ const typeOf = typeof memberChild;
464
+ if (typeOf === 'string' || typeOf === 'number' || typeOf === 'boolean') {
465
+ enumMembers[typeOf] = enumMembers[typeOf] || [];
466
+ enumMembers[typeOf].push(memberChild);
467
+ }
468
+ }
469
+ }
470
+ if (!(0, metadata_1.isAnyType)(member) &&
471
+ !(0, metadata_1.isUndefinedType)(member) &&
472
+ !(0, metadata_1.isEnumType)(member)) {
473
+ members.push(member);
474
+ }
475
+ }
476
+ const schemas = [];
477
+ for (let i = 0; i < members.length; i++) {
478
+ schemas.push(this.getSchemaForType(members[i]));
479
+ }
480
+ const enumMembersKeys = Object.keys(enumMembers);
481
+ for (let i = 0; i < enumMembersKeys.length; i++) {
482
+ const enumType = {
483
+ typeName: 'enum',
484
+ members: enumMembers[enumMembersKeys[i]],
485
+ };
486
+ schemas.push(this.getSchemaForEnumType(enumType));
487
+ }
488
+ if (schemas.length === 1) {
489
+ const schema = schemas[0];
490
+ if (schema.$ref) {
491
+ return { allOf: [schema], nullable };
492
+ }
493
+ return { ...schema, nullable };
494
+ }
495
+ return { anyOf: schemas, ...(nullable ? { nullable } : {}) };
496
+ }
497
+ }
498
+ exports.V3Generator = V3Generator;
499
499
  //# sourceMappingURL=module.js.map