diff --git a/.github/workflows/test-multiple-builds.yml b/.github/workflows/test-multiple-builds.yml index 1ec7646014..49233be8b9 100644 --- a/.github/workflows/test-multiple-builds.yml +++ b/.github/workflows/test-multiple-builds.yml @@ -43,7 +43,7 @@ jobs: sed -i~ "s/resolve('\.\/src\(.*\)\.ts')/resolve('\.\/dist\1.js')/" vitest.config.mts sed -i~ "s/import { useResetAtom } from 'jotai\/react\/utils'/const { useResetAtom } = require('..\/..\/..\/dist\/react\/utils.js')/" tests/react/utils/useResetAtom.test.tsx sed -i~ "s/import { RESET, atomWithReducer, atomWithReset } from 'jotai\/vanilla\/utils'/const { RESET, atomWithReducer, atomWithReset } = require('..\/..\/..\/dist\/vanilla\/utils.js')/" tests/react/utils/useResetAtom.test.tsx - perl -i~ -0777 -pe "s/import {[^}]+} from 'jotai\/vanilla\/internals'/const { INTERNAL_buildStoreRev2: INTERNAL_buildStore, INTERNAL_initializeStoreHooksRev2: INTERNAL_initializeStoreHooks, INTERNAL_getBuildingBlocksRev2: INTERNAL_getBuildingBlocks } = require('..\/..\/dist\/vanilla\/internals.js')/g" tests/vanilla/store.test.tsx tests/vanilla/internals.test.tsx tests/vanilla/derive.test.tsx tests/vanilla/effect.test.ts + perl -i~ -0777 -pe "s/import {[^}]+} from 'jotai\/vanilla\/internals'/const { INTERNAL_buildStoreRev3: INTERNAL_buildStore, INTERNAL_initializeStoreHooksRev3: INTERNAL_initializeStoreHooks, INTERNAL_getBuildingBlocksRev3: INTERNAL_getBuildingBlocks } = require('..\/..\/dist\/vanilla\/internals.js')/g" tests/vanilla/store.test.tsx tests/vanilla/internals.test.tsx tests/vanilla/derive.test.tsx tests/vanilla/effect.test.ts - name: Patch for ESM if: ${{ matrix.build == 'esm' }} run: | diff --git a/src/react/useAtomValue.ts b/src/react/useAtomValue.ts index c0e618af84..84a5847227 100644 --- a/src/react/useAtomValue.ts +++ b/src/react/useAtomValue.ts @@ -1,5 +1,5 @@ import React, { useDebugValue, useEffect, useReducer } from 'react' -import { INTERNAL_getBuildingBlocksRev2 as INTERNAL_getBuildingBlocks } from '../vanilla/internals.ts' +import { INTERNAL_getBuildingBlocksRev3 as INTERNAL_getBuildingBlocks } from '../vanilla/internals.ts' import type { Atom, ExtractAtomValue } from '../vanilla.ts' import { useStore } from './Provider.ts' @@ -85,7 +85,7 @@ const createContinuablePromise = ( continuablePromiseMap.set(nextValue, continuablePromise!) curr = nextValue nextValue.then(onFulfilled(nextValue), onRejected(nextValue)) - registerAbortHandler(store, nextValue, onAbort) + registerAbortHandler(buildingBlocks, store, nextValue, onAbort) } else { resolve(nextValue) } @@ -94,7 +94,7 @@ const createContinuablePromise = ( } } promise.then(onFulfilled(promise), onRejected(promise)) - registerAbortHandler(store, promise, onAbort) + registerAbortHandler(buildingBlocks, store, promise, onAbort) }) continuablePromiseMap.set(promise, continuablePromise) } diff --git a/src/vanilla/internals.ts b/src/vanilla/internals.ts index bbe9d2c24a..86540466af 100644 --- a/src/vanilla/internals.ts +++ b/src/vanilla/internals.ts @@ -89,70 +89,112 @@ type ChangedAtoms = SetLike type Callbacks = SetLike<() => void> type AtomRead = ( + buildingBlocks: Readonly, store: Store, atom: Atom, ...params: Parameters['read']> ) => Value type AtomWrite = ( + buildingBlocks: Readonly, store: Store, atom: WritableAtom, ...params: Parameters['write']> ) => Result -type AtomOnInit = (store: Store, atom: Atom) => void +type AtomOnInit = ( + buildingBlocks: Readonly, + store: Store, + atom: Atom, +) => void type AtomOnMount = ( + buildingBlocks: Readonly, store: Store, atom: WritableAtomWithOnMount, setAtom: (...args: Args) => Result, ) => OnUnmount | void type EnsureAtomState = ( + buildingBlocks: Readonly, store: Store, atom: Atom, ) => AtomState -type FlushCallbacks = (store: Store) => void -type RecomputeInvalidatedAtoms = (store: Store) => void +type FlushCallbacks = ( + buildingBlocks: Readonly, + store: Store, +) => void +type RecomputeInvalidatedAtoms = ( + buildingBlocks: Readonly, + store: Store, +) => void type ReadAtomState = ( + buildingBlocks: Readonly, store: Store, atom: Atom, ) => AtomState -type InvalidateDependents = (store: Store, atom: AnyAtom) => void +type InvalidateDependents = ( + buildingBlocks: Readonly, + store: Store, + atom: AnyAtom, +) => void type WriteAtomState = ( + buildingBlocks: Readonly, store: Store, atom: WritableAtom, - ...args: Args + args: Args, ) => Result -type MountDependencies = (store: Store, atom: AnyAtom) => void -type MountAtom = (store: Store, atom: Atom) => Mounted +type MountDependencies = ( + buildingBlocks: Readonly, + store: Store, + atom: AnyAtom, +) => void +type MountAtom = ( + buildingBlocks: Readonly, + store: Store, + atom: Atom, +) => Mounted type UnmountAtom = ( + buildingBlocks: Readonly, store: Store, atom: Atom, ) => Mounted | undefined type SetAtomStateValueOrPromise = ( + buildingBlocks: Readonly, store: Store, atom: Atom, valueOrPromise: Value, ) => void -type StoreGet = (store: Store, atom: Atom) => Value +type StoreGet = ( + buildingBlocks: Readonly, + store: Store, + atom: Atom, +) => Value type StoreSet = ( + buildingBlocks: Readonly, store: Store, atom: WritableAtom, ...args: Args ) => Result type StoreSub = ( + buildingBlocks: Readonly, store: Store, atom: AnyAtom, listener: () => void, ) => () => void type EnhanceBuildingBlocks = ( buildingBlocks: Readonly, + store: Store, ) => Readonly type AbortHandlersMap = WeakMapLike, Set<() => void>> type RegisterAbortHandler = ( + buildingBlocks: Readonly, store: Store, promise: PromiseLike, abortHandler: () => void, ) => void -type AbortPromise = (store: Store, promise: PromiseLike) => void +type AbortPromise = ( + buildingBlocks: Readonly, + store: Store, + promise: PromiseLike, +) => void type StoreEpochHolder = [n: EpochNumber] type Store = { @@ -384,17 +426,32 @@ function initializeStoreHooks(storeHooks: StoreHooks): Required { // Main functions // -const BUILDING_BLOCK_atomRead: AtomRead = (_store, atom, ...params) => - atom.read(...params) -const BUILDING_BLOCK_atomWrite: AtomWrite = (_store, atom, ...params) => - atom.write(...params) -const BUILDING_BLOCK_atomOnInit: AtomOnInit = (store, atom) => +const BUILDING_BLOCK_atomRead: AtomRead = ( + _buildingBlocks, + _store, + atom, + ...params +) => atom.read(...params) +const BUILDING_BLOCK_atomWrite: AtomWrite = ( + _buildingBlocks, + _store, + atom, + ...params +) => atom.write(...params) +const BUILDING_BLOCK_atomOnInit: AtomOnInit = (_buildingBlocks, store, atom) => atom.INTERNAL_onInit?.(store) -const BUILDING_BLOCK_atomOnMount: AtomOnMount = (_store, atom, setAtom) => - atom.onMount?.(setAtom) +const BUILDING_BLOCK_atomOnMount: AtomOnMount = ( + _buildingBlocks, + _store, + atom, + setAtom, +) => atom.onMount?.(setAtom) -const BUILDING_BLOCK_ensureAtomState: EnsureAtomState = (store, atom) => { - const buildingBlocks = getInternalBuildingBlocks(store) +const BUILDING_BLOCK_ensureAtomState: EnsureAtomState = ( + buildingBlocks, + store, + atom, +) => { const atomStateMap = buildingBlocks[0] const storeHooks = buildingBlocks[6] const atomOnInit = buildingBlocks[9] @@ -406,13 +463,15 @@ const BUILDING_BLOCK_ensureAtomState: EnsureAtomState = (store, atom) => { atomState = { d: new Map(), p: new Set(), n: 0 } atomStateMap.set(atom, atomState) storeHooks.i?.(atom) - atomOnInit?.(store, atom) + atomOnInit?.(buildingBlocks, store, atom) } return atomState as never } -const BUILDING_BLOCK_flushCallbacks: FlushCallbacks = (store) => { - const buildingBlocks = getInternalBuildingBlocks(store) +const BUILDING_BLOCK_flushCallbacks: FlushCallbacks = ( + buildingBlocks, + store, +) => { const mountedMap = buildingBlocks[1] const changedAtoms = buildingBlocks[3] const mountCallbacks = buildingBlocks[4] @@ -461,7 +520,7 @@ const BUILDING_BLOCK_flushCallbacks: FlushCallbacks = (store) => { call(fn) } if (changedAtoms.size) { - recomputeInvalidatedAtoms(store) + recomputeInvalidatedAtoms(buildingBlocks, store) } } while (changedAtoms.size || unmountCallbacks.size || mountCallbacks.size) if (errors.length) { @@ -470,9 +529,9 @@ const BUILDING_BLOCK_flushCallbacks: FlushCallbacks = (store) => { } const BUILDING_BLOCK_recomputeInvalidatedAtoms: RecomputeInvalidatedAtoms = ( + buildingBlocks, store, ) => { - const buildingBlocks = getInternalBuildingBlocks(store) const mountedMap = buildingBlocks[1] const invalidatedAtoms = buildingBlocks[2] const changedAtoms = buildingBlocks[3] @@ -497,7 +556,7 @@ const BUILDING_BLOCK_recomputeInvalidatedAtoms: RecomputeInvalidatedAtoms = ( // without incoming edges, which is one reason we can simplify the algorithm for (const atom of changedAtoms) { stackAtoms.push(atom) - stackStates.push(ensureAtomState(store, atom)) + stackStates.push(ensureAtomState(buildingBlocks, store, atom)) } while (stackAtoms.length) { const top = stackAtoms.length - 1 @@ -533,7 +592,7 @@ const BUILDING_BLOCK_recomputeInvalidatedAtoms: RecomputeInvalidatedAtoms = ( for (const d of getMountedOrPendingDependents(a, aState, mountedMap)) { if (!visiting.has(d)) { stackAtoms.push(d) - stackStates.push(ensureAtomState(store, d)) + stackStates.push(ensureAtomState(buildingBlocks, store, d)) } } } @@ -551,8 +610,8 @@ const BUILDING_BLOCK_recomputeInvalidatedAtoms: RecomputeInvalidatedAtoms = ( } if (hasChangedDeps) { invalidatedAtoms.set(a, aState.n) - readAtomState(store, a) - mountDependencies(store, a) + readAtomState(buildingBlocks, store, a) + mountDependencies(buildingBlocks, store, a) } invalidatedAtoms.delete(a) } @@ -561,8 +620,11 @@ const BUILDING_BLOCK_recomputeInvalidatedAtoms: RecomputeInvalidatedAtoms = ( // Dev only const storeMutationSet = new WeakSet() -const BUILDING_BLOCK_readAtomState: ReadAtomState = (store, atom) => { - const buildingBlocks = getInternalBuildingBlocks(store) +const BUILDING_BLOCK_readAtomState: ReadAtomState = ( + buildingBlocks, + store, + atom, +) => { const mountedMap = buildingBlocks[1] const invalidatedAtoms = buildingBlocks[2] const changedAtoms = buildingBlocks[3] @@ -577,7 +639,7 @@ const BUILDING_BLOCK_readAtomState: ReadAtomState = (store, atom) => { const setAtomStateValueOrPromise = buildingBlocks[20] const registerAbortHandler = buildingBlocks[26] const storeEpochHolder = buildingBlocks[28] - const atomState = ensureAtomState(store, atom) + const atomState = ensureAtomState(buildingBlocks, store, atom) const storeEpochNumber = storeEpochHolder[0] // See if we can skip recomputing this atom. if (isAtomStateInitialized(atomState)) { @@ -597,7 +659,7 @@ const BUILDING_BLOCK_readAtomState: ReadAtomState = (store, atom) => { // If all dependencies haven't changed, we can use the cache. let hasChangedDeps = false for (const [a, n] of atomState.d) { - if (readAtomState(store, a).n !== n) { + if (readAtomState(buildingBlocks, store, a).n !== n) { hasChangedDeps = true break } @@ -619,19 +681,19 @@ const BUILDING_BLOCK_readAtomState: ReadAtomState = (store, atom) => { if (mountedMap.has(atom)) { // If changedAtoms is already populated, an outer recompute cycle will handle it const shouldRecompute = !changedAtoms.size - mountDependencies(store, atom) + mountDependencies(buildingBlocks, store, atom) if (shouldRecompute) { - recomputeInvalidatedAtoms(store) - flushCallbacks(store) + recomputeInvalidatedAtoms(buildingBlocks, store) + flushCallbacks(buildingBlocks, store) } } } const getter = (a: Atom) => { if (a === (atom as AnyAtom)) { - const aState = ensureAtomState(store, a) + const aState = ensureAtomState(buildingBlocks, store, a) if (!isAtomStateInitialized(aState)) { if (hasInitialValue(a)) { - setAtomStateValueOrPromise(store, a, a.init) + setAtomStateValueOrPromise(buildingBlocks, store, a, a.init) } else { // NOTE invalid derived atoms can reach here throw new Error('no atom init') @@ -640,7 +702,7 @@ const BUILDING_BLOCK_readAtomState: ReadAtomState = (store, atom) => { return returnAtomValue(aState) } // a !== atom - const aState = readAtomState(store, a) + const aState = readAtomState(buildingBlocks, store, a) try { return returnAtomValue(aState) } finally { @@ -686,10 +748,10 @@ const BUILDING_BLOCK_readAtomState: ReadAtomState = (store, atom) => { } if (!isSync) { try { - return writeAtomState(store, atom, ...args) + return writeAtomState(buildingBlocks, store, atom, args) } finally { - recomputeInvalidatedAtoms(store) - flushCallbacks(store) + recomputeInvalidatedAtoms(buildingBlocks, store) + flushCallbacks(buildingBlocks, store) } } } @@ -703,15 +765,23 @@ const BUILDING_BLOCK_readAtomState: ReadAtomState = (store, atom) => { if (import.meta.env?.MODE !== 'production') { storeMutationSet.delete(store) } - const valueOrPromise = atomRead(store, atom, getter, options as never) + const valueOrPromise = atomRead( + buildingBlocks, + store, + atom, + getter, + options as never, + ) if (import.meta.env?.MODE !== 'production' && storeMutationSet.has(store)) { console.warn( 'Detected store mutation during atom read. This is not supported.', ) } - setAtomStateValueOrPromise(store, atom, valueOrPromise) + setAtomStateValueOrPromise(buildingBlocks, store, atom, valueOrPromise) if (isPromiseLike(valueOrPromise)) { - registerAbortHandler(store, valueOrPromise, () => controller?.abort()) + registerAbortHandler(buildingBlocks, store, valueOrPromise, () => + controller?.abort(), + ) const settle = () => { pruneDependencies() mountDependenciesIfAsync() @@ -740,19 +810,19 @@ const BUILDING_BLOCK_readAtomState: ReadAtomState = (store, atom) => { } const BUILDING_BLOCK_invalidateDependents: InvalidateDependents = ( + buildingBlocks, store, atom, ) => { - const buildingBlocks = getInternalBuildingBlocks(store) const mountedMap = buildingBlocks[1] const invalidatedAtoms = buildingBlocks[2] const ensureAtomState = buildingBlocks[11] const stack: AnyAtom[] = [atom] while (stack.length) { const a = stack.pop()! - const aState = ensureAtomState(store, a) + const aState = ensureAtomState(buildingBlocks, store, a) for (const d of getMountedOrPendingDependents(a, aState, mountedMap)) { - const dState = ensureAtomState(store, d) + const dState = ensureAtomState(buildingBlocks, store, d) if (invalidatedAtoms.get(d) !== dState.n) { invalidatedAtoms.set(d, dState.n) stack.push(d) @@ -762,11 +832,11 @@ const BUILDING_BLOCK_invalidateDependents: InvalidateDependents = ( } const BUILDING_BLOCK_writeAtomState: WriteAtomState = ( + buildingBlocks, store, atom, - ...args + args, ) => { - const buildingBlocks = getInternalBuildingBlocks(store) const changedAtoms = buildingBlocks[3] const storeHooks = buildingBlocks[6] const atomWrite = buildingBlocks[8] @@ -781,12 +851,12 @@ const BUILDING_BLOCK_writeAtomState: WriteAtomState = ( const storeEpochHolder = buildingBlocks[28] let isSync = true const getter: Getter = (a: Atom) => - returnAtomValue(readAtomState(store, a)) + returnAtomValue(readAtomState(buildingBlocks, store, a)) const setter: Setter = ( a: WritableAtom, ...args: As ) => { - const aState = ensureAtomState(store, a) + const aState = ensureAtomState(buildingBlocks, store, a) try { if (a === (atom as AnyAtom)) { if (!hasInitialValue(a)) { @@ -798,34 +868,37 @@ const BUILDING_BLOCK_writeAtomState: WriteAtomState = ( } const prevEpochNumber = aState.n const v = args[0] as V - setAtomStateValueOrPromise(store, a, v) - mountDependencies(store, a) + setAtomStateValueOrPromise(buildingBlocks, store, a, v) + mountDependencies(buildingBlocks, store, a) if (prevEpochNumber !== aState.n) { ++storeEpochHolder[0] changedAtoms.add(a) - invalidateDependents(store, a) + invalidateDependents(buildingBlocks, store, a) storeHooks.c?.(a) } return undefined as R } else { - return writeAtomState(store, a, ...args) + return writeAtomState(buildingBlocks, store, a, args) } } finally { if (!isSync) { - recomputeInvalidatedAtoms(store) - flushCallbacks(store) + recomputeInvalidatedAtoms(buildingBlocks, store) + flushCallbacks(buildingBlocks, store) } } } try { - return atomWrite(store, atom, getter, setter, ...args) + return atomWrite(buildingBlocks, store, atom, getter, setter, ...args) } finally { isSync = false } } -const BUILDING_BLOCK_mountDependencies: MountDependencies = (store, atom) => { - const buildingBlocks = getInternalBuildingBlocks(store) +const BUILDING_BLOCK_mountDependencies: MountDependencies = ( + buildingBlocks, + store, + atom, +) => { const mountedMap = buildingBlocks[1] const changedAtoms = buildingBlocks[3] const storeHooks = buildingBlocks[6] @@ -833,18 +906,18 @@ const BUILDING_BLOCK_mountDependencies: MountDependencies = (store, atom) => { const invalidateDependents = buildingBlocks[15] const mountAtom = buildingBlocks[18] const unmountAtom = buildingBlocks[19] - const atomState = ensureAtomState(store, atom) + const atomState = ensureAtomState(buildingBlocks, store, atom) const mounted = mountedMap.get(atom) if (mounted && atomState.d.size > 0) { for (const [a, n] of atomState.d) { if (!mounted.d.has(a)) { - const aState = ensureAtomState(store, a) - const aMounted = mountAtom(store, a) + const aState = ensureAtomState(buildingBlocks, store, a) + const aMounted = mountAtom(buildingBlocks, store, a) aMounted.t.add(atom) mounted.d.add(a) if (n !== aState.n) { changedAtoms.add(a) - invalidateDependents(store, a) + invalidateDependents(buildingBlocks, store, a) storeHooks.c?.(a) } } @@ -852,15 +925,14 @@ const BUILDING_BLOCK_mountDependencies: MountDependencies = (store, atom) => { for (const a of mounted.d) { if (!atomState.d.has(a)) { mounted.d.delete(a) - const aMounted = unmountAtom(store, a) + const aMounted = unmountAtom(buildingBlocks, store, a) aMounted?.t.delete(atom) } } } } -const BUILDING_BLOCK_mountAtom: MountAtom = (store, atom) => { - const buildingBlocks = getInternalBuildingBlocks(store) +const BUILDING_BLOCK_mountAtom: MountAtom = (buildingBlocks, store, atom) => { const mountedMap = buildingBlocks[1] const mountCallbacks = buildingBlocks[4] const storeHooks = buildingBlocks[6] @@ -871,14 +943,14 @@ const BUILDING_BLOCK_mountAtom: MountAtom = (store, atom) => { const readAtomState = buildingBlocks[14] const writeAtomState = buildingBlocks[16] const mountAtom = buildingBlocks[18] - const atomState = ensureAtomState(store, atom) + const atomState = ensureAtomState(buildingBlocks, store, atom) let mounted = mountedMap.get(atom) if (!mounted) { // recompute atom state - readAtomState(store, atom) + readAtomState(buildingBlocks, store, atom) // mount dependencies first for (const a of atomState.d.keys()) { - const aMounted = mountAtom(store, a) + const aMounted = mountAtom(buildingBlocks, store, a) aMounted.t.add(atom) } // mount self @@ -893,16 +965,16 @@ const BUILDING_BLOCK_mountAtom: MountAtom = (store, atom) => { let isSync = true const setAtom = (...args: unknown[]) => { try { - return writeAtomState(store, atom, ...args) + return writeAtomState(buildingBlocks, store, atom, args) } finally { if (!isSync) { - recomputeInvalidatedAtoms(store) - flushCallbacks(store) + recomputeInvalidatedAtoms(buildingBlocks, store) + flushCallbacks(buildingBlocks, store) } } } try { - const onUnmount = atomOnMount(store, atom, setAtom) + const onUnmount = atomOnMount(buildingBlocks, store, atom, setAtom) if (onUnmount) { mounted!.u = () => { isSync = true @@ -924,14 +996,17 @@ const BUILDING_BLOCK_mountAtom: MountAtom = (store, atom) => { return mounted } -const BUILDING_BLOCK_unmountAtom: UnmountAtom = (store, atom) => { - const buildingBlocks = getInternalBuildingBlocks(store) +const BUILDING_BLOCK_unmountAtom: UnmountAtom = ( + buildingBlocks, + store, + atom, +) => { const mountedMap = buildingBlocks[1] const unmountCallbacks = buildingBlocks[5] const storeHooks = buildingBlocks[6] const ensureAtomState = buildingBlocks[11] const unmountAtom = buildingBlocks[19] - const atomState = ensureAtomState(store, atom) + const atomState = ensureAtomState(buildingBlocks, store, atom) let mounted = mountedMap.get(atom) if (!mounted || mounted.l.size) { return mounted @@ -952,7 +1027,7 @@ const BUILDING_BLOCK_unmountAtom: UnmountAtom = (store, atom) => { mountedMap.delete(atom) // unmount dependencies for (const a of atomState.d.keys()) { - const aMounted = unmountAtom(store, a) + const aMounted = unmountAtom(buildingBlocks, store, a) aMounted?.t.delete(atom) } storeHooks.u?.(atom) @@ -962,14 +1037,14 @@ const BUILDING_BLOCK_unmountAtom: UnmountAtom = (store, atom) => { } const BUILDING_BLOCK_setAtomStateValueOrPromise: SetAtomStateValueOrPromise = ( + buildingBlocks, store, atom, valueOrPromise, ) => { - const buildingBlocks = getInternalBuildingBlocks(store) const ensureAtomState = buildingBlocks[11] const abortPromise = buildingBlocks[27] - const atomState = ensureAtomState(store, atom) + const atomState = ensureAtomState(buildingBlocks, store, atom) const hasPrevValue = 'v' in atomState const prevValue = atomState.v if (isPromiseLike(valueOrPromise)) { @@ -977,7 +1052,7 @@ const BUILDING_BLOCK_setAtomStateValueOrPromise: SetAtomStateValueOrPromise = ( addPendingPromiseToDependency( atom, valueOrPromise, - ensureAtomState(store, a), + ensureAtomState(buildingBlocks, store, a), ) } } @@ -986,55 +1061,63 @@ const BUILDING_BLOCK_setAtomStateValueOrPromise: SetAtomStateValueOrPromise = ( if (!hasPrevValue || !Object.is(prevValue, atomState.v)) { ++atomState.n if (isPromiseLike(prevValue)) { - abortPromise(store, prevValue) + abortPromise(buildingBlocks, store, prevValue) } } } -const BUILDING_BLOCK_storeGet: StoreGet = (store, atom) => { - const readAtomState = getInternalBuildingBlocks(store)[14] - return returnAtomValue(readAtomState(store, atom)) +const BUILDING_BLOCK_storeGet: StoreGet = (buildingBlocks, store, atom) => { + const readAtomState = buildingBlocks[14] + return returnAtomValue(readAtomState(buildingBlocks, store, atom)) } -const BUILDING_BLOCK_storeSet: StoreSet = (store, atom, ...args) => { - const buildingBlocks = getInternalBuildingBlocks(store) +const BUILDING_BLOCK_storeSet: StoreSet = ( + buildingBlocks, + store, + atom, + ...args +) => { const changedAtoms = buildingBlocks[3] const flushCallbacks = buildingBlocks[12] const recomputeInvalidatedAtoms = buildingBlocks[13] const writeAtomState = buildingBlocks[16] const prevChangedAtomsSize = changedAtoms.size try { - return writeAtomState(store, atom, ...args) + return writeAtomState(buildingBlocks, store, atom, args) } finally { if (changedAtoms.size !== prevChangedAtomsSize) { - recomputeInvalidatedAtoms(store) - flushCallbacks(store) + recomputeInvalidatedAtoms(buildingBlocks, store) + flushCallbacks(buildingBlocks, store) } } } -const BUILDING_BLOCK_storeSub: StoreSub = (store, atom, listener) => { - const buildingBlocks = getInternalBuildingBlocks(store) +const BUILDING_BLOCK_storeSub: StoreSub = ( + buildingBlocks, + store, + atom, + listener, +) => { const flushCallbacks = buildingBlocks[12] const mountAtom = buildingBlocks[18] const unmountAtom = buildingBlocks[19] - const mounted = mountAtom(store, atom) + const mounted = mountAtom(buildingBlocks, store, atom) const listeners = mounted.l listeners.add(listener) - flushCallbacks(store) + flushCallbacks(buildingBlocks, store) return () => { listeners.delete(listener) - unmountAtom(store, atom) - flushCallbacks(store) + unmountAtom(buildingBlocks, store, atom) + flushCallbacks(buildingBlocks, store) } } const BUILDING_BLOCK_registerAbortHandler: RegisterAbortHandler = ( - store, + buildingBlocks, + _store, promise, abortHandler, ) => { - const buildingBlocks = getInternalBuildingBlocks(store) const abortHandlersMap = buildingBlocks[25] let abortHandlers = abortHandlersMap.get(promise) if (!abortHandlers) { @@ -1046,8 +1129,11 @@ const BUILDING_BLOCK_registerAbortHandler: RegisterAbortHandler = ( abortHandlers.add(abortHandler) } -const BUILDING_BLOCK_abortPromise: AbortPromise = (store, promise) => { - const buildingBlocks = getInternalBuildingBlocks(store) +const BUILDING_BLOCK_abortPromise: AbortPromise = ( + buildingBlocks, + _store, + promise, +) => { const abortHandlersMap = buildingBlocks[25] const abortHandlers = abortHandlersMap.get(promise) abortHandlers?.forEach((fn) => fn()) @@ -1055,40 +1141,32 @@ const BUILDING_BLOCK_abortPromise: AbortPromise = (store, promise) => { const buildingBlockMap = new WeakMap>() -const getInternalBuildingBlocks = (store: Store): Readonly => { +function getBuildingBlocks(store: Store): Readonly { const buildingBlocks = buildingBlockMap.get(store)! if (import.meta.env?.MODE !== 'production' && !buildingBlocks) { throw new Error( 'Store must be created by buildStore to read its building blocks', ) } - return buildingBlocks -} - -function getBuildingBlocks(store: Store): Readonly { - const buildingBlocks = getInternalBuildingBlocks(store) const enhanceBuildingBlocks = buildingBlocks[24] if (enhanceBuildingBlocks) { - return enhanceBuildingBlocks(buildingBlocks) + return enhanceBuildingBlocks(buildingBlocks, store) } return buildingBlocks } -function buildStore(...buildArgs: Partial): Store { - const store = { +function buildStore(...partialBuildingBlocks: Partial): Store { + const store: Store = { get(atom) { - const storeGet = getInternalBuildingBlocks(store)[21] - return storeGet(store, atom) + return storeGet(buildingBlocks, store, atom) }, set(atom, ...args) { - const storeSet = getInternalBuildingBlocks(store)[22] - return storeSet(store, atom, ...args) + return storeSet(buildingBlocks, store, atom, ...args) }, sub(atom, listener) { - const storeSub = getInternalBuildingBlocks(store)[23] - return storeSub(store, atom, listener) + return storeSub(buildingBlocks, store, atom, listener) }, - } as Store + } const buildingBlocks = ( [ @@ -1119,7 +1197,7 @@ function buildStore(...buildArgs: Partial): Store { BUILDING_BLOCK_storeGet, BUILDING_BLOCK_storeSet, BUILDING_BLOCK_storeSub, - undefined, + undefined, // enhanceBuildingBlocks // abortable promise support new WeakMap(), // abortHandlersMap BUILDING_BLOCK_registerAbortHandler, @@ -1127,8 +1205,11 @@ function buildStore(...buildArgs: Partial): Store { // store epoch [0], ] satisfies BuildingBlocks - ).map((fn, i) => buildArgs[i] || fn) as BuildingBlocks + ).map((fn, i) => partialBuildingBlocks[i] || fn) as BuildingBlocks buildingBlockMap.set(store, Object.freeze(buildingBlocks)) + const storeGet = buildingBlocks[21] + const storeSet = buildingBlocks[22] + const storeSub = buildingBlocks[23] return store } @@ -1136,9 +1217,9 @@ export { // // Export internal functions // - buildStore as INTERNAL_buildStoreRev2, - getBuildingBlocks as INTERNAL_getBuildingBlocksRev2, - initializeStoreHooks as INTERNAL_initializeStoreHooksRev2, + buildStore as INTERNAL_buildStoreRev3, + getBuildingBlocks as INTERNAL_getBuildingBlocksRev3, + initializeStoreHooks as INTERNAL_initializeStoreHooksRev3, // // Still experimental and some of them will be gone soon diff --git a/src/vanilla/store.ts b/src/vanilla/store.ts index efa974e469..0a6e027efb 100644 --- a/src/vanilla/store.ts +++ b/src/vanilla/store.ts @@ -1,4 +1,4 @@ -import { INTERNAL_buildStoreRev2 as INTERNAL_buildStore } from './internals.ts' +import { INTERNAL_buildStoreRev3 as INTERNAL_buildStore } from './internals.ts' import type { INTERNAL_Store } from './internals.ts' export type Store = INTERNAL_Store diff --git a/tests/vanilla/effect.test.ts b/tests/vanilla/effect.test.ts index 503f68cde2..454d5cf7e3 100644 --- a/tests/vanilla/effect.test.ts +++ b/tests/vanilla/effect.test.ts @@ -2,8 +2,8 @@ import { afterEach, beforeEach, expect, it, vi } from 'vitest' import type { Atom, Getter, Setter, WritableAtom } from 'jotai/vanilla' import { atom, createStore } from 'jotai/vanilla' import { - INTERNAL_getBuildingBlocksRev2 as INTERNAL_getBuildingBlocks, - INTERNAL_initializeStoreHooksRev2 as INTERNAL_initializeStoreHooks, + INTERNAL_getBuildingBlocksRev3 as INTERNAL_getBuildingBlocks, + INTERNAL_initializeStoreHooksRev3 as INTERNAL_initializeStoreHooks, } from 'jotai/vanilla/internals' beforeEach(() => { diff --git a/tests/vanilla/internals.test.tsx b/tests/vanilla/internals.test.tsx index c95781e167..0b1005b162 100644 --- a/tests/vanilla/internals.test.tsx +++ b/tests/vanilla/internals.test.tsx @@ -7,9 +7,9 @@ import type { INTERNAL_InvalidatedAtoms, } from 'jotai/vanilla/internals' import { - INTERNAL_buildStoreRev2 as INTERNAL_buildStore, - INTERNAL_getBuildingBlocksRev2 as INTERNAL_getBuildingBlocks, - INTERNAL_initializeStoreHooksRev2 as INTERNAL_initializeStoreHooks, + INTERNAL_buildStoreRev3 as INTERNAL_buildStore, + INTERNAL_getBuildingBlocksRev3 as INTERNAL_getBuildingBlocks, + INTERNAL_initializeStoreHooksRev3 as INTERNAL_initializeStoreHooks, } from 'jotai/vanilla/internals' const buildingBlockLength = 29 @@ -203,9 +203,9 @@ describe('internals', () => { } as INTERNAL_InvalidatedAtoms })() - const buildingBlocks: Partial = [] - buildingBlocks[2] = invalidatedAtoms - const store = INTERNAL_buildStore(...buildingBlocks) + const partialBuildingBlocks: Partial = [] + partialBuildingBlocks[2] = invalidatedAtoms + const store = INTERNAL_buildStore(...partialBuildingBlocks) const baseAtom = atom(0) const midAtom1 = atom((get) => get(baseAtom)) @@ -213,8 +213,11 @@ describe('internals', () => { const leafAtom = atom((get) => get(midAtom1) + get(midAtom2)) const unsub = store.sub(leafAtom, () => {}) - const invalidateDependents = INTERNAL_getBuildingBlocks(store)[15] - expect(() => invalidateDependents(store, baseAtom)).not.toThrow() + const buildingBlocks = INTERNAL_getBuildingBlocks(store) + const invalidateDependents = buildingBlocks[15] + expect(() => + invalidateDependents(buildingBlocks, store, baseAtom), + ).not.toThrow() unsub() }) }) diff --git a/tests/vanilla/store.test.tsx b/tests/vanilla/store.test.tsx index b048605b5d..1a3269f709 100644 --- a/tests/vanilla/store.test.tsx +++ b/tests/vanilla/store.test.tsx @@ -2,9 +2,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { atom, createStore } from 'jotai/vanilla' import type { Atom, Getter, PrimitiveAtom } from 'jotai/vanilla' import { - INTERNAL_buildStoreRev2 as INTERNAL_buildStore, - INTERNAL_getBuildingBlocksRev2 as INTERNAL_getBuildingBlocks, - INTERNAL_initializeStoreHooksRev2 as INTERNAL_initializeStoreHooks, + INTERNAL_buildStoreRev3 as INTERNAL_buildStore, + INTERNAL_getBuildingBlocksRev3 as INTERNAL_getBuildingBlocks, + INTERNAL_initializeStoreHooksRev3 as INTERNAL_initializeStoreHooks, } from 'jotai/vanilla/internals' import type { INTERNAL_Store } from 'jotai/vanilla/internals' import { sleep } from '../test-utils' diff --git a/tests/vanilla/storedev.test.tsx b/tests/vanilla/storedev.test.tsx index 8d92e35505..3926a335ed 100644 --- a/tests/vanilla/storedev.test.tsx +++ b/tests/vanilla/storedev.test.tsx @@ -5,8 +5,8 @@ import { describe, expect, it, vi } from 'vitest' import { atom } from 'jotai/vanilla' import type { Atom, WritableAtom } from 'jotai/vanilla' import { - INTERNAL_buildStoreRev2 as INTERNAL_buildStore, - INTERNAL_initializeStoreHooksRev2 as INTERNAL_initializeStoreHooks, + INTERNAL_buildStoreRev3 as INTERNAL_buildStore, + INTERNAL_initializeStoreHooksRev3 as INTERNAL_initializeStoreHooks, } from 'jotai/vanilla/internals' import type { INTERNAL_AtomState, @@ -35,7 +35,7 @@ const createDevStore = (): INTERNAL_Store & DevStore => { undefined, storeHooks, undefined, - (_store, atom, get, set, ...args) => { + (_buildingBlocks, _store, atom, get, set, ...args) => { if (inRestoreAtom) { return set(atom, ...(args as any)) }