@@ -14,7 +14,7 @@ import {
14
14
getStoreTarget ,
15
15
isStore ,
16
16
} from '../reactive-primitives/impl/store' ;
17
- import type { ISsrNode , SymbolToChunkResolver } from '../ssr/ssr-types' ;
17
+ import type { ISsrNode , SsrAttrs , SymbolToChunkResolver } from '../ssr/ssr-types' ;
18
18
import { untrack } from '../use/use-core' ;
19
19
import { createResourceReturn , type ResourceReturnInternal } from '../use/use-resource' ;
20
20
import { isTask , Task } from '../use/use-task' ;
@@ -646,7 +646,7 @@ export interface SerializationContext {
646
646
* Returns a path string representing the path from roots through all parents to the object.
647
647
* Format: "3 2 0" where each number is the index within its parent, from root to leaf.
648
648
*/
649
- $addRoot$ : ( obj : unknown , parent : unknown ) => string | number ;
649
+ $addRoot$ : ( obj : unknown , parent ? : unknown ) => number ;
650
650
651
651
/**
652
652
* Get root path of the object without creating a new root.
@@ -759,7 +759,8 @@ export const createSerializationContext = (
759
759
seen . $rootIndex$ = roots . length ;
760
760
roots . push ( obj ) ;
761
761
}
762
- return $addRootPath$ ( obj ) ;
762
+ $addRootPath$ ( obj ) ;
763
+ return seen . $rootIndex$ ;
763
764
} ;
764
765
765
766
const isSsrNode = ( NodeConstructor ? ( obj ) => obj instanceof NodeConstructor : ( ) => false ) as (
@@ -771,7 +772,7 @@ export const createSerializationContext = (
771
772
772
773
return {
773
774
async $serialize$ ( ) : Promise < void > {
774
- return serialize ( this ) ;
775
+ return await serialize ( this ) ;
775
776
} ,
776
777
$isSsrNode$ : isSsrNode ,
777
778
$isDomRef$ : isDomRef ,
@@ -839,6 +840,23 @@ function $discoverRoots$(
839
840
}
840
841
}
841
842
843
+ const isSsrAttrs = ( value : number | SsrAttrs ) : value is SsrAttrs =>
844
+ Array . isArray ( value ) && value . length > 0 ;
845
+
846
+ const discoverValuesForVNodeData = ( vnodeData : VNodeData , callback : ( value : unknown ) => void ) => {
847
+ for ( const value of vnodeData ) {
848
+ if ( isSsrAttrs ( value ) ) {
849
+ for ( let i = 1 ; i < value . length ; i += 2 ) {
850
+ const attrValue = value [ i ] ;
851
+ if ( typeof attrValue === 'string' ) {
852
+ continue ;
853
+ }
854
+ callback ( attrValue ) ;
855
+ }
856
+ }
857
+ }
858
+ } ;
859
+
842
860
class PromiseResult {
843
861
constructor (
844
862
public $resolved$ : boolean ,
@@ -874,16 +892,8 @@ class SerializerResult extends PromiseResult {
874
892
* - Therefore root indexes need to be doubled to get the actual index.
875
893
*/
876
894
async function serialize ( serializationContext : SerializationContext ) : Promise < void > {
877
- const {
878
- $writer$,
879
- $isSsrNode$,
880
- $isDomRef$,
881
- $setProp$,
882
- $storeProxyMap$,
883
- $addRoot$,
884
- $pathMap$,
885
- $wasSeen$,
886
- } = serializationContext ;
895
+ const { $writer$, $isSsrNode$, $isDomRef$, $storeProxyMap$, $addRoot$, $pathMap$, $wasSeen$ } =
896
+ serializationContext ;
887
897
let depth = 0 ;
888
898
const forwardRefs : number [ ] = [ ] ;
889
899
let forwardRefsId = 0 ;
@@ -923,13 +933,13 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
923
933
depth ++ ;
924
934
outputArray ( value , ( valueItem , idx ) => {
925
935
$discoverRoots$ ( serializationContext , valueItem , parent , idx ) ;
926
- writeValue ( valueItem , idx ) ;
936
+ writeValue ( valueItem ) ;
927
937
} ) ;
928
938
depth -- ;
929
939
}
930
940
} ;
931
941
932
- const writeValue = ( value : unknown , idx : number ) => {
942
+ const writeValue = ( value : unknown ) => {
933
943
if ( fastSkipSerialize ( value as object ) ) {
934
944
output ( TypeIds . Constant , Constants . Undefined ) ;
935
945
} else if ( typeof value === 'bigint' ) {
@@ -959,7 +969,7 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
959
969
} else {
960
970
const qrl = qrlToString ( serializationContext , value ) ;
961
971
if ( ! isRootObject ) {
962
- const id = serializationContext . $addRoot$ ( qrl , null ) ;
972
+ const id = serializationContext . $addRoot$ ( qrl ) ;
963
973
output ( TypeIds . QRL , id ) ;
964
974
} else {
965
975
output ( TypeIds . QRL , qrl ) ;
@@ -1002,7 +1012,7 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
1002
1012
depth ++ ;
1003
1013
const oldParent = parent ;
1004
1014
parent = value ;
1005
- writeObjectValue ( value , idx ) ;
1015
+ writeObjectValue ( value ) ;
1006
1016
parent = oldParent ;
1007
1017
depth -- ;
1008
1018
}
@@ -1043,7 +1053,7 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
1043
1053
}
1044
1054
} ;
1045
1055
1046
- const writeObjectValue = ( value : { } , idx : number ) => {
1056
+ const writeObjectValue = ( value : { } ) => {
1047
1057
/**
1048
1058
* The object writer outputs an array object (without type prefix) and this increases the depth
1049
1059
* for the objects within (depth 1).
@@ -1061,11 +1071,9 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
1061
1071
output ( TypeIds . RootRef , rootPath ) ;
1062
1072
return ;
1063
1073
}
1064
- }
1065
- if ( depth > 1 ) {
1074
+ } else if ( depth > 1 ) {
1066
1075
const seen = $wasSeen$ ( value ) ;
1067
1076
if ( seen && seen . $rootIndex$ !== - 1 ) {
1068
- // console.log('writeObjectValue', value, $wasSeen$(value), depth);
1069
1077
// We have seen this object before, so we can serialize it as a reference.
1070
1078
// Otherwise serialize as normal
1071
1079
output ( TypeIds . RootRef , seen . $rootIndex$ ) ;
@@ -1104,7 +1112,7 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
1104
1112
if ( $storeProxyMap$ . has ( propValue ) ) {
1105
1113
const innerStore = $storeProxyMap$ . get ( propValue ) ;
1106
1114
innerStores . push ( innerStore ) ;
1107
- serializationContext . $addRoot$ ( innerStore , null ) ;
1115
+ serializationContext . $addRoot$ ( innerStore ) ;
1108
1116
}
1109
1117
}
1110
1118
@@ -1123,7 +1131,7 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
1123
1131
output ( TypeIds . ForwardRef , forwardRef ) ;
1124
1132
} else {
1125
1133
depth -- ;
1126
- writeValue ( result , idx ) ;
1134
+ writeValue ( result ) ;
1127
1135
depth ++ ;
1128
1136
}
1129
1137
} else if ( isObjectLiteral ( value ) ) {
@@ -1200,25 +1208,21 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
1200
1208
}
1201
1209
output ( TypeIds . Error , out ) ;
1202
1210
} else if ( $isSsrNode$ ( value ) ) {
1203
- if ( isRootObject ) {
1204
- // Tell the SsrNode which root id it is
1205
- $setProp$ ( value , ELEMENT_ID , String ( idx ) ) ;
1206
- // we need to output before the vnode overwrites its values
1207
- output ( TypeIds . VNode , value . id ) ;
1208
- const vNodeData = value . vnodeData ;
1209
- if ( vNodeData ) {
1210
- serializationContext . $prepVNodeData$ ?.( vNodeData ) ;
1211
+ const rootIndex = $addRoot$ ( value ) ;
1212
+ serializationContext . $setProp$ ( value , ELEMENT_ID , String ( rootIndex ) ) ;
1213
+ // we need to output before the vnode overwrites its values
1214
+ output ( TypeIds . VNode , value . id ) ;
1215
+ const vNodeData = value . vnodeData ;
1216
+ if ( vNodeData ) {
1217
+ serializationContext . $prepVNodeData$ ?.( vNodeData ) ;
1218
+ discoverValuesForVNodeData ( vNodeData , ( vNodeDataValue ) => $addRoot$ ( vNodeDataValue ) ) ;
1219
+ vNodeData [ 0 ] |= VNodeDataFlag . SERIALIZE ;
1220
+ }
1221
+ if ( value . childrenVNodeData ) {
1222
+ for ( const vNodeData of value . childrenVNodeData ) {
1223
+ discoverValuesForVNodeData ( vNodeData , ( vNodeDataValue ) => $addRoot$ ( vNodeDataValue ) ) ;
1211
1224
vNodeData [ 0 ] |= VNodeDataFlag . SERIALIZE ;
1212
1225
}
1213
- if ( value . childrenVNodeData ) {
1214
- for ( const vNodeData of value . childrenVNodeData ) {
1215
- vNodeData [ 0 ] |= VNodeDataFlag . SERIALIZE ;
1216
- }
1217
- }
1218
- } else {
1219
- // Promote the vnode to a root
1220
- serializationContext . $addRoot$ ( value , null ) ;
1221
- output ( TypeIds . RootRef , serializationContext . $roots$ . length - 1 ) ;
1222
1226
}
1223
1227
} else if ( typeof FormData !== 'undefined' && value instanceof FormData ) {
1224
1228
// FormData is generally used only once so don't bother with references
@@ -1273,7 +1277,7 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
1273
1277
output ( TypeIds . Resource , [ value . $resolved$ , value . $value$ , value . $effects$ ] ) ;
1274
1278
} else if ( value instanceof SerializerResult ) {
1275
1279
if ( value . $resolved$ ) {
1276
- writeValue ( value . $value$ , idx ) ;
1280
+ writeValue ( value . $value$ ) ;
1277
1281
} else {
1278
1282
console . error ( value . $value$ ) ;
1279
1283
throw qError ( QError . serializerSymbolRejectedPromise ) ;
@@ -1297,18 +1301,18 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
1297
1301
1298
1302
function $resolvePromise$ (
1299
1303
promise : Promise < unknown > ,
1300
- $addRoot$ : ( obj : unknown , parent : unknown ) => string | number ,
1304
+ $addRoot$ : ( obj : unknown ) => string | number ,
1301
1305
classCreator : ( resolved : boolean , resolvedValue : unknown ) => PromiseResult
1302
1306
) {
1303
1307
const forwardRefId = forwardRefsId ++ ;
1304
1308
promise
1305
1309
. then ( ( resolvedValue ) => {
1306
1310
promises . delete ( promise ) ;
1307
- forwardRefs [ forwardRefId ] = $addRoot$ ( classCreator ( true , resolvedValue ) , null ) as number ;
1311
+ forwardRefs [ forwardRefId ] = $addRoot$ ( classCreator ( true , resolvedValue ) ) as number ;
1308
1312
} )
1309
1313
. catch ( ( err ) => {
1310
1314
promises . delete ( promise ) ;
1311
- forwardRefs [ forwardRefId ] = $addRoot$ ( classCreator ( false , err ) , null ) as number ;
1315
+ forwardRefs [ forwardRefId ] = $addRoot$ ( classCreator ( false , err ) ) as number ;
1312
1316
} ) ;
1313
1317
1314
1318
promises . add ( promise ) ;
@@ -1326,7 +1330,7 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
1326
1330
}
1327
1331
for ( let i = lastRootsLength ; i < rootsLength ; i ++ ) {
1328
1332
const root = serializationContext . $roots$ [ i ] ;
1329
- writeValue ( root , 0 ) ;
1333
+ writeValue ( root ) ;
1330
1334
const isLast = i === rootsLength - 1 ;
1331
1335
if ( ! isLast ) {
1332
1336
$writer$ . write ( ',' ) ;
@@ -1458,7 +1462,7 @@ export function qrlToString(
1458
1462
serializedReferences += ' ' ;
1459
1463
}
1460
1464
// We refer by id so every capture needs to be a root
1461
- serializedReferences += serializationContext . $addRoot$ ( value . $captureRef$ [ i ] , null ) ;
1465
+ serializedReferences += serializationContext . $addRoot$ ( value . $captureRef$ [ i ] ) ;
1462
1466
}
1463
1467
qrlStringInline += `[${ serializedReferences } ]` ;
1464
1468
} else if ( value . $capture$ && value . $capture$ . length > 0 ) {
@@ -1484,9 +1488,8 @@ export async function _serialize(data: unknown[]): Promise<string> {
1484
1488
) ;
1485
1489
1486
1490
for ( const root of data ) {
1487
- serializationContext . $addRoot$ ( root , null ) ;
1491
+ serializationContext . $addRoot$ ( root ) ;
1488
1492
}
1489
- // await serializationContext.$breakCircularDepsAndAwaitPromises$();
1490
1493
await serializationContext . $serialize$ ( ) ;
1491
1494
return serializationContext . $writer$ . toString ( ) ;
1492
1495
}
@@ -1531,7 +1534,7 @@ function deserializeData(container: DeserializeContainer, typeId: number, value:
1531
1534
return propValue ;
1532
1535
}
1533
1536
1534
- function getObjectById ( id : number | string , stateData : unknown [ ] ) : unknown {
1537
+ export function getObjectById ( id : number | string , stateData : unknown [ ] ) : unknown {
1535
1538
if ( typeof id === 'string' ) {
1536
1539
id = parseInt ( id , 10 ) ;
1537
1540
}
@@ -1554,6 +1557,7 @@ export function _createDeserializeContainer(
1554
1557
$storeProxyMap$ : new WeakMap ( ) ,
1555
1558
element : null ,
1556
1559
$forwardRefs$ : null ,
1560
+ $initialQRLsIndexes$ : null ,
1557
1561
$scheduler$ : null ,
1558
1562
} ;
1559
1563
preprocessState ( stateData , container ) ;
@@ -1628,9 +1632,6 @@ export function preprocessState(data: unknown[], container: DeserializeContainer
1628
1632
let valueIndex = 0 ;
1629
1633
let parent : unknown [ ] | null = null ;
1630
1634
1631
- // console.log(dumpState(data));
1632
- // console.log('--------------------------------');
1633
-
1634
1635
for ( let i = 0 ; i < rootRefPath . length ; i ++ ) {
1635
1636
parent = object ;
1636
1637
@@ -1654,9 +1655,6 @@ export function preprocessState(data: unknown[], container: DeserializeContainer
1654
1655
}
1655
1656
data [ index ] = objectType ;
1656
1657
data [ index + 1 ] = object ;
1657
-
1658
- // console.log(dumpState(data));
1659
- // console.log('--------------------------------');
1660
1658
} ;
1661
1659
1662
1660
for ( let i = 0 ; i < data . length ; i += 2 ) {
@@ -1665,11 +1663,8 @@ export function preprocessState(data: unknown[], container: DeserializeContainer
1665
1663
} else if ( isForwardRefsMap ( data [ i ] as TypeIds ) ) {
1666
1664
container . $forwardRefs$ = data [ i + 1 ] as number [ ] ;
1667
1665
} else if ( isQrlType ( data [ i ] as TypeIds ) ) {
1668
- container . $scheduler$ ?.(
1669
- ChoreType . QRL_RESOLVE ,
1670
- null ,
1671
- data [ i + 1 ] as QRLInternal < ( ...args : unknown [ ] ) => unknown >
1672
- ) ;
1666
+ container . $initialQRLsIndexes$ ||= [ ] ;
1667
+ container . $initialQRLsIndexes$ . push ( i / 2 ) ;
1673
1668
}
1674
1669
}
1675
1670
}
0 commit comments