1
+ import assert from 'node:assert' ;
2
+
1
3
import { FlatpackedWrapper } from './flatpackUtil.mjs' ;
4
+ import { proxyDate , proxyObject , proxySet } from './proxy.mjs' ;
2
5
import {
3
6
ArrayRefElement ,
4
7
BigIntRefElement ,
@@ -8,6 +11,7 @@ import {
8
11
ObjectRefElement ,
9
12
ObjectWrapperRefElement ,
10
13
PrimitiveRefElement ,
14
+ PrimitiveRefElementBase ,
11
15
RefElements ,
12
16
RegExpRefElement ,
13
17
SetRefElement ,
@@ -76,6 +80,8 @@ export class FlatpackStore {
76
80
private cachedSets = new Map < ArrayRefElement | undefined , SetRefElement > ( ) ;
77
81
private cachedMaps = new Map < ArrayRefElement | undefined , Map < ArrayRefElement | undefined , MapRefElement > > ( ) ;
78
82
83
+ private cachedProxies = new WeakMap < RefElements , Serializable > ( ) ;
84
+
79
85
/**
80
86
* Cache of strings that have been deduped and stored in the data array.
81
87
*/
@@ -275,7 +281,7 @@ export class FlatpackStore {
275
281
276
282
private dedupeSetRefs ( value : Set < Serializable > , element : SetRefElement ) : SetRefElement {
277
283
if ( ! this . dedupe ) return element ;
278
- const values = element . values ( ) ;
284
+ const values = element . valueRefs ( ) ;
279
285
const found = this . cachedSets . get ( values ) ;
280
286
if ( ! found ) {
281
287
this . cachedSets . set ( values , element ) ;
@@ -287,6 +293,10 @@ export class FlatpackStore {
287
293
return found ;
288
294
}
289
295
296
+ private proxySetRef ( ref : SetRefElement ) : Set < Serializable > {
297
+ return proxySet ( new Set ( this . #toValue( ref . valueRefs ( ) ) as Serializable [ ] ) , ( ) => { } ) ;
298
+ }
299
+
290
300
private createUniqueKeys ( keys : Serializable [ ] ) : ArrayRefElement {
291
301
const cacheValue = false ;
292
302
let k = this . arrToRef ( keys , cacheValue ) ;
@@ -320,8 +330,8 @@ export class FlatpackStore {
320
330
321
331
private dedupeMapRefs ( value : Map < Serializable , Serializable > , element : MapRefElement ) : MapRefElement {
322
332
if ( ! this . dedupe ) return element ;
323
- const keys = element . keys ( ) ;
324
- const values = element . values ( ) ;
333
+ const keys = element . keyRefs ( ) ;
334
+ const values = element . valueRefs ( ) ;
325
335
let found = this . cachedMaps . get ( keys ) ;
326
336
if ( ! found ) {
327
337
found = new Map ( ) ;
@@ -340,6 +350,10 @@ export class FlatpackStore {
340
350
return element ;
341
351
}
342
352
353
+ private proxyMapRef ( _ref : MapRefElement ) : Map < Serializable , Serializable > {
354
+ return new Map ( ) ;
355
+ }
356
+
343
357
private cvtRegExpToRef ( value : RegExp ) : RegExpRefElement {
344
358
const found = this . cache . get ( value ) ;
345
359
if ( found !== undefined ) {
@@ -361,6 +375,10 @@ export class FlatpackStore {
361
375
return this . addValueAndElement ( value , new DateRefElement ( value . getTime ( ) ) ) ;
362
376
}
363
377
378
+ private proxyDateRef ( ref : DateRefElement ) : Date {
379
+ return proxyDate ( ref . value , ( date ) => ref . setTime ( date . getTime ( ) ) ) ;
380
+ }
381
+
364
382
private cvtBigintToRef ( value : bigint ) : BigIntRefElement {
365
383
const found = this . cache . get ( value ) ;
366
384
if ( found !== undefined ) {
@@ -415,8 +433,8 @@ export class FlatpackStore {
415
433
416
434
private dedupeObject ( value : PrimitiveObject | ObjectWrapper , element : ObjectRefElement ) : ObjectRefElement {
417
435
if ( ! this . dedupe ) return element ;
418
- const keys = element . keys ( ) ;
419
- const values = element . values ( ) ;
436
+ const keys = element . keyRefs ( ) ;
437
+ const values = element . valueRefs ( ) ;
420
438
let found = this . cachedObjects . get ( keys ) ;
421
439
if ( ! found ) {
422
440
found = new Map ( ) ;
@@ -435,6 +453,18 @@ export class FlatpackStore {
435
453
return element ;
436
454
}
437
455
456
+ private proxyObjectRef ( ref : ObjectRefElement ) : PrimitiveObject {
457
+ const keys = this . #toValue( ref . keyRefs ( ) ) as string [ ] | undefined ;
458
+ const values = this . #toValue( ref . valueRefs ( ) ) as Serializable [ ] | undefined ;
459
+ const obj = keys && values ? Object . fromEntries ( keys . map ( ( key , i ) => [ key , values [ i ] ] ) ) : { } ;
460
+ return proxyObject ( obj , ( _value ) => { } ) ;
461
+ }
462
+
463
+ private proxyObjectWrapperRef ( ref : ObjectWrapperRefElement ) : PrimitiveObject {
464
+ const value = Object ( this . #toValue( ref . valueRef ( ) ) ) as PrimitiveObject ;
465
+ return proxyObject ( value , ( _value ) => { } ) ;
466
+ }
467
+
438
468
/**
439
469
*
440
470
* @param value - The array converted to an ArrayRefElement.
@@ -482,6 +512,11 @@ export class FlatpackStore {
482
512
return this . dedupeArray ( value , element , cacheValue ) ;
483
513
}
484
514
515
+ private proxyArrayRef ( ref : ArrayRefElement ) : PrimitiveArray {
516
+ const arr = ref . valueRefs ( ) . map ( ( v ) => this . #toValue( v ) ) ;
517
+ return proxyObject ( arr , ( _value ) => { } ) ;
518
+ }
519
+
485
520
private valueToRef ( value : Serializable ) : RefElements {
486
521
if ( value === null ) {
487
522
return this . primitiveToRef ( value ) ;
@@ -619,6 +654,26 @@ export class FlatpackStore {
619
654
}
620
655
}
621
656
657
+ #resolveToValueProxy( ref : RefElements | undefined ) : Unpacked {
658
+ if ( ! ref ) return undefined ;
659
+ if ( ref instanceof ArrayRefElement ) return this . proxyArrayRef ( ref ) ;
660
+ if ( ref instanceof ObjectRefElement ) return this . proxyObjectRef ( ref ) ;
661
+ if ( ref instanceof PrimitiveRefElementBase ) return ref . value ;
662
+ if ( isStringRefElements ( ref ) ) return ref . value ;
663
+ if ( ref instanceof MapRefElement ) return this . proxyMapRef ( ref ) ;
664
+ if ( ref instanceof SetRefElement ) return this . proxySetRef ( ref ) ;
665
+ if ( ref instanceof BigIntRefElement ) return ref . value ;
666
+ if ( ref instanceof RegExpRefElement ) return ref . value ;
667
+ if ( ref instanceof DateRefElement ) return this . proxyDateRef ( ref ) ;
668
+ if ( ref instanceof ObjectWrapperRefElement ) return this . proxyObjectWrapperRef ( ref ) ;
669
+ assert ( false , 'Unknown ref type' ) ;
670
+ }
671
+
672
+ #toValue( ref : RefElements | undefined ) : Unpacked {
673
+ if ( ! ref ) return undefined ;
674
+ return getOrResolve ( this . cachedProxies , ref , ( ref ) => this . #resolveToValueProxy( ref ) ) ;
675
+ }
676
+
622
677
toJSON ( ) : Flatpacked {
623
678
const data = [ dataHeader ] as Flatpacked ;
624
679
const idxLookup = this . assignedElements ;
@@ -654,6 +709,10 @@ export class FlatpackStore {
654
709
toValue ( ) : Unpacked {
655
710
return fromJSON ( this . toJSON ( ) ) ;
656
711
}
712
+
713
+ _toValueProxy ( ) : Unpacked {
714
+ return this . #toValue( this . root ) ;
715
+ }
657
716
}
658
717
659
718
type TrieData = StringRefElements ;
@@ -686,3 +745,15 @@ export function toJSON<V extends Serializable>(json: V, options?: FlatpackOption
686
745
export function stringify ( data : Unpacked , pretty = true ) : string {
687
746
return pretty ? stringifyFlatpacked ( toJSON ( data ) ) : JSON . stringify ( toJSON ( data ) ) ;
688
747
}
748
+
749
+ type WeakOrNever < K , V > = K extends WeakKey ? WeakMap < K , V > : never ;
750
+ type SupportedMap < K , V > = Map < K , V > | WeakOrNever < K , V > ;
751
+
752
+ function getOrResolve < K , V > ( map : SupportedMap < K , V > , key : K , resolver : ( key : K ) => V ) : V {
753
+ let value = map . get ( key ) ;
754
+ if ( value === undefined && ! map . has ( key ) ) {
755
+ value = resolver ( key ) ;
756
+ map . set ( key , value ) ;
757
+ }
758
+ return value as V ;
759
+ }
0 commit comments