Skip to content

Commit 18e83e7

Browse files
author
David Maskasky
committed
fix: failing unstable_resolve tests
1 parent 1a26eaa commit 18e83e7

File tree

3 files changed

+129
-122
lines changed

3 files changed

+129
-122
lines changed

src/vanilla/store.ts

+68-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,7 @@ 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)
212214
if (!pendingMap.has(atom)) {
213215
pendingMap.set(atom, [prevAtomState, new Set()])
214216
addPendingDependent(atom, atomState)
@@ -425,22 +427,23 @@ export const createStore = (): Store => {
425427
const nextDependencies: NextDependencies = new Map()
426428
let isSync = true
427429
const getter: Getter = <V>(a: Atom<V>) => {
428-
if (a === (atom as AnyAtom)) {
429-
const aState = getAtomState(a)
430+
const resolvedA = resolveAtom(a)
431+
if (resolvedA === (atom as AnyAtom)) {
432+
const aState = getAtomState(resolvedA)
430433
if (aState) {
431-
nextDependencies.set(a, aState)
434+
nextDependencies.set(resolvedA, aState)
432435
return returnAtomValue(aState)
433436
}
434-
if (hasInitialValue(a)) {
435-
nextDependencies.set(a, undefined)
436-
return a.init
437+
if (hasInitialValue(resolvedA)) {
438+
nextDependencies.set(resolvedA, undefined)
439+
return resolvedA.init
437440
}
438441
// NOTE invalid derived atoms can reach here
439442
throw new Error('no atom init')
440443
}
441-
// a !== atom
442-
const aState = readAtomState(a, force)
443-
nextDependencies.set(a, aState)
444+
// resolvedA !== atom
445+
const aState = readAtomState(resolvedA, force)
446+
nextDependencies.set(resolvedA, aState)
444447
return returnAtomValue(aState)
445448
}
446449
let controller: AbortController | undefined
@@ -485,7 +488,7 @@ export const createStore = (): Store => {
485488
}
486489

487490
const readAtom = <Value>(atom: Atom<Value>): Value =>
488-
returnAtomValue(readAtomState(atom))
491+
returnAtomValue(readAtomState(resolveAtom(atom)))
489492

490493
const recomputeDependents = (atom: AnyAtom): void => {
491494
const getDependents = (a: AnyAtom): Dependents => {
@@ -556,28 +559,30 @@ export const createStore = (): Store => {
556559
atom: WritableAtom<Value, Args, Result>,
557560
...args: Args
558561
): Result => {
559-
const getter: Getter = <V>(a: Atom<V>) => returnAtomValue(readAtomState(a))
562+
const getter: Getter = <V>(a: Atom<V>) =>
563+
returnAtomValue(readAtomState(resolveAtom(a)))
560564
const setter: Setter = <V, As extends unknown[], R>(
561565
a: WritableAtom<V, As, R>,
562566
...args: As
563567
) => {
568+
const resolvedA = resolveAtom(a)
564569
const isSync = pendingStack.length > 0
565570
if (!isSync) {
566-
pendingStack.push(new Set([a]))
571+
pendingStack.push(new Set([resolvedA]))
567572
}
568573
let r: R | undefined
569-
if (a === (atom as AnyAtom)) {
570-
if (!hasInitialValue(a)) {
574+
if (resolvedA === (atom as AnyAtom)) {
575+
if (!hasInitialValue(resolvedA)) {
571576
// NOTE technically possible but restricted as it may cause bugs
572577
throw new Error('atom not writable')
573578
}
574-
const prevAtomState = getAtomState(a)
575-
const nextAtomState = setAtomValueOrPromise(a, args[0] as V)
579+
const prevAtomState = getAtomState(resolvedA)
580+
const nextAtomState = setAtomValueOrPromise(resolvedA, args[0] as V)
576581
if (!isEqualAtomValue(prevAtomState, nextAtomState)) {
577-
recomputeDependents(a)
582+
recomputeDependents(resolvedA)
578583
}
579584
} else {
580-
r = writeAtomState(a as AnyWritableAtom, ...args) as R
585+
r = writeAtomState(resolvedA as AnyWritableAtom, ...args) as R
581586
}
582587
if (!isSync) {
583588
const flushed = flushPending(pendingStack.pop()!)
@@ -597,8 +602,10 @@ export const createStore = (): Store => {
597602
atom: WritableAtom<Value, Args, Result>,
598603
...args: Args
599604
): Result => {
600-
pendingStack.push(new Set([atom]))
601-
const result = writeAtomState(atom, ...args)
605+
const resolvedAtom = resolveAtom(atom)
606+
pendingStack.push(new Set([resolvedAtom]))
607+
const result = writeAtomState(resolvedAtom, ...args)
608+
602609
const flushed = flushPending(pendingStack.pop()!)
603610
if (import.meta.env?.MODE !== 'production') {
604611
devListenersRev2.forEach((l) => l({ type: 'write', flushed: flushed! }))
@@ -781,8 +788,9 @@ export const createStore = (): Store => {
781788
}
782789

783790
const subscribeAtom = (atom: AnyAtom, listener: () => void) => {
784-
const mounted = mountAtom(atom)
785-
const flushed = flushPending([atom])
791+
const resolvedAtom = resolveAtom(atom)
792+
const mounted = mountAtom(resolvedAtom)
793+
const flushed = flushPending([resolvedAtom])
786794
const listeners = mounted.l
787795
listeners.add(listener)
788796
if (import.meta.env?.MODE !== 'production') {
@@ -792,52 +800,48 @@ export const createStore = (): Store => {
792800
}
793801
return () => {
794802
listeners.delete(listener)
795-
tryUnmountAtom(atom, mounted)
803+
tryUnmountAtom(resolvedAtom, mounted)
796804
if (import.meta.env?.MODE !== 'production') {
797805
// devtools uses this to detect if it _can_ unmount or not
798806
devListenersRev2.forEach((l) => l({ type: 'unsub' }))
799807
}
800808
}
801809
}
802810

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

843847
let defaultStore: Store | undefined

0 commit comments

Comments
 (0)