Skip to content

Commit 0317064

Browse files
committed
feat: eager $ref resolution
1 parent 58fbeb5 commit 0317064

File tree

16 files changed

+277
-105
lines changed

16 files changed

+277
-105
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"@types/pluralize": "^0.0.29",
7070
"@types/react": "16.9.2",
7171
"@types/react-dom": "16.9.0",
72+
"@types/treeify": "^1.0.0",
7273
"babel-jest": "^24.9.0",
7374
"babel-loader": "^8.0.6",
7475
"copyfiles": "^2.1.1",

src/__stories__/JsonSchemaViewer.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ storiesOf('JsonSchemaViewer', module)
2222
defaultExpandedDepth={number('defaultExpandedDepth', 0)}
2323
expanded={boolean('expanded', false)}
2424
hideTopBar={boolean('hideTopBar', false)}
25+
shouldResolveEagerly={boolean('shouldResolveEagerly', false)}
2526
onGoToRef={action('onGoToRef')}
2627
/>
2728
))
@@ -34,6 +35,7 @@ storiesOf('JsonSchemaViewer', module)
3435
onGoToRef={action('onGoToRef')}
3536
maxRows={number('maxRows', 5)}
3637
mergeAllOf={boolean('mergeAllOf', true)}
38+
shouldResolveEagerly={boolean('shouldResolveEagerly', false)}
3739
/>
3840
))
3941
.add('custom row renderer', () => {

src/components/JsonSchemaViewer.tsx

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { action } from 'mobx';
55
import * as React from 'react';
66

77
import { JSONSchema4 } from 'json-schema';
8-
import { SchemaTree, SchemaTreeRefDereferenceFn } from '../tree/tree';
8+
import { SchemaTree, SchemaTreeOptions, SchemaTreeRefDereferenceFn } from '../tree/tree';
99
import { GoToRefHandler, RowRenderer } from '../types';
1010
import { isSchemaViewerEmpty } from '../utils/isSchemaViewerEmpty';
1111
import { SchemaTree as SchemaTreeComponent } from './SchemaTree';
@@ -25,6 +25,7 @@ export interface IJsonSchemaViewer {
2525
FallbackComponent?: typeof FallbackComponent;
2626
rowRenderer?: RowRenderer;
2727
resolveRef?: SchemaTreeRefDereferenceFn;
28+
shouldResolveEagerly?: boolean;
2829
}
2930

3031
export class JsonSchemaViewerComponent extends React.PureComponent<IJsonSchemaViewer & ErrorBoundaryForwardedProps> {
@@ -36,16 +37,21 @@ export class JsonSchemaViewerComponent extends React.PureComponent<IJsonSchemaVi
3637
super(props);
3738

3839
this.treeState = new TreeState();
39-
this.tree = new SchemaTree(props.schema, this.treeState, {
40-
expandedDepth: this.expandedDepth,
41-
mergeAllOf: this.mergeAllOf,
42-
resolveRef: this.props.resolveRef,
43-
});
40+
this.tree = new SchemaTree(props.schema, this.treeState, this.treeOptions);
4441
this.treeStore = new TreeStore(this.tree, this.treeState, {
4542
defaultExpandedDepth: this.expandedDepth,
4643
});
4744
}
4845

46+
protected get treeOptions(): SchemaTreeOptions {
47+
return {
48+
expandedDepth: this.expandedDepth,
49+
mergeAllOf: this.mergeAllOf,
50+
resolveRef: this.props.resolveRef,
51+
shouldResolveEagerly: !!this.props.shouldResolveEagerly,
52+
};
53+
}
54+
4955
protected get mergeAllOf() {
5056
return this.props.mergeAllOf !== false;
5157
}
@@ -77,17 +83,17 @@ export class JsonSchemaViewerComponent extends React.PureComponent<IJsonSchemaVi
7783
@action
7884
public componentDidUpdate(prevProps: Readonly<IJsonSchemaViewer>) {
7985
if (prevProps.resolveRef !== this.props.resolveRef) {
80-
this.tree.resolver = this.props.resolveRef;
86+
this.tree.treeOptions.resolveRef = this.props.resolveRef;
8187
}
8288

8389
if (
8490
this.treeStore.defaultExpandedDepth !== this.expandedDepth ||
8591
prevProps.schema !== this.props.schema ||
86-
prevProps.mergeAllOf !== this.props.mergeAllOf
92+
prevProps.mergeAllOf !== this.props.mergeAllOf ||
93+
prevProps.shouldResolveEagerly !== this.props.shouldResolveEagerly
8794
) {
8895
this.treeStore.defaultExpandedDepth = this.expandedDepth;
89-
this.tree.expandedDepth = this.expandedDepth;
90-
this.tree.mergeAllOf = this.mergeAllOf;
96+
this.tree.treeOptions = this.treeOptions;
9197
this.tree.schema = this.props.schema;
9298
this.renderSchema();
9399
}

src/components/__tests__/Property.spec.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ describe('Property component', () => {
160160
expandedDepth: Infinity,
161161
mergeAllOf: false,
162162
resolveRef: void 0,
163+
shouldResolveEagerly: false,
163164
});
164165

165166
tree.populate();
@@ -184,6 +185,7 @@ describe('Property component', () => {
184185
expandedDepth: Infinity,
185186
mergeAllOf: false,
186187
resolveRef: void 0,
188+
shouldResolveEagerly: false,
187189
});
188190

189191
tree.populate();
@@ -208,6 +210,7 @@ describe('Property component', () => {
208210
expandedDepth: Infinity,
209211
mergeAllOf: false,
210212
resolveRef: void 0,
213+
shouldResolveEagerly: false,
211214
});
212215

213216
tree.populate();
@@ -233,6 +236,7 @@ describe('Property component', () => {
233236
expandedDepth: Infinity,
234237
mergeAllOf: false,
235238
resolveRef: void 0,
239+
shouldResolveEagerly: false,
236240
});
237241

238242
tree.populate();

src/components/__tests__/SchemaRow.spec.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ describe('SchemaRow component', () => {
6666
expandedDepth: Infinity,
6767
mergeAllOf: false,
6868
resolveRef: void 0,
69+
shouldResolveEagerly: false,
6970
});
7071

7172
tree.populate();
@@ -94,6 +95,7 @@ describe('SchemaRow component', () => {
9495
expandedDepth: Infinity,
9596
mergeAllOf: false,
9697
resolveRef: void 0,
98+
shouldResolveEagerly: false,
9799
});
98100

99101
tree.populate();
@@ -128,6 +130,7 @@ describe('SchemaRow component', () => {
128130
expandedDepth: Infinity,
129131
mergeAllOf: false,
130132
resolveRef: void 0,
133+
shouldResolveEagerly: false,
131134
});
132135

133136
tree.populate();
@@ -143,7 +146,7 @@ describe('SchemaRow component', () => {
143146

144147
test('given a custom resolver, should render a message thrown by it', () => {
145148
const message = "I don't know how to resolve it. Sorry";
146-
tree.resolver = () => {
149+
tree.treeOptions.resolveRef = () => {
147150
throw new Error(message);
148151
};
149152

@@ -185,6 +188,7 @@ describe('SchemaRow component', () => {
185188
expandedDepth: Infinity,
186189
mergeAllOf: false,
187190
resolveRef: void 0,
191+
shouldResolveEagerly: false,
188192
});
189193

190194
tree.populate();

src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
export { JsonSchemaViewer, SchemaRow, SchemaTree as SchemaTreeComponent, PropertyTypeColors } from './components';
22
export * from './tree';
33
export * from './types';
4-
export * from './utils';
54
export * from './errors';

src/tree/__tests__/tree.spec.ts

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ describe('SchemaTree', () => {
3838
expandedDepth: 0,
3939
mergeAllOf: false,
4040
resolveRef: void 0,
41+
shouldResolveEagerly: false,
4142
});
4243

4344
tree.populate();
@@ -139,6 +140,7 @@ describe('SchemaTree', () => {
139140
expandedDepth: 0,
140141
mergeAllOf: false,
141142
resolveRef: void 0,
143+
shouldResolveEagerly: false,
142144
});
143145

144146
tree.populate();
@@ -184,6 +186,7 @@ describe('SchemaTree', () => {
184186
expandedDepth: 0,
185187
mergeAllOf: false,
186188
resolveRef: void 0,
189+
shouldResolveEagerly: false,
187190
});
188191

189192
tree.populate();
@@ -199,6 +202,7 @@ describe('SchemaTree', () => {
199202
resolveRef() {
200203
throw new ResolvingError('Seems like you do not want this to be empty.');
201204
},
205+
shouldResolveEagerly: false,
202206
});
203207

204208
tree.populate();
@@ -236,6 +240,7 @@ describe('SchemaTree', () => {
236240
expandedDepth: 0,
237241
mergeAllOf: false,
238242
resolveRef: void 0,
243+
shouldResolveEagerly: false,
239244
});
240245

241246
tree.populate();
@@ -264,6 +269,7 @@ describe('SchemaTree', () => {
264269

265270
throw new ResolvingError(`Pointer "${pointer}" is missing`);
266271
},
272+
shouldResolveEagerly: false,
267273
});
268274

269275
tree.populate();
@@ -320,6 +326,7 @@ describe('SchemaTree', () => {
320326
expandedDepth: Infinity,
321327
mergeAllOf: true,
322328
resolveRef: void 0,
329+
shouldResolveEagerly: false,
323330
});
324331

325332
tree.populate();
@@ -401,6 +408,7 @@ describe('SchemaTree', () => {
401408
expandedDepth: Infinity,
402409
mergeAllOf: true,
403410
resolveRef: void 0,
411+
shouldResolveEagerly: false,
404412
});
405413

406414
tree.populate();
@@ -471,6 +479,7 @@ describe('SchemaTree', () => {
471479
expandedDepth: Infinity,
472480
mergeAllOf: true,
473481
resolveRef: void 0,
482+
shouldResolveEagerly: false,
474483
});
475484

476485
expect(tree.populate.bind(tree)).not.toThrow();
@@ -546,6 +555,7 @@ describe('SchemaTree', () => {
546555
expandedDepth: Infinity,
547556
mergeAllOf: true,
548557
resolveRef: void 0,
558+
shouldResolveEagerly: false,
549559
});
550560

551561
expect(tree.populate.bind(tree)).not.toThrow();
@@ -643,6 +653,7 @@ describe('SchemaTree', () => {
643653
expandedDepth: Infinity,
644654
mergeAllOf: true,
645655
resolveRef: void 0,
656+
shouldResolveEagerly: false,
646657
});
647658

648659
expect(tree.populate.bind(tree)).not.toThrow();
@@ -751,6 +762,7 @@ describe('SchemaTree', () => {
751762
expandedDepth: Infinity,
752763
mergeAllOf: true,
753764
resolveRef: void 0,
765+
shouldResolveEagerly: false,
754766
});
755767

756768
expect(tree.populate.bind(tree)).not.toThrow();
@@ -808,6 +820,7 @@ describe('SchemaTree', () => {
808820
expandedDepth: Infinity,
809821
mergeAllOf: false,
810822
resolveRef: void 0,
823+
shouldResolveEagerly: false,
811824
});
812825
});
813826

@@ -862,4 +875,121 @@ describe('SchemaTree', () => {
862875
]);
863876
});
864877
});
878+
879+
describe('eager $ref resolving', () => {
880+
test('given a plain object with properties, should resolve', () => {
881+
const schema: JSONSchema4 = {
882+
type: 'object',
883+
properties: {
884+
foo: {
885+
$ref: '#/properties/bar',
886+
},
887+
bar: {
888+
type: 'boolean',
889+
},
890+
},
891+
};
892+
893+
const tree = new SchemaTree(schema, new SchemaTreeState(), {
894+
expandedDepth: Infinity,
895+
mergeAllOf: true,
896+
resolveRef: void 0,
897+
shouldResolveEagerly: true,
898+
});
899+
900+
tree.populate();
901+
expect(printTree(tree)).toMatchInlineSnapshot(`
902+
"└─ #
903+
├─ type: object
904+
└─ children
905+
├─ 0
906+
│ └─ #/properties/foo
907+
│ └─ type: boolean
908+
└─ 1
909+
└─ #/properties/bar
910+
└─ type: boolean
911+
"
912+
`);
913+
});
914+
915+
test('given an array with $reffed items, should resolve', () => {
916+
const schema: JSONSchema4 = {
917+
type: 'object',
918+
properties: {
919+
foo: {
920+
type: 'array',
921+
items: {
922+
$ref: '#/properties/bar',
923+
},
924+
},
925+
bar: {
926+
type: 'boolean',
927+
},
928+
},
929+
};
930+
931+
const tree = new SchemaTree(schema, new SchemaTreeState(), {
932+
expandedDepth: Infinity,
933+
mergeAllOf: true,
934+
resolveRef: void 0,
935+
shouldResolveEagerly: true,
936+
});
937+
938+
tree.populate();
939+
expect(printTree(tree)).toMatchInlineSnapshot(`
940+
"└─ #
941+
├─ type: object
942+
└─ children
943+
├─ 0
944+
│ └─ #/properties/foo
945+
│ ├─ type: array
946+
│ └─ subtype: boolean
947+
└─ 1
948+
└─ #/properties/bar
949+
└─ type: boolean
950+
"
951+
`);
952+
});
953+
954+
test('should leave broken $refs', () => {
955+
const schema: JSONSchema4 = {
956+
type: 'object',
957+
properties: {
958+
foo: {
959+
type: 'array',
960+
items: {
961+
$ref: '#/properties/baz',
962+
},
963+
},
964+
bar: {
965+
$ref: '#/properties/bazinga',
966+
},
967+
},
968+
};
969+
970+
const tree = new SchemaTree(schema, new SchemaTreeState(), {
971+
expandedDepth: Infinity,
972+
mergeAllOf: true,
973+
resolveRef: void 0,
974+
shouldResolveEagerly: true,
975+
});
976+
977+
tree.populate();
978+
expect(printTree(tree)).toMatchInlineSnapshot(`
979+
"└─ #
980+
├─ type: object
981+
└─ children
982+
├─ 0
983+
│ └─ #/properties/foo
984+
│ ├─ type: array
985+
│ ├─ subtype: $ref[#/properties/baz]
986+
│ └─ children
987+
└─ 1
988+
└─ #/properties/bar
989+
├─ $ref: #/properties/bazinga
990+
└─ children
991+
"
992+
`);
993+
});
994+
});
865995
});

0 commit comments

Comments
 (0)