Skip to content

Commit bb34fcc

Browse files
author
Vishal Shingala
committed
Merge branch 'develop' of github.com:postmanlabs/openapi-to-postman
2 parents 75bec25 + 14f0eb0 commit bb34fcc

File tree

9 files changed

+605
-174
lines changed

9 files changed

+605
-174
lines changed

assets/json-schema-faker.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23469,6 +23469,9 @@ function extend() {
2346923469
var fn = keys[length].replace(/^x-/, '');
2347023470
var gen = this.support[fn];
2347123471
if (typeof gen === 'function') {
23472+
if (typeof schema[fn] === 'object' && schema[fn].hasOwnProperty('type')) {
23473+
continue;
23474+
}
2347223475
Object.defineProperty(schema, 'generate', {
2347323476
configurable: false,
2347423477
enumerable: false,

lib/deref.js

Lines changed: 41 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,17 @@ const _ = require('lodash'),
1616
'date-time': '<dateTime>',
1717
password: '<password>'
1818
},
19-
boolean: '<boolean>'
19+
boolean: '<boolean>',
20+
array: '<array>',
21+
object: '<object>'
22+
},
23+
SCHEMA_TYPES = {
24+
array: 'array',
25+
boolean: 'boolean',
26+
integer: 'integer',
27+
number: 'number',
28+
object: 'object',
29+
string: 'string'
2030
},
2131
PARAMETER_SOURCE = {
2232
REQUEST: 'REQUEST',
@@ -141,14 +151,6 @@ module.exports = {
141151
return { value: ERR_TOO_MANY_LEVELS };
142152
}
143153

144-
// Update max stack reached for all current refs that's being resolved
145-
if (!_.isEmpty(this._currentRefStack)) {
146-
_.forEach(this._currentRefStack, (refKey) => {
147-
_.set(schemaResolutionCache, [refKey, 'maxStack'],
148-
Math.max(_.get(schemaResolutionCache, [refKey, 'maxStack'], 0), stack));
149-
});
150-
}
151-
152154
if (!schema) {
153155
return { value: '<Error: Schema not found>' };
154156
}
@@ -177,10 +179,6 @@ module.exports = {
177179
return this.resolveAllOf(schema.allOf, parameterSourceOption, components, schemaResolutionCache, resolveFor,
178180
resolveTo, stack, _.cloneDeep(seenRef), stackLimit);
179181
}
180-
if (schema.additionalProperties && !_.isBoolean(schema.additionalProperties)) {
181-
schema.additionalProperties = this.resolveRefs(schema.additionalProperties, parameterSourceOption,
182-
components, schemaResolutionCache, resolveFor, resolveTo, stack, _.cloneDeep(seenRef), stackLimit);
183-
}
184182
if (schema.$ref && _.isFunction(schema.$ref.split)) {
185183
let refKey = schema.$ref,
186184
outerProperties = concreteUtils.getOuterPropsIfIsSupported(schema);
@@ -201,20 +199,6 @@ module.exports = {
201199
return { value: 'reference ' + schema.$ref + ' not found in the OpenAPI spec' };
202200
}
203201

204-
if (_.get(schemaResolutionCache, [refKey, 'schema'])) {
205-
// maxStack for cached schema is how deep of nesting level we reached while resolving that schema
206-
let maxStack = _.get(schemaResolutionCache, [refKey, 'maxStack'], 0),
207-
// resLevel of perticuler cached schema is nesting level at which schema was resolved
208-
resLevel = _.get(schemaResolutionCache, [refKey, 'resLevel'], stackLimit);
209-
210-
/**
211-
* use cached schema if it was resolved at level lower or equal then at current stack level or
212-
* if cached schema is resolved fully (it does not contain ERR_TOO_MANY_LEVELS value in sub schema)
213-
*/
214-
if (resLevel <= stack || maxStack < stackLimit) {
215-
return schemaResolutionCache[refKey].schema;
216-
}
217-
}
218202
// something like #/components/schemas/PaginationEnvelope/properties/page
219203
// will be resolved - we don't care about anything after the components part
220204
// splitRef.slice(1) will return ['components', 'schemas', 'PaginationEnvelope', 'properties', 'page']
@@ -235,32 +219,33 @@ module.exports = {
235219
resolvedSchema = concreteUtils.addOuterPropsToRefSchemaIfIsSupported(resolvedSchema, outerProperties);
236220
}
237221
if (resolvedSchema) {
238-
// add current ref that's being resolved in ref stack
239-
!_.isArray(this._currentRefStack) && (this._currentRefStack = []);
240-
this._currentRefStack.push(refKey);
241-
242222
let refResolvedSchema = this.resolveRefs(resolvedSchema, parameterSourceOption,
243223
components, schemaResolutionCache, resolveFor, resolveTo, stack, _.cloneDeep(seenRef), stackLimit);
244224

245-
// remove current ref that's being resolved from stack as soon as resolved
246-
_.isArray(this._currentRefStack) && (this._currentRefStack.pop());
247-
248-
if (refResolvedSchema && refResolvedSchema.value !== ERR_TOO_MANY_LEVELS) {
249-
_.set(schemaResolutionCache, [refKey, 'resLevel'], stack);
250-
_.set(schemaResolutionCache, [refKey, 'schema'], refResolvedSchema);
251-
}
252-
253225
return refResolvedSchema;
254226
}
255227
return { value: 'reference ' + schema.$ref + ' not found in the OpenAPI spec' };
256228
}
257-
if (concreteUtils.compareTypes(schema.type, 'objects') || schema.hasOwnProperty('properties')) {
229+
if (concreteUtils.compareTypes(schema.type, SCHEMA_TYPES.object) || schema.hasOwnProperty('properties') ||
230+
schema.hasOwnProperty('additionalProperties')) {
258231
// go through all props
259-
schema.type = 'object';
260-
if (schema.hasOwnProperty('properties')) {
232+
schema.type = SCHEMA_TYPES.object;
233+
if (_.has(schema, 'properties') || _.has(schema, 'additionalProperties')) {
261234
// shallow cloning schema object except properties object
262-
let tempSchema = _.omit(schema, 'properties');
263-
tempSchema.properties = {};
235+
let tempSchema = _.omit(schema, ['properties', 'additionalProperties']);
236+
237+
if (_.has(schema, 'additionalProperties')) {
238+
// don't resolve boolean values
239+
if (_.isBoolean(schema.additionalProperties)) {
240+
tempSchema.additionalProperties = schema.additionalProperties;
241+
}
242+
else {
243+
tempSchema.additionalProperties = this.resolveRefs(schema.additionalProperties, parameterSourceOption,
244+
components, schemaResolutionCache, resolveFor, resolveTo, stack, _.cloneDeep(seenRef), stackLimit);
245+
}
246+
}
247+
248+
!_.isEmpty(schema.properties) && (tempSchema.properties = {});
264249
for (prop in schema.properties) {
265250
if (schema.properties.hasOwnProperty(prop)) {
266251
/* eslint-disable max-depth */
@@ -273,9 +258,17 @@ module.exports = {
273258
}
274259

275260
if (property.readOnly && parameterSourceOption === PARAMETER_SOURCE.REQUEST) {
261+
// remove property from required as it'll not be present in resolved schema
262+
if (_.includes(tempSchema.required, prop)) {
263+
_.remove(tempSchema.required, _.matches(prop));
264+
}
276265
continue;
277266
}
278267
else if (property.writeOnly && parameterSourceOption === PARAMETER_SOURCE.RESPONSE) {
268+
// remove property from required as it'll not be present in resolved schema
269+
if (_.includes(tempSchema.required, prop)) {
270+
_.remove(tempSchema.required, _.matches(prop));
271+
}
279272
continue;
280273
}
281274
/* eslint-enable */
@@ -288,10 +281,10 @@ module.exports = {
288281

289282
// Override deefault value to appropriate type representation for parameter resolution to schema
290283
if (resolveFor === 'CONVERSION' && resolveTo === 'schema') {
291-
schema.default = '<object>';
284+
schema.default = type.object;
292285
}
293286
}
294-
else if (concreteUtils.compareTypes(schema.type, 'array') && schema.items) {
287+
else if (concreteUtils.compareTypes(schema.type, SCHEMA_TYPES.array) && schema.items) {
295288
/*
296289
For VALIDATION - keep minItems and maxItems properties defined by user in schema as is
297290
FOR CONVERSION -
@@ -350,11 +343,11 @@ module.exports = {
350343
}
351344
else {
352345
return {
353-
type: 'object'
346+
type: SCHEMA_TYPES.object
354347
};
355348
}
356349
if (!schema.type) {
357-
schema.type = 'string';
350+
schema.type = SCHEMA_TYPES.string;
358351
}
359352

360353
// Discard format if not supported by both json-schema-faker and ajv or pattern is also defined

lib/schemaUtils.js

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ module.exports = {
406406
let example = _.get(parameter, 'example'),
407407
examples = _.values(_.get(parameter, 'examples'));
408408

409-
if (example) {
409+
if (example !== undefined) {
410410
_.set(parameter, 'schema.example', example);
411411
}
412412
else if (examples) {
@@ -915,7 +915,7 @@ module.exports = {
915915
convertPathVariables: function(type, providedPathVars, commonPathVars, components, options, schemaCache) {
916916
options = _.merge({}, defaultOptions, options);
917917

918-
var variables = providedPathVars;
918+
var variables = [];
919919
// converting the base uri path variables, if any
920920
// commonPathVars is an object for type = root/method
921921
// array otherwise
@@ -948,7 +948,8 @@ module.exports = {
948948
});
949949
}
950950

951-
return variables;
951+
// keep already provided varables (server variables) at last
952+
return _.concat(variables, providedPathVars);
952953
},
953954

954955
/**
@@ -1429,16 +1430,21 @@ module.exports = {
14291430
else if (bodyObj.schema) {
14301431
if (bodyObj.schema.hasOwnProperty('$ref')) {
14311432
let outerProps = concreteUtils.getOuterPropsIfIsSupported(bodyObj.schema),
1433+
resolvedSchema;
1434+
1435+
// skip beforehand resolution for OAS 3.0
1436+
if (outerProps) {
14321437
resolvedSchema = this.getRefObject(bodyObj.schema.$ref, components, options);
1433-
bodyObj.schema = concreteUtils.addOuterPropsToRefSchemaIfIsSupported(resolvedSchema, outerProps);
1438+
bodyObj.schema = concreteUtils.addOuterPropsToRefSchemaIfIsSupported(resolvedSchema, outerProps);
1439+
}
14341440
}
14351441
if (options.schemaFaker) {
14361442
if (this.getHeaderFamily(contentType) === HEADER_TYPE.XML) {
14371443
schemaFormat = SCHEMA_FORMATS.XML;
14381444
}
14391445
// Do not fake schemas if the complexity score is 10
14401446
if (options.complexityScore === 10) {
1441-
schemaType = bodyObj.schema.type;
1447+
schemaType = _.get(this.getRefObject(bodyObj.schema.$ref, components, options), 'type');
14421448
if (schemaType === 'object') {
14431449
return {
14441450
value: '<Error: Spec size too large, skipping faking of schemas>'
@@ -1760,12 +1766,14 @@ module.exports = {
17601766
// handling for the urlencoded media type
17611767
if (contentObj.hasOwnProperty(URLENCODED)) {
17621768
rDataMode = 'urlencoded';
1763-
if (contentObj[URLENCODED].hasOwnProperty('schema') && contentObj[URLENCODED].schema.hasOwnProperty('$ref')) {
1764-
contentObj[URLENCODED].schema = this.getRefObject(contentObj[URLENCODED].schema.$ref, components, options);
1765-
}
17661769
bodyData = this.convertToPmBodyData(contentObj[URLENCODED], requestType, URLENCODED,
17671770
PARAMETER_SOURCE.REQUEST, options.indentCharacter, components, options, schemaCache);
17681771
encoding = contentObj[URLENCODED].encoding ? contentObj[URLENCODED].encoding : {};
1772+
1773+
if (contentObj[URLENCODED].hasOwnProperty('schema') && contentObj[URLENCODED].schema.hasOwnProperty('$ref')) {
1774+
contentObj[URLENCODED].schema = this.getRefObject(contentObj[URLENCODED].schema.$ref, components, options);
1775+
}
1776+
17691777
// create query parameters and add it to the request body object
17701778
_.forOwn(bodyData, (value, key) => {
17711779

@@ -2054,6 +2062,10 @@ module.exports = {
20542062
options = _.merge({}, defaultOptions, options);
20552063
var refObj, savedSchema;
20562064

2065+
if (typeof $ref !== 'string') {
2066+
return { value: `Invalid $ref: ${$ref} was found` };
2067+
}
2068+
20572069
savedSchema = $ref.split('/').slice(1).map((elem) => {
20582070
// https://swagger.io/docs/specification/using-ref#escape
20592071
// since / is the default delimiter, slashes are escaped with ~1

0 commit comments

Comments
 (0)