Skip to content

Commit f5960b9

Browse files
committed
Merge branch 'feature/extract-responses' into next
# Conflicts: # CHANGELOG.md
2 parents 43baaa2 + 9117bc7 commit f5960b9

File tree

8 files changed

+100
-36
lines changed

8 files changed

+100
-36
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# next release
22

3-
fix: problem with using `anyOf`
3+
fix: problem with using `anyOf`
4+
feat: `--extract-responses` (nodejs: `extractResponses`) option to extract all schemas from `/components/responses`
45

56
## 13.0.0
67

index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ const program = cli({
114114
default: codeGenBaseConfig.extractResponseError,
115115
internal: { formatter: Boolean },
116116
},
117+
{
118+
flags: '--extract-responses',
119+
description: 'extract all responses described in /components/responses',
120+
default: codeGenBaseConfig.extractResponses,
121+
internal: { formatter: Boolean },
122+
},
117123
{
118124
flags: '--modular',
119125
description:

src/code-gen-process.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,14 @@ class CodeGenProcess {
116116
}),
117117
);
118118

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+
);
120125

121-
const parsedSchemas = schemaComponents.map((schemaComponent) => {
126+
const parsedSchemas = componentsToParse.map((schemaComponent) => {
122127
const parsed = this.schemaParserFabric.parseSchema(
123128
schemaComponent.rawTypeData,
124129
schemaComponent.typeName,
@@ -234,8 +239,13 @@ class CodeGenProcess {
234239
const components = this.schemaComponentsMap.getComponents();
235240
let modelTypes = [];
236241

242+
const modelTypeComponents = _.compact([
243+
'schemas',
244+
this.config.extractResponses && 'responses',
245+
]);
246+
237247
const getSchemaComponentsCount = () =>
238-
components.filter((c) => c.componentName === 'schemas').length;
248+
this.schemaComponentsMap.filter(...modelTypeComponents).length;
239249

240250
let schemaComponentsCount = getSchemaComponentsCount();
241251
let processedCount = 0;
@@ -244,7 +254,7 @@ class CodeGenProcess {
244254
modelTypes = [];
245255
processedCount = 0;
246256
for (const component of components) {
247-
if (component.componentName === 'schemas') {
257+
if (modelTypeComponents.includes(component.componentName)) {
248258
const modelType = this.prepareModelType(component);
249259
if (modelType) {
250260
modelTypes.push(modelType);

src/configuration.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class CodeGenConfig {
7474
extractRequestBody = false;
7575
extractResponseBody = false;
7676
extractResponseError = false;
77+
extractResponses = false;
7778
extractEnums = false;
7879
fileNames = {
7980
dataContracts: 'data-contracts',

src/schema-components-map.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,14 @@ class SchemaComponentsMap {
5757
}
5858

5959
/**
60-
* @param componentName {string}
60+
* @params {...string[]} componentNames
6161
* @returns {SchemaComponent[]}
6262
*/
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+
),
6668
);
6769
}
6870

src/schema-parser/schema-parser.js

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,17 @@ class SchemaParser {
193193
this.typeName = this.schemaUtils.getSchemaType(this.schema);
194194
}
195195

196-
/**
197-
* swagger schemas fixes
198-
* ---->
199-
*/
196+
//#region swagger schemas fixes
197+
198+
// schema has items but don't have array type
200199
if (
201200
this.schema.items &&
202201
!Array.isArray(this.schema.items) &&
203202
!this.schema.type
204203
) {
205204
this.schema.type = SCHEMA_TYPES.ARRAY;
206205
}
206+
// schema is enum with one null value
207207
if (
208208
Array.isArray(this.schema.enum) &&
209209
this.schema.enum.length === 1 &&
@@ -212,9 +212,22 @@ class SchemaParser {
212212
this.logger.debug('invalid enum schema', this.schema);
213213
this.schema = { type: this.config.Ts.Keyword.Null };
214214
}
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
218231

219232
schemaType = this.schemaUtils.getInternalSchemaType(this.schema);
220233

@@ -268,6 +281,21 @@ class SchemaParser {
268281
);
269282
return formattedSchema.content;
270283
};
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+
};
271299
}
272300

273301
module.exports = {

src/schema-routes/schema-routes.js

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,22 +1201,19 @@ class SchemaRoutes {
12011201
routeGroups.outOfModule = this.sortRoutes(routeGroups.outOfModule);
12021202
}
12031203
if (routeGroups.combined) {
1204-
routeGroups.combined = this.sortRoutes(routeGroups.combined);
1204+
_.each(routeGroups.combined, (routeGroup) => {
1205+
routeGroup.routes = this.sortRoutes(routeGroup.routes);
1206+
});
12051207
}
12061208
}
12071209

12081210
return routeGroups;
12091211
};
12101212

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+
);
12201217
};
12211218
}
12221219

tests/generate-extended.js

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ allSchemas.forEach(async ({ absolutePath, apiFileName, outputPath }) => {
2323
const input = absolutePath;
2424
const output = outputPath;
2525

26+
const typePrefix = 'IMySuperPrefix'
27+
const typeSuffix = 'MySuperSuffix'
28+
2629
await generateApiForTest({
2730
name: name,
2831
input: input,
@@ -36,25 +39,41 @@ allSchemas.forEach(async ({ absolutePath, apiFileName, outputPath }) => {
3639
extractEnums: true,
3740
extractRequestParams: true,
3841
extractResponseError: true,
39-
typePrefix: "IMySuperPrefix",
40-
typeSuffix: "MySuperSuffix",
42+
extractResponses: true,
43+
typePrefix: typePrefix,
44+
typeSuffix: typeSuffix,
4145
sortTypes: true,
46+
sortRoutes: true,
4247
debugExtras: ["generate-extended", apiFileName],
4348
}).then((result) => {
4449
result.configuration.modelTypes.forEach((modelType) => {
4550
if (modelType.name) {
46-
if (modelType.name.startsWith("IMySuperPrefixIMySuperPrefix")) {
51+
if (modelType.name.startsWith(`${typePrefix}${typePrefix}`)) {
52+
throw new GenerateExtendedError(
53+
`[${outputPath}][${apiFileName}] modelType has prefix/suffix duplicates - ${modelType.name}`,
54+
output,
55+
name,
56+
);
57+
}
58+
if (!modelType.name.startsWith(typePrefix)) {
59+
throw new GenerateExtendedError(
60+
`[${outputPath}][${apiFileName}] modelType has not prefix/suffix - ${modelType.name}`,
61+
output,
62+
name,
63+
);
64+
}
65+
if (modelType.name.endsWith(`${typeSuffix}${typeSuffix}`)) {
4766
throw new GenerateExtendedError(
48-
`[${outputPath}][${apiFileName}] modelType has prefix/suffix duplicates - ${modelType.name}`,
49-
output,
50-
name,
67+
`[${outputPath}][${apiFileName}] modelType has prefix/suffix duplicates - ${modelType.name}`,
68+
output,
69+
name,
5170
);
5271
}
53-
if (!modelType.name.startsWith("IMySuperPrefix")) {
72+
if (!modelType.name.endsWith(typeSuffix)) {
5473
throw new GenerateExtendedError(
55-
`[${outputPath}][${apiFileName}] modelType has not prefix/suffix - ${modelType.name}`,
56-
output,
57-
name,
74+
`[${outputPath}][${apiFileName}] modelType has not prefix/suffix - ${modelType.name}`,
75+
output,
76+
name,
5877
);
5978
}
6079
}

0 commit comments

Comments
 (0)