1
- import { TypeIds , _constants , type Constants , parseQRL , deserializeData , resolvers } from './index' ;
1
+ import { TypeIds , _constants , type Constants , parseQRL , resolvers } from './index' ;
2
2
import type { DomContainer } from '../../client/dom-container' ;
3
3
import type { ElementVNode , VNode } from '../../client/vnode-impl' ;
4
4
import { vnode_isVNode , ensureMaterialized , vnode_getNode , vnode_locate } from '../../client/vnode' ;
@@ -17,12 +17,14 @@ import { qError, QError } from '../error/error';
17
17
import { JSXNodeImpl , createPropsProxy } from '../jsx/jsx-runtime' ;
18
18
import type { DeserializeContainer } from '../types' ;
19
19
import { _UNINITIALIZED } from '../utils/constants' ;
20
+ import { needsInflation } from './deser-proxy' ;
21
+
22
+ export const pendingStoreTargents = new Map < object , { t : TypeIds ; v : unknown } > ( ) ;
20
23
21
24
export const allocate = ( container : DeserializeContainer , typeId : number , value : unknown ) : any => {
22
- if ( typeId === TypeIds . Plain ) {
23
- return value ;
24
- }
25
25
switch ( typeId ) {
26
+ case TypeIds . Plain :
27
+ return value ;
26
28
case TypeIds . RootRef :
27
29
return container . $getObjectById$ ( value as number ) ;
28
30
case TypeIds . ForwardRef :
@@ -84,24 +86,23 @@ export const allocate = (container: DeserializeContainer, typeId: number, value:
84
86
return new AsyncComputedSignalImpl ( container as any , null ! ) ;
85
87
case TypeIds . SerializerSignal :
86
88
return new SerializerSignalImpl ( container as any , null ! ) ;
87
- case TypeIds . Store :
88
- /**
89
- * We have a problem here: In theory, both the store and the target need to be present at
90
- * allocate time before inflation can happen. However, that makes the code really complex.
91
- * Instead, we deserialize the target here, which will already allocate and inflate this store
92
- * if there is a cycle (because the original allocation for the store didn't complete yet).
93
- * Because we have a map of target -> store, we will reuse the same store instance after
94
- * target deserialization. So in that case, we will be running inflation twice on the same
95
- * store, but that is not a problem, very little overhead and the code is way simpler.
96
- */
97
- const storeValue = deserializeData (
98
- container ,
99
- ( value as any [ ] ) [ 0 ] as TypeIds ,
100
- ( value as any [ ] ) [ 1 ]
101
- ) ;
102
- ( value as any [ ] ) [ 0 ] = TypeIds . Plain ;
103
- ( value as any [ ] ) [ 1 ] = storeValue ;
104
- return getOrCreateStore ( storeValue , StoreFlags . NONE , container as DomContainer ) ;
89
+ case TypeIds . Store : {
90
+ const data = value as [ TypeIds , unknown ] ;
91
+ // We need to allocate the store first, before we inflate its data, because the data can
92
+ // reference the store itself (circular)
93
+ // Note: the actual store data will be inflated in inflate()
94
+ const t = data [ 0 ] as TypeIds ;
95
+ const v = data [ 1 ] ;
96
+ const storeValue = allocate ( container , t , v ) ;
97
+ const store = getOrCreateStore ( storeValue , StoreFlags . NONE , container as DomContainer ) ;
98
+ if ( needsInflation ( t ) ) {
99
+ pendingStoreTargents . set ( store , { t, v } ) ;
100
+ }
101
+ // We must store the reference so it doesn't get deserialized again in inflate()
102
+ data [ 0 ] = TypeIds . Plain ;
103
+ data [ 1 ] = storeValue ;
104
+ return store ;
105
+ }
105
106
case TypeIds . URLSearchParams :
106
107
return new URLSearchParams ( value as string ) ;
107
108
case TypeIds . FormData :
0 commit comments