swagger-typescript-api 13.0.0 → 13.0.2

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 CHANGED
@@ -81,6 +81,8 @@ Options:
81
81
  --debug additional information about processes inside this tool (default: false)
82
82
  --another-array-type generate array types as Array<Type> (by default Type[]) (default: false)
83
83
  --sort-types sort fields and types (default: false)
84
+ --sort-routes sort routes in alphabetical order (default: false)
85
+ --custom-config <string> custom config: primitiveTypeConstructs, hooks, ... (default: "")
84
86
  --extract-enums extract all enums from inline interface\type content to typescript enum construction (default: false)
85
87
  -h, --help display help for command
86
88
 
@@ -149,6 +151,8 @@ generateApi({
149
151
  enumKeyPrefix: '',
150
152
  enumKeySuffix: '',
151
153
  addReadonly: false,
154
+ sortTypes: false,
155
+ sortRouters: false,
152
156
  extractingOptions: {
153
157
  requestBodySuffix: ["Payload", "Body", "Input"],
154
158
  requestParamsSuffix: ["Params"],
package/index.js CHANGED
@@ -114,6 +114,12 @@ const program = cli({
114
114
  default: codeGenBaseConfig.extractResponseError,
115
115
  internal: { formatter: Boolean },
116
116
  },
117
+ {
118
+ flags: '--extract-responses',
119
+ description: 'extract all responses described in /components/responses',
120
+ default: codeGenBaseConfig.extractResponses,
121
+ internal: { formatter: Boolean },
122
+ },
117
123
  {
118
124
  flags: '--modular',
119
125
  description:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swagger-typescript-api",
3
- "version": "13.0.0",
3
+ "version": "13.0.2",
4
4
  "description": "Generate typescript/javascript api from swagger schema",
5
5
  "scripts": {
6
6
  "update-deps-to-latest": "npx --yes npm-check-updates && npm i",
@@ -40,6 +40,7 @@
40
40
  "test:--extract-response-error": "node tests/spec/extractResponseError/test.js",
41
41
  "test:--enum-names-as-values": "node tests/spec/enumNamesAsValues/test.js",
42
42
  "test:--default-response": "node tests/spec/defaultResponse/test.js",
43
+ "test:const-keyword": "node tests/spec/const-keyword/test.js",
43
44
  "test:--js": "node tests/spec/js/test.js",
44
45
  "test:jsSingleHttpClientModular": "node tests/spec/jsSingleHttpClientModular/test.js",
45
46
  "test:--js--axios": "node tests/spec/jsAxios/test.js",
@@ -116,9 +116,14 @@ class CodeGenProcess {
116
116
  }),
117
117
  );
118
118
 
119
- const schemaComponents = this.schemaComponentsMap.filter('schemas');
119
+ /**
120
+ * @type {SchemaComponent[]}
121
+ */
122
+ const componentsToParse = this.schemaComponentsMap.filter(
123
+ _.compact(['schemas', this.config.extractResponses && 'responses']),
124
+ );
120
125
 
121
- const parsedSchemas = schemaComponents.map((schemaComponent) => {
126
+ const parsedSchemas = componentsToParse.map((schemaComponent) => {
122
127
  const parsed = this.schemaParserFabric.parseSchema(
123
128
  schemaComponent.rawTypeData,
124
129
  schemaComponent.typeName,
@@ -234,8 +239,13 @@ class CodeGenProcess {
234
239
  const components = this.schemaComponentsMap.getComponents();
235
240
  let modelTypes = [];
236
241
 
242
+ const modelTypeComponents = _.compact([
243
+ 'schemas',
244
+ this.config.extractResponses && 'responses',
245
+ ]);
246
+
237
247
  const getSchemaComponentsCount = () =>
238
- components.filter((c) => c.componentName === 'schemas').length;
248
+ this.schemaComponentsMap.filter(...modelTypeComponents).length;
239
249
 
240
250
  let schemaComponentsCount = getSchemaComponentsCount();
241
251
  let processedCount = 0;
@@ -244,7 +254,7 @@ class CodeGenProcess {
244
254
  modelTypes = [];
245
255
  processedCount = 0;
246
256
  for (const component of components) {
247
- if (component.componentName === 'schemas') {
257
+ if (modelTypeComponents.includes(component.componentName)) {
248
258
  const modelType = this.prepareModelType(component);
249
259
  if (modelType) {
250
260
  modelTypes.push(modelType);
@@ -74,6 +74,7 @@ class CodeGenConfig {
74
74
  extractRequestBody = false;
75
75
  extractResponseBody = false;
76
76
  extractResponseError = false;
77
+ extractResponses = false;
77
78
  extractEnums = false;
78
79
  fileNames = {
79
80
  dataContracts: 'data-contracts',
@@ -240,7 +241,7 @@ class CodeGenConfig {
240
241
  /**
241
242
  * $A
242
243
  */
243
- NullValue: (content) => content,
244
+ NullValue: (content) => `null`,
244
245
  /**
245
246
  * $A1 | $A2
246
247
  */
@@ -276,6 +277,9 @@ class CodeGenConfig {
276
277
  */
277
278
  InterfaceDynamicField: (key, value) => `[key: ${key}]: ${value}`,
278
279
 
280
+ /**
281
+ * EnumName.EnumKey
282
+ */
279
283
  EnumUsageKey: (enumStruct, key) => `${enumStruct}.${key}`,
280
284
  /**
281
285
  * $A1 = $A2
@@ -57,12 +57,14 @@ class SchemaComponentsMap {
57
57
  }
58
58
 
59
59
  /**
60
- * @param componentName {string}
60
+ * @params {...string[]} componentNames
61
61
  * @returns {SchemaComponent[]}
62
62
  */
63
- filter(componentName) {
64
- return _.filter(this._data, (v) =>
65
- _.startsWith(v.$ref, `#/components/${componentName}`),
63
+ filter(...componentNames) {
64
+ return _.filter(this._data, (it) =>
65
+ componentNames.some((componentName) =>
66
+ _.startsWith(it.$ref, `#/components/${componentName}`),
67
+ ),
66
68
  );
67
69
  }
68
70
 
@@ -4,6 +4,7 @@ const { MonoSchemaParser } = require('../mono-schema-parser');
4
4
 
5
5
  class DiscriminatorSchemaParser extends MonoSchemaParser {
6
6
  parse() {
7
+ const ts = this.config.Ts;
7
8
  const { discriminator, ...noDiscriminatorSchema } = this.schema;
8
9
 
9
10
  if (!discriminator.mapping) {
@@ -27,7 +28,7 @@ class DiscriminatorSchemaParser extends MonoSchemaParser {
27
28
  abstractSchemaStruct,
28
29
  });
29
30
 
30
- const schemaContent = this.config.Ts.IntersectionType(
31
+ const schemaContent = ts.IntersectionType(
31
32
  [
32
33
  abstractSchemaStruct?.content,
33
34
  discriminatorSchemaStruct?.content,
@@ -40,7 +41,7 @@ class DiscriminatorSchemaParser extends MonoSchemaParser {
40
41
  $parsedSchema: true,
41
42
  schemaType: SCHEMA_TYPES.COMPLEX,
42
43
  type: SCHEMA_TYPES.PRIMITIVE,
43
- typeIdentifier: this.config.Ts.Keyword.Type,
44
+ typeIdentifier: ts.Keyword.Type,
44
45
  name: this.typeName,
45
46
  description: this.schemaFormatters.formatDescription(
46
47
  this.schema.description,
@@ -50,6 +51,8 @@ class DiscriminatorSchemaParser extends MonoSchemaParser {
50
51
  }
51
52
 
52
53
  createDiscriminatorSchema = ({ skipMappingType, abstractSchemaStruct }) => {
54
+ const ts = this.config.Ts;
55
+
53
56
  const refPath = this.schemaComponentsMap.createRef([
54
57
  'components',
55
58
  'schemas',
@@ -71,34 +74,36 @@ class DiscriminatorSchemaParser extends MonoSchemaParser {
71
74
  });
72
75
 
73
76
  if (ableToCreateMappingType) {
74
- mappingTypeName = this.schemaUtils.resolveTypeName(
75
- `${abstractSchemaStruct.typeName} ${discriminator.propertyName}`,
76
- {
77
- suffixes: this.config.extractingOptions.discriminatorMappingSuffix,
78
- resolver:
79
- this.config.extractingOptions.discriminatorMappingNameResolver,
80
- },
81
- );
82
- this.schemaParserFabric.createSchema({
83
- linkedComponent: this.schemaComponentsMap.createComponent(
84
- this.schemaComponentsMap.createRef([
85
- 'components',
86
- 'schemas',
87
- mappingTypeName,
88
- ]),
77
+ const rawTypeName = `${abstractSchemaStruct.typeName}_${discriminator.propertyName}`;
78
+ const generatedTypeName = this.schemaUtils.resolveTypeName(rawTypeName, {
79
+ suffixes: this.config.extractingOptions.discriminatorMappingSuffix,
80
+ resolver:
81
+ this.config.extractingOptions.discriminatorMappingNameResolver,
82
+ });
83
+
84
+ const content = ts.IntersectionType([
85
+ ts.ObjectWrapper(
86
+ ts.TypeField({
87
+ key: ts.StringValue(discriminator.propertyName),
88
+ value: 'Key',
89
+ }),
89
90
  ),
90
- content: this.config.Ts.IntersectionType([
91
- this.config.Ts.ObjectWrapper(
92
- this.config.Ts.TypeField({
93
- key: discriminator.propertyName,
94
- value: 'Key',
95
- }),
96
- ),
97
- 'Type',
98
- ]),
99
- genericArgs: [{ name: 'Key' }, { name: 'Type' }],
100
- internal: true,
91
+ 'Type',
92
+ ]);
93
+
94
+ const component = this.schemaParserFabric.createParsedComponent({
95
+ typeName: generatedTypeName,
96
+ schema: {
97
+ type: 'object',
98
+ properties: {},
99
+ genericArgs: [{ name: 'Key' }, { name: 'Type' }],
100
+ internal: true,
101
+ },
101
102
  });
103
+
104
+ component.typeData.content = content;
105
+
106
+ mappingTypeName = this.typeNameFormatter.format(component.typeName);
102
107
  }
103
108
 
104
109
  /** returns (GenericType<"mapping_key", MappingType>) or ({ discriminatorProperty: "mapping_key" } & MappingType) */
@@ -112,18 +117,15 @@ class DiscriminatorSchemaParser extends MonoSchemaParser {
112
117
 
113
118
  const mappingUsageKey =
114
119
  mappingPropertySchemaEnumKeysMap[mappingKey] ||
115
- this.config.Ts.StringValue(mappingKey);
120
+ ts.StringValue(mappingKey);
116
121
 
117
122
  if (ableToCreateMappingType) {
118
- return this.config.Ts.TypeWithGeneric(mappingTypeName, [
119
- mappingUsageKey,
120
- content,
121
- ]);
123
+ return ts.TypeWithGeneric(mappingTypeName, [mappingUsageKey, content]);
122
124
  } else {
123
- return this.config.Ts.ExpressionGroup(
124
- this.config.Ts.IntersectionType([
125
- this.config.Ts.ObjectWrapper(
126
- this.config.Ts.TypeField({
125
+ return ts.ExpressionGroup(
126
+ ts.IntersectionType([
127
+ ts.ObjectWrapper(
128
+ ts.TypeField({
127
129
  key: discriminator.propertyName,
128
130
  value: mappingUsageKey,
129
131
  }),
@@ -151,9 +153,7 @@ class DiscriminatorSchemaParser extends MonoSchemaParser {
151
153
 
152
154
  if (skipMappingType) return null;
153
155
 
154
- const content = this.config.Ts.ExpressionGroup(
155
- this.config.Ts.UnionType(mappingContents),
156
- );
156
+ const content = ts.ExpressionGroup(ts.UnionType(mappingContents));
157
157
 
158
158
  return {
159
159
  content,
@@ -164,6 +164,8 @@ class DiscriminatorSchemaParser extends MonoSchemaParser {
164
164
  abstractSchemaStruct,
165
165
  discPropertyName,
166
166
  }) => {
167
+ const ts = this.config.Ts;
168
+
167
169
  let mappingPropertySchemaEnumKeysMap = {};
168
170
  let mappingPropertySchema = _.get(
169
171
  abstractSchemaStruct?.component?.rawTypeData,
@@ -183,7 +185,7 @@ class DiscriminatorSchemaParser extends MonoSchemaParser {
183
185
  (acc, key, index) => {
184
186
  const enumKey =
185
187
  mappingPropertySchema.rawTypeData.$parsed.content[index].key;
186
- acc[key] = this.config.Ts.EnumUsageKey(
188
+ acc[key] = ts.EnumUsageKey(
187
189
  mappingPropertySchema.rawTypeData.$parsed.typeName,
188
190
  enumKey,
189
191
  );
@@ -284,12 +286,13 @@ class DiscriminatorSchemaParser extends MonoSchemaParser {
284
286
  };
285
287
 
286
288
  createComplexSchemaStruct = () => {
289
+ const ts = this.config.Ts;
287
290
  const complexType = this.schemaUtils.getComplexType(this.schema);
288
291
 
289
292
  if (complexType === SCHEMA_TYPES.COMPLEX_UNKNOWN) return null;
290
293
 
291
294
  return {
292
- content: this.config.Ts.ExpressionGroup(
295
+ content: ts.ExpressionGroup(
293
296
  this.schemaParser._complexSchemaParsers[complexType](this.schema),
294
297
  ),
295
298
  };
@@ -1,7 +1,7 @@
1
1
  const { MonoSchemaParser } = require('../mono-schema-parser');
2
2
  const _ = require('lodash');
3
3
 
4
- // T1 | T2 | (T1 & T2)
4
+ // T1 | T2
5
5
  class AnyOfSchemaParser extends MonoSchemaParser {
6
6
  parse() {
7
7
  const ignoreTypes = [this.config.Ts.Keyword.Any];
@@ -12,20 +12,13 @@ class AnyOfSchemaParser extends MonoSchemaParser {
12
12
  this.schemaPath,
13
13
  ),
14
14
  );
15
+
15
16
  const filtered = this.schemaUtils.filterSchemaContents(
16
17
  combined,
17
18
  (content) => !ignoreTypes.includes(content),
18
19
  );
19
20
 
20
- const type = this.config.Ts.UnionType(
21
- _.compact([
22
- ...filtered,
23
- filtered.length > 1 &&
24
- this.config.Ts.ExpressionGroup(
25
- this.config.Ts.IntersectionType(filtered),
26
- ),
27
- ]),
28
- );
21
+ const type = this.config.Ts.UnionType(filtered);
29
22
 
30
23
  return this.schemaUtils.safeAddNullToType(this.schema, type);
31
24
  }
@@ -79,6 +79,7 @@ class SchemaParserFabric {
79
79
  schemaCopy,
80
80
  );
81
81
  const parsed = this.parseSchema(schemaCopy, null, schemaPath);
82
+
82
83
  parsed.name = typeName;
83
84
  customComponent.typeData = parsed;
84
85
 
@@ -193,10 +193,9 @@ class SchemaParser {
193
193
  this.typeName = this.schemaUtils.getSchemaType(this.schema);
194
194
  }
195
195
 
196
- /**
197
- * swagger schemas fixes
198
- * ---->
199
- */
196
+ //#region swagger schemas fixes
197
+
198
+ // schema has items but don't have array type
200
199
  if (
201
200
  this.schema.items &&
202
201
  !Array.isArray(this.schema.items) &&
@@ -204,6 +203,7 @@ class SchemaParser {
204
203
  ) {
205
204
  this.schema.type = SCHEMA_TYPES.ARRAY;
206
205
  }
206
+ // schema is enum with one null value
207
207
  if (
208
208
  Array.isArray(this.schema.enum) &&
209
209
  this.schema.enum.length === 1 &&
@@ -212,9 +212,22 @@ class SchemaParser {
212
212
  this.logger.debug('invalid enum schema', this.schema);
213
213
  this.schema = { type: this.config.Ts.Keyword.Null };
214
214
  }
215
- /**
216
- * <----
217
- */
215
+ // schema is response schema
216
+ if (
217
+ 'content' in this.schema &&
218
+ typeof this.schema['content'] === 'object'
219
+ ) {
220
+ const schema = this.extractSchemaFromResponseStruct(this.schema);
221
+ const schemaParser = this.schemaParserFabric.createSchemaParser({
222
+ schema,
223
+ typeName: this.typeName,
224
+ schemaPath: this.schemaPath,
225
+ });
226
+ this.schema.$parsed = schemaParser.parseSchema();
227
+ return this.schema.$parsed;
228
+ }
229
+
230
+ //#endregion
218
231
 
219
232
  schemaType = this.schemaUtils.getInternalSchemaType(this.schema);
220
233
 
@@ -268,6 +281,21 @@ class SchemaParser {
268
281
  );
269
282
  return formattedSchema.content;
270
283
  };
284
+
285
+ extractSchemaFromResponseStruct = (responseStruct) => {
286
+ const { content, ...extras } = responseStruct;
287
+
288
+ const firstResponse = _.first(_.values(content));
289
+ const firstSchema = _.get(firstResponse, 'schema');
290
+
291
+ if (!firstSchema) return;
292
+
293
+ return {
294
+ ...extras,
295
+ ..._.omit(firstResponse, 'schema'),
296
+ ...firstSchema,
297
+ };
298
+ };
271
299
  }
272
300
 
273
301
  module.exports = {
@@ -248,24 +248,32 @@ class SchemaUtils {
248
248
  );
249
249
  }
250
250
 
251
- const primitiveType = this.getSchemaPrimitiveType(schema);
252
-
253
- if (primitiveType == null) return this.config.Ts.Keyword.Any;
254
-
255
251
  let resultType;
256
252
 
257
- const typeAlias =
258
- _.get(this.config.primitiveTypes, [primitiveType, schema.format]) ||
259
- _.get(this.config.primitiveTypes, [primitiveType, '$default']) ||
260
- this.config.primitiveTypes[primitiveType];
261
-
262
- if (_.isFunction(typeAlias)) {
263
- resultType = typeAlias(schema, this);
253
+ if (this.isConstantSchema(schema)) {
254
+ resultType = this.formatJsValue(schema.const);
264
255
  } else {
265
- resultType = typeAlias || primitiveType;
256
+ const primitiveType = this.getSchemaPrimitiveType(schema);
257
+
258
+ if (primitiveType == null) {
259
+ return this.config.Ts.Keyword.Any;
260
+ }
261
+
262
+ const typeAlias =
263
+ _.get(this.config.primitiveTypes, [primitiveType, schema.format]) ||
264
+ _.get(this.config.primitiveTypes, [primitiveType, '$default']) ||
265
+ this.config.primitiveTypes[primitiveType];
266
+
267
+ if (_.isFunction(typeAlias)) {
268
+ resultType = typeAlias(schema, this);
269
+ } else {
270
+ resultType = typeAlias || primitiveType;
271
+ }
266
272
  }
267
273
 
268
- if (!resultType) return this.config.Ts.Keyword.Any;
274
+ if (!resultType) {
275
+ return this.config.Ts.Keyword.Any;
276
+ }
269
277
 
270
278
  return this.checkAndAddRequiredKeys(
271
279
  schema,
@@ -284,6 +292,31 @@ class SchemaUtils {
284
292
  ),
285
293
  );
286
294
  };
295
+
296
+ isConstantSchema(schema) {
297
+ return 'const' in schema;
298
+ }
299
+
300
+ formatJsValue = (value) => {
301
+ switch (typeof value) {
302
+ case 'string': {
303
+ return this.config.Ts.StringValue(value);
304
+ }
305
+ case 'boolean': {
306
+ return this.config.Ts.BooleanValue(value);
307
+ }
308
+ case 'number': {
309
+ return this.config.Ts.NumberValue(value);
310
+ }
311
+ default: {
312
+ if (value === null) {
313
+ return this.config.Ts.NullValue(value);
314
+ }
315
+
316
+ return this.config.Ts.Keyword.Any;
317
+ }
318
+ }
319
+ };
287
320
  }
288
321
 
289
322
  module.exports = {
@@ -1201,22 +1201,19 @@ class SchemaRoutes {
1201
1201
  routeGroups.outOfModule = this.sortRoutes(routeGroups.outOfModule);
1202
1202
  }
1203
1203
  if (routeGroups.combined) {
1204
- routeGroups.combined = this.sortRoutes(routeGroups.combined);
1204
+ _.each(routeGroups.combined, (routeGroup) => {
1205
+ routeGroup.routes = this.sortRoutes(routeGroup.routes);
1206
+ });
1205
1207
  }
1206
1208
  }
1207
1209
 
1208
1210
  return routeGroups;
1209
1211
  };
1210
1212
 
1211
- sortRoutes = (routeInfo) => {
1212
- if (routeInfo) {
1213
- routeInfo.forEach((routeInfo) => {
1214
- routeInfo.routes.sort((routeA, routeB) =>
1215
- routeA.routeName.usage.localeCompare(routeB.routeName.usage),
1216
- );
1217
- });
1218
- }
1219
- return routeInfo;
1213
+ sortRoutes = (routes) => {
1214
+ return _.slice(routes).sort((routeA, routeB) =>
1215
+ routeA.routeName.usage.localeCompare(routeB.routeName.usage),
1216
+ );
1220
1217
  };
1221
1218
  }
1222
1219