Skip to content

Commit 5d99774

Browse files
authored
Merge pull request postmanlabs#866 from postmanlabs/feature/add-composite-schema-to-generated-type
Enhance type fetching to support composite schemas (anyOf, oneOf, allOf)
2 parents 306865a + 43124e0 commit 5d99774

File tree

2 files changed

+545
-8
lines changed

2 files changed

+545
-8
lines changed

libV2/schemaUtils.js

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ schemaFaker.option({
128128

129129
let QUERYPARAM = 'query',
130130
CONVERSION = 'conversion',
131+
TYPES_GENERATION = 'typesGeneration',
131132
HEADER = 'header',
132133
PATHPARAM = 'path',
133134
SCHEMA_TYPES = {
@@ -493,6 +494,15 @@ let QUERYPARAM = 'query',
493494
* @returns {Object} Resolved schema
494495
*/
495496
resolveAllOfSchema = (context, schema, stack = 0, resolveFor = CONVERSION, seenRef = {}, currentPath = '') => {
497+
if (resolveFor === TYPES_GENERATION) {
498+
return {
499+
allOf: _.map(schema.allOf, (schema) => {
500+
// eslint-disable-next-line no-use-before-define
501+
return _resolveSchema(context, schema, stack, resolveFor, _.cloneDeep(seenRef), currentPath);
502+
})
503+
};
504+
}
505+
496506
try {
497507
return mergeAllOf(_.assign(schema, {
498508
allOf: _.map(schema.allOf, (schema) => {
@@ -684,7 +694,7 @@ let QUERYPARAM = 'query',
684694
let { parametersResolution } = context.computedOptions;
685695

686696
// Override default value to schema for CONVERSION only for parmeter resolution set to schema
687-
if (resolveFor === CONVERSION && parametersResolution === 'schema') {
697+
if ((resolveFor === CONVERSION || resolveFor === TYPES_GENERATION) && parametersResolution === 'schema') {
688698
if (!schema.hasOwnProperty('format')) {
689699
schema.default = '<' + schema.type + '>';
690700
}
@@ -743,6 +753,30 @@ let QUERYPARAM = 'query',
743753
* @returns {Object} The processed schema details.
744754
*/
745755
processSchema = (resolvedSchema) => {
756+
if (resolvedSchema.anyOf) {
757+
return {
758+
anyOf: resolvedSchema.anyOf.map((schema) => {
759+
return processSchema(schema);
760+
})
761+
};
762+
}
763+
764+
if (resolvedSchema.oneOf) {
765+
return {
766+
oneOf: resolvedSchema.oneOf.map((schema) => {
767+
return processSchema(schema);
768+
})
769+
};
770+
}
771+
772+
if (resolvedSchema.allOf) {
773+
return {
774+
allOf: resolvedSchema.allOf.map((schema) => {
775+
return processSchema(schema);
776+
})
777+
};
778+
}
779+
746780
if (resolvedSchema.type === 'object' && resolvedSchema.properties) {
747781
const schemaDetails = {
748782
type: resolvedSchema.type,
@@ -752,7 +786,7 @@ let QUERYPARAM = 'query',
752786
requiredProperties = new Set(resolvedSchema.required || []);
753787

754788
for (let [propName, propValue] of Object.entries(resolvedSchema.properties)) {
755-
if (!propValue.type) {
789+
if (!propValue.type && !propValue.anyOf && !propValue.oneOf && !propValue.allOf) {
756790
continue;
757791
}
758792
const propertyDetails = {
@@ -772,7 +806,23 @@ let QUERYPARAM = 'query',
772806
if (requiredProperties.has(propName)) {
773807
schemaDetails.required.push(propName);
774808
}
775-
if (propValue.properties) {
809+
810+
if (propValue.anyOf) {
811+
propertyDetails.anyOf = propValue.anyOf.map((schema) => {
812+
return processSchema(schema);
813+
});
814+
}
815+
else if (propValue.oneOf) {
816+
propertyDetails.oneOf = propValue.oneOf.map((schema) => {
817+
return processSchema(schema);
818+
});
819+
}
820+
else if (propValue.allOf) {
821+
propertyDetails.allOf = propValue.allOf.map((schema) => {
822+
return processSchema(schema);
823+
});
824+
}
825+
else if (propValue.properties) {
776826
let processedProperties = processSchema(propValue);
777827
propertyDetails.properties = processedProperties.properties;
778828
if (processedProperties.required) {
@@ -1482,6 +1532,21 @@ let QUERYPARAM = 'query',
14821532
return [{ [bodyKey]: bodyData }];
14831533
}
14841534

1535+
// For type fetching, process the original schema before any modifications
1536+
// This is done to preserve the anyOf, oneOf etc in the original schema
1537+
// since they are otherwise flattened while resolving the schema
1538+
if (context.enableTypeFetching && requestBodySchema) {
1539+
const originalSchema = requestBodySchema.schema || requestBodySchema,
1540+
resolvedSchema = resolveSchema(
1541+
context,
1542+
originalSchema,
1543+
{ resolveFor: TYPES_GENERATION });
1544+
1545+
if (resolvedSchema.type || resolvedSchema.anyOf || resolvedSchema.oneOf || resolvedSchema.allOf) {
1546+
resolvedSchemaTypes.push(processSchema(resolvedSchema));
1547+
}
1548+
}
1549+
14851550
if (requestBodySchema.$ref) {
14861551
requestBodySchema = resolveSchema(
14871552
context,
@@ -1611,11 +1676,6 @@ let QUERYPARAM = 'query',
16111676

16121677
}
16131678

1614-
if (context.enableTypeFetching && requestBodySchema.type !== undefined) {
1615-
const requestBodySchemaTypes = processSchema(requestBodySchema);
1616-
resolvedSchemaTypes.push(requestBodySchemaTypes);
1617-
}
1618-
16191679
// Generate multiple examples when either request or response contains more than one example
16201680
if (
16211681
isExampleBody &&

0 commit comments

Comments
 (0)