UNPKG

reago

Version:

Reago is a declarative, atomic state management library for JavaScript and TypeScript

1,244 lines (1,208 loc) 36.4 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { atomAbortSignal: () => atomAbortSignal, atomAction: () => atomAction, atomComputationEffect: () => atomComputationEffect, atomMemo: () => atomMemo, atomMountEffect: () => atomMountEffect, atomReducer: () => atomReducer, atomRef: () => atomRef, atomState: () => atomState, atomStore: () => atomStore, createStore: () => createStore, deasync: () => deasync, dispatch: () => dispatch, getDefaultStore: () => getDefaultStore, invalidate: () => invalidate, read: () => read, watch: () => watch }); module.exports = __toCommonJS(index_exports); // src/const.ts var METADATA = Symbol(); var NO_VALUE = Symbol(); var FUNCTIONAL_ATOM = Symbol(); var GENERATIVE_ATOM = Symbol(); var PENDING = Symbol(); var RESOLVED = Symbol(); var REJECTED = Symbol(); var LOADED = Symbol(); var UNLOADED = Symbol(); var COMPUTED = Symbol(); var COMPUTING = Symbol(); var OUTDATED = Symbol(); var FRESH = Symbol(); var STALE = Symbol(); var MOUNTED_DIRECTLY = Symbol(); var MOUNTED_TRANSITIVELY = Symbol(); var UNMOUNTED = Symbol(); // src/core/atom-family.ts function createAtomFamily(atom) { return { atom, instanceMap: /* @__PURE__ */ new Map() }; } // src/util/stable-weakref.ts var stableWeakRefMap = /* @__PURE__ */ new WeakMap(); function stableWeakRef(v) { let ref = stableWeakRefMap.get(v); if (ref === void 0) { ref = new WeakRef(v); stableWeakRefMap.set(v, ref); } return ref; } // src/util/iterable-weakset.ts var IterableWeakSet = class { #set = /* @__PURE__ */ new Set(); add(value) { this.#set.add(stableWeakRef(value)); return this; } delete(value) { return this.#set.delete(stableWeakRef(value)); } some(callback) { for (const ref of this.#set.values()) { const value = ref.deref(); if (value) { if (callback(value)) { return true; } } else { this.#set.delete(ref); } } return false; } *[Symbol.iterator]() { for (const ref of this.#set.values()) { const value = ref.deref(); if (value) { yield value; } else { this.#set.delete(ref); } } } }; // src/core/atom-instance.ts function createAtomInstance(atom, args) { return { atom, args, status: OUTDATED, freshness: FRESH, mount: UNMOUNTED, watchers: /* @__PURE__ */ new Set(), dependencies: /* @__PURE__ */ new Set(), dependants: new IterableWeakSet(), stack: [], stackAction: [], stackComputationEffect: [], stackMountEffect: [], freezeStack: false }; } // src/core/atom-watcher.ts function createAtomWatcher(supervisor, instance, listener) { const watcher = { [METADATA]: { supervisor, instance, listener }, clear: () => { if (watcher[METADATA]) { const { supervisor: supervisor2, instance: instance2 } = watcher[METADATA]; watcher[METADATA] = void 0; if (instance2.watchers.delete(watcher)) { if (instance2.watchers.size === 0) { supervisor2.unmountInstance(instance2); supervisor2.flush(); } } } }, [Symbol.dispose]: () => { watcher.clear(); } }; return watcher; } // src/error.ts var AtomError = class extends Error { }; var InternalAtomError = class extends AtomError { }; var IllegalOperationAtomError = class extends AtomError { }; var ComputationAbortedAtomError = class extends AtomError { }; var ComputationContextRequiredAtomError = class extends AtomError { constructor() { super("atom: method can only be used inside an atom computation"); } }; var HookMismatchAtomError = class extends AtomError { constructor() { super("atom: hook call does not match the hook call from older computation"); } }; var HookCountMismatchAtomError = class extends AtomError { constructor() { super("atom: some hooks from a previous computation were omitted this time"); } }; var InvalidCleanupFunctionAtomError = class extends AtomError { constructor() { super("atom: effect returned an invalid cleanup function"); } }; var GeneratorPromiseExpectedAtomError = class extends AtomError { constructor(value) { super( `atom: generator yielded a value that is not a Promise value: ${value}` ); } }; function assert(condition) { if (!condition) { throw new InternalAtomError(); } } // src/reactor/callback-context.ts var callbackContextStack = []; function runWithCallbackContext(context, fn) { callbackContextStack.push(context); try { fn(); } finally { callbackContextStack.pop(); } } function getCallbackContext() { return callbackContextStack.length > 0 ? callbackContextStack[callbackContextStack.length - 1] : null; } // src/util/tracked-promise.ts var promiseState = /* @__PURE__ */ new WeakMap(); function trackPromise(promise) { if (promiseState.has(promise)) { return; } promiseState.set(promise, { status: PENDING }); promise.then( (result) => { promiseState.set(promise, { status: RESOLVED, result }); }, (error) => { promiseState.set(promise, { status: REJECTED, error }); } ); } function trackResolvedPromise(promise, result) { promiseState.set(promise, { status: RESOLVED, result }); } function trackRejectedPromise(promise, error) { promiseState.set(promise, { status: REJECTED, error }); } function getPromiseState(promise) { return promiseState.get(promise) ?? { status: PENDING }; } // src/util/type-check.ts function isAnyAtom(value) { return typeof value === "function"; } function isPromiseLike(value) { return value instanceof Object && typeof value.then === "function"; } function isGenerator(value) { return value instanceof Object && typeof value.next === "function" && typeof value.return === "function" && typeof value.throw === "function"; } // src/reactor/computation-context.ts var computationContextStack = []; function runWithComputationContext(context, fn) { computationContextStack.push(context); try { fn(); } finally { computationContextStack.pop(); } } function runWithoutComputationContext(fn) { computationContextStack.push(null); try { fn(); } finally { computationContextStack.pop(); } } function getComputationContext() { return computationContextStack.length > 0 ? computationContextStack[computationContextStack.length - 1] : null; } function requireComputationContext() { const context = getComputationContext(); if (context === null) { throw new ComputationContextRequiredAtomError(); } return context; } function requireComputationContextStackFrame(hook, frameInitializer) { const context = requireComputationContext(); if (context.computation.pointer < context.instance.stack.length) { if (context.instance.stack[context.computation.pointer].hook !== hook) { throw new HookMismatchAtomError(); } return context.instance.stack[context.computation.pointer++]; } else { if (context.instance.freezeStack) { throw new HookCountMismatchAtomError(); } const frame = frameInitializer(context); context.computation.pointer++; context.instance.stack.push(frame); return frame; } } // src/reactor/runner.ts function createRunner(atom) { return function(...args) { const result = atom(...args); if (isGenerator(result)) { return result; } else { return { [FUNCTIONAL_ATOM]: true, next() { return { done: true, value: result }; } }; } }; } // src/reactor/computation.ts function createComputation() { return { mode: FUNCTIONAL_ATOM, result: NO_VALUE, error: NO_VALUE, abortController: new AbortController(), pointer: 0, dependencies: /* @__PURE__ */ new Set() }; } function runComputation(supervisor, instance, computation) { const context = { supervisor, instance, computation }; let generator; try { runWithComputationContext(context, () => { generator = createRunner(instance.atom)(...instance.args); }); } catch (err) { storeComputationError(computation, err); return; } if (generator[FUNCTIONAL_ATOM] !== true) { computation.mode = GENERATIVE_ATOM; } let stepPromise = runComputationSynchronousSteps(context, generator, "next"); if (stepPromise === null) { return; } computation.promise = (async () => { while (stepPromise !== null) { let method, value; try { value = await stepPromise; method = "next"; } catch (err) { value = err; method = "throw"; } stepPromise = runComputationSynchronousSteps(context, generator, method, value); } })(); } function runComputationSynchronousSteps(context, generator, method, value = void 0) { let step = runComputationStep(context, generator, method, value); if (step === null) return null; do { if (!isPromiseLike(step.value)) { storeComputationError( context.computation, new GeneratorPromiseExpectedAtomError(step.value) ); return null; } trackPromise(step.value); const promiseState2 = getPromiseState(step.value); if (promiseState2.status === RESOLVED) { step = runComputationStep(context, generator, "next", promiseState2.result); if (step === null) return null; } else if (promiseState2.status === REJECTED) { step = runComputationStep(context, generator, "throw", promiseState2.error); if (step === null) return null; } else { return step.value; } } while (true); } function runComputationStep(context, generator, method, value = void 0) { let result = null; runWithComputationContext(context, () => { if (context.computation.abortController.signal.aborted) { try { generator.return(void 0); } catch (err) { } storeComputationAborted(context.computation); return; } let step; try { step = generator[method](value); } catch (err) { storeComputationError(context.computation, err); return; } if (step.done) { storeComputationResult(context.computation, step.value); return; } result = step; }); return result; } function storeComputationResult(computation, result) { computation.result = result; } function storeComputationError(computation, error) { computation.error = error; } function storeComputationAborted(computation) { computation.error = new ComputationAbortedAtomError(); } // src/util/arg-hash.ts function hashFamilyArguments(args) { return JSON.stringify(args); } // src/util/comparison.ts function compareEqual(a, b) { return Object.is(a, b); } function compareDepsEqual(a, b) { if (a === b) { return true; } for (let i = 0; i < Math.max(a.length, b.length); ++i) { if (!Object.is(a[i], b[i])) return false; } return true; } // src/util/swappable-promise.ts function createSwappablePromise(initial = null) { let resolve; let reject; const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); promise[METADATA] = { status: PENDING, promise: null, setPromise: (p) => { assert(promise[METADATA].status === PENDING); if (promise[METADATA].promise === p) { return; } promise[METADATA].promise = p; p?.then( (result) => { if (promise[METADATA].status === PENDING && promise[METADATA].promise === p) { promise[METADATA] = { status: RESOLVED }; resolve(result); } }, (error) => { if (promise[METADATA].status === PENDING && promise[METADATA].promise === p) { promise[METADATA] = { status: REJECTED }; reject(error); } } ); } }; if (initial) { promise[METADATA].setPromise(initial); } return promise; } function swapOrRecreatePromise(swappablePromise, innerPromise) { if (swappablePromise && swappablePromise[METADATA].status === PENDING) { swappablePromise[METADATA].setPromise(innerPromise); return swappablePromise; } else { return createSwappablePromise(innerPromise); } } function unbindSwappablePromiseIfPending(swappablePromise) { if (swappablePromise[METADATA].status === PENDING) { swappablePromise[METADATA].setPromise(null); } } // src/space/supervisor.ts var Supervisor = class { store = new Store(this); #atomFamily = /* @__PURE__ */ new WeakMap(); #mountGCLock = /* @__PURE__ */ new Set(); #flushTimeout = null; #computationQueue = /* @__PURE__ */ new Set(); #watcherDispatchQueue = /* @__PURE__ */ new Set(); #computationEffectQueue = /* @__PURE__ */ new Set(); #computationEffectCleanupRegistry; #mountEffectQueue = /* @__PURE__ */ new Set(); constructor() { this.#computationEffectCleanupRegistry = new FinalizationRegistry((cleanup) => { runWithCallbackContext({ supervisor: this }, cleanup); }); } getOrCreateFamily(atom) { let family = this.#atomFamily.get(atom); if (family === void 0) { family = createAtomFamily(atom); this.#atomFamily.set(atom, family); } return family; } getInstance(atom, ...args) { const family = this.getOrCreateFamily(atom); const hash = hashFamilyArguments(args); return family.instanceMap.get(hash) ?? null; } getOrCreateInstance(atom, ...args) { const family = this.getOrCreateFamily(atom); const hash = hashFamilyArguments(args); let instance = family.instanceMap.get(hash); if (instance === void 0) { instance = createAtomInstance(atom, args); family.instanceMap.set(hash, instance); } return instance; } readInstance(instance) { this.syncInstance(instance); if (instance.promise) { return instance.promise; } if (instance.computation.result !== NO_VALUE) { return instance.computation.result; } throw instance.computation.error; } watchInstance(instance, listener) { this.syncInstance(instance); this.mountInstance(instance); const watcher = createAtomWatcher(this, instance, listener); instance.watchers.add(watcher); return watcher; } dispatchInstance(instance, ...args) { this.syncInstance(instance); if (instance.status === COMPUTED) { this.#runInstanceActions(instance, ...args); } else { assert(instance.status === COMPUTING); instance.promise.finally(() => { this.dispatchInstance(instance, ...args); }).catch(() => { }); } } syncInstance(instance) { if (instance.freshness === STALE) { for (const dependency of instance.dependencies) { this.syncInstance(dependency); } instance.freshness = FRESH; } if (instance.status === OUTDATED) { this.#computationQueue.add(instance); } this.flush(); } mountInstance(instance, mode = MOUNTED_DIRECTLY) { if (instance.mount === UNMOUNTED) { for (const dependency of instance.dependencies) { this.mountInstance(dependency, MOUNTED_TRANSITIVELY); } this.#mountGCLock.add(instance); this.#mountEffectQueue.add(instance); } if (instance.mount !== MOUNTED_DIRECTLY) { instance.mount = mode; } } unmountInstance(instance) { const hasMountedParent = instance.dependants.some((dependant) => dependant.mount !== UNMOUNTED); instance.mount = hasMountedParent ? MOUNTED_TRANSITIVELY : UNMOUNTED; if (instance.mount === UNMOUNTED) { this.#mountGCLock.delete(instance); this.#mountEffectQueue.add(instance); const reverseUnmount = []; for (const dependency of instance.dependencies) { if (dependency.mount === MOUNTED_TRANSITIVELY) { reverseUnmount.push(dependency); } } for (let x = reverseUnmount.length - 1; x >= 0; --x) { this.unmountInstance(reverseUnmount[x]); } } } invalidateInstance(instance) { this.#markInstanceAsOutdated(instance); } // TODO: we really need an explicit way to manage atom instance lifecycle // destroyInstance<T extends AnyAtom>(instance: AtomInstance<T>): void { // ... // } flush() { if (this.#flushTimeout) { clearTimeout(this.#flushTimeout); this.#flushTimeout = null; } for (const pendingInstance of this.#computationQueue) { this.#runInstanceComputation(pendingInstance); } for (const pendingInstance of this.#computationEffectQueue) { this.#runInstanceComputationEffects(pendingInstance); } for (const pendingInstance of this.#mountEffectQueue) { this.#runInstanceMountEffects(pendingInstance); } for (const pendingWatcher of this.#watcherDispatchQueue) { this.#watcherDispatchQueue.delete(pendingWatcher); if (pendingWatcher[METADATA]) { runWithCallbackContext({ supervisor: this }, pendingWatcher[METADATA].listener); } } if (this.#flushTimeout) { this.flush(); } } requestAsyncFlush() { if (this.#flushTimeout === null) { this.#flushTimeout = setTimeout(this.flush.bind(this), 0); } } #runInstanceComputation(instance) { instance.computation?.abortController.abort(); this.#computationQueue.delete(instance); const prevComputation = instance.computation; const newComputation = createComputation(); let instanceValueChanged = false; instance.status = COMPUTING; instance.freshness = FRESH; instance.computation = newComputation; runComputation(this, instance, instance.computation); if (!newComputation.promise) { this.#commitComputation(instance); const hasNewValue = !prevComputation || newComputation.result !== NO_VALUE && !compareEqual(newComputation.result, prevComputation.result) || newComputation.error !== NO_VALUE && !compareEqual(newComputation.error, prevComputation.error); if (newComputation.mode === FUNCTIONAL_ATOM) { delete instance.promise; instanceValueChanged = hasNewValue; } else if (newComputation.mode === GENERATIVE_ATOM && (hasNewValue || !instance.promise)) { const prevPromise = instance.promise; if (newComputation.result !== NO_VALUE) { instance.promise = swapOrRecreatePromise(instance.promise, Promise.resolve(newComputation.result)); trackResolvedPromise(instance.promise, newComputation.result); } else { instance.promise = swapOrRecreatePromise(instance.promise, Promise.reject(newComputation.error)); trackRejectedPromise(instance.promise, newComputation.error); } instanceValueChanged = instance.promise !== prevPromise; } } else { const committedPromise = newComputation.promise.then( () => { if (!newComputation.abortController.signal.aborted) { this.#commitComputation(instance); } if (newComputation.error !== NO_VALUE) { throw newComputation.error; } return newComputation.result; }, /* istanbul ignore next -- @preserve */ (err) => { newComputation.error = err; if (!newComputation.abortController.signal.aborted) { this.#commitComputation(instance); } throw err; } ); const prevPromise = instance.promise; instance.promise = swapOrRecreatePromise(instance.promise, committedPromise); instanceValueChanged = instance.promise !== prevPromise; trackPromise(instance.promise); } if (instanceValueChanged) { for (const dependant of instance.dependants) { if (dependant.status === COMPUTING && !dependant.computation.dependencies.has(instance)) { continue; } this.#markInstanceAsOutdated(dependant); } } if (instanceValueChanged && instance.watchers.size > 0) { for (const watcher of instance.watchers) { this.#watcherDispatchQueue.add(watcher); } this.requestAsyncFlush(); } } #runInstanceActions(instance, ...args) { for (const action of instance.stackAction) { runWithCallbackContext({ supervisor: this }, () => { action.handler.call(void 0, ...args); }); } } #runInstanceComputationEffects(instance) { this.#computationEffectQueue.delete(instance); for (let x = instance.stackComputationEffect.length - 1; x >= 0; --x) { const computationEffect = instance.stackComputationEffect[x]; if (computationEffect.setup && computationEffect.cleanup) { runWithCallbackContext({ supervisor: this }, computationEffect.cleanup); this.#computationEffectCleanupRegistry.unregister(computationEffect.cleanup[METADATA].token); computationEffect.cleanup = void 0; } } for (const computationEffect of instance.stackComputationEffect) { if (!computationEffect.setup) continue; assert(!computationEffect.cleanup); let effectResult; runWithCallbackContext({ supervisor: this }, () => { effectResult = computationEffect.setup.call(void 0); }); computationEffect.setup = void 0; if (effectResult !== void 0) { if (typeof effectResult !== "function") { throw new InvalidCleanupFunctionAtomError(); } computationEffect.cleanup = function() { effectResult(); }; computationEffect.cleanup[METADATA] = { token: {} // guaranteed to be unique }; this.#computationEffectCleanupRegistry.register( instance, // tracked ref computationEffect.cleanup, // held value computationEffect.cleanup[METADATA].token // unregister token ); } } } #runInstanceMountEffects(instance) { this.#mountEffectQueue.delete(instance); const isMounted = instance.mount !== UNMOUNTED; for (let x = instance.stackMountEffect.length - 1; x >= 0; --x) { const mountEffect = instance.stackMountEffect[x]; if (mountEffect.cleanup && (!isMounted || isMounted && mountEffect.status === UNLOADED)) { runWithCallbackContext({ supervisor: this }, mountEffect.cleanup); mountEffect.status = UNLOADED; mountEffect.cleanup = void 0; } } for (const mountEffect of instance.stackMountEffect) { if (isMounted && mountEffect.status === UNLOADED) { assert(!mountEffect.cleanup); let effectResult; runWithCallbackContext({ supervisor: this }, () => { effectResult = mountEffect.setup.call(void 0); }); mountEffect.status = LOADED; if (effectResult !== void 0) { if (typeof effectResult !== "function") { throw new InvalidCleanupFunctionAtomError(); } mountEffect.cleanup = effectResult; } } } } #markInstanceAsOutdated(instance) { if (instance.status === OUTDATED) { return; } const immediateComputation = instance.status === COMPUTING || instance.mount === MOUNTED_DIRECTLY || instance.mount === MOUNTED_TRANSITIVELY; instance.status = OUTDATED; instance.freshness = FRESH; instance.computation?.abortController.abort(); if (instance.promise) { unbindSwappablePromiseIfPending(instance.promise); } if (immediateComputation) { this.#computationQueue.add(instance); this.requestAsyncFlush(); } for (const dependant of instance.dependants) { this.#markInstanceAsStale(dependant); } } #markInstanceAsStale(instance) { if (instance.status === OUTDATED || instance.freshness === STALE) { return; } instance.freshness = STALE; for (const dependant of instance.dependants) { this.#markInstanceAsStale(dependant); } } #commitComputation(instance) { instance.status = COMPUTED; const computation = instance.computation; if (computation.error !== NO_VALUE) { computation.abortController.abort(); } const computationDeps = computation.dependencies; for (const dependency of instance.dependencies) { if (computationDeps.has(dependency)) continue; instance.dependencies.delete(dependency); dependency.dependants.delete(instance); if (dependency.mount === MOUNTED_TRANSITIVELY && instance.mount === UNMOUNTED) { this.unmountInstance(dependency); } } computation.dependencies.clear(); if (computation.result !== NO_VALUE) { instance.freezeStack = true; } if (computation.pointer < instance.stack.length) { if (computation.error === NO_VALUE) { computation.result = NO_VALUE; computation.error = new HookCountMismatchAtomError(); } for (let ptr = computation.pointer; ptr < instance.stack.length; ++ptr) { instance.stack[ptr].hook.onSkip?.(instance.stack[ptr]); } } if (instance.stackComputationEffect.some((frame) => !!frame.setup)) { this.#computationEffectQueue.add(instance); } if (instance.mount !== UNMOUNTED) { if (instance.stackMountEffect.some((frame) => frame.status === UNLOADED)) { this.#mountEffectQueue.add(instance); } } } }; // src/space/store.ts var Store = class { #supervisor; constructor(supervisor) { this.#supervisor = supervisor; this.read = this.read.bind(this); this.watch = this.watch.bind(this); this.dispatch = this.dispatch.bind(this); this.invalidate = this.invalidate.bind(this); } read(atom, ...args) { const instance = this.#supervisor.getOrCreateInstance(atom, ...args); return this.#supervisor.readInstance(instance); } watch(atom, ...args) { const instance = this.#supervisor.getOrCreateInstance( atom, ...args.slice(0, -1) ); const watcher = this.#supervisor.watchInstance(instance, args[args.length - 1]); this.#supervisor.flush(); return watcher; } dispatch(atom, ...args) { return (...actionArgs) => { const instance = this.#supervisor.getOrCreateInstance(atom, ...args); this.#supervisor.dispatchInstance(instance, ...actionArgs); this.#supervisor.flush(); }; } invalidate(atom, ...args) { const instance = this.#supervisor.getInstance(atom, ...args); if (instance) { this.#supervisor.invalidateInstance(instance); this.#supervisor.flush(); } } }; // src/api/store.ts var defaultStore = null; function getDefaultStore() { if (defaultStore === null) { const supervisor = new Supervisor(); defaultStore = supervisor.store; } return defaultStore; } function createStore() { const supervisor = new Supervisor(); return supervisor.store; } // src/hook/read.ts function _read(atom, ...args) { const context = requireComputationContext(); const targetInstance = context.supervisor.getOrCreateInstance(atom, ...args); if (!context.computation.abortController.signal.aborted) { context.instance.dependencies.add(targetInstance); targetInstance.dependants.add(context.instance); if (context.instance.mount !== UNMOUNTED && targetInstance.mount === UNMOUNTED) { context.supervisor.mountInstance(targetInstance, MOUNTED_TRANSITIVELY); } } context.supervisor.syncInstance(targetInstance); context.computation.dependencies.add(targetInstance); return context.supervisor.readInstance(targetInstance); } // src/api/read.ts function read(atom, ...args) { if (getComputationContext() !== null) { return _read(atom, ...args); } else if (getCallbackContext() !== null) { const { supervisor } = getCallbackContext(); return supervisor.store.read(atom, ...args); } else { return getDefaultStore().read(atom, ...args); } } // src/api/watch.ts function watch(atom, ...args) { if (getComputationContext() !== null) { throw new IllegalOperationAtomError(); } else if (getCallbackContext() !== null) { const { supervisor } = getCallbackContext(); return supervisor.store.watch(atom, ...args); } else { return getDefaultStore().watch(atom, ...args); } } // src/api/dispatch.ts function dispatch(atom, ...args) { if (getComputationContext() !== null) { throw new IllegalOperationAtomError(); } else if (getCallbackContext() !== null) { const { supervisor } = getCallbackContext(); return supervisor.store.dispatch(atom, ...args); } else { return getDefaultStore().dispatch(atom, ...args); } } // src/api/invalidate.ts function invalidate(atom, ...args) { if (getComputationContext() !== null) { throw new IllegalOperationAtomError(); } else if (getCallbackContext() !== null) { const { supervisor } = getCallbackContext(); supervisor.store.invalidate(atom, ...args); } else { getDefaultStore().invalidate(atom, ...args); } } // src/hook/atom-computation-effect.ts function atomComputationEffect(setup, dependencies) { const frame = requireComputationContextStackFrame(atomComputationEffect, (context) => { const frame2 = { hook: atomComputationEffect, setup, dependencies }; context.instance.stackComputationEffect.push(frame2); return frame2; }); if (!dependencies || !frame.dependencies || !compareDepsEqual(frame.dependencies, dependencies)) { frame.setup = setup; frame.dependencies = dependencies; } } atomComputationEffect.onSkip = (frame) => { frame.setup = () => { }; frame.dependencies = [{}]; }; // src/hook/atom-memo.ts function atomMemo(calculateValue, dependencies) { const frame = requireComputationContextStackFrame(atomMemo, () => ({ hook: atomMemo, status: PENDING, dependencies })); if (frame.status === PENDING || !compareDepsEqual(frame.dependencies, dependencies)) { frame.dependencies = dependencies; try { runWithoutComputationContext(() => { frame.value = calculateValue(); }); frame.status = RESOLVED; delete frame.error; } catch (err) { frame.error = err; frame.status = REJECTED; delete frame.value; } } if (frame.status === RESOLVED) { return frame.value; } else { throw frame.error; } } // src/hook/atom-reducer.ts function atomReducer(reducer, initialArg, init) { const { supervisor, instance } = requireComputationContext(); const frame = requireComputationContextStackFrame(atomReducer, () => { let value; if (init) { runWithoutComputationContext(() => { value = init(initialArg); }); } else { value = initialArg; } const dispatcher = (...args) => { const next = reducer(frame.data[0], ...args); if (compareEqual(frame.data[0], next)) return; frame.data = [next, frame.data[1]]; supervisor.invalidateInstance(instance); }; return { hook: atomReducer, data: [value, dispatcher] }; }); return frame.data; } // src/api/deasync.ts function deasync(input) { if (isPromiseLike(input)) { return deasyncPromise(input); } else if (isAnyAtom(input)) { return deasyncAtom(input); } else { return deasyncRaw(input); } } function deasyncRaw(value) { return { status: "resolved", result: value }; } function deasyncPromise(promise) { trackPromise(promise); const state = getPromiseState(promise); if (state.status === PENDING) { return { status: "pending" }; } else if (state.status === RESOLVED) { return { status: "resolved", result: state.result }; } else { return { status: "rejected", error: state.error }; } } var stableDeasyncAtom = /* @__PURE__ */ new WeakMap(); function deasyncAtom(atom) { let derivedAtom = stableDeasyncAtom.get(atom); if (!derivedAtom) { derivedAtom = (...args) => { return deasyncAtomImplementation(read(atom, ...args)); }; stableDeasyncAtom.set(atom, derivedAtom); } return derivedAtom; } function deasyncAtomImplementation(result) { const unpacked = isPromiseLike(result) ? deasyncPromise(result) : deasyncRaw(result); const [_tick, refresh] = atomReducer((x) => x + 1, 0); atomComputationEffect( () => { if (unpacked.status === "pending" && isPromiseLike(result)) { result.then(refresh, refresh); } }, [unpacked.status, result] ); return atomMemo( () => unpacked, [unpacked.status, unpacked.result, unpacked.error] ); } // src/hook/atom-abort-signal.ts function atomAbortSignal() { const { computation } = requireComputationContext(); requireComputationContextStackFrame( atomAbortSignal, () => ({ hook: atomAbortSignal }) ); return computation.abortController.signal; } // src/hook/atom-action.ts function atomAction(handler, dependencies) { const frame = requireComputationContextStackFrame(atomAction, (context) => { const frame2 = { hook: atomAction, handler, dependencies }; context.instance.stackAction.push(frame2); return frame2; }); if (!compareDepsEqual(frame.dependencies, dependencies)) { frame.handler = handler; frame.dependencies = dependencies; } } atomAction.onSkip = (frame) => { frame.handler = () => { }; frame.dependencies = [{}]; }; // src/hook/atom-mount-effect.ts function atomMountEffect(setup, dependencies) { const frame = requireComputationContextStackFrame(atomMountEffect, (context) => { const frame2 = { hook: atomMountEffect, status: UNLOADED, setup, dependencies }; context.instance.stackMountEffect.push(frame2); return frame2; }); if (!compareDepsEqual(frame.dependencies, dependencies)) { frame.status = UNLOADED; frame.setup = setup; frame.dependencies = dependencies; } } atomMountEffect.onSkip = (frame) => { frame.status = UNLOADED; frame.setup = () => { }; frame.dependencies = [{}]; }; // src/hook/atom-ref.ts function atomRef(initialValue) { const frame = requireComputationContextStackFrame(atomRef, () => ({ hook: atomRef, data: { current: initialValue } })); return frame.data; } // src/hook/atom-state.ts function atomState(initialState) { const { supervisor, instance } = requireComputationContext(); const frame = requireComputationContextStackFrame(atomState, () => { let value; if (initialState instanceof Function) { runWithoutComputationContext(() => { value = initialState(); }); } else { value = initialState; } const setter = (nextState) => { const next = nextState instanceof Function ? nextState(frame.data[0]) : nextState; if (compareEqual(frame.data[0], next)) return; frame.data = [next, frame.data[1]]; supervisor.invalidateInstance(instance); }; return { hook: atomState, data: [value, setter] }; }); return frame.data; } // src/hook/atom-store.ts function atomStore() { requireComputationContextStackFrame( atomStore, () => ({ hook: atomStore }) ); return requireComputationContext().supervisor.store; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { atomAbortSignal, atomAction, atomComputationEffect, atomMemo, atomMountEffect, atomReducer, atomRef, atomState, atomStore, createStore, deasync, dispatch, getDefaultStore, invalidate, read, watch }); /* istanbul ignore if -- @preserve */