swagger-typescript-api 13.0.9 → 13.0.10

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 (65) hide show
  1. package/dist/chunk-3S356DIU.cjs +105 -0
  2. package/dist/chunk-3S356DIU.cjs.map +1 -0
  3. package/dist/chunk-MTWJNW6B.js +65 -0
  4. package/dist/chunk-MTWJNW6B.js.map +1 -0
  5. package/dist/cli.cjs +43 -0
  6. package/dist/cli.cjs.map +1 -0
  7. package/dist/cli.js +36 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/lib.cjs +21 -0
  10. package/dist/lib.cjs.map +1 -0
  11. package/dist/lib.js +4 -0
  12. package/dist/lib.js.map +1 -0
  13. package/package.json +25 -14
  14. package/cli/constants.js +0 -6
  15. package/cli/execute.js +0 -180
  16. package/cli/index.js +0 -94
  17. package/cli/operations/display-help.js +0 -177
  18. package/cli/operations/display-version.js +0 -5
  19. package/cli/parse-args.js +0 -24
  20. package/cli/process-option.js +0 -75
  21. package/index.js +0 -344
  22. package/src/code-formatter.js +0 -114
  23. package/src/code-gen-process.js +0 -569
  24. package/src/commands/generate-templates/configuration.js +0 -31
  25. package/src/commands/generate-templates/index.js +0 -10
  26. package/src/commands/generate-templates/templates-gen-process.js +0 -205
  27. package/src/component-type-name-resolver.js +0 -42
  28. package/src/configuration.js +0 -445
  29. package/src/constants.js +0 -77
  30. package/src/index.js +0 -16
  31. package/src/schema-components-map.js +0 -76
  32. package/src/schema-parser/base-schema-parsers/array.js +0 -41
  33. package/src/schema-parser/base-schema-parsers/complex.js +0 -49
  34. package/src/schema-parser/base-schema-parsers/discriminator.js +0 -305
  35. package/src/schema-parser/base-schema-parsers/enum.js +0 -156
  36. package/src/schema-parser/base-schema-parsers/object.js +0 -103
  37. package/src/schema-parser/base-schema-parsers/primitive.js +0 -61
  38. package/src/schema-parser/complex-schema-parsers/all-of.js +0 -26
  39. package/src/schema-parser/complex-schema-parsers/any-of.js +0 -27
  40. package/src/schema-parser/complex-schema-parsers/not.js +0 -9
  41. package/src/schema-parser/complex-schema-parsers/one-of.js +0 -27
  42. package/src/schema-parser/mono-schema-parser.js +0 -46
  43. package/src/schema-parser/schema-formatters.js +0 -164
  44. package/src/schema-parser/schema-parser-fabric.js +0 -130
  45. package/src/schema-parser/schema-parser.js +0 -295
  46. package/src/schema-parser/schema-utils.js +0 -319
  47. package/src/schema-parser/util/enum-key-resolver.js +0 -24
  48. package/src/schema-routes/schema-routes.js +0 -1208
  49. package/src/schema-routes/util/specific-arg-name-resolver.js +0 -24
  50. package/src/schema-walker.js +0 -91
  51. package/src/swagger-schema-resolver.js +0 -195
  52. package/src/templates-worker.js +0 -243
  53. package/src/translators/javascript.js +0 -81
  54. package/src/translators/translator.js +0 -33
  55. package/src/type-name-formatter.js +0 -111
  56. package/src/util/file-system.js +0 -95
  57. package/src/util/id.js +0 -7
  58. package/src/util/internal-case.js +0 -7
  59. package/src/util/logger.js +0 -142
  60. package/src/util/name-resolver.js +0 -103
  61. package/src/util/object-assign.js +0 -17
  62. package/src/util/pascal-case.js +0 -7
  63. package/src/util/random.js +0 -11
  64. package/src/util/request.js +0 -63
  65. package/src/util/sort-by-property.js +0 -15
@@ -1,1208 +0,0 @@
1
- import _ from "lodash";
2
- import {
3
- DEFAULT_BODY_ARG_NAME,
4
- RESERVED_BODY_ARG_NAMES,
5
- RESERVED_HEADER_ARG_NAMES,
6
- RESERVED_PATH_ARG_NAMES,
7
- RESERVED_QUERY_ARG_NAMES,
8
- } from "../constants.js";
9
- import { generateId } from "../util/id.js";
10
- import { SpecificArgNameResolver } from "./util/specific-arg-name-resolver.js";
11
-
12
- const CONTENT_KIND = {
13
- JSON: "JSON",
14
- URL_ENCODED: "URL_ENCODED",
15
- FORM_DATA: "FORM_DATA",
16
- IMAGE: "IMAGE",
17
- OTHER: "OTHER",
18
- TEXT: "TEXT",
19
- };
20
-
21
- class SchemaRoutes {
22
- /**
23
- * @type {CodeGenConfig}
24
- */
25
- config;
26
- /**
27
- * @type {SchemaParserFabric}
28
- */
29
- schemaParserFabric;
30
- /**
31
- * @type {SchemaUtils}
32
- */
33
- schemaUtils;
34
- /**
35
- * @type {TypeNameFormatter}
36
- */
37
- typeNameFormatter;
38
- /**
39
- * @type {SchemaComponentsMap}
40
- */
41
- schemaComponentsMap;
42
- /**
43
- * @type {Logger}
44
- */
45
- logger;
46
- /**
47
- * @type {TemplatesWorker}
48
- */
49
- templatesWorker;
50
-
51
- FORM_DATA_TYPES = [];
52
-
53
- routes = [];
54
- hasSecurityRoutes = false;
55
- hasQueryRoutes = false;
56
- hasFormDataRoutes = false;
57
-
58
- constructor({
59
- config,
60
- schemaParserFabric,
61
- schemaComponentsMap,
62
- logger,
63
- templatesWorker,
64
- typeNameFormatter,
65
- }) {
66
- this.config = config;
67
- this.schemaParserFabric = schemaParserFabric;
68
- this.schemaUtils = this.schemaParserFabric.schemaUtils;
69
- this.typeNameFormatter = typeNameFormatter;
70
- this.schemaComponentsMap = schemaComponentsMap;
71
- this.logger = logger;
72
- this.templatesWorker = templatesWorker;
73
-
74
- this.FORM_DATA_TYPES = _.uniq([
75
- this.schemaUtils.getSchemaType({ type: "string", format: "file" }),
76
- this.schemaUtils.getSchemaType({ type: "string", format: "binary" }),
77
- ]);
78
- }
79
-
80
- createRequestsMap = (routeInfoByMethodsMap) => {
81
- const parameters = _.get(routeInfoByMethodsMap, "parameters");
82
-
83
- return _.reduce(
84
- routeInfoByMethodsMap,
85
- (acc, requestInfo, method) => {
86
- if (
87
- _.startsWith(method, "x-") ||
88
- ["parameters", "$ref"].includes(method)
89
- ) {
90
- return acc;
91
- }
92
-
93
- acc[method] = {
94
- ...requestInfo,
95
- parameters: _.compact(_.concat(parameters, requestInfo.parameters)),
96
- };
97
-
98
- return acc;
99
- },
100
- {},
101
- );
102
- };
103
-
104
- parseRouteName = (originalRouteName) => {
105
- const routeName =
106
- this.config.hooks.onPreBuildRoutePath(originalRouteName) ||
107
- originalRouteName;
108
-
109
- const pathParamMatches = (routeName || "").match(
110
- /({(([A-z]){1}([a-zA-Z0-9]-?_?\.?)+)([0-9]+)?})|(:(([A-z]){1}([a-zA-Z0-9]-?_?\.?)+)([0-9]+)?:?)/g,
111
- );
112
-
113
- // used in case when path parameters is not declared in requestInfo.parameters ("in": "path")
114
- const pathParams = _.reduce(
115
- pathParamMatches,
116
- (pathParams, match) => {
117
- const paramName = _.replace(match, /\{|\}|:/g, "");
118
-
119
- if (!paramName) return pathParams;
120
-
121
- if (_.includes(paramName, "-")) {
122
- this.logger.warn("wrong path param name", paramName);
123
- }
124
-
125
- pathParams.push({
126
- $match: match,
127
- name: _.camelCase(paramName),
128
- required: true,
129
- type: "string",
130
- description: "",
131
- schema: {
132
- type: "string",
133
- },
134
- in: "path",
135
- });
136
-
137
- return pathParams;
138
- },
139
- [],
140
- );
141
-
142
- let fixedRoute = _.reduce(
143
- pathParams,
144
- (fixedRoute, pathParam, i, arr) => {
145
- const insertion =
146
- this.config.hooks.onInsertPathParam(
147
- pathParam.name,
148
- i,
149
- arr,
150
- fixedRoute,
151
- ) || pathParam.name;
152
- return _.replace(fixedRoute, pathParam.$match, `\${${insertion}}`);
153
- },
154
- routeName || "",
155
- );
156
-
157
- const queryParamMatches = fixedRoute.match(/(\{\?.*\})/g);
158
- const queryParams = [];
159
-
160
- if (queryParamMatches?.length) {
161
- queryParamMatches.forEach((match) => {
162
- fixedRoute = fixedRoute.replace(match, "");
163
- });
164
-
165
- _.uniq(
166
- queryParamMatches
167
- .join(",")
168
- .replace(/(\{\?)|(\})|\s/g, "")
169
- .split(","),
170
- ).forEach((paramName) => {
171
- if (_.includes(paramName, "-")) {
172
- this.logger.warn("wrong query param name", paramName);
173
- }
174
-
175
- queryParams.push({
176
- $match: paramName,
177
- name: _.camelCase(paramName),
178
- required: true,
179
- type: "string",
180
- description: "",
181
- schema: {
182
- type: "string",
183
- },
184
- in: "query",
185
- });
186
- });
187
- }
188
-
189
- const result = {
190
- originalRoute: originalRouteName || "",
191
- route: fixedRoute,
192
- pathParams,
193
- queryParams,
194
- };
195
-
196
- return this.config.hooks.onBuildRoutePath(result) || result;
197
- };
198
-
199
- getRouteParams = (
200
- routeInfo,
201
- pathParamsFromRouteName,
202
- queryParamsFromRouteName,
203
- ) => {
204
- const { parameters } = routeInfo;
205
-
206
- const routeParams = {
207
- path: [],
208
- header: [],
209
- body: [],
210
- query: [],
211
- formData: [],
212
- cookie: [],
213
- };
214
-
215
- _.each(parameters, (parameter) => {
216
- const refTypeInfo =
217
- this.schemaParserFabric.schemaUtils.getSchemaRefType(parameter);
218
- let routeParam = null;
219
-
220
- if (refTypeInfo?.rawTypeData.in && refTypeInfo.rawTypeData) {
221
- if (!routeParams[refTypeInfo.rawTypeData.in]) {
222
- routeParams[refTypeInfo.rawTypeData.in] = [];
223
- }
224
-
225
- routeParam = {
226
- ...refTypeInfo.rawTypeData,
227
- ...(refTypeInfo.rawTypeData.schema || {}),
228
- };
229
- } else {
230
- if (!parameter.in) return;
231
-
232
- if (!routeParams[parameter.in]) {
233
- routeParams[parameter.in] = [];
234
- }
235
-
236
- routeParam = {
237
- ...parameter,
238
- ...(parameter.schema || {}),
239
- };
240
- }
241
-
242
- if (routeParam.in === "path") {
243
- if (!routeParam.name) return;
244
-
245
- routeParam.name = _.camelCase(routeParam.name);
246
- }
247
-
248
- if (routeParam) {
249
- routeParams[routeParam.in].push(routeParam);
250
- }
251
- });
252
-
253
- // used in case when path parameters is not declared in requestInfo.parameters ("in": "path")
254
- _.each(pathParamsFromRouteName, (pathParam) => {
255
- const alreadyExist = _.some(
256
- routeParams.path,
257
- (parameter) => parameter.name === pathParam.name,
258
- );
259
-
260
- if (!alreadyExist) {
261
- routeParams.path.push(pathParam);
262
- }
263
- });
264
- // used in case when path parameters is not declared in requestInfo.parameters ("in": "path")
265
- _.each(queryParamsFromRouteName, (queryParam) => {
266
- const alreadyExist = _.some(
267
- routeParams.query,
268
- (parameter) => parameter.name === queryParam.name,
269
- );
270
-
271
- if (!alreadyExist) {
272
- routeParams.query.push(queryParam);
273
- }
274
- });
275
-
276
- return routeParams;
277
- };
278
-
279
- getContentTypes = (requestInfo, extraContentTypes) =>
280
- _.uniq(
281
- _.compact([
282
- ...(extraContentTypes || []),
283
- ..._.flatten(
284
- _.map(
285
- requestInfo,
286
- (requestInfoData) =>
287
- requestInfoData && _.keys(requestInfoData.content),
288
- ),
289
- ),
290
- ]),
291
- );
292
-
293
- getContentKind = (contentTypes) => {
294
- if (
295
- _.some(contentTypes, (contentType) =>
296
- _.startsWith(contentType, "application/json"),
297
- ) ||
298
- _.some(contentTypes, (contentType) => _.endsWith(contentType, "+json"))
299
- ) {
300
- return CONTENT_KIND.JSON;
301
- }
302
-
303
- if (contentTypes.includes("application/x-www-form-urlencoded")) {
304
- return CONTENT_KIND.URL_ENCODED;
305
- }
306
-
307
- if (contentTypes.includes("multipart/form-data")) {
308
- return CONTENT_KIND.FORM_DATA;
309
- }
310
-
311
- if (
312
- _.some(contentTypes, (contentType) => _.includes(contentType, "image/"))
313
- ) {
314
- return CONTENT_KIND.IMAGE;
315
- }
316
-
317
- if (
318
- _.some(contentTypes, (contentType) => _.startsWith(contentType, "text/"))
319
- ) {
320
- return CONTENT_KIND.TEXT;
321
- }
322
-
323
- return CONTENT_KIND.OTHER;
324
- };
325
-
326
- isSuccessStatus = (status) =>
327
- (this.config.defaultResponseAsSuccess && status === "default") ||
328
- (+status >= this.config.successResponseStatusRange[0] &&
329
- +status <= this.config.successResponseStatusRange[1]) ||
330
- status === "2xx";
331
-
332
- getSchemaFromRequestType = (requestInfo) => {
333
- const content = _.get(requestInfo, "content");
334
-
335
- if (!content) return null;
336
-
337
- /* content: { "multipart/form-data": { schema: {...} }, "application/json": { schema: {...} } } */
338
-
339
- /* for example: dataType = "multipart/form-data" */
340
- for (const dataType in content) {
341
- if (content[dataType]?.schema) {
342
- return {
343
- ...content[dataType].schema,
344
- dataType,
345
- };
346
- }
347
- }
348
-
349
- return null;
350
- };
351
-
352
- getTypeFromRequestInfo = ({
353
- requestInfo,
354
- parsedSchemas,
355
- operationId,
356
- defaultType,
357
- typeName,
358
- }) => {
359
- // TODO: make more flexible pick schema without content type
360
- const schema = this.getSchemaFromRequestType(requestInfo);
361
- const refTypeInfo =
362
- this.schemaParserFabric.schemaUtils.getSchemaRefType(requestInfo);
363
-
364
- if (schema) {
365
- const content = this.schemaParserFabric.getInlineParseContent(
366
- schema,
367
- typeName,
368
- [operationId],
369
- );
370
- const foundedSchemaByName = _.find(
371
- parsedSchemas,
372
- (parsedSchema) =>
373
- this.typeNameFormatter.format(parsedSchema.name) === content,
374
- );
375
- const foundSchemaByContent = _.find(parsedSchemas, (parsedSchema) =>
376
- _.isEqual(parsedSchema.content, content),
377
- );
378
-
379
- const foundSchema = foundedSchemaByName || foundSchemaByContent;
380
-
381
- return foundSchema
382
- ? this.typeNameFormatter.format(foundSchema.name)
383
- : content;
384
- }
385
-
386
- if (refTypeInfo) {
387
- // const refTypeWithoutOpId = refType.replace(operationId, '');
388
- // const foundedSchemaByName = _.find(parsedSchemas, ({ name }) => name === refType || name === refTypeWithoutOpId)
389
-
390
- // TODO:HACK fix problem of swagger2opeanpi
391
- const typeNameWithoutOpId = _.replace(
392
- refTypeInfo.typeName,
393
- operationId,
394
- "",
395
- );
396
- if (
397
- _.find(parsedSchemas, (schema) => schema.name === typeNameWithoutOpId)
398
- ) {
399
- return this.typeNameFormatter.format(typeNameWithoutOpId);
400
- }
401
-
402
- switch (refTypeInfo.componentName) {
403
- case "schemas":
404
- return this.typeNameFormatter.format(refTypeInfo.typeName);
405
- case "responses":
406
- case "requestBodies":
407
- return this.schemaParserFabric.getInlineParseContent(
408
- this.getSchemaFromRequestType(refTypeInfo.rawTypeData),
409
- refTypeInfo.typeName || null,
410
- [operationId],
411
- );
412
- default:
413
- return this.schemaParserFabric.getInlineParseContent(
414
- refTypeInfo.rawTypeData,
415
- refTypeInfo.typeName || null,
416
- [operationId],
417
- );
418
- }
419
- }
420
-
421
- return defaultType || this.config.Ts.Keyword.Any;
422
- };
423
-
424
- getRequestInfoTypes = ({
425
- requestInfos,
426
- parsedSchemas,
427
- operationId,
428
- defaultType,
429
- }) =>
430
- _.reduce(
431
- requestInfos,
432
- (acc, requestInfo, status) => {
433
- const contentTypes = this.getContentTypes([requestInfo]);
434
-
435
- return [
436
- ...acc,
437
- {
438
- ...(requestInfo || {}),
439
- contentTypes: contentTypes,
440
- contentKind: this.getContentKind(contentTypes),
441
- type: this.schemaParserFabric.schemaUtils.safeAddNullToType(
442
- requestInfo,
443
- this.getTypeFromRequestInfo({
444
- requestInfo,
445
- parsedSchemas,
446
- operationId,
447
- defaultType,
448
- }),
449
- ),
450
- description:
451
- this.schemaParserFabric.schemaFormatters.formatDescription(
452
- requestInfo.description || "",
453
- true,
454
- ),
455
- status: _.isNaN(+status) ? status : +status,
456
- isSuccess: this.isSuccessStatus(status),
457
- },
458
- ];
459
- },
460
- [],
461
- );
462
-
463
- getResponseBodyInfo = (routeInfo, parsedSchemas) => {
464
- const { produces, operationId, responses } = routeInfo;
465
-
466
- const contentTypes = this.getContentTypes(responses, [
467
- ...(produces || []),
468
- routeInfo["x-accepts"],
469
- ]);
470
-
471
- const responseInfos = this.getRequestInfoTypes({
472
- requestInfos: responses,
473
- parsedSchemas,
474
- operationId,
475
- defaultType: this.config.defaultResponseType,
476
- });
477
-
478
- const successResponse = responseInfos.find(
479
- (response) => response.isSuccess,
480
- );
481
- const errorResponses = responseInfos.filter(
482
- (response) =>
483
- !response.isSuccess && response.type !== this.config.Ts.Keyword.Any,
484
- );
485
-
486
- const handleResponseHeaders = (src) => {
487
- if (!src) {
488
- return "headers: {},";
489
- }
490
- const headerTypes = Object.fromEntries(
491
- Object.entries(src).map(([k, v]) => {
492
- return [k, this.schemaUtils.getSchemaType(v)];
493
- }),
494
- );
495
- const r = `headers: { ${Object.entries(headerTypes)
496
- .map(([k, v]) => `"${k}": ${v}`)
497
- .join(",")} },`;
498
- return r;
499
- };
500
-
501
- return {
502
- contentTypes,
503
- responses: responseInfos,
504
- success: {
505
- schema: successResponse,
506
- type: successResponse?.type || this.config.Ts.Keyword.Any,
507
- },
508
- error: {
509
- schemas: errorResponses,
510
- type:
511
- this.config.Ts.UnionType(
512
- errorResponses.map((response) => response.type),
513
- ) || this.config.Ts.Keyword.Any,
514
- },
515
- full: {
516
- types:
517
- this.config.Ts.UnionType(
518
- responseInfos.map(
519
- (response) => `{
520
- data: ${response.type}, status: ${response.status}, statusCode: ${
521
- response.status
522
- }, statusText: "${response.description}", ${handleResponseHeaders(
523
- response.headers,
524
- )} config: {} }`,
525
- ),
526
- ) || this.config.Ts.Keyword.Any,
527
- },
528
- };
529
- };
530
-
531
- convertRouteParamsIntoObject = (params) => {
532
- return _.reduce(
533
- params,
534
- (objectSchema, schemaPart) => {
535
- if (!schemaPart || !schemaPart.name) return objectSchema;
536
-
537
- let usageName = `${schemaPart.name}`;
538
-
539
- if (usageName.includes(".")) {
540
- usageName = _.camelCase(usageName);
541
- }
542
-
543
- return {
544
- ...objectSchema,
545
- properties: {
546
- ...objectSchema.properties,
547
- [usageName]: {
548
- ...schemaPart,
549
- ...(schemaPart.schema || {}),
550
- $origName: schemaPart.name,
551
- name: usageName,
552
- },
553
- },
554
- };
555
- },
556
- {
557
- properties: {},
558
- type: "object",
559
- },
560
- );
561
- };
562
-
563
- getRequestBodyInfo = (routeInfo, routeParams, parsedSchemas, routeName) => {
564
- const { requestBody, consumes, requestBodyName, operationId } = routeInfo;
565
- let schema = null;
566
- let content = null;
567
-
568
- const contentTypes = this.getContentTypes(
569
- [requestBody],
570
- [...(consumes || []), routeInfo["x-contentType"]],
571
- );
572
- let contentKind = this.getContentKind(contentTypes);
573
-
574
- let typeName = null;
575
-
576
- if (this.config.extractRequestBody) {
577
- typeName = this.schemaUtils.resolveTypeName(routeName.usage, {
578
- suffixes: this.config.extractingOptions.requestBodySuffix,
579
- resolver: this.config.extractingOptions.requestBodyNameResolver,
580
- });
581
- }
582
-
583
- if (routeParams.formData.length) {
584
- contentKind = CONTENT_KIND.FORM_DATA;
585
- schema = this.convertRouteParamsIntoObject(routeParams.formData);
586
- content = this.schemaParserFabric.getInlineParseContent(
587
- schema,
588
- typeName,
589
- [operationId],
590
- );
591
- } else if (contentKind === CONTENT_KIND.FORM_DATA) {
592
- schema = this.getSchemaFromRequestType(requestBody);
593
- content = this.schemaParserFabric.getInlineParseContent(
594
- schema,
595
- typeName,
596
- [operationId],
597
- );
598
- } else if (requestBody) {
599
- schema = this.getSchemaFromRequestType(requestBody);
600
- content = this.schemaParserFabric.schemaUtils.safeAddNullToType(
601
- requestBody,
602
- this.getTypeFromRequestInfo({
603
- requestInfo: requestBody,
604
- parsedSchemas,
605
- operationId,
606
- typeName,
607
- }),
608
- );
609
-
610
- // TODO: Refactor that.
611
- // It needed for cases when swagger schema is not declared request body type as form data
612
- // but request body data type contains form data types like File
613
- if (
614
- this.FORM_DATA_TYPES.some((dataType) =>
615
- _.includes(content, `: ${dataType}`),
616
- )
617
- ) {
618
- contentKind = CONTENT_KIND.FORM_DATA;
619
- }
620
- }
621
-
622
- if (schema && !schema.$ref && this.config.extractRequestBody) {
623
- schema = this.schemaParserFabric.createParsedComponent({
624
- schema,
625
- typeName,
626
- schemaPath: [operationId],
627
- });
628
- content = this.schemaParserFabric.getInlineParseContent({
629
- $ref: schema.$ref,
630
- });
631
- }
632
-
633
- return {
634
- paramName: requestBodyName || requestBody?.name || DEFAULT_BODY_ARG_NAME,
635
- contentTypes,
636
- contentKind,
637
- schema,
638
- type: content,
639
- required:
640
- requestBody &&
641
- (typeof requestBody.required === "undefined" || !!requestBody.required),
642
- };
643
- };
644
-
645
- createRequestParamsSchema = ({
646
- queryParams,
647
- queryObjectSchema,
648
- pathArgsSchemas,
649
- extractRequestParams,
650
- routeName,
651
- }) => {
652
- if (!queryParams || !queryParams.length) return null;
653
-
654
- const pathParams = _.reduce(
655
- pathArgsSchemas,
656
- (acc, pathArgSchema) => {
657
- if (pathArgSchema.name) {
658
- acc[pathArgSchema.name] = {
659
- ...pathArgSchema,
660
- in: "path",
661
- };
662
- }
663
-
664
- return acc;
665
- },
666
- {},
667
- );
668
-
669
- const fixedQueryParams = _.reduce(
670
- _.get(queryObjectSchema, "properties", {}),
671
- (acc, property, name) => {
672
- if (name && _.isObject(property)) {
673
- acc[name] = {
674
- ...property,
675
- in: "query",
676
- };
677
- }
678
-
679
- return acc;
680
- },
681
- {},
682
- );
683
-
684
- const schema = {
685
- ...queryObjectSchema,
686
- properties: {
687
- ...fixedQueryParams,
688
- ...pathParams,
689
- },
690
- };
691
-
692
- const fixedSchema = this.config.hooks.onCreateRequestParams(schema);
693
-
694
- if (fixedSchema) return fixedSchema;
695
-
696
- if (extractRequestParams) {
697
- const generatedTypeName = this.schemaUtils.resolveTypeName(
698
- routeName.usage,
699
- {
700
- suffixes: this.config.extractingOptions.requestParamsSuffix,
701
- resolver: this.config.extractingOptions.requestParamsNameResolver,
702
- },
703
- );
704
-
705
- return this.schemaParserFabric.createParsedComponent({
706
- typeName: generatedTypeName,
707
- schema: schema,
708
- });
709
- }
710
-
711
- return schema;
712
- };
713
-
714
- extractResponseBodyIfItNeeded = (routeInfo, responseBodyInfo, routeName) => {
715
- if (
716
- responseBodyInfo.responses.length &&
717
- responseBodyInfo.success &&
718
- responseBodyInfo.success.schema
719
- ) {
720
- const typeName = this.schemaUtils.resolveTypeName(routeName.usage, {
721
- suffixes: this.config.extractingOptions.responseBodySuffix,
722
- resolver: this.config.extractingOptions.responseBodyNameResolver,
723
- });
724
-
725
- const idx = responseBodyInfo.responses.indexOf(
726
- responseBodyInfo.success.schema,
727
- );
728
-
729
- let successResponse = responseBodyInfo.success;
730
-
731
- if (successResponse.schema && !successResponse.schema.$ref) {
732
- const schema = this.getSchemaFromRequestType(successResponse.schema);
733
- successResponse.schema = this.schemaParserFabric.createParsedComponent({
734
- schema,
735
- typeName,
736
- schemaPath: [routeInfo.operationId],
737
- });
738
- successResponse.type = this.schemaParserFabric.getInlineParseContent({
739
- $ref: successResponse.schema.$ref,
740
- });
741
-
742
- if (idx > -1) {
743
- _.assign(responseBodyInfo.responses[idx], {
744
- ...successResponse.schema,
745
- type: successResponse.type,
746
- });
747
- }
748
- }
749
- }
750
- };
751
-
752
- extractResponseErrorIfItNeeded = (routeInfo, responseBodyInfo, routeName) => {
753
- if (
754
- responseBodyInfo.responses.length &&
755
- responseBodyInfo.error.schemas &&
756
- responseBodyInfo.error.schemas.length
757
- ) {
758
- const typeName = this.schemaUtils.resolveTypeName(routeName.usage, {
759
- suffixes: this.config.extractingOptions.responseErrorSuffix,
760
- resolver: this.config.extractingOptions.responseErrorNameResolver,
761
- });
762
-
763
- const errorSchemas = responseBodyInfo.error.schemas
764
- .map(this.getSchemaFromRequestType)
765
- .filter(Boolean);
766
-
767
- if (!errorSchemas.length) return;
768
-
769
- const schema = this.schemaParserFabric.parseSchema(
770
- {
771
- oneOf: errorSchemas,
772
- title: errorSchemas
773
- .map((schema) => schema.title)
774
- .filter(Boolean)
775
- .join(" "),
776
- description: errorSchemas
777
- .map((schema) => schema.description)
778
- .filter(Boolean)
779
- .join("\n"),
780
- },
781
- null,
782
- [routeInfo.operationId],
783
- );
784
- const component = this.schemaComponentsMap.createComponent(
785
- this.schemaComponentsMap.createRef(["components", "schemas", typeName]),
786
- { ...schema },
787
- );
788
- responseBodyInfo.error.schemas = [component];
789
- responseBodyInfo.error.type = this.typeNameFormatter.format(
790
- component.typeName,
791
- );
792
- }
793
- };
794
-
795
- getRouteName = (rawRouteInfo) => {
796
- const { moduleName } = rawRouteInfo;
797
- const { routeNameDuplicatesMap, templatesToRender } = this.config;
798
- const routeNameTemplate = templatesToRender.routeName;
799
-
800
- const routeNameFromTemplate = this.templatesWorker.renderTemplate(
801
- routeNameTemplate,
802
- {
803
- routeInfo: rawRouteInfo,
804
- },
805
- );
806
-
807
- const routeName =
808
- this.config.hooks.onFormatRouteName(
809
- rawRouteInfo,
810
- routeNameFromTemplate,
811
- ) || routeNameFromTemplate;
812
-
813
- const duplicateIdentifier = `${moduleName}|${routeName}`;
814
-
815
- if (routeNameDuplicatesMap.has(duplicateIdentifier)) {
816
- routeNameDuplicatesMap.set(
817
- duplicateIdentifier,
818
- routeNameDuplicatesMap.get(duplicateIdentifier) + 1,
819
- );
820
-
821
- this.logger.warn(
822
- `Module "${moduleName}" already has method "${routeName}()"`,
823
- `\nThis method has been renamed to "${
824
- routeName + routeNameDuplicatesMap.get(duplicateIdentifier)
825
- }()" to solve conflict names.`,
826
- );
827
- } else {
828
- routeNameDuplicatesMap.set(duplicateIdentifier, 1);
829
- }
830
-
831
- const duplicates = routeNameDuplicatesMap.get(duplicateIdentifier);
832
-
833
- const routeNameInfo = {
834
- usage: routeName + (duplicates > 1 ? duplicates : ""),
835
- original: routeName,
836
- duplicate: duplicates > 1,
837
- };
838
-
839
- return (
840
- this.config.hooks.onCreateRouteName(routeNameInfo, rawRouteInfo) ||
841
- routeNameInfo
842
- );
843
- };
844
-
845
- parseRouteInfo = (
846
- rawRouteName,
847
- routeInfo,
848
- method,
849
- usageSchema,
850
- parsedSchemas,
851
- ) => {
852
- const { security: globalSecurity } = usageSchema;
853
- const { moduleNameIndex, moduleNameFirstTag, extractRequestParams } =
854
- this.config;
855
- const {
856
- operationId,
857
- requestBody,
858
- security,
859
- // eslint-disable-next-line no-unused-vars
860
- parameters,
861
- summary,
862
- description,
863
- tags,
864
- responses,
865
- // eslint-disable-next-line no-unused-vars
866
- requestBodyName,
867
- produces,
868
- consumes,
869
- ...otherInfo
870
- } = routeInfo;
871
- const {
872
- route,
873
- pathParams: pathParamsFromRouteName,
874
- queryParams: queryParamsFromRouteName,
875
- } = this.parseRouteName(rawRouteName);
876
-
877
- const routeId = generateId();
878
- const firstTag = tags && tags.length > 0 ? tags[0] : null;
879
- const moduleName =
880
- moduleNameFirstTag && firstTag
881
- ? _.camelCase(firstTag)
882
- : _.camelCase(_.compact(_.split(route, "/"))[moduleNameIndex]);
883
- let hasSecurity = !!globalSecurity?.length;
884
- if (security) {
885
- hasSecurity = security.length > 0;
886
- }
887
-
888
- const routeParams = this.getRouteParams(
889
- routeInfo,
890
- pathParamsFromRouteName,
891
- queryParamsFromRouteName,
892
- );
893
-
894
- const pathArgs = routeParams.path.map((pathArgSchema) => ({
895
- name: pathArgSchema.name,
896
- optional: !pathArgSchema.required,
897
- // mark it as any for now, because "getInlineParseContent" breaks type names of extracted enums
898
- type: this.config.Ts.Keyword.Any,
899
- description: pathArgSchema.description,
900
- }));
901
- const pathArgsNames = pathArgs.map((arg) => arg.name);
902
-
903
- const responseBodyInfo = this.getResponseBodyInfo(routeInfo, parsedSchemas);
904
-
905
- const rawRouteInfo = {
906
- ...otherInfo,
907
- pathArgs,
908
- operationId,
909
- method,
910
- route: rawRouteName,
911
- moduleName,
912
- responsesTypes: responseBodyInfo.responses,
913
- description,
914
- tags,
915
- summary,
916
- responses,
917
- produces,
918
- requestBody,
919
- consumes,
920
- };
921
-
922
- const queryObjectSchema = this.convertRouteParamsIntoObject(
923
- routeParams.query,
924
- );
925
- const pathObjectSchema = this.convertRouteParamsIntoObject(
926
- routeParams.path,
927
- );
928
- const headersObjectSchema = this.convertRouteParamsIntoObject(
929
- routeParams.header,
930
- );
931
-
932
- const routeName = this.getRouteName(rawRouteInfo);
933
-
934
- const requestBodyInfo = this.getRequestBodyInfo(
935
- routeInfo,
936
- routeParams,
937
- parsedSchemas,
938
- routeName,
939
- );
940
-
941
- const requestParamsSchema = this.createRequestParamsSchema({
942
- queryParams: routeParams.query,
943
- pathArgsSchemas: routeParams.path,
944
- queryObjectSchema,
945
- extractRequestParams,
946
- routeName,
947
- });
948
-
949
- if (this.config.extractResponseBody) {
950
- this.extractResponseBodyIfItNeeded(
951
- routeInfo,
952
- responseBodyInfo,
953
- routeName,
954
- );
955
- }
956
- if (this.config.extractResponseError) {
957
- this.extractResponseErrorIfItNeeded(
958
- routeInfo,
959
- responseBodyInfo,
960
- routeName,
961
- );
962
- }
963
-
964
- const typeName = this.schemaUtils.resolveTypeName(routeName.usage, {
965
- suffixes: this.config.extractingOptions.requestParamsSuffix,
966
- resolver: this.config.extractingOptions.requestParamsNameResolver,
967
- shouldReserve: false,
968
- });
969
-
970
- const queryType = routeParams.query.length
971
- ? this.schemaParserFabric.getInlineParseContent(queryObjectSchema, null, [
972
- typeName,
973
- ])
974
- : null;
975
- const pathType = routeParams.path.length
976
- ? this.schemaParserFabric.getInlineParseContent(pathObjectSchema, null, [
977
- typeName,
978
- ])
979
- : null;
980
- const headersType = routeParams.header.length
981
- ? this.schemaParserFabric.getInlineParseContent(
982
- headersObjectSchema,
983
- null,
984
- [typeName],
985
- )
986
- : null;
987
-
988
- const nameResolver = new SpecificArgNameResolver(
989
- this.config,
990
- this.logger,
991
- pathArgsNames,
992
- );
993
-
994
- const specificArgs = {
995
- query: queryType
996
- ? {
997
- name: nameResolver.resolve(RESERVED_QUERY_ARG_NAMES),
998
- optional: this.schemaParserFabric.parseSchema(
999
- queryObjectSchema,
1000
- null,
1001
- [routeName.usage],
1002
- ).allFieldsAreOptional,
1003
- type: queryType,
1004
- }
1005
- : void 0,
1006
- body: requestBodyInfo.type
1007
- ? {
1008
- name: nameResolver.resolve([
1009
- requestBodyInfo.paramName,
1010
- ...RESERVED_BODY_ARG_NAMES,
1011
- ]),
1012
- optional: !requestBodyInfo.required,
1013
- type: requestBodyInfo.type,
1014
- }
1015
- : void 0,
1016
- pathParams: pathType
1017
- ? {
1018
- name: nameResolver.resolve(RESERVED_PATH_ARG_NAMES),
1019
- optional: this.schemaParserFabric.parseSchema(
1020
- pathObjectSchema,
1021
- null,
1022
- [routeName.usage],
1023
- ).allFieldsAreOptional,
1024
- type: pathType,
1025
- }
1026
- : void 0,
1027
- headers: headersType
1028
- ? {
1029
- name: nameResolver.resolve(RESERVED_HEADER_ARG_NAMES),
1030
- optional: this.schemaParserFabric.parseSchema(
1031
- headersObjectSchema,
1032
- null,
1033
- [routeName.usage],
1034
- ).allFieldsAreOptional,
1035
- type: headersType,
1036
- }
1037
- : void 0,
1038
- };
1039
-
1040
- pathArgs.forEach((pathArg, i) => {
1041
- pathArg.type = this.schemaParserFabric.getInlineParseContent(
1042
- routeParams.path[i].schema,
1043
- null,
1044
- [typeName],
1045
- );
1046
- });
1047
-
1048
- return {
1049
- id: routeId,
1050
- namespace: _.replace(moduleName, /^(\d)/, "v$1"),
1051
- routeName,
1052
- routeParams,
1053
- requestBodyInfo,
1054
- responseBodyInfo,
1055
- specificArgs,
1056
- queryObjectSchema,
1057
- pathObjectSchema,
1058
- headersObjectSchema,
1059
- responseBodySchema: responseBodyInfo.success.schema,
1060
- requestBodySchema: requestBodyInfo.schema,
1061
- specificArgNameResolver: nameResolver,
1062
- request: {
1063
- contentTypes: requestBodyInfo.contentTypes,
1064
- parameters: pathArgs,
1065
- path: route,
1066
- formData: requestBodyInfo.contentKind === CONTENT_KIND.FORM_DATA,
1067
- isQueryBody: requestBodyInfo.contentKind === CONTENT_KIND.URL_ENCODED,
1068
- security: hasSecurity,
1069
- method: method,
1070
- requestParams: requestParamsSchema,
1071
-
1072
- payload: specificArgs.body,
1073
- query: specificArgs.query,
1074
- pathParams: specificArgs.pathParams,
1075
- headers: specificArgs.headers,
1076
- },
1077
- response: {
1078
- contentTypes: responseBodyInfo.contentTypes,
1079
- type: responseBodyInfo.success.type,
1080
- errorType: responseBodyInfo.error.type,
1081
- fullTypes: responseBodyInfo.full.types,
1082
- },
1083
- raw: rawRouteInfo,
1084
- };
1085
- };
1086
-
1087
- attachSchema = ({ usageSchema, parsedSchemas }) => {
1088
- this.config.routeNameDuplicatesMap.clear();
1089
-
1090
- const pathsEntries = _.entries(usageSchema.paths);
1091
-
1092
- _.forEach(pathsEntries, ([rawRouteName, routeInfoByMethodsMap]) => {
1093
- const routeInfosMap = this.createRequestsMap(routeInfoByMethodsMap);
1094
-
1095
- _.forEach(routeInfosMap, (routeInfo, method) => {
1096
- const parsedRouteInfo = this.parseRouteInfo(
1097
- rawRouteName,
1098
- routeInfo,
1099
- method,
1100
- usageSchema,
1101
- parsedSchemas,
1102
- );
1103
- const processedRouteInfo =
1104
- this.config.hooks.onCreateRoute(parsedRouteInfo);
1105
- if (processedRouteInfo !== false) {
1106
- const route = processedRouteInfo || parsedRouteInfo;
1107
-
1108
- if (!this.hasSecurityRoutes && route.security) {
1109
- this.hasSecurityRoutes = route.security;
1110
- }
1111
- if (!this.hasQueryRoutes && route.hasQuery) {
1112
- this.hasQueryRoutes = route.hasQuery;
1113
- }
1114
- if (!this.hasFormDataRoutes && route.hasFormDataParams) {
1115
- this.hasFormDataRoutes = route.hasFormDataParams;
1116
- }
1117
-
1118
- this.routes.push(route);
1119
- }
1120
- });
1121
- });
1122
- };
1123
-
1124
- getGroupedRoutes = () => {
1125
- const groupedRoutes = this.routes.reduce(
1126
- (modules, route) => {
1127
- if (route.namespace) {
1128
- if (!modules[route.namespace]) {
1129
- modules[route.namespace] = [];
1130
- }
1131
-
1132
- modules[route.namespace].push(route);
1133
- } else {
1134
- modules.$outOfModule.push(route);
1135
- }
1136
-
1137
- return modules;
1138
- },
1139
- {
1140
- $outOfModule: [],
1141
- },
1142
- );
1143
-
1144
- const routeGroups = _.reduce(
1145
- groupedRoutes,
1146
- (acc, routesGroup, moduleName) => {
1147
- if (moduleName === "$outOfModule") {
1148
- acc.outOfModule = routesGroup;
1149
- } else {
1150
- if (!acc.combined) acc.combined = [];
1151
-
1152
- acc.combined.push({
1153
- moduleName,
1154
- routes: _.map(routesGroup, (route) => {
1155
- const { original: originalName, usage: usageName } =
1156
- route.routeName;
1157
-
1158
- // TODO: https://github.com/acacode/swagger-typescript-api/issues/152
1159
- // TODO: refactor
1160
- if (
1161
- routesGroup.length > 1 &&
1162
- usageName !== originalName &&
1163
- !_.some(
1164
- routesGroup,
1165
- ({ routeName, id }) =>
1166
- id !== route.id && originalName === routeName.original,
1167
- )
1168
- ) {
1169
- return {
1170
- ...route,
1171
- routeName: {
1172
- ...route.routeName,
1173
- usage: originalName,
1174
- },
1175
- };
1176
- }
1177
-
1178
- return route;
1179
- }),
1180
- });
1181
- }
1182
- return acc;
1183
- },
1184
- {},
1185
- );
1186
-
1187
- if (this.config.sortRoutes) {
1188
- if (routeGroups.outOfModule) {
1189
- routeGroups.outOfModule = this.sortRoutes(routeGroups.outOfModule);
1190
- }
1191
- if (routeGroups.combined) {
1192
- _.each(routeGroups.combined, (routeGroup) => {
1193
- routeGroup.routes = this.sortRoutes(routeGroup.routes);
1194
- });
1195
- }
1196
- }
1197
-
1198
- return routeGroups;
1199
- };
1200
-
1201
- sortRoutes = (routes) => {
1202
- return _.slice(routes).sort((routeA, routeB) =>
1203
- routeA.routeName.usage.localeCompare(routeB.routeName.usage),
1204
- );
1205
- };
1206
- }
1207
-
1208
- export { SchemaRoutes };