@estjs/signals 0.0.15-beta.1

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.
@@ -0,0 +1,1916 @@
1
+ import { isFunction, isObject, warn, error, isPlainObject, info, hasChanged, isArray, isSet, isMap, isWeakMap, isWeakSet, isStringNumber, hasOwn } from '@estjs/shared';
2
+
3
+ /**
4
+ * @estjs/signals v0.0.15-beta.1
5
+ * (c) 2023-Present jiangxd <jiangxd2016@gmail.com>
6
+ * @license MIT
7
+ **/
8
+ var __defProp = Object.defineProperty;
9
+ var __defProps = Object.defineProperties;
10
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
11
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
12
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
13
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
14
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
15
+ var __spreadValues = (a, b) => {
16
+ for (var prop in b || (b = {}))
17
+ if (__hasOwnProp.call(b, prop))
18
+ __defNormalProp(a, prop, b[prop]);
19
+ if (__getOwnPropSymbols)
20
+ for (var prop of __getOwnPropSymbols(b)) {
21
+ if (__propIsEnum.call(b, prop))
22
+ __defNormalProp(a, prop, b[prop]);
23
+ }
24
+ return a;
25
+ };
26
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
27
+
28
+ // src/constants.ts
29
+ var TriggerOpTypes = {
30
+ SET: "SET",
31
+ ADD: "ADD",
32
+ DELETE: "DELETE",
33
+ CLEAR: "CLEAR"
34
+ };
35
+ var SIGNAL_KEY = Symbol("Signal_Key" );
36
+ var ARRAY_KEY = Symbol("Array_Key" );
37
+ var COLLECTION_KEY = Symbol("Collection_Key" );
38
+ var WEAK_COLLECTION_KEY = Symbol("WeakCollection_Key" );
39
+ var ARRAY_ITERATE_KEY = Symbol("Array_Iterate_Key" );
40
+
41
+ // src/propagation.ts
42
+ function propagate(link) {
43
+ let next = link.nextSubLink;
44
+ let stack;
45
+ top: do {
46
+ const sub = link.subNode;
47
+ const queueBit = sub.flag & 64 /* QUEUED */;
48
+ const watcherBit = sub.flag & 2 /* WATCHING */;
49
+ let flags = sub.flag & -65 /* QUEUED */;
50
+ if (!(flags & (16 /* DIRTY */ | 32 /* PENDING */ | 8 /* RECURSED */ | 4 /* RECURSED_CHECK */))) {
51
+ sub.flag = queueBit | watcherBit | flags | 32 /* PENDING */;
52
+ } else if (flags & (16 /* DIRTY */ | 32 /* PENDING */)) ; else if (!(flags & (8 /* RECURSED */ | 4 /* RECURSED_CHECK */))) {
53
+ flags = 0 /* NONE */;
54
+ sub.flag = queueBit | watcherBit;
55
+ } else if (!(flags & 4 /* RECURSED_CHECK */)) {
56
+ sub.flag = queueBit | watcherBit | (flags & -9 /* RECURSED */ | 32 /* PENDING */);
57
+ } else if (!(flags & (16 /* DIRTY */ | 32 /* PENDING */)) && isValidLink(link, sub)) {
58
+ sub.flag = queueBit | watcherBit | (flags | 8 /* RECURSED */ | 32 /* PENDING */);
59
+ flags &= 1 /* MUTABLE */;
60
+ } else {
61
+ flags = 0 /* NONE */;
62
+ sub.flag = queueBit | watcherBit;
63
+ }
64
+ if (sub.flag & 2 /* WATCHING */) {
65
+ enqueueEffect(sub);
66
+ }
67
+ if (flags & 1 /* MUTABLE */) {
68
+ const subSubs = sub.subLink;
69
+ if (subSubs) {
70
+ const nextSub = (link = subSubs).nextSubLink;
71
+ if (nextSub) {
72
+ stack = { value: next, prev: stack };
73
+ next = nextSub;
74
+ }
75
+ continue;
76
+ }
77
+ }
78
+ if (next) {
79
+ link = next;
80
+ next = link.nextSubLink;
81
+ continue;
82
+ }
83
+ while (stack) {
84
+ link = stack.value;
85
+ stack = stack.prev;
86
+ if (link) {
87
+ next = link.nextSubLink;
88
+ continue top;
89
+ }
90
+ }
91
+ break;
92
+ } while (true);
93
+ }
94
+ function shallowPropagate(link) {
95
+ while (link) {
96
+ const sub = link.subNode;
97
+ const queueBit = sub.flag & 64 /* QUEUED */;
98
+ const flags = sub.flag & -65 /* QUEUED */;
99
+ if (!(flags & 16 /* DIRTY */) && flags & (1 /* MUTABLE */ | 32 /* PENDING */)) {
100
+ const newFlags = queueBit | flags & -33 /* PENDING */ | 16 /* DIRTY */;
101
+ sub.flag = newFlags;
102
+ if (newFlags & 2 /* WATCHING */) {
103
+ enqueueEffect(sub);
104
+ }
105
+ if (flags & 1 /* MUTABLE */ && sub.subLink) {
106
+ shallowPropagate(sub.subLink);
107
+ }
108
+ }
109
+ link = link.nextSubLink;
110
+ }
111
+ }
112
+ function enqueueEffect(effect2) {
113
+ if (!effect2.active) {
114
+ return;
115
+ }
116
+ effect2.notify();
117
+ }
118
+
119
+ // src/link.ts
120
+ var currentLinkVersion = 0;
121
+ var activeSub;
122
+ var isUntracking = false;
123
+ function linkReactiveNode(depNode, subNode) {
124
+ if (isUntracking) {
125
+ return void 0;
126
+ }
127
+ const prevDep = subNode.depLinkTail;
128
+ if (prevDep && prevDep.depNode === depNode) {
129
+ return prevDep;
130
+ }
131
+ const nextDep = prevDep ? prevDep.nextDepLink : subNode.depLink;
132
+ if (nextDep && nextDep.depNode === depNode) {
133
+ nextDep.version = currentLinkVersion;
134
+ subNode.depLinkTail = nextDep;
135
+ return nextDep;
136
+ }
137
+ const prevSub = depNode.subLinkTail;
138
+ if (prevSub && prevSub.version === currentLinkVersion && prevSub.subNode === subNode) {
139
+ subNode.depLinkTail = prevSub;
140
+ return prevSub;
141
+ }
142
+ const newLink = {
143
+ version: currentLinkVersion,
144
+ depNode,
145
+ subNode,
146
+ // Subscriber chain pointers (horizontal)
147
+ prevSubLink: prevSub,
148
+ nextSubLink: void 0,
149
+ // Dependency chain pointers (vertical)
150
+ prevDepLink: prevDep,
151
+ nextDepLink: nextDep
152
+ };
153
+ if (nextDep) {
154
+ nextDep.prevDepLink = newLink;
155
+ }
156
+ if (prevDep) {
157
+ prevDep.nextDepLink = newLink;
158
+ } else {
159
+ subNode.depLink = newLink;
160
+ }
161
+ if (prevSub) {
162
+ prevSub.nextSubLink = newLink;
163
+ } else {
164
+ depNode.subLink = newLink;
165
+ }
166
+ depNode.subLinkTail = newLink;
167
+ subNode.depLinkTail = newLink;
168
+ {
169
+ if (subNode.onTrack && isFunction(subNode == null ? void 0 : subNode.onTrack)) {
170
+ subNode.onTrack({
171
+ effect: subNode,
172
+ target: depNode,
173
+ type: "get",
174
+ key: void 0
175
+ });
176
+ }
177
+ }
178
+ return newLink;
179
+ }
180
+ function unlinkReactiveNode(linkNode, subNode = linkNode.subNode) {
181
+ const depNode = linkNode.depNode;
182
+ const prevSub = linkNode.prevSubLink;
183
+ const nextSub = linkNode.nextSubLink;
184
+ const prevDep = linkNode.prevDepLink;
185
+ const nextDep = linkNode.nextDepLink;
186
+ if (nextDep) {
187
+ nextDep.prevDepLink = prevDep;
188
+ } else {
189
+ subNode.depLinkTail = prevDep;
190
+ }
191
+ if (prevDep) {
192
+ prevDep.nextDepLink = nextDep;
193
+ } else {
194
+ subNode.depLink = nextDep;
195
+ }
196
+ if (nextSub) {
197
+ nextSub.prevSubLink = prevSub;
198
+ } else {
199
+ depNode.subLinkTail = prevSub;
200
+ }
201
+ if (prevSub) {
202
+ prevSub.nextSubLink = nextSub;
203
+ } else {
204
+ depNode.subLink = nextSub;
205
+ if (nextSub === void 0) {
206
+ let toRemove = depNode.depLink;
207
+ while (toRemove) {
208
+ toRemove = unlinkReactiveNode(toRemove, depNode);
209
+ }
210
+ depNode.depLinkTail = void 0;
211
+ depNode.flag |= 16 /* DIRTY */;
212
+ {
213
+ if (depNode.depLink) {
214
+ error(
215
+ "[Link] Cascading cleanup failed: depNode still has dependency links. This indicates a bug in the unlinking logic."
216
+ );
217
+ }
218
+ }
219
+ }
220
+ }
221
+ linkNode.depNode = void 0;
222
+ linkNode.subNode = void 0;
223
+ linkNode.prevSubLink = void 0;
224
+ linkNode.nextSubLink = void 0;
225
+ linkNode.prevDepLink = void 0;
226
+ linkNode.nextDepLink = void 0;
227
+ return nextDep;
228
+ }
229
+ function checkDirty(link, sub) {
230
+ const stack = [{ link, owner: sub }];
231
+ const pendingNodes = [];
232
+ while (stack.length > 0) {
233
+ const frame = stack.pop();
234
+ let current = frame.link;
235
+ const owner = frame.owner;
236
+ while (current) {
237
+ const dep = current.depNode;
238
+ const depFlags = dep.flag;
239
+ if (owner.flag & 16 /* DIRTY */) {
240
+ return true;
241
+ }
242
+ if ((depFlags & (1 /* MUTABLE */ | 16 /* DIRTY */)) === (1 /* MUTABLE */ | 16 /* DIRTY */)) {
243
+ const subs = dep.subLink;
244
+ if (subs && subs.nextSubLink) {
245
+ shallowPropagate2(subs);
246
+ }
247
+ for (const node of pendingNodes) {
248
+ if (node.flag & 32 /* PENDING */) {
249
+ node.flag = node.flag & -33 /* PENDING */ | 16 /* DIRTY */;
250
+ }
251
+ }
252
+ return true;
253
+ }
254
+ if ((depFlags & (1 /* MUTABLE */ | 32 /* PENDING */)) === (1 /* MUTABLE */ | 32 /* PENDING */)) {
255
+ if (dep.depLink) {
256
+ pendingNodes.push(dep);
257
+ stack.push({ link: dep.depLink, owner: dep });
258
+ } else {
259
+ dep.flag &= -33 /* PENDING */;
260
+ }
261
+ } else if (depFlags & 32 /* PENDING */) {
262
+ dep.flag &= -33 /* PENDING */;
263
+ }
264
+ current = current.nextDepLink;
265
+ }
266
+ }
267
+ for (const node of pendingNodes) {
268
+ node.flag &= -33 /* PENDING */;
269
+ }
270
+ if (sub.flag & 32 /* PENDING */) {
271
+ sub.flag &= -33 /* PENDING */;
272
+ }
273
+ return false;
274
+ }
275
+ function shallowPropagate2(link) {
276
+ while (link) {
277
+ const sub = link.subNode;
278
+ const queueBit = sub.flag & 64 /* QUEUED */;
279
+ const flags = sub.flag & -65 /* QUEUED */;
280
+ if ((flags & (32 /* PENDING */ | 16 /* DIRTY */)) === 32 /* PENDING */) {
281
+ sub.flag = queueBit | flags | 16 /* DIRTY */;
282
+ }
283
+ link = link.nextSubLink;
284
+ }
285
+ }
286
+ function setActiveSub(sub) {
287
+ const prev = activeSub;
288
+ activeSub = sub;
289
+ return prev;
290
+ }
291
+ function startTracking(sub) {
292
+ currentLinkVersion++;
293
+ sub.depLinkTail = void 0;
294
+ sub.flag = sub.flag & -57 | 4 /* RECURSED_CHECK */;
295
+ return setActiveSub(sub);
296
+ }
297
+ function endTracking(sub, prevSub) {
298
+ activeSub = prevSub;
299
+ const depsTail = sub.depLinkTail;
300
+ let toRemove = depsTail ? depsTail.nextDepLink : sub.depLink;
301
+ while (toRemove) {
302
+ toRemove = unlinkReactiveNode(toRemove, sub);
303
+ }
304
+ sub.flag &= -5 /* RECURSED_CHECK */;
305
+ }
306
+ function untrack(fn) {
307
+ const prevSub = setActiveSub(void 0);
308
+ const prevUntracking = isUntracking;
309
+ isUntracking = true;
310
+ try {
311
+ return fn();
312
+ } finally {
313
+ isUntracking = prevUntracking;
314
+ setActiveSub(prevSub);
315
+ }
316
+ }
317
+ function isValidLink(checkLink, sub) {
318
+ let link = sub.depLinkTail;
319
+ while (link) {
320
+ if (link === checkLink) {
321
+ return true;
322
+ }
323
+ link = link.prevDepLink;
324
+ }
325
+ return false;
326
+ }
327
+ var targetMap = /* @__PURE__ */ new WeakMap();
328
+ function track(target, key) {
329
+ if (!activeSub || isUntracking) {
330
+ return;
331
+ }
332
+ let depsMap = targetMap.get(target);
333
+ if (!depsMap) {
334
+ depsMap = /* @__PURE__ */ new Map();
335
+ targetMap.set(target, depsMap);
336
+ }
337
+ let dep = depsMap.get(key);
338
+ if (!dep) {
339
+ dep = /* @__PURE__ */ new Set();
340
+ depsMap.set(key, dep);
341
+ }
342
+ if (!dep.has(activeSub)) {
343
+ dep.add(activeSub);
344
+ if (isFunction(activeSub.onTrack)) {
345
+ activeSub.onTrack({
346
+ effect: activeSub,
347
+ target,
348
+ type: "get",
349
+ key
350
+ });
351
+ }
352
+ }
353
+ }
354
+ function trigger(target, type, key, newValue) {
355
+ const depsMap = targetMap.get(target);
356
+ if (!depsMap) {
357
+ return;
358
+ }
359
+ const effects = /* @__PURE__ */ new Set();
360
+ if (key !== void 0) {
361
+ if (Array.isArray(key)) {
362
+ key.forEach((k) => {
363
+ const dep = depsMap.get(k);
364
+ if (dep) {
365
+ dep.forEach((effect2) => effects.add(effect2));
366
+ }
367
+ });
368
+ } else {
369
+ const dep = depsMap.get(key);
370
+ if (dep) {
371
+ dep.forEach((effect2) => effects.add(effect2));
372
+ }
373
+ }
374
+ }
375
+ if (type === "ADD" || type === "DELETE" || type === "CLEAR") {
376
+ const ITERATE_KEY2 = Symbol("iterate");
377
+ const ARRAY_ITERATE_KEY2 = Symbol("arrayIterate");
378
+ const iterationKey = Array.isArray(target) ? ARRAY_ITERATE_KEY2 : ITERATE_KEY2;
379
+ const iterationDep = depsMap.get(iterationKey);
380
+ if (iterationDep) {
381
+ iterationDep.forEach((effect2) => effects.add(effect2));
382
+ }
383
+ }
384
+ effects.forEach((effect2) => {
385
+ var _a5;
386
+ if (isFunction(effect2.onTrigger)) {
387
+ effect2.onTrigger({
388
+ effect: effect2,
389
+ target,
390
+ type,
391
+ key,
392
+ newValue
393
+ });
394
+ }
395
+ if (effect2.flag & 2 /* WATCHING */) {
396
+ (_a5 = effect2.notify) == null ? void 0 : _a5.call(effect2);
397
+ } else if (effect2.flag & 1 /* MUTABLE */) {
398
+ effect2.flag |= 16 /* DIRTY */;
399
+ if (effect2.subLink) {
400
+ propagate(effect2.subLink);
401
+ }
402
+ }
403
+ });
404
+ }
405
+ var reactiveCaches = /* @__PURE__ */ new WeakMap();
406
+ function toRaw(value) {
407
+ if (!value || !isObject(value)) {
408
+ return value;
409
+ }
410
+ const raw = value["_RAW" /* RAW */];
411
+ if (raw) {
412
+ return toRaw(raw);
413
+ }
414
+ if (isSignal(value)) {
415
+ return toRaw(value.peek());
416
+ }
417
+ return value;
418
+ }
419
+ var arrayInstrumentations = createArrayInstrumentations();
420
+ function createArrayInstrumentations() {
421
+ const instrumentations = {};
422
+ ["includes", "indexOf", "lastIndexOf"].forEach((key) => {
423
+ instrumentations[key] = function(...args) {
424
+ const arr = toRaw(this);
425
+ track(arr, ARRAY_ITERATE_KEY);
426
+ let res = arr[key](...args);
427
+ if ((res === -1 || res === false) && args.length > 0) {
428
+ const rawArgs = args.map((arg) => toRaw(arg));
429
+ res = arr[key](...rawArgs);
430
+ }
431
+ return res;
432
+ };
433
+ });
434
+ ["find", "findIndex", "findLast", "findLastIndex"].forEach((key) => {
435
+ instrumentations[key] = function(...args) {
436
+ const arr = toRaw(this);
437
+ const isShallowMode = isShallow(this);
438
+ track(arr, ARRAY_ITERATE_KEY);
439
+ const res = arr[key](...args);
440
+ if ((key === "find" || key === "findLast") && isObject(res) && !isShallowMode) {
441
+ return reactiveImpl(res);
442
+ }
443
+ return res;
444
+ };
445
+ });
446
+ ["push", "pop", "shift", "unshift", "splice", "sort", "reverse", "fill", "copyWithin"].forEach(
447
+ (key) => {
448
+ instrumentations[key] = function(...args) {
449
+ const arr = toRaw(this);
450
+ const res = Array.prototype[key].apply(arr, args);
451
+ trigger(arr, TriggerOpTypes.SET, ARRAY_KEY);
452
+ trigger(arr, TriggerOpTypes.SET, ARRAY_ITERATE_KEY);
453
+ return res;
454
+ };
455
+ }
456
+ );
457
+ ["toReversed", "toSorted", "toSpliced"].forEach((key) => {
458
+ instrumentations[key] = function(...args) {
459
+ const arr = toRaw(this);
460
+ const isShallowMode = isShallow(this);
461
+ track(arr, ARRAY_ITERATE_KEY);
462
+ if (key === "toSpliced") {
463
+ for (let i = 0, l = arr.length; i < l; i++) {
464
+ track(arr, `${i}`);
465
+ }
466
+ }
467
+ const res = Array.prototype[key].apply(arr, args);
468
+ if (!Array.isArray(res)) {
469
+ return res;
470
+ }
471
+ return res.map((item) => isObject(item) ? reactiveImpl(item, isShallowMode) : item);
472
+ };
473
+ });
474
+ ["concat", "slice", "filter", "map", "flatMap", "flat"].forEach((key) => {
475
+ instrumentations[key] = function(...args) {
476
+ const arr = toRaw(this);
477
+ track(arr, ARRAY_ITERATE_KEY);
478
+ const res = Array.prototype[key].apply(arr, args);
479
+ return res;
480
+ };
481
+ });
482
+ ["join", "toString", "toLocaleString"].forEach((key) => {
483
+ instrumentations[key] = function(...args) {
484
+ const arr = toRaw(this);
485
+ track(arr, ARRAY_ITERATE_KEY);
486
+ return Array.prototype[key].apply(arr, args);
487
+ };
488
+ });
489
+ ["values", "keys", "entries", Symbol.iterator].forEach((key) => {
490
+ instrumentations[key] = function() {
491
+ const arr = toRaw(this);
492
+ const isShallowMode = isShallow(this);
493
+ track(arr, ARRAY_KEY);
494
+ const rawIterator = key === Symbol.iterator ? arr[Symbol.iterator]() : arr[key]();
495
+ return {
496
+ next() {
497
+ const { value, done } = rawIterator.next();
498
+ if (done) {
499
+ return { value, done };
500
+ }
501
+ if (Array.isArray(value)) {
502
+ return {
503
+ value: value.map((v) => isObject(v) ? reactiveImpl(v, isShallowMode) : v),
504
+ done
505
+ };
506
+ }
507
+ return {
508
+ value: isObject(value) ? reactiveImpl(value, isShallowMode) : value,
509
+ done
510
+ };
511
+ },
512
+ [Symbol.iterator]() {
513
+ return this;
514
+ }
515
+ };
516
+ };
517
+ });
518
+ return instrumentations;
519
+ }
520
+ var arrayHandlers = (shallow) => ({
521
+ get: (target, key, receiver) => {
522
+ if (key === "_RAW" /* RAW */) {
523
+ return target;
524
+ }
525
+ if (key === "_IS_REACTIVE" /* IS_REACTIVE */) {
526
+ return true;
527
+ }
528
+ if (key === "_IS_SHALLOW" /* IS_SHALLOW */) {
529
+ return shallow;
530
+ }
531
+ if (hasOwn(arrayInstrumentations, key)) {
532
+ return arrayInstrumentations[key];
533
+ }
534
+ const value = Reflect.get(target, key, receiver);
535
+ if (isStringNumber(key)) {
536
+ track(target, key);
537
+ }
538
+ track(target, ARRAY_KEY);
539
+ if (isObject(value) && !shallow) {
540
+ return reactiveImpl(value);
541
+ }
542
+ return value;
543
+ },
544
+ set: (target, key, value, receiver) => {
545
+ const oldValue = Reflect.get(target, key, receiver);
546
+ const result = Reflect.set(target, key, value, receiver);
547
+ if (hasChanged(value, oldValue)) {
548
+ if (isStringNumber(key)) {
549
+ trigger(target, TriggerOpTypes.SET, [key, ARRAY_ITERATE_KEY, ARRAY_KEY]);
550
+ } else {
551
+ trigger(target, TriggerOpTypes.SET, key);
552
+ }
553
+ }
554
+ return result;
555
+ }
556
+ });
557
+ var shallowArrayHandlers = arrayHandlers(true);
558
+ var deepArrayHandlers = arrayHandlers(false);
559
+ var collectionHandlers = {
560
+ get(target, key) {
561
+ if (key === "_IS_REACTIVE" /* IS_REACTIVE */) {
562
+ return true;
563
+ }
564
+ if (key === "_RAW" /* RAW */) {
565
+ return target;
566
+ }
567
+ return Reflect.get(
568
+ hasOwn(collectionInstrumentations, key) ? collectionInstrumentations : target,
569
+ key,
570
+ target
571
+ );
572
+ }
573
+ };
574
+ var weakCollectionHandlers = {
575
+ get(target, key) {
576
+ if (key === "_IS_REACTIVE" /* IS_REACTIVE */) {
577
+ return true;
578
+ }
579
+ if (key === "_RAW" /* RAW */) {
580
+ return target;
581
+ }
582
+ return Reflect.get(
583
+ hasOwn(weakInstrumentations, key) && key in target ? weakInstrumentations : target,
584
+ key,
585
+ target
586
+ );
587
+ }
588
+ };
589
+ var collectionInstrumentations = {
590
+ get(key) {
591
+ const target = toRaw(this);
592
+ track(target, COLLECTION_KEY);
593
+ const value = target.get(key);
594
+ if (isObject(value) && !isShallow(this)) {
595
+ return reactiveImpl(value);
596
+ }
597
+ return value;
598
+ },
599
+ set(key, value) {
600
+ const target = toRaw(this);
601
+ const hadKey = target.has(key);
602
+ const oldValue = target.get(key);
603
+ const rawValue = toRaw(value);
604
+ target.set(key, rawValue);
605
+ if (!hadKey || hasChanged(oldValue, rawValue)) {
606
+ trigger(target, TriggerOpTypes.SET, COLLECTION_KEY);
607
+ }
608
+ return this;
609
+ },
610
+ add(value) {
611
+ const target = toRaw(this);
612
+ const rawValue = toRaw(value);
613
+ const hadValue = target.has(rawValue);
614
+ target.add(rawValue);
615
+ if (!hadValue) {
616
+ trigger(target, TriggerOpTypes.ADD, COLLECTION_KEY);
617
+ } else {
618
+ trigger(target, TriggerOpTypes.SET, COLLECTION_KEY);
619
+ }
620
+ return this;
621
+ },
622
+ has(key) {
623
+ const target = toRaw(this);
624
+ track(target, COLLECTION_KEY);
625
+ const hasKey = target.has(key);
626
+ if (!hasKey && isObject(key)) {
627
+ return target.has(toRaw(key));
628
+ }
629
+ return hasKey;
630
+ },
631
+ delete(key) {
632
+ const target = toRaw(this);
633
+ const hadKey = target.has(key);
634
+ let result = target.delete(key);
635
+ if (!result && isObject(key)) {
636
+ result = target.delete(toRaw(key));
637
+ }
638
+ if (hadKey || result) {
639
+ trigger(target, TriggerOpTypes.DELETE, COLLECTION_KEY);
640
+ }
641
+ return result;
642
+ },
643
+ clear() {
644
+ const target = toRaw(this);
645
+ const hadItems = target.size > 0;
646
+ const result = target.clear();
647
+ if (hadItems) {
648
+ trigger(target, TriggerOpTypes.CLEAR, COLLECTION_KEY);
649
+ }
650
+ return result;
651
+ },
652
+ forEach(callback, thisArg) {
653
+ const target = toRaw(this);
654
+ const isShallowMode = isShallow(this);
655
+ track(target, COLLECTION_KEY);
656
+ target.forEach((value, key) => {
657
+ const wrappedValue = isShallowMode || !isObject(value) ? value : reactiveImpl(value);
658
+ const wrappedKey = isShallowMode || !isObject(key) ? key : reactiveImpl(key);
659
+ callback.call(thisArg, wrappedValue, wrappedKey, this);
660
+ });
661
+ },
662
+ [Symbol.iterator]() {
663
+ const target = toRaw(this);
664
+ const isShallowMode = isShallow(this);
665
+ track(target, COLLECTION_KEY);
666
+ const rawIterator = target[Symbol.iterator]();
667
+ return {
668
+ next() {
669
+ const { value, done } = rawIterator.next();
670
+ if (done) {
671
+ return { value, done };
672
+ }
673
+ if (isShallowMode) {
674
+ return { value, done };
675
+ }
676
+ if (Array.isArray(value)) {
677
+ return {
678
+ value: value.map((v) => isObject(v) ? reactiveImpl(v) : v),
679
+ done
680
+ };
681
+ }
682
+ return {
683
+ value: isObject(value) ? reactiveImpl(value) : value,
684
+ done
685
+ };
686
+ },
687
+ [Symbol.iterator]() {
688
+ return this;
689
+ }
690
+ };
691
+ },
692
+ get size() {
693
+ const target = toRaw(this);
694
+ track(target, COLLECTION_KEY);
695
+ return target.size;
696
+ },
697
+ keys() {
698
+ const target = toRaw(this);
699
+ const isShallowMode = isShallow(this);
700
+ track(target, COLLECTION_KEY);
701
+ const rawIterator = target.keys();
702
+ return {
703
+ next() {
704
+ const { value, done } = rawIterator.next();
705
+ if (done) {
706
+ return { value, done };
707
+ }
708
+ return {
709
+ value: isShallowMode || !isObject(value) ? value : reactiveImpl(value),
710
+ done
711
+ };
712
+ },
713
+ [Symbol.iterator]() {
714
+ return this;
715
+ }
716
+ };
717
+ },
718
+ values() {
719
+ const target = toRaw(this);
720
+ const isShallowMode = isShallow(this);
721
+ track(target, COLLECTION_KEY);
722
+ const rawIterator = target.values();
723
+ return {
724
+ next() {
725
+ const { value, done } = rawIterator.next();
726
+ if (done) {
727
+ return { value, done };
728
+ }
729
+ return {
730
+ value: isShallowMode || !isObject(value) ? value : reactiveImpl(value),
731
+ done
732
+ };
733
+ },
734
+ [Symbol.iterator]() {
735
+ return this;
736
+ }
737
+ };
738
+ },
739
+ entries() {
740
+ const target = toRaw(this);
741
+ const isShallowMode = isShallow(this);
742
+ track(target, COLLECTION_KEY);
743
+ const rawIterator = target.entries();
744
+ return {
745
+ next() {
746
+ const { value, done } = rawIterator.next();
747
+ if (done) {
748
+ return { value, done };
749
+ }
750
+ if (isShallowMode) {
751
+ return { value, done };
752
+ }
753
+ return {
754
+ value: value.map((v) => isObject(v) ? reactiveImpl(v) : v),
755
+ done
756
+ };
757
+ },
758
+ [Symbol.iterator]() {
759
+ return this;
760
+ }
761
+ };
762
+ }
763
+ };
764
+ var weakInstrumentations = {
765
+ get(key) {
766
+ const target = toRaw(this);
767
+ track(target, WEAK_COLLECTION_KEY);
768
+ let value = target.get(key);
769
+ if (value === void 0 && isReactive(key)) {
770
+ value = target.get(toRaw(key));
771
+ }
772
+ if (isObject(value) && !isShallow(this)) {
773
+ return reactiveImpl(value);
774
+ }
775
+ return value;
776
+ },
777
+ set(key, value) {
778
+ const target = toRaw(this);
779
+ const rawKey = toRaw(key);
780
+ const hadKey = target.has(rawKey);
781
+ const oldValue = target.get(rawKey);
782
+ const rawValue = toRaw(value);
783
+ target.set(rawKey, rawValue);
784
+ if (!hadKey || hasChanged(oldValue, rawValue)) {
785
+ trigger(target, TriggerOpTypes.SET, WEAK_COLLECTION_KEY);
786
+ }
787
+ return this;
788
+ },
789
+ add(value) {
790
+ const target = toRaw(this);
791
+ const rawValue = toRaw(value);
792
+ const hadValue = target.has(rawValue);
793
+ target.add(rawValue);
794
+ if (!hadValue) {
795
+ trigger(target, TriggerOpTypes.ADD, WEAK_COLLECTION_KEY);
796
+ }
797
+ return this;
798
+ },
799
+ has(key) {
800
+ const target = toRaw(this);
801
+ track(target, WEAK_COLLECTION_KEY);
802
+ let hasKey = target.has(key);
803
+ if (!hasKey && isReactive(key)) {
804
+ hasKey = target.has(toRaw(key));
805
+ }
806
+ return hasKey;
807
+ },
808
+ delete(key) {
809
+ const target = toRaw(this);
810
+ const rawKey = toRaw(key);
811
+ const hadKey = target.has(rawKey);
812
+ const result = target.delete(rawKey);
813
+ if (hadKey || result) {
814
+ trigger(target, TriggerOpTypes.DELETE, WEAK_COLLECTION_KEY);
815
+ }
816
+ return result;
817
+ }
818
+ };
819
+ var objectHandlers = (shallow) => ({
820
+ get(target, key, receiver) {
821
+ if (key === "_RAW" /* RAW */) {
822
+ return target;
823
+ }
824
+ if (key === "_IS_REACTIVE" /* IS_REACTIVE */) {
825
+ return true;
826
+ }
827
+ if (key === "_IS_SHALLOW" /* IS_SHALLOW */) {
828
+ return shallow;
829
+ }
830
+ const value = Reflect.get(target, key, receiver);
831
+ const valueUnwrapped = isSignal(value) ? value.value : value;
832
+ track(target, key);
833
+ if (isObject(valueUnwrapped) && !shallow) {
834
+ return reactiveImpl(valueUnwrapped);
835
+ }
836
+ return valueUnwrapped;
837
+ },
838
+ set: (target, key, value, receiver) => {
839
+ const oldValue = Reflect.get(target, key, receiver);
840
+ const result = Reflect.set(target, key, toRaw(value), receiver);
841
+ if (hasChanged(value, oldValue)) {
842
+ trigger(target, TriggerOpTypes.SET, key, value);
843
+ }
844
+ return result;
845
+ },
846
+ deleteProperty: (target, key) => {
847
+ const hadKey = hasOwn(target, key);
848
+ const result = Reflect.deleteProperty(target, key);
849
+ if (hadKey && result) {
850
+ trigger(target, TriggerOpTypes.DELETE, key, void 0);
851
+ }
852
+ return result;
853
+ }
854
+ });
855
+ function reactiveImpl(target, shallow = false) {
856
+ if (!isObject(target)) {
857
+ return target;
858
+ }
859
+ if (isReactive(target)) {
860
+ return target;
861
+ }
862
+ const existingProxy = reactiveCaches.get(target);
863
+ if (existingProxy) {
864
+ return existingProxy;
865
+ }
866
+ let handler;
867
+ if (isArray(target)) {
868
+ handler = shallow ? shallowArrayHandlers : deepArrayHandlers;
869
+ } else if (isSet(target) || isMap(target)) {
870
+ handler = collectionHandlers;
871
+ } else if (isWeakMap(target) || isWeakSet(target)) {
872
+ handler = weakCollectionHandlers;
873
+ } else {
874
+ handler = objectHandlers(shallow);
875
+ }
876
+ const proxy = new Proxy(target, handler);
877
+ reactiveCaches.set(target, proxy);
878
+ return proxy;
879
+ }
880
+ function isReactive(target) {
881
+ return !!(target && target["_IS_REACTIVE" /* IS_REACTIVE */]);
882
+ }
883
+ function reactive(target) {
884
+ if (isReactive(target)) {
885
+ {
886
+ warn(
887
+ "[Reactive] Target is already reactive. Returning existing reactive proxy to avoid double wrapping."
888
+ );
889
+ }
890
+ return target;
891
+ }
892
+ if (isSignal(target)) {
893
+ {
894
+ warn(
895
+ "[Reactive] Creating a reactive proxy from a signal is not recommended. Use the signal directly or access its value property."
896
+ );
897
+ }
898
+ return target;
899
+ }
900
+ return reactiveImpl(target);
901
+ }
902
+ function shallowReactive(target) {
903
+ if (isReactive(target)) {
904
+ {
905
+ if (isShallow(target)) {
906
+ warn(
907
+ "[ShallowReactive] Target is already a shallow reactive proxy. Returning existing proxy to avoid double wrapping."
908
+ );
909
+ } else {
910
+ warn(
911
+ "[ShallowReactive] Target is already a deep reactive proxy. Cannot convert deep reactive to shallow reactive. Returning existing proxy."
912
+ );
913
+ }
914
+ }
915
+ return target;
916
+ }
917
+ if (isSignal(target)) {
918
+ {
919
+ warn(
920
+ "[ShallowReactive] Creating a reactive proxy from a signal is not recommended. Use the signal directly or access its value property."
921
+ );
922
+ }
923
+ return target;
924
+ }
925
+ return reactiveImpl(target, true);
926
+ }
927
+ function isShallow(value) {
928
+ return !!(value && value["_IS_SHALLOW" /* IS_SHALLOW */]);
929
+ }
930
+ var toReactive = (value) => isObject(value) ? reactive(value) : value;
931
+
932
+ // src/signal.ts
933
+ var _a;
934
+ _a = "_IS_SIGNAL" /* IS_SIGNAL */;
935
+ var SignalImpl = class {
936
+ // Mark as Signal
937
+ /**
938
+ * Create a new Signal with the given initial value.
939
+ *
940
+ * @param value - Initial value
941
+ * @param shallow - Whether only the top level should be reactive
942
+ */
943
+ constructor(value, shallow = false) {
944
+ this.flag = 1 /* MUTABLE */;
945
+ // Mark whether it's shallow reactive
946
+ // @ts-ignore
947
+ this[_a] = true;
948
+ this._oldValue = this._rawValue = value;
949
+ if (shallow) {
950
+ this._value = isObject(value) ? shallowReactive(value) : value;
951
+ } else {
952
+ this._value = isObject(value) ? reactive(value) : value;
953
+ }
954
+ this["_IS_SHALLOW" /* IS_SHALLOW */] = shallow;
955
+ }
956
+ // dep getter, returns itself for dependency collection
957
+ get dep() {
958
+ return this;
959
+ }
960
+ get value() {
961
+ const sub = activeSub;
962
+ if (sub) {
963
+ linkReactiveNode(this, sub);
964
+ }
965
+ if (this.flag & 16 /* DIRTY */ && this.shouldUpdate()) {
966
+ const subs = this.subLink;
967
+ if (subs) {
968
+ shallowPropagate2(subs);
969
+ }
970
+ }
971
+ return this._value;
972
+ }
973
+ // value setter, triggers update when value changes
974
+ set value(value) {
975
+ if (isSignal(value)) {
976
+ {
977
+ warn(
978
+ "Setting a signal value to another signal is not recommended. The value will be unwrapped automatically."
979
+ );
980
+ }
981
+ value = value.peek();
982
+ }
983
+ value = toRaw(value);
984
+ if (!hasChanged(this._rawValue, value)) {
985
+ return;
986
+ }
987
+ this.flag |= 16 /* DIRTY */;
988
+ this._rawValue = value;
989
+ const shallow = this["_IS_SHALLOW" /* IS_SHALLOW */];
990
+ if (shallow) {
991
+ this._value = isObject(value) ? shallowReactive(value) : value;
992
+ } else {
993
+ this._value = isObject(value) ? reactive(value) : value;
994
+ }
995
+ const subs = this.subLink;
996
+ if (subs) {
997
+ propagate(subs);
998
+ }
999
+ }
1000
+ // Check if the value should be update
1001
+ shouldUpdate() {
1002
+ this.flag &= -17 /* DIRTY */;
1003
+ return hasChanged(this._oldValue, this._oldValue = this._rawValue);
1004
+ }
1005
+ // Get current value without triggering dependency tracking
1006
+ peek() {
1007
+ return this._value;
1008
+ }
1009
+ // set method is an alias for the value setter
1010
+ set(value) {
1011
+ this.value = value;
1012
+ }
1013
+ // Update value using an updater function
1014
+ update(updater) {
1015
+ const nextValue = updater(this.peek());
1016
+ if (isSignal(nextValue)) {
1017
+ {
1018
+ warn(
1019
+ "Returning a signal from an update function is not recommended. The value will be unwrapped."
1020
+ );
1021
+ }
1022
+ this.value = nextValue.peek();
1023
+ } else {
1024
+ this.value = nextValue;
1025
+ }
1026
+ }
1027
+ };
1028
+ function signal(value) {
1029
+ if (isSignal(value)) {
1030
+ {
1031
+ warn(
1032
+ "Creating a signal with another signal is not recommended. The value will be unwrapped."
1033
+ );
1034
+ }
1035
+ return value;
1036
+ }
1037
+ return new SignalImpl(value);
1038
+ }
1039
+ function shallowSignal(value) {
1040
+ if (isSignal(value)) {
1041
+ {
1042
+ warn(
1043
+ "Creating a shallow signal with another signal is not recommended. The value will be unwrapped."
1044
+ );
1045
+ }
1046
+ value = value.peek();
1047
+ }
1048
+ return new SignalImpl(value, true);
1049
+ }
1050
+ function isSignal(value) {
1051
+ return !!value && !!value["_IS_SIGNAL" /* IS_SIGNAL */];
1052
+ }
1053
+ var queue = /* @__PURE__ */ new Set();
1054
+ var activePreFlushCbs = /* @__PURE__ */ new Set();
1055
+ var p = Promise.resolve();
1056
+ var isFlushPending = false;
1057
+ function nextTick(fn) {
1058
+ if (fn) {
1059
+ return new Promise((resolve, reject) => {
1060
+ queueMicrotask(() => {
1061
+ try {
1062
+ fn();
1063
+ resolve();
1064
+ } catch (error6) {
1065
+ reject(error6);
1066
+ }
1067
+ });
1068
+ });
1069
+ }
1070
+ return p;
1071
+ }
1072
+ function queueJob(job) {
1073
+ queue.add(job);
1074
+ queueFlush();
1075
+ }
1076
+ function queueFlush() {
1077
+ if (!isFlushPending) {
1078
+ isFlushPending = true;
1079
+ nextTick(flushJobs);
1080
+ }
1081
+ }
1082
+ function queuePreFlushCb(cb) {
1083
+ activePreFlushCbs.add(cb);
1084
+ queueFlush();
1085
+ }
1086
+ function flushJobs() {
1087
+ isFlushPending = false;
1088
+ flushPreFlushCbs();
1089
+ while (queue.size > 0) {
1090
+ const jobs = Array.from(queue);
1091
+ queue.clear();
1092
+ for (const job of jobs) {
1093
+ try {
1094
+ job();
1095
+ } catch (_error) {
1096
+ {
1097
+ error("Error executing queued job:", _error);
1098
+ }
1099
+ }
1100
+ }
1101
+ }
1102
+ }
1103
+ function flushPreFlushCbs() {
1104
+ const callbacks = Array.from(activePreFlushCbs);
1105
+ activePreFlushCbs.clear();
1106
+ for (const callback of callbacks) {
1107
+ try {
1108
+ callback();
1109
+ } catch (_error) {
1110
+ {
1111
+ error("Error executing pre-flush callback:", _error);
1112
+ }
1113
+ }
1114
+ }
1115
+ }
1116
+ function createScheduler(effect2, flush) {
1117
+ switch (flush) {
1118
+ case "sync":
1119
+ return () => effect2();
1120
+ case "pre":
1121
+ return () => queuePreFlushCb(effect2);
1122
+ case "post":
1123
+ return () => queueJob(effect2);
1124
+ default:
1125
+ {
1126
+ warn(`Invalid flush timing: ${flush}. Defaulting to 'post'.`);
1127
+ }
1128
+ return () => queueJob(effect2);
1129
+ }
1130
+ }
1131
+
1132
+ // src/batch.ts
1133
+ var batchDepth = 0;
1134
+ function batch(fn) {
1135
+ startBatch();
1136
+ try {
1137
+ return fn();
1138
+ } finally {
1139
+ endBatch();
1140
+ }
1141
+ }
1142
+ function startBatch() {
1143
+ batchDepth++;
1144
+ }
1145
+ function endBatch() {
1146
+ if (batchDepth === 0) {
1147
+ warn(
1148
+ "[Batch] endBatch() called without matching startBatch(). This may indicate unbalanced batch calls in your code."
1149
+ );
1150
+ return;
1151
+ }
1152
+ if (--batchDepth === 0) {
1153
+ flushJobs();
1154
+ if (batchDepth !== 0) {
1155
+ error(
1156
+ `[Batch] Batch depth is not zero after endBatch(). Current depth: ${batchDepth}. This indicates a bug in batch management.`
1157
+ );
1158
+ }
1159
+ }
1160
+ }
1161
+ function isBatching() {
1162
+ return batchDepth > 0;
1163
+ }
1164
+ function getBatchDepth() {
1165
+ return batchDepth;
1166
+ }
1167
+
1168
+ // src/effect.ts
1169
+ var _a2;
1170
+ _a2 = "_IS_EFFECT" /* IS_EFFECT */;
1171
+ var EffectImpl = class {
1172
+ /**
1173
+ * Create an Effect instance
1174
+ *
1175
+ * @param fn - The effect function
1176
+ * @param options - Configuration options
1177
+ */
1178
+ constructor(fn, options) {
1179
+ this.flag = 2 /* WATCHING */ | 16 /* DIRTY */;
1180
+ // @ts-ignore
1181
+ this[_a2] = true;
1182
+ // ===== State management =====
1183
+ this._active = true;
1184
+ this.fn = fn;
1185
+ if (options) {
1186
+ this.scheduler = options.flush || options.scheduler;
1187
+ this.onStop = options.onStop;
1188
+ this.onTrack = options.onTrack;
1189
+ this.onTrigger = options.onTrigger;
1190
+ }
1191
+ }
1192
+ /**
1193
+ * Check if the Effect is active
1194
+ */
1195
+ get active() {
1196
+ return this._active;
1197
+ }
1198
+ /**
1199
+ * Check if the Effect is dirty (needs re-execution)
1200
+
1201
+ */
1202
+ get dirty() {
1203
+ const flags = this.flag;
1204
+ if (flags & 16 /* DIRTY */) {
1205
+ return true;
1206
+ }
1207
+ if (flags & 32 /* PENDING */) {
1208
+ if (this.depLink && checkDirty(this.depLink, this)) {
1209
+ this.flag = flags & -33 /* PENDING */ | 16 /* DIRTY */;
1210
+ return true;
1211
+ }
1212
+ this.flag = flags & -33 /* PENDING */;
1213
+ }
1214
+ return false;
1215
+ }
1216
+ /**
1217
+ * Pause Effect execution
1218
+ *
1219
+ * When an effect is paused:
1220
+ * - It stops responding to dependency changes
1221
+ * - Notifications are ignored (see notify method)
1222
+ * - DIRTY and PENDING flags are still set when dependencies change
1223
+ * - The effect remains active and maintains its dependency links
1224
+ *
1225
+ * Use cases:
1226
+ * - Temporarily disable effects during bulk updates
1227
+ * - Prevent effects from running during initialization
1228
+ * - Control when side effects should execute
1229
+ *
1230
+ * @example
1231
+ * ```typescript
1232
+ * const count = signal(0);
1233
+ * const runner = effect(() => console.log(count.value));
1234
+ *
1235
+ * runner.effect.pause();
1236
+ * count.value = 1; // Effect won't run
1237
+ * count.value = 2; // Effect won't run
1238
+ * runner.effect.resume(); // Effect runs once with latest value
1239
+ * ```
1240
+ */
1241
+ pause() {
1242
+ this.flag |= 256 /* PAUSED */;
1243
+ }
1244
+ /**
1245
+ * Resume Effect execution
1246
+ *
1247
+ * When an effect is resumed:
1248
+ * - The PAUSED flag is cleared
1249
+ * - If dependencies changed during pause (DIRTY or PENDING flags set),
1250
+ * the effect executes immediately via notify()
1251
+ * - If no changes occurred, the effect simply becomes active again
1252
+ *
1253
+ * State management:
1254
+ * - Clears PAUSED flag atomically
1255
+ * - Checks for accumulated DIRTY/PENDING flags
1256
+ * - Triggers execution if needed
1257
+ *
1258
+ * @example
1259
+ * ```typescript
1260
+ * const count = signal(0);
1261
+ * const runner = effect(() => console.log(count.value));
1262
+ *
1263
+ * runner.effect.pause();
1264
+ * count.value = 1; // Queued
1265
+ * count.value = 2; // Queued
1266
+ * runner.effect.resume(); // Executes once with count.value = 2
1267
+ * ```
1268
+ */
1269
+ resume() {
1270
+ const flags = this.flag;
1271
+ const nextFlags = flags & -257 /* PAUSED */;
1272
+ this.flag = nextFlags;
1273
+ const wasDirty = (nextFlags & 16 /* DIRTY */) !== 0;
1274
+ const wasPending = (nextFlags & 32 /* PENDING */) !== 0;
1275
+ if (wasDirty || wasPending) {
1276
+ this.notify();
1277
+ }
1278
+ }
1279
+ /**
1280
+ * Execute the Effect function
1281
+ *
1282
+ * Core execution flow:
1283
+ * 1. Check if active
1284
+ * 2. Clear dirty flag
1285
+ * 3. Start tracking dependencies
1286
+ * 4. Execute user function
1287
+ * 5. End tracking, clean up stale dependencies
1288
+
1289
+ * @returns The return value of the effect function
1290
+ */
1291
+ run() {
1292
+ if (!this._active) {
1293
+ return this.fn();
1294
+ }
1295
+ const flags = this.flag;
1296
+ this.flag = flags & -17 /* DIRTY */ | 1024 /* STOP */;
1297
+ const prevSub = startTracking(this);
1298
+ try {
1299
+ return this.fn();
1300
+ } catch (error6) {
1301
+ this.flag |= 16 /* DIRTY */;
1302
+ throw error6;
1303
+ } finally {
1304
+ this.flag &= -1025 /* STOP */;
1305
+ endTracking(this, prevSub);
1306
+ }
1307
+ }
1308
+ /**
1309
+ * Get or create the job function for this effect
1310
+ */
1311
+ getJob() {
1312
+ if (!this._job) {
1313
+ this._job = () => this.run();
1314
+ }
1315
+ return this._job;
1316
+ }
1317
+ /**
1318
+ * Notify that the Effect needs to execute
1319
+ *
1320
+ * Called by dependent reactive values.
1321
+ * Decides whether to execute immediately or defer based on scheduling strategy.
1322
+ */
1323
+ notify() {
1324
+ const flags = this.flag;
1325
+ if (!this._active || flags & (256 /* PAUSED */ | 1024 /* STOP */ | 16 /* DIRTY */)) {
1326
+ return;
1327
+ }
1328
+ this.flag = flags | 16 /* DIRTY */;
1329
+ if (this.onTrigger) {
1330
+ this.onTrigger({
1331
+ effect: this,
1332
+ target: {},
1333
+ type: "set"
1334
+ });
1335
+ }
1336
+ if (this.scheduler) {
1337
+ if (isFunction(this.scheduler)) {
1338
+ this.scheduler(this);
1339
+ } else {
1340
+ const schedulerFn = createScheduler(() => this.run(), this.scheduler);
1341
+ schedulerFn();
1342
+ }
1343
+ } else if (isBatching()) {
1344
+ queueJob(this.getJob());
1345
+ } else {
1346
+ this.run();
1347
+ }
1348
+ }
1349
+ /**
1350
+ * Stop the Effect
1351
+ *
1352
+ * After stopping:
1353
+ * - No longer responds to dependency changes
1354
+ * - Disconnects all dependency links
1355
+ * - Clears cached job function
1356
+ * - Calls onStop callback
1357
+ * - Verifies complete cleanup in development mode
1358
+ */
1359
+ stop() {
1360
+ if (!this._active) {
1361
+ {
1362
+ warn("[Effect] Attempting to stop an already stopped effect.");
1363
+ }
1364
+ return;
1365
+ }
1366
+ this._active = false;
1367
+ let dep = this.depLink;
1368
+ while (dep) {
1369
+ dep = unlinkReactiveNode(dep, this);
1370
+ }
1371
+ let sub = this.subLink;
1372
+ while (sub) {
1373
+ sub = unlinkReactiveNode(sub);
1374
+ }
1375
+ this._job = void 0;
1376
+ this.depLinkTail = void 0;
1377
+ this.subLinkTail = void 0;
1378
+ {
1379
+ if (this.depLink) {
1380
+ error(
1381
+ "[Effect] Cleanup verification failed: depLink not cleared. This indicates a memory leak in the dependency tracking system."
1382
+ );
1383
+ }
1384
+ if (this.subLink) {
1385
+ error(
1386
+ "[Effect] Cleanup verification failed: subLink not cleared. This indicates a memory leak in the subscription system."
1387
+ );
1388
+ }
1389
+ }
1390
+ if (this.onStop) {
1391
+ this.onStop();
1392
+ }
1393
+ }
1394
+ };
1395
+ function effect(fn, options) {
1396
+ const effectInstance = new EffectImpl(fn, options);
1397
+ try {
1398
+ effectInstance.run();
1399
+ } catch (_error) {
1400
+ effectInstance.stop();
1401
+ {
1402
+ error(
1403
+ "[Effect] Effect failed during initial execution and has been stopped. Fix the error in your effect function.",
1404
+ _error
1405
+ );
1406
+ }
1407
+ throw _error;
1408
+ }
1409
+ const runner = () => effectInstance.run();
1410
+ runner.effect = effectInstance;
1411
+ runner.stop = () => effectInstance.stop();
1412
+ return runner;
1413
+ }
1414
+ function stop(runner) {
1415
+ runner.effect.stop();
1416
+ }
1417
+ function isEffect(value) {
1418
+ return !!(value && value["_IS_EFFECT" /* IS_EFFECT */]);
1419
+ }
1420
+ function memoEffect(fn, initialState, options) {
1421
+ let currentState = initialState;
1422
+ const effectFn = () => {
1423
+ const result = fn(currentState);
1424
+ currentState = result;
1425
+ };
1426
+ return effect(effectFn, options);
1427
+ }
1428
+ var NO_VALUE = Symbol("computed-no-value");
1429
+ var _a3;
1430
+ _a3 = "_IS_COMPUTED" /* IS_COMPUTED */;
1431
+ var ComputedImpl = class {
1432
+ /**
1433
+ * Create a Computed instance
1434
+ *
1435
+ * @param getter - The computation function
1436
+ * @param setter - Optional setter function
1437
+ * @param onTrack - Optional debug callback for dependency tracking
1438
+ * @param onTrigger - Optional debug callback for triggers
1439
+ */
1440
+ constructor(getter, setter, onTrack, onTrigger) {
1441
+ this.flag = 1 /* MUTABLE */ | 16 /* DIRTY */;
1442
+ //@ts-ignore
1443
+ this[_a3] = true;
1444
+ // ===== Cache =====
1445
+ // Use symbol sentinel to distinguish "no value" from undefined/null values
1446
+ this._value = NO_VALUE;
1447
+ this.getter = getter;
1448
+ this.setter = setter;
1449
+ this.onTrack = onTrack;
1450
+ this.onTrigger = onTrigger;
1451
+ this.flag |= 16 /* DIRTY */;
1452
+ }
1453
+ get value() {
1454
+ if (activeSub) {
1455
+ linkReactiveNode(this, activeSub);
1456
+ }
1457
+ const flags = this.flag;
1458
+ const hasValue = this._value !== NO_VALUE;
1459
+ if (hasValue && !(flags & (16 /* DIRTY */ | 32 /* PENDING */))) {
1460
+ return this._value;
1461
+ }
1462
+ if (!hasValue || flags & 16 /* DIRTY */) {
1463
+ this.recompute();
1464
+ return this._value;
1465
+ }
1466
+ if (flags & 32 /* PENDING */) {
1467
+ if (this.depLink && checkDirty(this.depLink, this)) {
1468
+ this.recompute();
1469
+ } else {
1470
+ this.flag = flags & -33 /* PENDING */;
1471
+ }
1472
+ }
1473
+ return this._value;
1474
+ }
1475
+ /**
1476
+ * Set value (only effective when setter is provided)
1477
+ *
1478
+ * @param newValue - The new value
1479
+ */
1480
+ set value(newValue) {
1481
+ if (this.setter) {
1482
+ this.setter(newValue);
1483
+ } else {
1484
+ warn(
1485
+ "[Computed] Cannot set readonly computed value. Provide a setter in the computed options to make it writable.\nExample: computed({ get: () => value, set: (v) => { ... } })"
1486
+ );
1487
+ }
1488
+ }
1489
+ /**
1490
+ * Read value without tracking dependencies
1491
+ *
1492
+ * @returns Current value
1493
+ */
1494
+ peek() {
1495
+ if (this._value === NO_VALUE) {
1496
+ this.recompute();
1497
+ }
1498
+ return this._value;
1499
+ }
1500
+ /**
1501
+ * Recompute the value
1502
+ *
1503
+ * computation logic:
1504
+ * 1. Start tracking dependencies
1505
+ * 2. Execute getter function
1506
+ * 3. Check if value changed using optimized comparison
1507
+ * 4. If changed, update cache and notify subscribers
1508
+ * 5. End tracking, clean up stale dependencies
1509
+ * @private
1510
+ */
1511
+ recompute() {
1512
+ const oldValue = this._value;
1513
+ const hadValue = oldValue !== NO_VALUE;
1514
+ const prevSub = startTracking(this);
1515
+ try {
1516
+ const newValue = this.getter();
1517
+ const flags = this.flag;
1518
+ const clearMask = ~(16 /* DIRTY */ | 32 /* PENDING */);
1519
+ const valueChanged = !hadValue || hasChanged(oldValue, newValue);
1520
+ if (valueChanged) {
1521
+ this._value = newValue;
1522
+ this.flag = flags & clearMask;
1523
+ if (this.onTrigger) {
1524
+ this.onTrigger({
1525
+ effect: this,
1526
+ target: this,
1527
+ type: "set",
1528
+ key: "value",
1529
+ newValue
1530
+ });
1531
+ }
1532
+ if (this.subLink) {
1533
+ shallowPropagate(this.subLink);
1534
+ }
1535
+ } else {
1536
+ this.flag = flags & clearMask;
1537
+ }
1538
+ } catch (_error) {
1539
+ this.flag &= -49;
1540
+ {
1541
+ error(
1542
+ "[Computed] Error occurred while computing value. Check your getter function for errors.",
1543
+ _error
1544
+ );
1545
+ }
1546
+ throw _error;
1547
+ } finally {
1548
+ endTracking(this, prevSub);
1549
+ }
1550
+ }
1551
+ /**
1552
+ * Check if update is needed
1553
+ *
1554
+ * Internal use, called by reactive system.
1555
+ *
1556
+ * @returns true if value changed
1557
+ */
1558
+ shouldUpdate() {
1559
+ const hadValue = this._value !== NO_VALUE;
1560
+ const oldValue = this._value;
1561
+ this.recompute();
1562
+ if (!hadValue) {
1563
+ return true;
1564
+ }
1565
+ return hasChanged(this._value, oldValue);
1566
+ }
1567
+ };
1568
+ function computed(getterOrOptions) {
1569
+ if (isComputed(getterOrOptions)) {
1570
+ {
1571
+ warn(
1572
+ "[Computed] Creating a computed from another computed is not recommended. The existing computed will be returned to avoid unnecessary wrapping."
1573
+ );
1574
+ }
1575
+ return getterOrOptions;
1576
+ }
1577
+ if (!getterOrOptions) {
1578
+ throw new Error(
1579
+ "[Computed] Invalid argument: computed() requires a getter function or options object."
1580
+ );
1581
+ }
1582
+ if (isFunction(getterOrOptions)) {
1583
+ return new ComputedImpl(getterOrOptions);
1584
+ }
1585
+ if (isPlainObject(getterOrOptions)) {
1586
+ const { get, set, onTrack, onTrigger } = getterOrOptions;
1587
+ if (!get) {
1588
+ throw new Error(
1589
+ "[Computed] Invalid options: getter function is required.\nUsage: computed({ get: () => value, set: (v) => { ... } })"
1590
+ );
1591
+ }
1592
+ if (!isFunction(get)) {
1593
+ throw new TypeError(
1594
+ `[Computed] Invalid options: getter must be a function.
1595
+ Received: ${typeof get}`
1596
+ );
1597
+ }
1598
+ return new ComputedImpl(get, set, onTrack, onTrigger);
1599
+ }
1600
+ throw new Error(
1601
+ `[Computed] Invalid argument: expected a function or options object.
1602
+ Received: ${typeof getterOrOptions}`
1603
+ );
1604
+ }
1605
+ function isComputed(value) {
1606
+ return !!value && !!value["_IS_COMPUTED" /* IS_COMPUTED */];
1607
+ }
1608
+ function createOptionsStore(options) {
1609
+ if (!options.state) {
1610
+ warn("Store state is required");
1611
+ throw new Error("Store state is required");
1612
+ }
1613
+ const { state, getters, actions } = options;
1614
+ const initState = __spreadValues({}, state);
1615
+ const reactiveState = reactive(state);
1616
+ const subscriptions = /* @__PURE__ */ new Set();
1617
+ const actionCallbacks = /* @__PURE__ */ new Set();
1618
+ const defaultActions = {
1619
+ patch$(payload) {
1620
+ if (!payload) {
1621
+ warn("Patch payload is required");
1622
+ return;
1623
+ }
1624
+ batch(() => {
1625
+ Object.assign(reactiveState, payload);
1626
+ });
1627
+ subscriptions.forEach((callback) => callback(reactiveState));
1628
+ actionCallbacks.forEach((callback) => callback(reactiveState));
1629
+ },
1630
+ subscribe$(callback) {
1631
+ if (!callback) {
1632
+ warn("Subscribe callback is required");
1633
+ return;
1634
+ }
1635
+ subscriptions.add(callback);
1636
+ },
1637
+ unsubscribe$(callback) {
1638
+ subscriptions.delete(callback);
1639
+ },
1640
+ onAction$(callback) {
1641
+ if (!callback) {
1642
+ warn("Action callback is required");
1643
+ return;
1644
+ }
1645
+ actionCallbacks.add(callback);
1646
+ },
1647
+ reset$() {
1648
+ batch(() => {
1649
+ Object.assign(reactiveState, initState);
1650
+ });
1651
+ subscriptions.forEach((callback) => callback(reactiveState));
1652
+ actionCallbacks.forEach((callback) => callback(reactiveState));
1653
+ }
1654
+ };
1655
+ const store = __spreadValues(__spreadProps(__spreadValues({}, reactiveState), {
1656
+ state: reactiveState
1657
+ }), defaultActions);
1658
+ if (getters) {
1659
+ for (const key in getters) {
1660
+ const getter = getters[key];
1661
+ if (getter) {
1662
+ Object.defineProperty(store, key, {
1663
+ get() {
1664
+ return computed(() => getter.call(store, reactiveState)).value;
1665
+ },
1666
+ enumerable: true,
1667
+ configurable: true
1668
+ });
1669
+ }
1670
+ }
1671
+ }
1672
+ if (actions) {
1673
+ for (const key in actions) {
1674
+ const action = actions[key];
1675
+ if (action) {
1676
+ store[key] = (...args) => {
1677
+ const result = action.apply(reactiveState, args);
1678
+ actionCallbacks.forEach((callback) => callback(reactiveState));
1679
+ return result;
1680
+ };
1681
+ }
1682
+ }
1683
+ }
1684
+ return store;
1685
+ }
1686
+ function createClassStore(StoreClass) {
1687
+ const instance = new StoreClass();
1688
+ const state = /* @__PURE__ */ Object.create(null);
1689
+ const getters = {};
1690
+ const actions = {};
1691
+ Object.getOwnPropertyNames(instance).forEach((key) => {
1692
+ state[key] = instance[key];
1693
+ });
1694
+ Object.getOwnPropertyNames(StoreClass.prototype).forEach((key) => {
1695
+ const descriptor = Object.getOwnPropertyDescriptor(StoreClass.prototype, key);
1696
+ if (descriptor) {
1697
+ if (typeof descriptor.get === "function") {
1698
+ getters[key] = function() {
1699
+ return descriptor.get.call(this);
1700
+ };
1701
+ } else if (typeof descriptor.value === "function" && key !== "constructor") {
1702
+ actions[key] = function(...args) {
1703
+ return descriptor.value.apply(this, args);
1704
+ };
1705
+ }
1706
+ }
1707
+ });
1708
+ return {
1709
+ state,
1710
+ getters,
1711
+ actions
1712
+ };
1713
+ }
1714
+ function createStore(storeDefinition) {
1715
+ if (!storeDefinition) {
1716
+ warn("Store definition is required");
1717
+ throw new Error("Store definition is required");
1718
+ }
1719
+ return () => {
1720
+ let options;
1721
+ if (typeof storeDefinition === "function") {
1722
+ options = createClassStore(storeDefinition);
1723
+ } else {
1724
+ options = storeDefinition;
1725
+ }
1726
+ const store = createOptionsStore(options);
1727
+ if (typeof storeDefinition === "function") {
1728
+ Object.keys(options.actions || {}).forEach((key) => {
1729
+ store[key] = options.actions[key].bind(store);
1730
+ });
1731
+ }
1732
+ return store;
1733
+ };
1734
+ }
1735
+ var _a4, _b;
1736
+ var RefImpl = class extends (_b = SignalImpl, _a4 = "_IS_REF" /* IS_REF */, _b) {
1737
+ /**
1738
+ * Creates a new ref with the given initial value.
1739
+ *
1740
+ * @param value - The initial value
1741
+ */
1742
+ constructor(value) {
1743
+ super(value, true);
1744
+ // @ts-ignore
1745
+ this[_a4] = true;
1746
+ }
1747
+ get value() {
1748
+ track(this, SIGNAL_KEY);
1749
+ return this._value;
1750
+ }
1751
+ set value(newValue) {
1752
+ if (isSignal(newValue)) {
1753
+ newValue = newValue.value;
1754
+ }
1755
+ if (isRef(newValue)) {
1756
+ newValue = newValue.value;
1757
+ }
1758
+ if (hasChanged(this._value, newValue)) {
1759
+ this._value = newValue;
1760
+ if (this.subLink) {
1761
+ shallowPropagate2(this.subLink);
1762
+ }
1763
+ trigger(this, "SET", SIGNAL_KEY);
1764
+ }
1765
+ }
1766
+ };
1767
+ function ref(value = void 0) {
1768
+ if (isRef(value)) {
1769
+ {
1770
+ info("Creating a ref with another ref is not recommended. The value will be unwrapped.");
1771
+ }
1772
+ return value;
1773
+ }
1774
+ if (isSignal(value)) {
1775
+ {
1776
+ info("Creating a ref with a signal is not recommended. The value will be unwrapped.");
1777
+ }
1778
+ return new RefImpl(value.peek());
1779
+ }
1780
+ return new RefImpl(value);
1781
+ }
1782
+ function isRef(value) {
1783
+ return !!value && !!value["_IS_REF" /* IS_REF */];
1784
+ }
1785
+ var INITIAL_WATCHER_VALUE = {};
1786
+ var cleanupMap = /* @__PURE__ */ new WeakMap();
1787
+ function traverse(value, seen = /* @__PURE__ */ new Set()) {
1788
+ if (!isObject(value) || seen.has(value)) {
1789
+ return value;
1790
+ }
1791
+ seen.add(value);
1792
+ if (isSignal(value) || isComputed(value)) {
1793
+ return traverse(value.value, seen);
1794
+ }
1795
+ if (Array.isArray(value)) {
1796
+ for (const element of value) {
1797
+ traverse(element, seen);
1798
+ }
1799
+ } else if (isMap(value)) {
1800
+ value.forEach((v) => {
1801
+ traverse(v, seen);
1802
+ });
1803
+ value.keys();
1804
+ value.values();
1805
+ } else if (isSet(value)) {
1806
+ value.forEach((v) => {
1807
+ traverse(v, seen);
1808
+ });
1809
+ value.values();
1810
+ } else {
1811
+ Object.keys(value).forEach((key) => {
1812
+ traverse(value[key], seen);
1813
+ });
1814
+ }
1815
+ return value;
1816
+ }
1817
+ function cloneValue(value) {
1818
+ if (!isObject(value)) {
1819
+ return value;
1820
+ }
1821
+ if (Array.isArray(value)) {
1822
+ return value.map((item) => cloneValue(item));
1823
+ }
1824
+ if (isMap(value)) {
1825
+ const cloned2 = /* @__PURE__ */ new Map();
1826
+ value.forEach((v, k) => {
1827
+ cloned2.set(k, cloneValue(v));
1828
+ });
1829
+ return cloned2;
1830
+ }
1831
+ if (isSet(value)) {
1832
+ const cloned2 = /* @__PURE__ */ new Set();
1833
+ value.forEach((v) => {
1834
+ cloned2.add(cloneValue(v));
1835
+ });
1836
+ return cloned2;
1837
+ }
1838
+ const cloned = {};
1839
+ for (const key of Object.keys(value)) {
1840
+ cloned[key] = cloneValue(value[key]);
1841
+ }
1842
+ return cloned;
1843
+ }
1844
+ function resolveSource(source) {
1845
+ if (Array.isArray(source)) {
1846
+ return () => source.map((s) => {
1847
+ if (isSignal(s) || isComputed(s)) {
1848
+ return s.value;
1849
+ }
1850
+ if (isReactive(s)) {
1851
+ return traverse(s);
1852
+ }
1853
+ if (isFunction(s)) {
1854
+ return s();
1855
+ }
1856
+ return s;
1857
+ });
1858
+ }
1859
+ if (isFunction(source)) {
1860
+ return source;
1861
+ }
1862
+ if (isSignal(source)) {
1863
+ return () => source.value;
1864
+ }
1865
+ if (isObject(source) && "value" in source) {
1866
+ return () => source.value;
1867
+ }
1868
+ if (isReactive(source)) {
1869
+ return () => traverse(source);
1870
+ }
1871
+ return () => source;
1872
+ }
1873
+ function watch(source, callback, options = {}) {
1874
+ const { immediate = false, deep = false } = options;
1875
+ let oldValue = INITIAL_WATCHER_VALUE;
1876
+ const getter = resolveSource(source);
1877
+ const job = () => {
1878
+ const currentEffect = runner.effect;
1879
+ if (!currentEffect.run) {
1880
+ return;
1881
+ }
1882
+ const newValue = currentEffect.run();
1883
+ if (hasChanged(newValue, oldValue)) {
1884
+ callback(newValue, oldValue === INITIAL_WATCHER_VALUE ? void 0 : oldValue);
1885
+ oldValue = cloneValue(newValue);
1886
+ }
1887
+ };
1888
+ const runner = effect(
1889
+ () => {
1890
+ const value = getter();
1891
+ if (deep) {
1892
+ traverse(value);
1893
+ }
1894
+ return value;
1895
+ },
1896
+ {
1897
+ // Use scheduler to queue job, implementing async and debouncing.
1898
+ scheduler: () => queueJob(job)
1899
+ }
1900
+ );
1901
+ if (immediate) {
1902
+ job();
1903
+ } else {
1904
+ oldValue = cloneValue(runner.effect.run());
1905
+ }
1906
+ return () => {
1907
+ runner.stop();
1908
+ const cleanups = cleanupMap.get(runner.effect);
1909
+ if (cleanups) {
1910
+ cleanups.forEach((fn) => fn());
1911
+ cleanupMap.delete(runner.effect);
1912
+ }
1913
+ };
1914
+ }
1915
+
1916
+ export { TriggerOpTypes, batch, computed, createStore, effect, endBatch, getBatchDepth, isBatching, isComputed, isEffect, isReactive, isRef, isShallow, isSignal, memoEffect, nextTick, queueJob, queuePreFlushCb, reactive, ref, shallowReactive, shallowSignal, signal, startBatch, stop, toRaw, toReactive, trigger, untrack, watch };