@@ -327,7 +327,14 @@ function loadServerReference<T>(
327
327
}
328
328
}
329
329
promise.then(
330
- createModelResolver(parentChunk, parentObject, key),
330
+ createModelResolver(
331
+ parentChunk,
332
+ parentObject,
333
+ key,
334
+ false,
335
+ response,
336
+ createModel,
337
+ ),
331
338
createModelReject(parentChunk),
332
339
);
333
340
// We need a placeholder value that will be replaced later.
@@ -406,19 +413,24 @@ function createModelResolver<T>(
406
413
chunk: SomeChunk< T > ,
407
414
parentObject: Object,
408
415
key: string,
416
+ cyclic: boolean,
417
+ response: Response,
418
+ map: (response: Response, model: any) => T ,
409
419
) : ( value : any ) => void {
410
420
let blocked ;
411
421
if ( initializingChunkBlockedModel ) {
412
422
blocked = initializingChunkBlockedModel ;
413
- blocked . deps ++ ;
423
+ if ( ! cyclic ) {
424
+ blocked . deps ++ ;
425
+ }
414
426
} else {
415
427
blocked = initializingChunkBlockedModel = {
416
- deps : 1 ,
428
+ deps : cyclic ? 0 : 1 ,
417
429
value : ( null : any ) ,
418
430
} ;
419
431
}
420
432
return value => {
421
- parentObject [ key ] = value ;
433
+ parentObject [ key ] = map ( response , value ) ;
422
434
423
435
// If this is the root object for a model reference, where `blocked.value`
424
436
// is a stale `null`, the resolved value can be used directly.
@@ -446,16 +458,61 @@ function createModelReject<T>(chunk: SomeChunk<T>): (error: mixed) => void {
446
458
return ( error : mixed ) = > triggerErrorOnChunk ( chunk , error ) ;
447
459
}
448
460
449
- function getOutlinedModel(response: Response, id: number): any {
461
+ function getOutlinedModel< T > (
462
+ response: Response,
463
+ id: number,
464
+ parentObject: Object,
465
+ key: string,
466
+ map: (response: Response, model: any) => T ,
467
+ ) : T {
450
468
const chunk = getChunk ( response , id ) ;
451
- if ( chunk . status === RESOLVED_MODEL ) {
452
- initializeModelChunk ( chunk ) ;
469
+ switch ( chunk . status ) {
470
+ case RESOLVED_MODEL :
471
+ initializeModelChunk ( chunk ) ;
472
+ break ;
453
473
}
454
- if ( chunk . status !== INITIALIZED ) {
455
- // We know that this is emitted earlier so otherwise it's an error.
456
- throw chunk . reason ;
474
+ // The status might have changed after initialization.
475
+ switch ( chunk . status ) {
476
+ case INITIALIZED :
477
+ return map ( response , chunk . value ) ;
478
+ case PENDING :
479
+ case BLOCKED :
480
+ const parentChunk = initializingChunk ;
481
+ chunk . then (
482
+ createModelResolver (
483
+ parentChunk ,
484
+ parentObject ,
485
+ key ,
486
+ false ,
487
+ response ,
488
+ map ,
489
+ ) ,
490
+ createModelReject ( parentChunk ) ,
491
+ ) ;
492
+ return ( null : any ) ;
493
+ default :
494
+ throw chunk . reason ;
457
495
}
458
- return chunk . value ;
496
+ }
497
+
498
+ function createMap (
499
+ response : Response ,
500
+ model : Array < [ any , any ] > ,
501
+ ): Map< any , any > {
502
+ return new Map ( model ) ;
503
+ }
504
+
505
+ function createSet(response: Response, model: Array< any > ): Set< any > {
506
+ return new Set ( model ) ;
507
+ }
508
+
509
+ function extractIterator(response: Response, model: Array< any > ): Iterator< any > {
510
+ // $FlowFixMe[incompatible-use]: This uses raw Symbols because we're extracting from a native array.
511
+ return model [ Symbol . iterator ] ( ) ;
512
+ }
513
+
514
+ function createModel(response: Response, model: any): any {
515
+ return model ;
459
516
}
460
517
461
518
function parseTypedArray(
@@ -481,10 +538,17 @@ function parseTypedArray(
481
538
} ) ;
482
539
483
540
// Since loading the buffer is an async operation we'll be blocking the parent
484
- // chunk. TODO: This is not safe if the parent chunk needs a mapper like Map.
541
+ // chunk.
485
542
const parentChunk = initializingChunk ;
486
543
promise . then (
487
- createModelResolver ( parentChunk , parentObject , parentKey ) ,
544
+ createModelResolver (
545
+ parentChunk ,
546
+ parentObject ,
547
+ parentKey ,
548
+ false ,
549
+ response ,
550
+ createModel ,
551
+ ) ,
488
552
createModelReject ( parentChunk ) ,
489
553
) ;
490
554
return null ;
@@ -728,7 +792,7 @@ function parseModelString(
728
792
const id = parseInt ( value . slice ( 2 ) , 16 ) ;
729
793
// TODO: Just encode this in the reference inline instead of as a model.
730
794
const metaData : { id : ServerReferenceId , bound : Thenable < Array < any >> } =
731
- getOutlinedModel ( response , id ) ;
795
+ getOutlinedModel ( response , id , obj , key , createModel ) ;
732
796
return loadServerReference (
733
797
response ,
734
798
metaData . id ,
@@ -745,14 +809,12 @@ function parseModelString(
745
809
case 'Q ': {
746
810
// Map
747
811
const id = parseInt ( value . slice ( 2 ) , 16 ) ;
748
- const data = getOutlinedModel ( response , id ) ;
749
- return new Map ( data ) ;
812
+ return getOutlinedModel ( response , id , obj , key , createMap ) ;
750
813
}
751
814
case 'W ': {
752
815
// Set
753
816
const id = parseInt ( value . slice ( 2 ) , 16 ) ;
754
- const data = getOutlinedModel ( response , id ) ;
755
- return new Set ( data ) ;
817
+ return getOutlinedModel ( response , id , obj , key , createSet ) ;
756
818
}
757
819
case 'K ': {
758
820
// FormData
@@ -774,8 +836,7 @@ function parseModelString(
774
836
case 'i ': {
775
837
// Iterator
776
838
const id = parseInt ( value . slice ( 2 ) , 16 ) ;
777
- const data = getOutlinedModel ( response , id ) ;
778
- return data [ Symbol . iterator ] ( ) ;
839
+ return getOutlinedModel ( response , id , obj , key , extractIterator ) ;
779
840
}
780
841
case 'I' : {
781
842
// $Infinity
@@ -873,27 +934,7 @@ function parseModelString(
873
934
874
935
// We assume that anything else is a reference ID.
875
936
const id = parseInt ( value . slice ( 1 ) , 16 ) ;
876
- const chunk = getChunk ( response , id ) ;
877
- switch ( chunk . status ) {
878
- case RESOLVED_MODEL :
879
- initializeModelChunk ( chunk ) ;
880
- break ;
881
- }
882
- // The status might have changed after initialization.
883
- switch ( chunk . status ) {
884
- case INITIALIZED :
885
- return chunk . value ;
886
- case PENDING :
887
- case BLOCKED :
888
- const parentChunk = initializingChunk ;
889
- chunk . then (
890
- createModelResolver ( parentChunk , obj , key ) ,
891
- createModelReject ( parentChunk ) ,
892
- ) ;
893
- return null ;
894
- default :
895
- throw chunk . reason ;
896
- }
937
+ return getOutlinedModel ( response , id , obj , key , createModel ) ;
897
938
}
898
939
return value ;
899
940
}
0 commit comments