@estjs/signals 0.0.16-beta.2 → 0.0.16-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -32,78 +32,7 @@ var WEAK_COLLECTION_KEY = /* @__PURE__ */ Symbol("WeakCollection_Key" );
32
32
  var ITERATE_KEY = /* @__PURE__ */ Symbol("Iterate_Key" );
33
33
  var ARRAY_ITERATE_KEY = /* @__PURE__ */ Symbol("Array_Iterate_Key" );
34
34
 
35
- // src/propagation.ts
36
- function enqueueEffect(effect2) {
37
- var _a5;
38
- (_a5 = effect2 == null ? void 0 : effect2.notify) == null ? void 0 : _a5.call(effect2);
39
- }
40
- function propagate(link) {
41
- let next = link.nextSubLink;
42
- let stack;
43
- top: do {
44
- const sub = link.subNode;
45
- const watcherBit = sub.flag & 2 /* WATCHING */;
46
- let flags = sub.flag;
47
- if (!(flags & (16 /* DIRTY */ | 32 /* PENDING */ | 8 /* RECURSED */ | 4 /* RECURSED_CHECK */))) {
48
- sub.flag = flags | 32 /* PENDING */;
49
- if (watcherBit) {
50
- enqueueEffect(sub);
51
- }
52
- } else if (!(flags & (8 /* RECURSED */ | 4 /* RECURSED_CHECK */))) {
53
- flags = 0 /* NONE */;
54
- } else if (!(flags & 4 /* RECURSED_CHECK */)) {
55
- sub.flag = flags & -9 /* RECURSED */ | 32 /* PENDING */;
56
- } else if (!(flags & (16 /* DIRTY */ | 32 /* PENDING */)) && isValidLink(link, sub)) {
57
- sub.flag = flags | (8 /* RECURSED */ | 32 /* PENDING */);
58
- if (watcherBit) {
59
- enqueueEffect(sub);
60
- }
61
- flags &= 1 /* MUTABLE */;
62
- } else {
63
- flags = 0 /* NONE */;
64
- }
65
- if (flags & 1 /* MUTABLE */) {
66
- const subSubs = sub.subLink;
67
- if (subSubs !== void 0) {
68
- const nextSub = subSubs.nextSubLink;
69
- if (nextSub !== void 0) {
70
- stack = { value: next, prev: stack };
71
- next = nextSub;
72
- }
73
- link = subSubs;
74
- continue;
75
- }
76
- }
77
- if ((link = next) !== void 0) {
78
- next = link.nextSubLink;
79
- continue;
80
- }
81
- while (stack !== void 0) {
82
- link = stack.value;
83
- stack = stack.prev;
84
- if (link !== void 0) {
85
- next = link.nextSubLink;
86
- continue top;
87
- }
88
- }
89
- break;
90
- } while (true);
91
- }
92
- function shallowPropagate(link) {
93
- while (link) {
94
- const sub = link.subNode;
95
- const flags = sub.flag;
96
- if ((flags & (32 /* PENDING */ | 16 /* DIRTY */)) === 32 /* PENDING */) {
97
- sub.flag = flags | 16 /* DIRTY */;
98
- if ((flags & (2 /* WATCHING */ | 4 /* RECURSED_CHECK */)) === 2 /* WATCHING */) {
99
- enqueueEffect(sub);
100
- }
101
- }
102
- link = link.nextSubLink;
103
- }
104
- }
105
-
106
- // src/link.ts
35
+ // src/system.ts
107
36
  var currentLinkVersion = 0;
108
37
  var activeSub;
109
38
  var isUntracking = false;
@@ -124,6 +53,10 @@ var Dep = class {
124
53
  }
125
54
  }
126
55
  };
56
+ function enqueueEffect(effect2) {
57
+ var _a5;
58
+ (_a5 = effect2 == null ? void 0 : effect2.notify) == null ? void 0 : _a5.call(effect2);
59
+ }
127
60
  function linkReactiveNode(depNode, subNode) {
128
61
  if (isUntracking) {
129
62
  return void 0;
@@ -147,10 +80,8 @@ function linkReactiveNode(depNode, subNode) {
147
80
  version: currentLinkVersion,
148
81
  depNode,
149
82
  subNode,
150
- // Subscriber chain pointers (horizontal)
151
83
  prevSubLink: prevSub,
152
84
  nextSubLink: void 0,
153
- // Dependency chain pointers (vertical)
154
85
  prevDepLink: prevDep,
155
86
  nextDepLink: nextDep
156
87
  };
@@ -169,15 +100,13 @@ function linkReactiveNode(depNode, subNode) {
169
100
  }
170
101
  depNode.subLinkTail = newLink;
171
102
  subNode.depLinkTail = newLink;
172
- {
173
- if (subNode.onTrack && shared.isFunction(subNode == null ? void 0 : subNode.onTrack)) {
174
- subNode.onTrack({
175
- effect: subNode,
176
- target: depNode,
177
- type: "get",
178
- key: void 0
179
- });
180
- }
103
+ if (subNode.onTrack && shared.isFunction(subNode.onTrack)) {
104
+ subNode.onTrack({
105
+ effect: subNode,
106
+ target: depNode,
107
+ type: "get",
108
+ key: void 0
109
+ });
181
110
  }
182
111
  return newLink;
183
112
  }
@@ -215,12 +144,10 @@ function unlinkReactiveNode(linkNode, subNode = linkNode.subNode) {
215
144
  if (!depNode.isDep) {
216
145
  depNode.flag |= 16 /* DIRTY */;
217
146
  }
218
- {
219
- if (depNode.depLink) {
220
- shared.error(
221
- "[Link] Cascading cleanup failed: depNode still has dependency links. This indicates a bug in the unlinking logic."
222
- );
223
- }
147
+ if (depNode.depLink) {
148
+ shared.error(
149
+ "[Link] Cascading cleanup failed: depNode still has dependency links. This indicates a bug in the unlinking logic."
150
+ );
224
151
  }
225
152
  }
226
153
  }
@@ -240,7 +167,7 @@ function checkDirty(link, sub) {
240
167
  if ((depFlags & (1 /* MUTABLE */ | 16 /* DIRTY */)) === (1 /* MUTABLE */ | 16 /* DIRTY */)) {
241
168
  const subs = dep.subLink;
242
169
  if (subs && subs.nextSubLink) {
243
- shallowPropagate2(subs);
170
+ shallowPropagate(subs);
244
171
  }
245
172
  currentDirty = true;
246
173
  } else if ((depFlags & (1 /* MUTABLE */ | 32 /* PENDING */)) === (1 /* MUTABLE */ | 32 /* PENDING */)) {
@@ -288,16 +215,71 @@ function checkDirty(link, sub) {
288
215
  return dirty;
289
216
  } while (true);
290
217
  }
291
- function shallowPropagate2(link) {
218
+ function shallowPropagate(link) {
292
219
  while (link) {
293
220
  const sub = link.subNode;
294
221
  const flags = sub.flag;
295
222
  if ((flags & (32 /* PENDING */ | 16 /* DIRTY */)) === 32 /* PENDING */) {
296
223
  sub.flag = flags | 16 /* DIRTY */;
224
+ if ((flags & (2 /* WATCHING */ | 4 /* RECURSED_CHECK */)) === 2 /* WATCHING */) {
225
+ enqueueEffect(sub);
226
+ }
297
227
  }
298
228
  link = link.nextSubLink;
299
229
  }
300
230
  }
231
+ function propagate(link) {
232
+ let next = link.nextSubLink;
233
+ let stack;
234
+ top: do {
235
+ const sub = link.subNode;
236
+ const watcherBit = sub.flag & 2 /* WATCHING */;
237
+ let flags = sub.flag;
238
+ if (!(flags & (16 /* DIRTY */ | 32 /* PENDING */ | 8 /* RECURSED */ | 4 /* RECURSED_CHECK */))) {
239
+ sub.flag = flags | 32 /* PENDING */;
240
+ if (watcherBit) {
241
+ enqueueEffect(sub);
242
+ }
243
+ } else if (!(flags & (8 /* RECURSED */ | 4 /* RECURSED_CHECK */))) {
244
+ flags = 0 /* NONE */;
245
+ } else if (!(flags & 4 /* RECURSED_CHECK */)) {
246
+ sub.flag = flags & -9 /* RECURSED */ | 32 /* PENDING */;
247
+ } else if (!(flags & (16 /* DIRTY */ | 32 /* PENDING */)) && isValidLink(link, sub)) {
248
+ sub.flag = flags | (8 /* RECURSED */ | 32 /* PENDING */);
249
+ if (watcherBit) {
250
+ enqueueEffect(sub);
251
+ }
252
+ flags &= 1 /* MUTABLE */;
253
+ } else {
254
+ flags = 0 /* NONE */;
255
+ }
256
+ if (flags & 1 /* MUTABLE */) {
257
+ const subSubs = sub.subLink;
258
+ if (subSubs !== void 0) {
259
+ const nextSub = subSubs.nextSubLink;
260
+ if (nextSub !== void 0) {
261
+ stack = { value: next, prev: stack };
262
+ next = nextSub;
263
+ }
264
+ link = subSubs;
265
+ continue;
266
+ }
267
+ }
268
+ if ((link = next) !== void 0) {
269
+ next = link.nextSubLink;
270
+ continue;
271
+ }
272
+ while (stack !== void 0) {
273
+ link = stack.value;
274
+ stack = stack.prev;
275
+ if (link !== void 0) {
276
+ next = link.nextSubLink;
277
+ continue top;
278
+ }
279
+ }
280
+ break;
281
+ } while (true);
282
+ }
301
283
  function setActiveSub(sub) {
302
284
  const prev = activeSub;
303
285
  activeSub = sub;
@@ -1051,7 +1033,7 @@ var SignalImpl = class {
1051
1033
  if (flags & 16 /* DIRTY */ && this.shouldUpdate()) {
1052
1034
  const subs = this.subLink;
1053
1035
  if (subs) {
1054
- shallowPropagate2(subs);
1036
+ shallowPropagate(subs);
1055
1037
  }
1056
1038
  }
1057
1039
  return this._value;
@@ -1263,6 +1245,133 @@ function isBatching() {
1263
1245
  function getBatchDepth() {
1264
1246
  return batchDepth;
1265
1247
  }
1248
+ var activeEffectScope;
1249
+ var EffectScope = class {
1250
+ constructor(detached = false, parent = void 0) {
1251
+ this.detached = detached;
1252
+ this.parent = parent;
1253
+ this._active = true;
1254
+ this.effects = [];
1255
+ this.scopes = [];
1256
+ this.cleanups = [];
1257
+ if (!detached && activeEffectScope) {
1258
+ this.parent = activeEffectScope;
1259
+ activeEffectScope.scopes.push(this);
1260
+ }
1261
+ }
1262
+ get active() {
1263
+ return this._active;
1264
+ }
1265
+ pause() {
1266
+ var _a5, _b2;
1267
+ if (!this._active) {
1268
+ return;
1269
+ }
1270
+ for (let i = 0; i < this.scopes.length; i++) {
1271
+ this.scopes[i].pause();
1272
+ }
1273
+ for (let i = 0; i < this.effects.length; i++) {
1274
+ (_b2 = (_a5 = this.effects[i]).pause) == null ? void 0 : _b2.call(_a5);
1275
+ }
1276
+ }
1277
+ resume() {
1278
+ var _a5, _b2;
1279
+ if (!this._active) {
1280
+ return;
1281
+ }
1282
+ for (let i = 0; i < this.scopes.length; i++) {
1283
+ this.scopes[i].resume();
1284
+ }
1285
+ for (let i = 0; i < this.effects.length; i++) {
1286
+ (_b2 = (_a5 = this.effects[i]).resume) == null ? void 0 : _b2.call(_a5);
1287
+ }
1288
+ }
1289
+ run(fn) {
1290
+ if (!this._active) {
1291
+ {
1292
+ shared.warn("cannot run an inactive effect scope.");
1293
+ }
1294
+ return;
1295
+ }
1296
+ const prevScope = activeEffectScope;
1297
+ activeEffectScope = this;
1298
+ try {
1299
+ return fn();
1300
+ } finally {
1301
+ activeEffectScope = prevScope;
1302
+ }
1303
+ }
1304
+ stop(fromParent = false) {
1305
+ if (!this._active) {
1306
+ return;
1307
+ }
1308
+ this._active = false;
1309
+ for (let i = 0; i < this.scopes.length; i++) {
1310
+ this.scopes[i].stop(true);
1311
+ }
1312
+ this.scopes.length = 0;
1313
+ const effects = this.effects.slice();
1314
+ this.effects.length = 0;
1315
+ for (const effect2 of effects) {
1316
+ effect2.stop();
1317
+ }
1318
+ for (let i = 0; i < this.cleanups.length; i++) {
1319
+ this.cleanups[i]();
1320
+ }
1321
+ this.cleanups.length = 0;
1322
+ if (!fromParent && this.parent) {
1323
+ const index = this.parent.scopes.indexOf(this);
1324
+ if (index >= 0) {
1325
+ this.parent.scopes.splice(index, 1);
1326
+ }
1327
+ }
1328
+ this.parent = void 0;
1329
+ }
1330
+ _record(effect2) {
1331
+ this.effects.push(effect2);
1332
+ effect2.scope = this;
1333
+ }
1334
+ _remove(effect2) {
1335
+ const index = this.effects.indexOf(effect2);
1336
+ if (index >= 0) {
1337
+ this.effects.splice(index, 1);
1338
+ }
1339
+ }
1340
+ _pushCleanup(fn) {
1341
+ this.cleanups.push(fn);
1342
+ }
1343
+ };
1344
+ function effectScope(detached = false) {
1345
+ return new EffectScope(detached);
1346
+ }
1347
+ function getCurrentScope() {
1348
+ return activeEffectScope;
1349
+ }
1350
+ function setCurrentScope(scope) {
1351
+ const prevScope = activeEffectScope;
1352
+ activeEffectScope = scope;
1353
+ return prevScope;
1354
+ }
1355
+ function onScopeDispose(fn, failSilently = false) {
1356
+ if (activeEffectScope) {
1357
+ activeEffectScope._pushCleanup(fn);
1358
+ } else if (!failSilently) {
1359
+ shared.warn("onScopeDispose() is called when there is no active effect scope to be associated with.");
1360
+ }
1361
+ }
1362
+ function recordDisposable(effect2, scope = activeEffectScope) {
1363
+ if (scope && scope.active) {
1364
+ scope._record(effect2);
1365
+ }
1366
+ }
1367
+ function releaseDisposable(effect2) {
1368
+ const scope = effect2.scope;
1369
+ if (!scope) {
1370
+ return;
1371
+ }
1372
+ effect2.scope = void 0;
1373
+ scope._remove(effect2);
1374
+ }
1266
1375
 
1267
1376
  // src/effect.ts
1268
1377
  var _a2;
@@ -1292,6 +1401,7 @@ var EffectImpl = class {
1292
1401
  if (options.onTrigger) this.onTrigger = options.onTrigger;
1293
1402
  }
1294
1403
  }
1404
+ recordDisposable(this);
1295
1405
  }
1296
1406
  /**
1297
1407
  * Check if the Effect is active.
@@ -1455,12 +1565,10 @@ var EffectImpl = class {
1455
1565
  stop() {
1456
1566
  var _a5;
1457
1567
  if (!this._active) {
1458
- {
1459
- shared.warn("[Effect] Attempting to stop an already stopped effect.");
1460
- }
1461
1568
  return;
1462
1569
  }
1463
1570
  this._active = false;
1571
+ releaseDisposable(this);
1464
1572
  let dep = this.depLink;
1465
1573
  while (dep) {
1466
1574
  dep = unlinkReactiveNode(dep, this);
@@ -1542,11 +1650,13 @@ var ComputedImpl = class {
1542
1650
  // Cache
1543
1651
  // Use symbol sentinel to distinguish "no value" from undefined/null values
1544
1652
  this._value = NO_VALUE;
1653
+ this._active = true;
1545
1654
  this.getter = getter;
1546
1655
  this.setter = setter;
1547
1656
  this.onTrack = onTrack;
1548
1657
  this.onTrigger = onTrigger;
1549
1658
  this.flag |= 16 /* DIRTY */;
1659
+ recordDisposable(this);
1550
1660
  }
1551
1661
  /**
1552
1662
  * Returns the current value.
@@ -1554,6 +1664,9 @@ var ComputedImpl = class {
1554
1664
  * @returns {T} The current value.
1555
1665
  */
1556
1666
  get value() {
1667
+ if (!this.active) {
1668
+ return this._value === NO_VALUE ? this.getter() : this._value;
1669
+ }
1557
1670
  if (activeSub) {
1558
1671
  linkReactiveNode(this, activeSub);
1559
1672
  }
@@ -1595,11 +1708,17 @@ var ComputedImpl = class {
1595
1708
  * @returns {T} The current value.
1596
1709
  */
1597
1710
  peek() {
1711
+ if (!this.active) {
1712
+ return this._value === NO_VALUE ? this.getter() : this._value;
1713
+ }
1598
1714
  if (this._value === NO_VALUE) {
1599
1715
  this.recompute();
1600
1716
  }
1601
1717
  return this._value;
1602
1718
  }
1719
+ get active() {
1720
+ return this._active;
1721
+ }
1603
1722
  /**
1604
1723
  * Recompute the value
1605
1724
  *
@@ -1612,6 +1731,12 @@ var ComputedImpl = class {
1612
1731
  * @private
1613
1732
  */
1614
1733
  recompute() {
1734
+ if (!this._active) {
1735
+ if (this._value === NO_VALUE) {
1736
+ this._value = this.getter();
1737
+ }
1738
+ return;
1739
+ }
1615
1740
  const oldValue = this._value;
1616
1741
  const hadValue = oldValue !== NO_VALUE;
1617
1742
  const prevSub = startTracking(this);
@@ -1670,6 +1795,24 @@ var ComputedImpl = class {
1670
1795
  }
1671
1796
  return shared.hasChanged(this._value, oldValue);
1672
1797
  }
1798
+ stop() {
1799
+ if (!this._active) {
1800
+ return;
1801
+ }
1802
+ this._active = false;
1803
+ releaseDisposable(this);
1804
+ let dep = this.depLink;
1805
+ while (dep) {
1806
+ dep = unlinkReactiveNode(dep, this);
1807
+ }
1808
+ let sub = this.subLink;
1809
+ while (sub) {
1810
+ sub = unlinkReactiveNode(sub);
1811
+ }
1812
+ this.depLinkTail = void 0;
1813
+ this.subLinkTail = void 0;
1814
+ this.flag &= -49;
1815
+ }
1673
1816
  };
1674
1817
  function computed(getterOrOptions) {
1675
1818
  if (isComputed(getterOrOptions)) {
@@ -2022,13 +2165,16 @@ function watch(source, callback, options = {}) {
2022
2165
  };
2023
2166
  }
2024
2167
 
2168
+ exports.EffectScope = EffectScope;
2025
2169
  exports.TriggerOpTypes = TriggerOpTypes;
2026
2170
  exports.batch = batch;
2027
2171
  exports.computed = computed;
2028
2172
  exports.createStore = createStore;
2029
2173
  exports.effect = effect;
2174
+ exports.effectScope = effectScope;
2030
2175
  exports.endBatch = endBatch;
2031
2176
  exports.getBatchDepth = getBatchDepth;
2177
+ exports.getCurrentScope = getCurrentScope;
2032
2178
  exports.isBatching = isBatching;
2033
2179
  exports.isComputed = isComputed;
2034
2180
  exports.isEffect = isEffect;
@@ -2038,10 +2184,12 @@ exports.isShallow = isShallow;
2038
2184
  exports.isSignal = isSignal;
2039
2185
  exports.memoEffect = memoEffect;
2040
2186
  exports.nextTick = nextTick;
2187
+ exports.onScopeDispose = onScopeDispose;
2041
2188
  exports.queueJob = queueJob;
2042
2189
  exports.queuePreFlushCb = queuePreFlushCb;
2043
2190
  exports.reactive = reactive;
2044
2191
  exports.ref = ref;
2192
+ exports.setCurrentScope = setCurrentScope;
2045
2193
  exports.shallowReactive = shallowReactive;
2046
2194
  exports.shallowSignal = shallowSignal;
2047
2195
  exports.signal = signal;