Skip to content

Commit

Permalink
fix: support circular oneOf/anyOf local props (#135)
Browse files Browse the repository at this point in the history
  • Loading branch information
RomanHotsiy committed Apr 27, 2022
1 parent 3c10a23 commit 7302dd3
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 5 deletions.
30 changes: 26 additions & 4 deletions src/traverse.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,19 @@ export function traverse(schema, options, spec, context) {
writeOnly: schema.writeOnly
}, schema.oneOf[0]);

return (
tryInferExample(schema) || traverse(firstOneOf, options, spec, context)
);
return traverseOneOrAnyOf(schema, firstOneOf)
}

if (schema.anyOf && schema.anyOf.length) {
popSchemaStack(seenSchemasStack, context);
return tryInferExample(schema) || traverse(schema.anyOf[0], options, spec, context);

// Make sure to pass down readOnly and writeOnly annotations from the parent
const firstAnyOf = Object.assign({
readOnly: schema.readOnly,
writeOnly: schema.writeOnly
}, schema.anyOf[0]);

return traverseOneOrAnyOf(schema, firstAnyOf)
}

if (schema.if && schema.then) {
Expand Down Expand Up @@ -151,4 +156,21 @@ export function traverse(schema, options, spec, context) {
writeOnly: schema.writeOnly,
type: type
};

function traverseOneOrAnyOf(schema, selectedSubSchema) {
const inferred = tryInferExample(schema);
if (inferred !== undefined) {
return inferred;
}

const localExample = traverse({...schema, oneOf: undefined, anyOf: undefined }, options, spec, context);
const subSchemaExample = traverse(selectedSubSchema, options, spec, context);

if (typeof localExample.value === 'object' && typeof subSchemaExample.value === 'object') {
const mergedExample = mergeDeep(localExample.value, subSchemaExample.value);
return {...subSchemaExample, value: mergedExample };
}

return subSchemaExample;
}
}
2 changes: 1 addition & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function mergeDeep(...objects) {
const isObject = obj => obj && typeof obj === 'object';

return objects.reduce((prev, obj) => {
Object.keys(obj).forEach(key => {
Object.keys(obj || {}).forEach(key => {
const pVal = prev[key];
const oVal = obj[key];

Expand Down
34 changes: 34 additions & 0 deletions test/integration.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,40 @@ describe('Integration', function() {
expected = 0;
expect(result).to.equal(expected);
});

it('should work with nested circular oneOf', function () {
result = OpenAPISampler.sample({ $ref: '#/definitions/A' }, {}, {
definitions: {
A: {
properties: {
a: { type: 'string' }
},
oneOf: [
{ $ref: '#/definitions/A' }
]
}
}
});
expected = { a: 'string' }
expect(result).to.deep.equal(expected);
});

it('should work with nested circular anyOf', function () {
result = OpenAPISampler.sample({ $ref: '#/definitions/A' }, {}, {
definitions: {
A: {
properties: {
a: { type: 'string' }
},
anyOf: [
{ $ref: '#/definitions/A' }
]
}
}
});
expected = { a: 'string' }
expect(result).to.deep.equal(expected);
});
});

describe('inferring type from root schema', function() {
Expand Down

0 comments on commit 7302dd3

Please sign in to comment.