swagger-typescript-api 10.0.1 → 10.0.3
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/LICENSE +21 -21
- package/README.md +288 -262
- package/index.d.ts +11 -1
- package/index.js +2 -0
- package/package.json +119 -114
- package/src/components.js +3 -5
- package/src/config.js +6 -0
- package/src/constants.js +7 -0
- package/src/files.js +6 -6
- package/src/formatFileContent.js +13 -6
- package/src/index.js +8 -7
- package/src/logger.js +9 -0
- package/src/modelNames.js +1 -5
- package/src/modelTypes.js +7 -6
- package/src/output.js +22 -23
- package/src/render/utils/index.js +9 -1
- package/src/routes.js +4 -1
- package/src/schema.js +87 -64
- package/src/swagger.js +4 -1
- package/src/templates.js +46 -23
- package/src/translators/JavaScript.js +3 -14
- package/src/typeFormatters.js +81 -35
- package/src/utils/resolveName.js +1 -4
- package/templates/README.md +17 -13
- package/templates/base/README.md +7 -7
- package/templates/base/data-contract-jsdoc.ejs +32 -0
- package/templates/base/data-contracts.ejs +28 -0
- package/templates/base/enum-data-contract.ejs +15 -0
- package/templates/base/{http-client.eta → http-client.ejs} +2 -2
- package/templates/base/http-clients/{axios-http-client.eta → axios-http-client.ejs} +133 -145
- package/templates/base/http-clients/{fetch-http-client.eta → fetch-http-client.ejs} +222 -222
- package/templates/base/interface-data-contract.ejs +10 -0
- package/templates/base/object-field-jsdoc.ejs +28 -0
- package/templates/base/{route-docs.eta → route-docs.ejs} +30 -31
- package/templates/base/{route-name.eta → route-name.ejs} +42 -42
- package/templates/base/{route-type.eta → route-type.ejs} +21 -21
- package/templates/base/type-data-contract.ejs +15 -0
- package/templates/default/README.md +6 -6
- package/templates/default/{api.eta → api.ejs} +65 -65
- package/templates/default/{procedure-call.eta → procedure-call.ejs} +99 -99
- package/templates/default/{route-types.eta → route-types.ejs} +28 -28
- package/templates/modular/README.md +6 -6
- package/templates/modular/{api.eta → api.ejs} +28 -28
- package/templates/modular/{procedure-call.eta → procedure-call.ejs} +99 -99
- package/templates/modular/{route-types.eta → route-types.ejs} +18 -18
- package/CHANGELOG.md +0 -872
- package/templates/base/data-contracts.eta +0 -45
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
const { classNameCase, formatDescription, internalCase } = require("../../common");
|
|
2
2
|
const { getComponentByRef } = require("../../components");
|
|
3
3
|
const { formatModelName } = require("../../modelNames");
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
getInlineParseContent,
|
|
6
|
+
getParseContent,
|
|
7
|
+
parseSchema,
|
|
8
|
+
checkAndAddNull,
|
|
9
|
+
isNeedToAddNull,
|
|
10
|
+
} = require("../../schema");
|
|
5
11
|
const { formatters, inlineExtraFormatters } = require("../../typeFormatters");
|
|
6
12
|
const { NameResolver } = require("../../utils/resolveName");
|
|
7
13
|
|
|
@@ -14,6 +20,8 @@ module.exports = {
|
|
|
14
20
|
getComponentByRef,
|
|
15
21
|
parseSchema,
|
|
16
22
|
formatters,
|
|
23
|
+
checkAndAddNull,
|
|
24
|
+
isNeedToAddNull,
|
|
17
25
|
inlineExtraFormatters,
|
|
18
26
|
formatModelName,
|
|
19
27
|
fmtToJSDocLine: require("./fmtToJSDocLine"),
|
package/src/routes.js
CHANGED
|
@@ -520,7 +520,10 @@ const parseRoutes = ({ usageSchema, parsedSchemas, moduleNameIndex, moduleNameFi
|
|
|
520
520
|
moduleNameFirstTag && firstTag
|
|
521
521
|
? _.camelCase(firstTag)
|
|
522
522
|
: _.camelCase(_.compact(_.split(route, "/"))[moduleNameIndex]);
|
|
523
|
-
|
|
523
|
+
let hasSecurity = !!(globalSecurity && globalSecurity.length);
|
|
524
|
+
if (security) {
|
|
525
|
+
hasSecurity = security.length > 0;
|
|
526
|
+
}
|
|
524
527
|
|
|
525
528
|
const routeParams = getRouteParams(routeInfo, pathParams);
|
|
526
529
|
|
package/src/schema.js
CHANGED
|
@@ -74,6 +74,23 @@ const getInternalSchemaType = (schema) => {
|
|
|
74
74
|
return SCHEMA_TYPES.PRIMITIVE;
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
+
const isNeedToAddNull = (contract, value) => {
|
|
78
|
+
const { nullable, type } = contract || {};
|
|
79
|
+
return (
|
|
80
|
+
(nullable || !!_.get(contract, "x-nullable") || type === TS_KEYWORDS.NULL) &&
|
|
81
|
+
(!_.isString(value) || (!value.includes(` ${TS_KEYWORDS.NULL}`) && !value.includes(`${TS_KEYWORDS.NULL} `)))
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const checkAndAddRequiredKeys = (schema, resultType) => {
|
|
86
|
+
if ("$$requiredKeys" in schema && schema.$$requiredKeys.length) {
|
|
87
|
+
config.internalTemplateOptions.addUtilRequiredKeysType = true;
|
|
88
|
+
return `UtilRequiredKeys<${resultType}, ${schema.$$requiredKeys.map((k) => `"${k}"`).join(" | ")}>`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return resultType;
|
|
92
|
+
};
|
|
93
|
+
|
|
77
94
|
const checkAndAddNull = (schema, value) => {
|
|
78
95
|
const { nullable, type } = schema || {};
|
|
79
96
|
return (nullable || !!_.get(schema, "x-nullable") || type === TS_KEYWORDS.NULL) &&
|
|
@@ -88,9 +105,9 @@ const isRef = (property) => {
|
|
|
88
105
|
return !!(property && property["$ref"]);
|
|
89
106
|
};
|
|
90
107
|
|
|
91
|
-
const getRefType = (
|
|
92
|
-
const ref =
|
|
93
|
-
return
|
|
108
|
+
const getRefType = (schema) => {
|
|
109
|
+
const ref = schema && schema["$ref"];
|
|
110
|
+
return config.componentsMap[ref] || null;
|
|
94
111
|
};
|
|
95
112
|
|
|
96
113
|
const getType = (schema) => {
|
|
@@ -99,11 +116,11 @@ const getType = (schema) => {
|
|
|
99
116
|
const refTypeInfo = getRefType(schema);
|
|
100
117
|
|
|
101
118
|
if (refTypeInfo) {
|
|
102
|
-
return checkAndAddNull(schema, formatModelName(refTypeInfo.typeName));
|
|
119
|
+
return checkAndAddRequiredKeys(schema, checkAndAddNull(schema, formatModelName(refTypeInfo.typeName)));
|
|
103
120
|
}
|
|
104
121
|
|
|
105
122
|
const primitiveType = getTypeAlias(schema);
|
|
106
|
-
return primitiveType ? checkAndAddNull(schema, primitiveType) : TS_KEYWORDS.ANY;
|
|
123
|
+
return primitiveType ? checkAndAddRequiredKeys(schema, checkAndAddNull(schema, primitiveType)) : TS_KEYWORDS.ANY;
|
|
107
124
|
};
|
|
108
125
|
|
|
109
126
|
const isRequired = (property, name, requiredProperties) => {
|
|
@@ -177,73 +194,76 @@ const getObjectTypeContent = (schema) => {
|
|
|
177
194
|
return propertiesContent;
|
|
178
195
|
};
|
|
179
196
|
|
|
180
|
-
const
|
|
181
|
-
const filterContents = (contents, types) => _.filter(contents, (type) => !_.includes(types, type));
|
|
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
|
-
);
|
|
197
|
+
const filterContents = (contents, types) => _.uniq(_.filter(contents, (type) => !_.includes(types, type)));
|
|
196
198
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const parentPropertiesRequiredByChild = required.filter(
|
|
200
|
-
(key) => !_.keys(childSchema.properties).includes(key) && _.keys(parentSchema.properties).includes(key),
|
|
201
|
-
);
|
|
199
|
+
const makeAddRequiredToChildSchema = (parentSchema, childSchema) => {
|
|
200
|
+
if (!childSchema) return childSchema;
|
|
202
201
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
202
|
+
const required = _.uniq([...(parentSchema.required || []), ...(childSchema.required || [])]);
|
|
203
|
+
|
|
204
|
+
const refData = getRefType(childSchema);
|
|
205
|
+
|
|
206
|
+
if (refData) {
|
|
207
|
+
const refObjectProperties = _.keys((refData.rawTypeData && refData.rawTypeData.properties) || {});
|
|
208
|
+
const existedRequiredKeys = refObjectProperties.filter((key) => required.includes(key));
|
|
209
|
+
|
|
210
|
+
if (!existedRequiredKeys.length) return childSchema;
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
...childSchema,
|
|
214
|
+
$$requiredKeys: existedRequiredKeys,
|
|
215
|
+
};
|
|
216
|
+
} else if (childSchema.properties) {
|
|
217
|
+
const childSchemaProperties = _.keys(childSchema.properties);
|
|
218
|
+
const existedRequiredKeys = childSchemaProperties.filter((key) => required.includes(key));
|
|
219
|
+
|
|
220
|
+
if (!existedRequiredKeys.length) return childSchema;
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
required: _.uniq([...(childSchema.required || []), ...existedRequiredKeys]),
|
|
224
|
+
...childSchema,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return childSchema;
|
|
222
229
|
};
|
|
223
230
|
|
|
224
231
|
const complexSchemaParsers = {
|
|
232
|
+
// T1 | T2
|
|
225
233
|
[SCHEMA_TYPES.COMPLEX_ONE_OF]: (schema) => {
|
|
226
|
-
|
|
227
|
-
|
|
234
|
+
const combined = _.map(schema.oneOf, (childSchema) =>
|
|
235
|
+
getInlineParseContent(makeAddRequiredToChildSchema(schema, childSchema)),
|
|
236
|
+
);
|
|
237
|
+
const filtered = filterContents(combined, [TS_KEYWORDS.ANY]);
|
|
228
238
|
|
|
229
|
-
|
|
239
|
+
const type = filtered.join(" | ");
|
|
240
|
+
|
|
241
|
+
return checkAndAddNull(schema, type);
|
|
230
242
|
},
|
|
243
|
+
// T1 & T2
|
|
231
244
|
[SCHEMA_TYPES.COMPLEX_ALL_OF]: (schema) => {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
return checkAndAddNull(
|
|
235
|
-
schema,
|
|
236
|
-
filterContents(combined, [...JS_EMPTY_TYPES, ...JS_PRIMITIVE_TYPES, TS_KEYWORDS.ANY]).join(" & "),
|
|
245
|
+
const combined = _.map(schema.allOf, (childSchema) =>
|
|
246
|
+
getInlineParseContent(makeAddRequiredToChildSchema(schema, childSchema)),
|
|
237
247
|
);
|
|
248
|
+
const filtered = filterContents(combined, [...JS_PRIMITIVE_TYPES, TS_KEYWORDS.ANY]);
|
|
249
|
+
|
|
250
|
+
const type = filtered.join(TS_KEYWORDS.TYPE_AND_OPERATOR);
|
|
251
|
+
|
|
252
|
+
return checkAndAddNull(schema, type);
|
|
238
253
|
},
|
|
254
|
+
// T1 | T2 | (T1 & T2)
|
|
239
255
|
[SCHEMA_TYPES.COMPLEX_ANY_OF]: (schema) => {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const nonEmptyTypesCombined = filterContents(combined, [...JS_EMPTY_TYPES, ...JS_PRIMITIVE_TYPES, TS_KEYWORDS.ANY]);
|
|
243
|
-
return checkAndAddNull(
|
|
244
|
-
schema,
|
|
245
|
-
`${combined.join(" | ")}` + (nonEmptyTypesCombined.length > 1 ? ` | (${nonEmptyTypesCombined.join(" & ")})` : ""),
|
|
256
|
+
const combined = _.map(schema.anyOf, (childSchema) =>
|
|
257
|
+
getInlineParseContent(makeAddRequiredToChildSchema(schema, childSchema)),
|
|
246
258
|
);
|
|
259
|
+
const filtered = filterContents(combined, [...JS_PRIMITIVE_TYPES, TS_KEYWORDS.ANY]);
|
|
260
|
+
|
|
261
|
+
const type = _.compact([
|
|
262
|
+
...filtered,
|
|
263
|
+
filtered.length > 1 && `(${filtered.join(TS_KEYWORDS.TYPE_AND_OPERATOR)})`,
|
|
264
|
+
]).join(TS_KEYWORDS.TYPE_OR_OPERATOR);
|
|
265
|
+
|
|
266
|
+
return checkAndAddNull(schema, type);
|
|
247
267
|
},
|
|
248
268
|
// TODO
|
|
249
269
|
[SCHEMA_TYPES.COMPLEX_NOT]: (schema) => {
|
|
@@ -357,15 +377,17 @@ const schemaParsers = {
|
|
|
357
377
|
schema.description || _.compact(_.map(schema[complexType], "description"))[0] || "",
|
|
358
378
|
),
|
|
359
379
|
content:
|
|
360
|
-
_.
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
380
|
+
_.uniq(
|
|
381
|
+
_.compact([
|
|
382
|
+
complexSchemaContent && `(${complexSchemaContent})`,
|
|
383
|
+
getInternalSchemaType(simpleSchema) === SCHEMA_TYPES.OBJECT && `(${getInlineParseContent(simpleSchema)})`,
|
|
384
|
+
]),
|
|
385
|
+
).join(" & ") || TS_KEYWORDS.ANY,
|
|
364
386
|
});
|
|
365
387
|
},
|
|
366
388
|
[SCHEMA_TYPES.PRIMITIVE]: (schema, typeName) => {
|
|
367
389
|
let contentType = null;
|
|
368
|
-
const { additionalProperties, type, description } = schema || {};
|
|
390
|
+
const { additionalProperties, type, description, $$requiredKeys } = schema || {};
|
|
369
391
|
|
|
370
392
|
if (type === TS_KEYWORDS.OBJECT && additionalProperties) {
|
|
371
393
|
const fieldType = _.isObject(additionalProperties)
|
|
@@ -444,6 +466,7 @@ module.exports = {
|
|
|
444
466
|
parseSchemas,
|
|
445
467
|
getInlineParseContent,
|
|
446
468
|
getParseContent,
|
|
469
|
+
isNeedToAddNull,
|
|
447
470
|
getType,
|
|
448
471
|
getRefType,
|
|
449
472
|
SCHEMA_TYPES,
|
package/src/swagger.js
CHANGED
|
@@ -25,7 +25,10 @@ const getSwaggerFile = (pathToSwagger, urlToSwagger, disableStrictSSL, disablePr
|
|
|
25
25
|
} else {
|
|
26
26
|
logger.log(`try to get swagger by URL "${urlToSwagger}"`);
|
|
27
27
|
// setup options for Axios
|
|
28
|
-
const axiosOptions = {
|
|
28
|
+
const axiosOptions = {
|
|
29
|
+
maxContentLength: Infinity,
|
|
30
|
+
maxBodyLength: Infinity,
|
|
31
|
+
};
|
|
29
32
|
//
|
|
30
33
|
if (disableStrictSSL) {
|
|
31
34
|
axiosOptions.httpsAgent = new https.Agent({
|
package/src/templates.js
CHANGED
|
@@ -5,16 +5,23 @@ const { config } = require("./config");
|
|
|
5
5
|
const { resolve } = require("path");
|
|
6
6
|
const { logger } = require("./logger");
|
|
7
7
|
|
|
8
|
+
const TEMPLATE_EXTENSIONS = [".eta", ".ejs"];
|
|
9
|
+
|
|
8
10
|
/**
|
|
9
11
|
* name - project template name,
|
|
10
12
|
* fileName - template file name,
|
|
11
13
|
*/
|
|
12
14
|
const TEMPLATE_INFOS = [
|
|
13
|
-
{ name: "api", fileName: "api
|
|
14
|
-
{ name: "dataContracts", fileName: "data-contracts
|
|
15
|
-
{ name: "
|
|
16
|
-
{ name: "
|
|
17
|
-
{ name: "
|
|
15
|
+
{ name: "api", fileName: "api" },
|
|
16
|
+
{ name: "dataContracts", fileName: "data-contracts" },
|
|
17
|
+
{ name: "dataContractJsDoc", fileName: "data-contract-jsdoc" },
|
|
18
|
+
{ name: "interfaceDataContract", fileName: "interface-data-contract" },
|
|
19
|
+
{ name: "typeDataContract", fileName: "type-data-contract" },
|
|
20
|
+
{ name: "enumDataContract", fileName: "enum-data-contract" },
|
|
21
|
+
{ name: "objectFieldJsDoc", fileName: "object-field-jsdoc" },
|
|
22
|
+
{ name: "httpClient", fileName: "http-client" },
|
|
23
|
+
{ name: "routeTypes", fileName: "route-types" },
|
|
24
|
+
{ name: "routeName", fileName: "route-name" },
|
|
18
25
|
];
|
|
19
26
|
|
|
20
27
|
const getTemplatePaths = ({ templates, modular }) => {
|
|
@@ -38,6 +45,16 @@ const getTemplatePaths = ({ templates, modular }) => {
|
|
|
38
45
|
};
|
|
39
46
|
};
|
|
40
47
|
|
|
48
|
+
const cropExtension = (path) =>
|
|
49
|
+
TEMPLATE_EXTENSIONS.reduce((path, ext) => (_.endsWith(path, ext) ? path.replace(ext, "") : path), path);
|
|
50
|
+
|
|
51
|
+
const getTemplateFullPath = (path, fileName) => {
|
|
52
|
+
const raw = resolve(path, "./", cropExtension(fileName));
|
|
53
|
+
const pathVariants = TEMPLATE_EXTENSIONS.map((extension) => `${raw}${extension}`);
|
|
54
|
+
|
|
55
|
+
return pathVariants.find((variant) => !!pathIsExist(variant));
|
|
56
|
+
};
|
|
57
|
+
|
|
41
58
|
const getTemplate = ({ fileName, name, path }) => {
|
|
42
59
|
const { templatePaths } = config;
|
|
43
60
|
|
|
@@ -47,14 +64,13 @@ const getTemplate = ({ fileName, name, path }) => {
|
|
|
47
64
|
|
|
48
65
|
if (!fileName) return "";
|
|
49
66
|
|
|
50
|
-
const customFullPath =
|
|
51
|
-
let fileContent =
|
|
67
|
+
const customFullPath = getTemplateFullPath(templatePaths.custom, fileName);
|
|
68
|
+
let fileContent = customFullPath && getFileContent(customFullPath);
|
|
52
69
|
|
|
53
70
|
if (!fileContent) {
|
|
54
|
-
const baseFullPath =
|
|
55
|
-
const originalFullPath = resolve(templatePaths.original, "./", fileName);
|
|
71
|
+
const baseFullPath = getTemplateFullPath(templatePaths.base, fileName);
|
|
56
72
|
|
|
57
|
-
if (
|
|
73
|
+
if (baseFullPath) {
|
|
58
74
|
fileContent = getFileContent(baseFullPath);
|
|
59
75
|
} else {
|
|
60
76
|
logger.warn(
|
|
@@ -63,7 +79,9 @@ const getTemplate = ({ fileName, name, path }) => {
|
|
|
63
79
|
);
|
|
64
80
|
}
|
|
65
81
|
|
|
66
|
-
|
|
82
|
+
const originalFullPath = getTemplateFullPath(templatePaths.original, fileName);
|
|
83
|
+
|
|
84
|
+
if (originalFullPath) {
|
|
67
85
|
fileContent = getFileContent(originalFullPath);
|
|
68
86
|
}
|
|
69
87
|
}
|
|
@@ -87,27 +105,30 @@ const getTemplates = ({ templatePaths }) => {
|
|
|
87
105
|
};
|
|
88
106
|
|
|
89
107
|
const getTemplateContent = (path) => {
|
|
90
|
-
|
|
108
|
+
const foundTemplatePathKey = _.keys(config.templatePaths).find((key) => _.startsWith(path, `@${key}`));
|
|
91
109
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
110
|
+
const findPathWithExt = (path) => {
|
|
111
|
+
const raw = cropExtension(path);
|
|
112
|
+
const pathVariants = TEMPLATE_EXTENSIONS.map((extension) => `${raw}${extension}`);
|
|
113
|
+
return pathVariants.find((variant) => pathIsExist(variant));
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const rawPath = resolve(_.replace(path, `@${foundTemplatePathKey}`, config.templatePaths[foundTemplatePathKey]));
|
|
117
|
+
const fixedPath = findPathWithExt(rawPath);
|
|
97
118
|
|
|
98
|
-
if (
|
|
119
|
+
if (fixedPath) {
|
|
99
120
|
return getFileContent(fixedPath);
|
|
100
121
|
}
|
|
101
122
|
|
|
102
|
-
const customPath = resolve(config.templatePaths.custom,
|
|
123
|
+
const customPath = findPathWithExt(resolve(config.templatePaths.custom, path));
|
|
103
124
|
|
|
104
|
-
if (
|
|
125
|
+
if (customPath) {
|
|
105
126
|
return getFileContent(customPath);
|
|
106
127
|
}
|
|
107
128
|
|
|
108
|
-
const originalPath = resolve(config.templatePaths.original,
|
|
129
|
+
const originalPath = findPathWithExt(resolve(config.templatePaths.original, path));
|
|
109
130
|
|
|
110
|
-
if (
|
|
131
|
+
if (originalPath) {
|
|
111
132
|
return getFileContent(originalPath);
|
|
112
133
|
}
|
|
113
134
|
|
|
@@ -120,7 +141,9 @@ const renderTemplate = (template, configuration, options) => {
|
|
|
120
141
|
return Eta.render(template, configuration, {
|
|
121
142
|
async: false,
|
|
122
143
|
...(options || {}),
|
|
123
|
-
includeFile: (path, payload) =>
|
|
144
|
+
includeFile: (path, payload, options) => {
|
|
145
|
+
return renderTemplate(getTemplateContent(path), payload, options);
|
|
146
|
+
},
|
|
124
147
|
});
|
|
125
148
|
};
|
|
126
149
|
|
|
@@ -7,20 +7,9 @@ function translate(fileName, content, options) {
|
|
|
7
7
|
const originalSourceFileGet = host.getSourceFile.bind(host);
|
|
8
8
|
host.getSourceFile = (sourceFileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
9
9
|
if (sourceFileName !== fileName)
|
|
10
|
-
return originalSourceFileGet(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
onError,
|
|
14
|
-
shouldCreateNewSourceFile,
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
return ts.createSourceFile(
|
|
18
|
-
sourceFileName,
|
|
19
|
-
content,
|
|
20
|
-
languageVersion,
|
|
21
|
-
true,
|
|
22
|
-
ts.ScriptKind.External,
|
|
23
|
-
);
|
|
10
|
+
return originalSourceFileGet(sourceFileName, languageVersion, onError, shouldCreateNewSourceFile);
|
|
11
|
+
|
|
12
|
+
return ts.createSourceFile(sourceFileName, content, languageVersion, true, ts.ScriptKind.External);
|
|
24
13
|
};
|
|
25
14
|
|
|
26
15
|
host.writeFile = (fileName, contents) => {
|
package/src/typeFormatters.js
CHANGED
|
@@ -1,57 +1,70 @@
|
|
|
1
1
|
const _ = require("lodash");
|
|
2
2
|
const { config } = require("./config");
|
|
3
|
-
const { TS_KEYWORDS, SCHEMA_TYPES } = require("./constants");
|
|
3
|
+
const { TS_KEYWORDS, SCHEMA_TYPES, TS_EXTERNAL } = require("./constants");
|
|
4
|
+
|
|
5
|
+
const checkAndAddNull = (schema, value) => {
|
|
6
|
+
const { nullable, type } = schema || {};
|
|
7
|
+
return (nullable || !!_.get(schema, "x-nullable") || type === TS_KEYWORDS.NULL) &&
|
|
8
|
+
_.isString(value) &&
|
|
9
|
+
!value.includes(` ${TS_KEYWORDS.NULL}`) &&
|
|
10
|
+
!value.includes(`${TS_KEYWORDS.NULL} `)
|
|
11
|
+
? `${value} | ${TS_KEYWORDS.NULL}`
|
|
12
|
+
: value;
|
|
13
|
+
};
|
|
4
14
|
|
|
5
15
|
const formatters = {
|
|
6
|
-
[SCHEMA_TYPES.ENUM]: (
|
|
7
|
-
const isNumberEnum = _.some(content, (content) => typeof content.key === "number");
|
|
16
|
+
[SCHEMA_TYPES.ENUM]: (parsedSchema) => {
|
|
17
|
+
const isNumberEnum = _.some(parsedSchema.content, (content) => typeof content.key === "number");
|
|
8
18
|
const formatAsUnionType = !!(isNumberEnum || config.generateUnionEnums);
|
|
9
19
|
|
|
10
20
|
if (formatAsUnionType) {
|
|
11
|
-
return
|
|
21
|
+
return {
|
|
22
|
+
...parsedSchema,
|
|
23
|
+
$content: parsedSchema.content,
|
|
24
|
+
content: _.map(parsedSchema.content, ({ value }) => value).join(" | "),
|
|
25
|
+
};
|
|
12
26
|
}
|
|
13
27
|
|
|
14
|
-
return
|
|
28
|
+
return {
|
|
29
|
+
...parsedSchema,
|
|
30
|
+
$content: parsedSchema.content,
|
|
31
|
+
content: _.map(parsedSchema.content, ({ key, value }) => ` ${key} = ${value}`).join(",\n"),
|
|
32
|
+
};
|
|
15
33
|
},
|
|
16
|
-
[SCHEMA_TYPES.OBJECT]: (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
...(comments.length === 1
|
|
30
|
-
? [`/** ${comments[0]} */`]
|
|
31
|
-
: ["/**", ...comments.map((commentPart) => ` * ${commentPart}`), " */"]),
|
|
32
|
-
]
|
|
33
|
-
.map((part) => `${extraSpace}${part}\n`)
|
|
34
|
-
.join("")
|
|
35
|
-
: "";
|
|
36
|
-
|
|
37
|
-
return `${commonText}${result}`;
|
|
38
|
-
}).join(""),
|
|
39
|
-
[SCHEMA_TYPES.PRIMITIVE]: (content) => {
|
|
40
|
-
return content;
|
|
34
|
+
[SCHEMA_TYPES.OBJECT]: (parsedSchema) => {
|
|
35
|
+
if (parsedSchema.nullable) return inlineExtraFormatters[SCHEMA_TYPES.OBJECT](parsedSchema);
|
|
36
|
+
return {
|
|
37
|
+
...parsedSchema,
|
|
38
|
+
$content: parsedSchema.content,
|
|
39
|
+
content: formatObjectContent(parsedSchema.content),
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
[SCHEMA_TYPES.PRIMITIVE]: (parsedSchema) => {
|
|
43
|
+
return {
|
|
44
|
+
...parsedSchema,
|
|
45
|
+
$content: parsedSchema.content,
|
|
46
|
+
};
|
|
41
47
|
},
|
|
42
48
|
};
|
|
43
49
|
|
|
44
50
|
/** transform content of parsed schema to string or compact size */
|
|
45
51
|
const inlineExtraFormatters = {
|
|
46
52
|
[SCHEMA_TYPES.OBJECT]: (parsedSchema) => {
|
|
53
|
+
if (_.isString(parsedSchema.content)) {
|
|
54
|
+
return {
|
|
55
|
+
...parsedSchema,
|
|
56
|
+
typeIdentifier: TS_KEYWORDS.TYPE,
|
|
57
|
+
content: checkAndAddNull(parsedSchema.content),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
47
61
|
return {
|
|
48
62
|
...parsedSchema,
|
|
49
63
|
typeIdentifier: TS_KEYWORDS.TYPE,
|
|
50
|
-
content:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
: TS_KEYWORDS.OBJECT,
|
|
64
|
+
content: checkAndAddNull(
|
|
65
|
+
parsedSchema,
|
|
66
|
+
parsedSchema.content.length ? `{\n${formatObjectContent(parsedSchema.content)}\n}` : TS_EXTERNAL.RECORD,
|
|
67
|
+
),
|
|
55
68
|
};
|
|
56
69
|
},
|
|
57
70
|
[SCHEMA_TYPES.ENUM]: (parsedSchema) => {
|
|
@@ -69,6 +82,39 @@ const inlineExtraFormatters = {
|
|
|
69
82
|
},
|
|
70
83
|
};
|
|
71
84
|
|
|
85
|
+
const formatObjectContent = (content) => {
|
|
86
|
+
return _.map(content, (part) => {
|
|
87
|
+
const extraSpace = " ";
|
|
88
|
+
const result = `${extraSpace}${part.field},\n`;
|
|
89
|
+
|
|
90
|
+
const comments = _.uniq(
|
|
91
|
+
_.compact([
|
|
92
|
+
part.title,
|
|
93
|
+
part.description,
|
|
94
|
+
part.deprecated && ` * @deprecated`,
|
|
95
|
+
!_.isUndefined(part.format) && `@format ${part.format}`,
|
|
96
|
+
!_.isUndefined(part.minimum) && `@min ${part.minimum}`,
|
|
97
|
+
!_.isUndefined(part.maximum) && `@max ${part.maximum}`,
|
|
98
|
+
!_.isUndefined(part.pattern) && `@pattern ${part.pattern}`,
|
|
99
|
+
!_.isUndefined(part.example) &&
|
|
100
|
+
`@example ${_.isObject(part.example) ? JSON.stringify(part.example) : part.example}`,
|
|
101
|
+
]).reduce((acc, comment) => [...acc, ...comment.split(/\n/g)], []),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const commonText = comments.length
|
|
105
|
+
? [
|
|
106
|
+
...(comments.length === 1
|
|
107
|
+
? [`/** ${comments[0]} */`]
|
|
108
|
+
: ["/**", ...comments.map((commentPart) => ` * ${commentPart}`), " */"]),
|
|
109
|
+
]
|
|
110
|
+
.map((part) => `${extraSpace}${part}\n`)
|
|
111
|
+
.join("")
|
|
112
|
+
: "";
|
|
113
|
+
|
|
114
|
+
return `${commonText}${result}`;
|
|
115
|
+
}).join("");
|
|
116
|
+
};
|
|
117
|
+
|
|
72
118
|
module.exports = {
|
|
73
119
|
formatters,
|
|
74
120
|
inlineExtraFormatters,
|
package/src/utils/resolveName.js
CHANGED
|
@@ -82,10 +82,7 @@ class ComponentTypeNameResolver extends NameResolver {
|
|
|
82
82
|
*/
|
|
83
83
|
constructor(reservedNames) {
|
|
84
84
|
super(reservedNames, (variants) => {
|
|
85
|
-
return (
|
|
86
|
-
(variants[0] && `${variants[0]}${getRandomInt(1, 10)}`) ||
|
|
87
|
-
`ComponentType${getRandomInt(1, 10)}`
|
|
88
|
-
);
|
|
85
|
+
return (variants[0] && `${variants[0]}${getRandomInt(1, 10)}`) || `ComponentType${getRandomInt(1, 10)}`;
|
|
89
86
|
});
|
|
90
87
|
}
|
|
91
88
|
}
|
package/templates/README.md
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
# swagger-typescript-api
|
|
2
|
-
|
|
3
|
-
# templates
|
|
4
|
-
|
|
5
|
-
Templates:
|
|
6
|
-
- `api.
|
|
7
|
-
- `data-contracts.
|
|
8
|
-
- `http-client.
|
|
9
|
-
- `procedure-call.
|
|
10
|
-
- `route-docs.
|
|
11
|
-
- `route-name.
|
|
12
|
-
- `route-type.
|
|
13
|
-
- `route-types.
|
|
1
|
+
# swagger-typescript-api
|
|
2
|
+
|
|
3
|
+
# templates
|
|
4
|
+
|
|
5
|
+
Templates:
|
|
6
|
+
- `api.ejs` - *(generates file)* Api class module (locations: [default](https://github.com/acacode/swagger-typescript-api/tree/next/templates/default/api.ejs), [modular](https://github.com/acacode/swagger-typescript-api/tree/next/templates/modular/api.ejs))
|
|
7
|
+
- `data-contracts.ejs` - *(generates file)* all types (data contracts) from swagger schema (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/data-contracts.ejs))
|
|
8
|
+
- `http-client.ejs` - *(generates file)* HttpClient class module (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/http-client.ejs))
|
|
9
|
+
- `procedure-call.ejs` - *(subtemplate)* route in Api class (locations: [default](https://github.com/acacode/swagger-typescript-api/tree/next/templates/default/procedure-call.ejs), [modular](https://github.com/acacode/swagger-typescript-api/tree/next/templates/modular/procedure-call.ejs))
|
|
10
|
+
- `route-docs.ejs` - *(generates file)* documentation for route in Api class (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/route-docs.ejs))
|
|
11
|
+
- `route-name.ejs` - *(subtemplate)* route name for route in Api class (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/route-name.ejs))
|
|
12
|
+
- `route-type.ejs` - *(`--route-types` option)* *(subtemplate)* (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/route-type.ejs))
|
|
13
|
+
- `route-types.ejs` - *(`--route-types` option)* *(subtemplate)* (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/route-types.ejs)) - `data-contract-jsdoc.ejs` - *(subtemplate)* generates JSDOC for data contract (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/data-contract-jsdoc.ejs))
|
|
14
|
+
|
|
15
|
+
[//]: # (- `enum-data-contract.ejs` - *(subtemplate)* generates `enum` data contract (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/enum-data-contract.ejs)))
|
|
16
|
+
[//]: # (- `interface-data-contract.ejs` - *(subtemplate)* generates `interface` data contract (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/interface-data-contract.ejs)))
|
|
17
|
+
[//]: # (- `type-data-contract.ejs` - *(subtemplate)* generates `type` data contract (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/type-data-contract.ejs)))
|
package/templates/base/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# swagger-typescript-api
|
|
2
|
-
|
|
3
|
-
# templates/base
|
|
4
|
-
|
|
5
|
-
This templates use both for multiple api files and single api file
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
# swagger-typescript-api
|
|
2
|
+
|
|
3
|
+
# templates/base
|
|
4
|
+
|
|
5
|
+
This templates use both for multiple api files and single api file
|
|
6
|
+
|
|
7
|
+
|
|
8
8
|
path prefix `@base`
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<%
|
|
2
|
+
const { contract, utils } = it;
|
|
3
|
+
const { formatDescription, require, _ } = utils;
|
|
4
|
+
|
|
5
|
+
let jsDocLines = [];
|
|
6
|
+
|
|
7
|
+
jsDocLines.push(
|
|
8
|
+
contract.title,
|
|
9
|
+
contract.description && formatDescription(contract.description),
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
if (contract.typeData) {
|
|
13
|
+
jsDocLines.push(
|
|
14
|
+
contract.typeData.deprecated === true && '@deprecated',
|
|
15
|
+
!_.isUndefined(contract.typeData.format) && `@format ${contract.typeData.format}`,
|
|
16
|
+
!_.isUndefined(contract.typeData.minimum) && `@min ${contract.typeData.minimum}`,
|
|
17
|
+
!_.isUndefined(contract.typeData.maximum) && `@max ${contract.typeData.maximum}`,
|
|
18
|
+
!_.isUndefined(contract.typeData.pattern) && `@pattern ${contract.typeData.pattern}`,
|
|
19
|
+
!_.isUndefined(contract.typeData.example) && `@example ${
|
|
20
|
+
_.isObject(contract.typeData.example) ? JSON.stringify(contract.typeData.example) : contract.typeData.example
|
|
21
|
+
}`
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
jsDocLines = _.compact(jsDocLines);
|
|
26
|
+
%>
|
|
27
|
+
<% if (jsDocLines.length) { %>
|
|
28
|
+
/**
|
|
29
|
+
<%~ jsDocLines.map(part => `* ${part}`).join("\n") %>
|
|
30
|
+
|
|
31
|
+
*/
|
|
32
|
+
<% } %>
|