123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- /**
- * @license Angular v19.2.13
- * (c) 2010-2025 Google LLC. https://angular.io/
- * License: MIT
- */
- /**
- * The default equality function used for `signal` and `computed`, which uses referential equality.
- */
- function defaultEquals(a, b) {
- return Object.is(a, b);
- }
- /**
- * The currently active consumer `ReactiveNode`, if running code in a reactive context.
- *
- * Change this via `setActiveConsumer`.
- */
- let activeConsumer = null;
- let inNotificationPhase = false;
- /**
- * Global epoch counter. Incremented whenever a source signal is set.
- */
- let epoch = 1;
- /**
- * Symbol used to tell `Signal`s apart from other functions.
- *
- * This can be used to auto-unwrap signals in various cases, or to auto-wrap non-signal values.
- */
- const SIGNAL = /* @__PURE__ */ Symbol('SIGNAL');
- function setActiveConsumer(consumer) {
- const prev = activeConsumer;
- activeConsumer = consumer;
- return prev;
- }
- function getActiveConsumer() {
- return activeConsumer;
- }
- function isInNotificationPhase() {
- return inNotificationPhase;
- }
- function isReactive(value) {
- return value[SIGNAL] !== undefined;
- }
- const REACTIVE_NODE = {
- version: 0,
- lastCleanEpoch: 0,
- dirty: false,
- producerNode: undefined,
- producerLastReadVersion: undefined,
- producerIndexOfThis: undefined,
- nextProducerIndex: 0,
- liveConsumerNode: undefined,
- liveConsumerIndexOfThis: undefined,
- consumerAllowSignalWrites: false,
- consumerIsAlwaysLive: false,
- kind: 'unknown',
- producerMustRecompute: () => false,
- producerRecomputeValue: () => { },
- consumerMarkedDirty: () => { },
- consumerOnSignalRead: () => { },
- };
- /**
- * Called by implementations when a producer's signal is read.
- */
- function producerAccessed(node) {
- if (inNotificationPhase) {
- throw new Error(typeof ngDevMode !== 'undefined' && ngDevMode
- ? `Assertion error: signal read during notification phase`
- : '');
- }
- if (activeConsumer === null) {
- // Accessed outside of a reactive context, so nothing to record.
- return;
- }
- activeConsumer.consumerOnSignalRead(node);
- // This producer is the `idx`th dependency of `activeConsumer`.
- const idx = activeConsumer.nextProducerIndex++;
- assertConsumerNode(activeConsumer);
- if (idx < activeConsumer.producerNode.length && activeConsumer.producerNode[idx] !== node) {
- // There's been a change in producers since the last execution of `activeConsumer`.
- // `activeConsumer.producerNode[idx]` holds a stale dependency which will be be removed and
- // replaced with `this`.
- //
- // If `activeConsumer` isn't live, then this is a no-op, since we can replace the producer in
- // `activeConsumer.producerNode` directly. However, if `activeConsumer` is live, then we need
- // to remove it from the stale producer's `liveConsumer`s.
- if (consumerIsLive(activeConsumer)) {
- const staleProducer = activeConsumer.producerNode[idx];
- producerRemoveLiveConsumerAtIndex(staleProducer, activeConsumer.producerIndexOfThis[idx]);
- // At this point, the only record of `staleProducer` is the reference at
- // `activeConsumer.producerNode[idx]` which will be overwritten below.
- }
- }
- if (activeConsumer.producerNode[idx] !== node) {
- // We're a new dependency of the consumer (at `idx`).
- activeConsumer.producerNode[idx] = node;
- // If the active consumer is live, then add it as a live consumer. If not, then use 0 as a
- // placeholder value.
- activeConsumer.producerIndexOfThis[idx] = consumerIsLive(activeConsumer)
- ? producerAddLiveConsumer(node, activeConsumer, idx)
- : 0;
- }
- activeConsumer.producerLastReadVersion[idx] = node.version;
- }
- /**
- * Increment the global epoch counter.
- *
- * Called by source producers (that is, not computeds) whenever their values change.
- */
- function producerIncrementEpoch() {
- epoch++;
- }
- /**
- * Ensure this producer's `version` is up-to-date.
- */
- function producerUpdateValueVersion(node) {
- if (consumerIsLive(node) && !node.dirty) {
- // A live consumer will be marked dirty by producers, so a clean state means that its version
- // is guaranteed to be up-to-date.
- return;
- }
- if (!node.dirty && node.lastCleanEpoch === epoch) {
- // Even non-live consumers can skip polling if they previously found themselves to be clean at
- // the current epoch, since their dependencies could not possibly have changed (such a change
- // would've increased the epoch).
- return;
- }
- if (!node.producerMustRecompute(node) && !consumerPollProducersForChange(node)) {
- // None of our producers report a change since the last time they were read, so no
- // recomputation of our value is necessary, and we can consider ourselves clean.
- producerMarkClean(node);
- return;
- }
- node.producerRecomputeValue(node);
- // After recomputing the value, we're no longer dirty.
- producerMarkClean(node);
- }
- /**
- * Propagate a dirty notification to live consumers of this producer.
- */
- function producerNotifyConsumers(node) {
- if (node.liveConsumerNode === undefined) {
- return;
- }
- // Prevent signal reads when we're updating the graph
- const prev = inNotificationPhase;
- inNotificationPhase = true;
- try {
- for (const consumer of node.liveConsumerNode) {
- if (!consumer.dirty) {
- consumerMarkDirty(consumer);
- }
- }
- }
- finally {
- inNotificationPhase = prev;
- }
- }
- /**
- * Whether this `ReactiveNode` in its producer capacity is currently allowed to initiate updates,
- * based on the current consumer context.
- */
- function producerUpdatesAllowed() {
- return activeConsumer?.consumerAllowSignalWrites !== false;
- }
- function consumerMarkDirty(node) {
- node.dirty = true;
- producerNotifyConsumers(node);
- node.consumerMarkedDirty?.(node);
- }
- function producerMarkClean(node) {
- node.dirty = false;
- node.lastCleanEpoch = epoch;
- }
- /**
- * Prepare this consumer to run a computation in its reactive context.
- *
- * Must be called by subclasses which represent reactive computations, before those computations
- * begin.
- */
- function consumerBeforeComputation(node) {
- node && (node.nextProducerIndex = 0);
- return setActiveConsumer(node);
- }
- /**
- * Finalize this consumer's state after a reactive computation has run.
- *
- * Must be called by subclasses which represent reactive computations, after those computations
- * have finished.
- */
- function consumerAfterComputation(node, prevConsumer) {
- setActiveConsumer(prevConsumer);
- if (!node ||
- node.producerNode === undefined ||
- node.producerIndexOfThis === undefined ||
- node.producerLastReadVersion === undefined) {
- return;
- }
- if (consumerIsLive(node)) {
- // For live consumers, we need to remove the producer -> consumer edge for any stale producers
- // which weren't dependencies after the recomputation.
- for (let i = node.nextProducerIndex; i < node.producerNode.length; i++) {
- producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
- }
- }
- // Truncate the producer tracking arrays.
- // Perf note: this is essentially truncating the length to `node.nextProducerIndex`, but
- // benchmarking has shown that individual pop operations are faster.
- while (node.producerNode.length > node.nextProducerIndex) {
- node.producerNode.pop();
- node.producerLastReadVersion.pop();
- node.producerIndexOfThis.pop();
- }
- }
- /**
- * Determine whether this consumer has any dependencies which have changed since the last time
- * they were read.
- */
- function consumerPollProducersForChange(node) {
- assertConsumerNode(node);
- // Poll producers for change.
- for (let i = 0; i < node.producerNode.length; i++) {
- const producer = node.producerNode[i];
- const seenVersion = node.producerLastReadVersion[i];
- // First check the versions. A mismatch means that the producer's value is known to have
- // changed since the last time we read it.
- if (seenVersion !== producer.version) {
- return true;
- }
- // The producer's version is the same as the last time we read it, but it might itself be
- // stale. Force the producer to recompute its version (calculating a new value if necessary).
- producerUpdateValueVersion(producer);
- // Now when we do this check, `producer.version` is guaranteed to be up to date, so if the
- // versions still match then it has not changed since the last time we read it.
- if (seenVersion !== producer.version) {
- return true;
- }
- }
- return false;
- }
- /**
- * Disconnect this consumer from the graph.
- */
- function consumerDestroy(node) {
- assertConsumerNode(node);
- if (consumerIsLive(node)) {
- // Drop all connections from the graph to this node.
- for (let i = 0; i < node.producerNode.length; i++) {
- producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
- }
- }
- // Truncate all the arrays to drop all connection from this node to the graph.
- node.producerNode.length =
- node.producerLastReadVersion.length =
- node.producerIndexOfThis.length =
- 0;
- if (node.liveConsumerNode) {
- node.liveConsumerNode.length = node.liveConsumerIndexOfThis.length = 0;
- }
- }
- /**
- * Add `consumer` as a live consumer of this node.
- *
- * Note that this operation is potentially transitive. If this node becomes live, then it becomes
- * a live consumer of all of its current producers.
- */
- function producerAddLiveConsumer(node, consumer, indexOfThis) {
- assertProducerNode(node);
- if (node.liveConsumerNode.length === 0 && isConsumerNode(node)) {
- // When going from 0 to 1 live consumers, we become a live consumer to our producers.
- for (let i = 0; i < node.producerNode.length; i++) {
- node.producerIndexOfThis[i] = producerAddLiveConsumer(node.producerNode[i], node, i);
- }
- }
- node.liveConsumerIndexOfThis.push(indexOfThis);
- return node.liveConsumerNode.push(consumer) - 1;
- }
- /**
- * Remove the live consumer at `idx`.
- */
- function producerRemoveLiveConsumerAtIndex(node, idx) {
- assertProducerNode(node);
- if (typeof ngDevMode !== 'undefined' && ngDevMode && idx >= node.liveConsumerNode.length) {
- throw new Error(`Assertion error: active consumer index ${idx} is out of bounds of ${node.liveConsumerNode.length} consumers)`);
- }
- if (node.liveConsumerNode.length === 1 && isConsumerNode(node)) {
- // When removing the last live consumer, we will no longer be live. We need to remove
- // ourselves from our producers' tracking (which may cause consumer-producers to lose
- // liveness as well).
- for (let i = 0; i < node.producerNode.length; i++) {
- producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
- }
- }
- // Move the last value of `liveConsumers` into `idx`. Note that if there's only a single
- // live consumer, this is a no-op.
- const lastIdx = node.liveConsumerNode.length - 1;
- node.liveConsumerNode[idx] = node.liveConsumerNode[lastIdx];
- node.liveConsumerIndexOfThis[idx] = node.liveConsumerIndexOfThis[lastIdx];
- // Truncate the array.
- node.liveConsumerNode.length--;
- node.liveConsumerIndexOfThis.length--;
- // If the index is still valid, then we need to fix the index pointer from the producer to this
- // consumer, and update it from `lastIdx` to `idx` (accounting for the move above).
- if (idx < node.liveConsumerNode.length) {
- const idxProducer = node.liveConsumerIndexOfThis[idx];
- const consumer = node.liveConsumerNode[idx];
- assertConsumerNode(consumer);
- consumer.producerIndexOfThis[idxProducer] = idx;
- }
- }
- function consumerIsLive(node) {
- return node.consumerIsAlwaysLive || (node?.liveConsumerNode?.length ?? 0) > 0;
- }
- function assertConsumerNode(node) {
- node.producerNode ??= [];
- node.producerIndexOfThis ??= [];
- node.producerLastReadVersion ??= [];
- }
- function assertProducerNode(node) {
- node.liveConsumerNode ??= [];
- node.liveConsumerIndexOfThis ??= [];
- }
- function isConsumerNode(node) {
- return node.producerNode !== undefined;
- }
- /**
- * Create a computed signal which derives a reactive value from an expression.
- */
- function createComputed(computation, equal) {
- const node = Object.create(COMPUTED_NODE);
- node.computation = computation;
- if (equal !== undefined) {
- node.equal = equal;
- }
- const computed = () => {
- // Check if the value needs updating before returning it.
- producerUpdateValueVersion(node);
- // Record that someone looked at this signal.
- producerAccessed(node);
- if (node.value === ERRORED) {
- throw node.error;
- }
- return node.value;
- };
- computed[SIGNAL] = node;
- return computed;
- }
- /**
- * A dedicated symbol used before a computed value has been calculated for the first time.
- * Explicitly typed as `any` so we can use it as signal's value.
- */
- const UNSET = /* @__PURE__ */ Symbol('UNSET');
- /**
- * A dedicated symbol used in place of a computed signal value to indicate that a given computation
- * is in progress. Used to detect cycles in computation chains.
- * Explicitly typed as `any` so we can use it as signal's value.
- */
- const COMPUTING = /* @__PURE__ */ Symbol('COMPUTING');
- /**
- * A dedicated symbol used in place of a computed signal value to indicate that a given computation
- * failed. The thrown error is cached until the computation gets dirty again.
- * Explicitly typed as `any` so we can use it as signal's value.
- */
- const ERRORED = /* @__PURE__ */ Symbol('ERRORED');
- // Note: Using an IIFE here to ensure that the spread assignment is not considered
- // a side-effect, ending up preserving `COMPUTED_NODE` and `REACTIVE_NODE`.
- // TODO: remove when https://github.com/evanw/esbuild/issues/3392 is resolved.
- const COMPUTED_NODE = /* @__PURE__ */ (() => {
- return {
- ...REACTIVE_NODE,
- value: UNSET,
- dirty: true,
- error: null,
- equal: defaultEquals,
- kind: 'computed',
- producerMustRecompute(node) {
- // Force a recomputation if there's no current value, or if the current value is in the
- // process of being calculated (which should throw an error).
- return node.value === UNSET || node.value === COMPUTING;
- },
- producerRecomputeValue(node) {
- if (node.value === COMPUTING) {
- // Our computation somehow led to a cyclic read of itself.
- throw new Error('Detected cycle in computations.');
- }
- const oldValue = node.value;
- node.value = COMPUTING;
- const prevConsumer = consumerBeforeComputation(node);
- let newValue;
- let wasEqual = false;
- try {
- newValue = node.computation();
- // We want to mark this node as errored if calling `equal` throws; however, we don't want
- // to track any reactive reads inside `equal`.
- setActiveConsumer(null);
- wasEqual =
- oldValue !== UNSET &&
- oldValue !== ERRORED &&
- newValue !== ERRORED &&
- node.equal(oldValue, newValue);
- }
- catch (err) {
- newValue = ERRORED;
- node.error = err;
- }
- finally {
- consumerAfterComputation(node, prevConsumer);
- }
- if (wasEqual) {
- // No change to `valueVersion` - old and new values are
- // semantically equivalent.
- node.value = oldValue;
- return;
- }
- node.value = newValue;
- node.version++;
- },
- };
- })();
- function defaultThrowError() {
- throw new Error();
- }
- let throwInvalidWriteToSignalErrorFn = defaultThrowError;
- function throwInvalidWriteToSignalError(node) {
- throwInvalidWriteToSignalErrorFn(node);
- }
- function setThrowInvalidWriteToSignalError(fn) {
- throwInvalidWriteToSignalErrorFn = fn;
- }
- /**
- * If set, called after `WritableSignal`s are updated.
- *
- * This hook can be used to achieve various effects, such as running effects synchronously as part
- * of setting a signal.
- */
- let postSignalSetFn = null;
- /**
- * Create a `Signal` that can be set or updated directly.
- */
- function createSignal(initialValue, equal) {
- const node = Object.create(SIGNAL_NODE);
- node.value = initialValue;
- if (equal !== undefined) {
- node.equal = equal;
- }
- const getter = (() => {
- producerAccessed(node);
- return node.value;
- });
- getter[SIGNAL] = node;
- return getter;
- }
- function setPostSignalSetFn(fn) {
- const prev = postSignalSetFn;
- postSignalSetFn = fn;
- return prev;
- }
- function signalSetFn(node, newValue) {
- if (!producerUpdatesAllowed()) {
- throwInvalidWriteToSignalError(node);
- }
- if (!node.equal(node.value, newValue)) {
- node.value = newValue;
- signalValueChanged(node);
- }
- }
- function signalUpdateFn(node, updater) {
- if (!producerUpdatesAllowed()) {
- throwInvalidWriteToSignalError(node);
- }
- signalSetFn(node, updater(node.value));
- }
- function runPostSignalSetFn() {
- postSignalSetFn?.();
- }
- // Note: Using an IIFE here to ensure that the spread assignment is not considered
- // a side-effect, ending up preserving `COMPUTED_NODE` and `REACTIVE_NODE`.
- // TODO: remove when https://github.com/evanw/esbuild/issues/3392 is resolved.
- const SIGNAL_NODE = /* @__PURE__ */ (() => {
- return {
- ...REACTIVE_NODE,
- equal: defaultEquals,
- value: undefined,
- kind: 'signal',
- };
- })();
- function signalValueChanged(node) {
- node.version++;
- producerIncrementEpoch();
- producerNotifyConsumers(node);
- postSignalSetFn?.();
- }
- function createLinkedSignal(sourceFn, computationFn, equalityFn) {
- const node = Object.create(LINKED_SIGNAL_NODE);
- node.source = sourceFn;
- node.computation = computationFn;
- if (equalityFn != undefined) {
- node.equal = equalityFn;
- }
- const linkedSignalGetter = () => {
- // Check if the value needs updating before returning it.
- producerUpdateValueVersion(node);
- // Record that someone looked at this signal.
- producerAccessed(node);
- if (node.value === ERRORED) {
- throw node.error;
- }
- return node.value;
- };
- const getter = linkedSignalGetter;
- getter[SIGNAL] = node;
- return getter;
- }
- function linkedSignalSetFn(node, newValue) {
- producerUpdateValueVersion(node);
- signalSetFn(node, newValue);
- producerMarkClean(node);
- }
- function linkedSignalUpdateFn(node, updater) {
- producerUpdateValueVersion(node);
- signalUpdateFn(node, updater);
- producerMarkClean(node);
- }
- // Note: Using an IIFE here to ensure that the spread assignment is not considered
- // a side-effect, ending up preserving `LINKED_SIGNAL_NODE` and `REACTIVE_NODE`.
- // TODO: remove when https://github.com/evanw/esbuild/issues/3392 is resolved.
- const LINKED_SIGNAL_NODE = /* @__PURE__ */ (() => {
- return {
- ...REACTIVE_NODE,
- value: UNSET,
- dirty: true,
- error: null,
- equal: defaultEquals,
- kind: 'linkedSignal',
- producerMustRecompute(node) {
- // Force a recomputation if there's no current value, or if the current value is in the
- // process of being calculated (which should throw an error).
- return node.value === UNSET || node.value === COMPUTING;
- },
- producerRecomputeValue(node) {
- if (node.value === COMPUTING) {
- // Our computation somehow led to a cyclic read of itself.
- throw new Error('Detected cycle in computations.');
- }
- const oldValue = node.value;
- node.value = COMPUTING;
- const prevConsumer = consumerBeforeComputation(node);
- let newValue;
- try {
- const newSourceValue = node.source();
- const prev = oldValue === UNSET || oldValue === ERRORED
- ? undefined
- : {
- source: node.sourceValue,
- value: oldValue,
- };
- newValue = node.computation(newSourceValue, prev);
- node.sourceValue = newSourceValue;
- }
- catch (err) {
- newValue = ERRORED;
- node.error = err;
- }
- finally {
- consumerAfterComputation(node, prevConsumer);
- }
- if (oldValue !== UNSET && newValue !== ERRORED && node.equal(oldValue, newValue)) {
- // No change to `valueVersion` - old and new values are
- // semantically equivalent.
- node.value = oldValue;
- return;
- }
- node.value = newValue;
- node.version++;
- },
- };
- })();
- function setAlternateWeakRefImpl(impl) {
- // TODO: remove this function
- }
- /**
- * Execute an arbitrary function in a non-reactive (non-tracking) context. The executed function
- * can, optionally, return a value.
- */
- function untracked(nonReactiveReadsFn) {
- const prevConsumer = setActiveConsumer(null);
- // We are not trying to catch any particular errors here, just making sure that the consumers
- // stack is restored in case of errors.
- try {
- return nonReactiveReadsFn();
- }
- finally {
- setActiveConsumer(prevConsumer);
- }
- }
- export { REACTIVE_NODE, SIGNAL, SIGNAL_NODE, consumerAfterComputation, consumerBeforeComputation, consumerDestroy, consumerMarkDirty, consumerPollProducersForChange, createComputed, createLinkedSignal, createSignal, defaultEquals, getActiveConsumer, isInNotificationPhase, isReactive, linkedSignalSetFn, linkedSignalUpdateFn, producerAccessed, producerIncrementEpoch, producerMarkClean, producerNotifyConsumers, producerUpdateValueVersion, producerUpdatesAllowed, runPostSignalSetFn, setActiveConsumer, setAlternateWeakRefImpl, setPostSignalSetFn, setThrowInvalidWriteToSignalError, signalSetFn, signalUpdateFn, untracked };
- //# sourceMappingURL=untracked-BKcld_ew.mjs.map
|