@@ -2,6 +2,7 @@ import { TreeListParentNode } from '@stoplight/tree-list';
22import { JSONSchema4 } from 'json-schema' ;
33import { getNodeMetadata } from '../metadata' ;
44import { SchemaTree , SchemaTreeState } from '../tree' ;
5+ import { printTree } from './utils/printTree' ;
56
67describe ( 'SchemaTree' , ( ) => {
78 describe ( 'expanding' , ( ) => {
@@ -61,7 +62,7 @@ describe('SchemaTree', () => {
6162 } ,
6263 } ,
6364 ] ,
64- } ) ,
65+ } )
6566 ) ;
6667 } ) ;
6768
@@ -82,7 +83,7 @@ describe('SchemaTree', () => {
8283 type : 'string' ,
8384 } ,
8485 } ,
85- } ) ,
86+ } )
8687 ) ;
8788 } ) ;
8889
@@ -102,7 +103,7 @@ describe('SchemaTree', () => {
102103 type : 'string' ,
103104 } ,
104105 } ,
105- } ) ,
106+ } )
106107 ) ;
107108 } ) ;
108109 } ) ;
@@ -158,7 +159,7 @@ describe('SchemaTree', () => {
158159 type : 'string' ,
159160 } ,
160161 } ,
161- } ) ,
162+ } )
162163 ) ;
163164 } ) ;
164165 } ) ;
@@ -187,10 +188,7 @@ describe('SchemaTree', () => {
187188 tree . populate ( ) ;
188189
189190 tree . unwrap ( tree . itemAt ( 1 ) as TreeListParentNode ) ;
190- expect ( getNodeMetadata ( tree . itemAt ( 2 ) as TreeListParentNode ) ) . toHaveProperty (
191- 'error' ,
192- 'The pointer is empty' ,
193- ) ;
191+ expect ( getNodeMetadata ( tree . itemAt ( 2 ) as TreeListParentNode ) ) . toHaveProperty ( 'error' , 'The pointer is empty' ) ;
194192 } ) ;
195193
196194 test ( 'given a custom resolver, should attempt to resolve the reference' , ( ) => {
@@ -244,13 +242,13 @@ describe('SchemaTree', () => {
244242 tree . unwrap ( tree . itemAt ( 1 ) as TreeListParentNode ) ;
245243 expect ( getNodeMetadata ( tree . itemAt ( 2 ) as TreeListParentNode ) ) . toHaveProperty (
246244 'error' ,
247- 'Cannot dereference external references' ,
245+ 'Cannot dereference external references'
248246 ) ;
249247
250248 tree . unwrap ( tree . itemAt ( 3 ) as TreeListParentNode ) ;
251249 expect ( getNodeMetadata ( tree . itemAt ( 4 ) as TreeListParentNode ) ) . toHaveProperty (
252250 'error' ,
253- 'Cannot dereference external references' ,
251+ 'Cannot dereference external references'
254252 ) ;
255253 } ) ;
256254
@@ -272,16 +270,256 @@ describe('SchemaTree', () => {
272270 tree . unwrap ( tree . itemAt ( 1 ) as TreeListParentNode ) ;
273271 expect ( getNodeMetadata ( tree . itemAt ( 2 ) as TreeListParentNode ) ) . toHaveProperty (
274272 'error' ,
275- 'Could not read "../test"' ,
273+ 'Could not read "../test"'
276274 ) ;
277275
278276 tree . unwrap ( tree . itemAt ( 3 ) as TreeListParentNode ) ;
279277 expect ( getNodeMetadata ( tree . itemAt ( 4 ) as TreeListParentNode ) ) . toHaveProperty (
280278 'error' ,
281- 'Pointer "#id" is missing' ,
279+ 'Pointer "#id" is missing'
282280 ) ;
283281 } ) ;
284282 } ) ;
283+
284+ describe ( '$refs in allOf' , ( ) => {
285+ test ( 'given $ref in allOf' , ( ) => {
286+ const schema : JSONSchema4 = {
287+ type : 'object' ,
288+ properties : {
289+ foo : {
290+ type : 'object' ,
291+ properties : {
292+ name : {
293+ type : 'string' ,
294+ } ,
295+ id : {
296+ type : 'number' ,
297+ } ,
298+ } ,
299+ } ,
300+ bar : {
301+ allOf : [
302+ {
303+ $ref : '#/properties/foo' ,
304+ } ,
305+ {
306+ type : 'object' ,
307+ properties : {
308+ address : {
309+ type : 'string' ,
310+ } ,
311+ } ,
312+ } ,
313+ ] ,
314+ } ,
315+ } ,
316+ } ;
317+
318+ const tree = new SchemaTree ( schema , new SchemaTreeState ( ) , {
319+ expandedDepth : Infinity ,
320+ mergeAllOf : true ,
321+ resolveRef : void 0 ,
322+ } ) ;
323+
324+ tree . populate ( ) ;
325+ expect ( printTree ( tree ) ) . toMatchInlineSnapshot ( `
326+ "└─ #
327+ ├─ type: object
328+ └─ children
329+ ├─ 0
330+ │ └─ #/properties/foo
331+ │ ├─ type: object
332+ │ └─ children
333+ │ ├─ 0
334+ │ │ └─ #/properties/foo/properties/name
335+ │ │ └─ type: string
336+ │ └─ 1
337+ │ └─ #/properties/foo/properties/id
338+ │ └─ type: number
339+ └─ 1
340+ └─ #/properties/bar
341+ ├─ type: object
342+ └─ children
343+ ├─ 0
344+ │ └─ #/properties/bar/properties/name
345+ │ └─ type: string
346+ ├─ 1
347+ │ └─ #/properties/bar/properties/id
348+ │ └─ type: number
349+ └─ 2
350+ └─ #/properties/bar/properties/address
351+ └─ type: string
352+ "
353+ ` ) ;
354+ } ) ;
355+
356+ test ( 'given $ref in allOf pointing at another allOf, should keep merging' , ( ) => {
357+ const schema : JSONSchema4 = {
358+ type : 'object' ,
359+ properties : {
360+ baz : {
361+ type : 'object' ,
362+ } ,
363+ foo : {
364+ allOf : [
365+ {
366+ type : 'object' ,
367+ properties : {
368+ name : {
369+ type : 'string' ,
370+ } ,
371+ id : {
372+ type : 'number' ,
373+ } ,
374+ } ,
375+ } ,
376+ {
377+ $ref : '#/properties/baz' ,
378+ } ,
379+ ] ,
380+ } ,
381+ bar : {
382+ allOf : [
383+ {
384+ $ref : '#/properties/foo' ,
385+ } ,
386+ {
387+ type : 'object' ,
388+ properties : {
389+ address : {
390+ type : 'string' ,
391+ } ,
392+ } ,
393+ } ,
394+ ] ,
395+ } ,
396+ } ,
397+ } ;
398+
399+ const tree = new SchemaTree ( schema , new SchemaTreeState ( ) , {
400+ expandedDepth : Infinity ,
401+ mergeAllOf : true ,
402+ resolveRef : void 0 ,
403+ } ) ;
404+
405+ tree . populate ( ) ;
406+ expect ( printTree ( tree ) ) . toMatchInlineSnapshot ( `
407+ "└─ #
408+ ├─ type: object
409+ └─ children
410+ ├─ 0
411+ │ └─ #/properties/baz
412+ │ └─ type: object
413+ ├─ 1
414+ │ └─ #/properties/foo
415+ │ ├─ type: object
416+ │ └─ children
417+ │ ├─ 0
418+ │ │ └─ #/properties/foo/properties/name
419+ │ │ └─ type: string
420+ │ └─ 1
421+ │ └─ #/properties/foo/properties/id
422+ │ └─ type: number
423+ └─ 2
424+ └─ #/properties/bar
425+ ├─ type: object
426+ └─ children
427+ ├─ 0
428+ │ └─ #/properties/bar/properties/name
429+ │ └─ type: string
430+ ├─ 1
431+ │ └─ #/properties/bar/properties/id
432+ │ └─ type: number
433+ └─ 2
434+ └─ #/properties/bar/properties/address
435+ └─ type: string
436+ "
437+ ` ) ;
438+ } ) ;
439+
440+ test ( 'given direct circular reference pointing at allOf, should throw' , ( ) => {
441+ const schema : JSONSchema4 = {
442+ type : 'object' ,
443+ properties : {
444+ foo : {
445+ allOf : [
446+ {
447+ $ref : '#/properties/bar' ,
448+ } ,
449+ ] ,
450+ } ,
451+ bar : {
452+ allOf : [
453+ {
454+ $ref : '#/properties/foo' ,
455+ } ,
456+ {
457+ type : 'object' ,
458+ properties : {
459+ name : {
460+ type : 'string' ,
461+ } ,
462+ } ,
463+ } ,
464+ ] ,
465+ } ,
466+ } ,
467+ } ;
468+
469+ const tree = new SchemaTree ( schema , new SchemaTreeState ( ) , {
470+ expandedDepth : Infinity ,
471+ mergeAllOf : true ,
472+ resolveRef : void 0 ,
473+ } ) ;
474+
475+ expect ( tree . populate . bind ( tree ) ) . toThrowError ( 'Circular reference detected' ) ;
476+ } ) ;
477+
478+ test ( 'given indirect circular reference pointing at allOf, should throw' , ( ) => {
479+ const schema : JSONSchema4 = {
480+ type : 'object' ,
481+ properties : {
482+ baz : {
483+ allOf : [
484+ {
485+ $ref : '#/properties/bar' ,
486+ } ,
487+ ] ,
488+ } ,
489+ foo : {
490+ allOf : [
491+ {
492+ $ref : '#/properties/baz' ,
493+ } ,
494+ ] ,
495+ } ,
496+ bar : {
497+ allOf : [
498+ {
499+ $ref : '#/properties/foo' ,
500+ } ,
501+ {
502+ type : 'object' ,
503+ properties : {
504+ name : {
505+ type : 'string' ,
506+ } ,
507+ } ,
508+ } ,
509+ ] ,
510+ } ,
511+ } ,
512+ } ;
513+
514+ const tree = new SchemaTree ( schema , new SchemaTreeState ( ) , {
515+ expandedDepth : Infinity ,
516+ mergeAllOf : true ,
517+ resolveRef : void 0 ,
518+ } ) ;
519+
520+ expect ( tree . populate . bind ( tree ) ) . toThrowError ( 'Circular reference detected' ) ;
521+ } ) ;
522+ } ) ;
285523 } ) ;
286524
287525 describe ( 'paths generation' , ( ) => {
@@ -328,30 +566,19 @@ describe('SchemaTree', () => {
328566 test ( 'for plain object member' , ( ) => {
329567 tree . populate ( ) ;
330568
331- expect ( getNodeMetadata ( tree . itemAt ( 1 ) ! ) ) . toHaveProperty ( 'path' , [
332- 'properties' ,
333- 'user'
334- ] ) ;
569+ expect ( getNodeMetadata ( tree . itemAt ( 1 ) ! ) ) . toHaveProperty ( 'path' , [ 'properties' , 'user' ] ) ;
335570 } ) ;
336571
337572 test ( 'for deep object member' , ( ) => {
338573 tree . populate ( ) ;
339574
340- expect ( getNodeMetadata ( tree . itemAt ( 2 ) ! ) ) . toHaveProperty ( 'path' , [
341- 'properties' ,
342- 'user' ,
343- 'properties' ,
344- 'name' ,
345- ] ) ;
575+ expect ( getNodeMetadata ( tree . itemAt ( 2 ) ! ) ) . toHaveProperty ( 'path' , [ 'properties' , 'user' , 'properties' , 'name' ] ) ;
346576 } ) ;
347577
348578 test ( 'for array items' , ( ) => {
349579 tree . populate ( ) ;
350580
351- expect ( getNodeMetadata ( tree . itemAt ( tree . count - 1 ) ! ) ) . toHaveProperty ( 'path' , [
352- 'properties' ,
353- 'permissions' ,
354- ] ) ;
581+ expect ( getNodeMetadata ( tree . itemAt ( tree . count - 1 ) ! ) ) . toHaveProperty ( 'path' , [ 'properties' , 'permissions' ] ) ;
355582 } ) ;
356583
357584 test ( 'for $reffed array items' , ( ) => {
0 commit comments