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.
@@ -1953,16 +1953,20 @@ function batch(effect, immediate) {
1953
1953
  addToBatch(effect[i], caller, immediate === 'immediate');
1954
1954
  }
1955
1955
  if (immediate) {
1956
+ const firstReturn = {};
1956
1957
  // Execute immediately (before batch returns)
1957
1958
  for (let i = 0; i < effect.length; i++) {
1958
1959
  try {
1959
- effect[i]();
1960
+ const rv = effect[i]();
1961
+ if (rv !== undefined && !('value' in firstReturn))
1962
+ firstReturn.value = rv;
1960
1963
  }
1961
1964
  finally {
1962
1965
  const root = getRoot(effect[i]);
1963
1966
  batchQueue.all.delete(root);
1964
1967
  }
1965
1968
  }
1969
+ return firstReturn.value;
1966
1970
  }
1967
1971
  // Otherwise, effects will be picked up in next executeNext() call
1968
1972
  }
@@ -2054,57 +2058,65 @@ function batch(effect, immediate) {
2054
2058
  // Execute in dependency order
2055
2059
  const firstReturn = {};
2056
2060
  try {
2057
- while (batchQueue.all.size > 0) {
2058
- if (effectuatedRoots.length > options.maxEffectChain) {
2059
- const cycle = findCycleInChain(effectuatedRoots);
2060
- const trace = formatRoots(effectuatedRoots);
2061
- const message = cycle
2062
- ? `Max effect chain reached (cycle detected: ${formatRoots(cycle)})`
2063
- : `Max effect chain reached (trace: ${trace})`;
2064
- const queuedRoots = batchQueue ? Array.from(batchQueue.all.keys()) : [];
2065
- const queued = queuedRoots.map((r) => r.name || '<anonymous>');
2066
- const debugInfo = {
2067
- code: ReactiveErrorCode.MaxDepthExceeded,
2068
- effectuatedRoots,
2069
- cycle,
2070
- trace,
2071
- maxEffectChain: options.maxEffectChain,
2072
- queued: queued.slice(0, 50),
2073
- queuedCount: queued.length,
2074
- // Try to get causation for the last effect
2075
- causalChain: effectuatedRoots.length > 0
2076
- ? getTriggerChain(batchQueue.all.get(effectuatedRoots[effectuatedRoots.length - 1]))
2077
- : [],
2078
- };
2079
- switch (options.maxEffectReaction) {
2080
- case 'throw':
2081
- throw new ReactiveError(`[reactive] ${message}`, debugInfo);
2082
- case 'debug':
2083
- // biome-ignore lint/suspicious/noDebugger: This is the whole point here
2084
- debugger;
2085
- throw new ReactiveError(`[reactive] ${message}`, debugInfo);
2086
- case 'warn':
2087
- options.warn(`[reactive] ${message} (queued: ${queued.slice(0, 10).join(', ')}${queued.length > 10 ? ', …' : ''})`);
2088
- break;
2061
+ // Outer loop: continue while there are effects OR cleanups pending.
2062
+ // This ensures effects triggered by cleanups are not lost.
2063
+ while (batchQueue.all.size > 0 || batchCleanups.size > 0) {
2064
+ // Inner loop: execute all pending effects
2065
+ while (batchQueue.all.size > 0) {
2066
+ if (effectuatedRoots.length > options.maxEffectChain) {
2067
+ const cycle = findCycleInChain(effectuatedRoots);
2068
+ const trace = formatRoots(effectuatedRoots);
2069
+ const message = cycle
2070
+ ? `Max effect chain reached (cycle detected: ${formatRoots(cycle)})`
2071
+ : `Max effect chain reached (trace: ${trace})`;
2072
+ const queuedRoots = batchQueue ? Array.from(batchQueue.all.keys()) : [];
2073
+ const queued = queuedRoots.map((r) => r.name || '<anonymous>');
2074
+ const debugInfo = {
2075
+ code: ReactiveErrorCode.MaxDepthExceeded,
2076
+ effectuatedRoots,
2077
+ cycle,
2078
+ trace,
2079
+ maxEffectChain: options.maxEffectChain,
2080
+ queued: queued.slice(0, 50),
2081
+ queuedCount: queued.length,
2082
+ // Try to get causation for the last effect
2083
+ causalChain: effectuatedRoots.length > 0
2084
+ ? getTriggerChain(batchQueue.all.get(effectuatedRoots[effectuatedRoots.length - 1]))
2085
+ : [],
2086
+ };
2087
+ switch (options.maxEffectReaction) {
2088
+ case 'throw':
2089
+ throw new ReactiveError(`[reactive] ${message}`, debugInfo);
2090
+ case 'debug':
2091
+ // biome-ignore lint/suspicious/noDebugger: This is the whole point here
2092
+ debugger;
2093
+ throw new ReactiveError(`[reactive] ${message}`, debugInfo);
2094
+ case 'warn':
2095
+ options.warn(`[reactive] ${message} (queued: ${queued.slice(0, 10).join(', ')}${queued.length > 10 ? ', …' : ''})`);
2096
+ break;
2097
+ }
2098
+ }
2099
+ const rv = executeNext(effectuatedRoots);
2100
+ // executeNext() returns null when batch is complete or cycle detected (throws error)
2101
+ // But functions can legitimately return null, so we check batchQueue.all.size instead
2102
+ if (batchQueue.all.size === 0) {
2103
+ // Batch complete
2104
+ break;
2089
2105
  }
2106
+ // If executeNext() returned null but batch is not empty, it means a cycle was detected
2107
+ // and an error was thrown, so we won't reach here
2108
+ if (rv !== undefined && !('value' in firstReturn))
2109
+ firstReturn.value = rv;
2110
+ // Note: executeNext() already removed it from batchQueue, so we track by count
2090
2111
  }
2091
- const rv = executeNext(effectuatedRoots);
2092
- // executeNext() returns null when batch is complete or cycle detected (throws error)
2093
- // But functions can legitimately return null, so we check batchQueue.all.size instead
2094
- if (batchQueue.all.size === 0) {
2095
- // Batch complete
2096
- break;
2112
+ // Process cleanups. If they trigger new effects, the outer loop will catch them.
2113
+ if (batchCleanups.size > 0) {
2114
+ const cleanups = Array.from(batchCleanups);
2115
+ batchCleanups.clear();
2116
+ for (const cleanup of cleanups)
2117
+ cleanup();
2097
2118
  }
2098
- // If executeNext() returned null but batch is not empty, it means a cycle was detected
2099
- // and an error was thrown, so we won't reach here
2100
- if (rv !== undefined && !('value' in firstReturn))
2101
- firstReturn.value = rv;
2102
- // Note: executeNext() already removed it from batchQueue, so we track by count
2103
2119
  }
2104
- const cleanups = Array.from(batchCleanups);
2105
- batchCleanups.clear();
2106
- for (const cleanup of cleanups)
2107
- cleanup();
2108
2120
  return firstReturn.value;
2109
2121
  }
2110
2122
  finally {
@@ -2864,7 +2876,11 @@ const reactiveHandlers = {
2864
2876
  dependant(current, prop);
2865
2877
  if (Object.hasOwn(current, prop))
2866
2878
  break;
2867
- current = reactiveObject(Object.getPrototypeOf(current));
2879
+ let next = reactiveObject(Object.getPrototypeOf(current));
2880
+ if (next === current) {
2881
+ next = reactiveObject(Object.getPrototypeOf(unwrap(current)));
2882
+ }
2883
+ current = next;
2868
2884
  }
2869
2885
  }
2870
2886
  const value = ReflectGet(obj, prop, receiver);
@@ -4837,5 +4853,5 @@ const profileInfo = {
4837
4853
  nonReactiveObjects,
4838
4854
  };
4839
4855
 
4840
- export { unreactive as A, watch as B, mapped as C, reduced as D, memoize as E, immutables as F, isNonReactive as G, registerNativeReactivity as H, IterableWeakMap as I, project as J, isReactive as K, ReactiveBase as L, reactive as M, unwrap as N, organize as O, organized as P, Register as Q, ReadOnlyError as R, register as S, options as T, ReactiveError as U, isZoneEnabled as V, setZoneEnabled as W, IterableWeakSet as a, touched1 as b, buildReactivityGraph as c, registerObjectForDebug as d, enableDevTools as e, setObjectName as f, getState as g, deepWatch as h, isDevtoolsEnabled as i, addBatchCleanup as j, atomic as k, biDi as l, mixin as m, defer as n, effect as o, profileInfo as p, getActiveEffect as q, registerEffectForDebug as r, setEffectName as s, touched as t, root as u, trackEffect as v, untracked as w, cleanedBy as x, cleanup as y, derived as z };
4841
- //# sourceMappingURL=index-DzUDtFc7.esm.js.map
4856
+ export { derived as A, unreactive as B, watch as C, mapped as D, reduced as E, memoize as F, immutables as G, isNonReactive as H, IterableWeakMap as I, registerNativeReactivity as J, project as K, isReactive as L, ReactiveBase as M, reactive as N, unwrap as O, organize as P, organized as Q, ReadOnlyError as R, Register as S, register as T, options as U, ReactiveError as V, isZoneEnabled as W, setZoneEnabled as X, IterableWeakSet as a, touched1 as b, buildReactivityGraph as c, registerObjectForDebug as d, enableDevTools as e, setObjectName as f, getState as g, deepWatch as h, isDevtoolsEnabled as i, addBatchCleanup as j, atomic as k, batch as l, mixin as m, biDi as n, defer as o, profileInfo as p, effect as q, registerEffectForDebug as r, setEffectName as s, touched as t, getActiveEffect as u, root as v, trackEffect as w, untracked as x, cleanedBy as y, cleanup as z };
4857
+ //# sourceMappingURL=index-79Kk8D6e.esm.js.map