swagger-typescript-api 10.0.2 → 11.0.0--alpha

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 (55) hide show
  1. package/README.md +263 -41
  2. package/index.d.ts +97 -0
  3. package/index.js +242 -115
  4. package/package.json +121 -116
  5. package/src/code-formatter.js +101 -0
  6. package/src/code-gen-process.js +456 -0
  7. package/src/configuration.js +425 -0
  8. package/src/constants.js +14 -31
  9. package/src/index.js +20 -271
  10. package/src/schema-components-map.js +60 -0
  11. package/src/schema-parser/schema-formatters.js +145 -0
  12. package/src/schema-parser/schema-parser.js +497 -0
  13. package/src/schema-parser/schema-routes.js +902 -0
  14. package/src/swagger-schema-resolver.js +187 -0
  15. package/src/templates.js +174 -155
  16. package/src/translators/JavaScript.js +3 -14
  17. package/src/type-name.js +79 -0
  18. package/src/util/file-system.js +76 -0
  19. package/src/{utils → util}/id.js +9 -9
  20. package/src/util/internal-case.js +5 -0
  21. package/src/util/logger.js +100 -0
  22. package/src/{utils/resolveName.js → util/name-resolver.js} +94 -97
  23. package/src/util/object-assign.js +11 -0
  24. package/src/util/pascal-case.js +5 -0
  25. package/src/{utils → util}/random.js +14 -14
  26. package/templates/base/data-contract-jsdoc.ejs +29 -24
  27. package/templates/base/data-contracts.ejs +3 -3
  28. package/templates/base/interface-data-contract.ejs +1 -0
  29. package/templates/base/route-docs.ejs +3 -4
  30. package/templates/base/route-type.ejs +2 -2
  31. package/templates/default/procedure-call.ejs +2 -2
  32. package/templates/default/route-types.ejs +2 -2
  33. package/templates/modular/api.ejs +2 -2
  34. package/templates/modular/procedure-call.ejs +2 -2
  35. package/templates/modular/route-types.ejs +2 -2
  36. package/src/apiConfig.js +0 -30
  37. package/src/common.js +0 -28
  38. package/src/components.js +0 -91
  39. package/src/config.js +0 -106
  40. package/src/filePrefix.js +0 -14
  41. package/src/files.js +0 -56
  42. package/src/formatFileContent.js +0 -81
  43. package/src/logger.js +0 -59
  44. package/src/modelNames.js +0 -78
  45. package/src/modelTypes.js +0 -31
  46. package/src/output.js +0 -165
  47. package/src/prettierOptions.js +0 -23
  48. package/src/render/utils/fmtToJSDocLine.js +0 -10
  49. package/src/render/utils/index.js +0 -31
  50. package/src/render/utils/templateRequire.js +0 -17
  51. package/src/routeNames.js +0 -46
  52. package/src/routes.js +0 -809
  53. package/src/schema.js +0 -474
  54. package/src/swagger.js +0 -152
  55. package/src/typeFormatters.js +0 -121
package/src/routes.js DELETED
@@ -1,809 +0,0 @@
1
- const _ = require("lodash");
2
- const { types, parseSchema, getType, getRefType, getInlineParseContent, checkAndAddNull } = require("./schema");
3
- const { formatModelName } = require("./modelNames");
4
- const {
5
- DEFAULT_BODY_ARG_NAME,
6
- SUCCESS_RESPONSE_STATUS_RANGE,
7
- TS_KEYWORDS,
8
- RESERVED_QUERY_ARG_NAMES,
9
- RESERVED_BODY_ARG_NAMES,
10
- RESERVED_PATH_ARG_NAMES,
11
- RESERVED_HEADER_ARG_NAMES,
12
- } = require("./constants");
13
- const { formatDescription, classNameCase } = require("./common");
14
- const { config } = require("./config");
15
- const { generateId } = require("./utils/id");
16
- const { getRouteName } = require("./routeNames");
17
- const { createComponent } = require("./components");
18
- const { logger } = require("./logger");
19
- const { SpecificArgNameResolver } = require("./utils/resolveName");
20
-
21
- const formDataTypes = _.uniq([types.file, types.string.binary]);
22
-
23
- const getSchemaFromRequestType = (requestInfo) => {
24
- const content = _.get(requestInfo, "content");
25
-
26
- if (!content) return null;
27
-
28
- /* content: { "multipart/form-data": { schema: {...} }, "application/json": { schema: {...} } } */
29
-
30
- /* for example: dataType = "multipart/form-data" */
31
- for (const dataType in content) {
32
- if (content[dataType] && content[dataType].schema) {
33
- return {
34
- ...content[dataType].schema,
35
- dataType,
36
- };
37
- }
38
- }
39
-
40
- return null;
41
- };
42
-
43
- const getTypeFromRequestInfo = ({ requestInfo, parsedSchemas, operationId, defaultType, typeName }) => {
44
- // TODO: make more flexible pick schema without content type
45
- const schema = getSchemaFromRequestType(requestInfo);
46
- const refTypeInfo = getRefType(requestInfo);
47
-
48
- if (schema) {
49
- const content = getInlineParseContent(schema, typeName);
50
- const foundedSchemaByName = _.find(parsedSchemas, (parsedSchema) => formatModelName(parsedSchema.name) === content);
51
- const foundSchemaByContent = _.find(parsedSchemas, (parsedSchema) => _.isEqual(parsedSchema.content, content));
52
-
53
- const foundSchema = foundedSchemaByName || foundSchemaByContent;
54
-
55
- return foundSchema ? formatModelName(foundSchema.name) : content;
56
- }
57
-
58
- if (refTypeInfo) {
59
- // const refTypeWithoutOpId = refType.replace(operationId, '');
60
- // const foundedSchemaByName = _.find(parsedSchemas, ({ name }) => name === refType || name === refTypeWithoutOpId)
61
-
62
- // TODO:HACK fix problem of swagger2opeanpi
63
- const typeNameWithoutOpId = _.replace(refTypeInfo.typeName, operationId, "");
64
- if (_.find(parsedSchemas, (schema) => schema.name === typeNameWithoutOpId)) {
65
- return formatModelName(typeNameWithoutOpId);
66
- }
67
-
68
- switch (refTypeInfo.componentName) {
69
- case "schemas":
70
- return formatModelName(refTypeInfo.typeName);
71
- case "responses":
72
- case "requestBodies":
73
- return getInlineParseContent(getSchemaFromRequestType(refTypeInfo.rawTypeData), refTypeInfo.typeName || null);
74
- default:
75
- return getInlineParseContent(refTypeInfo.rawTypeData, refTypeInfo.typeName || null);
76
- }
77
- }
78
-
79
- return defaultType || TS_KEYWORDS.ANY;
80
- };
81
-
82
- const getRequestInfoTypes = ({ requestInfos, parsedSchemas, operationId, defaultType }) =>
83
- _.reduce(
84
- requestInfos,
85
- (acc, requestInfo, status) => {
86
- const contentTypes = getContentTypes([requestInfo]);
87
-
88
- return [
89
- ...acc,
90
- {
91
- ...(requestInfo || {}),
92
- contentTypes: contentTypes,
93
- contentKind: getContentKind(contentTypes),
94
- type: checkAndAddNull(
95
- requestInfo,
96
- getTypeFromRequestInfo({
97
- requestInfo,
98
- parsedSchemas,
99
- operationId,
100
- defaultType,
101
- }),
102
- ),
103
- description: formatDescription(requestInfo.description || "", true),
104
- status: _.isNaN(+status) ? status : +status,
105
- isSuccess: isSuccessStatus(status),
106
- },
107
- ];
108
- },
109
- [],
110
- );
111
-
112
- const isSuccessStatus = (status) =>
113
- (config.defaultResponseAsSuccess && status === "default") ||
114
- (+status >= SUCCESS_RESPONSE_STATUS_RANGE[0] && +status < SUCCESS_RESPONSE_STATUS_RANGE[1]) ||
115
- status === "2xx";
116
-
117
- const parseRoute = (route) => {
118
- const pathParamMatches = (route || "").match(
119
- /({(([a-zA-Z]-?_?){1,})([0-9]{1,})?})|(:(([a-zA-Z]-?_?){1,})([0-9]{1,})?:?)/g,
120
- );
121
-
122
- // used in case when path parameters is not declared in requestInfo.parameters ("in": "path")
123
- const pathParams = _.reduce(
124
- pathParamMatches,
125
- (pathParams, match) => {
126
- const paramName = _.replace(match, /\{|\}|\:/g, "");
127
-
128
- if (!paramName) return pathParams;
129
-
130
- if (_.includes(paramName, "-")) {
131
- logger.warn("wrong path param name", paramName);
132
- }
133
-
134
- return [
135
- ...pathParams,
136
- {
137
- $match: match,
138
- name: _.camelCase(paramName),
139
- required: true,
140
- type: "string",
141
- description: "",
142
- schema: {
143
- type: "string",
144
- },
145
- in: "path",
146
- },
147
- ];
148
- },
149
- [],
150
- );
151
-
152
- const fixedRoute = _.reduce(
153
- pathParams,
154
- (fixedRoute, pathParam) => {
155
- return _.replace(fixedRoute, pathParam.$match, `\${${pathParam.name}}`);
156
- },
157
- route || "",
158
- );
159
-
160
- return {
161
- originalRoute: route || "",
162
- route: fixedRoute,
163
- pathParams,
164
- };
165
- };
166
-
167
- const getRouteParams = (routeInfo, pathParams) => {
168
- const { parameters } = routeInfo;
169
-
170
- const routeParams = {
171
- path: [],
172
- header: [],
173
- body: [],
174
- query: [],
175
- body: [],
176
- formData: [],
177
- cookie: [],
178
- };
179
-
180
- _.each(parameters, (parameter) => {
181
- const refTypeInfo = getRefType(parameter);
182
- let routeParam = null;
183
-
184
- if (refTypeInfo && refTypeInfo.rawTypeData.in && refTypeInfo.rawTypeData) {
185
- if (!routeParams[refTypeInfo.rawTypeData.in]) {
186
- routeParams[refTypeInfo.rawTypeData.in] = [];
187
- }
188
-
189
- routeParam = {
190
- ...refTypeInfo.rawTypeData,
191
- ...(refTypeInfo.rawTypeData.schema || {}),
192
- };
193
- } else {
194
- if (!parameter.in) return;
195
-
196
- if (!routeParams[parameter.in]) {
197
- routeParams[parameter.in] = [];
198
- }
199
-
200
- routeParam = {
201
- ...parameter,
202
- ...(parameter.schema || {}),
203
- };
204
- }
205
-
206
- if (routeParam.in === "path") {
207
- if (!routeParam.name) return;
208
-
209
- routeParam.name = _.camelCase(routeParam.name);
210
- }
211
-
212
- if (routeParam) {
213
- routeParams[routeParam.in].push(routeParam);
214
- }
215
- });
216
-
217
- // used in case when path parameters is not declared in requestInfo.parameters ("in": "path")
218
- _.each(pathParams, (pathParam) => {
219
- const alreadyExist = _.some(routeParams.path, (parameter) => parameter.name === pathParam.name);
220
-
221
- if (!alreadyExist) {
222
- routeParams.path.push(pathParam);
223
- }
224
- });
225
-
226
- return routeParams;
227
- };
228
-
229
- const convertRouteParamsIntoObject = (params) => {
230
- return _.reduce(
231
- params,
232
- (objectSchema, schemaPart) => {
233
- if (!schemaPart || !schemaPart.name) return objectSchema;
234
-
235
- return {
236
- ...objectSchema,
237
- properties: {
238
- ...objectSchema.properties,
239
- [schemaPart.name]: {
240
- ...schemaPart,
241
- ...(schemaPart.schema || {}),
242
- },
243
- },
244
- };
245
- },
246
- {
247
- properties: {},
248
- type: "object",
249
- },
250
- );
251
- };
252
-
253
- const createRequestsMap = (routeInfoByMethodsMap) => {
254
- const parameters = _.get(routeInfoByMethodsMap, "parameters");
255
-
256
- return _.reduce(
257
- routeInfoByMethodsMap,
258
- (acc, requestInfo, method) => {
259
- if (method.startsWith("x-") || ["parameters", "$ref"].includes(method)) {
260
- return acc;
261
- }
262
-
263
- acc[method] = {
264
- ...requestInfo,
265
- parameters: _.compact(_.concat(parameters, requestInfo.parameters)),
266
- };
267
-
268
- return acc;
269
- },
270
- {},
271
- );
272
- };
273
-
274
- const createRequestParamsSchema = ({
275
- queryParams,
276
- queryObjectSchema,
277
- pathArgsSchemas,
278
- extractRequestParams,
279
- routeName,
280
- }) => {
281
- if (!queryParams || !queryParams.length) return null;
282
-
283
- const pathParams = _.reduce(
284
- pathArgsSchemas,
285
- (acc, pathArgSchema) => {
286
- if (pathArgSchema.name) {
287
- acc[pathArgSchema.name] = {
288
- ...pathArgSchema,
289
- in: "path",
290
- };
291
- }
292
-
293
- return acc;
294
- },
295
- {},
296
- );
297
-
298
- const fixedQueryParams = _.reduce(
299
- _.get(queryObjectSchema, "properties", {}),
300
- (acc, property, name) => {
301
- if (name && _.isObject(property)) {
302
- acc[name] = {
303
- ...property,
304
- in: "query",
305
- };
306
- }
307
-
308
- return acc;
309
- },
310
- {},
311
- );
312
-
313
- const schema = {
314
- ...queryObjectSchema,
315
- properties: {
316
- ...fixedQueryParams,
317
- ...pathParams,
318
- },
319
- };
320
-
321
- const fixedSchema = config.hooks.onCreateRequestParams(schema);
322
-
323
- if (fixedSchema) return fixedSchema;
324
-
325
- if (extractRequestParams) {
326
- const typeName = config.componentTypeNameResolver.resolve([classNameCase(`${routeName.usage} Params`)]);
327
-
328
- return createComponent("schemas", typeName, { ...schema });
329
- }
330
-
331
- return schema;
332
- };
333
-
334
- const getContentTypes = (requestInfo, extraContentTypes) =>
335
- _.uniq(
336
- _.compact([
337
- ...(extraContentTypes || []),
338
- ..._.flatten(_.map(requestInfo, (requestInfoData) => requestInfoData && _.keys(requestInfoData.content))),
339
- ]),
340
- );
341
-
342
- const CONTENT_KIND = {
343
- JSON: "JSON",
344
- URL_ENCODED: "URL_ENCODED",
345
- FORM_DATA: "FORM_DATA",
346
- IMAGE: "IMAGE",
347
- OTHER: "OTHER",
348
- };
349
-
350
- const getContentKind = (contentTypes) => {
351
- if (
352
- _.includes(contentTypes, "application/json") ||
353
- _.some(contentTypes, (contentType) => _.endsWith(contentType, "+json"))
354
- ) {
355
- return CONTENT_KIND.JSON;
356
- }
357
-
358
- if (contentTypes.includes("application/x-www-form-urlencoded")) {
359
- return CONTENT_KIND.URL_ENCODED;
360
- }
361
-
362
- if (contentTypes.includes("multipart/form-data")) {
363
- return CONTENT_KIND.FORM_DATA;
364
- }
365
-
366
- if (_.some(contentTypes, (contentType) => _.includes(contentType, "image/"))) {
367
- return CONTENT_KIND.IMAGE;
368
- }
369
-
370
- return CONTENT_KIND.OTHER;
371
- };
372
-
373
- const getRequestBodyInfo = (routeInfo, routeParams, parsedSchemas, routeName) => {
374
- const { requestBody, consumes, requestBodyName, operationId } = routeInfo;
375
- let schema = null;
376
- let type = null;
377
-
378
- const contentTypes = getContentTypes([requestBody], [...(consumes || []), routeInfo["x-contentType"]]);
379
- let contentKind = getContentKind(contentTypes);
380
-
381
- let typeName = null;
382
-
383
- if (config.extractRequestBody) {
384
- typeName = config.componentTypeNameResolver.resolve([
385
- classNameCase(`${routeName.usage} Payload`),
386
- classNameCase(`${routeName.usage} Body`),
387
- classNameCase(`${routeName.usage} Input`),
388
- ]);
389
- }
390
-
391
- if (routeParams.formData.length) {
392
- contentKind = CONTENT_KIND.FORM_DATA;
393
- schema = convertRouteParamsIntoObject(routeParams.formData);
394
- type = getInlineParseContent(schema, typeName);
395
- } else if (contentKind === CONTENT_KIND.FORM_DATA) {
396
- schema = getSchemaFromRequestType(requestBody);
397
- type = getInlineParseContent(schema, typeName);
398
- } else if (requestBody) {
399
- schema = getSchemaFromRequestType(requestBody);
400
- type = checkAndAddNull(
401
- requestBody,
402
- getTypeFromRequestInfo({
403
- requestInfo: requestBody,
404
- parsedSchemas,
405
- operationId,
406
- typeName,
407
- }),
408
- );
409
-
410
- // TODO: Refactor that.
411
- // It needed for cases when swagger schema is not declared request body type as form data
412
- // but request body data type contains form data types like File
413
- if (formDataTypes.some((dataType) => _.includes(type, `: ${dataType}`))) {
414
- contentKind = CONTENT_KIND.FORM_DATA;
415
- }
416
- }
417
-
418
- if (schema && !schema.$ref && config.extractRequestBody) {
419
- schema = createComponent("schemas", typeName, { ...schema });
420
- type = getInlineParseContent(schema);
421
- }
422
-
423
- return {
424
- paramName: requestBodyName || (requestBody && requestBody.name) || DEFAULT_BODY_ARG_NAME,
425
- contentTypes,
426
- contentKind,
427
- schema,
428
- type,
429
- required: requestBody && (typeof requestBody.required === "undefined" || !!requestBody.required),
430
- };
431
- };
432
-
433
- const getResponseBodyInfo = (routeInfo, routeParams, parsedSchemas) => {
434
- const { produces, operationId, responses } = routeInfo;
435
-
436
- const contentTypes = getContentTypes(responses, [...(produces || []), routeInfo["x-accepts"]]);
437
-
438
- const responseInfos = getRequestInfoTypes({
439
- requestInfos: responses,
440
- parsedSchemas,
441
- operationId,
442
- defaultType: config.defaultResponseType || TS_KEYWORDS.VOID,
443
- });
444
-
445
- const successResponse = responseInfos.find((response) => response.isSuccess);
446
- const errorResponses = responseInfos.filter((response) => !response.isSuccess && response.type !== TS_KEYWORDS.ANY);
447
-
448
- const handleResponseHeaders = (src) => {
449
- if (!src) {
450
- return "headers: {},";
451
- }
452
- const headerTypes = Object.fromEntries(
453
- Object.entries(src).map(([k, v]) => {
454
- return [k, getType(v)];
455
- }),
456
- );
457
- const r = `headers: { ${Object.entries(headerTypes)
458
- .map(([k, v]) => `"${k}": ${v}`)
459
- .join(",")} },`;
460
- return r;
461
- };
462
-
463
- return {
464
- contentTypes,
465
- responses: responseInfos,
466
- success: {
467
- schema: successResponse,
468
- type: (successResponse && successResponse.type) || TS_KEYWORDS.ANY,
469
- },
470
- error: {
471
- schemas: errorResponses,
472
- type: _.uniq(errorResponses.map((response) => response.type)).join(" | ") || TS_KEYWORDS.ANY,
473
- },
474
- full: {
475
- types:
476
- responseInfos
477
- .map(
478
- (response) => `{
479
- data: ${response.type}, status: ${response.status}, statusCode: ${response.status}, statusText: "${
480
- response.description
481
- }", ${handleResponseHeaders(response.headers)} config: {} }`,
482
- )
483
- .join(" | ") || TS_KEYWORDS.ANY,
484
- },
485
- };
486
- };
487
-
488
- const parseRoutes = ({ usageSchema, parsedSchemas, moduleNameIndex, moduleNameFirstTag, extractRequestParams }) => {
489
- const { paths, security: globalSecurity } = usageSchema;
490
- const pathsEntries = _.entries(paths);
491
-
492
- return pathsEntries.reduce((routes, [rawRoute, routeInfoByMethodsMap]) => {
493
- if (rawRoute.startsWith("x-")) return routes;
494
-
495
- const routeInfosMap = createRequestsMap(routeInfoByMethodsMap);
496
-
497
- return [
498
- ...routes,
499
- ..._.compact(
500
- _.map(routeInfosMap, (routeInfo, method) => {
501
- const {
502
- operationId,
503
- requestBody,
504
- security,
505
- parameters,
506
- summary,
507
- description,
508
- tags,
509
- responses,
510
- requestBodyName,
511
- produces,
512
- consumes,
513
- ...otherInfo
514
- } = routeInfo;
515
- const { route, pathParams } = parseRoute(rawRoute);
516
-
517
- const routeId = generateId();
518
- const firstTag = tags && tags.length > 0 ? tags[0] : null;
519
- const moduleName =
520
- moduleNameFirstTag && firstTag
521
- ? _.camelCase(firstTag)
522
- : _.camelCase(_.compact(_.split(route, "/"))[moduleNameIndex]);
523
- let hasSecurity = !!(globalSecurity && globalSecurity.length);
524
- if (security) {
525
- hasSecurity = security.length > 0;
526
- }
527
-
528
- const routeParams = getRouteParams(routeInfo, pathParams);
529
-
530
- const pathArgs = routeParams.path.map((pathArgSchema) => ({
531
- name: pathArgSchema.name,
532
- optional: !pathArgSchema.required,
533
- type: getInlineParseContent(pathArgSchema.schema),
534
- description: pathArgSchema.description,
535
- }));
536
- const pathArgsNames = pathArgs.map((arg) => arg.name);
537
-
538
- const responseBodyInfo = getResponseBodyInfo(routeInfo, routeParams, parsedSchemas);
539
-
540
- const rawRouteInfo = {
541
- pathArgs,
542
- operationId,
543
- method,
544
- route: rawRoute,
545
- moduleName,
546
- responsesTypes: responseBodyInfo.responses,
547
- description,
548
- tags,
549
- summary,
550
- responses,
551
- produces,
552
- requestBody,
553
- consumes,
554
- ...otherInfo,
555
- };
556
-
557
- const queryObjectSchema = convertRouteParamsIntoObject(routeParams.query);
558
- const pathObjectSchema = convertRouteParamsIntoObject(routeParams.path);
559
- const headersObjectSchema = convertRouteParamsIntoObject(routeParams.header);
560
-
561
- const routeName = getRouteName(rawRouteInfo);
562
-
563
- const requestBodyInfo = getRequestBodyInfo(routeInfo, routeParams, parsedSchemas, routeName);
564
-
565
- const requestParamsSchema = createRequestParamsSchema({
566
- queryParams: routeParams.query,
567
- pathArgsSchemas: routeParams.path,
568
- queryObjectSchema,
569
- extractRequestParams,
570
- routeName,
571
- });
572
-
573
- extractResponseBodyIfItNeeded(routeInfo, responseBodyInfo, routeParams, rawRouteInfo, routeName);
574
- extractResponseErrorIfItNeeded(routeInfo, responseBodyInfo, routeParams, rawRouteInfo, routeName);
575
-
576
- const queryType = routeParams.query.length ? getInlineParseContent(queryObjectSchema) : null;
577
- const pathType = routeParams.path.length ? getInlineParseContent(pathObjectSchema) : null;
578
- const headersType = routeParams.header.length ? getInlineParseContent(headersObjectSchema) : null;
579
-
580
- const nameResolver = new SpecificArgNameResolver(pathArgsNames);
581
-
582
- const specificArgs = {
583
- query: queryType
584
- ? {
585
- name: nameResolver.resolve(RESERVED_QUERY_ARG_NAMES),
586
- optional: parseSchema(queryObjectSchema, null).allFieldsAreOptional,
587
- type: queryType,
588
- }
589
- : void 0,
590
- body: requestBodyInfo.type
591
- ? {
592
- name: nameResolver.resolve([requestBodyInfo.paramName, ...RESERVED_BODY_ARG_NAMES]),
593
- optional: !requestBodyInfo.required,
594
- type: requestBodyInfo.type,
595
- }
596
- : void 0,
597
- pathParams: pathType
598
- ? {
599
- name: nameResolver.resolve(RESERVED_PATH_ARG_NAMES),
600
- optional: parseSchema(pathObjectSchema, null).allFieldsAreOptional,
601
- type: pathType,
602
- }
603
- : void 0,
604
- headers: headersType
605
- ? {
606
- name: nameResolver.resolve(RESERVED_HEADER_ARG_NAMES),
607
- optional: parseSchema(headersObjectSchema, null).allFieldsAreOptional,
608
- type: headersType,
609
- }
610
- : void 0,
611
- };
612
-
613
- let routeArgs = _.compact([...pathArgs, specificArgs.query, specificArgs.body]);
614
-
615
- if (routeArgs.some((pathArg) => pathArg.optional)) {
616
- const { optionalArgs, requiredArgs } = _.reduce(
617
- [...routeArgs],
618
- (acc, pathArg) => {
619
- if (pathArg.optional) {
620
- acc.optionalArgs.push(pathArg);
621
- } else {
622
- acc.requiredArgs.push(pathArg);
623
- }
624
-
625
- return acc;
626
- },
627
- {
628
- optionalArgs: [],
629
- requiredArgs: [],
630
- },
631
- );
632
-
633
- routeArgs = [...requiredArgs, ...optionalArgs];
634
- }
635
-
636
- const routeData = {
637
- id: routeId,
638
- namespace: _.replace(moduleName, /^(\d)/, "v$1"),
639
- routeName,
640
- routeParams,
641
- requestBodyInfo,
642
- responseBodyInfo,
643
- specificArgs,
644
- queryObjectSchema,
645
- pathObjectSchema,
646
- headersObjectSchema,
647
- responseBodySchema: responseBodyInfo.success.schema,
648
- requestBodySchema: requestBodyInfo.schema,
649
- specificArgNameResolver: nameResolver,
650
- request: {
651
- contentTypes: requestBodyInfo.contentTypes,
652
- parameters: pathArgs,
653
- path: route,
654
- formData: requestBodyInfo.contentKind === CONTENT_KIND.FORM_DATA,
655
- isQueryBody: requestBodyInfo.contentKind === CONTENT_KIND.URL_ENCODED,
656
- security: hasSecurity,
657
- method: method,
658
- requestParams: requestParamsSchema,
659
-
660
- payload: specificArgs.body,
661
- query: specificArgs.query,
662
- pathParams: specificArgs.pathParams,
663
- headers: specificArgs.headers,
664
- },
665
- response: {
666
- contentTypes: responseBodyInfo.contentTypes,
667
- type: responseBodyInfo.success.type,
668
- errorType: responseBodyInfo.error.type,
669
- fullTypes: responseBodyInfo.full.types,
670
- },
671
- raw: rawRouteInfo,
672
- };
673
-
674
- const usageRouteData = config.hooks.onCreateRoute(routeData);
675
-
676
- return usageRouteData === false ? null : usageRouteData || routeData;
677
- }),
678
- ),
679
- ];
680
- }, []);
681
- };
682
-
683
- const groupRoutes = (routes) => {
684
- return _.reduce(
685
- routes.reduce(
686
- (modules, route) => {
687
- if (route.namespace) {
688
- if (!modules[route.namespace]) {
689
- modules[route.namespace] = [];
690
- }
691
-
692
- modules[route.namespace].push(route);
693
- } else {
694
- modules.$outOfModule.push(route);
695
- }
696
-
697
- return modules;
698
- },
699
- {
700
- $outOfModule: [],
701
- },
702
- ),
703
- (acc, packRoutes, moduleName) => {
704
- if (moduleName === "$outOfModule") {
705
- acc.outOfModule = packRoutes;
706
- } else {
707
- if (!acc.combined) acc.combined = [];
708
-
709
- acc.combined.push({
710
- moduleName,
711
- routes: _.map(packRoutes, (route) => {
712
- const { original: originalName, usage: usageName } = route.routeName;
713
-
714
- // TODO: https://github.com/acacode/swagger-typescript-api/issues/152
715
- // TODO: refactor
716
- if (
717
- packRoutes.length > 1 &&
718
- usageName !== originalName &&
719
- !_.some(packRoutes, ({ routeName, id }) => id !== route.id && originalName === routeName.original)
720
- ) {
721
- return {
722
- ...route,
723
- routeName: {
724
- ...route.routeName,
725
- usage: originalName,
726
- },
727
- };
728
- }
729
-
730
- return route;
731
- }),
732
- });
733
- }
734
- return acc;
735
- },
736
- {},
737
- );
738
- };
739
-
740
- const extractResponseBodyIfItNeeded = (routeInfo, responseBodyInfo, routeParams, rawRouteInfo, routeName) => {
741
- if (
742
- config.extractResponseBody &&
743
- responseBodyInfo.responses.length &&
744
- responseBodyInfo.success &&
745
- responseBodyInfo.success.schema
746
- ) {
747
- const typeName = config.componentTypeNameResolver.resolve([
748
- classNameCase(`${routeName.usage} Data`),
749
- classNameCase(`${routeName.usage} Result`),
750
- classNameCase(`${routeName.usage} Output`),
751
- ]);
752
-
753
- const idx = responseBodyInfo.responses.indexOf(responseBodyInfo.success.schema);
754
-
755
- let successResponse = responseBodyInfo.success;
756
-
757
- if (successResponse.schema && !successResponse.schema.$ref) {
758
- const schema = getSchemaFromRequestType(successResponse.schema);
759
- successResponse.schema = createComponent("schemas", typeName, { ...schema });
760
- successResponse.type = getInlineParseContent(successResponse.schema);
761
-
762
- if (idx > -1) {
763
- responseBodyInfo.responses[idx] = successResponse.schema;
764
- }
765
- }
766
- }
767
- };
768
-
769
- const extractResponseErrorIfItNeeded = (routeInfo, responseBodyInfo, routeParams, rawRouteInfo, routeName) => {
770
- if (
771
- config.extractResponseError &&
772
- responseBodyInfo.responses.length &&
773
- responseBodyInfo.error.schemas &&
774
- responseBodyInfo.error.schemas.length
775
- ) {
776
- const typeName = config.componentTypeNameResolver.resolve([
777
- classNameCase(`${routeName.usage} Error`),
778
- classNameCase(`${routeName.usage} Fail`),
779
- classNameCase(`${routeName.usage} Fails`),
780
- classNameCase(`${routeName.usage} ErrorData`),
781
- classNameCase(`${routeName.usage} HttpError`),
782
- classNameCase(`${routeName.usage} BadResponse`),
783
- ]);
784
-
785
- const errorSchemas = responseBodyInfo.error.schemas.map(getSchemaFromRequestType).filter(Boolean);
786
-
787
- if (!errorSchemas.length) return;
788
-
789
- const schema = parseSchema({
790
- oneOf: errorSchemas,
791
- title: errorSchemas
792
- .map((schema) => schema.title)
793
- .filter(Boolean)
794
- .join(" "),
795
- description: errorSchemas
796
- .map((schema) => schema.description)
797
- .filter(Boolean)
798
- .join("\n"),
799
- });
800
- const component = createComponent("schemas", typeName, { ...schema });
801
- responseBodyInfo.error.schemas = [component];
802
- responseBodyInfo.error.type = formatModelName(component.typeName);
803
- }
804
- };
805
-
806
- module.exports = {
807
- parseRoutes,
808
- groupRoutes,
809
- };