@@ -1682,3 +1682,81 @@ asyncErrorTests('throws for promise resolving to function', async () => {
16821682} ) ;
16831683
16841684asyncErrorTests . run ( ) ;
1685+
1686+ const circularCustomTypes = uvu . suite ( 'circular references through custom types' ) ;
1687+
1688+ circularCustomTypes ( 'resolves circular reference through two custom types' , ( ) => {
1689+ const foo = new Foo ( { name : 'outer' } ) ;
1690+ const bar = new Bar ( { name : 'inner' , ref : foo } ) ;
1691+ foo . value . ref = bar ;
1692+
1693+ const reducers = {
1694+ Foo : ( x ) => x instanceof Foo && x . value ,
1695+ Bar : ( x ) => x instanceof Bar && x . value
1696+ } ;
1697+ const fooCache = new WeakMap ( ) ;
1698+ const barCache = new WeakMap ( ) ;
1699+ const revivers = {
1700+ Foo : ( x ) => {
1701+ let inst = fooCache . get ( x ) ;
1702+ if ( ! inst ) {
1703+ inst = Object . create ( Foo . prototype ) ;
1704+ fooCache . set ( x , inst ) ;
1705+ }
1706+ inst . value = x ;
1707+ return inst ;
1708+ } ,
1709+ Bar : ( x ) => {
1710+ let inst = barCache . get ( x ) ;
1711+ if ( ! inst ) {
1712+ inst = Object . create ( Bar . prototype ) ;
1713+ barCache . set ( x , inst ) ;
1714+ }
1715+ inst . value = x ;
1716+ return inst ;
1717+ }
1718+ } ;
1719+
1720+ const json = stringify ( foo , reducers ) ;
1721+ const result = parse ( json , revivers ) ;
1722+
1723+ assert . ok ( result instanceof Foo ) ;
1724+ assert . ok ( result . value . ref instanceof Bar ) ;
1725+ assert . is ( result . value . ref . value . ref , result ) ;
1726+ } ) ;
1727+
1728+ circularCustomTypes ( 'resolves self-referencing custom type' , ( ) => {
1729+ const foo = new Foo ( { name : 'self' } ) ;
1730+ foo . value . ref = foo ;
1731+
1732+ const reducers = {
1733+ Foo : ( x ) => x instanceof Foo && x . value
1734+ } ;
1735+ const fooCache = new WeakMap ( ) ;
1736+ const revivers = {
1737+ Foo : ( x ) => {
1738+ let inst = fooCache . get ( x ) ;
1739+ if ( ! inst ) {
1740+ inst = Object . create ( Foo . prototype ) ;
1741+ fooCache . set ( x , inst ) ;
1742+ }
1743+ inst . value = x ;
1744+ return inst ;
1745+ }
1746+ } ;
1747+
1748+ const json = stringify ( foo , reducers ) ;
1749+ const result = parse ( json , revivers ) ;
1750+
1751+ assert . ok ( result instanceof Foo ) ;
1752+ assert . is ( result . value . ref , result ) ;
1753+ } ) ;
1754+
1755+ circularCustomTypes ( 'still rejects genuinely invalid circular reference' , ( ) => {
1756+ assert . throws (
1757+ ( ) => parse ( '[["Custom", 0]]' , { Custom : ( v ) => v } ) ,
1758+ ( error ) => error . message === 'Invalid circular reference'
1759+ ) ;
1760+ } ) ;
1761+
1762+ circularCustomTypes . run ( ) ;
0 commit comments