@@ -86,4 +86,78 @@ describe('mergeDeep', () => {
8686 . decorate ( 'db' , Object . freeze ( { hello : 'world' } ) )
8787 . guard ( { } , ( app ) => app )
8888 } )
89+
90+ it ( 'handle circular references' , ( ) => {
91+ const a : {
92+ x : number
93+ toB ?: typeof b
94+ } = { x : 1 }
95+ const b : {
96+ y : number
97+ toA ?: typeof a
98+ } = { y : 2 }
99+
100+ a . toB = b
101+ b . toA = a
102+
103+ const target = { }
104+ const source = { prop : a }
105+
106+ const result = mergeDeep ( target , source )
107+
108+ expect ( result . prop . x ) . toBe ( 1 )
109+ expect ( result . prop . toB ?. y ) . toBe ( 2 )
110+ } )
111+
112+ it ( 'handle shared references in different branches' , ( ) => {
113+ const shared = { value : 123 }
114+ const target = { x : { } , y : { } }
115+ const source = { x : shared , y : shared }
116+
117+ const result = mergeDeep ( target , source )
118+
119+ expect ( result . x . value ) . toBe ( 123 )
120+ expect ( result . y . value ) . toBe ( 123 )
121+ } )
122+
123+ it ( 'deduplicate plugin with circular decorators' , async ( ) => {
124+ const a : {
125+ x : number
126+ toB ?: typeof b
127+ } = { x : 1 }
128+ const b : {
129+ y : number
130+ toA ?: typeof a
131+ } = { y : 2 }
132+ a . toB = b
133+ b . toA = a
134+
135+ const complex = { a }
136+
137+ const Plugin = new Elysia ( { name : 'Plugin' , seed : 'seed' } )
138+ . decorate ( 'dep' , complex )
139+ . as ( 'scoped' )
140+
141+ const ModuleA = new Elysia ( { name : 'ModuleA' } )
142+ . use ( Plugin )
143+ . get ( '/moda/a' , ( { dep } ) => dep . a . x )
144+ . get ( '/moda/b' , ( { dep } ) => dep . a . toB ?. y )
145+
146+ const ModuleB = new Elysia ( { name : 'ModuleB' } )
147+ . use ( Plugin )
148+ . get ( '/modb/a' , ( { dep } ) => dep . a . x )
149+ . get ( '/modb/b' , ( { dep } ) => dep . a . toB ?. y )
150+
151+ const app = new Elysia ( ) . use ( ModuleA ) . use ( ModuleB )
152+
153+ const resA = await app . handle ( req ( '/moda/a' ) ) . then ( ( x ) => x . text ( ) )
154+ const resB = await app . handle ( req ( '/modb/a' ) ) . then ( ( x ) => x . text ( ) )
155+ const resC = await app . handle ( req ( '/moda/b' ) ) . then ( ( x ) => x . text ( ) )
156+ const resD = await app . handle ( req ( '/modb/b' ) ) . then ( ( x ) => x . text ( ) )
157+
158+ expect ( resA ) . toBe ( '1' )
159+ expect ( resB ) . toBe ( '1' )
160+ expect ( resC ) . toBe ( '2' )
161+ expect ( resD ) . toBe ( '2' )
162+ } )
89163} )
0 commit comments