Skip to content
This repository was archived by the owner on Nov 8, 2024. It is now read-only.

Support additionalProperties with subschema #611

Merged
merged 1 commit into from
Feb 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions packages/openapi2-parser/lib/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,16 +114,29 @@ class DataStructureGenerator {
// Create member elements for required keys which are not defined in properties
const missingRequiredProperties = required.filter(name => properties[name] === undefined);
const requiredMembers = missingRequiredProperties.map((name) => {
const member = new this.minim.elements.Member(name);
let member;

if (schema.additionalProperties !== undefined && typeof schema.additionalProperties !== 'boolean') {
member = this.generateMember(name, schema.additionalProperties);
} else {
member = new this.minim.elements.Member(name);
}

member.attributes.set('typeAttributes', ['required']);
return member;
});
element.content.push(...requiredMembers);

if (schema.additionalProperties === false) {
if (schema.additionalProperties !== undefined && schema.additionalProperties !== true) {
const typeAttributes = element.attributes.get('typeAttributes') || new this.minim.elements.Array([]);
typeAttributes.push('fixed-type');
typeAttributes.push('fixedType');
element.attributes.set('typeAttributes', typeAttributes);

if (schema.additionalProperties !== false) {
const member = this.generateMember('', schema.additionalProperties);
member.attributes.set('variable', true);
element.content.push(member);
}
}

return element;
Expand Down
85 changes: 84 additions & 1 deletion packages/openapi2-parser/test/schema-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,90 @@ describe('JSON Schema to Data Structure', () => {
expect(dataStructure.content).to.be.instanceof(ObjectElement);

expect(dataStructure.content.length).to.equal(0);
expect(dataStructure.content.attributes.getValue('typeAttributes')).to.deep.equal(['fixed-type']);
expect(dataStructure.content.attributes.getValue('typeAttributes')).to.deep.equal(['fixedType']);
});

it('produces object with additionalProperties as false with required properties', () => {
const schema = {
type: 'object',
required: ['type'],
additionalProperties: false,
};

const dataStructure = schemaToDataStructure(schema);

expect(dataStructure.element).to.equal('dataStructure');
expect(dataStructure.content).to.be.instanceof(ObjectElement);

expect(dataStructure.content.length).to.equal(1);
expect(dataStructure.content.attributes.getValue('typeAttributes')).to.deep.equal(['fixedType']);

const type = dataStructure.content.getMember('type');
expect(type).to.be.instanceof(MemberElement);
expect(type.attributes.getValue('variable')).to.be.undefined;
expect(type.attributes.getValue('typeAttributes')).to.deep.equal(['required']);
expect(type.value).to.be.undefined;
});

it('produces object with additionalProperties containing a structure', () => {
const schema = {
type: 'object',
additionalProperties: {
type: 'string',
},
};

const dataStructure = schemaToDataStructure(schema);

expect(dataStructure.element).to.equal('dataStructure');
expect(dataStructure.content).to.be.instanceof(ObjectElement);

expect(dataStructure.content.length).to.equal(1);

const member = dataStructure.content.getMember('');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically, the key of the member is a "sample" key, but we don't really have one so I have used an empty string.

Note this structure is equivalent to API Blueprint, except the key name where API Blueprint provides a sample name.

+ Response 200 (application/json)
    + Attributes (fixed-type)
        + *name* (string)

expect(member).to.be.instanceof(MemberElement);
expect(member.attributes.getValue('variable')).to.be.true;
expect(member.value).to.be.instanceof(StringElement);

expect(dataStructure.content.attributes.getValue('typeAttributes')).to.deep.equal(['fixedType']);
});

it('produces object with required additionalProperties containing a structure', () => {
const schema = {
type: 'object',
additionalProperties: {
type: 'string',
},
required: ['type', 'mode'],
};

const dataStructure = schemaToDataStructure(schema);

expect(dataStructure.element).to.equal('dataStructure');
expect(dataStructure.content).to.be.instanceof(ObjectElement);
expect(dataStructure.content.attributes.getValue('typeAttributes')).to.deep.equal(['fixedType']);

expect(dataStructure.content.length).to.equal(3);

// Variable property
const variable = dataStructure.content.getMember('');
expect(variable).to.be.instanceof(MemberElement);
expect(variable.attributes.getValue('variable')).to.be.true;
expect(variable.value).to.be.instanceof(StringElement);

// Required 'type' property
const type = dataStructure.content.getMember('type');
expect(type).to.be.instanceof(MemberElement);
expect(type.attributes.getValue('variable')).to.be.undefined;
expect(type.attributes.getValue('typeAttributes')).to.deep.equal(['required']);
expect(type.value).to.be.instanceof(StringElement);

// Required 'mode' property
const mode = dataStructure.content.getMember('mode');
expect(mode).to.be.instanceof(MemberElement);
expect(mode.attributes.getValue('variable')).to.be.undefined;
expect(mode.attributes.getValue('typeAttributes')).to.deep.equal(['required']);
expect(mode.value).to.be.instanceof(StringElement);
});
});

Expand Down