swagger-typescript-api 11.1.2 → 12.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/README.md +23 -5
- package/index.d.ts +67 -3
- package/index.js +6 -1
- package/package.json +6 -2
- package/src/code-gen-process.js +12 -14
- package/src/configuration.js +27 -4
- package/src/schema-parser/schema-formatters.js +26 -19
- package/src/schema-parser/schema-parser.js +131 -204
- package/src/schema-parser/schema-routes.js +113 -53
- package/src/schema-parser/schema-utils.js +165 -0
- package/src/templates.js +2 -2
- package/src/type-name.js +49 -30
- package/src/util/logger.js +19 -1
- package/src/util/name-resolver.js +50 -31
- package/templates/base/enum-data-contract.ejs +1 -4
- package/templates/base/http-clients/axios-http-client.ejs +5 -0
- package/templates/base/http-clients/fetch-http-client.ejs +2 -0
- package/templates/default/procedure-call.ejs +1 -0
- package/templates/modular/procedure-call.ejs +1 -0
|
@@ -16,6 +16,7 @@ const CONTENT_KIND = {
|
|
|
16
16
|
FORM_DATA: "FORM_DATA",
|
|
17
17
|
IMAGE: "IMAGE",
|
|
18
18
|
OTHER: "OTHER",
|
|
19
|
+
TEXT: "TEXT",
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
class SchemaRoutes {
|
|
@@ -27,6 +28,10 @@ class SchemaRoutes {
|
|
|
27
28
|
* @type {SchemaParser}
|
|
28
29
|
*/
|
|
29
30
|
schemaParser;
|
|
31
|
+
/**
|
|
32
|
+
* @type {SchemaUtils}
|
|
33
|
+
*/
|
|
34
|
+
schemaUtils;
|
|
30
35
|
/**
|
|
31
36
|
* @type {TypeName}
|
|
32
37
|
*/
|
|
@@ -54,14 +59,15 @@ class SchemaRoutes {
|
|
|
54
59
|
constructor(config, schemaParser, schemaComponentMap, logger, templates, typeName) {
|
|
55
60
|
this.config = config;
|
|
56
61
|
this.schemaParser = schemaParser;
|
|
62
|
+
this.schemaUtils = this.schemaParser.schemaUtils;
|
|
57
63
|
this.typeName = typeName;
|
|
58
64
|
this.schemaComponentMap = schemaComponentMap;
|
|
59
65
|
this.logger = logger;
|
|
60
66
|
this.templates = templates;
|
|
61
67
|
|
|
62
68
|
this.FORM_DATA_TYPES = _.uniq([
|
|
63
|
-
this.schemaParser.
|
|
64
|
-
this.schemaParser.
|
|
69
|
+
this.schemaParser.getSchemaType({ type: "string", format: "file" }),
|
|
70
|
+
this.schemaParser.getSchemaType({ type: "string", format: "binary" }),
|
|
65
71
|
]);
|
|
66
72
|
}
|
|
67
73
|
|
|
@@ -86,7 +92,9 @@ class SchemaRoutes {
|
|
|
86
92
|
);
|
|
87
93
|
};
|
|
88
94
|
|
|
89
|
-
parseRouteName = (
|
|
95
|
+
parseRouteName = (originalRouteName) => {
|
|
96
|
+
const routeName = this.config.hooks.onPreBuildRoutePath(originalRouteName) || originalRouteName;
|
|
97
|
+
|
|
90
98
|
const pathParamMatches = (routeName || "").match(
|
|
91
99
|
/({(([a-zA-Z]-?_?\.?){1,})([0-9]{1,})?})|(:(([a-zA-Z]-?_?\.?){1,})([0-9]{1,})?:?)/g,
|
|
92
100
|
);
|
|
@@ -103,40 +111,75 @@ class SchemaRoutes {
|
|
|
103
111
|
this.logger.warn("wrong path param name", paramName);
|
|
104
112
|
}
|
|
105
113
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
114
|
+
pathParams.push({
|
|
115
|
+
$match: match,
|
|
116
|
+
name: _.camelCase(paramName),
|
|
117
|
+
required: true,
|
|
118
|
+
type: "string",
|
|
119
|
+
description: "",
|
|
120
|
+
schema: {
|
|
112
121
|
type: "string",
|
|
113
|
-
description: "",
|
|
114
|
-
schema: {
|
|
115
|
-
type: "string",
|
|
116
|
-
},
|
|
117
|
-
in: "path",
|
|
118
122
|
},
|
|
119
|
-
|
|
123
|
+
in: "path",
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return pathParams;
|
|
120
127
|
},
|
|
121
128
|
[],
|
|
122
129
|
);
|
|
123
130
|
|
|
124
|
-
|
|
131
|
+
let fixedRoute = _.reduce(
|
|
125
132
|
pathParams,
|
|
126
|
-
(fixedRoute, pathParam) => {
|
|
127
|
-
|
|
133
|
+
(fixedRoute, pathParam, i, arr) => {
|
|
134
|
+
const insertion = this.config.hooks.onInsertPathParam(pathParam.name, i, arr, fixedRoute) || pathParam.name;
|
|
135
|
+
return _.replace(fixedRoute, pathParam.$match, `\${${insertion}}`);
|
|
128
136
|
},
|
|
129
137
|
routeName || "",
|
|
130
138
|
);
|
|
131
139
|
|
|
132
|
-
|
|
133
|
-
|
|
140
|
+
const queryParamMatches = fixedRoute.match(/(\{\?.*\})/g);
|
|
141
|
+
const queryParams = [];
|
|
142
|
+
|
|
143
|
+
if (queryParamMatches && queryParamMatches.length) {
|
|
144
|
+
queryParamMatches.forEach((match) => {
|
|
145
|
+
fixedRoute = fixedRoute.replace(match, "");
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
_.uniq(
|
|
149
|
+
queryParamMatches
|
|
150
|
+
.join(",")
|
|
151
|
+
.replace(/(\{\?)|(\})|\s/g, "")
|
|
152
|
+
.split(","),
|
|
153
|
+
).forEach((paramName) => {
|
|
154
|
+
if (_.includes(paramName, "-")) {
|
|
155
|
+
this.logger.warn("wrong query param name", paramName);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
queryParams.push({
|
|
159
|
+
$match: paramName,
|
|
160
|
+
name: _.camelCase(paramName),
|
|
161
|
+
required: true,
|
|
162
|
+
type: "string",
|
|
163
|
+
description: "",
|
|
164
|
+
schema: {
|
|
165
|
+
type: "string",
|
|
166
|
+
},
|
|
167
|
+
in: "query",
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const result = {
|
|
173
|
+
originalRoute: originalRouteName || "",
|
|
134
174
|
route: fixedRoute,
|
|
135
175
|
pathParams,
|
|
176
|
+
queryParams,
|
|
136
177
|
};
|
|
178
|
+
|
|
179
|
+
return this.config.hooks.onBuildRoutePath(result) || result;
|
|
137
180
|
};
|
|
138
181
|
|
|
139
|
-
getRouteParams = (routeInfo,
|
|
182
|
+
getRouteParams = (routeInfo, pathParamsFromRouteName, queryParamsFromRouteName) => {
|
|
140
183
|
const { parameters } = routeInfo;
|
|
141
184
|
|
|
142
185
|
const routeParams = {
|
|
@@ -149,7 +192,7 @@ class SchemaRoutes {
|
|
|
149
192
|
};
|
|
150
193
|
|
|
151
194
|
_.each(parameters, (parameter) => {
|
|
152
|
-
const refTypeInfo = this.schemaParser.
|
|
195
|
+
const refTypeInfo = this.schemaParser.schemaUtils.getSchemaRefType(parameter);
|
|
153
196
|
let routeParam = null;
|
|
154
197
|
|
|
155
198
|
if (refTypeInfo && refTypeInfo.rawTypeData.in && refTypeInfo.rawTypeData) {
|
|
@@ -186,13 +229,21 @@ class SchemaRoutes {
|
|
|
186
229
|
});
|
|
187
230
|
|
|
188
231
|
// used in case when path parameters is not declared in requestInfo.parameters ("in": "path")
|
|
189
|
-
_.each(
|
|
232
|
+
_.each(pathParamsFromRouteName, (pathParam) => {
|
|
190
233
|
const alreadyExist = _.some(routeParams.path, (parameter) => parameter.name === pathParam.name);
|
|
191
234
|
|
|
192
235
|
if (!alreadyExist) {
|
|
193
236
|
routeParams.path.push(pathParam);
|
|
194
237
|
}
|
|
195
238
|
});
|
|
239
|
+
// used in case when path parameters is not declared in requestInfo.parameters ("in": "path")
|
|
240
|
+
_.each(queryParamsFromRouteName, (queryParam) => {
|
|
241
|
+
const alreadyExist = _.some(routeParams.query, (parameter) => parameter.name === queryParam.name);
|
|
242
|
+
|
|
243
|
+
if (!alreadyExist) {
|
|
244
|
+
routeParams.query.push(queryParam);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
196
247
|
|
|
197
248
|
return routeParams;
|
|
198
249
|
};
|
|
@@ -207,7 +258,7 @@ class SchemaRoutes {
|
|
|
207
258
|
|
|
208
259
|
getContentKind = (contentTypes) => {
|
|
209
260
|
if (
|
|
210
|
-
_.
|
|
261
|
+
_.some(contentTypes, (contentType) => _.startsWith(contentType, "application/json")) ||
|
|
211
262
|
_.some(contentTypes, (contentType) => _.endsWith(contentType, "+json"))
|
|
212
263
|
) {
|
|
213
264
|
return CONTENT_KIND.JSON;
|
|
@@ -225,6 +276,10 @@ class SchemaRoutes {
|
|
|
225
276
|
return CONTENT_KIND.IMAGE;
|
|
226
277
|
}
|
|
227
278
|
|
|
279
|
+
if (_.some(contentTypes, (contentType) => _.startsWith(contentType, "text/"))) {
|
|
280
|
+
return CONTENT_KIND.TEXT;
|
|
281
|
+
}
|
|
282
|
+
|
|
228
283
|
return CONTENT_KIND.OTHER;
|
|
229
284
|
};
|
|
230
285
|
|
|
@@ -256,7 +311,7 @@ class SchemaRoutes {
|
|
|
256
311
|
getTypeFromRequestInfo = ({ requestInfo, parsedSchemas, operationId, defaultType, typeName }) => {
|
|
257
312
|
// TODO: make more flexible pick schema without content type
|
|
258
313
|
const schema = this.getSchemaFromRequestType(requestInfo);
|
|
259
|
-
const refTypeInfo = this.schemaParser.
|
|
314
|
+
const refTypeInfo = this.schemaParser.schemaUtils.getSchemaRefType(requestInfo);
|
|
260
315
|
|
|
261
316
|
if (schema) {
|
|
262
317
|
const content = this.schemaParser.getInlineParseContent(schema, typeName);
|
|
@@ -310,7 +365,7 @@ class SchemaRoutes {
|
|
|
310
365
|
...(requestInfo || {}),
|
|
311
366
|
contentTypes: contentTypes,
|
|
312
367
|
contentKind: this.getContentKind(contentTypes),
|
|
313
|
-
type: this.schemaParser.
|
|
368
|
+
type: this.schemaParser.schemaUtils.safeAddNullToType(
|
|
314
369
|
requestInfo,
|
|
315
370
|
this.getTypeFromRequestInfo({
|
|
316
371
|
requestInfo,
|
|
@@ -351,7 +406,7 @@ class SchemaRoutes {
|
|
|
351
406
|
}
|
|
352
407
|
const headerTypes = Object.fromEntries(
|
|
353
408
|
Object.entries(src).map(([k, v]) => {
|
|
354
|
-
return [k, this.schemaParser.
|
|
409
|
+
return [k, this.schemaParser.getSchemaType(v)];
|
|
355
410
|
}),
|
|
356
411
|
);
|
|
357
412
|
const r = `headers: { ${Object.entries(headerTypes)
|
|
@@ -420,11 +475,11 @@ class SchemaRoutes {
|
|
|
420
475
|
let typeName = null;
|
|
421
476
|
|
|
422
477
|
if (this.config.extractRequestBody) {
|
|
423
|
-
typeName = this.
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
478
|
+
typeName = this.schemaUtils.resolveTypeName(
|
|
479
|
+
routeName.usage,
|
|
480
|
+
this.config.extractingOptions.requestBodySuffix,
|
|
481
|
+
this.config.extractingOptions.requestBodyNameResolver,
|
|
482
|
+
);
|
|
428
483
|
}
|
|
429
484
|
|
|
430
485
|
if (routeParams.formData.length) {
|
|
@@ -436,7 +491,7 @@ class SchemaRoutes {
|
|
|
436
491
|
type = this.schemaParser.getInlineParseContent(schema, typeName);
|
|
437
492
|
} else if (requestBody) {
|
|
438
493
|
schema = this.getSchemaFromRequestType(requestBody);
|
|
439
|
-
type = this.schemaParser.
|
|
494
|
+
type = this.schemaParser.schemaUtils.safeAddNullToType(
|
|
440
495
|
requestBody,
|
|
441
496
|
this.getTypeFromRequestInfo({
|
|
442
497
|
requestInfo: requestBody,
|
|
@@ -521,7 +576,11 @@ class SchemaRoutes {
|
|
|
521
576
|
if (fixedSchema) return fixedSchema;
|
|
522
577
|
|
|
523
578
|
if (extractRequestParams) {
|
|
524
|
-
const typeName = this.
|
|
579
|
+
const typeName = this.schemaUtils.resolveTypeName(
|
|
580
|
+
routeName.usage,
|
|
581
|
+
this.config.extractingOptions.requestParamsSuffix,
|
|
582
|
+
this.config.extractingOptions.requestParamsNameResolver,
|
|
583
|
+
);
|
|
525
584
|
|
|
526
585
|
return this.schemaComponentMap.createComponent("schemas", typeName, { ...schema });
|
|
527
586
|
}
|
|
@@ -531,11 +590,11 @@ class SchemaRoutes {
|
|
|
531
590
|
|
|
532
591
|
extractResponseBodyIfItNeeded = (routeInfo, responseBodyInfo, routeName) => {
|
|
533
592
|
if (responseBodyInfo.responses.length && responseBodyInfo.success && responseBodyInfo.success.schema) {
|
|
534
|
-
const typeName = this.
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
593
|
+
const typeName = this.schemaUtils.resolveTypeName(
|
|
594
|
+
routeName.usage,
|
|
595
|
+
this.config.extractingOptions.responseBodySuffix,
|
|
596
|
+
this.config.extractingOptions.responseBodyNameResolver,
|
|
597
|
+
);
|
|
539
598
|
|
|
540
599
|
const idx = responseBodyInfo.responses.indexOf(responseBodyInfo.success.schema);
|
|
541
600
|
|
|
@@ -558,14 +617,11 @@ class SchemaRoutes {
|
|
|
558
617
|
|
|
559
618
|
extractResponseErrorIfItNeeded = (routeInfo, responseBodyInfo, routeName) => {
|
|
560
619
|
if (responseBodyInfo.responses.length && responseBodyInfo.error.schemas && responseBodyInfo.error.schemas.length) {
|
|
561
|
-
const typeName = this.
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
pascalCase(`${routeName.usage} HttpError`),
|
|
567
|
-
pascalCase(`${routeName.usage} BadResponse`),
|
|
568
|
-
]);
|
|
620
|
+
const typeName = this.schemaUtils.resolveTypeName(
|
|
621
|
+
routeName.usage,
|
|
622
|
+
this.config.extractingOptions.responseErrorSuffix,
|
|
623
|
+
this.config.extractingOptions.responseErrorNameResolver,
|
|
624
|
+
);
|
|
569
625
|
|
|
570
626
|
const errorSchemas = responseBodyInfo.error.schemas.map(this.getSchemaFromRequestType).filter(Boolean);
|
|
571
627
|
|
|
@@ -642,7 +698,11 @@ class SchemaRoutes {
|
|
|
642
698
|
consumes,
|
|
643
699
|
...otherInfo
|
|
644
700
|
} = routeInfo;
|
|
645
|
-
const {
|
|
701
|
+
const {
|
|
702
|
+
route,
|
|
703
|
+
pathParams: pathParamsFromRouteName,
|
|
704
|
+
queryParams: queryParamsFromRouteName,
|
|
705
|
+
} = this.parseRouteName(rawRouteName);
|
|
646
706
|
|
|
647
707
|
const routeId = generateId();
|
|
648
708
|
const firstTag = tags && tags.length > 0 ? tags[0] : null;
|
|
@@ -655,7 +715,7 @@ class SchemaRoutes {
|
|
|
655
715
|
hasSecurity = security.length > 0;
|
|
656
716
|
}
|
|
657
717
|
|
|
658
|
-
const routeParams = this.getRouteParams(routeInfo,
|
|
718
|
+
const routeParams = this.getRouteParams(routeInfo, pathParamsFromRouteName, queryParamsFromRouteName);
|
|
659
719
|
|
|
660
720
|
const pathArgs = routeParams.path.map((pathArgSchema) => ({
|
|
661
721
|
name: pathArgSchema.name,
|
|
@@ -711,13 +771,13 @@ class SchemaRoutes {
|
|
|
711
771
|
const pathType = routeParams.path.length ? this.schemaParser.getInlineParseContent(pathObjectSchema) : null;
|
|
712
772
|
const headersType = routeParams.header.length ? this.schemaParser.getInlineParseContent(headersObjectSchema) : null;
|
|
713
773
|
|
|
714
|
-
const nameResolver = new SpecificArgNameResolver(pathArgsNames);
|
|
774
|
+
const nameResolver = new SpecificArgNameResolver(this.logger, pathArgsNames);
|
|
715
775
|
|
|
716
776
|
const specificArgs = {
|
|
717
777
|
query: queryType
|
|
718
778
|
? {
|
|
719
779
|
name: nameResolver.resolve(RESERVED_QUERY_ARG_NAMES),
|
|
720
|
-
optional: this.schemaParser.parseSchema(queryObjectSchema
|
|
780
|
+
optional: this.schemaParser.parseSchema(queryObjectSchema).allFieldsAreOptional,
|
|
721
781
|
type: queryType,
|
|
722
782
|
}
|
|
723
783
|
: void 0,
|
|
@@ -731,14 +791,14 @@ class SchemaRoutes {
|
|
|
731
791
|
pathParams: pathType
|
|
732
792
|
? {
|
|
733
793
|
name: nameResolver.resolve(RESERVED_PATH_ARG_NAMES),
|
|
734
|
-
optional: this.schemaParser.parseSchema(pathObjectSchema
|
|
794
|
+
optional: this.schemaParser.parseSchema(pathObjectSchema).allFieldsAreOptional,
|
|
735
795
|
type: pathType,
|
|
736
796
|
}
|
|
737
797
|
: void 0,
|
|
738
798
|
headers: headersType
|
|
739
799
|
? {
|
|
740
800
|
name: nameResolver.resolve(RESERVED_HEADER_ARG_NAMES),
|
|
741
|
-
optional: this.schemaParser.parseSchema(headersObjectSchema
|
|
801
|
+
optional: this.schemaParser.parseSchema(headersObjectSchema).allFieldsAreOptional,
|
|
742
802
|
type: headersType,
|
|
743
803
|
}
|
|
744
804
|
: void 0,
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
const _ = require("lodash");
|
|
2
|
+
const { SCHEMA_TYPES } = require("../constants");
|
|
3
|
+
const { internalCase } = require("../util/internal-case");
|
|
4
|
+
const { pascalCase } = require("../util/pascal-case");
|
|
5
|
+
|
|
6
|
+
class SchemaUtils {
|
|
7
|
+
/**
|
|
8
|
+
* @type {CodeGenConfig}
|
|
9
|
+
*/
|
|
10
|
+
config;
|
|
11
|
+
/**
|
|
12
|
+
* @type {SchemaComponentsMap}
|
|
13
|
+
*/
|
|
14
|
+
schemaComponentsMap;
|
|
15
|
+
|
|
16
|
+
constructor(config, schemaComponentsMap) {
|
|
17
|
+
this.config = config;
|
|
18
|
+
this.schemaComponentsMap = schemaComponentsMap;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getRequiredProperties = (schema) => {
|
|
22
|
+
return _.uniq((schema && _.isArray(schema.required) && schema.required) || []);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
isRefSchema = (schema) => {
|
|
26
|
+
return !!(schema && schema["$ref"]);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
getEnumNames = (schema) => {
|
|
30
|
+
return schema["x-enumNames"] || schema["xEnumNames"] || schema["x-enumnames"] || schema["x-enum-varnames"];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
getSchemaRefType = (schema) => {
|
|
34
|
+
if (!this.isRefSchema(schema)) return null;
|
|
35
|
+
return this.schemaComponentsMap.get(schema.$ref);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
isPropertyRequired = (name, propertySchema, rootSchema) => {
|
|
39
|
+
if (propertySchema["x-omitempty"] === false) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const isRequired = _.isBoolean(propertySchema.required)
|
|
44
|
+
? !!propertySchema.required
|
|
45
|
+
: _.isArray(rootSchema.required)
|
|
46
|
+
? rootSchema.required.includes(name)
|
|
47
|
+
: !!rootSchema.required;
|
|
48
|
+
|
|
49
|
+
if (this.config.convertedFromSwagger2) {
|
|
50
|
+
return typeof propertySchema.nullable === this.config.Ts.Keyword.Undefined
|
|
51
|
+
? isRequired
|
|
52
|
+
: !propertySchema.nullable;
|
|
53
|
+
}
|
|
54
|
+
return isRequired;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
isNullMissingInType = (schema, type) => {
|
|
58
|
+
const { nullable, type: schemaType } = schema || {};
|
|
59
|
+
return (
|
|
60
|
+
(nullable || !!_.get(schema, "x-nullable") || schemaType === this.config.Ts.Keyword.Null) &&
|
|
61
|
+
_.isString(type) &&
|
|
62
|
+
!type.includes(` ${this.config.Ts.Keyword.Null}`) &&
|
|
63
|
+
!type.includes(`${this.config.Ts.Keyword.Null} `)
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
safeAddNullToType = (schema, type) => {
|
|
68
|
+
if (this.isNullMissingInType(schema, type)) {
|
|
69
|
+
return this.config.Ts.UnionType([type, this.config.Ts.Keyword.Null]);
|
|
70
|
+
}
|
|
71
|
+
return type;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
getSchemaPrimitiveType = (rawSchema) => {
|
|
75
|
+
const schema = rawSchema || {};
|
|
76
|
+
|
|
77
|
+
if (schema.type) {
|
|
78
|
+
return internalCase(schema.type);
|
|
79
|
+
}
|
|
80
|
+
if (schema.enum) {
|
|
81
|
+
const enumFieldType = typeof schema.enum[0];
|
|
82
|
+
if (enumFieldType === this.config.Ts.Keyword.Undefined) return;
|
|
83
|
+
|
|
84
|
+
return internalCase(enumFieldType);
|
|
85
|
+
}
|
|
86
|
+
if (_.keys(schema.properties).length) {
|
|
87
|
+
return SCHEMA_TYPES.OBJECT;
|
|
88
|
+
}
|
|
89
|
+
if (!!schema.items) {
|
|
90
|
+
return SCHEMA_TYPES.ARRAY;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return null;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
checkAndAddRequiredKeys = (schema, resultType) => {
|
|
97
|
+
if ("$$requiredKeys" in schema && schema.$$requiredKeys.length) {
|
|
98
|
+
this.config.update({
|
|
99
|
+
internalTemplateOptions: {
|
|
100
|
+
addUtilRequiredKeysType: true,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
return this.config.Ts.TypeWithGeneric(this.config.Ts.CodeGenKeyword.UtilRequiredKeys, [
|
|
104
|
+
resultType,
|
|
105
|
+
this.config.Ts.UnionType(schema.$$requiredKeys.map(this.config.Ts.StringValue)),
|
|
106
|
+
]);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return resultType;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
makeAddRequiredToChildSchema = (parentSchema, childSchema) => {
|
|
113
|
+
if (!childSchema) return childSchema;
|
|
114
|
+
|
|
115
|
+
const required = _.uniq([...this.getRequiredProperties(parentSchema), ...this.getRequiredProperties(childSchema)]);
|
|
116
|
+
|
|
117
|
+
const refData = this.getSchemaRefType(childSchema);
|
|
118
|
+
|
|
119
|
+
if (refData) {
|
|
120
|
+
const refObjectProperties = _.keys((refData.rawTypeData && refData.rawTypeData.properties) || {});
|
|
121
|
+
const existedRequiredKeys = refObjectProperties.filter((key) => required.includes(key));
|
|
122
|
+
|
|
123
|
+
if (!existedRequiredKeys.length) return childSchema;
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
...childSchema,
|
|
127
|
+
$$requiredKeys: existedRequiredKeys,
|
|
128
|
+
};
|
|
129
|
+
} else if (childSchema.properties) {
|
|
130
|
+
const childSchemaProperties = _.keys(childSchema.properties);
|
|
131
|
+
const existedRequiredKeys = childSchemaProperties.filter((key) => required.includes(key));
|
|
132
|
+
|
|
133
|
+
if (!existedRequiredKeys.length) return childSchema;
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
required: _.uniq([...this.getRequiredProperties(childSchema), ...existedRequiredKeys]),
|
|
137
|
+
...childSchema,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return childSchema;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
filterSchemaContents = (contents, filterFn) => {
|
|
145
|
+
return _.uniq(_.filter(contents, (type) => filterFn(type)));
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
resolveTypeName = (typeName, suffixes, resolver) => {
|
|
149
|
+
if (resolver) {
|
|
150
|
+
return this.config.componentTypeNameResolver.resolve((reserved) => {
|
|
151
|
+
const variant = resolver(pascalCase(typeName), reserved);
|
|
152
|
+
if (variant == null) return variant;
|
|
153
|
+
return pascalCase(variant);
|
|
154
|
+
});
|
|
155
|
+
} else {
|
|
156
|
+
return this.config.componentTypeNameResolver.resolve(
|
|
157
|
+
suffixes.map((suffix) => pascalCase(`${typeName} ${suffix}`)),
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
module.exports = {
|
|
164
|
+
SchemaUtils,
|
|
165
|
+
};
|
package/src/templates.js
CHANGED
|
@@ -164,8 +164,8 @@ class Templates {
|
|
|
164
164
|
{
|
|
165
165
|
async: false,
|
|
166
166
|
...(options || {}),
|
|
167
|
-
includeFile: (path,
|
|
168
|
-
return this.renderTemplate(this.getTemplateContent(path),
|
|
167
|
+
includeFile: (path, configuration, options) => {
|
|
168
|
+
return this.renderTemplate(this.getTemplateContent(path), configuration, options);
|
|
169
169
|
},
|
|
170
170
|
},
|
|
171
171
|
);
|
package/src/type-name.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
const _ = require("lodash");
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {"enum-key" | "type-name"} FormattingSchemaType
|
|
5
|
+
*/
|
|
6
|
+
|
|
3
7
|
class TypeName {
|
|
4
8
|
/** @type {Map<string, string>} */
|
|
5
9
|
formattedModelNamesMap = new Map();
|
|
@@ -17,12 +21,20 @@ class TypeName {
|
|
|
17
21
|
|
|
18
22
|
/**
|
|
19
23
|
* @param name
|
|
20
|
-
* @param options {{
|
|
24
|
+
* @param options {{ type?: FormattingSchemaType }}
|
|
21
25
|
* @return {string}
|
|
22
26
|
*/
|
|
23
27
|
format = (name, options) => {
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
options = options || {};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @type {FormattingSchemaType}
|
|
32
|
+
*/
|
|
33
|
+
const schemaType = options.type || "type-name";
|
|
34
|
+
|
|
35
|
+
const typePrefix = schemaType === "enum-key" ? this.config.enumKeyPrefix : this.config.typePrefix;
|
|
36
|
+
const typeSuffix = schemaType === "enum-key" ? this.config.enumKeySuffix : this.config.typeSuffix;
|
|
37
|
+
|
|
26
38
|
const hashKey = `${typePrefix}_${name}_${typeSuffix}`;
|
|
27
39
|
|
|
28
40
|
if (typeof name !== "string") {
|
|
@@ -38,41 +50,48 @@ class TypeName {
|
|
|
38
50
|
return this.formattedModelNamesMap.get(hashKey);
|
|
39
51
|
}
|
|
40
52
|
|
|
41
|
-
const fixedModelName = fixModelName(name);
|
|
53
|
+
const fixedModelName = this.fixModelName(name, { type: schemaType });
|
|
42
54
|
|
|
43
|
-
const
|
|
44
|
-
const
|
|
55
|
+
const formattedName = _.replace(_.startCase(`${typePrefix}_${fixedModelName}_${typeSuffix}`), /\s/g, "");
|
|
56
|
+
const formattedResultName = this.config.hooks.onFormatTypeName(formattedName, name, schemaType) || formattedName;
|
|
45
57
|
|
|
46
|
-
this.formattedModelNamesMap.set(hashKey,
|
|
58
|
+
this.formattedModelNamesMap.set(hashKey, formattedResultName);
|
|
47
59
|
|
|
48
|
-
return
|
|
60
|
+
return formattedResultName;
|
|
49
61
|
};
|
|
50
62
|
|
|
51
|
-
isValidName =
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const isValidName = (name) => /^([A-Za-z$_]{1,})$/g.test(name);
|
|
63
|
+
isValidName = (name) => /^([A-Za-z$_]{1,})$/g.test(name);
|
|
55
64
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
65
|
+
/**
|
|
66
|
+
* @param name
|
|
67
|
+
* @param options {{ type?: FormattingSchemaType }}
|
|
68
|
+
* @return {string}
|
|
69
|
+
*/
|
|
70
|
+
fixModelName = (name, options) => {
|
|
71
|
+
if (!this.isValidName(name)) {
|
|
72
|
+
if (!/^[a-zA-Z_$]/g.test(name)) {
|
|
73
|
+
const fixPrefix =
|
|
74
|
+
options && options.type === "enum-key"
|
|
75
|
+
? this.config.fixInvalidEnumKeyPrefix
|
|
76
|
+
: this.config.fixInvalidTypeNamePrefix;
|
|
77
|
+
name = `${fixPrefix} ${name}`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// specific replaces for TSOA 3.x
|
|
81
|
+
if (name.includes("."))
|
|
82
|
+
name = name
|
|
83
|
+
.replace(/Exclude_keyof[A-Za-z]{1,}/g, (match) => "ExcludeKeys")
|
|
84
|
+
.replace(/%22\~AND\~%22/g, "And")
|
|
85
|
+
.replace(/%22\~OR\~%22/g, "Or")
|
|
86
|
+
.replace(/(\.?%22)|\./g, "_")
|
|
87
|
+
.replace(/__+$/, "");
|
|
88
|
+
|
|
89
|
+
if (name.includes("-")) name = _.startCase(name).replace(/ /g, "");
|
|
60
90
|
}
|
|
61
91
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
.replace(/Exclude_keyof[A-Za-z]{1,}/g, (match) => "ExcludeKeys")
|
|
66
|
-
.replace(/%22\~AND\~%22/g, "And")
|
|
67
|
-
.replace(/%22\~OR\~%22/g, "Or")
|
|
68
|
-
.replace(/(\.?%22)|\./g, "_")
|
|
69
|
-
.replace(/__+$/, "");
|
|
70
|
-
|
|
71
|
-
if (name.includes("-")) name = _.startCase(name).replace(/ /g, "");
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return name;
|
|
75
|
-
};
|
|
92
|
+
return name;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
76
95
|
|
|
77
96
|
module.exports = {
|
|
78
97
|
TypeName,
|
package/src/util/logger.js
CHANGED
|
@@ -12,7 +12,7 @@ class Logger {
|
|
|
12
12
|
this.config = config;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
createLogMessage = ({ type, emojiName, messages }) => {
|
|
15
|
+
createLogMessage = ({ type, emojiName, messages, raw }) => {
|
|
16
16
|
if (this.config.silent) return;
|
|
17
17
|
|
|
18
18
|
const emoji = emojify(emojiName);
|
|
@@ -26,6 +26,11 @@ class Logger {
|
|
|
26
26
|
);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
if (raw) {
|
|
30
|
+
console.log(...raw);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
29
34
|
console[type](
|
|
30
35
|
emoji,
|
|
31
36
|
" ",
|
|
@@ -93,6 +98,19 @@ class Logger {
|
|
|
93
98
|
emojiName: ":exclamation:",
|
|
94
99
|
messages,
|
|
95
100
|
});
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
*
|
|
104
|
+
* @param messages {any[]}
|
|
105
|
+
* @return {void}
|
|
106
|
+
*/
|
|
107
|
+
debug = (...messages) => {
|
|
108
|
+
if (!this.config.debug) return;
|
|
109
|
+
|
|
110
|
+
this.createLogMessage({
|
|
111
|
+
raw: messages,
|
|
112
|
+
});
|
|
113
|
+
};
|
|
96
114
|
}
|
|
97
115
|
|
|
98
116
|
module.exports = {
|