Skip to content

Commit 077462f

Browse files
github-actions[bot]barshan23AyushShriweb-flow
authored
Release version v5.2.0 (#869)
* Enhance type fetching to support composite schemas (anyOf, oneOf, allOf) * Refactor type fetching logic to process original schema before modifications * Update parameter resolution logic to handle 'PROCESSING' state in schema conversion * Refactor schema processing to conditionally push resolved schema types for 'PROCESSING' state * Add support for composite schemas (anyOf, oneOf, allOf) in conversion process * schema changes for 2-way-sync * fixed test * Enhance composite schema tests to validate specific structures for anyOf cases * removed examples * Refactor ESLint rules and remove unnecessary one-var disables; enhance schema resolution logic for composite parameters in conversion tests (#868) Refactor ESLint rules and remove unnecessary one-var disables; enhance schema resolution logic for composite parameters in conversion tests (#868) * added deprecated example * added test for description * Resolved comments * Bug Fixes * refactored * Prepare release v5.2.0 --------- Co-authored-by: Avishek Saha <[email protected]> Co-authored-by: barshan23 <[email protected]> Co-authored-by: Ayush Shrivastav <[email protected]> Co-authored-by: GitHub Actions <[email protected]>
1 parent a4d0aa4 commit 077462f

File tree

9 files changed

+861
-50
lines changed

9 files changed

+861
-50
lines changed

.eslintrc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@
195195
"no-unneeded-ternary": "error",
196196
"no-whitespace-before-property": "error",
197197
"object-curly-spacing": ["error", "always"],
198-
"one-var": ["error", "always"],
199198
"one-var-declaration-per-line": "error",
200199
"operator-assignment": "error",
201200
"operator-linebreak": ["error", "after"],

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## [Unreleased]
44

5+
## [v5.2.0] - 2025-09-19
6+
57
## [v5.1.0] - 2025-09-01
68

79
## [v5.0.2] - 2025-08-25
@@ -661,7 +663,9 @@ Newer releases follow the [Keep a Changelog](https://keepachangelog.com/en/1.0.0
661663

662664
- Base release
663665

664-
[Unreleased]: https://github.com/postmanlabs/openapi-to-postman/compare/v5.1.0...HEAD
666+
[Unreleased]: https://github.com/postmanlabs/openapi-to-postman/compare/v5.2.0...HEAD
667+
668+
[v5.2.0]: https://github.com/postmanlabs/openapi-to-postman/compare/v5.1.0...v5.2.0
665669

666670
[v5.1.0]: https://github.com/postmanlabs/openapi-to-postman/compare/v5.0.2...v5.1.0
667671

libV2/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/* eslint-disable one-var */
21
const _ = require('lodash'),
32
{ Collection } = require('postman-collection/lib/collection/collection'),
43
GraphLib = require('graphlib'),

libV2/schemaUtils.js

Lines changed: 140 additions & 34 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,30 @@ let QUERYPARAM = 'query',
493494
* @returns {Object} Resolved schema
494495
*/
495496
resolveAllOfSchema = (context, schema, stack = 0, resolveFor = CONVERSION, seenRef = {}, currentPath = '') => {
497+
/*
498+
For TYPES_GENERATION, we do not want to merge the allOf schemas
499+
instead we want to keep them separate so that we can generate types like:
500+
allOf: [
501+
{ $ref: '#/components/schemas/User' },
502+
{
503+
type: 'object',
504+
properties: {
505+
timestamp: { type: 'string', format: 'date-time' }
506+
}
507+
}
508+
]
509+
If we merge the schemas, we will loose the information that the schema was
510+
a combination of multiple schemas
511+
*/
512+
if (resolveFor === TYPES_GENERATION) {
513+
return {
514+
allOf: _.map(schema.allOf, (schema) => {
515+
// eslint-disable-next-line no-use-before-define
516+
return _resolveSchema(context, schema, stack, resolveFor, _.cloneDeep(seenRef), currentPath);
517+
})
518+
};
519+
}
520+
496521
try {
497522
return mergeAllOf(_.assign(schema, {
498523
allOf: _.map(schema.allOf, (schema) => {
@@ -543,7 +568,6 @@ let QUERYPARAM = 'query',
543568

544569
stack++;
545570

546-
// eslint-disable-next-line one-var
547571
const compositeKeyword = schema.anyOf ? 'anyOf' : 'oneOf',
548572
{ concreteUtils } = context;
549573

@@ -618,7 +642,6 @@ let QUERYPARAM = 'query',
618642
writeOnlyPropCache: context.writeOnlyPropCache
619643
};
620644

621-
// eslint-disable-next-line one-var
622645
const newReadPropCache = context.readOnlyPropCache,
623646
newWritePropCache = context.writeOnlyPropCache;
624647

@@ -684,7 +707,7 @@ let QUERYPARAM = 'query',
684707
let { parametersResolution } = context.computedOptions;
685708

686709
// Override default value to schema for CONVERSION only for parmeter resolution set to schema
687-
if (resolveFor === CONVERSION && parametersResolution === 'schema') {
710+
if ((resolveFor === CONVERSION || resolveFor === TYPES_GENERATION) && parametersResolution === 'schema') {
688711
if (!schema.hasOwnProperty('format')) {
689712
schema.default = '<' + schema.type + '>';
690713
}
@@ -743,16 +766,42 @@ let QUERYPARAM = 'query',
743766
* @returns {Object} The processed schema details.
744767
*/
745768
processSchema = (resolvedSchema) => {
769+
if (resolvedSchema.anyOf) {
770+
return {
771+
anyOf: resolvedSchema.anyOf.map((schema) => {
772+
return processSchema(schema);
773+
})
774+
};
775+
}
776+
777+
if (resolvedSchema.oneOf) {
778+
return {
779+
oneOf: resolvedSchema.oneOf.map((schema) => {
780+
return processSchema(schema);
781+
})
782+
};
783+
}
784+
785+
if (resolvedSchema.allOf) {
786+
return {
787+
allOf: resolvedSchema.allOf.map((schema) => {
788+
return processSchema(schema);
789+
})
790+
};
791+
}
792+
746793
if (resolvedSchema.type === 'object' && resolvedSchema.properties) {
747794
const schemaDetails = {
795+
description: resolvedSchema.description,
796+
title: resolvedSchema.title,
748797
type: resolvedSchema.type,
749798
properties: {},
750799
required: []
751800
},
752801
requiredProperties = new Set(resolvedSchema.required || []);
753802

754803
for (let [propName, propValue] of Object.entries(resolvedSchema.properties)) {
755-
if (!propValue.type) {
804+
if (!propValue.type && !propValue.anyOf && !propValue.oneOf && !propValue.allOf) {
756805
continue;
757806
}
758807
const propertyDetails = {
@@ -772,7 +821,23 @@ let QUERYPARAM = 'query',
772821
if (requiredProperties.has(propName)) {
773822
schemaDetails.required.push(propName);
774823
}
775-
if (propValue.properties) {
824+
825+
if (propValue.anyOf) {
826+
propertyDetails.anyOf = propValue.anyOf.map((schema) => {
827+
return processSchema(schema);
828+
});
829+
}
830+
else if (propValue.oneOf) {
831+
propertyDetails.oneOf = propValue.oneOf.map((schema) => {
832+
return processSchema(schema);
833+
});
834+
}
835+
else if (propValue.allOf) {
836+
propertyDetails.allOf = propValue.allOf.map((schema) => {
837+
return processSchema(schema);
838+
});
839+
}
840+
else if (propValue.properties) {
776841
let processedProperties = processSchema(propValue);
777842
propertyDetails.properties = processedProperties.properties;
778843
if (processedProperties.required) {
@@ -1113,16 +1178,24 @@ let QUERYPARAM = 'query',
11131178
* Gets the description of the parameter.
11141179
* If the parameter is required, it prepends a `(Requried)` before the parameter description
11151180
* If the parameter type is enum, it appends the possible enum values
1181+
* @param {object} context - Global context object controlling behavior
11161182
* @param {object} parameter - input param for which description needs to be returned
11171183
* @returns {string} description of the parameters
11181184
*/
1119-
getParameterDescription = (parameter) => {
1185+
getParameterDescription = (context, parameter) => {
11201186
if (!_.isObject(parameter)) {
11211187
return '';
11221188
}
11231189

1124-
return (parameter.required ? '(Required) ' : '') + (parameter.description || '') +
1125-
(parameter.enum ? ' (This can only be one of ' + parameter.enum + ')' : '');
1190+
const requiredPrefix = (context && !context.enableTypeFetching && parameter.required ? '(Required) ' : ''),
1191+
desc = parameter.description || '';
1192+
1193+
let enumDescription = '';
1194+
if (parameter && parameter.schema && parameter.schema.enum && !(context && context.enableTypeFetching)) {
1195+
enumDescription = ' (This can only be one of ' + parameter.schema.enum + ')';
1196+
}
1197+
1198+
return requiredPrefix + desc + enumDescription;
11261199
},
11271200

11281201
/**
@@ -1141,7 +1214,7 @@ let QUERYPARAM = 'query',
11411214
{ enableOptionalParameters } = context.computedOptions;
11421215

11431216
let serialisedValue = '',
1144-
description = getParameterDescription(param),
1217+
description = getParameterDescription(context, param),
11451218
paramName = _.get(param, 'name'),
11461219
disabled = !enableOptionalParameters && _.get(param, 'required') !== true,
11471220
pmParams = [],
@@ -1421,7 +1494,6 @@ let QUERYPARAM = 'query',
14211494
});
14221495
});
14231496

1424-
// eslint-disable-next-line one-var
14251497
let responseExample,
14261498
responseExampleData;
14271499

@@ -1482,6 +1554,21 @@ let QUERYPARAM = 'query',
14821554
return [{ [bodyKey]: bodyData }];
14831555
}
14841556

1557+
// For type fetching, process the original schema before any modifications
1558+
// This is done to preserve the anyOf, oneOf etc in the original schema
1559+
// since they are otherwise flattened while resolving the schema
1560+
if (context.enableTypeFetching && requestBodySchema) {
1561+
const originalSchema = requestBodySchema.schema || requestBodySchema,
1562+
resolvedSchema = resolveSchema(
1563+
context,
1564+
originalSchema,
1565+
{ resolveFor: TYPES_GENERATION });
1566+
1567+
if (resolvedSchema.type || resolvedSchema.anyOf || resolvedSchema.oneOf || resolvedSchema.allOf) {
1568+
resolvedSchemaTypes.push(processSchema(resolvedSchema));
1569+
}
1570+
}
1571+
14851572
if (requestBodySchema.$ref) {
14861573
requestBodySchema = resolveSchema(
14871574
context,
@@ -1611,11 +1698,6 @@ let QUERYPARAM = 'query',
16111698

16121699
}
16131700

1614-
if (context.enableTypeFetching && requestBodySchema.type !== undefined) {
1615-
const requestBodySchemaTypes = processSchema(requestBodySchema);
1616-
resolvedSchemaTypes.push(requestBodySchemaTypes);
1617-
}
1618-
16191701
// Generate multiple examples when either request or response contains more than one example
16201702
if (
16211703
isExampleBody &&
@@ -1772,7 +1854,7 @@ let QUERYPARAM = 'query',
17721854
paramSchema.required = _.has(paramSchema, 'required') ?
17731855
paramSchema.required :
17741856
_.indexOf(requestBodySchema.required, key) !== -1;
1775-
description = getParameterDescription(paramSchema);
1857+
description = getParameterDescription(context, paramSchema);
17761858

17771859
if (typeof _.get(encoding, `[${key}].contentType`) === 'string') {
17781860
contentType = encoding[key].contentType;
@@ -2027,8 +2109,8 @@ let QUERYPARAM = 'query',
20272109
type: schema.type,
20282110
format: schema.format,
20292111
default: schema.default,
2030-
required: param.required || false,
2031-
deprecated: param.deprecated || false,
2112+
required: param.required,
2113+
deprecated: param.deprecated,
20322114
enum: schema.enum || undefined,
20332115
minLength: schema.minLength,
20342116
maxLength: schema.maxLength,
@@ -2054,14 +2136,18 @@ let QUERYPARAM = 'query',
20542136
param = resolveSchema(context, param);
20552137
}
20562138

2057-
if (_.has(param.schema, '$ref')) {
2058-
param.schema = resolveSchema(context, param.schema);
2059-
}
2060-
20612139
if (param.in !== QUERYPARAM || (!includeDeprecated && param.deprecated)) {
20622140
return;
20632141
}
20642142

2143+
const shouldResolveSchema = _.has(param, 'schema') &&
2144+
(_.has(param.schema, '$ref') || _.has(param.schema, 'anyOf') ||
2145+
_.has(param.schema, 'oneOf') || _.has(param.schema, 'allOf'));
2146+
2147+
if (shouldResolveSchema) {
2148+
param.schema = resolveSchema(context, param.schema);
2149+
}
2150+
20652151
let queryParamTypeInfo = {},
20662152
properties = {},
20672153
paramValue = resolveValueOfParameter(context, param);
@@ -2103,14 +2189,19 @@ let QUERYPARAM = 'query',
21032189
param = resolveSchema(context, param);
21042190
}
21052191

2106-
if (_.has(param.schema, '$ref')) {
2107-
param.schema = resolveSchema(context, param.schema);
2108-
}
2109-
21102192
if (param.in !== PATHPARAM) {
21112193
return;
21122194
}
21132195

2196+
2197+
const shouldResolveSchema = _.has(param, 'schema') &&
2198+
(_.has(param.schema, '$ref') || _.has(param.schema, 'anyOf') ||
2199+
_.has(param.schema, 'oneOf') || _.has(param.schema, 'allOf'));
2200+
2201+
if (shouldResolveSchema) {
2202+
param.schema = resolveSchema(context, param.schema);
2203+
}
2204+
21142205
let pathParamTypeInfo = {},
21152206
properties = {},
21162207
paramValue = resolveValueOfParameter(context, param);
@@ -2180,14 +2271,18 @@ let QUERYPARAM = 'query',
21802271
param = resolveSchema(context, param);
21812272
}
21822273

2183-
if (_.has(param.schema, '$ref')) {
2184-
param.schema = resolveSchema(context, param.schema);
2185-
}
2186-
21872274
if (param.in !== HEADER || (!includeDeprecated && param.deprecated)) {
21882275
return;
21892276
}
21902277

2278+
const shouldResolveSchema = _.has(param, 'schema') &&
2279+
(_.has(param.schema, '$ref') || _.has(param.schema, 'anyOf') ||
2280+
_.has(param.schema, 'oneOf') || _.has(param.schema, 'allOf'));
2281+
2282+
if (shouldResolveSchema) {
2283+
param.schema = resolveSchema(context, param.schema);
2284+
}
2285+
21912286
if (!keepImplicitHeaders && _.includes(IMPLICIT_HEADERS, _.toLower(_.get(param, 'name')))) {
21922287
return;
21932288
}
@@ -2340,14 +2435,25 @@ let QUERYPARAM = 'query',
23402435

23412436
headers.push(...serialisedHeader);
23422437

2343-
if (headerData && headerData.name && headerData.schema && headerData.schema.type) {
2344-
const { schema } = headerData;
2438+
if (headerData && headerData.name && headerData.schema) {
2439+
let { schema } = headerData;
2440+
const shouldResolveSchema = _.has(schema, '$ref') || _.has(schema, 'anyOf') ||
2441+
_.has(schema, 'oneOf') || _.has(schema, 'allOf');
2442+
2443+
if (shouldResolveSchema) {
2444+
schema = resolveSchema(context, schema);
2445+
}
2446+
2447+
if (!schema.type) {
2448+
return;
2449+
}
2450+
23452451
properties = {
23462452
type: schema.type,
23472453
format: schema.format,
23482454
default: schema.default,
2349-
required: schema.required || false,
2350-
deprecated: schema.deprecated || false,
2455+
required: schema.required,
2456+
deprecated: schema.deprecated,
23512457
enum: schema.enum || undefined,
23522458
minLength: schema.minLength,
23532459
maxLength: schema.maxLength,

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "openapi-to-postmanv2",
3-
"version": "5.1.0",
3+
"version": "5.2.0",
44
"description": "Convert a given OpenAPI specification to Postman Collection v2.0",
55
"homepage": "https://github.com/postmanlabs/openapi-to-postman",
66
"bugs": "https://github.com/postmanlabs/openapi-to-postman/issues",

test/data/valid_openapi/test1.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,10 @@
281281
"in": "query",
282282
"description": "component level query param",
283283
"required": false,
284+
"deprecated": false,
284285
"schema": {
285-
"type": "string"
286+
"type": "string",
287+
"enum": ["medium"]
286288
}
287289
}
288290
},

0 commit comments

Comments
 (0)