Skip to content

Commit 9af3efa

Browse files
author
David Maskasky
committed
fix: failing unstable_resolve tests
1 parent 1e4c2c9 commit 9af3efa

File tree

3 files changed

+133
-125
lines changed

3 files changed

+133
-125
lines changed

src/vanilla/store.ts

+69-64
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ type PrdStore = {
147147
...args: Args
148148
) => Result
149149
sub: (atom: AnyAtom, listener: () => void) => () => void
150-
unstable_resolve?: <Value>(atom: Atom<Value>) => Atom<Value>
150+
unstable_resolve?: <A extends Atom<unknown>>(atom: A) => A
151151
}
152152
type Store = PrdStore & Partial<DevStoreRev2>
153153

@@ -182,10 +182,12 @@ export const createStore = (): Store => {
182182
mountedAtoms = new Set()
183183
}
184184

185+
const resolveAtom = <A extends Atom<unknown>>(atom: A): A => {
186+
return store.unstable_resolve?.(atom) ?? atom
187+
}
188+
185189
const getAtomState = <Value>(atom: Atom<Value>) =>
186-
atomStateMap.get(store.unstable_resolve?.(atom) || atom) as
187-
| AtomState<Value>
188-
| undefined
190+
atomStateMap.get(atom) as AtomState<Value> | undefined
189191

190192
const addPendingDependent = (atom: AnyAtom, atomState: AtomState) => {
191193
atomState.d.forEach((_, a) => {
@@ -208,7 +210,8 @@ export const createStore = (): Store => {
208210
Object.freeze(atomState)
209211
}
210212
const prevAtomState = getAtomState(atom)
211-
atomStateMap.set(store.unstable_resolve?.(atom) || atom, atomState)
213+
atomStateMap.set(atom, atomState)
214+
pendingStack[pendingStack.length - 1]?.add(atom)
212215
if (!pendingMap.has(atom)) {
213216
pendingMap.set(atom, [prevAtomState, new Set()])
214217
addPendingDependent(atom, atomState)
@@ -425,22 +428,23 @@ export const createStore = (): Store => {
425428
const nextDependencies: NextDependencies = new Map()
426429
let isSync = true
427430
const getter: Getter = <V>(a: Atom<V>) => {
428-
if (a === (atom as AnyAtom)) {
429-
const aState = getAtomState(a)
431+
const resolvedA = resolveAtom(a)
432+
if (resolvedA === (atom as AnyAtom)) {
433+
const aState = getAtomState(resolvedA)
430434
if (aState) {
431-
nextDependencies.set(a, aState)
435+
nextDependencies.set(resolvedA, aState)
432436
return returnAtomValue(aState)
433437
}
434-
if (hasInitialValue(a)) {
435-
nextDependencies.set(a, undefined)
436-
return a.init
438+
if (hasInitialValue(resolvedA)) {
439+
nextDependencies.set(resolvedA, undefined)
440+
return resolvedA.init
437441
}
438442
// NOTE invalid derived atoms can reach here
439443
throw new Error('no atom init')
440444
}
441-
// a !== atom
442-
const aState = readAtomState(a, force)
443-
nextDependencies.set(a, aState)
445+
// resolvedA !== atom
446+
const aState = readAtomState(resolvedA, force)
447+
nextDependencies.set(resolvedA, aState)
444448
return returnAtomValue(aState)
445449
}
446450
let controller: AbortController | undefined
@@ -485,7 +489,7 @@ export const createStore = (): Store => {
485489
}
486490

487491
const readAtom = <Value>(atom: Atom<Value>): Value =>
488-
returnAtomValue(readAtomState(atom))
492+
returnAtomValue(readAtomState(resolveAtom(atom)))
489493

490494
const recomputeDependents = (atom: AnyAtom): void => {
491495
const getDependents = (a: AnyAtom): Dependents => {
@@ -556,28 +560,30 @@ export const createStore = (): Store => {
556560
atom: WritableAtom<Value, Args, Result>,
557561
...args: Args
558562
): Result => {
559-
const getter: Getter = <V>(a: Atom<V>) => returnAtomValue(readAtomState(a))
563+
const getter: Getter = <V>(a: Atom<V>) =>
564+
returnAtomValue(readAtomState(resolveAtom(a)))
560565
const setter: Setter = <V, As extends unknown[], R>(
561566
a: WritableAtom<V, As, R>,
562567
...args: As
563568
) => {
569+
const resolvedA = resolveAtom(a)
564570
const isSync = pendingStack.length > 0
565571
if (!isSync) {
566-
pendingStack.push(new Set([a]))
572+
pendingStack.push(new Set([resolvedA]))
567573
}
568574
let r: R | undefined
569-
if (a === (atom as AnyAtom)) {
570-
if (!hasInitialValue(a)) {
575+
if (resolvedA === (atom as AnyAtom)) {
576+
if (!hasInitialValue(resolvedA)) {
571577
// NOTE technically possible but restricted as it may cause bugs
572578
throw new Error('atom not writable')
573579
}
574-
const prevAtomState = getAtomState(a)
575-
const nextAtomState = setAtomValueOrPromise(a, args[0] as V)
580+
const prevAtomState = getAtomState(resolvedA)
581+
const nextAtomState = setAtomValueOrPromise(resolvedA, args[0] as V)
576582
if (!isEqualAtomValue(prevAtomState, nextAtomState)) {
577-
recomputeDependents(a)
583+
recomputeDependents(resolvedA)
578584
}
579585
} else {
580-
r = writeAtomState(a as AnyWritableAtom, ...args) as R
586+
r = writeAtomState(resolvedA as AnyWritableAtom, ...args) as R
581587
}
582588
if (!isSync) {
583589
const flushed = flushPending(pendingStack.pop()!)
@@ -597,8 +603,10 @@ export const createStore = (): Store => {
597603
atom: WritableAtom<Value, Args, Result>,
598604
...args: Args
599605
): Result => {
600-
pendingStack.push(new Set([atom]))
601-
const result = writeAtomState(atom, ...args)
606+
const resolvedAtom = resolveAtom(atom)
607+
pendingStack.push(new Set([resolvedAtom]))
608+
const result = writeAtomState(resolvedAtom, ...args)
609+
602610
const flushed = flushPending(pendingStack.pop()!)
603611
if (import.meta.env?.MODE !== 'production') {
604612
devListenersRev2.forEach((l) => l({ type: 'write', flushed: flushed! }))
@@ -781,8 +789,9 @@ export const createStore = (): Store => {
781789
}
782790

783791
const subscribeAtom = (atom: AnyAtom, listener: () => void) => {
784-
const mounted = mountAtom(atom)
785-
const flushed = flushPending([atom])
792+
const resolvedAtom = resolveAtom(atom)
793+
const mounted = mountAtom(resolvedAtom)
794+
const flushed = flushPending([resolvedAtom])
786795
const listeners = mounted.l
787796
listeners.add(listener)
788797
if (import.meta.env?.MODE !== 'production') {
@@ -792,52 +801,48 @@ export const createStore = (): Store => {
792801
}
793802
return () => {
794803
listeners.delete(listener)
795-
tryUnmountAtom(atom, mounted)
804+
tryUnmountAtom(resolvedAtom, mounted)
796805
if (import.meta.env?.MODE !== 'production') {
797806
// devtools uses this to detect if it _can_ unmount or not
798807
devListenersRev2.forEach((l) => l({ type: 'unsub' }))
799808
}
800809
}
801810
}
802811

803-
const store: Store =
804-
import.meta.env?.MODE !== 'production'
805-
? {
806-
get: readAtom,
807-
set: writeAtom,
808-
sub: subscribeAtom,
809-
// store dev methods (these are tentative and subject to change without notice)
810-
dev_subscribe_store: (l: DevListenerRev2) => {
811-
devListenersRev2.add(l)
812-
return () => {
813-
devListenersRev2.delete(l)
814-
}
815-
},
816-
dev_get_mounted_atoms: () => mountedAtoms.values(),
817-
dev_get_atom_state: getAtomState,
818-
dev_get_mounted: (a: AnyAtom) => mountedMap.get(a),
819-
dev_restore_atoms: (
820-
values: Iterable<readonly [AnyAtom, AnyValue]>,
821-
) => {
822-
pendingStack.push(new Set())
823-
for (const [atom, valueOrPromise] of values) {
824-
if (hasInitialValue(atom)) {
825-
setAtomValueOrPromise(atom, valueOrPromise)
826-
recomputeDependents(atom)
827-
}
828-
}
829-
const flushed = flushPending(pendingStack.pop()!)
830-
devListenersRev2.forEach((l) =>
831-
l({ type: 'restore', flushed: flushed! }),
832-
)
833-
},
812+
const store: Store = {
813+
get: readAtom,
814+
set: writeAtom,
815+
sub: subscribeAtom,
816+
}
817+
if (import.meta.env?.MODE !== 'production') {
818+
const devStore: DevStoreRev2 = {
819+
// store dev methods (these are tentative and subject to change without notice)
820+
dev_subscribe_store: (l) => {
821+
devListenersRev2.add(l)
822+
return () => {
823+
devListenersRev2.delete(l)
834824
}
835-
: {
836-
get: readAtom,
837-
set: writeAtom,
838-
sub: subscribeAtom,
825+
},
826+
dev_get_mounted_atoms: () => mountedAtoms.values(),
827+
dev_get_atom_state: getAtomState,
828+
dev_get_mounted: (a) => mountedMap.get(a),
829+
dev_restore_atoms: (values) => {
830+
pendingStack.push(new Set())
831+
for (const [atom, valueOrPromise] of values) {
832+
if (hasInitialValue(atom)) {
833+
setAtomValueOrPromise(atom, valueOrPromise)
834+
recomputeDependents(atom)
835+
}
839836
}
840-
return store
837+
const flushed = flushPending(pendingStack.pop()!)
838+
devListenersRev2.forEach((l) =>
839+
l({ type: 'restore', flushed: flushed! }),
840+
)
841+
},
842+
}
843+
Object.assign(store, devStore)
844+
}
845+
return store as Store
841846
}
842847

843848
let defaultStore: Store | undefined

0 commit comments

Comments
 (0)