sibujs 2.0.0 → 2.1.0

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.
Files changed (60) hide show
  1. package/dist/browser.cjs +144 -102
  2. package/dist/browser.js +4 -4
  3. package/dist/build.cjs +183 -102
  4. package/dist/build.js +10 -10
  5. package/dist/cdn.global.js +7 -7
  6. package/dist/{chunk-MIUAXB7K.js → chunk-3DZP6OIT.js} +2 -2
  7. package/dist/{chunk-ITX6OO3F.js → chunk-45YP72ZQ.js} +1 -1
  8. package/dist/{chunk-ND2664SF.js → chunk-AMK2TYNW.js} +13 -9
  9. package/dist/{chunk-R73P76YZ.js → chunk-CWBVQML6.js} +1 -1
  10. package/dist/{chunk-54EDRCEF.js → chunk-DRUZZAK4.js} +1 -1
  11. package/dist/{chunk-3NSGB5JN.js → chunk-GWWURC5M.js} +2 -2
  12. package/dist/{chunk-SAHNHTFC.js → chunk-KGYT6UO6.js} +3 -3
  13. package/dist/{chunk-52YJLLRO.js → chunk-NASX6ST2.js} +1 -1
  14. package/dist/{chunk-O2MNQFLP.js → chunk-O6EFQ3KT.js} +5 -5
  15. package/dist/{chunk-GTBNNBJ6.js → chunk-OJ3P4ECI.js} +1 -1
  16. package/dist/{chunk-7JDB7I65.js → chunk-ON5MMR2J.js} +4 -4
  17. package/dist/{chunk-KLRMB5ZS.js → chunk-P2HSJDDN.js} +2 -2
  18. package/dist/{chunk-VLPPXTYG.js → chunk-QO3WC6FS.js} +145 -93
  19. package/dist/{chunk-CC65Y57T.js → chunk-RDTDJCAB.js} +1 -1
  20. package/dist/{chunk-JXMMDLBY.js → chunk-TH2ILCYW.js} +8 -4
  21. package/dist/{chunk-3LR7GLWQ.js → chunk-V6C4FADE.js} +3 -3
  22. package/dist/{chunk-WOMYAHHI.js → chunk-WANSMF2L.js} +4 -4
  23. package/dist/{chunk-DFPFITST.js → chunk-WIPZPFBQ.js} +1 -1
  24. package/dist/{chunk-HB24TBAF.js → chunk-WZA53FXU.js} +38 -10
  25. package/dist/{chunk-JA6667UN.js → chunk-ZAQSMOED.js} +4 -4
  26. package/dist/data.cjs +176 -102
  27. package/dist/data.js +6 -6
  28. package/dist/devtools.cjs +148 -91
  29. package/dist/devtools.d.cts +1 -1
  30. package/dist/devtools.d.ts +1 -1
  31. package/dist/devtools.js +4 -4
  32. package/dist/ecosystem.cjs +176 -102
  33. package/dist/ecosystem.js +7 -7
  34. package/dist/extras.cjs +182 -104
  35. package/dist/extras.d.cts +1 -1
  36. package/dist/extras.d.ts +1 -1
  37. package/dist/extras.js +19 -19
  38. package/dist/index.cjs +185 -102
  39. package/dist/index.d.cts +15 -1
  40. package/dist/index.d.ts +15 -1
  41. package/dist/index.js +14 -10
  42. package/dist/{introspect-BWNjNw64.d.cts → introspect-2TOlQ7oa.d.cts} +3 -1
  43. package/dist/{introspect-cY2pg9pW.d.ts → introspect-DnIpHQQz.d.ts} +3 -1
  44. package/dist/motion.cjs +78 -62
  45. package/dist/motion.js +3 -3
  46. package/dist/patterns.cjs +176 -102
  47. package/dist/patterns.js +5 -5
  48. package/dist/performance.cjs +142 -89
  49. package/dist/performance.js +4 -4
  50. package/dist/plugins.cjs +142 -89
  51. package/dist/plugins.js +6 -6
  52. package/dist/ssr.cjs +144 -102
  53. package/dist/ssr.js +7 -7
  54. package/dist/testing.cjs +66 -28
  55. package/dist/testing.js +2 -2
  56. package/dist/ui.cjs +174 -89
  57. package/dist/ui.js +6 -6
  58. package/dist/widgets.cjs +176 -102
  59. package/dist/widgets.js +6 -6
  60. package/package.json +1 -1
package/dist/build.cjs CHANGED
@@ -1204,6 +1204,7 @@ __export(index_exports, {
1204
1204
  registerComponent: () => registerComponent,
1205
1205
  registerDisposer: () => registerDisposer,
1206
1206
  resolveComponent: () => resolveComponent,
1207
+ retrack: () => retrack,
1207
1208
  rp: () => rp,
1208
1209
  rt: () => rt,
1209
1210
  ruby: () => ruby,
@@ -1214,6 +1215,7 @@ __export(index_exports, {
1214
1215
  section: () => section,
1215
1216
  select: () => select,
1216
1217
  setGlobalErrorHandler: () => setGlobalErrorHandler,
1218
+ setMaxDrainIterations: () => setMaxDrainIterations,
1217
1219
  show: () => show,
1218
1220
  signal: () => signal,
1219
1221
  slot: () => slot,
@@ -1350,11 +1352,24 @@ function isUrlAttribute(attr) {
1350
1352
 
1351
1353
  // src/reactivity/track.ts
1352
1354
  var _isDev2 = isDev();
1353
- var subscriberStack = new Array(32);
1354
- var stackCapacity = 32;
1355
+ var STACK_INITIAL = 32;
1356
+ var STACK_SHRINK_THRESHOLD = 128;
1357
+ var subscriberStack = new Array(STACK_INITIAL);
1358
+ var stackCapacity = STACK_INITIAL;
1355
1359
  var stackTop = -1;
1356
1360
  var currentSubscriber = null;
1357
1361
  var SUBS = "__s";
1362
+ function syncFastPath(signal2, subs) {
1363
+ const size = subs.size;
1364
+ if (size === 0) {
1365
+ signal2.__f = void 0;
1366
+ delete signal2[SUBS];
1367
+ } else if (size === 1) {
1368
+ signal2.__f = subs.values().next().value;
1369
+ } else {
1370
+ signal2.__f = void 0;
1371
+ }
1372
+ }
1358
1373
  var notifyDepth = 0;
1359
1374
  var pendingQueue = [];
1360
1375
  var pendingSet = /* @__PURE__ */ new Set();
@@ -1368,13 +1383,45 @@ function safeInvoke(sub2) {
1368
1383
  }
1369
1384
  var suspendDepth = 0;
1370
1385
  var trackingSuspended = false;
1386
+ var subscriberEpochCounter = 0;
1371
1387
  function retrack(effectFn, subscriber) {
1372
1388
  const prev = currentSubscriber;
1373
1389
  currentSubscriber = subscriber;
1390
+ const sub2 = subscriber;
1391
+ const epoch = ++subscriberEpochCounter;
1392
+ sub2._epoch = epoch;
1374
1393
  try {
1375
1394
  effectFn();
1376
1395
  } finally {
1377
1396
  currentSubscriber = prev;
1397
+ pruneStaleDeps(sub2, epoch);
1398
+ }
1399
+ }
1400
+ function pruneStaleDeps(sub2, currentEpoch) {
1401
+ if (sub2._dep !== void 0) {
1402
+ if (sub2._depEpoch !== currentEpoch) {
1403
+ const sig = sub2._dep;
1404
+ const subs = sig[SUBS];
1405
+ if (subs?.delete(sub2)) syncFastPath(sig, subs);
1406
+ sub2._dep = void 0;
1407
+ sub2._depEpoch = void 0;
1408
+ }
1409
+ return;
1410
+ }
1411
+ const deps = sub2._deps;
1412
+ if (!deps || deps.size === 0) return;
1413
+ let stales;
1414
+ for (const [signal2, epoch] of deps) {
1415
+ if (epoch !== currentEpoch) {
1416
+ (stales ?? (stales = [])).push(signal2);
1417
+ }
1418
+ }
1419
+ if (!stales) return;
1420
+ for (const signal2 of stales) {
1421
+ deps.delete(signal2);
1422
+ const sig = signal2;
1423
+ const subs = sig[SUBS];
1424
+ if (subs?.delete(sub2)) syncFastPath(sig, subs);
1378
1425
  }
1379
1426
  }
1380
1427
  function track(effectFn, subscriber) {
@@ -1392,6 +1439,10 @@ function track(effectFn, subscriber) {
1392
1439
  } finally {
1393
1440
  stackTop--;
1394
1441
  currentSubscriber = stackTop >= 0 ? subscriberStack[stackTop] : null;
1442
+ if (stackTop < 0 && stackCapacity > STACK_SHRINK_THRESHOLD) {
1443
+ stackCapacity = Math.max(STACK_INITIAL, stackCapacity >>> 1);
1444
+ subscriberStack.length = stackCapacity;
1445
+ }
1395
1446
  }
1396
1447
  return () => cleanup(subscriber);
1397
1448
  }
@@ -1427,30 +1478,39 @@ function untracked(fn) {
1427
1478
  function recordDependency(signal2) {
1428
1479
  if (!currentSubscriber) return;
1429
1480
  const sub2 = currentSubscriber;
1430
- if (sub2._dep === signal2) return;
1481
+ const epoch = sub2._epoch;
1482
+ if (sub2._dep === signal2) {
1483
+ sub2._depEpoch = epoch;
1484
+ return;
1485
+ }
1431
1486
  const deps = sub2._deps;
1432
1487
  if (deps) {
1433
- if (deps.has(signal2)) return;
1434
- deps.add(signal2);
1488
+ deps.set(signal2, epoch);
1435
1489
  } else if (sub2._dep !== void 0) {
1436
- const set = /* @__PURE__ */ new Set();
1437
- set.add(sub2._dep);
1438
- set.add(signal2);
1439
- sub2._deps = set;
1490
+ const map2 = /* @__PURE__ */ new Map();
1491
+ map2.set(sub2._dep, sub2._depEpoch);
1492
+ map2.set(signal2, epoch);
1493
+ sub2._deps = map2;
1440
1494
  sub2._dep = void 0;
1495
+ sub2._depEpoch = void 0;
1441
1496
  } else {
1442
1497
  sub2._dep = signal2;
1498
+ sub2._depEpoch = epoch;
1443
1499
  }
1444
- let subs = signal2[SUBS];
1500
+ const sig = signal2;
1501
+ let subs = sig[SUBS];
1445
1502
  if (!subs) {
1446
1503
  subs = /* @__PURE__ */ new Set();
1447
- signal2[SUBS] = subs;
1504
+ sig[SUBS] = subs;
1448
1505
  }
1506
+ const prevSize = subs.size;
1449
1507
  subs.add(currentSubscriber);
1450
- if (subs.size === 1) {
1451
- signal2.__f = currentSubscriber;
1452
- } else if (signal2.__f !== void 0) {
1453
- signal2.__f = void 0;
1508
+ if (subs.size !== prevSize) {
1509
+ if (subs.size === 1) {
1510
+ sig.__f = currentSubscriber;
1511
+ } else if (sig.__f !== void 0) {
1512
+ sig.__f = void 0;
1513
+ }
1454
1514
  }
1455
1515
  }
1456
1516
  function queueSignalNotification(signal2) {
@@ -1465,24 +1525,60 @@ function queueSignalNotification(signal2) {
1465
1525
  }
1466
1526
  }
1467
1527
  }
1468
- var maxDrainIterations = 1e5;
1528
+ var maxSubscriberRepeats = 50;
1529
+ var maxDrainIterations = 1e6;
1530
+ var drainEpoch = 0;
1531
+ function setMaxDrainIterations(n) {
1532
+ const prev = maxDrainIterations;
1533
+ if (Number.isFinite(n) && n > 0) maxDrainIterations = Math.floor(n);
1534
+ return prev;
1535
+ }
1536
+ function tickRepeat(sub2) {
1537
+ const s2 = sub2;
1538
+ if (s2._runEpoch !== drainEpoch) {
1539
+ s2._runEpoch = drainEpoch;
1540
+ s2._runs = 1;
1541
+ return false;
1542
+ }
1543
+ return ++s2._runs > maxSubscriberRepeats;
1544
+ }
1545
+ function cycleError(sub2) {
1546
+ if (typeof console !== "undefined") {
1547
+ const name = sub2.__name ?? "<unnamed>";
1548
+ console.error(
1549
+ `[SibuJS] subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. Breaking to prevent infinite loop.`
1550
+ );
1551
+ }
1552
+ }
1553
+ function absoluteDrainError() {
1554
+ if (typeof console !== "undefined") {
1555
+ console.error(
1556
+ `[SibuJS] Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
1557
+ );
1558
+ }
1559
+ }
1560
+ function drainQueue() {
1561
+ let i2 = 0;
1562
+ while (i2 < pendingQueue.length) {
1563
+ if (i2 >= maxDrainIterations) {
1564
+ absoluteDrainError();
1565
+ break;
1566
+ }
1567
+ const sub2 = pendingQueue[i2++];
1568
+ if (tickRepeat(sub2)) {
1569
+ cycleError(sub2);
1570
+ break;
1571
+ }
1572
+ pendingSet.delete(sub2);
1573
+ safeInvoke(sub2);
1574
+ }
1575
+ }
1469
1576
  function drainNotificationQueue() {
1470
1577
  if (notifyDepth > 0) return;
1471
1578
  notifyDepth++;
1579
+ drainEpoch++;
1472
1580
  try {
1473
- let i2 = 0;
1474
- while (i2 < pendingQueue.length) {
1475
- if (i2 >= maxDrainIterations) {
1476
- if (typeof console !== "undefined") {
1477
- console.error(
1478
- `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
1479
- );
1480
- }
1481
- break;
1482
- }
1483
- safeInvoke(pendingQueue[i2]);
1484
- i2++;
1485
- }
1581
+ drainQueue();
1486
1582
  } finally {
1487
1583
  notifyDepth--;
1488
1584
  if (notifyDepth === 0) {
@@ -1545,25 +1641,16 @@ function notifySubscribers(signal2) {
1545
1641
  return;
1546
1642
  }
1547
1643
  notifyDepth++;
1644
+ drainEpoch++;
1548
1645
  try {
1549
1646
  if (first._c) {
1550
1647
  propagateDirty(first);
1648
+ } else if (tickRepeat(first)) {
1649
+ cycleError(first);
1551
1650
  } else {
1552
1651
  safeInvoke(first);
1553
1652
  }
1554
- let i2 = 0;
1555
- while (i2 < pendingQueue.length) {
1556
- if (i2 >= maxDrainIterations) {
1557
- if (typeof console !== "undefined") {
1558
- console.error(
1559
- `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
1560
- );
1561
- }
1562
- break;
1563
- }
1564
- safeInvoke(pendingQueue[i2]);
1565
- i2++;
1566
- }
1653
+ drainQueue();
1567
1654
  } finally {
1568
1655
  notifyDepth--;
1569
1656
  if (notifyDepth === 0) {
@@ -1587,44 +1674,17 @@ function notifySubscribers(signal2) {
1587
1674
  return;
1588
1675
  }
1589
1676
  notifyDepth++;
1677
+ drainEpoch++;
1590
1678
  try {
1591
- let directCount = 0;
1592
- let hasComputedSub = false;
1593
1679
  for (const sub2 of subs) {
1594
- if (sub2._c) hasComputedSub = true;
1595
- pendingQueue[directCount++] = sub2;
1596
- }
1597
- if (!hasComputedSub) {
1598
- for (let i3 = 0; i3 < directCount; i3++) {
1599
- safeInvoke(pendingQueue[i3]);
1600
- }
1601
- } else {
1602
- for (let i3 = 0; i3 < directCount; i3++) {
1603
- if (pendingQueue[i3]._c) {
1604
- propagateDirty(pendingQueue[i3]);
1605
- }
1606
- }
1607
- for (let i3 = 0; i3 < directCount; i3++) {
1608
- const sub2 = pendingQueue[i3];
1609
- if (!sub2._c && !pendingSet.has(sub2)) {
1610
- pendingSet.add(sub2);
1611
- safeInvoke(sub2);
1612
- }
1613
- }
1614
- }
1615
- let i2 = directCount;
1616
- while (i2 < pendingQueue.length) {
1617
- if (i2 - directCount >= maxDrainIterations) {
1618
- if (typeof console !== "undefined") {
1619
- console.error(
1620
- `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
1621
- );
1622
- }
1623
- break;
1680
+ if (sub2._c) {
1681
+ propagateDirty(sub2);
1682
+ } else if (!pendingSet.has(sub2)) {
1683
+ pendingSet.add(sub2);
1684
+ pendingQueue.push(sub2);
1624
1685
  }
1625
- safeInvoke(pendingQueue[i2]);
1626
- i2++;
1627
1686
  }
1687
+ drainQueue();
1628
1688
  } finally {
1629
1689
  notifyDepth--;
1630
1690
  if (notifyDepth === 0) {
@@ -1637,29 +1697,22 @@ function cleanup(subscriber) {
1637
1697
  const sub2 = subscriber;
1638
1698
  const singleDep = sub2._dep;
1639
1699
  if (singleDep !== void 0) {
1640
- const subs = singleDep[SUBS];
1641
- if (subs) {
1642
- subs.delete(subscriber);
1643
- if (singleDep.__f === subscriber) {
1644
- singleDep.__f = subs.size === 1 ? subs.values().next().value : void 0;
1645
- } else if (subs.size === 1 && singleDep.__f === void 0) {
1646
- singleDep.__f = subs.values().next().value;
1647
- }
1700
+ const sig = singleDep;
1701
+ const subs = sig[SUBS];
1702
+ if (subs?.delete(subscriber)) {
1703
+ syncFastPath(sig, subs);
1648
1704
  }
1649
1705
  sub2._dep = void 0;
1706
+ sub2._depEpoch = void 0;
1650
1707
  return;
1651
1708
  }
1652
1709
  const deps = sub2._deps;
1653
1710
  if (!deps || deps.size === 0) return;
1654
- for (const signal2 of deps) {
1655
- const subs = signal2[SUBS];
1656
- if (subs) {
1657
- subs.delete(subscriber);
1658
- if (signal2.__f === subscriber) {
1659
- signal2.__f = subs.size === 1 ? subs.values().next().value : void 0;
1660
- } else if (subs.size === 1 && signal2.__f === void 0) {
1661
- signal2.__f = subs.values().next().value;
1662
- }
1711
+ for (const signal2 of deps.keys()) {
1712
+ const sig = signal2;
1713
+ const subs = sig[SUBS];
1714
+ if (subs?.delete(subscriber)) {
1715
+ syncFastPath(sig, subs);
1663
1716
  }
1664
1717
  }
1665
1718
  deps.clear();
@@ -3446,29 +3499,57 @@ function effect(effectFn, options) {
3446
3499
  let cleanupHandle = () => {
3447
3500
  };
3448
3501
  let running = false;
3502
+ let rerunPending = false;
3503
+ const MAX_RERUNS = 100;
3449
3504
  const subscriber = () => {
3450
3505
  if (running) {
3451
- if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
3452
- console.warn(
3453
- "[SibuJS] effect re-entered itself while running \u2014 the triggering update will be ignored. Wrap mutual writes in `batch()` or split the effect to avoid this."
3454
- );
3455
- }
3506
+ rerunPending = true;
3456
3507
  return;
3457
3508
  }
3458
3509
  running = true;
3459
3510
  try {
3460
- runUserCleanups();
3461
- cleanupHandle();
3462
- cleanupHandle = track(wrappedFn, subscriber);
3511
+ let reruns = 0;
3512
+ do {
3513
+ rerunPending = false;
3514
+ runUserCleanups();
3515
+ cleanupHandle();
3516
+ cleanupHandle = track(wrappedFn, subscriber);
3517
+ if (++reruns > MAX_RERUNS) {
3518
+ if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
3519
+ console.error(
3520
+ `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
3521
+ );
3522
+ }
3523
+ rerunPending = false;
3524
+ break;
3525
+ }
3526
+ } while (rerunPending);
3463
3527
  } finally {
3464
3528
  running = false;
3529
+ rerunPending = false;
3465
3530
  }
3466
3531
  };
3467
3532
  running = true;
3468
3533
  try {
3469
- cleanupHandle = track(wrappedFn, subscriber);
3534
+ let reruns = 0;
3535
+ do {
3536
+ rerunPending = false;
3537
+ runUserCleanups();
3538
+ cleanupHandle();
3539
+ cleanupHandle = track(wrappedFn, subscriber);
3540
+ if (++reruns > MAX_RERUNS) {
3541
+ if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
3542
+ console.error(
3543
+ `[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times on initial run \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
3544
+ );
3545
+ }
3546
+ rerunPending = false;
3547
+ break;
3548
+ }
3549
+ } while (rerunPending);
3470
3550
  } finally {
3471
3551
  running = false;
3552
+ rerunPending = false;
3472
3553
  }
3473
3554
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
3474
3555
  if (hook) hook.emit("effect:create", { effectFn });
package/dist/build.js CHANGED
@@ -1,20 +1,20 @@
1
1
  import {
2
2
  index_exports
3
- } from "./chunk-ND2664SF.js";
3
+ } from "./chunk-AMK2TYNW.js";
4
4
  import "./chunk-YT6HQ6AM.js";
5
- import "./chunk-R73P76YZ.js";
6
- import "./chunk-ITX6OO3F.js";
5
+ import "./chunk-CWBVQML6.js";
6
+ import "./chunk-45YP72ZQ.js";
7
7
  import "./chunk-JYD2PWXH.js";
8
- import "./chunk-GTBNNBJ6.js";
9
- import "./chunk-KLRMB5ZS.js";
10
- import "./chunk-DFPFITST.js";
11
- import "./chunk-54EDRCEF.js";
8
+ import "./chunk-OJ3P4ECI.js";
9
+ import "./chunk-P2HSJDDN.js";
10
+ import "./chunk-WIPZPFBQ.js";
11
+ import "./chunk-DRUZZAK4.js";
12
12
  import "./chunk-2UPRY23K.js";
13
13
  import "./chunk-UCS6AMJ7.js";
14
- import "./chunk-HB24TBAF.js";
14
+ import "./chunk-WZA53FXU.js";
15
15
  import "./chunk-2RA7SHDA.js";
16
- import "./chunk-CC65Y57T.js";
17
- import "./chunk-VLPPXTYG.js";
16
+ import "./chunk-RDTDJCAB.js";
17
+ import "./chunk-QO3WC6FS.js";
18
18
  import "./chunk-LMLD24FC.js";
19
19
 
20
20
  // src/build/compileTemplates.ts