@@ -251,7 +251,7 @@ type PrdStore = {
251
251
...args : Args
252
252
) => Result
253
253
sub : ( atom : AnyAtom , listener : ( ) => void ) => ( ) => void
254
- unstable_resolve ?: < Value > ( atom : Atom < Value > ) => Atom < Value >
254
+ unstable_resolve ?: < A extends Atom < unknown > > ( atom : A ) => A
255
255
}
256
256
type Store = PrdStore | ( PrdStore & DevStoreRev4 )
257
257
@@ -268,7 +268,6 @@ export const createStore = (): Store => {
268
268
}
269
269
270
270
const getAtomState = < Value > ( atom : Atom < Value > ) => {
271
- atom = store . unstable_resolve ?.( atom ) || atom
272
271
let atomState = atomStateMap . get ( atom ) as AtomState < Value > | undefined
273
272
if ( ! atomState ) {
274
273
atomState = { d : new Map ( ) , p : new Set ( ) , n : 0 }
@@ -277,6 +276,10 @@ export const createStore = (): Store => {
277
276
return atomState
278
277
}
279
278
279
+ const resolveAtom = < A extends Atom < unknown > > ( atom : A ) : A => {
280
+ return store . unstable_resolve ?.( atom ) ?? atom
281
+ }
282
+
280
283
const setAtomStateValueOrPromise = (
281
284
atom : AnyAtom ,
282
285
atomState : AtomState ,
@@ -326,6 +329,7 @@ export const createStore = (): Store => {
326
329
++ atomState . n
327
330
}
328
331
}
332
+
329
333
const addDependency = < Value > (
330
334
pending : Pending | undefined ,
331
335
atom : Atom < Value > ,
@@ -352,9 +356,10 @@ export const createStore = (): Store => {
352
356
atom : Atom < Value > ,
353
357
force ?: ( a : AnyAtom ) => boolean ,
354
358
) : AtomState < Value > => {
359
+ const resolvedAtom = resolveAtom ( atom )
355
360
// See if we can skip recomputing this atom.
356
- const atomState = getAtomState ( atom )
357
- if ( ! force ?.( atom ) && isAtomStateInitialized ( atomState ) ) {
361
+ const atomState = getAtomState ( resolvedAtom )
362
+ if ( ! force ?.( resolvedAtom ) && isAtomStateInitialized ( atomState ) ) {
358
363
// If the atom is mounted, we can use the cache.
359
364
// because it should have been updated by dependencies.
360
365
if ( atomState . m ) {
@@ -377,26 +382,27 @@ export const createStore = (): Store => {
377
382
atomState . d . clear ( )
378
383
let isSync = true
379
384
const getter : Getter = < V > ( a : Atom < V > ) => {
380
- if ( a === ( atom as AnyAtom ) ) {
381
- const aState = getAtomState ( a )
385
+ const resolvedA = resolveAtom ( a )
386
+ if ( resolvedA === ( resolvedAtom as AnyAtom ) ) {
387
+ const aState = getAtomState ( resolvedA )
382
388
if ( ! isAtomStateInitialized ( aState ) ) {
383
- if ( hasInitialValue ( a ) ) {
384
- setAtomStateValueOrPromise ( a , aState , a . init )
389
+ if ( hasInitialValue ( resolvedA ) ) {
390
+ setAtomStateValueOrPromise ( resolvedA , aState , resolvedA . init )
385
391
} else {
386
392
// NOTE invalid derived atoms can reach here
387
393
throw new Error ( 'no atom init' )
388
394
}
389
395
}
390
396
return returnAtomValue ( aState )
391
397
}
392
- // a !== atom
393
- const aState = readAtomState ( pending , a , force )
398
+ // resolvedA !== resolvedAtom
399
+ const aState = readAtomState ( pending , resolvedA , force )
394
400
if ( isSync ) {
395
- addDependency ( pending , atom , a , aState )
401
+ addDependency ( pending , resolvedAtom , resolvedA , aState )
396
402
} else {
397
403
const pending = createPending ( )
398
- addDependency ( pending , atom , a , aState )
399
- mountDependencies ( pending , atom , atomState )
404
+ addDependency ( pending , resolvedAtom , resolvedA , aState )
405
+ mountDependencies ( pending , resolvedAtom , atomState )
400
406
flushPending ( pending )
401
407
}
402
408
return returnAtomValue ( aState )
@@ -413,34 +419,34 @@ export const createStore = (): Store => {
413
419
get setSelf ( ) {
414
420
if (
415
421
import . meta. env ?. MODE !== 'production' &&
416
- ! isActuallyWritableAtom ( atom )
422
+ ! isActuallyWritableAtom ( resolvedAtom )
417
423
) {
418
424
console . warn ( 'setSelf function cannot be used with read-only atom' )
419
425
}
420
- if ( ! setSelf && isActuallyWritableAtom ( atom ) ) {
426
+ if ( ! setSelf && isActuallyWritableAtom ( resolvedAtom ) ) {
421
427
setSelf = ( ...args ) => {
422
428
if ( import . meta. env ?. MODE !== 'production' && isSync ) {
423
429
console . warn ( 'setSelf function cannot be called in sync' )
424
430
}
425
431
if ( ! isSync ) {
426
- return writeAtom ( atom , ...args )
432
+ return writeAtom ( resolvedAtom , ...args )
427
433
}
428
434
}
429
435
}
430
436
return setSelf
431
437
} ,
432
438
}
433
439
try {
434
- const valueOrPromise = atom . read ( getter , options as never )
440
+ const valueOrPromise = resolvedAtom . read ( getter , options as never )
435
441
setAtomStateValueOrPromise (
436
- atom ,
442
+ resolvedAtom ,
437
443
atomState ,
438
444
valueOrPromise ,
439
445
( ) => controller ?. abort ( ) ,
440
446
( ) => {
441
447
if ( atomState . m ) {
442
448
const pending = createPending ( )
443
- mountDependencies ( pending , atom , atomState )
449
+ mountDependencies ( pending , resolvedAtom , atomState )
444
450
flushPending ( pending )
445
451
}
446
452
} ,
@@ -530,35 +536,37 @@ export const createStore = (): Store => {
530
536
atom : WritableAtom < Value , Args , Result > ,
531
537
...args : Args
532
538
) : Result => {
539
+ const resolvedAtom = resolveAtom ( atom )
533
540
const getter : Getter = < V > ( a : Atom < V > ) =>
534
- returnAtomValue ( readAtomState ( pending , a ) )
541
+ returnAtomValue ( readAtomState ( pending , resolveAtom ( a ) ) )
535
542
const setter : Setter = < V , As extends unknown [ ] , R > (
536
543
a : WritableAtom < V , As , R > ,
537
544
...args : As
538
545
) => {
539
546
let r : R | undefined
540
- if ( a === ( atom as AnyAtom ) ) {
541
- if ( ! hasInitialValue ( a ) ) {
547
+ const resolvedA = resolveAtom ( a )
548
+ if ( resolvedA === ( resolvedAtom as AnyAtom ) ) {
549
+ if ( ! hasInitialValue ( resolvedA ) ) {
542
550
// NOTE technically possible but restricted as it may cause bugs
543
551
throw new Error ( 'atom not writable' )
544
552
}
545
- const aState = getAtomState ( a )
553
+ const aState = getAtomState ( resolvedA )
546
554
const hasPrevValue = 'v' in aState
547
555
const prevValue = aState . v
548
556
const v = args [ 0 ] as V
549
- setAtomStateValueOrPromise ( a , aState , v )
550
- mountDependencies ( pending , a , aState )
557
+ setAtomStateValueOrPromise ( resolvedA , aState , v )
558
+ mountDependencies ( pending , resolvedA , aState )
551
559
if ( ! hasPrevValue || ! Object . is ( prevValue , aState . v ) ) {
552
- addPendingAtom ( pending , a , aState )
553
- recomputeDependents ( pending , a )
560
+ addPendingAtom ( pending , resolvedA , aState )
561
+ recomputeDependents ( pending , resolvedA )
554
562
}
555
563
} else {
556
- r = writeAtomState ( pending , a as AnyWritableAtom , ...args ) as R
564
+ r = writeAtomState ( pending , resolvedA , ...args )
557
565
}
558
566
flushPending ( pending )
559
567
return r as R
560
568
}
561
- const result = atom . write ( getter , setter , ...args )
569
+ const result = resolvedAtom . write ( getter , setter , ...args )
562
570
return result
563
571
}
564
572
@@ -596,14 +604,15 @@ export const createStore = (): Store => {
596
604
}
597
605
598
606
const mountAtom = ( pending : Pending , atom : AnyAtom ) : Mounted => {
599
- const atomState = getAtomState ( atom )
607
+ const resolvedAtom = resolveAtom ( atom )
608
+ const atomState = getAtomState ( resolvedAtom )
600
609
if ( ! atomState . m ) {
601
610
// recompute atom state
602
- readAtomState ( pending , atom )
611
+ readAtomState ( pending , resolvedAtom )
603
612
// mount dependencies first
604
613
for ( const a of atomState . d . keys ( ) ) {
605
614
const aMounted = mountAtom ( pending , a )
606
- aMounted . t . add ( atom )
615
+ aMounted . t . add ( resolvedAtom )
607
616
}
608
617
// mount self
609
618
atomState . m = {
@@ -612,14 +621,14 @@ export const createStore = (): Store => {
612
621
t : new Set ( ) ,
613
622
}
614
623
if ( import . meta. env ?. MODE !== 'production' ) {
615
- debugMountedAtoms . add ( atom )
624
+ debugMountedAtoms . add ( resolvedAtom )
616
625
}
617
- if ( isActuallyWritableAtom ( atom ) && atom . onMount ) {
626
+ if ( isActuallyWritableAtom ( resolvedAtom ) && resolvedAtom . onMount ) {
618
627
const mounted = atomState . m
619
- const { onMount } = atom
628
+ const { onMount } = resolvedAtom
620
629
addPendingFunction ( pending , ( ) => {
621
630
const onUnmount = onMount ( ( ...args ) =>
622
- writeAtomState ( pending , atom , ...args ) ,
631
+ writeAtomState ( pending , resolvedAtom , ...args ) ,
623
632
)
624
633
if ( onUnmount ) {
625
634
mounted . u = onUnmount
@@ -634,7 +643,8 @@ export const createStore = (): Store => {
634
643
pending : Pending ,
635
644
atom : AnyAtom ,
636
645
) : Mounted | undefined => {
637
- const atomState = getAtomState ( atom )
646
+ const resolvedAtom = resolveAtom ( atom )
647
+ const atomState = getAtomState ( resolvedAtom )
638
648
if (
639
649
atomState . m &&
640
650
! atomState . m . l . size &&
@@ -647,12 +657,12 @@ export const createStore = (): Store => {
647
657
}
648
658
delete atomState . m
649
659
if ( import . meta. env ?. MODE !== 'production' ) {
650
- debugMountedAtoms . delete ( atom )
660
+ debugMountedAtoms . delete ( resolvedAtom )
651
661
}
652
662
// unmount dependencies
653
663
for ( const a of atomState . d . keys ( ) ) {
654
664
const aMounted = unmountAtom ( pending , a )
655
- aMounted ?. t . delete ( atom )
665
+ aMounted ?. t . delete ( resolvedAtom )
656
666
}
657
667
// abort pending promise
658
668
const pendingPromise = getPendingContinuablePromise ( atomState )
@@ -685,6 +695,7 @@ export const createStore = (): Store => {
685
695
get : readAtom ,
686
696
set : writeAtom ,
687
697
sub : subscribeAtom ,
698
+ unstable_resolve : undefined ,
688
699
// store dev methods (these are tentative and subject to change without notice)
689
700
dev4_get_internal_weak_map : ( ) => atomStateMap ,
690
701
dev4_override_method : ( key , fn ) => {
@@ -712,6 +723,7 @@ export const createStore = (): Store => {
712
723
get : readAtom ,
713
724
set : writeAtom ,
714
725
sub : subscribeAtom ,
726
+ unstable_resolve : undefined ,
715
727
}
716
728
return store
717
729
}
0 commit comments