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.
Files changed (47) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +288 -262
  3. package/index.d.ts +11 -1
  4. package/index.js +2 -0
  5. package/package.json +119 -114
  6. package/src/components.js +3 -5
  7. package/src/config.js +6 -0
  8. package/src/constants.js +7 -0
  9. package/src/files.js +6 -6
  10. package/src/formatFileContent.js +13 -6
  11. package/src/index.js +8 -7
  12. package/src/logger.js +9 -0
  13. package/src/modelNames.js +1 -5
  14. package/src/modelTypes.js +7 -6
  15. package/src/output.js +22 -23
  16. package/src/render/utils/index.js +9 -1
  17. package/src/routes.js +4 -1
  18. package/src/schema.js +87 -64
  19. package/src/swagger.js +4 -1
  20. package/src/templates.js +46 -23
  21. package/src/translators/JavaScript.js +3 -14
  22. package/src/typeFormatters.js +81 -35
  23. package/src/utils/resolveName.js +1 -4
  24. package/templates/README.md +17 -13
  25. package/templates/base/README.md +7 -7
  26. package/templates/base/data-contract-jsdoc.ejs +32 -0
  27. package/templates/base/data-contracts.ejs +28 -0
  28. package/templates/base/enum-data-contract.ejs +15 -0
  29. package/templates/base/{http-client.eta → http-client.ejs} +2 -2
  30. package/templates/base/http-clients/{axios-http-client.eta → axios-http-client.ejs} +133 -145
  31. package/templates/base/http-clients/{fetch-http-client.eta → fetch-http-client.ejs} +222 -222
  32. package/templates/base/interface-data-contract.ejs +10 -0
  33. package/templates/base/object-field-jsdoc.ejs +28 -0
  34. package/templates/base/{route-docs.eta → route-docs.ejs} +30 -31
  35. package/templates/base/{route-name.eta → route-name.ejs} +42 -42
  36. package/templates/base/{route-type.eta → route-type.ejs} +21 -21
  37. package/templates/base/type-data-contract.ejs +15 -0
  38. package/templates/default/README.md +6 -6
  39. package/templates/default/{api.eta → api.ejs} +65 -65
  40. package/templates/default/{procedure-call.eta → procedure-call.ejs} +99 -99
  41. package/templates/default/{route-types.eta → route-types.ejs} +28 -28
  42. package/templates/modular/README.md +6 -6
  43. package/templates/modular/{api.eta → api.ejs} +28 -28
  44. package/templates/modular/{procedure-call.eta → procedure-call.ejs} +99 -99
  45. package/templates/modular/{route-types.eta → route-types.ejs} +18 -18
  46. package/CHANGELOG.md +0 -872
  47. 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 { getInlineParseContent, getParseContent, parseSchema } = require("../../schema");
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
- const hasSecurity = !!((globalSecurity && globalSecurity.length) || (security && security.length));
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 = (property) => {
92
- const ref = property && property["$ref"];
93
- return (ref && config.componentsMap[ref]) || null;
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 complexTypeGetter = (schema) => getInlineParseContent(schema);
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
- // 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
- );
199
+ const makeAddRequiredToChildSchema = (parentSchema, childSchema) => {
200
+ if (!childSchema) return childSchema;
202
201
 
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
- );
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
- // T1 | T2
227
- const combined = _.map(_.map(schema.oneOf, makeAddRequiredToChildSchema(schema)), complexTypeGetter);
234
+ const combined = _.map(schema.oneOf, (childSchema) =>
235
+ getInlineParseContent(makeAddRequiredToChildSchema(schema, childSchema)),
236
+ );
237
+ const filtered = filterContents(combined, [TS_KEYWORDS.ANY]);
228
238
 
229
- return checkAndAddNull(schema, filterContents(combined, [TS_KEYWORDS.ANY]).join(" | "));
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
- // T1 & T2
233
- const combined = _.map(_.map(schema.allOf, makeAddRequiredToChildSchema(schema)), complexTypeGetter);
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
- // T1 | T2 | (T1 & T2)
241
- const combined = _.map(_.map(schema.anyOf, makeAddRequiredToChildSchema(schema)), complexTypeGetter);
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
- _.compact([
361
- complexSchemaContent && `(${complexSchemaContent})`,
362
- getInternalSchemaType(simpleSchema) === TS_KEYWORDS.OBJECT && getInlineParseContent(simpleSchema),
363
- ]).join(" & ") || TS_KEYWORDS.ANY,
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.eta" },
14
- { name: "dataContracts", fileName: "data-contracts.eta" },
15
- { name: "httpClient", fileName: "http-client.eta" },
16
- { name: "routeTypes", fileName: "route-types.eta" },
17
- { name: "routeName", fileName: "route-name.eta" },
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 = resolve(templatePaths.custom, "./", fileName);
51
- let fileContent = pathIsExist(customFullPath) && getFileContent(customFullPath);
67
+ const customFullPath = getTemplateFullPath(templatePaths.custom, fileName);
68
+ let fileContent = customFullPath && getFileContent(customFullPath);
52
69
 
53
70
  if (!fileContent) {
54
- const baseFullPath = resolve(templatePaths.base, "./", fileName);
55
- const originalFullPath = resolve(templatePaths.original, "./", fileName);
71
+ const baseFullPath = getTemplateFullPath(templatePaths.base, fileName);
56
72
 
57
- if (pathIsExist(baseFullPath)) {
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
- if (pathIsExist(originalFullPath)) {
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
- let fixedPath = _.endsWith(path, ".eta") ? path : `${path}.eta`;
108
+ const foundTemplatePathKey = _.keys(config.templatePaths).find((key) => _.startsWith(path, `@${key}`));
91
109
 
92
- _.keys(config.templatePaths).forEach((key) => {
93
- if (_.startsWith(fixedPath, `@${key}`)) {
94
- fixedPath = resolve(_.replace(fixedPath, `@${key}`, config.templatePaths[key]));
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 (pathIsExist(fixedPath)) {
119
+ if (fixedPath) {
99
120
  return getFileContent(fixedPath);
100
121
  }
101
122
 
102
- const customPath = resolve(config.templatePaths.custom, fixedPath);
123
+ const customPath = findPathWithExt(resolve(config.templatePaths.custom, path));
103
124
 
104
- if (pathIsExist(customPath)) {
125
+ if (customPath) {
105
126
  return getFileContent(customPath);
106
127
  }
107
128
 
108
- const originalPath = resolve(config.templatePaths.original, fixedPath);
129
+ const originalPath = findPathWithExt(resolve(config.templatePaths.original, path));
109
130
 
110
- if (pathIsExist(originalPath)) {
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) => renderTemplate(getTemplateContent(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
- sourceFileName,
12
- languageVersion,
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) => {
@@ -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]: (content) => {
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 _.map(content, ({ value }) => value).join(" | ");
21
+ return {
22
+ ...parsedSchema,
23
+ $content: parsedSchema.content,
24
+ content: _.map(parsedSchema.content, ({ value }) => value).join(" | "),
25
+ };
12
26
  }
13
27
 
14
- return _.map(content, ({ key, value }) => ` ${key} = ${value}`).join(",\n");
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]: (content) =>
17
- _.map(content, (part) => {
18
- const extraSpace = " ";
19
- const result = `${extraSpace}${part.field};\n`;
20
-
21
- const comments = _.uniq(_.compact([part.title, part.description]).reduce(
22
- (acc, comment) => [...acc, ...comment.split(/\n/g)],
23
- [],
24
- ));
25
-
26
- const commonText = comments.length
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: _.isString(parsedSchema.content)
51
- ? parsedSchema.content
52
- : parsedSchema.content.length
53
- ? `{ ${parsedSchema.content.map((part) => part.field).join(", ")} }`
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,
@@ -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
  }
@@ -1,13 +1,17 @@
1
- # swagger-typescript-api
2
-
3
- # templates
4
-
5
- Templates:
6
- - `api.eta` - Api class module (locations: [default](https://github.com/acacode/swagger-typescript-api/tree/next/templates/default/api.eta), [modular](https://github.com/acacode/swagger-typescript-api/tree/next/templates/modular/api.eta))
7
- - `data-contracts.eta` - all types (data contracts) from swagger schema (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/data-contracts.eta))
8
- - `http-client.eta` - HttpClient class module (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/http-client.eta))
9
- - `procedure-call.eta` - route in Api class (locations: [default](https://github.com/acacode/swagger-typescript-api/tree/next/templates/default/procedure-call.eta), [modular](https://github.com/acacode/swagger-typescript-api/tree/next/templates/modular/procedure-call.eta))
10
- - `route-docs.eta` - documentation for route in Api class (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/route-docs.eta))
11
- - `route-name.eta` - route name for route in Api class (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/route-name.eta))
12
- - `route-type.eta` - *(`--route-types` option)* (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/route-type.eta))
13
- - `route-types.eta` - *(`--route-types` option)* (locations: [base](https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/route-types.eta))
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` - *&#40;subtemplate&#41;* generates `enum` data contract &#40;locations: [base]&#40;https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/enum-data-contract.ejs&#41;&#41;)
16
+ [//]: # (- `interface-data-contract.ejs` - *&#40;subtemplate&#41;* generates `interface` data contract &#40;locations: [base]&#40;https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/interface-data-contract.ejs&#41;&#41;)
17
+ [//]: # (- `type-data-contract.ejs` - *&#40;subtemplate&#41;* generates `type` data contract &#40;locations: [base]&#40;https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/type-data-contract.ejs&#41;&#41;)
@@ -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
+ <% } %>