swagger-typescript-api 9.2.0 → 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/LICENSE +21 -21
- package/README.md +19 -13
- package/index.d.ts +56 -57
- package/index.js +48 -73
- package/package.json +21 -15
- package/src/config.js +9 -0
- package/src/index.js +54 -7
- package/src/prettierOptions.js +23 -0
- package/src/routeNames.js +3 -7
- package/src/routes.js +91 -79
- package/src/schema.js +66 -43
- package/src/swagger.js +27 -7
- package/src/typeFormatters.js +2 -2
- package/src/utils/id.js +9 -0
- package/templates/base/data-contracts.eta +2 -1
- package/templates/base/http-clients/axios-http-client.eta +38 -18
- package/templates/base/http-clients/fetch-http-client.eta +9 -7
- package/templates/default/api.eta +1 -1
- package/templates/modular/api.eta +1 -1
package/src/index.js
CHANGED
|
@@ -21,6 +21,7 @@ const { generateOutputFiles } = require("./output");
|
|
|
21
21
|
const formatFileContent = require("./formatFileContent");
|
|
22
22
|
const { logger } = require("./logger");
|
|
23
23
|
const { ComponentTypeNameResolver } = require("./utils/resolveName");
|
|
24
|
+
const { getPrettierOptions } = require("./prettierOptions");
|
|
24
25
|
|
|
25
26
|
module.exports = {
|
|
26
27
|
constants: constants,
|
|
@@ -39,14 +40,19 @@ module.exports = {
|
|
|
39
40
|
generateClient = config.generateClient,
|
|
40
41
|
httpClientType = config.httpClientType,
|
|
41
42
|
generateUnionEnums = config.generateUnionEnums,
|
|
43
|
+
addReadonly = config.addReadonly,
|
|
42
44
|
moduleNameIndex = config.moduleNameIndex,
|
|
43
45
|
moduleNameFirstTag = config.moduleNameFirstTag,
|
|
44
46
|
extractRequestParams = config.extractRequestParams,
|
|
45
47
|
extractRequestBody = config.extractRequestBody,
|
|
48
|
+
extractResponseBody = config.extractResponseBody,
|
|
49
|
+
extractResponseError = config.extractResponseError,
|
|
46
50
|
defaultResponseType = config.defaultResponseType,
|
|
47
51
|
unwrapResponseData = config.unwrapResponseData,
|
|
52
|
+
disableThrowOnError = config.disableThrowOnError,
|
|
53
|
+
sortTypes = config.sortTypes,
|
|
48
54
|
singleHttpClient = config.singleHttpClient,
|
|
49
|
-
prettier: prettierOptions =
|
|
55
|
+
prettier: prettierOptions = getPrettierOptions(),
|
|
50
56
|
hooks: rawHooks,
|
|
51
57
|
extraTemplates,
|
|
52
58
|
enumNamesAsValues,
|
|
@@ -56,6 +62,9 @@ module.exports = {
|
|
|
56
62
|
silent = config.silent,
|
|
57
63
|
typePrefix = config.typePrefix,
|
|
58
64
|
typeSuffix = config.typeSuffix,
|
|
65
|
+
patch = config.patch,
|
|
66
|
+
authorizationToken,
|
|
67
|
+
apiClassName = config.apiClassName,
|
|
59
68
|
}) =>
|
|
60
69
|
new Promise((resolve, reject) => {
|
|
61
70
|
addToConfig({
|
|
@@ -66,12 +75,15 @@ module.exports = {
|
|
|
66
75
|
generateResponses,
|
|
67
76
|
templates,
|
|
68
77
|
generateUnionEnums,
|
|
78
|
+
addReadonly,
|
|
69
79
|
moduleNameIndex,
|
|
70
80
|
moduleNameFirstTag,
|
|
71
81
|
prettierOptions,
|
|
72
82
|
modular,
|
|
73
83
|
extractRequestParams,
|
|
74
84
|
extractRequestBody,
|
|
85
|
+
extractResponseBody,
|
|
86
|
+
extractResponseError,
|
|
75
87
|
hooks: _.merge(config.hooks, rawHooks || {}),
|
|
76
88
|
enumNamesAsValues,
|
|
77
89
|
disableStrictSSL,
|
|
@@ -79,16 +91,20 @@ module.exports = {
|
|
|
79
91
|
cleanOutput,
|
|
80
92
|
defaultResponseType,
|
|
81
93
|
unwrapResponseData,
|
|
94
|
+
disableThrowOnError,
|
|
95
|
+
sortTypes,
|
|
82
96
|
singleHttpClient,
|
|
83
97
|
constants,
|
|
84
98
|
silent,
|
|
85
99
|
toJS: translateToJavaScript,
|
|
86
100
|
typePrefix,
|
|
87
101
|
typeSuffix,
|
|
102
|
+
patch,
|
|
103
|
+
apiClassName,
|
|
88
104
|
});
|
|
89
105
|
(spec
|
|
90
|
-
? convertSwaggerObject(spec)
|
|
91
|
-
: getSwaggerObject(input, url, disableStrictSSL, disableProxy)
|
|
106
|
+
? convertSwaggerObject(spec, { patch })
|
|
107
|
+
: getSwaggerObject(input, url, disableStrictSSL, disableProxy, authorizationToken, { patch })
|
|
92
108
|
)
|
|
93
109
|
.then(({ usageSchema, originalSchema }) => {
|
|
94
110
|
const templatePaths = getTemplatePaths(config);
|
|
@@ -113,9 +129,7 @@ module.exports = {
|
|
|
113
129
|
|
|
114
130
|
const componentsMap = createComponentsMap(components);
|
|
115
131
|
|
|
116
|
-
const componentSchemasNames = filterComponentsMap(componentsMap, "schemas").map(
|
|
117
|
-
(c) => c.typeName,
|
|
118
|
-
);
|
|
132
|
+
const componentSchemasNames = filterComponentsMap(componentsMap, "schemas").map((c) => c.typeName);
|
|
119
133
|
|
|
120
134
|
addToConfig({
|
|
121
135
|
componentTypeNameResolver: new ComponentTypeNameResolver(componentSchemasNames),
|
|
@@ -138,11 +152,44 @@ module.exports = {
|
|
|
138
152
|
const hasFormDataRoutes = routes.some((route) => route.hasFormDataParams);
|
|
139
153
|
|
|
140
154
|
const usageComponentSchemas = filterComponentsMap(componentsMap, "schemas");
|
|
155
|
+
const sortByProperty = (o1, o2, propertyName) => {
|
|
156
|
+
if (o1[propertyName] > o2[propertyName]) {
|
|
157
|
+
return 1;
|
|
158
|
+
}
|
|
159
|
+
if (o1[propertyName] < o2[propertyName]) {
|
|
160
|
+
return -1;
|
|
161
|
+
}
|
|
162
|
+
return 0;
|
|
163
|
+
};
|
|
164
|
+
const sortByTypeName = (o1, o2) => sortByProperty(o1, o2, "typeName");
|
|
165
|
+
|
|
166
|
+
const sortByName = (o1, o2) => sortByProperty(o1, o2, "name");
|
|
167
|
+
|
|
168
|
+
const sortSchemas = (schemas) => {
|
|
169
|
+
if (config.sortTypes) {
|
|
170
|
+
return schemas.sort(sortByTypeName).map((schema) => {
|
|
171
|
+
if (schema.rawTypeData?.properties) {
|
|
172
|
+
return {
|
|
173
|
+
...schema,
|
|
174
|
+
rawTypeData: {
|
|
175
|
+
...schema.rawTypeData,
|
|
176
|
+
$parsed: {
|
|
177
|
+
...schema.rawTypeData["$parsed"],
|
|
178
|
+
content: schema.rawTypeData["$parsed"].content.sort(sortByName),
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
return schema;
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return schemas;
|
|
187
|
+
};
|
|
141
188
|
|
|
142
189
|
const rawConfiguration = {
|
|
143
190
|
apiConfig: createApiConfig(usageSchema),
|
|
144
191
|
config,
|
|
145
|
-
modelTypes: _.map(usageComponentSchemas, prepareModelType),
|
|
192
|
+
modelTypes: _.map(sortSchemas(usageComponentSchemas), prepareModelType),
|
|
146
193
|
rawModelTypes: usageComponentSchemas,
|
|
147
194
|
hasFormDataRoutes,
|
|
148
195
|
hasSecurityRoutes,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const { cosmiconfigSync } = require("cosmiconfig");
|
|
2
|
+
const constants = require("./constants");
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Get prettier options from user's project or return the default one
|
|
6
|
+
* @return {import('prettier').Options} Prettier options
|
|
7
|
+
*/
|
|
8
|
+
function getPrettierOptions() {
|
|
9
|
+
const prettier = cosmiconfigSync("prettier").search();
|
|
10
|
+
|
|
11
|
+
if (prettier) {
|
|
12
|
+
return {
|
|
13
|
+
...prettier.config,
|
|
14
|
+
parser: "typescript",
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return constants.PRETTIER_OPTIONS;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
getPrettierOptions,
|
|
23
|
+
};
|
package/src/routeNames.js
CHANGED
|
@@ -13,19 +13,15 @@ const getRouteName = (routeInfo) => {
|
|
|
13
13
|
config,
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
const routeName =
|
|
17
|
-
config.hooks.onFormatRouteName(routeInfo, routeNameFromTemplate) || routeNameFromTemplate;
|
|
16
|
+
const routeName = config.hooks.onFormatRouteName(routeInfo, routeNameFromTemplate) || routeNameFromTemplate;
|
|
18
17
|
|
|
19
18
|
const duplicateIdentifier = `${moduleName}|${routeName}`;
|
|
20
19
|
|
|
21
20
|
if (routeNameDuplicatesMap.has(duplicateIdentifier)) {
|
|
22
|
-
routeNameDuplicatesMap.set(
|
|
23
|
-
duplicateIdentifier,
|
|
24
|
-
routeNameDuplicatesMap.get(duplicateIdentifier) + 1,
|
|
25
|
-
);
|
|
21
|
+
routeNameDuplicatesMap.set(duplicateIdentifier, routeNameDuplicatesMap.get(duplicateIdentifier) + 1);
|
|
26
22
|
|
|
27
23
|
logger.warn(
|
|
28
|
-
`Module "${moduleName}" already
|
|
24
|
+
`Module "${moduleName}" already has method "${routeName}()"`,
|
|
29
25
|
`\nThis method has been renamed to "${
|
|
30
26
|
routeName + routeNameDuplicatesMap.get(duplicateIdentifier)
|
|
31
27
|
}()" to solve conflict names.`,
|
package/src/routes.js
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
const _ = require("lodash");
|
|
2
|
-
const {
|
|
3
|
-
types,
|
|
4
|
-
parseSchema,
|
|
5
|
-
getType,
|
|
6
|
-
getRefType,
|
|
7
|
-
getInlineParseContent,
|
|
8
|
-
checkAndAddNull,
|
|
9
|
-
} = require("./schema");
|
|
2
|
+
const { types, parseSchema, getType, getRefType, getInlineParseContent, checkAndAddNull } = require("./schema");
|
|
10
3
|
const { formatModelName } = require("./modelNames");
|
|
11
4
|
const {
|
|
12
5
|
DEFAULT_BODY_ARG_NAME,
|
|
@@ -19,7 +12,7 @@ const {
|
|
|
19
12
|
} = require("./constants");
|
|
20
13
|
const { formatDescription, classNameCase } = require("./common");
|
|
21
14
|
const { config } = require("./config");
|
|
22
|
-
const {
|
|
15
|
+
const { generateId } = require("./utils/id");
|
|
23
16
|
const { getRouteName } = require("./routeNames");
|
|
24
17
|
const { createComponent } = require("./components");
|
|
25
18
|
const { logger } = require("./logger");
|
|
@@ -47,26 +40,15 @@ const getSchemaFromRequestType = (requestInfo) => {
|
|
|
47
40
|
return null;
|
|
48
41
|
};
|
|
49
42
|
|
|
50
|
-
const getTypeFromRequestInfo = ({
|
|
51
|
-
requestInfo,
|
|
52
|
-
parsedSchemas,
|
|
53
|
-
operationId,
|
|
54
|
-
defaultType,
|
|
55
|
-
typeName,
|
|
56
|
-
}) => {
|
|
43
|
+
const getTypeFromRequestInfo = ({ requestInfo, parsedSchemas, operationId, defaultType, typeName }) => {
|
|
57
44
|
// TODO: make more flexible pick schema without content type
|
|
58
45
|
const schema = getSchemaFromRequestType(requestInfo);
|
|
59
46
|
const refTypeInfo = getRefType(requestInfo);
|
|
60
47
|
|
|
61
48
|
if (schema) {
|
|
62
49
|
const content = getInlineParseContent(schema, typeName);
|
|
63
|
-
const foundedSchemaByName = _.find(
|
|
64
|
-
|
|
65
|
-
(parsedSchema) => formatModelName(parsedSchema.name) === content,
|
|
66
|
-
);
|
|
67
|
-
const foundSchemaByContent = _.find(parsedSchemas, (parsedSchema) =>
|
|
68
|
-
_.isEqual(parsedSchema.content, content),
|
|
69
|
-
);
|
|
50
|
+
const foundedSchemaByName = _.find(parsedSchemas, (parsedSchema) => formatModelName(parsedSchema.name) === content);
|
|
51
|
+
const foundSchemaByContent = _.find(parsedSchemas, (parsedSchema) => _.isEqual(parsedSchema.content, content));
|
|
70
52
|
|
|
71
53
|
const foundSchema = foundedSchemaByName || foundSchemaByContent;
|
|
72
54
|
|
|
@@ -88,10 +70,7 @@ const getTypeFromRequestInfo = ({
|
|
|
88
70
|
return formatModelName(refTypeInfo.typeName);
|
|
89
71
|
case "responses":
|
|
90
72
|
case "requestBodies":
|
|
91
|
-
return getInlineParseContent(
|
|
92
|
-
getSchemaFromRequestType(refTypeInfo.rawTypeData),
|
|
93
|
-
refTypeInfo.typeName || null,
|
|
94
|
-
);
|
|
73
|
+
return getInlineParseContent(getSchemaFromRequestType(refTypeInfo.rawTypeData), refTypeInfo.typeName || null);
|
|
95
74
|
default:
|
|
96
75
|
return getInlineParseContent(refTypeInfo.rawTypeData, refTypeInfo.typeName || null);
|
|
97
76
|
}
|
|
@@ -344,9 +323,7 @@ const createRequestParamsSchema = ({
|
|
|
344
323
|
if (fixedSchema) return fixedSchema;
|
|
345
324
|
|
|
346
325
|
if (extractRequestParams) {
|
|
347
|
-
const typeName = config.componentTypeNameResolver.resolve([
|
|
348
|
-
classNameCase(`${routeName.usage} Params`),
|
|
349
|
-
]);
|
|
326
|
+
const typeName = config.componentTypeNameResolver.resolve([classNameCase(`${routeName.usage} Params`)]);
|
|
350
327
|
|
|
351
328
|
return createComponent("schemas", typeName, { ...schema });
|
|
352
329
|
}
|
|
@@ -358,9 +335,7 @@ const getContentTypes = (requestInfo, extraContentTypes) =>
|
|
|
358
335
|
_.uniq(
|
|
359
336
|
_.compact([
|
|
360
337
|
...(extraContentTypes || []),
|
|
361
|
-
..._.flatten(
|
|
362
|
-
_.map(requestInfo, (requestInfoData) => requestInfoData && _.keys(requestInfoData.content)),
|
|
363
|
-
),
|
|
338
|
+
..._.flatten(_.map(requestInfo, (requestInfoData) => requestInfoData && _.keys(requestInfoData.content))),
|
|
364
339
|
]),
|
|
365
340
|
);
|
|
366
341
|
|
|
@@ -400,10 +375,7 @@ const getRequestBodyInfo = (routeInfo, routeParams, parsedSchemas, routeName) =>
|
|
|
400
375
|
let schema = null;
|
|
401
376
|
let type = null;
|
|
402
377
|
|
|
403
|
-
const contentTypes = getContentTypes(
|
|
404
|
-
[requestBody],
|
|
405
|
-
[...(consumes || []), routeInfo["x-contentType"]],
|
|
406
|
-
);
|
|
378
|
+
const contentTypes = getContentTypes([requestBody], [...(consumes || []), routeInfo["x-contentType"]]);
|
|
407
379
|
let contentKind = getContentKind(contentTypes);
|
|
408
380
|
|
|
409
381
|
let typeName = null;
|
|
@@ -454,8 +426,7 @@ const getRequestBodyInfo = (routeInfo, routeParams, parsedSchemas, routeName) =>
|
|
|
454
426
|
contentKind,
|
|
455
427
|
schema,
|
|
456
428
|
type,
|
|
457
|
-
required:
|
|
458
|
-
requestBody && (typeof requestBody.required === "undefined" || !!requestBody.required),
|
|
429
|
+
required: requestBody && (typeof requestBody.required === "undefined" || !!requestBody.required),
|
|
459
430
|
};
|
|
460
431
|
};
|
|
461
432
|
|
|
@@ -472,9 +443,7 @@ const getResponseBodyInfo = (routeInfo, routeParams, parsedSchemas) => {
|
|
|
472
443
|
});
|
|
473
444
|
|
|
474
445
|
const successResponse = responseInfos.find((response) => response.isSuccess);
|
|
475
|
-
const errorResponses = responseInfos.filter(
|
|
476
|
-
(response) => !response.isSuccess && response.type !== TS_KEYWORDS.ANY,
|
|
477
|
-
);
|
|
446
|
+
const errorResponses = responseInfos.filter((response) => !response.isSuccess && response.type !== TS_KEYWORDS.ANY);
|
|
478
447
|
|
|
479
448
|
const handleResponseHeaders = (src) => {
|
|
480
449
|
if (!src) {
|
|
@@ -507,24 +476,16 @@ const getResponseBodyInfo = (routeInfo, routeParams, parsedSchemas) => {
|
|
|
507
476
|
responseInfos
|
|
508
477
|
.map(
|
|
509
478
|
(response) => `{
|
|
510
|
-
data: ${response.type}, status: ${response.status}, statusCode: ${
|
|
511
|
-
response.
|
|
512
|
-
},
|
|
513
|
-
response.headers,
|
|
514
|
-
)} config: {} }`,
|
|
479
|
+
data: ${response.type}, status: ${response.status}, statusCode: ${response.status}, statusText: "${
|
|
480
|
+
response.description
|
|
481
|
+
}", ${handleResponseHeaders(response.headers)} config: {} }`,
|
|
515
482
|
)
|
|
516
483
|
.join(" | ") || TS_KEYWORDS.ANY,
|
|
517
484
|
},
|
|
518
485
|
};
|
|
519
486
|
};
|
|
520
487
|
|
|
521
|
-
const parseRoutes = ({
|
|
522
|
-
usageSchema,
|
|
523
|
-
parsedSchemas,
|
|
524
|
-
moduleNameIndex,
|
|
525
|
-
moduleNameFirstTag,
|
|
526
|
-
extractRequestParams,
|
|
527
|
-
}) => {
|
|
488
|
+
const parseRoutes = ({ usageSchema, parsedSchemas, moduleNameIndex, moduleNameFirstTag, extractRequestParams }) => {
|
|
528
489
|
const { paths, security: globalSecurity } = usageSchema;
|
|
529
490
|
const pathsEntries = _.entries(paths);
|
|
530
491
|
|
|
@@ -553,16 +514,13 @@ const parseRoutes = ({
|
|
|
553
514
|
} = routeInfo;
|
|
554
515
|
const { route, pathParams } = parseRoute(rawRoute);
|
|
555
516
|
|
|
556
|
-
const routeId =
|
|
517
|
+
const routeId = generateId();
|
|
557
518
|
const firstTag = tags && tags.length > 0 ? tags[0] : null;
|
|
558
519
|
const moduleName =
|
|
559
520
|
moduleNameFirstTag && firstTag
|
|
560
521
|
? _.camelCase(firstTag)
|
|
561
522
|
: _.camelCase(_.compact(_.split(route, "/"))[moduleNameIndex]);
|
|
562
|
-
const hasSecurity = !!(
|
|
563
|
-
(globalSecurity && globalSecurity.length) ||
|
|
564
|
-
(security && security.length)
|
|
565
|
-
);
|
|
523
|
+
const hasSecurity = !!((globalSecurity && globalSecurity.length) || (security && security.length));
|
|
566
524
|
|
|
567
525
|
const routeParams = getRouteParams(routeInfo, pathParams);
|
|
568
526
|
|
|
@@ -599,12 +557,7 @@ const parseRoutes = ({
|
|
|
599
557
|
|
|
600
558
|
const routeName = getRouteName(rawRouteInfo);
|
|
601
559
|
|
|
602
|
-
const requestBodyInfo = getRequestBodyInfo(
|
|
603
|
-
routeInfo,
|
|
604
|
-
routeParams,
|
|
605
|
-
parsedSchemas,
|
|
606
|
-
routeName,
|
|
607
|
-
);
|
|
560
|
+
const requestBodyInfo = getRequestBodyInfo(routeInfo, routeParams, parsedSchemas, routeName);
|
|
608
561
|
|
|
609
562
|
const requestParamsSchema = createRequestParamsSchema({
|
|
610
563
|
queryParams: routeParams.query,
|
|
@@ -614,13 +567,12 @@ const parseRoutes = ({
|
|
|
614
567
|
routeName,
|
|
615
568
|
});
|
|
616
569
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
570
|
+
extractResponseBodyIfItNeeded(routeInfo, responseBodyInfo, routeParams, rawRouteInfo, routeName);
|
|
571
|
+
extractResponseErrorIfItNeeded(routeInfo, responseBodyInfo, routeParams, rawRouteInfo, routeName);
|
|
572
|
+
|
|
573
|
+
const queryType = routeParams.query.length ? getInlineParseContent(queryObjectSchema) : null;
|
|
620
574
|
const pathType = routeParams.path.length ? getInlineParseContent(pathObjectSchema) : null;
|
|
621
|
-
const headersType = routeParams.header.length
|
|
622
|
-
? getInlineParseContent(headersObjectSchema)
|
|
623
|
-
: null;
|
|
575
|
+
const headersType = routeParams.header.length ? getInlineParseContent(headersObjectSchema) : null;
|
|
624
576
|
|
|
625
577
|
const nameResolver = new SpecificArgNameResolver(pathArgsNames);
|
|
626
578
|
|
|
@@ -634,10 +586,7 @@ const parseRoutes = ({
|
|
|
634
586
|
: void 0,
|
|
635
587
|
body: requestBodyInfo.type
|
|
636
588
|
? {
|
|
637
|
-
name: nameResolver.resolve([
|
|
638
|
-
requestBodyInfo.paramName,
|
|
639
|
-
...RESERVED_BODY_ARG_NAMES,
|
|
640
|
-
]),
|
|
589
|
+
name: nameResolver.resolve([requestBodyInfo.paramName, ...RESERVED_BODY_ARG_NAMES]),
|
|
641
590
|
optional: !requestBodyInfo.required,
|
|
642
591
|
type: requestBodyInfo.type,
|
|
643
592
|
}
|
|
@@ -764,10 +713,7 @@ const groupRoutes = (routes) => {
|
|
|
764
713
|
if (
|
|
765
714
|
packRoutes.length > 1 &&
|
|
766
715
|
usageName !== originalName &&
|
|
767
|
-
!_.some(
|
|
768
|
-
packRoutes,
|
|
769
|
-
({ routeName, id }) => id !== route.id && originalName === routeName.original,
|
|
770
|
-
)
|
|
716
|
+
!_.some(packRoutes, ({ routeName, id }) => id !== route.id && originalName === routeName.original)
|
|
771
717
|
) {
|
|
772
718
|
return {
|
|
773
719
|
...route,
|
|
@@ -788,6 +734,72 @@ const groupRoutes = (routes) => {
|
|
|
788
734
|
);
|
|
789
735
|
};
|
|
790
736
|
|
|
737
|
+
const extractResponseBodyIfItNeeded = (routeInfo, responseBodyInfo, routeParams, rawRouteInfo, routeName) => {
|
|
738
|
+
if (
|
|
739
|
+
config.extractResponseBody &&
|
|
740
|
+
responseBodyInfo.responses.length &&
|
|
741
|
+
responseBodyInfo.success &&
|
|
742
|
+
responseBodyInfo.success.schema
|
|
743
|
+
) {
|
|
744
|
+
const typeName = config.componentTypeNameResolver.resolve([
|
|
745
|
+
classNameCase(`${routeName.usage} Data`),
|
|
746
|
+
classNameCase(`${routeName.usage} Result`),
|
|
747
|
+
classNameCase(`${routeName.usage} Output`),
|
|
748
|
+
]);
|
|
749
|
+
|
|
750
|
+
const idx = responseBodyInfo.responses.indexOf(responseBodyInfo.success.schema);
|
|
751
|
+
|
|
752
|
+
let successResponse = responseBodyInfo.success;
|
|
753
|
+
|
|
754
|
+
if (successResponse.schema && !successResponse.schema.$ref) {
|
|
755
|
+
const schema = getSchemaFromRequestType(successResponse.schema);
|
|
756
|
+
successResponse.schema = createComponent("schemas", typeName, { ...schema });
|
|
757
|
+
successResponse.type = getInlineParseContent(successResponse.schema);
|
|
758
|
+
|
|
759
|
+
if (idx > -1) {
|
|
760
|
+
responseBodyInfo.responses[idx] = successResponse.schema;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
|
|
766
|
+
const extractResponseErrorIfItNeeded = (routeInfo, responseBodyInfo, routeParams, rawRouteInfo, routeName) => {
|
|
767
|
+
if (
|
|
768
|
+
config.extractResponseError &&
|
|
769
|
+
responseBodyInfo.responses.length &&
|
|
770
|
+
responseBodyInfo.error.schemas &&
|
|
771
|
+
responseBodyInfo.error.schemas.length
|
|
772
|
+
) {
|
|
773
|
+
const typeName = config.componentTypeNameResolver.resolve([
|
|
774
|
+
classNameCase(`${routeName.usage} Error`),
|
|
775
|
+
classNameCase(`${routeName.usage} Fail`),
|
|
776
|
+
classNameCase(`${routeName.usage} Fails`),
|
|
777
|
+
classNameCase(`${routeName.usage} ErrorData`),
|
|
778
|
+
classNameCase(`${routeName.usage} HttpError`),
|
|
779
|
+
classNameCase(`${routeName.usage} BadResponse`),
|
|
780
|
+
]);
|
|
781
|
+
|
|
782
|
+
const errorSchemas = responseBodyInfo.error.schemas.map(getSchemaFromRequestType).filter(Boolean);
|
|
783
|
+
|
|
784
|
+
if (!errorSchemas.length) return;
|
|
785
|
+
|
|
786
|
+
const schema = parseSchema({
|
|
787
|
+
oneOf: errorSchemas,
|
|
788
|
+
title: errorSchemas
|
|
789
|
+
.map((schema) => schema.title)
|
|
790
|
+
.filter(Boolean)
|
|
791
|
+
.join(" "),
|
|
792
|
+
description: errorSchemas
|
|
793
|
+
.map((schema) => schema.description)
|
|
794
|
+
.filter(Boolean)
|
|
795
|
+
.join("\n"),
|
|
796
|
+
});
|
|
797
|
+
const component = createComponent("schemas", typeName, { ...schema });
|
|
798
|
+
responseBodyInfo.error.schemas = [component];
|
|
799
|
+
responseBodyInfo.error.type = formatModelName(component.typeName);
|
|
800
|
+
}
|
|
801
|
+
};
|
|
802
|
+
|
|
791
803
|
module.exports = {
|
|
792
804
|
parseRoutes,
|
|
793
805
|
groupRoutes,
|
package/src/schema.js
CHANGED
|
@@ -63,12 +63,7 @@ const getTypeAlias = (rawSchema) => {
|
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
const getEnumNames = (schema) => {
|
|
66
|
-
return
|
|
67
|
-
schema["x-enumNames"] ||
|
|
68
|
-
schema["xEnumNames"] ||
|
|
69
|
-
schema["x-enumnames"] ||
|
|
70
|
-
schema["x-enum-varnames"]
|
|
71
|
-
);
|
|
66
|
+
return schema["x-enumNames"] || schema["xEnumNames"] || schema["x-enumnames"] || schema["x-enum-varnames"];
|
|
72
67
|
};
|
|
73
68
|
|
|
74
69
|
const getInternalSchemaType = (schema) => {
|
|
@@ -137,29 +132,36 @@ const getObjectTypeContent = (schema) => {
|
|
|
137
132
|
const nullable = !!(rawTypeData.nullable || property.nullable);
|
|
138
133
|
const fieldName = isValidName(name) ? name : `"${name}"`;
|
|
139
134
|
const fieldValue = getInlineParseContent(property);
|
|
135
|
+
const readOnly = property.readOnly;
|
|
140
136
|
|
|
141
137
|
return {
|
|
142
138
|
$$raw: property,
|
|
139
|
+
title: property.title,
|
|
143
140
|
description: _.compact([
|
|
144
141
|
property.description ||
|
|
145
142
|
_.compact(_.map(property[getComplexType(property)], "description"))[0] ||
|
|
146
143
|
rawTypeData.description ||
|
|
147
144
|
_.compact(_.map(rawTypeData[getComplexType(rawTypeData)], "description"))[0] ||
|
|
148
145
|
"",
|
|
146
|
+
!_.isUndefined(property.deprecated) && `@deprecated`,
|
|
149
147
|
!_.isUndefined(property.format) && `@format ${property.format}`,
|
|
150
148
|
!_.isUndefined(property.minimum) && `@min ${property.minimum}`,
|
|
151
149
|
!_.isUndefined(property.maximum) && `@max ${property.maximum}`,
|
|
152
150
|
!_.isUndefined(property.pattern) && `@pattern ${property.pattern}`,
|
|
153
151
|
!_.isUndefined(property.example) &&
|
|
154
|
-
`@example ${
|
|
155
|
-
_.isObject(property.example) ? JSON.stringify(property.example) : property.example
|
|
156
|
-
}`,
|
|
152
|
+
`@example ${_.isObject(property.example) ? JSON.stringify(property.example) : property.example}`,
|
|
157
153
|
]).join("\n"),
|
|
158
154
|
isRequired: required,
|
|
159
155
|
isNullable: nullable,
|
|
160
156
|
name: fieldName,
|
|
161
157
|
value: fieldValue,
|
|
162
|
-
field: _.compact([
|
|
158
|
+
field: _.compact([
|
|
159
|
+
readOnly && config.addReadonly && "readonly ",
|
|
160
|
+
fieldName,
|
|
161
|
+
!required && "?",
|
|
162
|
+
": ",
|
|
163
|
+
fieldValue,
|
|
164
|
+
]).join(""),
|
|
163
165
|
};
|
|
164
166
|
});
|
|
165
167
|
|
|
@@ -178,39 +180,73 @@ const getObjectTypeContent = (schema) => {
|
|
|
178
180
|
const complexTypeGetter = (schema) => getInlineParseContent(schema);
|
|
179
181
|
const filterContents = (contents, types) => _.filter(contents, (type) => !_.includes(types, type));
|
|
180
182
|
|
|
183
|
+
const makeAddRequiredToChildSchema = (parentSchema) => (childSchema) => {
|
|
184
|
+
let required = childSchema.required || [];
|
|
185
|
+
let properties = childSchema.properties || {};
|
|
186
|
+
|
|
187
|
+
// Inherit all the required fields from the parent schema that are defined
|
|
188
|
+
// either on the parent schema or on the child schema
|
|
189
|
+
// TODO: any that are defined at grandparents or higher are ignored
|
|
190
|
+
required = required.concat(
|
|
191
|
+
(parentSchema.required || []).filter(
|
|
192
|
+
(key) =>
|
|
193
|
+
!required.includes(key) && (_.keys(properties).includes(key) || _.keys(parentSchema.properties).includes(key)),
|
|
194
|
+
),
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
// Identify properties that are required in the child schema, but
|
|
198
|
+
// defined only in the parent schema (TODO: this only works one level deep)
|
|
199
|
+
const parentPropertiesRequiredByChild = required.filter(
|
|
200
|
+
(key) => !_.keys(childSchema.properties).includes(key) && _.keys(parentSchema.properties).includes(key),
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
// Add such properties to the child so that they can be overriden and made required
|
|
204
|
+
properties = {
|
|
205
|
+
...properties,
|
|
206
|
+
...parentPropertiesRequiredByChild.reduce(
|
|
207
|
+
(additionalProperties, key) => ({
|
|
208
|
+
...additionalProperties,
|
|
209
|
+
[key]: (parentSchema.properties || {})[key],
|
|
210
|
+
}),
|
|
211
|
+
{},
|
|
212
|
+
),
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
return _.merge(
|
|
216
|
+
{
|
|
217
|
+
required: required,
|
|
218
|
+
properties: properties,
|
|
219
|
+
},
|
|
220
|
+
childSchema,
|
|
221
|
+
);
|
|
222
|
+
};
|
|
223
|
+
|
|
181
224
|
const complexSchemaParsers = {
|
|
182
225
|
[SCHEMA_TYPES.COMPLEX_ONE_OF]: (schema) => {
|
|
183
226
|
// T1 | T2
|
|
184
|
-
const combined = _.map(schema.oneOf, complexTypeGetter);
|
|
227
|
+
const combined = _.map(_.map(schema.oneOf, makeAddRequiredToChildSchema(schema)), complexTypeGetter);
|
|
185
228
|
|
|
186
229
|
return checkAndAddNull(schema, filterContents(combined, [TS_KEYWORDS.ANY]).join(" | "));
|
|
187
230
|
},
|
|
188
231
|
[SCHEMA_TYPES.COMPLEX_ALL_OF]: (schema) => {
|
|
189
232
|
// T1 & T2
|
|
190
|
-
const combined = _.map(schema.allOf, complexTypeGetter);
|
|
233
|
+
const combined = _.map(_.map(schema.allOf, makeAddRequiredToChildSchema(schema)), complexTypeGetter);
|
|
191
234
|
return checkAndAddNull(
|
|
192
235
|
schema,
|
|
193
|
-
filterContents(combined, [...JS_EMPTY_TYPES, ...JS_PRIMITIVE_TYPES, TS_KEYWORDS.ANY]).join(
|
|
194
|
-
" & ",
|
|
195
|
-
),
|
|
236
|
+
filterContents(combined, [...JS_EMPTY_TYPES, ...JS_PRIMITIVE_TYPES, TS_KEYWORDS.ANY]).join(" & "),
|
|
196
237
|
);
|
|
197
238
|
},
|
|
198
239
|
[SCHEMA_TYPES.COMPLEX_ANY_OF]: (schema) => {
|
|
199
240
|
// T1 | T2 | (T1 & T2)
|
|
200
|
-
const combined = _.map(schema.anyOf, complexTypeGetter);
|
|
201
|
-
const nonEmptyTypesCombined = filterContents(combined, [
|
|
202
|
-
...JS_EMPTY_TYPES,
|
|
203
|
-
...JS_PRIMITIVE_TYPES,
|
|
204
|
-
TS_KEYWORDS.ANY,
|
|
205
|
-
]);
|
|
241
|
+
const combined = _.map(_.map(schema.anyOf, makeAddRequiredToChildSchema(schema)), complexTypeGetter);
|
|
242
|
+
const nonEmptyTypesCombined = filterContents(combined, [...JS_EMPTY_TYPES, ...JS_PRIMITIVE_TYPES, TS_KEYWORDS.ANY]);
|
|
206
243
|
return checkAndAddNull(
|
|
207
244
|
schema,
|
|
208
|
-
`${combined.join(" | ")}` +
|
|
209
|
-
(nonEmptyTypesCombined.length > 1 ? ` | (${nonEmptyTypesCombined.join(" & ")})` : ""),
|
|
245
|
+
`${combined.join(" | ")}` + (nonEmptyTypesCombined.length > 1 ? ` | (${nonEmptyTypesCombined.join(" & ")})` : ""),
|
|
210
246
|
);
|
|
211
247
|
},
|
|
212
248
|
// TODO
|
|
213
|
-
[SCHEMA_TYPES.
|
|
249
|
+
[SCHEMA_TYPES.COMPLEX_NOT]: (schema) => {
|
|
214
250
|
// TODO
|
|
215
251
|
return TS_KEYWORDS.ANY;
|
|
216
252
|
},
|
|
@@ -227,8 +263,7 @@ const getComplexType = (schema) => {
|
|
|
227
263
|
};
|
|
228
264
|
|
|
229
265
|
const attachParsedRef = (originalSchema, parsedSchema) => {
|
|
230
|
-
const parsedSchemaAfterHook =
|
|
231
|
-
config.hooks.onParseSchema(originalSchema, parsedSchema) || parsedSchema;
|
|
266
|
+
const parsedSchemaAfterHook = config.hooks.onParseSchema(originalSchema, parsedSchema) || parsedSchema;
|
|
232
267
|
|
|
233
268
|
if (originalSchema) {
|
|
234
269
|
originalSchema.$parsed = parsedSchemaAfterHook;
|
|
@@ -263,12 +298,7 @@ const schemaParsers = {
|
|
|
263
298
|
return {
|
|
264
299
|
key: formattedKey,
|
|
265
300
|
type: keyType,
|
|
266
|
-
value:
|
|
267
|
-
enumValue === null
|
|
268
|
-
? enumValue
|
|
269
|
-
: isIntegerOrBooleanEnum
|
|
270
|
-
? `${enumValue}`
|
|
271
|
-
: `"${enumValue}"`,
|
|
301
|
+
value: enumValue === null ? enumValue : isIntegerOrBooleanEnum ? `${enumValue}` : `"${enumValue}"`,
|
|
272
302
|
};
|
|
273
303
|
});
|
|
274
304
|
} else {
|
|
@@ -290,9 +320,7 @@ const schemaParsers = {
|
|
|
290
320
|
type: SCHEMA_TYPES.ENUM,
|
|
291
321
|
keyType: keyType,
|
|
292
322
|
typeIdentifier:
|
|
293
|
-
config.generateUnionEnums || (!enumNames && isIntegerOrBooleanEnum)
|
|
294
|
-
? TS_KEYWORDS.TYPE
|
|
295
|
-
: TS_KEYWORDS.ENUM,
|
|
323
|
+
config.generateUnionEnums || (!enumNames && isIntegerOrBooleanEnum) ? TS_KEYWORDS.TYPE : TS_KEYWORDS.ENUM,
|
|
296
324
|
name: typeName,
|
|
297
325
|
description: formatDescription(schema.description),
|
|
298
326
|
content,
|
|
@@ -331,8 +359,7 @@ const schemaParsers = {
|
|
|
331
359
|
content:
|
|
332
360
|
_.compact([
|
|
333
361
|
complexSchemaContent && `(${complexSchemaContent})`,
|
|
334
|
-
getInternalSchemaType(simpleSchema) === TS_KEYWORDS.OBJECT &&
|
|
335
|
-
getInlineParseContent(simpleSchema),
|
|
362
|
+
getInternalSchemaType(simpleSchema) === TS_KEYWORDS.OBJECT && getInlineParseContent(simpleSchema),
|
|
336
363
|
]).join(" & ") || TS_KEYWORDS.ANY,
|
|
337
364
|
});
|
|
338
365
|
},
|
|
@@ -400,10 +427,7 @@ const parseSchema = (rawSchema, typeName, formattersMap) => {
|
|
|
400
427
|
parsedSchema = schemaParsers[schemaType](fixedRawSchema, typeName);
|
|
401
428
|
}
|
|
402
429
|
|
|
403
|
-
return (
|
|
404
|
-
(formattersMap && formattersMap[schemaType] && formattersMap[schemaType](parsedSchema)) ||
|
|
405
|
-
parsedSchema
|
|
406
|
-
);
|
|
430
|
+
return (formattersMap && formattersMap[schemaType] && formattersMap[schemaType](parsedSchema)) || parsedSchema;
|
|
407
431
|
};
|
|
408
432
|
|
|
409
433
|
const parseSchemas = (components) =>
|
|
@@ -412,8 +436,7 @@ const parseSchemas = (components) =>
|
|
|
412
436
|
const getInlineParseContent = (rawTypeData, typeName = null) =>
|
|
413
437
|
parseSchema(rawTypeData, typeName, inlineExtraFormatters).content;
|
|
414
438
|
|
|
415
|
-
const getParseContent = (rawTypeData, typeName = null) =>
|
|
416
|
-
parseSchema(rawTypeData, typeName).content;
|
|
439
|
+
const getParseContent = (rawTypeData, typeName = null) => parseSchema(rawTypeData, typeName).content;
|
|
417
440
|
|
|
418
441
|
module.exports = {
|
|
419
442
|
types,
|