@trapi/swagger 0.2.11 → 0.2.15
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/config/utils/index.d.ts +1 -1
- package/dist/config/utils/validator.d.ts +2 -2
- package/dist/config/utils/validator.d.ts.map +1 -1
- package/dist/config/utils/validator.js +9 -9
- package/dist/config/utils/validator.js.map +1 -1
- package/dist/metadata.d.ts +1 -1
- package/dist/metadata.d.ts.map +1 -1
- package/dist/specification/abstract.d.ts +5 -5
- package/dist/specification/abstract.d.ts.map +1 -1
- package/dist/specification/abstract.js +23 -27
- package/dist/specification/abstract.js.map +1 -1
- package/dist/specification/index.d.ts +1 -1
- package/dist/specification/type.d.ts +0 -3
- package/dist/specification/type.d.ts.map +1 -1
- package/dist/specification/type.js.map +1 -1
- package/dist/specification/utils.d.ts +3 -3
- package/dist/specification/utils.d.ts.map +1 -1
- package/dist/specification/utils.js +1 -1
- package/dist/specification/utils.js.map +1 -1
- package/dist/specification/v2/index.d.ts +3 -3
- package/dist/specification/v2/index.d.ts.map +1 -1
- package/dist/specification/v2/index.js +48 -60
- package/dist/specification/v2/index.js.map +1 -1
- package/dist/specification/v2/type.d.ts +1 -1
- package/dist/specification/v2/type.d.ts.map +1 -1
- package/dist/specification/v3/index.d.ts +3 -3
- package/dist/specification/v3/index.d.ts.map +1 -1
- package/dist/specification/v3/index.js +28 -36
- package/dist/specification/v3/index.js.map +1 -1
- package/dist/specification/v3/type.d.ts +1 -1
- package/dist/specification/v3/type.d.ts.map +1 -1
- package/dist/utils.d.ts +3 -3
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +1 -1
- package/dist/utils.js.map +1 -1
- package/package.json +12 -9
- package/src/config/index.ts +0 -8
- package/src/config/utils/index.ts +0 -8
- package/src/config/utils/validator.ts +0 -94
- package/src/index.ts +0 -12
- package/src/metadata.ts +0 -58
- package/src/specification/abstract.ts +0 -250
- package/src/specification/index.ts +0 -11
- package/src/specification/type.ts +0 -328
- package/src/specification/utils.ts +0 -47
- package/src/specification/v2/index.ts +0 -463
- package/src/specification/v2/type.ts +0 -92
- package/src/specification/v3/index.ts +0 -448
- package/src/specification/v3/type.ts +0 -129
- package/src/type.ts +0 -14
- package/src/utils.ts +0 -28
- package/test/data/metadata.json +0 -1
- package/test/jest.config.js +0 -43
- package/test/tsconfig.json +0 -28
- package/test/unit/index.ts +0 -425
- package/tsconfig.build.json +0 -11
- package/tsconfig.json +0 -9
- package/writable/.gitignore +0 -3
|
@@ -1,463 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2021.
|
|
3
|
-
* Author Peter Placzek (tada5hi)
|
|
4
|
-
* For the full copyright and license information,
|
|
5
|
-
* view the LICENSE file that was distributed with this source code.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import {union} from "lodash";
|
|
9
|
-
import {posix} from "path";
|
|
10
|
-
import {URL} from 'url';
|
|
11
|
-
|
|
12
|
-
import {hasOwnProperty, normalizePathParameters} from "@trapi/metadata-utils";
|
|
13
|
-
import {Method, Parameter, Property, Response, Resolver} from "@trapi/metadata";
|
|
14
|
-
|
|
15
|
-
import {Specification} from "../type";
|
|
16
|
-
import {SpecificationV2} from "./type";
|
|
17
|
-
import {AbstractSpecGenerator} from "../abstract";
|
|
18
|
-
|
|
19
|
-
export class Version2SpecGenerator extends AbstractSpecGenerator<SpecificationV2.Spec, SpecificationV2.Schema> {
|
|
20
|
-
public getSwaggerSpec(): SpecificationV2.Spec {
|
|
21
|
-
return this.build();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public build() : SpecificationV2.Spec {
|
|
25
|
-
if(typeof this.spec !== 'undefined') {
|
|
26
|
-
return this.spec;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
let spec: SpecificationV2.Spec = {
|
|
30
|
-
basePath: this.config.basePath,
|
|
31
|
-
definitions: this.buildDefinitions(),
|
|
32
|
-
info: this.buildInfo(),
|
|
33
|
-
paths: this.buildPaths(),
|
|
34
|
-
swagger: '2.0'
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
spec.securityDefinitions = this.config.securityDefinitions
|
|
38
|
-
? Version2SpecGenerator.translateSecurityDefinitions(this.config.securityDefinitions)
|
|
39
|
-
: {};
|
|
40
|
-
|
|
41
|
-
if (this.config.consumes) {
|
|
42
|
-
spec.consumes = this.config.consumes;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (this.config.produces) {
|
|
46
|
-
spec.produces = this.config.produces;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (this.config.host) {
|
|
50
|
-
const url = new URL(this.config.host);
|
|
51
|
-
let host : string = (url.host + url.pathname).replace(/([^:]\/)\/+/g, "$1");
|
|
52
|
-
host = host.substr(-1, 1) === '/' ? host.substr(0, host.length -1) : host;
|
|
53
|
-
|
|
54
|
-
spec.host = host;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (this.config.specificationExtra) {
|
|
58
|
-
spec = require('merge').recursive(spec, this.config.specificationExtra);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
this.spec = spec;
|
|
62
|
-
|
|
63
|
-
return spec;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
private static translateSecurityDefinitions(securityDefinitions: Specification.SecurityDefinitions) : Record<string, SpecificationV2.Security> {
|
|
67
|
-
const definitions : Record<string, SpecificationV2.Security> = {};
|
|
68
|
-
|
|
69
|
-
// tslint:disable-next-line:forin
|
|
70
|
-
for(const name in securityDefinitions) {
|
|
71
|
-
const securityDefinition : Specification.SecurityDefinition = securityDefinitions[name];
|
|
72
|
-
|
|
73
|
-
switch (securityDefinition.type) {
|
|
74
|
-
case 'http':
|
|
75
|
-
if(securityDefinition.schema === 'basic') {
|
|
76
|
-
definitions[name] = {
|
|
77
|
-
type: 'basic'
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
break;
|
|
81
|
-
case 'apiKey':
|
|
82
|
-
definitions[name] = securityDefinition;
|
|
83
|
-
break;
|
|
84
|
-
case 'oauth2':
|
|
85
|
-
if(securityDefinition.flows.implicit) {
|
|
86
|
-
definitions[`${name}Implicit`] = {
|
|
87
|
-
type: "oauth2",
|
|
88
|
-
flow: "implicit",
|
|
89
|
-
authorizationUrl: securityDefinition.flows.implicit.authorizationUrl,
|
|
90
|
-
scopes: securityDefinition.flows.implicit.scopes
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if(securityDefinition.flows.password) {
|
|
95
|
-
definitions[`${name}Implicit`] = {
|
|
96
|
-
type: "oauth2",
|
|
97
|
-
flow: "password",
|
|
98
|
-
tokenUrl: securityDefinition.flows.password.tokenUrl,
|
|
99
|
-
scopes: securityDefinition.flows.password.scopes
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if(securityDefinition.flows.authorizationCode) {
|
|
104
|
-
definitions[`${name}AccessCode`] = {
|
|
105
|
-
type: "oauth2",
|
|
106
|
-
flow: "accessCode",
|
|
107
|
-
tokenUrl: securityDefinition.flows.authorizationCode.tokenUrl,
|
|
108
|
-
authorizationUrl: securityDefinition.flows.authorizationCode.authorizationUrl,
|
|
109
|
-
scopes: securityDefinition.flows.authorizationCode.scopes
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if(securityDefinition.flows.clientCredentials) {
|
|
114
|
-
definitions[`${name}Application`] = {
|
|
115
|
-
type: "oauth2",
|
|
116
|
-
flow: "application",
|
|
117
|
-
tokenUrl: securityDefinition.flows.clientCredentials.tokenUrl,
|
|
118
|
-
scopes: securityDefinition.flows.clientCredentials.scopes
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
break;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return definitions;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/*
|
|
130
|
-
Definitions ( + utils)
|
|
131
|
-
*/
|
|
132
|
-
|
|
133
|
-
private buildDefinitions() {
|
|
134
|
-
const definitions: { [definitionsName: string]: SpecificationV2.Schema } = {};
|
|
135
|
-
Object.keys(this.metadata.referenceTypes).map(typeName => {
|
|
136
|
-
const referenceType : Resolver.ReferenceType = this.metadata.referenceTypes[typeName];
|
|
137
|
-
// const key : string = referenceType.typeName.replace('_', '');
|
|
138
|
-
|
|
139
|
-
if (Resolver.isRefObjectType(referenceType)) {
|
|
140
|
-
const required = referenceType.properties.filter((p: Property) => p.required).map((p: Property) => p.name);
|
|
141
|
-
|
|
142
|
-
definitions[referenceType.refName] = {
|
|
143
|
-
description: referenceType.description,
|
|
144
|
-
properties: this.buildProperties(referenceType.properties),
|
|
145
|
-
required: required && required.length > 0 ? Array.from(new Set(required)) : undefined,
|
|
146
|
-
type: 'object',
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
if (referenceType.additionalProperties) {
|
|
150
|
-
definitions[referenceType.refName].additionalProperties = true;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (referenceType.example) {
|
|
154
|
-
// @ts-ignore
|
|
155
|
-
definitions[referenceType.refName].example = referenceType.example;
|
|
156
|
-
}
|
|
157
|
-
} else if (Resolver.isRefEnumType(referenceType)) {
|
|
158
|
-
|
|
159
|
-
definitions[referenceType.refName] = {
|
|
160
|
-
description: referenceType.description,
|
|
161
|
-
enum: referenceType.members,
|
|
162
|
-
type: this.decideEnumType(referenceType.members, referenceType.refName),
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
if (referenceType.memberNames !== undefined && referenceType.members.length === referenceType.memberNames.length) {
|
|
166
|
-
// @ts-ignore
|
|
167
|
-
definitions[referenceType.refName]['x-enum-varnames'] = referenceType.memberNames;
|
|
168
|
-
}
|
|
169
|
-
} else if (Resolver.isRefAliasType(referenceType)) {
|
|
170
|
-
const swaggerType = this.getSwaggerType(referenceType.type);
|
|
171
|
-
const format : Specification.DataFormat = referenceType.format as Specification.DataFormat;
|
|
172
|
-
const validators = Object.keys(referenceType.validators)
|
|
173
|
-
.filter(key => {
|
|
174
|
-
return !key.startsWith('is') && key !== 'minDate' && key !== 'maxDate';
|
|
175
|
-
})
|
|
176
|
-
.reduce((acc, key) => {
|
|
177
|
-
return {
|
|
178
|
-
...acc,
|
|
179
|
-
[key]: referenceType.validators[key].value,
|
|
180
|
-
};
|
|
181
|
-
}, {});
|
|
182
|
-
|
|
183
|
-
definitions[referenceType.refName] = {
|
|
184
|
-
...(swaggerType as SpecificationV2.Schema),
|
|
185
|
-
default: referenceType.default || swaggerType.default,
|
|
186
|
-
example: referenceType.example as {[p: string]: Specification.Example},
|
|
187
|
-
format: format || swaggerType.format,
|
|
188
|
-
description: referenceType.description,
|
|
189
|
-
...validators,
|
|
190
|
-
};
|
|
191
|
-
} else {
|
|
192
|
-
console.log(referenceType);
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
return definitions;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
private decideEnumType(anEnum: Array<string | number>, nameOfEnum: string): 'string' | 'number' {
|
|
200
|
-
const typesUsedInEnum = this.determineTypesUsedInEnum(anEnum);
|
|
201
|
-
|
|
202
|
-
const badEnumErrorMessage = () => {
|
|
203
|
-
const valuesDelimited = Array.from(typesUsedInEnum).join(',');
|
|
204
|
-
return `Enums can only have string or number values, but enum ${nameOfEnum} had ${valuesDelimited}`;
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
let enumTypeForSwagger: 'string' | 'number' = 'string';
|
|
208
|
-
if (typesUsedInEnum.has('string') && typesUsedInEnum.size === 1) {
|
|
209
|
-
enumTypeForSwagger = 'string';
|
|
210
|
-
} else if (typesUsedInEnum.has('number') && typesUsedInEnum.size === 1) {
|
|
211
|
-
enumTypeForSwagger = 'number';
|
|
212
|
-
} else if(typesUsedInEnum.size === 2 && typesUsedInEnum.has('number') && typesUsedInEnum.has('string')) {
|
|
213
|
-
enumTypeForSwagger = 'string';
|
|
214
|
-
} else {
|
|
215
|
-
throw new Error(badEnumErrorMessage());
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return enumTypeForSwagger;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/*
|
|
222
|
-
Path & Parameter ( + utils)
|
|
223
|
-
*/
|
|
224
|
-
|
|
225
|
-
private buildPaths() {
|
|
226
|
-
const paths: { [pathName: string]: Specification.Path<SpecificationV2.Operation, SpecificationV2.Response> } = {};
|
|
227
|
-
|
|
228
|
-
this.metadata.controllers.forEach(controller => {
|
|
229
|
-
controller.methods.forEach(method => {
|
|
230
|
-
let fullPath : string = posix.join('/', (controller.path ? controller.path : ''), method.path);
|
|
231
|
-
fullPath = normalizePathParameters(fullPath);
|
|
232
|
-
|
|
233
|
-
paths[fullPath] = paths[fullPath] || {};
|
|
234
|
-
method.consumes = union(controller.consumes, method.consumes);
|
|
235
|
-
method.produces = union(controller.produces, method.produces);
|
|
236
|
-
method.tags = union(controller.tags, method.tags);
|
|
237
|
-
method.security = method.security || controller.security;
|
|
238
|
-
method.responses = union(controller.responses, method.responses);
|
|
239
|
-
const pathObject: any = paths[fullPath];
|
|
240
|
-
pathObject[method.method] = this.buildPathMethod(controller.name, method);
|
|
241
|
-
});
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
return paths;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
private buildPathMethod(controllerName: string, method: Method) {
|
|
248
|
-
const pathMethod: any = this.buildOperation(method);
|
|
249
|
-
pathMethod.description = method.description;
|
|
250
|
-
if (method.summary) {
|
|
251
|
-
pathMethod.summary = method.summary;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (method.deprecated) { pathMethod.deprecated = method.deprecated; }
|
|
255
|
-
if (method.tags.length) { pathMethod.tags = method.tags; }
|
|
256
|
-
if (method.security) {
|
|
257
|
-
pathMethod.security = method.security.map(s => ({
|
|
258
|
-
[s.name]: s.scopes || []
|
|
259
|
-
}));
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
this.handleMethodConsumes(method, pathMethod);
|
|
263
|
-
|
|
264
|
-
pathMethod.parameters = method.parameters
|
|
265
|
-
.filter(p => (p.in !== 'param'))
|
|
266
|
-
.map(p => this.buildParameter(p));
|
|
267
|
-
|
|
268
|
-
method.parameters
|
|
269
|
-
.filter(p => (p.in === 'param'))
|
|
270
|
-
.forEach(p => {
|
|
271
|
-
pathMethod.parameters.push(this.buildParameter({
|
|
272
|
-
description: p.description,
|
|
273
|
-
in: 'query',
|
|
274
|
-
name: p.name,
|
|
275
|
-
parameterName: p.parameterName,
|
|
276
|
-
required: false,
|
|
277
|
-
type: p.type
|
|
278
|
-
}));
|
|
279
|
-
pathMethod.parameters.push(this.buildParameter({
|
|
280
|
-
description: p.description,
|
|
281
|
-
in: 'formData',
|
|
282
|
-
name: p.name,
|
|
283
|
-
parameterName: p.parameterName,
|
|
284
|
-
required: false,
|
|
285
|
-
type: p.type
|
|
286
|
-
}));
|
|
287
|
-
});
|
|
288
|
-
if (pathMethod.parameters.filter((p: Specification.BaseParameter<SpecificationV2.Schema>) => p.in === 'body').length > 1) {
|
|
289
|
-
throw new Error('Only one body parameter allowed per controller method.');
|
|
290
|
-
}
|
|
291
|
-
return pathMethod;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
private buildParameter(parameter: Parameter): Specification.Parameter<SpecificationV2.Schema> {
|
|
295
|
-
const swaggerParameter: any = {
|
|
296
|
-
description: parameter.description,
|
|
297
|
-
in: parameter.in,
|
|
298
|
-
name: parameter.name,
|
|
299
|
-
required: parameter.required
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
const parameterType = this.getSwaggerType(parameter.type);
|
|
303
|
-
if ((hasOwnProperty(parameterType, '$ref') && parameterType.$ref) || parameter.in === 'body') {
|
|
304
|
-
swaggerParameter.schema = parameterType;
|
|
305
|
-
} else {
|
|
306
|
-
swaggerParameter.type = parameterType.type;
|
|
307
|
-
|
|
308
|
-
if (parameterType.items) {
|
|
309
|
-
swaggerParameter.items = parameterType.items;
|
|
310
|
-
|
|
311
|
-
if (parameter.collectionFormat || this.config.collectionFormat) {
|
|
312
|
-
swaggerParameter.collectionFormat = parameter.collectionFormat || this.config.collectionFormat;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if (parameterType.format) { swaggerParameter.format = parameterType.format; }
|
|
318
|
-
|
|
319
|
-
if (parameter.default !== undefined) { swaggerParameter.default = parameter.default; }
|
|
320
|
-
|
|
321
|
-
if (parameterType.enum) { swaggerParameter.enum = parameterType.enum; }
|
|
322
|
-
|
|
323
|
-
return swaggerParameter;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
private handleMethodConsumes(method: Method, pathMethod: any) {
|
|
327
|
-
if (method.consumes.length) { pathMethod.consumes = method.consumes; }
|
|
328
|
-
|
|
329
|
-
if ((!pathMethod.consumes || !pathMethod.consumes.length)) {
|
|
330
|
-
if (method.parameters.some(p => (p.in === 'formData' && p.type.typeName === 'file'))) {
|
|
331
|
-
pathMethod.consumes = pathMethod.consumes || [];
|
|
332
|
-
pathMethod.consumes.push('multipart/form-data');
|
|
333
|
-
} else if (this.hasFormParams(method)) {
|
|
334
|
-
pathMethod.consumes = pathMethod.consumes || [];
|
|
335
|
-
pathMethod.consumes.push('application/x-www-form-urlencoded');
|
|
336
|
-
} else if (this.supportsBodyParameters(method.method)) {
|
|
337
|
-
pathMethod.consumes = pathMethod.consumes || [];
|
|
338
|
-
pathMethod.consumes.push('application/json');
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
private hasFormParams(method: Method) {
|
|
344
|
-
return method.parameters.find(p => (p.in === 'formData'));
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
private supportsBodyParameters(method: string) {
|
|
348
|
-
return ['post', 'put', 'patch'].some(m => m === method);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/*
|
|
352
|
-
Swagger Type ( + utils)
|
|
353
|
-
*/
|
|
354
|
-
|
|
355
|
-
protected getSwaggerTypeForEnumType(enumType: Resolver.EnumType) : SpecificationV2.Schema {
|
|
356
|
-
const types = this.determineTypesUsedInEnum(enumType.members);
|
|
357
|
-
|
|
358
|
-
if (types.size === 1) {
|
|
359
|
-
const type = types.values().next().value;
|
|
360
|
-
const nullable = !!enumType.members.includes(null);
|
|
361
|
-
return { type: type, enum: enumType.members.map((member: string | number | boolean | null) => (member === null ? null : String(member))), ['x-nullable']: nullable };
|
|
362
|
-
} else {
|
|
363
|
-
const valuesDelimited = Array.from(types).join(',');
|
|
364
|
-
throw new Error(`Enums can only have string or number values, but enum had ${valuesDelimited}`);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
protected getSwaggerTypeForIntersectionType(type: Resolver.IntersectionType) : SpecificationV2.Schema {
|
|
369
|
-
// tslint:disable-next-line:no-shadowed-variable
|
|
370
|
-
const properties = type.members.reduce((acc, type) => {
|
|
371
|
-
if (type.typeName === 'refObject') {
|
|
372
|
-
let refType = type;
|
|
373
|
-
refType = this.metadata.referenceTypes[refType.refName] as Resolver.RefObjectType;
|
|
374
|
-
|
|
375
|
-
const props =
|
|
376
|
-
refType &&
|
|
377
|
-
refType.properties &&
|
|
378
|
-
refType.properties.reduce((pAcc, prop) => {
|
|
379
|
-
return {
|
|
380
|
-
...pAcc,
|
|
381
|
-
[prop.name]: this.getSwaggerType(prop.type),
|
|
382
|
-
};
|
|
383
|
-
}, {});
|
|
384
|
-
return { ...acc, ...props };
|
|
385
|
-
} else {
|
|
386
|
-
return { ...acc };
|
|
387
|
-
}
|
|
388
|
-
}, {});
|
|
389
|
-
|
|
390
|
-
return { type: 'object', properties: properties };
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
protected getSwaggerTypeForReferenceType(referenceType: Resolver.ReferenceType): SpecificationV2.Schema {
|
|
394
|
-
return { $ref: `#/definitions/${referenceType.refName}` };
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
protected buildProperties(properties: Property[]) : Record<string, SpecificationV2.Schema> {
|
|
398
|
-
const swaggerProperties: { [propertyName: string]: SpecificationV2.Schema } = {};
|
|
399
|
-
|
|
400
|
-
properties.forEach(property => {
|
|
401
|
-
const swaggerType = this.getSwaggerType(property.type);
|
|
402
|
-
if (!hasOwnProperty(swaggerType, '$ref') || !swaggerType.$ref) {
|
|
403
|
-
swaggerType.description = property.description;
|
|
404
|
-
}
|
|
405
|
-
swaggerProperties[property.name] = swaggerType;
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
return swaggerProperties;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
private buildOperation(method: Method) {
|
|
412
|
-
const operation: any = {
|
|
413
|
-
operationId: this.getOperationId(method.name),
|
|
414
|
-
produces: [],
|
|
415
|
-
responses: {}
|
|
416
|
-
};
|
|
417
|
-
const methodReturnTypes = new Set<string>();
|
|
418
|
-
|
|
419
|
-
method.responses.forEach((res: Response) => {
|
|
420
|
-
operation.responses[res.status] = {
|
|
421
|
-
description: res.description
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
if (res.schema) {
|
|
425
|
-
const swaggerType = this.getSwaggerType(res.schema);
|
|
426
|
-
if (swaggerType.type !== 'void') {
|
|
427
|
-
operation.responses[res.status]['schema'] = swaggerType;
|
|
428
|
-
}
|
|
429
|
-
methodReturnTypes.add(this.getMimeType(swaggerType));
|
|
430
|
-
}
|
|
431
|
-
if (res.examples) {
|
|
432
|
-
operation.responses[res.status]['examples'] = { 'application/json': res.examples };
|
|
433
|
-
}
|
|
434
|
-
});
|
|
435
|
-
this.handleMethodProduces(method, operation, methodReturnTypes);
|
|
436
|
-
return operation;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
private getMimeType(swaggerType: SpecificationV2.Schema) {
|
|
440
|
-
if (
|
|
441
|
-
swaggerType.$ref ||
|
|
442
|
-
swaggerType.type === 'array' ||
|
|
443
|
-
swaggerType.type === 'object'
|
|
444
|
-
) {
|
|
445
|
-
return 'application/json';
|
|
446
|
-
} else if (
|
|
447
|
-
swaggerType.type === 'string' &&
|
|
448
|
-
swaggerType.format === 'binary'
|
|
449
|
-
) {
|
|
450
|
-
return 'application/octet-stream';
|
|
451
|
-
} else {
|
|
452
|
-
return 'text/html';
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
private handleMethodProduces(method: Method, operation: any, methodReturnTypes: Set<string>) {
|
|
457
|
-
if (method.produces.length) {
|
|
458
|
-
operation.produces = method.produces;
|
|
459
|
-
} else if (methodReturnTypes && methodReturnTypes.size > 0) {
|
|
460
|
-
operation.produces = Array.from(methodReturnTypes);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2021.
|
|
3
|
-
* Author Peter Placzek (tada5hi)
|
|
4
|
-
* For the full copyright and license information,
|
|
5
|
-
* view the LICENSE file that was distributed with this source code.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
Specification
|
|
10
|
-
} from "../type";
|
|
11
|
-
|
|
12
|
-
export namespace SpecificationV2 {
|
|
13
|
-
export interface Spec extends Specification.BaseSpec {
|
|
14
|
-
swagger: '2.0';
|
|
15
|
-
host?: string;
|
|
16
|
-
basePath?: string;
|
|
17
|
-
schemes?: string[];
|
|
18
|
-
consumes?: string[];
|
|
19
|
-
produces?: string[];
|
|
20
|
-
paths: { [pathName: string]: Specification.Path<Operation, Response> };
|
|
21
|
-
definitions?: { [definitionsName: string]: Schema };
|
|
22
|
-
parameters?: { [parameterName: string]: Schema | Specification.QueryParameter<Schema> };
|
|
23
|
-
responses?: { [responseName: string]: Response };
|
|
24
|
-
security?: Security[];
|
|
25
|
-
securityDefinitions?: { [name: string]: Security };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export type Parameter = Omit<Specification.Parameter<Schema> & {'x-deprecated'?: boolean }, 'deprecated'>;
|
|
29
|
-
|
|
30
|
-
export interface Operation extends Specification.BaseOperation<Parameter, Response, Security> {
|
|
31
|
-
produces?: [string];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface Response extends Specification.BaseResponse{
|
|
35
|
-
schema?: Schema;
|
|
36
|
-
headers?: { [headerName: string]: Header };
|
|
37
|
-
examples?: { [exampleName: string]: Specification.Example };
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface Header {
|
|
41
|
-
type: 'string' | 'number' | 'integer' | 'boolean' | 'array';
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// tslint:disable-next-line:no-shadowed-variable
|
|
45
|
-
export interface Schema extends Specification.BaseSchema<Schema> {
|
|
46
|
-
['x-nullable']?: boolean;
|
|
47
|
-
['x-deprecated']?: boolean;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface BasicSecurity extends Specification.BaseSecurity {
|
|
51
|
-
type: 'basic';
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface BaseOAuthSecurity extends Specification.BaseSecurity {
|
|
55
|
-
type: 'oauth2';
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface OAuth2ImplicitSecurity extends BaseOAuthSecurity {
|
|
59
|
-
flow: 'implicit';
|
|
60
|
-
authorizationUrl: string;
|
|
61
|
-
scopes?: Record<string, string>;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export interface OAuth2PasswordSecurity extends BaseOAuthSecurity {
|
|
65
|
-
flow: 'password';
|
|
66
|
-
tokenUrl: string;
|
|
67
|
-
scopes?: Record<string, string>;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export interface OAuth2ApplicationSecurity extends BaseOAuthSecurity {
|
|
71
|
-
flow: 'application';
|
|
72
|
-
tokenUrl: string;
|
|
73
|
-
scopes?: Record<string, string>;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface OAuth2AccessCodeSecurity extends BaseOAuthSecurity {
|
|
77
|
-
flow: 'accessCode';
|
|
78
|
-
tokenUrl: string;
|
|
79
|
-
authorizationUrl: string;
|
|
80
|
-
scopes?: Record<string, string>;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export type OAuth2Security = OAuth2AccessCodeSecurity |
|
|
84
|
-
OAuth2ApplicationSecurity |
|
|
85
|
-
OAuth2ImplicitSecurity |
|
|
86
|
-
OAuth2PasswordSecurity;
|
|
87
|
-
|
|
88
|
-
export type Security =
|
|
89
|
-
BasicSecurity |
|
|
90
|
-
OAuth2Security |
|
|
91
|
-
Specification.ApiKeySecurity;
|
|
92
|
-
}
|