mutts 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1955,16 +1955,20 @@ function batch(effect, immediate) {
1955
1955
  addToBatch(effect[i], caller, immediate === 'immediate');
1956
1956
  }
1957
1957
  if (immediate) {
1958
+ const firstReturn = {};
1958
1959
  // Execute immediately (before batch returns)
1959
1960
  for (let i = 0; i < effect.length; i++) {
1960
1961
  try {
1961
- effect[i]();
1962
+ const rv = effect[i]();
1963
+ if (rv !== undefined && !('value' in firstReturn))
1964
+ firstReturn.value = rv;
1962
1965
  }
1963
1966
  finally {
1964
1967
  const root = getRoot(effect[i]);
1965
1968
  batchQueue.all.delete(root);
1966
1969
  }
1967
1970
  }
1971
+ return firstReturn.value;
1968
1972
  }
1969
1973
  // Otherwise, effects will be picked up in next executeNext() call
1970
1974
  }
@@ -2056,57 +2060,65 @@ function batch(effect, immediate) {
2056
2060
  // Execute in dependency order
2057
2061
  const firstReturn = {};
2058
2062
  try {
2059
- while (batchQueue.all.size > 0) {
2060
- if (effectuatedRoots.length > options.maxEffectChain) {
2061
- const cycle = findCycleInChain(effectuatedRoots);
2062
- const trace = formatRoots(effectuatedRoots);
2063
- const message = cycle
2064
- ? `Max effect chain reached (cycle detected: ${formatRoots(cycle)})`
2065
- : `Max effect chain reached (trace: ${trace})`;
2066
- const queuedRoots = batchQueue ? Array.from(batchQueue.all.keys()) : [];
2067
- const queued = queuedRoots.map((r) => r.name || '<anonymous>');
2068
- const debugInfo = {
2069
- code: ReactiveErrorCode.MaxDepthExceeded,
2070
- effectuatedRoots,
2071
- cycle,
2072
- trace,
2073
- maxEffectChain: options.maxEffectChain,
2074
- queued: queued.slice(0, 50),
2075
- queuedCount: queued.length,
2076
- // Try to get causation for the last effect
2077
- causalChain: effectuatedRoots.length > 0
2078
- ? getTriggerChain(batchQueue.all.get(effectuatedRoots[effectuatedRoots.length - 1]))
2079
- : [],
2080
- };
2081
- switch (options.maxEffectReaction) {
2082
- case 'throw':
2083
- throw new ReactiveError(`[reactive] ${message}`, debugInfo);
2084
- case 'debug':
2085
- // biome-ignore lint/suspicious/noDebugger: This is the whole point here
2086
- debugger;
2087
- throw new ReactiveError(`[reactive] ${message}`, debugInfo);
2088
- case 'warn':
2089
- options.warn(`[reactive] ${message} (queued: ${queued.slice(0, 10).join(', ')}${queued.length > 10 ? ', …' : ''})`);
2090
- break;
2063
+ // Outer loop: continue while there are effects OR cleanups pending.
2064
+ // This ensures effects triggered by cleanups are not lost.
2065
+ while (batchQueue.all.size > 0 || batchCleanups.size > 0) {
2066
+ // Inner loop: execute all pending effects
2067
+ while (batchQueue.all.size > 0) {
2068
+ if (effectuatedRoots.length > options.maxEffectChain) {
2069
+ const cycle = findCycleInChain(effectuatedRoots);
2070
+ const trace = formatRoots(effectuatedRoots);
2071
+ const message = cycle
2072
+ ? `Max effect chain reached (cycle detected: ${formatRoots(cycle)})`
2073
+ : `Max effect chain reached (trace: ${trace})`;
2074
+ const queuedRoots = batchQueue ? Array.from(batchQueue.all.keys()) : [];
2075
+ const queued = queuedRoots.map((r) => r.name || '<anonymous>');
2076
+ const debugInfo = {
2077
+ code: ReactiveErrorCode.MaxDepthExceeded,
2078
+ effectuatedRoots,
2079
+ cycle,
2080
+ trace,
2081
+ maxEffectChain: options.maxEffectChain,
2082
+ queued: queued.slice(0, 50),
2083
+ queuedCount: queued.length,
2084
+ // Try to get causation for the last effect
2085
+ causalChain: effectuatedRoots.length > 0
2086
+ ? getTriggerChain(batchQueue.all.get(effectuatedRoots[effectuatedRoots.length - 1]))
2087
+ : [],
2088
+ };
2089
+ switch (options.maxEffectReaction) {
2090
+ case 'throw':
2091
+ throw new ReactiveError(`[reactive] ${message}`, debugInfo);
2092
+ case 'debug':
2093
+ // biome-ignore lint/suspicious/noDebugger: This is the whole point here
2094
+ debugger;
2095
+ throw new ReactiveError(`[reactive] ${message}`, debugInfo);
2096
+ case 'warn':
2097
+ options.warn(`[reactive] ${message} (queued: ${queued.slice(0, 10).join(', ')}${queued.length > 10 ? ', …' : ''})`);
2098
+ break;
2099
+ }
2100
+ }
2101
+ const rv = executeNext(effectuatedRoots);
2102
+ // executeNext() returns null when batch is complete or cycle detected (throws error)
2103
+ // But functions can legitimately return null, so we check batchQueue.all.size instead
2104
+ if (batchQueue.all.size === 0) {
2105
+ // Batch complete
2106
+ break;
2091
2107
  }
2108
+ // If executeNext() returned null but batch is not empty, it means a cycle was detected
2109
+ // and an error was thrown, so we won't reach here
2110
+ if (rv !== undefined && !('value' in firstReturn))
2111
+ firstReturn.value = rv;
2112
+ // Note: executeNext() already removed it from batchQueue, so we track by count
2092
2113
  }
2093
- const rv = executeNext(effectuatedRoots);
2094
- // executeNext() returns null when batch is complete or cycle detected (throws error)
2095
- // But functions can legitimately return null, so we check batchQueue.all.size instead
2096
- if (batchQueue.all.size === 0) {
2097
- // Batch complete
2098
- break;
2114
+ // Process cleanups. If they trigger new effects, the outer loop will catch them.
2115
+ if (batchCleanups.size > 0) {
2116
+ const cleanups = Array.from(batchCleanups);
2117
+ batchCleanups.clear();
2118
+ for (const cleanup of cleanups)
2119
+ cleanup();
2099
2120
  }
2100
- // If executeNext() returned null but batch is not empty, it means a cycle was detected
2101
- // and an error was thrown, so we won't reach here
2102
- if (rv !== undefined && !('value' in firstReturn))
2103
- firstReturn.value = rv;
2104
- // Note: executeNext() already removed it from batchQueue, so we track by count
2105
2121
  }
2106
- const cleanups = Array.from(batchCleanups);
2107
- batchCleanups.clear();
2108
- for (const cleanup of cleanups)
2109
- cleanup();
2110
2122
  return firstReturn.value;
2111
2123
  }
2112
2124
  finally {
@@ -2866,7 +2878,11 @@ const reactiveHandlers = {
2866
2878
  dependant(current, prop);
2867
2879
  if (Object.hasOwn(current, prop))
2868
2880
  break;
2869
- current = reactiveObject(Object.getPrototypeOf(current));
2881
+ let next = reactiveObject(Object.getPrototypeOf(current));
2882
+ if (next === current) {
2883
+ next = reactiveObject(Object.getPrototypeOf(unwrap(current)));
2884
+ }
2885
+ current = next;
2870
2886
  }
2871
2887
  }
2872
2888
  const value = decorator.ReflectGet(obj, prop, receiver);
@@ -4847,6 +4863,7 @@ exports.ReadOnlyError = ReadOnlyError;
4847
4863
  exports.Register = Register;
4848
4864
  exports.addBatchCleanup = addBatchCleanup;
4849
4865
  exports.atomic = atomic;
4866
+ exports.batch = batch;
4850
4867
  exports.biDi = biDi;
4851
4868
  exports.buildReactivityGraph = buildReactivityGraph;
4852
4869
  exports.cleanedBy = cleanedBy;
@@ -4888,4 +4905,4 @@ exports.unreactive = unreactive;
4888
4905
  exports.untracked = untracked;
4889
4906
  exports.unwrap = unwrap;
4890
4907
  exports.watch = watch;
4891
- //# sourceMappingURL=index-HNVqPzjz.js.map
4908
+ //# sourceMappingURL=index-GRBSx0mB.js.map