@pyreon/reactivity 0.5.4 → 0.5.6

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.
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
5386
5386
  </script>
5387
5387
  <script>
5388
5388
  /*<!--*/
5389
- const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"dc498794-1","name":"batch.ts"},{"uid":"dc498794-3","name":"cell.ts"},{"uid":"dc498794-5","name":"scope.ts"},{"uid":"dc498794-7","name":"tracking.ts"},{"uid":"dc498794-9","name":"computed.ts"},{"uid":"dc498794-11","name":"effect.ts"},{"uid":"dc498794-13","name":"createSelector.ts"},{"uid":"dc498794-15","name":"debug.ts"},{"uid":"dc498794-17","name":"signal.ts"},{"uid":"dc498794-19","name":"store.ts"},{"uid":"dc498794-21","name":"reconcile.ts"},{"uid":"dc498794-23","name":"resource.ts"},{"uid":"dc498794-25","name":"watch.ts"},{"uid":"dc498794-27","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"dc498794-1":{"renderedLength":916,"gzipLength":475,"brotliLength":0,"metaUid":"dc498794-0"},"dc498794-3":{"renderedLength":1669,"gzipLength":792,"brotliLength":0,"metaUid":"dc498794-2"},"dc498794-5":{"renderedLength":1787,"gzipLength":764,"brotliLength":0,"metaUid":"dc498794-4"},"dc498794-7":{"renderedLength":2073,"gzipLength":797,"brotliLength":0,"metaUid":"dc498794-6"},"dc498794-9":{"renderedLength":914,"gzipLength":385,"brotliLength":0,"metaUid":"dc498794-8"},"dc498794-11":{"renderedLength":2957,"gzipLength":1131,"brotliLength":0,"metaUid":"dc498794-10"},"dc498794-13":{"renderedLength":1810,"gzipLength":833,"brotliLength":0,"metaUid":"dc498794-12"},"dc498794-15":{"renderedLength":2469,"gzipLength":1092,"brotliLength":0,"metaUid":"dc498794-14"},"dc498794-17":{"renderedLength":2019,"gzipLength":916,"brotliLength":0,"metaUid":"dc498794-16"},"dc498794-19":{"renderedLength":2879,"gzipLength":1056,"brotliLength":0,"metaUid":"dc498794-18"},"dc498794-21":{"renderedLength":2109,"gzipLength":867,"brotliLength":0,"metaUid":"dc498794-20"},"dc498794-23":{"renderedLength":1029,"gzipLength":475,"brotliLength":0,"metaUid":"dc498794-22"},"dc498794-25":{"renderedLength":1249,"gzipLength":582,"brotliLength":0,"metaUid":"dc498794-24"},"dc498794-27":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"dc498794-26"}},"nodeMetas":{"dc498794-0":{"id":"/src/batch.ts","moduleParts":{"index.js":"dc498794-1"},"imported":[],"importedBy":[{"uid":"dc498794-26"},{"uid":"dc498794-16"},{"uid":"dc498794-6"}]},"dc498794-2":{"id":"/src/cell.ts","moduleParts":{"index.js":"dc498794-3"},"imported":[],"importedBy":[{"uid":"dc498794-26"}]},"dc498794-4":{"id":"/src/scope.ts","moduleParts":{"index.js":"dc498794-5"},"imported":[],"importedBy":[{"uid":"dc498794-26"},{"uid":"dc498794-8"},{"uid":"dc498794-10"}]},"dc498794-6":{"id":"/src/tracking.ts","moduleParts":{"index.js":"dc498794-7"},"imported":[{"uid":"dc498794-0"}],"importedBy":[{"uid":"dc498794-26"},{"uid":"dc498794-8"},{"uid":"dc498794-12"},{"uid":"dc498794-10"},{"uid":"dc498794-22"},{"uid":"dc498794-16"}]},"dc498794-8":{"id":"/src/computed.ts","moduleParts":{"index.js":"dc498794-9"},"imported":[{"uid":"dc498794-4"},{"uid":"dc498794-6"}],"importedBy":[{"uid":"dc498794-26"}]},"dc498794-10":{"id":"/src/effect.ts","moduleParts":{"index.js":"dc498794-11"},"imported":[{"uid":"dc498794-4"},{"uid":"dc498794-6"}],"importedBy":[{"uid":"dc498794-26"},{"uid":"dc498794-12"},{"uid":"dc498794-22"},{"uid":"dc498794-24"}]},"dc498794-12":{"id":"/src/createSelector.ts","moduleParts":{"index.js":"dc498794-13"},"imported":[{"uid":"dc498794-10"},{"uid":"dc498794-6"}],"importedBy":[{"uid":"dc498794-26"}]},"dc498794-14":{"id":"/src/debug.ts","moduleParts":{"index.js":"dc498794-15"},"imported":[],"importedBy":[{"uid":"dc498794-26"},{"uid":"dc498794-16"}]},"dc498794-16":{"id":"/src/signal.ts","moduleParts":{"index.js":"dc498794-17"},"imported":[{"uid":"dc498794-0"},{"uid":"dc498794-14"},{"uid":"dc498794-6"}],"importedBy":[{"uid":"dc498794-26"},{"uid":"dc498794-22"},{"uid":"dc498794-18"}]},"dc498794-18":{"id":"/src/store.ts","moduleParts":{"index.js":"dc498794-19"},"imported":[{"uid":"dc498794-16"}],"importedBy":[{"uid":"dc498794-26"},{"uid":"dc498794-20"}]},"dc498794-20":{"id":"/src/reconcile.ts","moduleParts":{"index.js":"dc498794-21"},"imported":[{"uid":"dc498794-18"}],"importedBy":[{"uid":"dc498794-26"}]},"dc498794-22":{"id":"/src/resource.ts","moduleParts":{"index.js":"dc498794-23"},"imported":[{"uid":"dc498794-10"},{"uid":"dc498794-16"},{"uid":"dc498794-6"}],"importedBy":[{"uid":"dc498794-26"}]},"dc498794-24":{"id":"/src/watch.ts","moduleParts":{"index.js":"dc498794-25"},"imported":[{"uid":"dc498794-10"}],"importedBy":[{"uid":"dc498794-26"}]},"dc498794-26":{"id":"/src/index.ts","moduleParts":{"index.js":"dc498794-27"},"imported":[{"uid":"dc498794-0"},{"uid":"dc498794-2"},{"uid":"dc498794-8"},{"uid":"dc498794-12"},{"uid":"dc498794-14"},{"uid":"dc498794-10"},{"uid":"dc498794-20"},{"uid":"dc498794-22"},{"uid":"dc498794-4"},{"uid":"dc498794-16"},{"uid":"dc498794-18"},{"uid":"dc498794-6"},{"uid":"dc498794-24"}],"importedBy":[],"isEntry":true}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5389
+ const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"6a4a12b6-1","name":"batch.ts"},{"uid":"6a4a12b6-3","name":"cell.ts"},{"uid":"6a4a12b6-5","name":"scope.ts"},{"uid":"6a4a12b6-7","name":"tracking.ts"},{"uid":"6a4a12b6-9","name":"computed.ts"},{"uid":"6a4a12b6-11","name":"effect.ts"},{"uid":"6a4a12b6-13","name":"createSelector.ts"},{"uid":"6a4a12b6-15","name":"debug.ts"},{"uid":"6a4a12b6-17","name":"signal.ts"},{"uid":"6a4a12b6-19","name":"store.ts"},{"uid":"6a4a12b6-21","name":"reconcile.ts"},{"uid":"6a4a12b6-23","name":"resource.ts"},{"uid":"6a4a12b6-25","name":"watch.ts"},{"uid":"6a4a12b6-27","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"6a4a12b6-1":{"renderedLength":949,"gzipLength":487,"brotliLength":0,"metaUid":"6a4a12b6-0"},"6a4a12b6-3":{"renderedLength":1669,"gzipLength":792,"brotliLength":0,"metaUid":"6a4a12b6-2"},"6a4a12b6-5":{"renderedLength":1787,"gzipLength":764,"brotliLength":0,"metaUid":"6a4a12b6-4"},"6a4a12b6-7":{"renderedLength":2168,"gzipLength":825,"brotliLength":0,"metaUid":"6a4a12b6-6"},"6a4a12b6-9":{"renderedLength":2791,"gzipLength":971,"brotliLength":0,"metaUid":"6a4a12b6-8"},"6a4a12b6-11":{"renderedLength":3536,"gzipLength":1271,"brotliLength":0,"metaUid":"6a4a12b6-10"},"6a4a12b6-13":{"renderedLength":1810,"gzipLength":833,"brotliLength":0,"metaUid":"6a4a12b6-12"},"6a4a12b6-15":{"renderedLength":2469,"gzipLength":1092,"brotliLength":0,"metaUid":"6a4a12b6-14"},"6a4a12b6-17":{"renderedLength":2019,"gzipLength":916,"brotliLength":0,"metaUid":"6a4a12b6-16"},"6a4a12b6-19":{"renderedLength":2879,"gzipLength":1056,"brotliLength":0,"metaUid":"6a4a12b6-18"},"6a4a12b6-21":{"renderedLength":2109,"gzipLength":867,"brotliLength":0,"metaUid":"6a4a12b6-20"},"6a4a12b6-23":{"renderedLength":1029,"gzipLength":475,"brotliLength":0,"metaUid":"6a4a12b6-22"},"6a4a12b6-25":{"renderedLength":1249,"gzipLength":582,"brotliLength":0,"metaUid":"6a4a12b6-24"},"6a4a12b6-27":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"6a4a12b6-26"}},"nodeMetas":{"6a4a12b6-0":{"id":"/src/batch.ts","moduleParts":{"index.js":"6a4a12b6-1"},"imported":[],"importedBy":[{"uid":"6a4a12b6-26"},{"uid":"6a4a12b6-16"},{"uid":"6a4a12b6-6"}]},"6a4a12b6-2":{"id":"/src/cell.ts","moduleParts":{"index.js":"6a4a12b6-3"},"imported":[],"importedBy":[{"uid":"6a4a12b6-26"}]},"6a4a12b6-4":{"id":"/src/scope.ts","moduleParts":{"index.js":"6a4a12b6-5"},"imported":[],"importedBy":[{"uid":"6a4a12b6-26"},{"uid":"6a4a12b6-8"},{"uid":"6a4a12b6-10"}]},"6a4a12b6-6":{"id":"/src/tracking.ts","moduleParts":{"index.js":"6a4a12b6-7"},"imported":[{"uid":"6a4a12b6-0"}],"importedBy":[{"uid":"6a4a12b6-26"},{"uid":"6a4a12b6-8"},{"uid":"6a4a12b6-12"},{"uid":"6a4a12b6-10"},{"uid":"6a4a12b6-22"},{"uid":"6a4a12b6-16"}]},"6a4a12b6-8":{"id":"/src/computed.ts","moduleParts":{"index.js":"6a4a12b6-9"},"imported":[{"uid":"6a4a12b6-4"},{"uid":"6a4a12b6-6"}],"importedBy":[{"uid":"6a4a12b6-26"}]},"6a4a12b6-10":{"id":"/src/effect.ts","moduleParts":{"index.js":"6a4a12b6-11"},"imported":[{"uid":"6a4a12b6-4"},{"uid":"6a4a12b6-6"}],"importedBy":[{"uid":"6a4a12b6-26"},{"uid":"6a4a12b6-12"},{"uid":"6a4a12b6-22"},{"uid":"6a4a12b6-24"}]},"6a4a12b6-12":{"id":"/src/createSelector.ts","moduleParts":{"index.js":"6a4a12b6-13"},"imported":[{"uid":"6a4a12b6-10"},{"uid":"6a4a12b6-6"}],"importedBy":[{"uid":"6a4a12b6-26"}]},"6a4a12b6-14":{"id":"/src/debug.ts","moduleParts":{"index.js":"6a4a12b6-15"},"imported":[],"importedBy":[{"uid":"6a4a12b6-26"},{"uid":"6a4a12b6-16"}]},"6a4a12b6-16":{"id":"/src/signal.ts","moduleParts":{"index.js":"6a4a12b6-17"},"imported":[{"uid":"6a4a12b6-0"},{"uid":"6a4a12b6-14"},{"uid":"6a4a12b6-6"}],"importedBy":[{"uid":"6a4a12b6-26"},{"uid":"6a4a12b6-22"},{"uid":"6a4a12b6-18"}]},"6a4a12b6-18":{"id":"/src/store.ts","moduleParts":{"index.js":"6a4a12b6-19"},"imported":[{"uid":"6a4a12b6-16"}],"importedBy":[{"uid":"6a4a12b6-26"},{"uid":"6a4a12b6-20"}]},"6a4a12b6-20":{"id":"/src/reconcile.ts","moduleParts":{"index.js":"6a4a12b6-21"},"imported":[{"uid":"6a4a12b6-18"}],"importedBy":[{"uid":"6a4a12b6-26"}]},"6a4a12b6-22":{"id":"/src/resource.ts","moduleParts":{"index.js":"6a4a12b6-23"},"imported":[{"uid":"6a4a12b6-10"},{"uid":"6a4a12b6-16"},{"uid":"6a4a12b6-6"}],"importedBy":[{"uid":"6a4a12b6-26"}]},"6a4a12b6-24":{"id":"/src/watch.ts","moduleParts":{"index.js":"6a4a12b6-25"},"imported":[{"uid":"6a4a12b6-10"}],"importedBy":[{"uid":"6a4a12b6-26"}]},"6a4a12b6-26":{"id":"/src/index.ts","moduleParts":{"index.js":"6a4a12b6-27"},"imported":[{"uid":"6a4a12b6-0"},{"uid":"6a4a12b6-2"},{"uid":"6a4a12b6-8"},{"uid":"6a4a12b6-12"},{"uid":"6a4a12b6-14"},{"uid":"6a4a12b6-10"},{"uid":"6a4a12b6-20"},{"uid":"6a4a12b6-22"},{"uid":"6a4a12b6-4"},{"uid":"6a4a12b6-16"},{"uid":"6a4a12b6-18"},{"uid":"6a4a12b6-6"},{"uid":"6a4a12b6-24"}],"importedBy":[],"isEntry":true}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5390
5390
 
5391
5391
  const run = () => {
5392
5392
  const width = window.innerWidth;
package/lib/index.js CHANGED
@@ -9,7 +9,7 @@ function batch(fn) {
9
9
  fn();
10
10
  } finally {
11
11
  batchDepth--;
12
- if (batchDepth === 0) {
12
+ if (batchDepth === 0 && pendingNotifications.size > 0) {
13
13
  const flush = pendingNotifications;
14
14
  pendingNotifications = flush === setA ? setB : setA;
15
15
  for (const notify of flush) notify();
@@ -173,9 +173,13 @@ function effectScope() {
173
173
  let activeEffect = null;
174
174
  const effectDeps = /* @__PURE__ */ new WeakMap();
175
175
  let _depsCollector = null;
176
+ let _skipDepsCollection = false;
176
177
  function setDepsCollector(collector) {
177
178
  _depsCollector = collector;
178
179
  }
180
+ function setSkipDepsCollection(skip) {
181
+ _skipDepsCollection = skip;
182
+ }
179
183
  /**
180
184
  * Register the active effect as a subscriber of the given reactive source.
181
185
  * The subscriber Set is created lazily on the host — sources read only outside
@@ -184,16 +188,16 @@ function setDepsCollector(collector) {
184
188
  function trackSubscriber(host) {
185
189
  if (activeEffect) {
186
190
  if (!host._s) host._s = /* @__PURE__ */ new Set();
187
- const subscribers = host._s;
188
- subscribers.add(activeEffect);
189
- if (_depsCollector) _depsCollector.push(subscribers);
191
+ host._s.add(activeEffect);
192
+ if (_skipDepsCollection) return;
193
+ if (_depsCollector) _depsCollector.push(host._s);
190
194
  else {
191
195
  let deps = effectDeps.get(activeEffect);
192
196
  if (!deps) {
193
197
  deps = /* @__PURE__ */ new Set();
194
198
  effectDeps.set(activeEffect, deps);
195
199
  }
196
- deps.add(subscribers);
200
+ deps.add(host._s);
197
201
  }
198
202
  }
199
203
  }
@@ -257,32 +261,93 @@ function runUntracked(fn) {
257
261
 
258
262
  //#endregion
259
263
  //#region src/computed.ts
264
+ /** Remove a computed from all dependency subscriber sets (local deps array). */
265
+ function cleanupLocalDeps$1(deps, fn) {
266
+ for (let i = 0; i < deps.length; i++) deps[i].delete(fn);
267
+ deps.length = 0;
268
+ }
269
+ /** Re-track dependencies using the local deps array collector. */
270
+ function trackWithLocalDeps(deps, effect, fn) {
271
+ setDepsCollector(deps);
272
+ const result = withTracking(effect, fn);
273
+ setDepsCollector(null);
274
+ return result;
275
+ }
260
276
  function computed(fn, options) {
277
+ return options?.equals ? computedWithEquals(fn, options.equals) : computedLazy(fn);
278
+ }
279
+ /**
280
+ * Default computed — lazy evaluation with deferred cleanup.
281
+ *
282
+ * On notification: just marks dirty and propagates (no cleanup/re-track).
283
+ * On read: cleans up old deps, re-evaluates, re-tracks.
284
+ *
285
+ * The `if (dirty) return` early exit in recompute prevents double-propagation
286
+ * in diamond patterns (a→b,c→d: b notifies d, c tries to notify d again —
287
+ * skipped because d is already dirty).
288
+ */
289
+ function computedLazy(fn) {
261
290
  let value;
262
291
  let dirty = true;
263
- let initialized = false;
264
292
  let disposed = false;
265
- const customEquals = options?.equals;
293
+ let tracked = false;
294
+ const deps = [];
266
295
  const host = { _s: null };
267
296
  const recompute = () => {
268
- if (disposed) return;
269
- cleanupEffect(recompute);
270
- if (customEquals) {
271
- const next = withTracking(recompute, fn);
272
- if (initialized && customEquals(value, next)) return;
273
- value = next;
297
+ if (disposed || dirty) return;
298
+ dirty = true;
299
+ if (host._s) notifySubscribers(host._s);
300
+ };
301
+ const read = () => {
302
+ trackSubscriber(host);
303
+ if (dirty) {
304
+ if (tracked) {
305
+ setSkipDepsCollection(true);
306
+ value = withTracking(recompute, fn);
307
+ setSkipDepsCollection(false);
308
+ } else {
309
+ value = trackWithLocalDeps(deps, recompute, fn);
310
+ tracked = true;
311
+ }
274
312
  dirty = false;
275
- initialized = true;
276
- if (host._s) notifySubscribers(host._s);
277
- } else {
278
- dirty = true;
279
- if (host._s) notifySubscribers(host._s);
280
313
  }
314
+ return value;
315
+ };
316
+ read.dispose = () => {
317
+ disposed = true;
318
+ cleanupLocalDeps$1(deps, recompute);
319
+ };
320
+ getCurrentScope()?.add({ dispose: read.dispose });
321
+ return read;
322
+ }
323
+ /**
324
+ * Computed with custom equality — eager evaluation on notification.
325
+ *
326
+ * Re-evaluates immediately when deps change and only notifies downstream
327
+ * if `equals(prev, next)` returns false.
328
+ */
329
+ function computedWithEquals(fn, equals) {
330
+ let value;
331
+ let dirty = true;
332
+ let initialized = false;
333
+ let disposed = false;
334
+ const deps = [];
335
+ const host = { _s: null };
336
+ const recompute = () => {
337
+ if (disposed) return;
338
+ cleanupLocalDeps$1(deps, recompute);
339
+ const next = trackWithLocalDeps(deps, recompute, fn);
340
+ if (initialized && equals(value, next)) return;
341
+ value = next;
342
+ dirty = false;
343
+ initialized = true;
344
+ if (host._s) notifySubscribers(host._s);
281
345
  };
282
346
  const read = () => {
283
347
  trackSubscriber(host);
284
348
  if (dirty) {
285
- value = withTracking(recompute, fn);
349
+ cleanupLocalDeps$1(deps, recompute);
350
+ value = trackWithLocalDeps(deps, recompute, fn);
286
351
  dirty = false;
287
352
  initialized = true;
288
353
  }
@@ -290,6 +355,7 @@ function computed(fn, options) {
290
355
  };
291
356
  read.dispose = () => {
292
357
  disposed = true;
358
+ cleanupLocalDeps$1(deps, recompute);
293
359
  cleanupEffect(recompute);
294
360
  };
295
361
  getCurrentScope()?.add({ dispose: read.dispose });
@@ -304,11 +370,22 @@ let _errorHandler = (err) => {
304
370
  function setErrorHandler(fn) {
305
371
  _errorHandler = fn;
306
372
  }
373
+ /** Remove an effect from all dependency subscriber sets (local deps array). */
374
+ function cleanupLocalDeps(deps, fn) {
375
+ if (deps.length === 1) {
376
+ deps[0].delete(fn);
377
+ deps.length = 0;
378
+ } else if (deps.length > 1) {
379
+ for (let i = 0; i < deps.length; i++) deps[i].delete(fn);
380
+ deps.length = 0;
381
+ }
382
+ }
307
383
  function effect(fn) {
308
384
  const scope = getCurrentScope();
309
385
  let disposed = false;
310
386
  let isFirstRun = true;
311
387
  let cleanup;
388
+ const deps = [];
312
389
  const runCleanup = () => {
313
390
  if (typeof cleanup === "function") {
314
391
  try {
@@ -322,10 +399,13 @@ function effect(fn) {
322
399
  const run = () => {
323
400
  if (disposed) return;
324
401
  runCleanup();
325
- cleanupEffect(run);
326
402
  try {
403
+ cleanupLocalDeps(deps, run);
404
+ setDepsCollector(deps);
327
405
  cleanup = withTracking(run, fn) || void 0;
406
+ setDepsCollector(null);
328
407
  } catch (err) {
408
+ setDepsCollector(null);
329
409
  _errorHandler(err);
330
410
  }
331
411
  if (!isFirstRun) scope?.notifyEffectRan();
@@ -335,7 +415,7 @@ function effect(fn) {
335
415
  const e = { dispose() {
336
416
  runCleanup();
337
417
  disposed = true;
338
- cleanupEffect(run);
418
+ cleanupLocalDeps(deps, run);
339
419
  } };
340
420
  getCurrentScope()?.add(e);
341
421
  return e;
@@ -385,26 +465,30 @@ function _bind(fn) {
385
465
  getCurrentScope()?.add({ dispose });
386
466
  return dispose;
387
467
  }
468
+ /** Full re-track path for renderEffect: cleanup old deps, evaluate with tracking. */
469
+ function renderEffectFullTrack(deps, run, fn) {
470
+ if (deps.length === 1) {
471
+ deps[0].delete(run);
472
+ deps.length = 0;
473
+ } else if (deps.length > 1) {
474
+ for (const s of deps) s.delete(run);
475
+ deps.length = 0;
476
+ }
477
+ setDepsCollector(deps);
478
+ _setActiveEffect(run);
479
+ try {
480
+ fn();
481
+ } finally {
482
+ _restoreActiveEffect();
483
+ setDepsCollector(null);
484
+ }
485
+ }
388
486
  function renderEffect(fn) {
389
487
  const deps = [];
390
488
  let disposed = false;
391
489
  const run = () => {
392
490
  if (disposed) return;
393
- if (deps.length === 1) {
394
- deps[0].delete(run);
395
- deps.length = 0;
396
- } else if (deps.length > 1) {
397
- for (const s of deps) s.delete(run);
398
- deps.length = 0;
399
- }
400
- setDepsCollector(deps);
401
- _setActiveEffect(run);
402
- try {
403
- fn();
404
- } finally {
405
- _restoreActiveEffect();
406
- setDepsCollector(null);
407
- }
491
+ renderEffectFullTrack(deps, run, fn);
408
492
  };
409
493
  run();
410
494
  const dispose = () => {
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/batch.ts","../src/cell.ts","../src/scope.ts","../src/tracking.ts","../src/computed.ts","../src/effect.ts","../src/createSelector.ts","../src/debug.ts","../src/signal.ts","../src/store.ts","../src/reconcile.ts","../src/resource.ts","../src/watch.ts"],"sourcesContent":["// Batch multiple signal updates into a single notification pass.\n// Uses a Set so the same subscriber is never flushed more than once per batch,\n// even if multiple signals it depends on change within the same batch.\n\nlet batchDepth = 0\n\n// Two pre-allocated Sets swapped on each flush — avoids allocating a new Set()\n// on every batch exit. The \"active\" set collects enqueued notifications; on flush\n// we swap to the other set and iterate the captured one, then clear it for reuse.\nlet setA = new Set<() => void>()\nlet setB = new Set<() => void>()\nlet pendingNotifications = setA\n\nexport function batch(fn: () => void): void {\n batchDepth++\n try {\n fn()\n } finally {\n batchDepth--\n if (batchDepth === 0) {\n // Swap to the other pre-allocated Set before flushing so new enqueues\n // during notification land in the alternate Set, not mixed into the\n // current iteration.\n const flush = pendingNotifications\n pendingNotifications = flush === setA ? setB : setA\n for (const notify of flush) notify()\n flush.clear()\n }\n }\n}\n\nexport function isBatching(): boolean {\n return batchDepth > 0\n}\n\nexport function enqueuePendingNotification(notify: () => void): void {\n pendingNotifications.add(notify)\n}\n\n/**\n * Returns a Promise that resolves after all currently-pending microtasks have flushed.\n * Useful when you need to read the DOM after a batch of signal updates has settled.\n *\n * @example\n * count.set(1); count.set(2)\n * await nextTick()\n * // DOM is now up-to-date\n */\nexport function nextTick(): Promise<void> {\n return new Promise((resolve) => queueMicrotask(resolve))\n}\n","/**\n * Lightweight reactive cell — class-based alternative to signal().\n *\n * - 1 object allocation vs signal()'s 6 closures\n * - Same API surface: peek(), set(), update(), subscribe(), listen()\n * - NOT callable as a getter (no effect tracking) — use for fixed subscriptions\n * - Methods on prototype, shared across all instances\n * - Single-listener fast path: no Set allocated when ≤1 subscriber\n *\n * Use when you need reactive state but don't need automatic effect dependency tracking.\n * Ideal for list item labels in keyed reconcilers where subscribe() is used directly.\n */\nexport class Cell<T> {\n /** @internal */ _v: T\n /** @internal */ _l: (() => void) | null = null // single-listener fast path\n /** @internal */ _s: Set<() => void> | null = null // multi-listener fallback\n\n constructor(value: T) {\n this._v = value\n }\n\n peek(): T {\n return this._v\n }\n\n set(value: T): void {\n if (Object.is(this._v, value)) return\n this._v = value\n if (this._l) this._l()\n else if (this._s) for (const fn of this._s) fn()\n }\n\n update(fn: (current: T) => T): void {\n this.set(fn(this._v))\n }\n\n /**\n * Fire-and-forget subscription — no unsubscribe returned.\n * Use when the listener's lifetime matches the cell's (e.g., list rows).\n * Saves 1 closure allocation per call vs subscribe().\n */\n listen(listener: () => void): void {\n if (!this._l && !this._s) {\n this._l = listener\n } else {\n // Promote to Set\n if (!this._s) {\n this._s = new Set()\n if (this._l) {\n this._s.add(this._l)\n this._l = null\n }\n }\n this._s.add(listener)\n }\n }\n\n subscribe(listener: () => void): () => void {\n this.listen(listener)\n if (this._l === listener) {\n return () => {\n if (this._l === listener) this._l = null\n }\n }\n return () => this._s?.delete(listener)\n }\n}\n\nexport function cell<T>(value: T): Cell<T> {\n return new Cell(value)\n}\n","// EffectScope — auto-tracks effects created during a component's setup\n// and disposes them all at once when the component unmounts.\n\nexport class EffectScope {\n private _effects: { dispose(): void }[] = []\n private _active = true\n private _updateHooks: (() => void)[] = []\n private _updatePending = false\n\n /** Register an effect/computed to be disposed when this scope stops. */\n add(e: { dispose(): void }): void {\n if (this._active) this._effects.push(e)\n }\n\n /**\n * Temporarily re-activate this scope so effects created inside `fn` are\n * auto-tracked and will be disposed when the scope stops.\n * Used to ensure effects created in `onMount` callbacks belong to their\n * component's scope rather than leaking as global effects.\n */\n runInScope<T>(fn: () => T): T {\n const prev = _currentScope\n _currentScope = this\n try {\n return fn()\n } finally {\n _currentScope = prev\n }\n }\n\n /** Register a callback to run after any reactive update in this scope. */\n addUpdateHook(fn: () => void): void {\n this._updateHooks.push(fn)\n }\n\n /**\n * Called by effects after each non-initial re-run.\n * Schedules onUpdate hooks via microtask so all synchronous effects settle first.\n */\n notifyEffectRan(): void {\n if (!this._active || this._updateHooks.length === 0 || this._updatePending) return\n this._updatePending = true\n queueMicrotask(() => {\n this._updatePending = false\n if (!this._active) return\n for (const fn of this._updateHooks) {\n try {\n fn()\n } catch (err) {\n console.error(\"[pyreon] onUpdate hook error:\", err)\n }\n }\n })\n }\n\n /** Dispose all tracked effects. */\n stop(): void {\n if (!this._active) return\n for (const e of this._effects) e.dispose()\n this._effects = []\n this._updateHooks = []\n this._updatePending = false\n this._active = false\n }\n}\n\nlet _currentScope: EffectScope | null = null\n\nexport function getCurrentScope(): EffectScope | null {\n return _currentScope\n}\n\nexport function setCurrentScope(scope: EffectScope | null): void {\n _currentScope = scope\n}\n\n/** Create a new EffectScope. */\nexport function effectScope(): EffectScope {\n return new EffectScope()\n}\n","// Global subscriber tracking context\n\nimport { enqueuePendingNotification, isBatching } from \"./batch\"\n\nlet activeEffect: (() => void) | null = null\n\n// Tracks which subscriber sets each effect is registered in, so we can\n// clean them up before a re-run (dynamic dependency tracking).\nconst effectDeps = new WeakMap<() => void, Set<Set<() => void>>>()\n\n// Fast deps collector for renderEffect — avoids WeakMap overhead entirely.\n// When set, trackSubscriber pushes subscriber sets here instead of effectDeps.\nlet _depsCollector: Set<() => void>[] | null = null\n\nexport function setDepsCollector(collector: Set<() => void>[] | null): void {\n _depsCollector = collector\n}\n\n/**\n * Subscriber host — any reactive source that can have downstream subscribers.\n * Signals, computeds, and createSelector buckets all implement this interface.\n * The Set is created lazily — only allocated when an effect actually tracks this source.\n */\nexport interface SubscriberHost {\n /** @internal subscriber set — null until first tracked by an effect */\n _s: Set<() => void> | null\n}\n\n/**\n * Register the active effect as a subscriber of the given reactive source.\n * The subscriber Set is created lazily on the host — sources read only outside\n * effects never allocate a Set.\n */\nexport function trackSubscriber(host: SubscriberHost) {\n if (activeEffect) {\n if (!host._s) host._s = new Set()\n const subscribers = host._s\n subscribers.add(activeEffect)\n if (_depsCollector) {\n // Fast path: renderEffect stores deps inline, no WeakMap\n _depsCollector.push(subscribers)\n } else {\n // Record this dep so we can remove it on cleanup\n let deps = effectDeps.get(activeEffect)\n if (!deps) {\n deps = new Set()\n effectDeps.set(activeEffect, deps)\n }\n deps.add(subscribers)\n }\n }\n}\n\n/**\n * Remove an effect from every subscriber set it was registered in,\n * then clear its dep record. Call this before each re-run and on dispose.\n */\nexport function cleanupEffect(fn: () => void): void {\n const deps = effectDeps.get(fn)\n if (deps) {\n for (const sub of deps) sub.delete(fn)\n deps.clear()\n }\n}\n\nexport function notifySubscribers(subscribers: Set<() => void>) {\n if (subscribers.size === 0) return\n // Single-subscriber fast path: avoid any iteration overhead.\n if (subscribers.size === 1) {\n const sub = subscribers.values().next().value as () => void\n if (isBatching()) enqueuePendingNotification(sub)\n else sub()\n return\n }\n if (isBatching()) {\n // Effects are queued not run inline — no re-entrancy risk, iterate the live Set directly.\n for (const sub of subscribers) enqueuePendingNotification(sub)\n } else {\n // Effects run inline and may call cleanupEffect (removes) + trackSubscriber (re-adds).\n // Instead of snapshotting with [...subscribers] (allocates an array), we iterate the\n // live Set but cap iterations at the original size to prevent infinite loops from\n // re-inserted entries. This is safe because:\n // - cleanupEffect removes the effect from the Set (no double-fire)\n // - trackSubscriber may re-add it (but we stop after originalSize iterations)\n // - Any effects re-added during this pass are already up-to-date (just ran)\n const originalSize = subscribers.size\n let i = 0\n for (const sub of subscribers) {\n if (i >= originalSize) break\n sub()\n i++\n }\n }\n}\n\nexport function withTracking<T>(fn: () => void, compute: () => T): T {\n const prev = activeEffect\n activeEffect = fn\n try {\n return compute()\n } finally {\n activeEffect = prev\n }\n}\n\n// Stack for inlined tracking in renderEffect — avoids withTracking function call overhead.\nlet _prevEffect: (() => void) | null = null\n\nexport function _setActiveEffect(fn: () => void): void {\n _prevEffect = activeEffect\n activeEffect = fn\n}\n\nexport function _restoreActiveEffect(): void {\n activeEffect = _prevEffect\n _prevEffect = null\n}\n\nexport function runUntracked<T>(fn: () => T): T {\n const prev = activeEffect\n activeEffect = null\n try {\n return fn()\n } finally {\n activeEffect = prev\n }\n}\n","import { getCurrentScope } from \"./scope\"\nimport { cleanupEffect, notifySubscribers, trackSubscriber, withTracking } from \"./tracking\"\n\nexport interface Computed<T> {\n (): T\n /** Remove this computed from all its reactive dependencies. */\n dispose(): void\n}\n\nexport interface ComputedOptions<T> {\n /**\n * Custom equality function. When provided, the computed eagerly re-evaluates\n * on dependency change and only notifies downstream if `equals(prev, next)`\n * returns false. Useful for derived objects/arrays to skip spurious updates.\n *\n * @example\n * const sorted = computed(() => items().slice().sort(), {\n * equals: (a, b) => a.length === b.length && a.every((v, i) => v === b[i])\n * })\n */\n equals?: (prev: T, next: T) => boolean\n}\n\nexport function computed<T>(fn: () => T, options?: ComputedOptions<T>): Computed<T> {\n let value: T\n let dirty = true\n let initialized = false\n let disposed = false\n const customEquals = options?.equals\n\n // SubscriberHost — _s is lazily allocated by trackSubscriber\n const host: { _s: Set<() => void> | null } = { _s: null }\n\n const recompute = () => {\n if (disposed) return\n // Remove from all current deps before re-evaluating (dynamic deps support)\n cleanupEffect(recompute)\n if (customEquals) {\n // Eager evaluation: only notify downstream if the value actually changed\n const next = withTracking(recompute, fn)\n if (initialized && customEquals(value as T, next)) return\n value = next\n dirty = false\n initialized = true\n if (host._s) notifySubscribers(host._s)\n } else {\n dirty = true\n if (host._s) notifySubscribers(host._s)\n }\n }\n\n const read = (): T => {\n trackSubscriber(host)\n if (dirty) {\n value = withTracking(recompute, fn)\n dirty = false\n initialized = true\n }\n return value as T\n }\n\n read.dispose = () => {\n disposed = true\n cleanupEffect(recompute)\n }\n\n // Auto-register with the active EffectScope (if any)\n getCurrentScope()?.add({ dispose: read.dispose })\n\n return read\n}\n","import { getCurrentScope } from \"./scope\"\nimport {\n _restoreActiveEffect,\n _setActiveEffect,\n cleanupEffect,\n setDepsCollector,\n withTracking,\n} from \"./tracking\"\n\nexport interface Effect {\n dispose(): void\n}\n\n// Global error handler — called for unhandled errors thrown inside effects.\n// Defaults to console.error so silent failures are never swallowed.\nlet _errorHandler: (err: unknown) => void = (err) => {\n console.error(\"[pyreon] Unhandled effect error:\", err)\n}\n\nexport function setErrorHandler(fn: (err: unknown) => void): void {\n _errorHandler = fn\n}\n\n// biome-ignore lint/suspicious/noConfusingVoidType: void is intentional — callbacks that return nothing must be assignable\nexport function effect(fn: () => (() => void) | void): Effect {\n // Capture the scope at creation time — remains correct during future re-runs\n // even after setCurrentScope(null) has been called post-setup.\n const scope = getCurrentScope()\n let disposed = false\n let isFirstRun = true\n let cleanup: (() => void) | undefined\n\n const runCleanup = () => {\n if (typeof cleanup === \"function\") {\n try {\n cleanup()\n } catch (err) {\n _errorHandler(err)\n }\n cleanup = undefined\n }\n }\n\n const run = () => {\n if (disposed) return\n // Run previous cleanup before re-running\n runCleanup()\n // Clean up previous subscriptions before re-running (dynamic dep tracking)\n cleanupEffect(run)\n try {\n cleanup = withTracking(run, fn) || undefined\n } catch (err) {\n _errorHandler(err)\n }\n // Notify scope after each reactive re-run (not the initial synchronous run)\n // so onUpdate hooks fire after the DOM has settled.\n if (!isFirstRun) scope?.notifyEffectRan()\n isFirstRun = false\n }\n\n run()\n\n const e: Effect = {\n dispose() {\n runCleanup()\n disposed = true\n cleanupEffect(run)\n },\n }\n\n // Auto-register with the active EffectScope (if any)\n getCurrentScope()?.add(e)\n\n return e\n}\n\n/**\n * Lightweight effect for DOM render bindings.\n *\n * Differences from `effect()`:\n * - No EffectScope registration (caller owns the dispose lifecycle)\n * - No error handler (errors propagate naturally)\n * - No onUpdate notification\n * - Deps stored in a local array instead of the global WeakMap — faster\n * creation and disposal (~200ns saved per effect vs WeakMap path)\n *\n * Returns a dispose function (not an Effect object — saves 1 allocation).\n */\n/**\n * Static-dep binding — compiler helper for template expressions.\n *\n * Like renderEffect but assumes dependencies never change (true for all\n * compiler-emitted template bindings like `_tpl()` text/attribute updates).\n *\n * Tracks dependencies only on the first run. Re-runs skip cleanup, re-tracking,\n * and tracking context save/restore entirely — just calls `fn()` directly.\n *\n * Per re-run savings vs renderEffect:\n * - No deps iteration + Set.delete (cleanup)\n * - No setDepsCollector + withTracking (re-registration)\n * - Signal reads hit `if (activeEffect)` null check → instant return\n */\nexport function _bind(fn: () => void): () => void {\n const deps: Set<() => void>[] = []\n let disposed = false\n\n const run = () => {\n if (disposed) return\n fn()\n }\n\n // First run: track deps so we know what to unsubscribe on dispose\n setDepsCollector(deps)\n withTracking(run, fn)\n setDepsCollector(null)\n\n const dispose = () => {\n if (disposed) return\n disposed = true\n for (const s of deps) s.delete(run)\n deps.length = 0\n }\n\n // Auto-register with scope so template bindings are disposed during teardown\n getCurrentScope()?.add({ dispose })\n\n return dispose\n}\n\nexport function renderEffect(fn: () => void): () => void {\n const deps: Set<() => void>[] = []\n let disposed = false\n\n const run = () => {\n if (disposed) return\n // Single-dep fast path — most render effects track exactly 1 signal.\n // Avoids for-of iterator creation + deps.length check on every re-run.\n if (deps.length === 1) {\n ;(deps[0] as Set<() => void>).delete(run)\n deps.length = 0\n } else if (deps.length > 1) {\n for (const s of deps) s.delete(run)\n deps.length = 0\n }\n // Inline tracking setup — avoids setDepsCollector + withTracking function call overhead\n setDepsCollector(deps)\n _setActiveEffect(run)\n try {\n fn()\n } finally {\n _restoreActiveEffect()\n setDepsCollector(null)\n }\n }\n\n run()\n\n const dispose = () => {\n if (disposed) return\n disposed = true\n if (deps.length === 1) {\n ;(deps[0] as Set<() => void>).delete(run)\n } else {\n for (const s of deps) s.delete(run)\n }\n deps.length = 0\n }\n\n // Auto-register with scope so render effects are disposed during teardown\n getCurrentScope()?.add({ dispose })\n\n return dispose\n}\n","import { effect } from \"./effect\"\nimport { trackSubscriber } from \"./tracking\"\n\n/**\n * Notify a subscriber bucket without snapshot allocation.\n * Caps iteration at the original size to avoid infinite loops from\n * re-inserted entries (same pattern as notifySubscribers in tracking.ts).\n */\nfunction notifyBucket(bucket: Set<() => void>): void {\n if (bucket.size === 0) return\n if (bucket.size === 1) {\n ;(bucket.values().next().value as () => void)()\n return\n }\n const originalSize = bucket.size\n let i = 0\n for (const fn of bucket) {\n if (i >= originalSize) break\n fn()\n i++\n }\n}\n\n/**\n * Create an equality selector — returns a reactive predicate that is true\n * only for the currently selected value.\n *\n * Unlike a plain `() => source() === value`, this only triggers the TWO\n * affected subscribers (deselected + newly selected) instead of ALL\n * subscribers, making selection O(1) regardless of list size.\n *\n * @example\n * const isSelected = createSelector(selectedId)\n * // In each row:\n * class: () => (isSelected(row.id) ? \"selected\" : \"\")\n */\nexport function createSelector<T>(source: () => T): (value: T) => boolean {\n const subs = new Map<T, Set<() => void>>()\n let current: T\n let initialized = false\n\n effect(() => {\n const next = source()\n if (!initialized) {\n initialized = true\n current = next\n return\n }\n if (Object.is(next, current)) return\n const old = current\n current = next\n // Only notify the two affected buckets — O(1) regardless of list size.\n // Iteration-capped loop avoids [...bucket] snapshot allocation.\n const oldBucket = subs.get(old)\n const newBucket = subs.get(next)\n if (oldBucket) notifyBucket(oldBucket)\n if (newBucket) notifyBucket(newBucket)\n })\n\n // Reusable hosts per value — avoids allocating a closure per trackSubscriber call\n const hosts = new Map<T, { _s: Set<() => void> | null }>()\n\n return (value: T): boolean => {\n let host = hosts.get(value)\n if (!host) {\n let bucket = subs.get(value)\n if (!bucket) {\n bucket = new Set()\n subs.set(value, bucket)\n }\n host = { _s: bucket }\n hosts.set(value, host)\n }\n trackSubscriber(host)\n return Object.is(current, value)\n }\n}\n","/**\n * @pyreon/reactivity debug utilities.\n *\n * Development-only tools for tracing signal updates, inspecting reactive\n * graphs, and understanding why DOM nodes re-render.\n *\n * All utilities are tree-shakeable — they compile away in production builds\n * when unused.\n */\n\nimport type { Signal, SignalDebugInfo } from \"./signal\"\n\n// ─── Signal update tracing ───────────────────────────────────────────────────\n\ninterface SignalUpdateEvent {\n /** The signal that changed */\n signal: Signal<unknown>\n /** Signal name (from options or label) */\n name: string | undefined\n /** Previous value */\n prev: unknown\n /** New value */\n next: unknown\n /** Stack trace at the point of the .set() / .update() call */\n stack: string\n /** Timestamp */\n timestamp: number\n}\n\ntype SignalUpdateListener = (event: SignalUpdateEvent) => void\n\nlet _traceListeners: SignalUpdateListener[] | null = null\n\n/**\n * Register a listener that fires on every signal write.\n * Returns a dispose function.\n *\n * @example\n * const dispose = onSignalUpdate(e => {\n * console.log(`${e.name ?? 'anonymous'}: ${e.prev} → ${e.next}`)\n * })\n */\nexport function onSignalUpdate(listener: SignalUpdateListener): () => void {\n if (!_traceListeners) _traceListeners = []\n _traceListeners.push(listener)\n return () => {\n if (!_traceListeners) return\n _traceListeners = _traceListeners.filter((l) => l !== listener)\n if (_traceListeners.length === 0) _traceListeners = null\n }\n}\n\n/** @internal — called from signal.set() when tracing is active */\nexport function _notifyTraceListeners(sig: Signal<unknown>, prev: unknown, next: unknown): void {\n if (!_traceListeners) return\n const event: SignalUpdateEvent = {\n signal: sig,\n name: sig.label,\n prev,\n next,\n stack: new Error().stack ?? \"\",\n timestamp: performance.now(),\n }\n for (const l of _traceListeners) l(event)\n}\n\n/** Check if any trace listeners are active (fast path for signal.set) */\nexport function isTracing(): boolean {\n return _traceListeners !== null\n}\n\n// ─── why() — trace which signal caused a re-run ──────────────────────────────\n\nlet _whyActive = false\nlet _whyLog: { name: string | undefined; prev: unknown; next: unknown }[] = []\n\n/**\n * Trace the next signal update. Logs which signals fire and what changed.\n * Call before triggering a state change to see what updates and why.\n *\n * @example\n * why()\n * count.set(5)\n * // Console: [pyreon:why] \"count\": 3 → 5 (2 subscribers)\n */\nexport function why(): void {\n if (_whyActive) return\n _whyActive = true\n _whyLog = []\n\n const dispose = onSignalUpdate((e) => {\n const _subCount = (e.signal as unknown as { _s: Set<unknown> | null })._s?.size ?? 0\n const _name = e.name ? `\"${e.name}\"` : \"(anonymous signal)\"\n\n console.log(\n `[pyreon:why] ${_name}: ${JSON.stringify(e.prev)} → ${JSON.stringify(e.next)} (${_subCount} subscriber${_subCount === 1 ? \"\" : \"s\"})`,\n )\n _whyLog.push({ name: e.name, prev: e.prev, next: e.next })\n })\n\n // Auto-dispose after the current microtask (captures the synchronous batch)\n queueMicrotask(() => {\n dispose()\n if (_whyLog.length === 0) {\n console.log(\"[pyreon:why] No signal updates detected\")\n }\n _whyActive = false\n _whyLog = []\n })\n}\n\n// ─── inspectSignal — rich console output ─────────────────────────────────────\n\n/**\n * Print a signal's current state to the console in a readable format.\n *\n * @example\n * const count = signal(42, { name: \"count\" })\n * inspectSignal(count)\n * // Console:\n * // 🔍 Signal \"count\"\n * // value: 42\n * // subscribers: 3\n */\nexport function inspectSignal<T>(sig: Signal<T>): SignalDebugInfo<T> {\n const info = sig.debug()\n\n console.group(`🔍 Signal ${info.name ? `\"${info.name}\"` : \"(anonymous)\"}`)\n console.log(\"value:\", info.value)\n console.log(\"subscribers:\", info.subscriberCount)\n console.groupEnd()\n\n return info\n}\n","import { enqueuePendingNotification, isBatching } from \"./batch\"\nimport { _notifyTraceListeners, isTracing } from \"./debug\"\nimport { notifySubscribers, trackSubscriber } from \"./tracking\"\n\nexport interface SignalDebugInfo<T> {\n /** Signal name (set via options or inferred) */\n name: string | undefined\n /** Current value (same as peek()) */\n value: T\n /** Number of active subscribers */\n subscriberCount: number\n}\n\n/**\n * Read-only reactive value — the common interface that both Signal and Computed satisfy.\n * Use this as the parameter type when a function only needs to read a reactive value.\n */\nexport interface ReadonlySignal<T> {\n (): T\n}\n\nexport interface Signal<T> {\n (): T\n /** Read the current value WITHOUT registering a reactive dependency. */\n peek(): T\n set(value: T): void\n update(fn: (current: T) => T): void\n /**\n * Subscribe a static listener directly — no effect overhead (no withTracking,\n * no cleanupEffect, no effectDeps WeakMap). Use when the dependency is fixed\n * and dynamic re-tracking is not needed.\n * Returns a disposer that removes the subscription.\n */\n subscribe(listener: () => void): () => void\n /**\n * Register a direct updater — even lighter than subscribe().\n * Uses a flat array instead of Set. Disposal nulls the slot (no Set.delete).\n * Intended for compiler-emitted DOM bindings (_bindText, _bindDirect).\n * Returns a disposer that nulls the slot.\n */\n direct(updater: () => void): () => void\n /** Debug name — useful for devtools and logging. */\n label: string | undefined\n /** Returns a snapshot of the signal's debug info (value, name, subscriber count). */\n debug(): SignalDebugInfo<T>\n}\n\nexport interface SignalOptions {\n /** Debug name for this signal — shows up in devtools and debug() output. */\n name?: string\n}\n\n// Internal shape of a signal function — state stored as properties on the\n// function object so methods can be shared via assignment (not per-signal closures).\ninterface SignalFn<T> {\n (): T\n /** @internal current value */\n _v: T\n /** @internal subscriber set (lazily allocated by trackSubscriber) */\n _s: Set<() => void> | null\n /** @internal direct updaters array — compiler-emitted DOM updaters (lazily allocated) */\n _d: ((() => void) | null)[] | null\n peek(): T\n set(value: T): void\n update(fn: (current: T) => T): void\n subscribe(listener: () => void): () => void\n /** Register a direct updater — lighter than subscribe, uses array index disposal. */\n direct(updater: () => void): () => void\n label: string | undefined\n debug(): SignalDebugInfo<T>\n}\n\n// Shared method implementations — defined once, assigned to every signal.\n// Uses `this` binding (signal methods are always called as `signal.method()`).\nfunction _peek(this: SignalFn<unknown>) {\n return this._v\n}\n\nfunction _set(this: SignalFn<unknown>, newValue: unknown) {\n if (Object.is(this._v, newValue)) return\n const prev = this._v\n this._v = newValue\n if (isTracing()) _notifyTraceListeners(this as unknown as Signal<unknown>, prev, newValue)\n // Direct updaters — flat array, no Set overhead, batch-aware\n if (this._d) notifyDirect(this._d)\n if (this._s) notifySubscribers(this._s)\n}\n\nfunction _update(this: SignalFn<unknown>, fn: (current: unknown) => unknown) {\n _set.call(this, fn(this._v))\n}\n\nfunction _subscribe(this: SignalFn<unknown>, listener: () => void): () => void {\n if (!this._s) this._s = new Set()\n this._s.add(listener)\n return () => this._s?.delete(listener)\n}\n\n/**\n * Register a direct updater — lighter than subscribe().\n * Uses a flat array instead of Set. Disposal nulls the slot (no Set.delete overhead).\n * Used by compiler-emitted _bindText/_bindDirect for zero-overhead DOM bindings.\n */\nfunction _directFn(this: SignalFn<unknown>, updater: () => void): () => void {\n if (!this._d) this._d = []\n const arr = this._d\n const idx = arr.length\n arr.push(updater)\n return () => {\n arr[idx] = null\n }\n}\n\n/**\n * Notify direct updaters — flat array iteration, batch-aware.\n * Null slots (from disposed updaters) are skipped.\n */\nfunction notifyDirect(updaters: ((() => void) | null)[]): void {\n if (isBatching()) {\n for (let i = 0; i < updaters.length; i++) {\n const fn = updaters[i]\n if (fn) enqueuePendingNotification(fn)\n }\n } else {\n for (let i = 0; i < updaters.length; i++) {\n updaters[i]?.()\n }\n }\n}\n\nfunction _debug(this: SignalFn<unknown>): SignalDebugInfo<unknown> {\n return {\n name: this.label,\n value: this._v,\n subscriberCount: this._s?.size ?? 0,\n }\n}\n\n/**\n * Create a reactive signal.\n *\n * Only 1 closure is allocated (the read function). State is stored as\n * properties on the function object (_v, _s) and methods (peek, set,\n * update, subscribe) are shared across all signals — not per-signal closures.\n */\nexport function signal<T>(initialValue: T, options?: SignalOptions): Signal<T> {\n // The read function is the only per-signal closure.\n // It doubles as the SubscriberHost (_s property) for trackSubscriber.\n const read = (() => {\n trackSubscriber(read as SignalFn<T>)\n return read._v\n }) as unknown as SignalFn<T>\n\n read._v = initialValue\n read._s = null\n read._d = null\n read.peek = _peek as () => T\n read.set = _set as (value: T) => void\n read.update = _update as (fn: (current: T) => T) => void\n read.subscribe = _subscribe as (listener: () => void) => () => void\n read.direct = _directFn as (updater: () => void) => () => void\n read.debug = _debug as () => SignalDebugInfo<T>\n read.label = options?.name\n\n return read as unknown as Signal<T>\n}\n","/**\n * createStore — deep reactive Proxy store.\n *\n * Wraps a plain object/array in a Proxy that creates a fine-grained signal for\n * every property. Direct mutations (`store.count++`, `store.items[0].label = \"x\"`)\n * trigger only the signals for the mutated properties — not the whole tree.\n *\n * @example\n * const state = createStore({ count: 0, items: [{ id: 1, text: \"hello\" }] })\n *\n * effect(() => console.log(state.count)) // tracks state.count only\n * state.count++ // only the count effect re-runs\n * state.items[0].text = \"world\" // only text-tracking effects re-run\n */\n\nimport { type Signal, signal } from \"./signal\"\n\n// WeakMap: raw object → its reactive proxy (ensures each raw object gets one proxy)\nconst proxyCache = new WeakMap<object, object>()\n\nconst IS_STORE = Symbol(\"pyreon.store\")\n\n/** Returns true if the value is a createStore proxy. */\nexport function isStore(value: unknown): boolean {\n return (\n value !== null &&\n typeof value === \"object\" &&\n (value as Record<symbol, unknown>)[IS_STORE] === true\n )\n}\n\n/**\n * Create a deep reactive store from a plain object or array.\n * Returns a proxy — mutations to the proxy trigger fine-grained reactive updates.\n */\nexport function createStore<T extends object>(initial: T): T {\n return wrap(initial) as T\n}\n\nfunction wrap(raw: object): object {\n const cached = proxyCache.get(raw)\n if (cached) return cached\n\n // Per-property signals. Lazily created on first access.\n const propSignals = new Map<PropertyKey, Signal<unknown>>()\n // For arrays: track length changes separately (push/pop/splice affect length)\n const isArray = Array.isArray(raw)\n const lengthSig = isArray ? signal((raw as unknown[]).length) : null\n\n function getOrCreateSignal(key: PropertyKey): Signal<unknown> {\n if (!propSignals.has(key)) {\n propSignals.set(key, signal((raw as Record<PropertyKey, unknown>)[key]))\n }\n return propSignals.get(key) as Signal<unknown>\n }\n\n const proxy = new Proxy(raw, {\n get(target, key) {\n // Pass through the identity marker and non-string/number keys (symbols, etc.)\n if (key === IS_STORE) return true\n if (typeof key === \"symbol\") return (target as Record<symbol, unknown>)[key]\n\n // Array length — tracked via dedicated signal for push/pop/splice reactivity\n if (isArray && key === \"length\") return lengthSig?.()\n\n // Non-own properties: prototype methods (forEach, map, push, …)\n // These must be returned untracked so array methods work normally.\n // Array methods will then go through set/get on indices via the proxy.\n if (!Object.hasOwn(target, key)) {\n return (target as Record<PropertyKey, unknown>)[key]\n }\n\n // Track via per-property signal\n const value = getOrCreateSignal(key)()\n\n // Deep reactivity: wrap nested objects/arrays transparently\n if (value !== null && typeof value === \"object\") {\n return wrap(value as object)\n }\n\n return value\n },\n\n set(target, key, value) {\n if (typeof key === \"symbol\") {\n ;(target as Record<symbol, unknown>)[key] = value\n return true\n }\n\n const prevLength = isArray ? (target as unknown[]).length : 0\n ;(target as Record<PropertyKey, unknown>)[key] = value\n\n // Array length set directly (e.g. arr.length = 0)\n if (isArray && key === \"length\") {\n lengthSig?.set(value as number)\n return true\n }\n\n // Update or create signal for this property\n if (propSignals.has(key)) {\n propSignals.get(key)?.set(value)\n } else {\n propSignals.set(key, signal(value))\n }\n\n // If array length changed (e.g. via push/splice index assignment), update it\n if (isArray && (target as unknown[]).length !== prevLength) {\n lengthSig?.set((target as unknown[]).length)\n }\n\n return true\n },\n\n deleteProperty(target, key) {\n delete (target as Record<PropertyKey, unknown>)[key]\n if (typeof key !== \"symbol\" && propSignals.has(key)) {\n propSignals.get(key)?.set(undefined)\n propSignals.delete(key)\n }\n if (isArray) lengthSig?.set((target as unknown[]).length)\n return true\n },\n\n has(target, key) {\n return Reflect.has(target, key)\n },\n\n ownKeys(target) {\n return Reflect.ownKeys(target)\n },\n\n getOwnPropertyDescriptor(target, key) {\n return Reflect.getOwnPropertyDescriptor(target, key)\n },\n })\n\n proxyCache.set(raw, proxy)\n return proxy\n}\n","/**\n * reconcile — surgically diff new state into an existing createStore proxy.\n *\n * Instead of replacing the store root (which would trigger all downstream effects),\n * reconcile walks both the new value and the store in parallel and only calls\n * `.set()` on signals whose value actually changed.\n *\n * Ideal for applying API responses to a long-lived store:\n *\n * @example\n * const state = createStore({ user: { name: \"Alice\", age: 30 }, items: [] })\n *\n * // API response arrives:\n * reconcile({ user: { name: \"Alice\", age: 31 }, items: [{ id: 1 }] }, state)\n * // → only state.user.age signal fires (name unchanged)\n * // → state.items[0] is newly created\n *\n * Arrays are reconciled by index — elements at the same index are recursively\n * diffed rather than replaced wholesale. Excess old elements are removed.\n */\n\nimport { isStore } from \"./store\"\n\ntype AnyObject = Record<PropertyKey, unknown>\n\nexport function reconcile<T extends object>(source: T, target: T): void {\n _reconcileInner(source, target, new WeakSet())\n}\n\nfunction _reconcileInner(source: object, target: object, seen: WeakSet<object>): void {\n if (seen.has(source)) return // circular reference — stop recursion\n seen.add(source)\n if (Array.isArray(source) && Array.isArray(target)) {\n _reconcileArray(source as unknown[], target as unknown[], seen)\n } else {\n _reconcileObject(source as AnyObject, target as AnyObject, seen)\n }\n}\n\nfunction _reconcileArray(source: unknown[], target: unknown[], seen: WeakSet<object>): void {\n const targetLen = target.length\n const sourceLen = source.length\n\n // Update / add entries\n for (let i = 0; i < sourceLen; i++) {\n const sv = source[i]\n const tv = (target as unknown[])[i]\n\n if (\n i < targetLen &&\n sv !== null &&\n typeof sv === \"object\" &&\n tv !== null &&\n typeof tv === \"object\"\n ) {\n // Both sides are objects — recurse\n _reconcileInner(sv as object, tv as object, seen)\n } else {\n // Scalar or new entry — write directly (signal will skip if equal via Object.is)\n ;(target as unknown[])[i] = sv\n }\n }\n\n // Trim excess entries\n if (targetLen > sourceLen) {\n target.length = sourceLen\n }\n}\n\nfunction _reconcileObject(source: AnyObject, target: AnyObject, seen: WeakSet<object>): void {\n const sourceKeys = Object.keys(source)\n const targetKeys = new Set(Object.keys(target))\n\n for (const key of sourceKeys) {\n const sv = source[key]\n const tv = target[key]\n\n if (sv !== null && typeof sv === \"object\" && tv !== null && typeof tv === \"object\") {\n if (isStore(tv)) {\n // Both objects — recurse into the store node\n _reconcileInner(sv as object, tv as object, seen)\n } else {\n // Target is a raw object (not yet proxied) — just assign\n target[key] = sv\n }\n } else {\n // Scalar: assign (store proxy's set trap skips if Object.is equal)\n target[key] = sv\n }\n\n targetKeys.delete(key)\n }\n\n // Remove keys that no longer exist in source\n for (const key of targetKeys) {\n delete target[key]\n }\n}\n","import { effect } from \"./effect\"\nimport type { Signal } from \"./signal\"\nimport { signal } from \"./signal\"\nimport { runUntracked } from \"./tracking\"\n\nexport interface Resource<T> {\n /** The latest resolved value (undefined while loading or on error). */\n data: Signal<T | undefined>\n /** True while a fetch is in flight. */\n loading: Signal<boolean>\n /** The last error thrown by the fetcher, or undefined. */\n error: Signal<unknown>\n /** Re-run the fetcher with the current source value. */\n refetch(): void\n}\n\n/**\n * Async data primitive. Fetches data reactively whenever `source()` changes.\n *\n * @example\n * const userId = signal(1)\n * const user = createResource(userId, (id) => fetchUser(id))\n * // user.data() — the fetched user (undefined while loading)\n * // user.loading() — true while in flight\n * // user.error() — last error\n */\nexport function createResource<T, P>(\n source: () => P,\n fetcher: (param: P) => Promise<T>,\n): Resource<T> {\n const data = signal<T | undefined>(undefined)\n const loading = signal(false)\n const error = signal<unknown>(undefined)\n let requestId = 0\n\n const doFetch = (param: P) => {\n const id = ++requestId\n loading.set(true)\n error.set(undefined)\n fetcher(param)\n .then((result) => {\n if (id !== requestId) return\n data.set(result)\n loading.set(false)\n })\n .catch((err: unknown) => {\n if (id !== requestId) return\n error.set(err)\n loading.set(false)\n })\n }\n\n effect(() => {\n const param = source()\n runUntracked(() => doFetch(param))\n })\n\n return {\n data,\n loading,\n error,\n refetch() {\n runUntracked(() => doFetch(source()))\n },\n }\n}\n","import { effect } from \"./effect\"\n\nexport interface WatchOptions {\n /** If true, call the callback immediately with the current value on setup. Default: false. */\n immediate?: boolean\n}\n\n/**\n * Watch a reactive source and run a callback whenever it changes.\n *\n * Returns a stop function that disposes the watcher.\n *\n * The callback receives (newValue, oldValue). On the first call (when\n * `immediate` is true) oldValue is `undefined`.\n *\n * The callback may return a cleanup function that is called before each\n * re-run and on stop — useful for cancelling async work.\n *\n * @example\n * const stop = watch(\n * () => userId(),\n * async (id, prev) => {\n * const data = await fetch(`/api/user/${id}`)\n * setUser(await data.json())\n * },\n * )\n * // Later: stop()\n */\nexport function watch<T>(\n source: () => T,\n // biome-ignore lint/suspicious/noConfusingVoidType: void is intentional — callers may return void\n callback: (newVal: T, oldVal: T | undefined) => void | (() => void),\n opts: WatchOptions = {},\n): () => void {\n let oldVal: T | undefined\n let isFirst = true\n let cleanupFn: (() => void) | undefined\n\n const e = effect(() => {\n const newVal = source()\n\n if (isFirst) {\n isFirst = false\n oldVal = newVal\n if (opts.immediate) {\n const result = callback(newVal, undefined)\n if (typeof result === \"function\") cleanupFn = result\n }\n return\n }\n\n if (cleanupFn) {\n cleanupFn()\n cleanupFn = undefined\n }\n\n const result = callback(newVal, oldVal)\n if (typeof result === \"function\") cleanupFn = result\n oldVal = newVal\n })\n\n return () => {\n e.dispose()\n if (cleanupFn) {\n cleanupFn()\n cleanupFn = undefined\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["cleanupLocalDeps"],"sources":["../src/batch.ts","../src/cell.ts","../src/scope.ts","../src/tracking.ts","../src/computed.ts","../src/effect.ts","../src/createSelector.ts","../src/debug.ts","../src/signal.ts","../src/store.ts","../src/reconcile.ts","../src/resource.ts","../src/watch.ts"],"sourcesContent":["// Batch multiple signal updates into a single notification pass.\n// Uses a Set so the same subscriber is never flushed more than once per batch,\n// even if multiple signals it depends on change within the same batch.\n\nlet batchDepth = 0\n\n// Two pre-allocated Sets swapped on each flush — avoids allocating a new Set()\n// on every batch exit. The \"active\" set collects enqueued notifications; on flush\n// we swap to the other set and iterate the captured one, then clear it for reuse.\nlet setA = new Set<() => void>()\nlet setB = new Set<() => void>()\nlet pendingNotifications = setA\n\nexport function batch(fn: () => void): void {\n batchDepth++\n try {\n fn()\n } finally {\n batchDepth--\n if (batchDepth === 0 && pendingNotifications.size > 0) {\n // Swap to the other pre-allocated Set before flushing so new enqueues\n // during notification land in the alternate Set, not mixed into the\n // current iteration.\n const flush = pendingNotifications\n pendingNotifications = flush === setA ? setB : setA\n for (const notify of flush) notify()\n flush.clear()\n }\n }\n}\n\nexport function isBatching(): boolean {\n return batchDepth > 0\n}\n\nexport function enqueuePendingNotification(notify: () => void): void {\n pendingNotifications.add(notify)\n}\n\n/**\n * Returns a Promise that resolves after all currently-pending microtasks have flushed.\n * Useful when you need to read the DOM after a batch of signal updates has settled.\n *\n * @example\n * count.set(1); count.set(2)\n * await nextTick()\n * // DOM is now up-to-date\n */\nexport function nextTick(): Promise<void> {\n return new Promise((resolve) => queueMicrotask(resolve))\n}\n","/**\n * Lightweight reactive cell — class-based alternative to signal().\n *\n * - 1 object allocation vs signal()'s 6 closures\n * - Same API surface: peek(), set(), update(), subscribe(), listen()\n * - NOT callable as a getter (no effect tracking) — use for fixed subscriptions\n * - Methods on prototype, shared across all instances\n * - Single-listener fast path: no Set allocated when ≤1 subscriber\n *\n * Use when you need reactive state but don't need automatic effect dependency tracking.\n * Ideal for list item labels in keyed reconcilers where subscribe() is used directly.\n */\nexport class Cell<T> {\n /** @internal */ _v: T\n /** @internal */ _l: (() => void) | null = null // single-listener fast path\n /** @internal */ _s: Set<() => void> | null = null // multi-listener fallback\n\n constructor(value: T) {\n this._v = value\n }\n\n peek(): T {\n return this._v\n }\n\n set(value: T): void {\n if (Object.is(this._v, value)) return\n this._v = value\n if (this._l) this._l()\n else if (this._s) for (const fn of this._s) fn()\n }\n\n update(fn: (current: T) => T): void {\n this.set(fn(this._v))\n }\n\n /**\n * Fire-and-forget subscription — no unsubscribe returned.\n * Use when the listener's lifetime matches the cell's (e.g., list rows).\n * Saves 1 closure allocation per call vs subscribe().\n */\n listen(listener: () => void): void {\n if (!this._l && !this._s) {\n this._l = listener\n } else {\n // Promote to Set\n if (!this._s) {\n this._s = new Set()\n if (this._l) {\n this._s.add(this._l)\n this._l = null\n }\n }\n this._s.add(listener)\n }\n }\n\n subscribe(listener: () => void): () => void {\n this.listen(listener)\n if (this._l === listener) {\n return () => {\n if (this._l === listener) this._l = null\n }\n }\n return () => this._s?.delete(listener)\n }\n}\n\nexport function cell<T>(value: T): Cell<T> {\n return new Cell(value)\n}\n","// EffectScope — auto-tracks effects created during a component's setup\n// and disposes them all at once when the component unmounts.\n\nexport class EffectScope {\n private _effects: { dispose(): void }[] = []\n private _active = true\n private _updateHooks: (() => void)[] = []\n private _updatePending = false\n\n /** Register an effect/computed to be disposed when this scope stops. */\n add(e: { dispose(): void }): void {\n if (this._active) this._effects.push(e)\n }\n\n /**\n * Temporarily re-activate this scope so effects created inside `fn` are\n * auto-tracked and will be disposed when the scope stops.\n * Used to ensure effects created in `onMount` callbacks belong to their\n * component's scope rather than leaking as global effects.\n */\n runInScope<T>(fn: () => T): T {\n const prev = _currentScope\n _currentScope = this\n try {\n return fn()\n } finally {\n _currentScope = prev\n }\n }\n\n /** Register a callback to run after any reactive update in this scope. */\n addUpdateHook(fn: () => void): void {\n this._updateHooks.push(fn)\n }\n\n /**\n * Called by effects after each non-initial re-run.\n * Schedules onUpdate hooks via microtask so all synchronous effects settle first.\n */\n notifyEffectRan(): void {\n if (!this._active || this._updateHooks.length === 0 || this._updatePending) return\n this._updatePending = true\n queueMicrotask(() => {\n this._updatePending = false\n if (!this._active) return\n for (const fn of this._updateHooks) {\n try {\n fn()\n } catch (err) {\n console.error(\"[pyreon] onUpdate hook error:\", err)\n }\n }\n })\n }\n\n /** Dispose all tracked effects. */\n stop(): void {\n if (!this._active) return\n for (const e of this._effects) e.dispose()\n this._effects = []\n this._updateHooks = []\n this._updatePending = false\n this._active = false\n }\n}\n\nlet _currentScope: EffectScope | null = null\n\nexport function getCurrentScope(): EffectScope | null {\n return _currentScope\n}\n\nexport function setCurrentScope(scope: EffectScope | null): void {\n _currentScope = scope\n}\n\n/** Create a new EffectScope. */\nexport function effectScope(): EffectScope {\n return new EffectScope()\n}\n","// Global subscriber tracking context\n\nimport { enqueuePendingNotification, isBatching } from \"./batch\"\n\nlet activeEffect: (() => void) | null = null\n\n// Tracks which subscriber sets each effect is registered in, so we can\n// clean them up before a re-run (dynamic dependency tracking).\nconst effectDeps = new WeakMap<() => void, Set<Set<() => void>>>()\n\n// Fast deps collector for renderEffect — avoids WeakMap overhead entirely.\n// When set, trackSubscriber pushes subscriber sets here instead of effectDeps.\nlet _depsCollector: Set<() => void>[] | null = null\n\n// Skip deps collection mode — for re-evaluating computeds/effects with static deps.\n// When true, trackSubscriber only does Set.add (no-op if already subscribed) and skips\n// the _depsCollector.push / WeakMap work entirely.\nlet _skipDepsCollection = false\n\nexport function setDepsCollector(collector: Set<() => void>[] | null): void {\n _depsCollector = collector\n}\n\nexport function setSkipDepsCollection(skip: boolean): void {\n _skipDepsCollection = skip\n}\n\n/**\n * Subscriber host — any reactive source that can have downstream subscribers.\n * Signals, computeds, and createSelector buckets all implement this interface.\n * The Set is created lazily — only allocated when an effect actually tracks this source.\n */\nexport interface SubscriberHost {\n /** @internal subscriber set — null until first tracked by an effect */\n _s: Set<() => void> | null\n}\n\n/**\n * Register the active effect as a subscriber of the given reactive source.\n * The subscriber Set is created lazily on the host — sources read only outside\n * effects never allocate a Set.\n */\nexport function trackSubscriber(host: SubscriberHost) {\n if (activeEffect) {\n if (!host._s) host._s = new Set()\n host._s.add(activeEffect)\n // Skip collection mode: we're already subscribed (Set.add is no-op),\n // just need activeEffect set for nested computed reads to work.\n if (_skipDepsCollection) return\n if (_depsCollector) {\n // Fast path: renderEffect stores deps inline, no WeakMap\n _depsCollector.push(host._s)\n } else {\n // Record this dep so we can remove it on cleanup\n let deps = effectDeps.get(activeEffect)\n if (!deps) {\n deps = new Set()\n effectDeps.set(activeEffect, deps)\n }\n deps.add(host._s)\n }\n }\n}\n\n/**\n * Remove an effect from every subscriber set it was registered in,\n * then clear its dep record. Call this before each re-run and on dispose.\n */\nexport function cleanupEffect(fn: () => void): void {\n const deps = effectDeps.get(fn)\n if (deps) {\n for (const sub of deps) sub.delete(fn)\n deps.clear()\n }\n}\n\nexport function notifySubscribers(subscribers: Set<() => void>) {\n if (subscribers.size === 0) return\n // Single-subscriber fast path: avoid any iteration overhead.\n if (subscribers.size === 1) {\n const sub = subscribers.values().next().value as () => void\n if (isBatching()) enqueuePendingNotification(sub)\n else sub()\n return\n }\n if (isBatching()) {\n // Effects are queued not run inline — no re-entrancy risk, iterate the live Set directly.\n for (const sub of subscribers) enqueuePendingNotification(sub)\n } else {\n // Effects run inline and may call cleanupEffect (removes) + trackSubscriber (re-adds).\n // Instead of snapshotting with [...subscribers] (allocates an array), we iterate the\n // live Set but cap iterations at the original size to prevent infinite loops from\n // re-inserted entries. This is safe because:\n // - cleanupEffect removes the effect from the Set (no double-fire)\n // - trackSubscriber may re-add it (but we stop after originalSize iterations)\n // - Any effects re-added during this pass are already up-to-date (just ran)\n const originalSize = subscribers.size\n let i = 0\n for (const sub of subscribers) {\n if (i >= originalSize) break\n sub()\n i++\n }\n }\n}\n\nexport function withTracking<T>(fn: () => void, compute: () => T): T {\n const prev = activeEffect\n activeEffect = fn\n try {\n return compute()\n } finally {\n activeEffect = prev\n }\n}\n\n// Stack for inlined tracking in renderEffect — avoids withTracking function call overhead.\nlet _prevEffect: (() => void) | null = null\n\nexport function _setActiveEffect(fn: () => void): void {\n _prevEffect = activeEffect\n activeEffect = fn\n}\n\nexport function _restoreActiveEffect(): void {\n activeEffect = _prevEffect\n _prevEffect = null\n}\n\nexport function runUntracked<T>(fn: () => T): T {\n const prev = activeEffect\n activeEffect = null\n try {\n return fn()\n } finally {\n activeEffect = prev\n }\n}\n","import { getCurrentScope } from \"./scope\"\nimport {\n cleanupEffect,\n notifySubscribers,\n setDepsCollector,\n setSkipDepsCollection,\n trackSubscriber,\n withTracking,\n} from \"./tracking\"\n\nexport interface Computed<T> {\n (): T\n /** Remove this computed from all its reactive dependencies. */\n dispose(): void\n}\n\nexport interface ComputedOptions<T> {\n /**\n * Custom equality function. When provided, the computed eagerly re-evaluates\n * on dependency change and only notifies downstream if `equals(prev, next)`\n * returns false. Useful for derived objects/arrays to skip spurious updates.\n *\n * @example\n * const sorted = computed(() => items().slice().sort(), {\n * equals: (a, b) => a.length === b.length && a.every((v, i) => v === b[i])\n * })\n */\n equals?: (prev: T, next: T) => boolean\n}\n\n/** Remove a computed from all dependency subscriber sets (local deps array). */\nfunction cleanupLocalDeps(deps: Set<() => void>[], fn: () => void): void {\n for (let i = 0; i < deps.length; i++) (deps[i] as Set<() => void>).delete(fn)\n deps.length = 0\n}\n\n/** Re-track dependencies using the local deps array collector. */\nfunction trackWithLocalDeps<T>(deps: Set<() => void>[], effect: () => void, fn: () => T): T {\n setDepsCollector(deps)\n const result = withTracking(effect, fn)\n setDepsCollector(null)\n return result\n}\n\nexport function computed<T>(fn: () => T, options?: ComputedOptions<T>): Computed<T> {\n return options?.equals ? computedWithEquals(fn, options.equals) : computedLazy(fn)\n}\n\n/**\n * Default computed — lazy evaluation with deferred cleanup.\n *\n * On notification: just marks dirty and propagates (no cleanup/re-track).\n * On read: cleans up old deps, re-evaluates, re-tracks.\n *\n * The `if (dirty) return` early exit in recompute prevents double-propagation\n * in diamond patterns (a→b,c→d: b notifies d, c tries to notify d again —\n * skipped because d is already dirty).\n */\nfunction computedLazy<T>(fn: () => T): Computed<T> {\n let value: T\n let dirty = true\n let disposed = false\n let tracked = false\n const deps: Set<() => void>[] = []\n const host: { _s: Set<() => void> | null } = { _s: null }\n\n const recompute = () => {\n if (disposed || dirty) return\n dirty = true\n if (host._s) notifySubscribers(host._s)\n }\n\n const read = (): T => {\n trackSubscriber(host)\n if (dirty) {\n if (tracked) {\n // Static deps fast path: already subscribed to our deps from first run.\n // Set.add in trackSubscriber is a no-op for existing members.\n // Skip cleanup (Set.delete) and collection (array.push) entirely.\n setSkipDepsCollection(true)\n value = withTracking(recompute, fn)\n setSkipDepsCollection(false)\n } else {\n // First evaluation — full tracking to record deps for dispose\n value = trackWithLocalDeps(deps, recompute, fn)\n tracked = true\n }\n dirty = false\n }\n return value as T\n }\n\n read.dispose = () => {\n disposed = true\n cleanupLocalDeps(deps, recompute)\n }\n\n getCurrentScope()?.add({ dispose: read.dispose })\n return read\n}\n\n/**\n * Computed with custom equality — eager evaluation on notification.\n *\n * Re-evaluates immediately when deps change and only notifies downstream\n * if `equals(prev, next)` returns false.\n */\nfunction computedWithEquals<T>(fn: () => T, equals: (prev: T, next: T) => boolean): Computed<T> {\n let value: T\n let dirty = true\n let initialized = false\n let disposed = false\n const deps: Set<() => void>[] = []\n const host: { _s: Set<() => void> | null } = { _s: null }\n\n const recompute = () => {\n if (disposed) return\n cleanupLocalDeps(deps, recompute)\n const next = trackWithLocalDeps(deps, recompute, fn)\n if (initialized && equals(value as T, next)) return\n value = next\n dirty = false\n initialized = true\n if (host._s) notifySubscribers(host._s)\n }\n\n const read = (): T => {\n trackSubscriber(host)\n if (dirty) {\n cleanupLocalDeps(deps, recompute)\n value = trackWithLocalDeps(deps, recompute, fn)\n dirty = false\n initialized = true\n }\n return value as T\n }\n\n read.dispose = () => {\n disposed = true\n cleanupLocalDeps(deps, recompute)\n cleanupEffect(recompute)\n }\n\n getCurrentScope()?.add({ dispose: read.dispose })\n return read\n}\n","import { getCurrentScope } from \"./scope\"\nimport { _restoreActiveEffect, _setActiveEffect, setDepsCollector, withTracking } from \"./tracking\"\n\nexport interface Effect {\n dispose(): void\n}\n\n// Global error handler — called for unhandled errors thrown inside effects.\n// Defaults to console.error so silent failures are never swallowed.\nlet _errorHandler: (err: unknown) => void = (err) => {\n console.error(\"[pyreon] Unhandled effect error:\", err)\n}\n\nexport function setErrorHandler(fn: (err: unknown) => void): void {\n _errorHandler = fn\n}\n\n/** Remove an effect from all dependency subscriber sets (local deps array). */\nfunction cleanupLocalDeps(deps: Set<() => void>[], fn: () => void): void {\n if (deps.length === 1) {\n ;(deps[0] as Set<() => void>).delete(fn)\n deps.length = 0\n } else if (deps.length > 1) {\n for (let i = 0; i < deps.length; i++) (deps[i] as Set<() => void>).delete(fn)\n deps.length = 0\n }\n}\n\n// biome-ignore lint/suspicious/noConfusingVoidType: void is intentional — callbacks that return nothing must be assignable\nexport function effect(fn: () => (() => void) | void): Effect {\n // Capture the scope at creation time — remains correct during future re-runs\n // even after setCurrentScope(null) has been called post-setup.\n const scope = getCurrentScope()\n let disposed = false\n let isFirstRun = true\n let cleanup: (() => void) | undefined\n // Local deps array — avoids WeakMap overhead (like renderEffect)\n const deps: Set<() => void>[] = []\n\n const runCleanup = () => {\n if (typeof cleanup === \"function\") {\n try {\n cleanup()\n } catch (err) {\n _errorHandler(err)\n }\n cleanup = undefined\n }\n }\n\n const run = () => {\n if (disposed) return\n // Run previous cleanup before re-running\n runCleanup()\n try {\n cleanupLocalDeps(deps, run)\n setDepsCollector(deps)\n cleanup = withTracking(run, fn) || undefined\n setDepsCollector(null)\n } catch (err) {\n setDepsCollector(null)\n _errorHandler(err)\n }\n // Notify scope after each reactive re-run (not the initial synchronous run)\n // so onUpdate hooks fire after the DOM has settled.\n if (!isFirstRun) scope?.notifyEffectRan()\n isFirstRun = false\n }\n\n run()\n\n const e: Effect = {\n dispose() {\n runCleanup()\n disposed = true\n cleanupLocalDeps(deps, run)\n },\n }\n\n // Auto-register with the active EffectScope (if any)\n getCurrentScope()?.add(e)\n\n return e\n}\n\n/**\n * Lightweight effect for DOM render bindings.\n *\n * Differences from `effect()`:\n * - No EffectScope registration (caller owns the dispose lifecycle)\n * - No error handler (errors propagate naturally)\n * - No onUpdate notification\n * - Deps stored in a local array instead of the global WeakMap — faster\n * creation and disposal (~200ns saved per effect vs WeakMap path)\n *\n * Returns a dispose function (not an Effect object — saves 1 allocation).\n */\n/**\n * Static-dep binding — compiler helper for template expressions.\n *\n * Like renderEffect but assumes dependencies never change (true for all\n * compiler-emitted template bindings like `_tpl()` text/attribute updates).\n *\n * Tracks dependencies only on the first run. Re-runs skip cleanup, re-tracking,\n * and tracking context save/restore entirely — just calls `fn()` directly.\n *\n * Per re-run savings vs renderEffect:\n * - No deps iteration + Set.delete (cleanup)\n * - No setDepsCollector + withTracking (re-registration)\n * - Signal reads hit `if (activeEffect)` null check → instant return\n */\nexport function _bind(fn: () => void): () => void {\n const deps: Set<() => void>[] = []\n let disposed = false\n\n const run = () => {\n if (disposed) return\n fn()\n }\n\n // First run: track deps so we know what to unsubscribe on dispose\n setDepsCollector(deps)\n withTracking(run, fn)\n setDepsCollector(null)\n\n const dispose = () => {\n if (disposed) return\n disposed = true\n for (const s of deps) s.delete(run)\n deps.length = 0\n }\n\n // Auto-register with scope so template bindings are disposed during teardown\n getCurrentScope()?.add({ dispose })\n\n return dispose\n}\n\n/** Full re-track path for renderEffect: cleanup old deps, evaluate with tracking. */\nfunction renderEffectFullTrack(deps: Set<() => void>[], run: () => void, fn: () => void): void {\n if (deps.length === 1) {\n ;(deps[0] as Set<() => void>).delete(run)\n deps.length = 0\n } else if (deps.length > 1) {\n for (const s of deps) s.delete(run)\n deps.length = 0\n }\n setDepsCollector(deps)\n _setActiveEffect(run)\n try {\n fn()\n } finally {\n _restoreActiveEffect()\n setDepsCollector(null)\n }\n}\n\nexport function renderEffect(fn: () => void): () => void {\n const deps: Set<() => void>[] = []\n let disposed = false\n\n const run = () => {\n if (disposed) return\n renderEffectFullTrack(deps, run, fn)\n }\n\n run()\n\n const dispose = () => {\n if (disposed) return\n disposed = true\n if (deps.length === 1) {\n ;(deps[0] as Set<() => void>).delete(run)\n } else {\n for (const s of deps) s.delete(run)\n }\n deps.length = 0\n }\n\n // Auto-register with scope so render effects are disposed during teardown\n getCurrentScope()?.add({ dispose })\n\n return dispose\n}\n","import { effect } from \"./effect\"\nimport { trackSubscriber } from \"./tracking\"\n\n/**\n * Notify a subscriber bucket without snapshot allocation.\n * Caps iteration at the original size to avoid infinite loops from\n * re-inserted entries (same pattern as notifySubscribers in tracking.ts).\n */\nfunction notifyBucket(bucket: Set<() => void>): void {\n if (bucket.size === 0) return\n if (bucket.size === 1) {\n ;(bucket.values().next().value as () => void)()\n return\n }\n const originalSize = bucket.size\n let i = 0\n for (const fn of bucket) {\n if (i >= originalSize) break\n fn()\n i++\n }\n}\n\n/**\n * Create an equality selector — returns a reactive predicate that is true\n * only for the currently selected value.\n *\n * Unlike a plain `() => source() === value`, this only triggers the TWO\n * affected subscribers (deselected + newly selected) instead of ALL\n * subscribers, making selection O(1) regardless of list size.\n *\n * @example\n * const isSelected = createSelector(selectedId)\n * // In each row:\n * class: () => (isSelected(row.id) ? \"selected\" : \"\")\n */\nexport function createSelector<T>(source: () => T): (value: T) => boolean {\n const subs = new Map<T, Set<() => void>>()\n let current: T\n let initialized = false\n\n effect(() => {\n const next = source()\n if (!initialized) {\n initialized = true\n current = next\n return\n }\n if (Object.is(next, current)) return\n const old = current\n current = next\n // Only notify the two affected buckets — O(1) regardless of list size.\n // Iteration-capped loop avoids [...bucket] snapshot allocation.\n const oldBucket = subs.get(old)\n const newBucket = subs.get(next)\n if (oldBucket) notifyBucket(oldBucket)\n if (newBucket) notifyBucket(newBucket)\n })\n\n // Reusable hosts per value — avoids allocating a closure per trackSubscriber call\n const hosts = new Map<T, { _s: Set<() => void> | null }>()\n\n return (value: T): boolean => {\n let host = hosts.get(value)\n if (!host) {\n let bucket = subs.get(value)\n if (!bucket) {\n bucket = new Set()\n subs.set(value, bucket)\n }\n host = { _s: bucket }\n hosts.set(value, host)\n }\n trackSubscriber(host)\n return Object.is(current, value)\n }\n}\n","/**\n * @pyreon/reactivity debug utilities.\n *\n * Development-only tools for tracing signal updates, inspecting reactive\n * graphs, and understanding why DOM nodes re-render.\n *\n * All utilities are tree-shakeable — they compile away in production builds\n * when unused.\n */\n\nimport type { Signal, SignalDebugInfo } from \"./signal\"\n\n// ─── Signal update tracing ───────────────────────────────────────────────────\n\ninterface SignalUpdateEvent {\n /** The signal that changed */\n signal: Signal<unknown>\n /** Signal name (from options or label) */\n name: string | undefined\n /** Previous value */\n prev: unknown\n /** New value */\n next: unknown\n /** Stack trace at the point of the .set() / .update() call */\n stack: string\n /** Timestamp */\n timestamp: number\n}\n\ntype SignalUpdateListener = (event: SignalUpdateEvent) => void\n\nlet _traceListeners: SignalUpdateListener[] | null = null\n\n/**\n * Register a listener that fires on every signal write.\n * Returns a dispose function.\n *\n * @example\n * const dispose = onSignalUpdate(e => {\n * console.log(`${e.name ?? 'anonymous'}: ${e.prev} → ${e.next}`)\n * })\n */\nexport function onSignalUpdate(listener: SignalUpdateListener): () => void {\n if (!_traceListeners) _traceListeners = []\n _traceListeners.push(listener)\n return () => {\n if (!_traceListeners) return\n _traceListeners = _traceListeners.filter((l) => l !== listener)\n if (_traceListeners.length === 0) _traceListeners = null\n }\n}\n\n/** @internal — called from signal.set() when tracing is active */\nexport function _notifyTraceListeners(sig: Signal<unknown>, prev: unknown, next: unknown): void {\n if (!_traceListeners) return\n const event: SignalUpdateEvent = {\n signal: sig,\n name: sig.label,\n prev,\n next,\n stack: new Error().stack ?? \"\",\n timestamp: performance.now(),\n }\n for (const l of _traceListeners) l(event)\n}\n\n/** Check if any trace listeners are active (fast path for signal.set) */\nexport function isTracing(): boolean {\n return _traceListeners !== null\n}\n\n// ─── why() — trace which signal caused a re-run ──────────────────────────────\n\nlet _whyActive = false\nlet _whyLog: { name: string | undefined; prev: unknown; next: unknown }[] = []\n\n/**\n * Trace the next signal update. Logs which signals fire and what changed.\n * Call before triggering a state change to see what updates and why.\n *\n * @example\n * why()\n * count.set(5)\n * // Console: [pyreon:why] \"count\": 3 → 5 (2 subscribers)\n */\nexport function why(): void {\n if (_whyActive) return\n _whyActive = true\n _whyLog = []\n\n const dispose = onSignalUpdate((e) => {\n const _subCount = (e.signal as unknown as { _s: Set<unknown> | null })._s?.size ?? 0\n const _name = e.name ? `\"${e.name}\"` : \"(anonymous signal)\"\n\n console.log(\n `[pyreon:why] ${_name}: ${JSON.stringify(e.prev)} → ${JSON.stringify(e.next)} (${_subCount} subscriber${_subCount === 1 ? \"\" : \"s\"})`,\n )\n _whyLog.push({ name: e.name, prev: e.prev, next: e.next })\n })\n\n // Auto-dispose after the current microtask (captures the synchronous batch)\n queueMicrotask(() => {\n dispose()\n if (_whyLog.length === 0) {\n console.log(\"[pyreon:why] No signal updates detected\")\n }\n _whyActive = false\n _whyLog = []\n })\n}\n\n// ─── inspectSignal — rich console output ─────────────────────────────────────\n\n/**\n * Print a signal's current state to the console in a readable format.\n *\n * @example\n * const count = signal(42, { name: \"count\" })\n * inspectSignal(count)\n * // Console:\n * // 🔍 Signal \"count\"\n * // value: 42\n * // subscribers: 3\n */\nexport function inspectSignal<T>(sig: Signal<T>): SignalDebugInfo<T> {\n const info = sig.debug()\n\n console.group(`🔍 Signal ${info.name ? `\"${info.name}\"` : \"(anonymous)\"}`)\n console.log(\"value:\", info.value)\n console.log(\"subscribers:\", info.subscriberCount)\n console.groupEnd()\n\n return info\n}\n","import { enqueuePendingNotification, isBatching } from \"./batch\"\nimport { _notifyTraceListeners, isTracing } from \"./debug\"\nimport { notifySubscribers, trackSubscriber } from \"./tracking\"\n\nexport interface SignalDebugInfo<T> {\n /** Signal name (set via options or inferred) */\n name: string | undefined\n /** Current value (same as peek()) */\n value: T\n /** Number of active subscribers */\n subscriberCount: number\n}\n\n/**\n * Read-only reactive value — the common interface that both Signal and Computed satisfy.\n * Use this as the parameter type when a function only needs to read a reactive value.\n */\nexport interface ReadonlySignal<T> {\n (): T\n}\n\nexport interface Signal<T> {\n (): T\n /** Read the current value WITHOUT registering a reactive dependency. */\n peek(): T\n set(value: T): void\n update(fn: (current: T) => T): void\n /**\n * Subscribe a static listener directly — no effect overhead (no withTracking,\n * no cleanupEffect, no effectDeps WeakMap). Use when the dependency is fixed\n * and dynamic re-tracking is not needed.\n * Returns a disposer that removes the subscription.\n */\n subscribe(listener: () => void): () => void\n /**\n * Register a direct updater — even lighter than subscribe().\n * Uses a flat array instead of Set. Disposal nulls the slot (no Set.delete).\n * Intended for compiler-emitted DOM bindings (_bindText, _bindDirect).\n * Returns a disposer that nulls the slot.\n */\n direct(updater: () => void): () => void\n /** Debug name — useful for devtools and logging. */\n label: string | undefined\n /** Returns a snapshot of the signal's debug info (value, name, subscriber count). */\n debug(): SignalDebugInfo<T>\n}\n\nexport interface SignalOptions {\n /** Debug name for this signal — shows up in devtools and debug() output. */\n name?: string\n}\n\n// Internal shape of a signal function — state stored as properties on the\n// function object so methods can be shared via assignment (not per-signal closures).\ninterface SignalFn<T> {\n (): T\n /** @internal current value */\n _v: T\n /** @internal subscriber set (lazily allocated by trackSubscriber) */\n _s: Set<() => void> | null\n /** @internal direct updaters array — compiler-emitted DOM updaters (lazily allocated) */\n _d: ((() => void) | null)[] | null\n peek(): T\n set(value: T): void\n update(fn: (current: T) => T): void\n subscribe(listener: () => void): () => void\n /** Register a direct updater — lighter than subscribe, uses array index disposal. */\n direct(updater: () => void): () => void\n label: string | undefined\n debug(): SignalDebugInfo<T>\n}\n\n// Shared method implementations — defined once, assigned to every signal.\n// Uses `this` binding (signal methods are always called as `signal.method()`).\nfunction _peek(this: SignalFn<unknown>) {\n return this._v\n}\n\nfunction _set(this: SignalFn<unknown>, newValue: unknown) {\n if (Object.is(this._v, newValue)) return\n const prev = this._v\n this._v = newValue\n if (isTracing()) _notifyTraceListeners(this as unknown as Signal<unknown>, prev, newValue)\n // Direct updaters — flat array, no Set overhead, batch-aware\n if (this._d) notifyDirect(this._d)\n if (this._s) notifySubscribers(this._s)\n}\n\nfunction _update(this: SignalFn<unknown>, fn: (current: unknown) => unknown) {\n _set.call(this, fn(this._v))\n}\n\nfunction _subscribe(this: SignalFn<unknown>, listener: () => void): () => void {\n if (!this._s) this._s = new Set()\n this._s.add(listener)\n return () => this._s?.delete(listener)\n}\n\n/**\n * Register a direct updater — lighter than subscribe().\n * Uses a flat array instead of Set. Disposal nulls the slot (no Set.delete overhead).\n * Used by compiler-emitted _bindText/_bindDirect for zero-overhead DOM bindings.\n */\nfunction _directFn(this: SignalFn<unknown>, updater: () => void): () => void {\n if (!this._d) this._d = []\n const arr = this._d\n const idx = arr.length\n arr.push(updater)\n return () => {\n arr[idx] = null\n }\n}\n\n/**\n * Notify direct updaters — flat array iteration, batch-aware.\n * Null slots (from disposed updaters) are skipped.\n */\nfunction notifyDirect(updaters: ((() => void) | null)[]): void {\n if (isBatching()) {\n for (let i = 0; i < updaters.length; i++) {\n const fn = updaters[i]\n if (fn) enqueuePendingNotification(fn)\n }\n } else {\n for (let i = 0; i < updaters.length; i++) {\n updaters[i]?.()\n }\n }\n}\n\nfunction _debug(this: SignalFn<unknown>): SignalDebugInfo<unknown> {\n return {\n name: this.label,\n value: this._v,\n subscriberCount: this._s?.size ?? 0,\n }\n}\n\n/**\n * Create a reactive signal.\n *\n * Only 1 closure is allocated (the read function). State is stored as\n * properties on the function object (_v, _s) and methods (peek, set,\n * update, subscribe) are shared across all signals — not per-signal closures.\n */\nexport function signal<T>(initialValue: T, options?: SignalOptions): Signal<T> {\n // The read function is the only per-signal closure.\n // It doubles as the SubscriberHost (_s property) for trackSubscriber.\n const read = (() => {\n trackSubscriber(read as SignalFn<T>)\n return read._v\n }) as unknown as SignalFn<T>\n\n read._v = initialValue\n read._s = null\n read._d = null\n read.peek = _peek as () => T\n read.set = _set as (value: T) => void\n read.update = _update as (fn: (current: T) => T) => void\n read.subscribe = _subscribe as (listener: () => void) => () => void\n read.direct = _directFn as (updater: () => void) => () => void\n read.debug = _debug as () => SignalDebugInfo<T>\n read.label = options?.name\n\n return read as unknown as Signal<T>\n}\n","/**\n * createStore — deep reactive Proxy store.\n *\n * Wraps a plain object/array in a Proxy that creates a fine-grained signal for\n * every property. Direct mutations (`store.count++`, `store.items[0].label = \"x\"`)\n * trigger only the signals for the mutated properties — not the whole tree.\n *\n * @example\n * const state = createStore({ count: 0, items: [{ id: 1, text: \"hello\" }] })\n *\n * effect(() => console.log(state.count)) // tracks state.count only\n * state.count++ // only the count effect re-runs\n * state.items[0].text = \"world\" // only text-tracking effects re-run\n */\n\nimport { type Signal, signal } from \"./signal\"\n\n// WeakMap: raw object → its reactive proxy (ensures each raw object gets one proxy)\nconst proxyCache = new WeakMap<object, object>()\n\nconst IS_STORE = Symbol(\"pyreon.store\")\n\n/** Returns true if the value is a createStore proxy. */\nexport function isStore(value: unknown): boolean {\n return (\n value !== null &&\n typeof value === \"object\" &&\n (value as Record<symbol, unknown>)[IS_STORE] === true\n )\n}\n\n/**\n * Create a deep reactive store from a plain object or array.\n * Returns a proxy — mutations to the proxy trigger fine-grained reactive updates.\n */\nexport function createStore<T extends object>(initial: T): T {\n return wrap(initial) as T\n}\n\nfunction wrap(raw: object): object {\n const cached = proxyCache.get(raw)\n if (cached) return cached\n\n // Per-property signals. Lazily created on first access.\n const propSignals = new Map<PropertyKey, Signal<unknown>>()\n // For arrays: track length changes separately (push/pop/splice affect length)\n const isArray = Array.isArray(raw)\n const lengthSig = isArray ? signal((raw as unknown[]).length) : null\n\n function getOrCreateSignal(key: PropertyKey): Signal<unknown> {\n if (!propSignals.has(key)) {\n propSignals.set(key, signal((raw as Record<PropertyKey, unknown>)[key]))\n }\n return propSignals.get(key) as Signal<unknown>\n }\n\n const proxy = new Proxy(raw, {\n get(target, key) {\n // Pass through the identity marker and non-string/number keys (symbols, etc.)\n if (key === IS_STORE) return true\n if (typeof key === \"symbol\") return (target as Record<symbol, unknown>)[key]\n\n // Array length — tracked via dedicated signal for push/pop/splice reactivity\n if (isArray && key === \"length\") return lengthSig?.()\n\n // Non-own properties: prototype methods (forEach, map, push, …)\n // These must be returned untracked so array methods work normally.\n // Array methods will then go through set/get on indices via the proxy.\n if (!Object.hasOwn(target, key)) {\n return (target as Record<PropertyKey, unknown>)[key]\n }\n\n // Track via per-property signal\n const value = getOrCreateSignal(key)()\n\n // Deep reactivity: wrap nested objects/arrays transparently\n if (value !== null && typeof value === \"object\") {\n return wrap(value as object)\n }\n\n return value\n },\n\n set(target, key, value) {\n if (typeof key === \"symbol\") {\n ;(target as Record<symbol, unknown>)[key] = value\n return true\n }\n\n const prevLength = isArray ? (target as unknown[]).length : 0\n ;(target as Record<PropertyKey, unknown>)[key] = value\n\n // Array length set directly (e.g. arr.length = 0)\n if (isArray && key === \"length\") {\n lengthSig?.set(value as number)\n return true\n }\n\n // Update or create signal for this property\n if (propSignals.has(key)) {\n propSignals.get(key)?.set(value)\n } else {\n propSignals.set(key, signal(value))\n }\n\n // If array length changed (e.g. via push/splice index assignment), update it\n if (isArray && (target as unknown[]).length !== prevLength) {\n lengthSig?.set((target as unknown[]).length)\n }\n\n return true\n },\n\n deleteProperty(target, key) {\n delete (target as Record<PropertyKey, unknown>)[key]\n if (typeof key !== \"symbol\" && propSignals.has(key)) {\n propSignals.get(key)?.set(undefined)\n propSignals.delete(key)\n }\n if (isArray) lengthSig?.set((target as unknown[]).length)\n return true\n },\n\n has(target, key) {\n return Reflect.has(target, key)\n },\n\n ownKeys(target) {\n return Reflect.ownKeys(target)\n },\n\n getOwnPropertyDescriptor(target, key) {\n return Reflect.getOwnPropertyDescriptor(target, key)\n },\n })\n\n proxyCache.set(raw, proxy)\n return proxy\n}\n","/**\n * reconcile — surgically diff new state into an existing createStore proxy.\n *\n * Instead of replacing the store root (which would trigger all downstream effects),\n * reconcile walks both the new value and the store in parallel and only calls\n * `.set()` on signals whose value actually changed.\n *\n * Ideal for applying API responses to a long-lived store:\n *\n * @example\n * const state = createStore({ user: { name: \"Alice\", age: 30 }, items: [] })\n *\n * // API response arrives:\n * reconcile({ user: { name: \"Alice\", age: 31 }, items: [{ id: 1 }] }, state)\n * // → only state.user.age signal fires (name unchanged)\n * // → state.items[0] is newly created\n *\n * Arrays are reconciled by index — elements at the same index are recursively\n * diffed rather than replaced wholesale. Excess old elements are removed.\n */\n\nimport { isStore } from \"./store\"\n\ntype AnyObject = Record<PropertyKey, unknown>\n\nexport function reconcile<T extends object>(source: T, target: T): void {\n _reconcileInner(source, target, new WeakSet())\n}\n\nfunction _reconcileInner(source: object, target: object, seen: WeakSet<object>): void {\n if (seen.has(source)) return // circular reference — stop recursion\n seen.add(source)\n if (Array.isArray(source) && Array.isArray(target)) {\n _reconcileArray(source as unknown[], target as unknown[], seen)\n } else {\n _reconcileObject(source as AnyObject, target as AnyObject, seen)\n }\n}\n\nfunction _reconcileArray(source: unknown[], target: unknown[], seen: WeakSet<object>): void {\n const targetLen = target.length\n const sourceLen = source.length\n\n // Update / add entries\n for (let i = 0; i < sourceLen; i++) {\n const sv = source[i]\n const tv = (target as unknown[])[i]\n\n if (\n i < targetLen &&\n sv !== null &&\n typeof sv === \"object\" &&\n tv !== null &&\n typeof tv === \"object\"\n ) {\n // Both sides are objects — recurse\n _reconcileInner(sv as object, tv as object, seen)\n } else {\n // Scalar or new entry — write directly (signal will skip if equal via Object.is)\n ;(target as unknown[])[i] = sv\n }\n }\n\n // Trim excess entries\n if (targetLen > sourceLen) {\n target.length = sourceLen\n }\n}\n\nfunction _reconcileObject(source: AnyObject, target: AnyObject, seen: WeakSet<object>): void {\n const sourceKeys = Object.keys(source)\n const targetKeys = new Set(Object.keys(target))\n\n for (const key of sourceKeys) {\n const sv = source[key]\n const tv = target[key]\n\n if (sv !== null && typeof sv === \"object\" && tv !== null && typeof tv === \"object\") {\n if (isStore(tv)) {\n // Both objects — recurse into the store node\n _reconcileInner(sv as object, tv as object, seen)\n } else {\n // Target is a raw object (not yet proxied) — just assign\n target[key] = sv\n }\n } else {\n // Scalar: assign (store proxy's set trap skips if Object.is equal)\n target[key] = sv\n }\n\n targetKeys.delete(key)\n }\n\n // Remove keys that no longer exist in source\n for (const key of targetKeys) {\n delete target[key]\n }\n}\n","import { effect } from \"./effect\"\nimport type { Signal } from \"./signal\"\nimport { signal } from \"./signal\"\nimport { runUntracked } from \"./tracking\"\n\nexport interface Resource<T> {\n /** The latest resolved value (undefined while loading or on error). */\n data: Signal<T | undefined>\n /** True while a fetch is in flight. */\n loading: Signal<boolean>\n /** The last error thrown by the fetcher, or undefined. */\n error: Signal<unknown>\n /** Re-run the fetcher with the current source value. */\n refetch(): void\n}\n\n/**\n * Async data primitive. Fetches data reactively whenever `source()` changes.\n *\n * @example\n * const userId = signal(1)\n * const user = createResource(userId, (id) => fetchUser(id))\n * // user.data() — the fetched user (undefined while loading)\n * // user.loading() — true while in flight\n * // user.error() — last error\n */\nexport function createResource<T, P>(\n source: () => P,\n fetcher: (param: P) => Promise<T>,\n): Resource<T> {\n const data = signal<T | undefined>(undefined)\n const loading = signal(false)\n const error = signal<unknown>(undefined)\n let requestId = 0\n\n const doFetch = (param: P) => {\n const id = ++requestId\n loading.set(true)\n error.set(undefined)\n fetcher(param)\n .then((result) => {\n if (id !== requestId) return\n data.set(result)\n loading.set(false)\n })\n .catch((err: unknown) => {\n if (id !== requestId) return\n error.set(err)\n loading.set(false)\n })\n }\n\n effect(() => {\n const param = source()\n runUntracked(() => doFetch(param))\n })\n\n return {\n data,\n loading,\n error,\n refetch() {\n runUntracked(() => doFetch(source()))\n },\n }\n}\n","import { effect } from \"./effect\"\n\nexport interface WatchOptions {\n /** If true, call the callback immediately with the current value on setup. Default: false. */\n immediate?: boolean\n}\n\n/**\n * Watch a reactive source and run a callback whenever it changes.\n *\n * Returns a stop function that disposes the watcher.\n *\n * The callback receives (newValue, oldValue). On the first call (when\n * `immediate` is true) oldValue is `undefined`.\n *\n * The callback may return a cleanup function that is called before each\n * re-run and on stop — useful for cancelling async work.\n *\n * @example\n * const stop = watch(\n * () => userId(),\n * async (id, prev) => {\n * const data = await fetch(`/api/user/${id}`)\n * setUser(await data.json())\n * },\n * )\n * // Later: stop()\n */\nexport function watch<T>(\n source: () => T,\n // biome-ignore lint/suspicious/noConfusingVoidType: void is intentional — callers may return void\n callback: (newVal: T, oldVal: T | undefined) => void | (() => void),\n opts: WatchOptions = {},\n): () => void {\n let oldVal: T | undefined\n let isFirst = true\n let cleanupFn: (() => void) | undefined\n\n const e = effect(() => {\n const newVal = source()\n\n if (isFirst) {\n isFirst = false\n oldVal = newVal\n if (opts.immediate) {\n const result = callback(newVal, undefined)\n if (typeof result === \"function\") cleanupFn = result\n }\n return\n }\n\n if (cleanupFn) {\n cleanupFn()\n cleanupFn = undefined\n }\n\n const result = callback(newVal, oldVal)\n if (typeof result === \"function\") cleanupFn = result\n oldVal = newVal\n })\n\n return () => {\n e.dispose()\n if (cleanupFn) {\n cleanupFn()\n cleanupFn = undefined\n }\n }\n}\n"],"mappings":"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"}
@@ -4,7 +4,7 @@ function batch(fn) {
4
4
  fn();
5
5
  } finally {
6
6
  batchDepth--;
7
- if (batchDepth === 0) {
7
+ if (batchDepth === 0 && pendingNotifications.size > 0) {
8
8
  const flush = pendingNotifications;
9
9
  pendingNotifications = flush === setA ? setB : setA;
10
10
  for (const notify of flush) notify();
@@ -70,6 +70,9 @@ function effectScope() {
70
70
  function setDepsCollector(collector) {
71
71
  _depsCollector = collector;
72
72
  }
73
+ function setSkipDepsCollection(skip) {
74
+ _skipDepsCollection = skip;
75
+ }
73
76
  /**
74
77
  * Register the active effect as a subscriber of the given reactive source.
75
78
  * The subscriber Set is created lazily on the host — sources read only outside
@@ -78,15 +81,15 @@ function setDepsCollector(collector) {
78
81
  function trackSubscriber(host) {
79
82
  if (activeEffect) {
80
83
  if (!host._s) host._s = /* @__PURE__ */new Set();
81
- const subscribers = host._s;
82
- subscribers.add(activeEffect);
83
- if (_depsCollector) _depsCollector.push(subscribers);else {
84
+ host._s.add(activeEffect);
85
+ if (_skipDepsCollection) return;
86
+ if (_depsCollector) _depsCollector.push(host._s);else {
84
87
  let deps = effectDeps.get(activeEffect);
85
88
  if (!deps) {
86
89
  deps = /* @__PURE__ */new Set();
87
90
  effectDeps.set(activeEffect, deps);
88
91
  }
89
- deps.add(subscribers);
92
+ deps.add(host._s);
90
93
  }
91
94
  }
92
95
  }
@@ -147,34 +150,99 @@ function runUntracked(fn) {
147
150
 
148
151
  //#endregion
149
152
  //#region src/computed.ts
153
+ /** Remove a computed from all dependency subscriber sets (local deps array). */
154
+ function cleanupLocalDeps$1(deps, fn) {
155
+ for (let i = 0; i < deps.length; i++) deps[i].delete(fn);
156
+ deps.length = 0;
157
+ }
158
+ /** Re-track dependencies using the local deps array collector. */
159
+ function trackWithLocalDeps(deps, effect, fn) {
160
+ setDepsCollector(deps);
161
+ const result = withTracking(effect, fn);
162
+ setDepsCollector(null);
163
+ return result;
164
+ }
150
165
  function computed(fn, options) {
166
+ return options?.equals ? computedWithEquals(fn, options.equals) : computedLazy(fn);
167
+ }
168
+ /**
169
+ * Default computed — lazy evaluation with deferred cleanup.
170
+ *
171
+ * On notification: just marks dirty and propagates (no cleanup/re-track).
172
+ * On read: cleans up old deps, re-evaluates, re-tracks.
173
+ *
174
+ * The `if (dirty) return` early exit in recompute prevents double-propagation
175
+ * in diamond patterns (a→b,c→d: b notifies d, c tries to notify d again —
176
+ * skipped because d is already dirty).
177
+ */
178
+ function computedLazy(fn) {
151
179
  let value;
152
180
  let dirty = true;
153
- let initialized = false;
154
181
  let disposed = false;
155
- const customEquals = options?.equals;
182
+ let tracked = false;
183
+ const deps = [];
156
184
  const host = {
157
185
  _s: null
158
186
  };
159
187
  const recompute = () => {
160
- if (disposed) return;
161
- cleanupEffect(recompute);
162
- if (customEquals) {
163
- const next = withTracking(recompute, fn);
164
- if (initialized && customEquals(value, next)) return;
165
- value = next;
188
+ if (disposed || dirty) return;
189
+ dirty = true;
190
+ if (host._s) notifySubscribers(host._s);
191
+ };
192
+ const read = () => {
193
+ trackSubscriber(host);
194
+ if (dirty) {
195
+ if (tracked) {
196
+ setSkipDepsCollection(true);
197
+ value = withTracking(recompute, fn);
198
+ setSkipDepsCollection(false);
199
+ } else {
200
+ value = trackWithLocalDeps(deps, recompute, fn);
201
+ tracked = true;
202
+ }
166
203
  dirty = false;
167
- initialized = true;
168
- if (host._s) notifySubscribers(host._s);
169
- } else {
170
- dirty = true;
171
- if (host._s) notifySubscribers(host._s);
172
204
  }
205
+ return value;
206
+ };
207
+ read.dispose = () => {
208
+ disposed = true;
209
+ cleanupLocalDeps$1(deps, recompute);
210
+ };
211
+ getCurrentScope()?.add({
212
+ dispose: read.dispose
213
+ });
214
+ return read;
215
+ }
216
+ /**
217
+ * Computed with custom equality — eager evaluation on notification.
218
+ *
219
+ * Re-evaluates immediately when deps change and only notifies downstream
220
+ * if `equals(prev, next)` returns false.
221
+ */
222
+ function computedWithEquals(fn, equals) {
223
+ let value;
224
+ let dirty = true;
225
+ let initialized = false;
226
+ let disposed = false;
227
+ const deps = [];
228
+ const host = {
229
+ _s: null
230
+ };
231
+ const recompute = () => {
232
+ if (disposed) return;
233
+ cleanupLocalDeps$1(deps, recompute);
234
+ const next = trackWithLocalDeps(deps, recompute, fn);
235
+ if (initialized && equals(value, next)) return;
236
+ value = next;
237
+ dirty = false;
238
+ initialized = true;
239
+ if (host._s) notifySubscribers(host._s);
173
240
  };
174
241
  const read = () => {
175
242
  trackSubscriber(host);
176
243
  if (dirty) {
177
- value = withTracking(recompute, fn);
244
+ cleanupLocalDeps$1(deps, recompute);
245
+ value = trackWithLocalDeps(deps, recompute, fn);
178
246
  dirty = false;
179
247
  initialized = true;
180
248
  }
@@ -182,6 +250,7 @@ function computed(fn, options) {
182
250
  };
183
251
  read.dispose = () => {
184
252
  disposed = true;
253
+ cleanupLocalDeps$1(deps, recompute);
185
254
  cleanupEffect(recompute);
186
255
  };
187
256
  getCurrentScope()?.add({
@@ -196,11 +265,22 @@ function computed(fn, options) {
196
265
  function setErrorHandler(fn) {
197
266
  _errorHandler = fn;
198
267
  }
268
+ /** Remove an effect from all dependency subscriber sets (local deps array). */
269
+ function cleanupLocalDeps(deps, fn) {
270
+ if (deps.length === 1) {
271
+ deps[0].delete(fn);
272
+ deps.length = 0;
273
+ } else if (deps.length > 1) {
274
+ for (let i = 0; i < deps.length; i++) deps[i].delete(fn);
275
+ deps.length = 0;
276
+ }
277
+ }
199
278
  function effect(fn) {
200
279
  const scope = getCurrentScope();
201
280
  let disposed = false;
202
281
  let isFirstRun = true;
203
282
  let cleanup;
283
+ const deps = [];
204
284
  const runCleanup = () => {
205
285
  if (typeof cleanup === "function") {
206
286
  try {
@@ -214,10 +294,13 @@ function effect(fn) {
214
294
  const run = () => {
215
295
  if (disposed) return;
216
296
  runCleanup();
217
- cleanupEffect(run);
218
297
  try {
298
+ cleanupLocalDeps(deps, run);
299
+ setDepsCollector(deps);
219
300
  cleanup = withTracking(run, fn) || void 0;
301
+ setDepsCollector(null);
220
302
  } catch (err) {
303
+ setDepsCollector(null);
221
304
  _errorHandler(err);
222
305
  }
223
306
  if (!isFirstRun) scope?.notifyEffectRan();
@@ -228,7 +311,7 @@ function effect(fn) {
228
311
  dispose() {
229
312
  runCleanup();
230
313
  disposed = true;
231
- cleanupEffect(run);
314
+ cleanupLocalDeps(deps, run);
232
315
  }
233
316
  };
234
317
  getCurrentScope()?.add(e);
@@ -281,26 +364,30 @@ function _bind(fn) {
281
364
  });
282
365
  return dispose;
283
366
  }
367
+ /** Full re-track path for renderEffect: cleanup old deps, evaluate with tracking. */
368
+ function renderEffectFullTrack(deps, run, fn) {
369
+ if (deps.length === 1) {
370
+ deps[0].delete(run);
371
+ deps.length = 0;
372
+ } else if (deps.length > 1) {
373
+ for (const s of deps) s.delete(run);
374
+ deps.length = 0;
375
+ }
376
+ setDepsCollector(deps);
377
+ _setActiveEffect(run);
378
+ try {
379
+ fn();
380
+ } finally {
381
+ _restoreActiveEffect();
382
+ setDepsCollector(null);
383
+ }
384
+ }
284
385
  function renderEffect(fn) {
285
386
  const deps = [];
286
387
  let disposed = false;
287
388
  const run = () => {
288
389
  if (disposed) return;
289
- if (deps.length === 1) {
290
- deps[0].delete(run);
291
- deps.length = 0;
292
- } else if (deps.length > 1) {
293
- for (const s of deps) s.delete(run);
294
- deps.length = 0;
295
- }
296
- setDepsCollector(deps);
297
- _setActiveEffect(run);
298
- try {
299
- fn();
300
- } finally {
301
- _restoreActiveEffect();
302
- setDepsCollector(null);
303
- }
390
+ renderEffectFullTrack(deps, run, fn);
304
391
  };
305
392
  run();
306
393
  const dispose = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/batch.ts","../../../src/cell.ts","../../../src/scope.ts","../../../src/tracking.ts","../../../src/computed.ts","../../../src/effect.ts","../../../src/createSelector.ts","../../../src/debug.ts","../../../src/signal.ts","../../../src/store.ts","../../../src/reconcile.ts","../../../src/resource.ts","../../../src/watch.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":["cleanupLocalDeps"],"sources":["../../../src/batch.ts","../../../src/cell.ts","../../../src/scope.ts","../../../src/tracking.ts","../../../src/computed.ts","../../../src/effect.ts","../../../src/createSelector.ts","../../../src/debug.ts","../../../src/signal.ts","../../../src/store.ts","../../../src/reconcile.ts","../../../src/resource.ts","../../../src/watch.ts"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyreon/reactivity",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "Signals-based reactivity system for Pyreon",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/batch.ts CHANGED
@@ -17,7 +17,7 @@ export function batch(fn: () => void): void {
17
17
  fn()
18
18
  } finally {
19
19
  batchDepth--
20
- if (batchDepth === 0) {
20
+ if (batchDepth === 0 && pendingNotifications.size > 0) {
21
21
  // Swap to the other pre-allocated Set before flushing so new enqueues
22
22
  // during notification land in the alternate Set, not mixed into the
23
23
  // current iteration.
package/src/computed.ts CHANGED
@@ -1,5 +1,12 @@
1
1
  import { getCurrentScope } from "./scope"
2
- import { cleanupEffect, notifySubscribers, trackSubscriber, withTracking } from "./tracking"
2
+ import {
3
+ cleanupEffect,
4
+ notifySubscribers,
5
+ setDepsCollector,
6
+ setSkipDepsCollection,
7
+ trackSubscriber,
8
+ withTracking,
9
+ } from "./tracking"
3
10
 
4
11
  export interface Computed<T> {
5
12
  (): T
@@ -21,38 +28,107 @@ export interface ComputedOptions<T> {
21
28
  equals?: (prev: T, next: T) => boolean
22
29
  }
23
30
 
31
+ /** Remove a computed from all dependency subscriber sets (local deps array). */
32
+ function cleanupLocalDeps(deps: Set<() => void>[], fn: () => void): void {
33
+ for (let i = 0; i < deps.length; i++) (deps[i] as Set<() => void>).delete(fn)
34
+ deps.length = 0
35
+ }
36
+
37
+ /** Re-track dependencies using the local deps array collector. */
38
+ function trackWithLocalDeps<T>(deps: Set<() => void>[], effect: () => void, fn: () => T): T {
39
+ setDepsCollector(deps)
40
+ const result = withTracking(effect, fn)
41
+ setDepsCollector(null)
42
+ return result
43
+ }
44
+
24
45
  export function computed<T>(fn: () => T, options?: ComputedOptions<T>): Computed<T> {
46
+ return options?.equals ? computedWithEquals(fn, options.equals) : computedLazy(fn)
47
+ }
48
+
49
+ /**
50
+ * Default computed — lazy evaluation with deferred cleanup.
51
+ *
52
+ * On notification: just marks dirty and propagates (no cleanup/re-track).
53
+ * On read: cleans up old deps, re-evaluates, re-tracks.
54
+ *
55
+ * The `if (dirty) return` early exit in recompute prevents double-propagation
56
+ * in diamond patterns (a→b,c→d: b notifies d, c tries to notify d again —
57
+ * skipped because d is already dirty).
58
+ */
59
+ function computedLazy<T>(fn: () => T): Computed<T> {
25
60
  let value: T
26
61
  let dirty = true
27
- let initialized = false
28
62
  let disposed = false
29
- const customEquals = options?.equals
30
-
31
- // SubscriberHost — _s is lazily allocated by trackSubscriber
63
+ let tracked = false
64
+ const deps: Set<() => void>[] = []
32
65
  const host: { _s: Set<() => void> | null } = { _s: null }
33
66
 
34
67
  const recompute = () => {
35
- if (disposed) return
36
- // Remove from all current deps before re-evaluating (dynamic deps support)
37
- cleanupEffect(recompute)
38
- if (customEquals) {
39
- // Eager evaluation: only notify downstream if the value actually changed
40
- const next = withTracking(recompute, fn)
41
- if (initialized && customEquals(value as T, next)) return
42
- value = next
68
+ if (disposed || dirty) return
69
+ dirty = true
70
+ if (host._s) notifySubscribers(host._s)
71
+ }
72
+
73
+ const read = (): T => {
74
+ trackSubscriber(host)
75
+ if (dirty) {
76
+ if (tracked) {
77
+ // Static deps fast path: already subscribed to our deps from first run.
78
+ // Set.add in trackSubscriber is a no-op for existing members.
79
+ // Skip cleanup (Set.delete) and collection (array.push) entirely.
80
+ setSkipDepsCollection(true)
81
+ value = withTracking(recompute, fn)
82
+ setSkipDepsCollection(false)
83
+ } else {
84
+ // First evaluation — full tracking to record deps for dispose
85
+ value = trackWithLocalDeps(deps, recompute, fn)
86
+ tracked = true
87
+ }
43
88
  dirty = false
44
- initialized = true
45
- if (host._s) notifySubscribers(host._s)
46
- } else {
47
- dirty = true
48
- if (host._s) notifySubscribers(host._s)
49
89
  }
90
+ return value as T
91
+ }
92
+
93
+ read.dispose = () => {
94
+ disposed = true
95
+ cleanupLocalDeps(deps, recompute)
96
+ }
97
+
98
+ getCurrentScope()?.add({ dispose: read.dispose })
99
+ return read
100
+ }
101
+
102
+ /**
103
+ * Computed with custom equality — eager evaluation on notification.
104
+ *
105
+ * Re-evaluates immediately when deps change and only notifies downstream
106
+ * if `equals(prev, next)` returns false.
107
+ */
108
+ function computedWithEquals<T>(fn: () => T, equals: (prev: T, next: T) => boolean): Computed<T> {
109
+ let value: T
110
+ let dirty = true
111
+ let initialized = false
112
+ let disposed = false
113
+ const deps: Set<() => void>[] = []
114
+ const host: { _s: Set<() => void> | null } = { _s: null }
115
+
116
+ const recompute = () => {
117
+ if (disposed) return
118
+ cleanupLocalDeps(deps, recompute)
119
+ const next = trackWithLocalDeps(deps, recompute, fn)
120
+ if (initialized && equals(value as T, next)) return
121
+ value = next
122
+ dirty = false
123
+ initialized = true
124
+ if (host._s) notifySubscribers(host._s)
50
125
  }
51
126
 
52
127
  const read = (): T => {
53
128
  trackSubscriber(host)
54
129
  if (dirty) {
55
- value = withTracking(recompute, fn)
130
+ cleanupLocalDeps(deps, recompute)
131
+ value = trackWithLocalDeps(deps, recompute, fn)
56
132
  dirty = false
57
133
  initialized = true
58
134
  }
@@ -61,11 +137,10 @@ export function computed<T>(fn: () => T, options?: ComputedOptions<T>): Computed
61
137
 
62
138
  read.dispose = () => {
63
139
  disposed = true
140
+ cleanupLocalDeps(deps, recompute)
64
141
  cleanupEffect(recompute)
65
142
  }
66
143
 
67
- // Auto-register with the active EffectScope (if any)
68
144
  getCurrentScope()?.add({ dispose: read.dispose })
69
-
70
145
  return read
71
146
  }
package/src/effect.ts CHANGED
@@ -1,11 +1,5 @@
1
1
  import { getCurrentScope } from "./scope"
2
- import {
3
- _restoreActiveEffect,
4
- _setActiveEffect,
5
- cleanupEffect,
6
- setDepsCollector,
7
- withTracking,
8
- } from "./tracking"
2
+ import { _restoreActiveEffect, _setActiveEffect, setDepsCollector, withTracking } from "./tracking"
9
3
 
10
4
  export interface Effect {
11
5
  dispose(): void
@@ -21,6 +15,17 @@ export function setErrorHandler(fn: (err: unknown) => void): void {
21
15
  _errorHandler = fn
22
16
  }
23
17
 
18
+ /** Remove an effect from all dependency subscriber sets (local deps array). */
19
+ function cleanupLocalDeps(deps: Set<() => void>[], fn: () => void): void {
20
+ if (deps.length === 1) {
21
+ ;(deps[0] as Set<() => void>).delete(fn)
22
+ deps.length = 0
23
+ } else if (deps.length > 1) {
24
+ for (let i = 0; i < deps.length; i++) (deps[i] as Set<() => void>).delete(fn)
25
+ deps.length = 0
26
+ }
27
+ }
28
+
24
29
  // biome-ignore lint/suspicious/noConfusingVoidType: void is intentional — callbacks that return nothing must be assignable
25
30
  export function effect(fn: () => (() => void) | void): Effect {
26
31
  // Capture the scope at creation time — remains correct during future re-runs
@@ -29,6 +34,8 @@ export function effect(fn: () => (() => void) | void): Effect {
29
34
  let disposed = false
30
35
  let isFirstRun = true
31
36
  let cleanup: (() => void) | undefined
37
+ // Local deps array — avoids WeakMap overhead (like renderEffect)
38
+ const deps: Set<() => void>[] = []
32
39
 
33
40
  const runCleanup = () => {
34
41
  if (typeof cleanup === "function") {
@@ -45,11 +52,13 @@ export function effect(fn: () => (() => void) | void): Effect {
45
52
  if (disposed) return
46
53
  // Run previous cleanup before re-running
47
54
  runCleanup()
48
- // Clean up previous subscriptions before re-running (dynamic dep tracking)
49
- cleanupEffect(run)
50
55
  try {
56
+ cleanupLocalDeps(deps, run)
57
+ setDepsCollector(deps)
51
58
  cleanup = withTracking(run, fn) || undefined
59
+ setDepsCollector(null)
52
60
  } catch (err) {
61
+ setDepsCollector(null)
53
62
  _errorHandler(err)
54
63
  }
55
64
  // Notify scope after each reactive re-run (not the initial synchronous run)
@@ -64,7 +73,7 @@ export function effect(fn: () => (() => void) | void): Effect {
64
73
  dispose() {
65
74
  runCleanup()
66
75
  disposed = true
67
- cleanupEffect(run)
76
+ cleanupLocalDeps(deps, run)
68
77
  },
69
78
  }
70
79
 
@@ -127,30 +136,32 @@ export function _bind(fn: () => void): () => void {
127
136
  return dispose
128
137
  }
129
138
 
139
+ /** Full re-track path for renderEffect: cleanup old deps, evaluate with tracking. */
140
+ function renderEffectFullTrack(deps: Set<() => void>[], run: () => void, fn: () => void): void {
141
+ if (deps.length === 1) {
142
+ ;(deps[0] as Set<() => void>).delete(run)
143
+ deps.length = 0
144
+ } else if (deps.length > 1) {
145
+ for (const s of deps) s.delete(run)
146
+ deps.length = 0
147
+ }
148
+ setDepsCollector(deps)
149
+ _setActiveEffect(run)
150
+ try {
151
+ fn()
152
+ } finally {
153
+ _restoreActiveEffect()
154
+ setDepsCollector(null)
155
+ }
156
+ }
157
+
130
158
  export function renderEffect(fn: () => void): () => void {
131
159
  const deps: Set<() => void>[] = []
132
160
  let disposed = false
133
161
 
134
162
  const run = () => {
135
163
  if (disposed) return
136
- // Single-dep fast path — most render effects track exactly 1 signal.
137
- // Avoids for-of iterator creation + deps.length check on every re-run.
138
- if (deps.length === 1) {
139
- ;(deps[0] as Set<() => void>).delete(run)
140
- deps.length = 0
141
- } else if (deps.length > 1) {
142
- for (const s of deps) s.delete(run)
143
- deps.length = 0
144
- }
145
- // Inline tracking setup — avoids setDepsCollector + withTracking function call overhead
146
- setDepsCollector(deps)
147
- _setActiveEffect(run)
148
- try {
149
- fn()
150
- } finally {
151
- _restoreActiveEffect()
152
- setDepsCollector(null)
153
- }
164
+ renderEffectFullTrack(deps, run, fn)
154
165
  }
155
166
 
156
167
  run()
package/src/tracking.ts CHANGED
@@ -12,10 +12,19 @@ const effectDeps = new WeakMap<() => void, Set<Set<() => void>>>()
12
12
  // When set, trackSubscriber pushes subscriber sets here instead of effectDeps.
13
13
  let _depsCollector: Set<() => void>[] | null = null
14
14
 
15
+ // Skip deps collection mode — for re-evaluating computeds/effects with static deps.
16
+ // When true, trackSubscriber only does Set.add (no-op if already subscribed) and skips
17
+ // the _depsCollector.push / WeakMap work entirely.
18
+ let _skipDepsCollection = false
19
+
15
20
  export function setDepsCollector(collector: Set<() => void>[] | null): void {
16
21
  _depsCollector = collector
17
22
  }
18
23
 
24
+ export function setSkipDepsCollection(skip: boolean): void {
25
+ _skipDepsCollection = skip
26
+ }
27
+
19
28
  /**
20
29
  * Subscriber host — any reactive source that can have downstream subscribers.
21
30
  * Signals, computeds, and createSelector buckets all implement this interface.
@@ -34,11 +43,13 @@ export interface SubscriberHost {
34
43
  export function trackSubscriber(host: SubscriberHost) {
35
44
  if (activeEffect) {
36
45
  if (!host._s) host._s = new Set()
37
- const subscribers = host._s
38
- subscribers.add(activeEffect)
46
+ host._s.add(activeEffect)
47
+ // Skip collection mode: we're already subscribed (Set.add is no-op),
48
+ // just need activeEffect set for nested computed reads to work.
49
+ if (_skipDepsCollection) return
39
50
  if (_depsCollector) {
40
51
  // Fast path: renderEffect stores deps inline, no WeakMap
41
- _depsCollector.push(subscribers)
52
+ _depsCollector.push(host._s)
42
53
  } else {
43
54
  // Record this dep so we can remove it on cleanup
44
55
  let deps = effectDeps.get(activeEffect)
@@ -46,7 +57,7 @@ export function trackSubscriber(host: SubscriberHost) {
46
57
  deps = new Set()
47
58
  effectDeps.set(activeEffect, deps)
48
59
  }
49
- deps.add(subscribers)
60
+ deps.add(host._s)
50
61
  }
51
62
  }
52
63
  }