untracked.mjs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /**
  2. * @license Angular v20.1.0
  3. * (c) 2010-2025 Google LLC. https://angular.io/
  4. * License: MIT
  5. */
  6. import { SIGNAL, runPostProducerCreatedFn, producerUpdateValueVersion, signalSetFn, producerMarkClean, signalUpdateFn, REACTIVE_NODE, UNSET, defaultEquals, COMPUTING, consumerBeforeComputation, ERRORED, consumerAfterComputation, producerAccessed, setActiveConsumer } from './signal.mjs';
  7. function createLinkedSignal(sourceFn, computationFn, equalityFn) {
  8. const node = Object.create(LINKED_SIGNAL_NODE);
  9. node.source = sourceFn;
  10. node.computation = computationFn;
  11. if (equalityFn != undefined) {
  12. node.equal = equalityFn;
  13. }
  14. const linkedSignalGetter = () => {
  15. // Check if the value needs updating before returning it.
  16. producerUpdateValueVersion(node);
  17. // Record that someone looked at this signal.
  18. producerAccessed(node);
  19. if (node.value === ERRORED) {
  20. throw node.error;
  21. }
  22. return node.value;
  23. };
  24. const getter = linkedSignalGetter;
  25. getter[SIGNAL] = node;
  26. if (typeof ngDevMode !== 'undefined' && ngDevMode) {
  27. const debugName = node.debugName ? ' (' + node.debugName + ')' : '';
  28. getter.toString = () => `[LinkedSignal${debugName}: ${node.value}]`;
  29. }
  30. runPostProducerCreatedFn(node);
  31. return getter;
  32. }
  33. function linkedSignalSetFn(node, newValue) {
  34. producerUpdateValueVersion(node);
  35. signalSetFn(node, newValue);
  36. producerMarkClean(node);
  37. }
  38. function linkedSignalUpdateFn(node, updater) {
  39. producerUpdateValueVersion(node);
  40. signalUpdateFn(node, updater);
  41. producerMarkClean(node);
  42. }
  43. // Note: Using an IIFE here to ensure that the spread assignment is not considered
  44. // a side-effect, ending up preserving `LINKED_SIGNAL_NODE` and `REACTIVE_NODE`.
  45. // TODO: remove when https://github.com/evanw/esbuild/issues/3392 is resolved.
  46. const LINKED_SIGNAL_NODE = /* @__PURE__ */ (() => {
  47. return {
  48. ...REACTIVE_NODE,
  49. value: UNSET,
  50. dirty: true,
  51. error: null,
  52. equal: defaultEquals,
  53. kind: 'linkedSignal',
  54. producerMustRecompute(node) {
  55. // Force a recomputation if there's no current value, or if the current value is in the
  56. // process of being calculated (which should throw an error).
  57. return node.value === UNSET || node.value === COMPUTING;
  58. },
  59. producerRecomputeValue(node) {
  60. if (node.value === COMPUTING) {
  61. // Our computation somehow led to a cyclic read of itself.
  62. throw new Error(typeof ngDevMode !== 'undefined' && ngDevMode ? 'Detected cycle in computations.' : '');
  63. }
  64. const oldValue = node.value;
  65. node.value = COMPUTING;
  66. const prevConsumer = consumerBeforeComputation(node);
  67. let newValue;
  68. try {
  69. const newSourceValue = node.source();
  70. const prev = oldValue === UNSET || oldValue === ERRORED
  71. ? undefined
  72. : {
  73. source: node.sourceValue,
  74. value: oldValue,
  75. };
  76. newValue = node.computation(newSourceValue, prev);
  77. node.sourceValue = newSourceValue;
  78. }
  79. catch (err) {
  80. newValue = ERRORED;
  81. node.error = err;
  82. }
  83. finally {
  84. consumerAfterComputation(node, prevConsumer);
  85. }
  86. if (oldValue !== UNSET && newValue !== ERRORED && node.equal(oldValue, newValue)) {
  87. // No change to `valueVersion` - old and new values are
  88. // semantically equivalent.
  89. node.value = oldValue;
  90. return;
  91. }
  92. node.value = newValue;
  93. node.version++;
  94. },
  95. };
  96. })();
  97. /**
  98. * Execute an arbitrary function in a non-reactive (non-tracking) context. The executed function
  99. * can, optionally, return a value.
  100. */
  101. function untracked(nonReactiveReadsFn) {
  102. const prevConsumer = setActiveConsumer(null);
  103. // We are not trying to catch any particular errors here, just making sure that the consumers
  104. // stack is restored in case of errors.
  105. try {
  106. return nonReactiveReadsFn();
  107. }
  108. finally {
  109. setActiveConsumer(prevConsumer);
  110. }
  111. }
  112. export { createLinkedSignal, linkedSignalSetFn, linkedSignalUpdateFn, untracked };
  113. //# sourceMappingURL=untracked.mjs.map