Skip to content

Commit

Permalink
feat: support multiple combiners (#82)
Browse files Browse the repository at this point in the history
* feat: support multiple combiners

* chore: allOf goes first

* refactor: tweak mergeOneOrAnyOf
  • Loading branch information
P0lip authored Oct 5, 2020
1 parent 985268c commit f9f804f
Show file tree
Hide file tree
Showing 14 changed files with 470 additions and 57 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
"ts-jest": "^24.0.2",
"tslint": "^5.19.0",
"tslint-config-stoplight": "^1.4.0",
"typescript": "^3.7.5"
"typescript": "^4.0.3"
},
"lint-staged": {
"*.{ts,tsx}$": [
Expand Down
64 changes: 64 additions & 0 deletions src/components/__tests__/Property.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -416,4 +416,68 @@ describe('Property component', () => {
expect(wrapper.find(Types)).toHaveProp('title', void 0);
});
});

test("no title for combiner's children", () => {
const schema: JSONSchema4 = {
type: 'object',
title: 'Account',
allOf: [
{
type: 'object',
properties: {
type: {
type: 'string',
enum: ['admin', 'editor'],
},
enabled: {
type: 'boolean',
description: 'Is this account enabled',
},
},
required: ['type'],
},
],
oneOf: [
{
type: 'object',
title: 'Admin',
properties: {
root: {
type: 'boolean',
},
group: {
type: 'string',
},
expirationDate: {
type: 'string',
},
},
},
{
type: 'object',
title: 'Editor',
properties: {
supervisor: {
type: 'string',
},
key: {
type: 'string',
},
},
},
],
};

const tree = new SchemaTree(schema, new TreeState(), {
expandedDepth: Infinity,
mergeAllOf: true,
resolveRef: void 0,
shouldResolveEagerly: false,
onPopulate: void 0,
});

tree.populate();
const wrapper = shallow(<Property node={Array.from(tree)[1]} />);
expect(wrapper.children().first()).toEqual(wrapper.find(Types));
});
});
2 changes: 1 addition & 1 deletion src/components/shared/Property.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function shouldShowPropertyName(treeNode: SchemaTreeListNode) {
if (treeNode.parent === null) return false;
try {
const { schemaNode } = getSchemaNodeMetadata(treeNode.parent);
if (!('type' in schemaNode)) {
if (!('type' in schemaNode) || 'combiner' in schemaNode) {
return false;
}

Expand Down
180 changes: 180 additions & 0 deletions src/tree/__tests__/__snapshots__/tree.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,183 @@ exports[`SchemaTree expanding $refs in allOf given very complex model with circu
└─ children
"
`;

exports[`SchemaTree tree correctness given anyOf combiner placed next to allOf given allOf merging disabled, should preserve both combiners 1`] = `
"├─ 0
│ └─ #
│ ├─ type: object
│ ├─ combiner: anyOf
│ └─ children
│ ├─ 0
│ │ └─ #/anyOf/0
│ │ ├─ type: object
│ │ └─ children
│ │ ├─ 0
│ │ │ └─ #/anyOf/0/properties/root
│ │ │ └─ type: boolean
│ │ ├─ 1
│ │ │ └─ #/anyOf/0/properties/group
│ │ │ └─ type: string
│ │ └─ 2
│ │ └─ #/anyOf/0/properties/expirationDate
│ │ └─ type: string
│ └─ 1
│ └─ #/anyOf/1
│ ├─ type: object
│ └─ children
│ ├─ 0
│ │ └─ #/anyOf/1/properties/supervisor
│ │ └─ type: string
│ └─ 1
│ └─ #/anyOf/1/properties/key
│ └─ type: string
└─ 1
└─ #
├─ type: object
├─ combiner: allOf
└─ children
└─ 0
└─ #/allOf/0
├─ type: object
└─ children
├─ 0
│ └─ #/allOf/0/properties/type
│ └─ type: string
└─ 1
└─ #/allOf/0/properties/enabled
└─ type: boolean
"
`;

exports[`SchemaTree tree correctness given anyOf combiner placed next to allOf given allOf merging enabled, should merge contents of allOf combiners 1`] = `
"└─ #
├─ type: object
├─ combiner: anyOf
└─ children
├─ 0
│ └─ #/anyOf/0
│ ├─ type: object
│ └─ children
│ ├─ 0
│ │ └─ #/anyOf/0/properties/type
│ │ └─ type: string
│ ├─ 1
│ │ └─ #/anyOf/0/properties/enabled
│ │ └─ type: boolean
│ ├─ 2
│ │ └─ #/anyOf/0/properties/root
│ │ └─ type: boolean
│ ├─ 3
│ │ └─ #/anyOf/0/properties/group
│ │ └─ type: string
│ └─ 4
│ └─ #/anyOf/0/properties/expirationDate
│ └─ type: string
└─ 1
└─ #/anyOf/1
├─ type: object
└─ children
├─ 0
│ └─ #/anyOf/1/properties/type
│ └─ type: string
├─ 1
│ └─ #/anyOf/1/properties/enabled
│ └─ type: boolean
├─ 2
│ └─ #/anyOf/1/properties/supervisor
│ └─ type: string
└─ 3
└─ #/anyOf/1/properties/key
└─ type: string
"
`;

exports[`SchemaTree tree correctness given oneOf combiner placed next to allOf given allOf merging disabled, should preserve both combiners 1`] = `
"├─ 0
│ └─ #
│ ├─ type: object
│ ├─ combiner: oneOf
│ └─ children
│ ├─ 0
│ │ └─ #/oneOf/0
│ │ ├─ type: object
│ │ └─ children
│ │ ├─ 0
│ │ │ └─ #/oneOf/0/properties/root
│ │ │ └─ type: boolean
│ │ ├─ 1
│ │ │ └─ #/oneOf/0/properties/group
│ │ │ └─ type: string
│ │ └─ 2
│ │ └─ #/oneOf/0/properties/expirationDate
│ │ └─ type: string
│ └─ 1
│ └─ #/oneOf/1
│ ├─ type: object
│ └─ children
│ ├─ 0
│ │ └─ #/oneOf/1/properties/supervisor
│ │ └─ type: string
│ └─ 1
│ └─ #/oneOf/1/properties/key
│ └─ type: string
└─ 1
└─ #
├─ type: object
├─ combiner: allOf
└─ children
└─ 0
└─ #/allOf/0
├─ type: object
└─ children
├─ 0
│ └─ #/allOf/0/properties/type
│ └─ type: string
└─ 1
└─ #/allOf/0/properties/enabled
└─ type: boolean
"
`;

exports[`SchemaTree tree correctness given oneOf combiner placed next to allOf given allOf merging enabled, should merge contents of allOf combiners 1`] = `
"└─ #
├─ type: object
├─ combiner: oneOf
└─ children
├─ 0
│ └─ #/oneOf/0
│ ├─ type: object
│ └─ children
│ ├─ 0
│ │ └─ #/oneOf/0/properties/type
│ │ └─ type: string
│ ├─ 1
│ │ └─ #/oneOf/0/properties/enabled
│ │ └─ type: boolean
│ ├─ 2
│ │ └─ #/oneOf/0/properties/root
│ │ └─ type: boolean
│ ├─ 3
│ │ └─ #/oneOf/0/properties/group
│ │ └─ type: string
│ └─ 4
│ └─ #/oneOf/0/properties/expirationDate
│ └─ type: string
└─ 1
└─ #/oneOf/1
├─ type: object
└─ children
├─ 0
│ └─ #/oneOf/1/properties/type
│ └─ type: string
├─ 1
│ └─ #/oneOf/1/properties/enabled
│ └─ type: boolean
├─ 2
│ └─ #/oneOf/1/properties/supervisor
│ └─ type: string
└─ 3
└─ #/oneOf/1/properties/key
└─ type: string
"
`;
82 changes: 82 additions & 0 deletions src/tree/__tests__/tree.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1283,6 +1283,88 @@ describe('SchemaTree', () => {
"
`);
});

describe.each(['anyOf', 'oneOf'])('given %s combiner placed next to allOf', combiner => {
let schema: JSONSchema4;

beforeEach(() => {
schema = {
type: 'object',
title: 'Account',
allOf: [
{
type: 'object',
properties: {
type: {
type: 'string',
enum: ['admin', 'editor'],
},
enabled: {
type: 'boolean',
description: 'Is this account enabled',
},
},
required: ['type'],
},
],
[combiner]: [
{
type: 'object',
title: 'Admin',
properties: {
root: {
type: 'boolean',
},
group: {
type: 'string',
},
expirationDate: {
type: 'string',
},
},
},
{
type: 'object',
title: 'Editor',
properties: {
supervisor: {
type: 'string',
},
key: {
type: 'string',
},
},
},
],
};
});

test('given allOf merging disabled, should preserve both combiners', () => {
const tree = new SchemaTree(schema, new SchemaTreeState(), {
expandedDepth: Infinity,
mergeAllOf: false,
resolveRef: void 0,
shouldResolveEagerly: true,
onPopulate: void 0,
});

tree.populate();
expect(printTree(tree)).toMatchSnapshot();
});

test('given allOf merging enabled, should merge contents of allOf combiners', () => {
const tree = new SchemaTree(schema, new SchemaTreeState(), {
expandedDepth: Infinity,
mergeAllOf: true,
resolveRef: void 0,
shouldResolveEagerly: true,
onPopulate: void 0,
});

tree.populate();
expect(printTree(tree)).toMatchSnapshot();
});
});
});

test('given visible $ref node, should try to inject the title immediately', () => {
Expand Down
5 changes: 4 additions & 1 deletion src/tree/__tests__/utils/printTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import { getNodeMetadata } from '../../metadata';
import { SchemaTree } from '../../tree';

export function printTree(tree: SchemaTree) {
return treeify.asTree(prepareTree(tree.root.children[0]) as treeify.TreeObject, true, true);
const root: unknown =
tree.root.children.length > 1 ? tree.root.children.map(prepareTree) : prepareTree(tree.root.children[0]);

return treeify.asTree(root as treeify.TreeObject, true, true);
}

type PrintableNode = {
Expand Down
Loading

0 comments on commit f9f804f

Please sign in to comment.