@rlabs-inc/signals 0.2.0 → 1.0.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.
package/dist/index.js CHANGED
@@ -29,452 +29,1006 @@ var __export = (target, all) => {
29
29
  // src/index.ts
30
30
  var exports_src = {};
31
31
  __export(exports_src, {
32
- watch: () => watch,
32
+ writeVersion: () => writeVersion,
33
+ updateReaction: () => updateReaction,
34
+ updateEffect: () => updateEffect,
35
+ untracking: () => untracking,
33
36
  untrack: () => untrack,
34
37
  toRaw: () => toRaw,
38
+ tick: () => tick,
39
+ stateRaw: () => stateRaw,
35
40
  state: () => state,
41
+ source: () => source,
36
42
  signal: () => signal,
37
43
  shallowEquals: () => shallowEquals,
38
- readonly: () => readonly,
39
- reactiveArray: () => reactiveArray,
44
+ setUntracking: () => setUntracking,
45
+ setSignalStatus: () => setSignalStatus,
46
+ setActiveReaction: () => setActiveReaction,
47
+ setActiveEffect: () => setActiveEffect,
48
+ set: () => set,
49
+ safeNotEqual: () => safeNotEqual,
50
+ safeEquals: () => safeEquals,
51
+ removeReactions: () => removeReactions,
52
+ readVersion: () => readVersion,
53
+ proxy: () => proxy,
40
54
  peek: () => peek,
55
+ neverEquals: () => neverEquals,
56
+ mutableSource: () => mutableSource,
57
+ markReactions: () => markReactions,
41
58
  isReactive: () => isReactive,
42
- effectScope: () => effectScope,
59
+ isDirty: () => isDirty,
60
+ incrementWriteVersion: () => incrementWriteVersion,
61
+ incrementReadVersion: () => incrementReadVersion,
62
+ incrementBatchDepth: () => incrementBatchDepth,
63
+ getWriteVersion: () => getWriteVersion,
64
+ getReadVersion: () => getReadVersion,
65
+ getBatchDepth: () => getBatchDepth,
66
+ get: () => get,
67
+ flushSync: () => flushSync,
68
+ equals: () => equals,
43
69
  effect: () => effect,
70
+ disconnectDerived: () => disconnectDerived,
71
+ destroyEffect: () => destroyEffect,
44
72
  derived: () => derived,
45
- defaultEquals: () => defaultEquals,
73
+ decrementBatchDepth: () => decrementBatchDepth,
74
+ createEquals: () => createEquals,
75
+ createEffect: () => createEffect,
76
+ createDerived: () => createDerived,
77
+ batchDepth: () => batchDepth,
46
78
  batch: () => batch,
79
+ alwaysEquals: () => alwaysEquals,
80
+ activeReaction: () => activeReaction,
81
+ activeEffect: () => activeEffect,
82
+ USER_EFFECT: () => USER_EFFECT,
83
+ UNOWNED: () => UNOWNED,
84
+ UNINITIALIZED: () => UNINITIALIZED,
85
+ STATE_SYMBOL: () => STATE_SYMBOL,
86
+ STALE_REACTION: () => STALE_REACTION,
47
87
  ReactiveSet: () => ReactiveSet,
48
- ReactiveMap: () => ReactiveMap
88
+ ReactiveMap: () => ReactiveMap,
89
+ ReactiveDate: () => ReactiveDate,
90
+ ROOT_EFFECT: () => ROOT_EFFECT,
91
+ RENDER_EFFECT: () => RENDER_EFFECT,
92
+ REACTIVE_MARKER: () => REACTIVE_MARKER,
93
+ REACTION_IS_UPDATING: () => REACTION_IS_UPDATING,
94
+ MAYBE_DIRTY: () => MAYBE_DIRTY,
95
+ INERT: () => INERT,
96
+ EFFECT_RAN: () => EFFECT_RAN,
97
+ EFFECT_PRESERVED: () => EFFECT_PRESERVED,
98
+ EFFECT: () => EFFECT,
99
+ DISCONNECTED: () => DISCONNECTED,
100
+ DIRTY: () => DIRTY,
101
+ DESTROYED: () => DESTROYED,
102
+ DERIVED: () => DERIVED,
103
+ CLEAN: () => CLEAN,
104
+ BRANCH_EFFECT: () => BRANCH_EFFECT,
105
+ BLOCK_EFFECT: () => BLOCK_EFFECT
49
106
  });
50
107
  module.exports = __toCommonJS(exports_src);
51
- var activeReaction = null;
52
- var reactionStack = [];
53
- var batchDepth = 0;
54
- var pendingReactions = new Set;
55
- var untracking = false;
56
- var proxyToSignal = new WeakMap;
57
- var rawToProxy = new WeakMap;
58
- var defaultEquals = (a, b) => Object.is(a, b);
59
- var shallowEquals = (a, b) => {
60
- if (Object.is(a, b))
108
+
109
+ // src/reactivity/equality.ts
110
+ var equals = (oldValue, newValue) => Object.is(oldValue, newValue);
111
+ function safeNotEqual(a, b) {
112
+ return a != a ? b == b : a !== b || a !== null && typeof a === "object" || typeof a === "function";
113
+ }
114
+ var safeEquals = (oldValue, newValue) => !safeNotEqual(oldValue, newValue);
115
+ var shallowEquals = (oldValue, newValue) => {
116
+ if (Object.is(oldValue, newValue)) {
61
117
  return true;
62
- if (typeof a !== "object" || typeof b !== "object")
63
- return false;
64
- if (a === null || b === null)
118
+ }
119
+ if (typeof oldValue !== "object" || oldValue === null || typeof newValue !== "object" || newValue === null) {
65
120
  return false;
66
- const keysA = Object.keys(a);
67
- const keysB = Object.keys(b);
68
- if (keysA.length !== keysB.length)
121
+ }
122
+ if (Array.isArray(oldValue) && Array.isArray(newValue)) {
123
+ if (oldValue.length !== newValue.length) {
124
+ return false;
125
+ }
126
+ for (let i = 0;i < oldValue.length; i++) {
127
+ if (!Object.is(oldValue[i], newValue[i])) {
128
+ return false;
129
+ }
130
+ }
131
+ return true;
132
+ }
133
+ const oldKeys = Object.keys(oldValue);
134
+ const newKeys = Object.keys(newValue);
135
+ if (oldKeys.length !== newKeys.length) {
69
136
  return false;
70
- for (const key of keysA) {
71
- if (!Object.is(a[key], b[key]))
137
+ }
138
+ for (const key of oldKeys) {
139
+ if (!Object.prototype.hasOwnProperty.call(newValue, key) || !Object.is(oldValue[key], newValue[key])) {
72
140
  return false;
141
+ }
73
142
  }
74
143
  return true;
75
144
  };
76
- function signal(initial, options) {
77
- const internal = {
78
- v: initial,
79
- reactions: new Set,
80
- equals: options?.equals ?? defaultEquals
81
- };
82
- let proxyCache = null;
83
- return {
84
- get value() {
85
- track(internal);
86
- if (internal.v !== null && typeof internal.v === "object") {
87
- if (!proxyCache) {
88
- proxyCache = createDeepReactiveForSignal(internal.v, internal);
145
+ function createEquals(fn) {
146
+ return (oldValue, newValue) => fn(oldValue, newValue);
147
+ }
148
+ var neverEquals = () => false;
149
+ var alwaysEquals = () => true;
150
+
151
+ // src/core/constants.ts
152
+ var DERIVED = 1 << 1;
153
+ var EFFECT = 1 << 2;
154
+ var RENDER_EFFECT = 1 << 3;
155
+ var ROOT_EFFECT = 1 << 4;
156
+ var BRANCH_EFFECT = 1 << 5;
157
+ var USER_EFFECT = 1 << 6;
158
+ var BLOCK_EFFECT = 1 << 7;
159
+ var CLEAN = 1 << 10;
160
+ var DIRTY = 1 << 11;
161
+ var MAYBE_DIRTY = 1 << 12;
162
+ var REACTION_IS_UPDATING = 1 << 13;
163
+ var DESTROYED = 1 << 14;
164
+ var INERT = 1 << 15;
165
+ var EFFECT_RAN = 1 << 16;
166
+ var EFFECT_PRESERVED = 1 << 17;
167
+ var UNOWNED = 1 << 8;
168
+ var DISCONNECTED = 1 << 9;
169
+ var INSPECT_EFFECT = 1 << 18;
170
+ var UNINITIALIZED = Symbol.for("rlabs.signals.uninitialized");
171
+ var STALE_REACTION = Symbol.for("rlabs.signals.stale_reaction");
172
+ var STATE_SYMBOL = Symbol.for("rlabs.signals.state");
173
+ var REACTIVE_MARKER = Symbol.for("rlabs.signals.reactive");
174
+ var STATUS_MASK = ~(DIRTY | MAYBE_DIRTY | CLEAN);
175
+
176
+ // src/core/globals.ts
177
+ var activeReaction = null;
178
+ var activeEffect = null;
179
+ var untracking = false;
180
+ var writeVersion = 1;
181
+ var readVersion = 0;
182
+ var newDeps = null;
183
+ var skippedDeps = 0;
184
+ var untrackedWrites = null;
185
+ var batchDepth = 0;
186
+ var pendingReactions = new Set;
187
+ var queuedRootEffects = [];
188
+ var isFlushingSync = false;
189
+ function setActiveReaction(reaction) {
190
+ const prev = activeReaction;
191
+ activeReaction = reaction;
192
+ return prev;
193
+ }
194
+ function setActiveEffect(effect) {
195
+ const prev = activeEffect;
196
+ activeEffect = effect;
197
+ return prev;
198
+ }
199
+ function setUntracking(value) {
200
+ const prev = untracking;
201
+ untracking = value;
202
+ return prev;
203
+ }
204
+ function incrementWriteVersion() {
205
+ return ++writeVersion;
206
+ }
207
+ function incrementReadVersion() {
208
+ return ++readVersion;
209
+ }
210
+ function setNewDeps(deps) {
211
+ const prev = newDeps;
212
+ newDeps = deps;
213
+ return prev;
214
+ }
215
+ function setSkippedDeps(count) {
216
+ const prev = skippedDeps;
217
+ skippedDeps = count;
218
+ return prev;
219
+ }
220
+ function setUntrackedWrites(writes) {
221
+ const prev = untrackedWrites;
222
+ untrackedWrites = writes;
223
+ return prev;
224
+ }
225
+ function addUntrackedWrite(signal) {
226
+ if (untrackedWrites === null) {
227
+ untrackedWrites = [signal];
228
+ } else {
229
+ untrackedWrites.push(signal);
230
+ }
231
+ }
232
+ function incrementBatchDepth() {
233
+ return ++batchDepth;
234
+ }
235
+ function decrementBatchDepth() {
236
+ return --batchDepth;
237
+ }
238
+ function setIsFlushingSync(value) {
239
+ const prev = isFlushingSync;
240
+ isFlushingSync = value;
241
+ return prev;
242
+ }
243
+ function clearPendingReactions() {
244
+ pendingReactions = new Set;
245
+ }
246
+ function addPendingReaction(reaction) {
247
+ pendingReactions.add(reaction);
248
+ }
249
+ function clearQueuedRootEffects() {
250
+ const prev = queuedRootEffects;
251
+ queuedRootEffects = [];
252
+ return prev;
253
+ }
254
+ function addQueuedRootEffect(effect) {
255
+ queuedRootEffects.push(effect);
256
+ }
257
+ function getReadVersion() {
258
+ return readVersion;
259
+ }
260
+ function getWriteVersion() {
261
+ return writeVersion;
262
+ }
263
+ function getBatchDepth() {
264
+ return batchDepth;
265
+ }
266
+
267
+ // src/reactivity/scheduling.ts
268
+ function scheduleEffect(reaction) {
269
+ addPendingReaction(reaction);
270
+ if (batchDepth > 0) {
271
+ return;
272
+ }
273
+ let effect = reaction;
274
+ while (effect.parent !== null) {
275
+ effect = effect.parent;
276
+ const flags = effect.f;
277
+ if ((flags & (ROOT_EFFECT | BRANCH_EFFECT)) !== 0) {
278
+ if ((flags & CLEAN) === 0) {
279
+ return;
280
+ }
281
+ effect.f ^= CLEAN;
282
+ }
283
+ }
284
+ addQueuedRootEffect(effect);
285
+ if (!isFlushingSync) {
286
+ queueMicrotask(flushEffects);
287
+ }
288
+ }
289
+ var updateEffectImpl = () => {
290
+ throw new Error("updateEffect not initialized - import effect.ts first");
291
+ };
292
+ function setUpdateEffectImpl(impl) {
293
+ updateEffectImpl = impl;
294
+ }
295
+ function flushEffects() {
296
+ const roots = clearQueuedRootEffects();
297
+ for (const root of roots) {
298
+ if (isDirty(root)) {
299
+ updateEffectImpl(root);
300
+ }
301
+ processEffectTree(root);
302
+ }
303
+ }
304
+ function processEffectTree(effect) {
305
+ let child = effect.first;
306
+ while (child !== null) {
307
+ const next = child.next;
308
+ if (isDirty(child)) {
309
+ updateEffectImpl(child);
310
+ }
311
+ if (child.first !== null) {
312
+ processEffectTree(child);
313
+ }
314
+ child = next;
315
+ }
316
+ }
317
+ function flushPendingReactions() {
318
+ const reactions = [...pendingReactions];
319
+ clearPendingReactions();
320
+ for (const reaction of reactions) {
321
+ if (isDirty(reaction)) {
322
+ if ("parent" in reaction) {
323
+ updateEffectImpl(reaction);
324
+ }
325
+ }
326
+ }
327
+ }
328
+ var MAX_FLUSH_COUNT = 1000;
329
+ function flushSync(fn) {
330
+ const wasFlushingSync = isFlushingSync;
331
+ setIsFlushingSync(true);
332
+ try {
333
+ let result;
334
+ let flushCount = 0;
335
+ if (fn) {
336
+ flushEffects();
337
+ result = fn();
338
+ }
339
+ while (true) {
340
+ if (++flushCount > MAX_FLUSH_COUNT) {
341
+ throw new Error("Maximum update depth exceeded. This can happen when an effect " + "continuously triggers itself. Check for effects that write to " + "signals they depend on without proper guards.");
342
+ }
343
+ const roots = clearQueuedRootEffects();
344
+ if (roots.length === 0) {
345
+ if (pendingReactions.size === 0) {
346
+ return result;
89
347
  }
90
- return proxyCache;
348
+ flushPendingReactions();
349
+ continue;
91
350
  }
92
- return internal.v;
93
- },
94
- set value(newValue) {
95
- if (!internal.equals(internal.v, newValue)) {
96
- internal.v = newValue;
97
- proxyCache = null;
98
- trigger(internal);
351
+ for (const root of roots) {
352
+ if (isDirty(root)) {
353
+ updateEffectImpl(root);
354
+ }
355
+ processEffectTree(root);
99
356
  }
100
357
  }
101
- };
358
+ } finally {
359
+ setIsFlushingSync(wasFlushingSync);
360
+ }
102
361
  }
103
- function effect(fn) {
104
- const reaction = {
105
- execute: () => {
106
- if (reaction.cleanup) {
107
- reaction.cleanup();
108
- reaction.cleanup = undefined;
109
- }
110
- for (const dep of reaction.deps) {
111
- dep.reactions.delete(reaction);
112
- }
113
- reaction.deps.clear();
114
- reactionStack.push(reaction);
115
- const prevReaction = activeReaction;
116
- activeReaction = reaction;
117
- try {
118
- const cleanup = fn();
119
- if (typeof cleanup === "function") {
120
- reaction.cleanup = cleanup;
362
+ async function tick() {
363
+ await Promise.resolve();
364
+ flushSync();
365
+ }
366
+
367
+ // src/reactivity/tracking.ts
368
+ function get(signal) {
369
+ if (activeReaction !== null && !untracking) {
370
+ if ((activeReaction.f & REACTION_IS_UPDATING) !== 0) {
371
+ if (signal.rv < readVersion) {
372
+ signal.rv = readVersion;
373
+ const deps = activeReaction.deps;
374
+ if (newDeps === null && deps !== null && deps[skippedDeps] === signal) {
375
+ setSkippedDeps(skippedDeps + 1);
376
+ } else {
377
+ if (newDeps === null) {
378
+ setNewDeps([signal]);
379
+ } else {
380
+ newDeps.push(signal);
381
+ }
121
382
  }
122
- } finally {
123
- activeReaction = prevReaction;
124
- reactionStack.pop();
125
383
  }
126
- },
127
- deps: new Set,
128
- active: true
129
- };
130
- reaction.execute();
131
- return () => {
132
- if (!reaction.active)
133
- return;
134
- reaction.active = false;
135
- if (reaction.cleanup) {
136
- reaction.cleanup();
384
+ } else {
385
+ if (activeReaction.deps === null) {
386
+ activeReaction.deps = [signal];
387
+ } else if (!activeReaction.deps.includes(signal)) {
388
+ activeReaction.deps.push(signal);
389
+ }
390
+ if (signal.reactions === null) {
391
+ signal.reactions = [activeReaction];
392
+ } else if (!signal.reactions.includes(activeReaction)) {
393
+ signal.reactions.push(activeReaction);
394
+ }
137
395
  }
138
- for (const dep of reaction.deps) {
139
- dep.reactions.delete(reaction);
396
+ }
397
+ if ((signal.f & DERIVED) !== 0) {
398
+ const derived = signal;
399
+ if (isDirty(derived)) {
400
+ updateDerived(derived);
140
401
  }
141
- reaction.deps.clear();
142
- };
402
+ }
403
+ return signal.v;
143
404
  }
144
- function derived(fn, options) {
145
- const internal = {
146
- v: undefined,
147
- reactions: new Set,
148
- equals: options?.equals ?? defaultEquals,
149
- fn,
150
- dirty: true
151
- };
152
- const deps = new Set;
153
- const markDirty = () => {
154
- if (!internal.dirty) {
155
- internal.dirty = true;
156
- trigger(internal);
157
- }
158
- };
159
- const recompute = () => {
160
- for (const dep of deps) {
161
- dep.reactions.delete(derivedReaction);
405
+ function set(signal, value) {
406
+ if (activeReaction !== null && (activeReaction.f & DERIVED) !== 0) {
407
+ throw new Error("Cannot write to signals inside a derived. " + "Deriveds should be pure computations with no side effects.");
408
+ }
409
+ if (!signal.equals(signal.v, value)) {
410
+ signal.v = value;
411
+ signal.wv = incrementWriteVersion();
412
+ markReactions(signal, DIRTY);
413
+ if (activeEffect !== null && (activeEffect.f & CLEAN) !== 0 && (activeEffect.f & (ROOT_EFFECT | BRANCH_EFFECT)) === 0) {
414
+ addUntrackedWrite(signal);
162
415
  }
163
- deps.clear();
164
- const prevReaction = activeReaction;
165
- activeReaction = derivedReaction;
166
- try {
167
- const newValue = fn();
168
- internal.v = newValue;
169
- } finally {
170
- activeReaction = prevReaction;
416
+ }
417
+ return value;
418
+ }
419
+ function markReactions(signal, status) {
420
+ const reactions = signal.reactions;
421
+ if (reactions === null)
422
+ return;
423
+ for (let i = 0;i < reactions.length; i++) {
424
+ const reaction = reactions[i];
425
+ const flags = reaction.f;
426
+ const notDirty = (flags & DIRTY) === 0;
427
+ if (notDirty) {
428
+ setSignalStatus(reaction, status);
171
429
  }
172
- internal.dirty = false;
173
- };
174
- const derivedReaction = {
175
- execute: markDirty,
176
- deps,
177
- active: true
178
- };
179
- return {
180
- get value() {
181
- track(internal);
182
- if (internal.dirty) {
183
- recompute();
184
- }
185
- return internal.v;
430
+ if ((flags & DERIVED) !== 0) {
431
+ markReactions(reaction, MAYBE_DIRTY);
432
+ } else if (notDirty) {
433
+ scheduleEffect(reaction);
186
434
  }
187
- };
435
+ }
188
436
  }
189
- derived.by = derived;
190
- function batch(fn) {
191
- batchDepth++;
192
- try {
193
- return fn();
194
- } finally {
195
- batchDepth--;
196
- if (batchDepth === 0) {
197
- flushPending();
437
+ function setSignalStatus(signal, status) {
438
+ signal.f = signal.f & STATUS_MASK | status;
439
+ }
440
+ function isDirty(reaction) {
441
+ if ((reaction.f & DIRTY) !== 0) {
442
+ return true;
443
+ }
444
+ if ((reaction.f & MAYBE_DIRTY) !== 0) {
445
+ const deps = reaction.deps;
446
+ if (deps !== null) {
447
+ for (let i = 0;i < deps.length; i++) {
448
+ const dep = deps[i];
449
+ if ((dep.f & DERIVED) !== 0) {
450
+ if (isDirty(dep)) {
451
+ updateDerived(dep);
452
+ }
453
+ }
454
+ if (dep.wv > reaction.wv) {
455
+ return true;
456
+ }
457
+ }
198
458
  }
459
+ setSignalStatus(reaction, CLEAN);
199
460
  }
461
+ return false;
200
462
  }
201
- function untrack(fn) {
202
- const prev = untracking;
203
- untracking = true;
204
- try {
205
- return fn();
206
- } finally {
207
- untracking = prev;
463
+ var updateDerivedImpl = () => {
464
+ throw new Error("updateDerived not initialized - import derived.ts first");
465
+ };
466
+ function updateDerived(derived) {
467
+ updateDerivedImpl(derived);
468
+ }
469
+ function setUpdateDerivedImpl(impl) {
470
+ updateDerivedImpl = impl;
471
+ }
472
+ function removeReactions(reaction, start) {
473
+ const deps = reaction.deps;
474
+ if (deps === null)
475
+ return;
476
+ for (let i = start;i < deps.length; i++) {
477
+ removeReaction(reaction, deps[i]);
208
478
  }
209
479
  }
210
- function track(signal2) {
211
- if (activeReaction && !untracking) {
212
- activeReaction.deps.add(signal2);
213
- signal2.reactions.add(activeReaction);
480
+ function removeReaction(reaction, dep) {
481
+ const reactions = dep.reactions;
482
+ if (reactions === null)
483
+ return;
484
+ const index = reactions.indexOf(reaction);
485
+ if (index !== -1) {
486
+ const last = reactions.length - 1;
487
+ if (index !== last) {
488
+ reactions[index] = reactions[last];
489
+ }
490
+ reactions.pop();
491
+ if (reactions.length === 0) {
492
+ dep.reactions = null;
493
+ }
214
494
  }
215
495
  }
216
- function trigger(signal2) {
217
- const reactions = [...signal2.reactions];
218
- for (const reaction of reactions) {
219
- if (!reaction.active)
220
- continue;
221
- if ("dirty" in reaction) {
222
- reaction.dirty = true;
496
+ function updateReaction(reaction) {
497
+ const prevNewDeps = newDeps;
498
+ const prevSkippedDeps = skippedDeps;
499
+ const prevReaction = activeReaction;
500
+ const prevUntrackedWrites = untrackedWrites;
501
+ setNewDeps(null);
502
+ setSkippedDeps(0);
503
+ setActiveReaction(reaction);
504
+ setUntrackedWrites(null);
505
+ const prevReadVersion = readVersion;
506
+ incrementReadVersion();
507
+ reaction.f |= REACTION_IS_UPDATING;
508
+ try {
509
+ const result = reaction.fn();
510
+ const deps = reaction.deps;
511
+ if (newDeps !== null) {
512
+ removeReactions(reaction, skippedDeps);
513
+ if (deps !== null && skippedDeps > 0) {
514
+ deps.length = skippedDeps + newDeps.length;
515
+ for (let i = 0;i < newDeps.length; i++) {
516
+ deps[skippedDeps + i] = newDeps[i];
517
+ }
518
+ } else {
519
+ reaction.deps = newDeps;
520
+ }
521
+ const finalDeps = reaction.deps;
522
+ for (let i = skippedDeps;i < finalDeps.length; i++) {
523
+ const dep = finalDeps[i];
524
+ if (dep.reactions === null) {
525
+ dep.reactions = [reaction];
526
+ } else {
527
+ dep.reactions.push(reaction);
528
+ }
529
+ }
530
+ } else if (deps !== null && skippedDeps < deps.length) {
531
+ removeReactions(reaction, skippedDeps);
532
+ deps.length = skippedDeps;
223
533
  }
224
- if (batchDepth > 0) {
225
- pendingReactions.add(reaction);
534
+ if (untrackedWrites !== null && reaction.deps !== null && (reaction.f & EFFECT) !== 0 && (reaction.f & DERIVED) === 0) {
535
+ for (const signal of untrackedWrites) {
536
+ if (reaction.deps.includes(signal)) {
537
+ setSignalStatus(reaction, DIRTY);
538
+ scheduleEffect(reaction);
539
+ break;
540
+ }
541
+ }
542
+ }
543
+ return result;
544
+ } finally {
545
+ reaction.f &= ~REACTION_IS_UPDATING;
546
+ setNewDeps(prevNewDeps);
547
+ setSkippedDeps(prevSkippedDeps);
548
+ setActiveReaction(prevReaction);
549
+ if (untrackedWrites !== null) {
550
+ if (prevUntrackedWrites === null) {
551
+ setUntrackedWrites(untrackedWrites);
552
+ } else {
553
+ prevUntrackedWrites.push(...untrackedWrites);
554
+ setUntrackedWrites(prevUntrackedWrites);
555
+ }
226
556
  } else {
227
- reaction.execute();
557
+ setUntrackedWrites(prevUntrackedWrites);
228
558
  }
229
559
  }
230
560
  }
231
- function flushPending() {
232
- const reactions = [...pendingReactions];
233
- pendingReactions.clear();
234
- for (const reaction of reactions) {
235
- if (reaction.active) {
236
- reaction.execute();
561
+
562
+ // src/primitives/signal.ts
563
+ function source(initialValue, options) {
564
+ return {
565
+ f: 0,
566
+ v: initialValue,
567
+ equals: options?.equals ?? equals,
568
+ reactions: null,
569
+ rv: 0,
570
+ wv: 0
571
+ };
572
+ }
573
+ function mutableSource(initialValue) {
574
+ return source(initialValue, { equals: safeEquals });
575
+ }
576
+ function signal(initialValue, options) {
577
+ const src = source(initialValue, options);
578
+ return {
579
+ get value() {
580
+ return get(src);
581
+ },
582
+ set value(newValue) {
583
+ set(src, newValue);
237
584
  }
585
+ };
586
+ }
587
+ var proxyFn = null;
588
+ function setProxyFn(fn) {
589
+ proxyFn = fn;
590
+ }
591
+ function state(initialValue) {
592
+ if (proxyFn === null) {
593
+ throw new Error("state() requires proxy to be initialized. Import from index.ts.");
238
594
  }
595
+ return proxyFn(initialValue);
239
596
  }
240
- var REACTIVE_MARKER = Symbol("reactive");
241
- function state(initial) {
242
- return createDeepReactive(initial);
597
+ function stateRaw(initialValue) {
598
+ return signal(initialValue);
243
599
  }
600
+
601
+ // src/deep/proxy.ts
244
602
  function shouldProxy(value) {
245
- if (value === null || typeof value !== "object")
246
- return false;
247
- if (value[REACTIVE_MARKER])
603
+ if (value === null || typeof value !== "object") {
248
604
  return false;
605
+ }
249
606
  const proto = Object.getPrototypeOf(value);
250
607
  return proto === Object.prototype || proto === Array.prototype || proto === null;
251
608
  }
252
- function createDeepReactive(target) {
253
- const existing = rawToProxy.get(target);
254
- if (existing)
255
- return existing;
256
- const internal = {
257
- v: target,
258
- reactions: new Set,
259
- equals: defaultEquals
609
+ function isProxy(value) {
610
+ return value !== null && typeof value === "object" && STATE_SYMBOL in value;
611
+ }
612
+ function isWritable(target, prop) {
613
+ const descriptor = Object.getOwnPropertyDescriptor(target, prop);
614
+ return descriptor === undefined || descriptor.writable === true;
615
+ }
616
+ function proxy(value) {
617
+ if (!shouldProxy(value) || isProxy(value)) {
618
+ return value;
619
+ }
620
+ const sources = new Map;
621
+ const version = source(0);
622
+ const isArray = Array.isArray(value);
623
+ if (isArray) {
624
+ sources.set("length", source(value.length));
625
+ }
626
+ const parentReadVersion = readVersion;
627
+ const withParent = (fn) => {
628
+ if (readVersion === parentReadVersion) {
629
+ return fn();
630
+ }
631
+ const prevReaction = activeReaction;
632
+ setActiveReaction(null);
633
+ try {
634
+ return fn();
635
+ } finally {
636
+ setActiveReaction(prevReaction);
637
+ }
260
638
  };
261
- const propSignals = new Map;
262
- const getPropSignal = (prop) => {
263
- let sig = propSignals.get(prop);
264
- if (!sig) {
265
- sig = {
266
- v: target[prop],
267
- reactions: new Set,
268
- equals: defaultEquals
269
- };
270
- propSignals.set(prop, sig);
639
+ const getSource = (prop, initialValue) => {
640
+ let s = sources.get(prop);
641
+ if (s === undefined) {
642
+ s = withParent(() => {
643
+ const proxied = shouldProxy(initialValue) ? proxy(initialValue) : initialValue;
644
+ return source(proxied);
645
+ });
646
+ sources.set(prop, s);
271
647
  }
272
- return sig;
648
+ return s;
273
649
  };
274
- const proxy = new Proxy(target, {
275
- get(target2, prop, receiver) {
276
- if (prop === REACTIVE_MARKER)
277
- return true;
278
- const value = Reflect.get(target2, prop, receiver);
279
- if (Array.isArray(target2) && typeof value === "function") {
280
- track(internal);
281
- return value.bind(proxy);
282
- }
283
- const sig = getPropSignal(prop);
284
- track(sig);
285
- if (shouldProxy(value)) {
286
- const existingProxy = rawToProxy.get(value);
287
- if (existingProxy)
288
- return existingProxy;
289
- return createDeepReactive(value);
290
- }
291
- return value;
292
- },
293
- set(target2, prop, value, receiver) {
294
- const oldValue = target2[prop];
295
- const rawValue = value?.[REACTIVE_MARKER] ? proxyToRaw.get(value) ?? value : value;
296
- if (Object.is(oldValue, rawValue))
297
- return true;
298
- const result = Reflect.set(target2, prop, rawValue, receiver);
299
- if (result) {
300
- const sig = getPropSignal(prop);
301
- sig.v = rawValue;
302
- trigger(sig);
303
- if (Array.isArray(target2)) {
304
- internal.v = target2;
305
- trigger(internal);
650
+ const proxyObj = new Proxy(value, {
651
+ get(target, prop, receiver) {
652
+ if (prop === STATE_SYMBOL) {
653
+ return value;
654
+ }
655
+ const exists = prop in target;
656
+ const currentValue = Reflect.get(target, prop, receiver);
657
+ if (isArray && typeof currentValue === "function") {
658
+ get(version);
659
+ return currentValue.bind(proxyObj);
660
+ }
661
+ if (exists || isWritable(target, prop)) {
662
+ const s = getSource(prop, currentValue);
663
+ const val = get(s);
664
+ if (val === UNINITIALIZED) {
665
+ return;
306
666
  }
667
+ return val;
307
668
  }
308
- return result;
669
+ return currentValue;
309
670
  },
310
- deleteProperty(target2, prop) {
311
- const hadKey = prop in target2;
312
- const result = Reflect.deleteProperty(target2, prop);
313
- if (result && hadKey) {
314
- const sig = propSignals.get(prop);
315
- if (sig) {
316
- sig.v = undefined;
317
- trigger(sig);
671
+ set(target, prop, newValue, receiver) {
672
+ const exists = prop in target;
673
+ let s = sources.get(prop);
674
+ if (s === undefined) {
675
+ if (!exists && !isWritable(target, prop)) {
676
+ return false;
318
677
  }
319
- trigger(internal);
678
+ s = withParent(() => source(undefined));
679
+ sources.set(prop, s);
320
680
  }
321
- return result;
322
- },
323
- has(target2, prop) {
324
- if (prop === REACTIVE_MARKER)
325
- return true;
326
- track(internal);
327
- return Reflect.has(target2, prop);
328
- },
329
- ownKeys(target2) {
330
- track(internal);
331
- return Reflect.ownKeys(target2);
332
- }
333
- });
334
- rawToProxy.set(target, proxy);
335
- proxyToRaw.set(proxy, target);
336
- proxyToSignal.set(proxy, internal);
337
- return proxy;
338
- }
339
- var proxyToRaw = new WeakMap;
340
- var signalProxyCache = new WeakMap;
341
- function createDeepReactiveForSignal(target, parentSignal) {
342
- const existingProxy = signalProxyCache.get(target);
343
- if (existingProxy)
344
- return existingProxy;
345
- const propSignals = new Map;
346
- const getPropSignal = (prop) => {
347
- let sig = propSignals.get(prop);
348
- if (!sig) {
349
- sig = {
350
- v: target[prop],
351
- reactions: new Set,
352
- equals: defaultEquals
353
- };
354
- propSignals.set(prop, sig);
355
- }
356
- return sig;
357
- };
358
- const internal = {
359
- v: target,
360
- reactions: new Set,
361
- equals: defaultEquals
362
- };
363
- const proxy = new Proxy(target, {
364
- get(target2, prop, receiver) {
365
- if (prop === REACTIVE_MARKER)
366
- return true;
367
- const value = Reflect.get(target2, prop, receiver);
368
- if (Array.isArray(target2) && typeof value === "function") {
369
- track(internal);
370
- return value.bind(proxy);
371
- }
372
- const sig = getPropSignal(prop);
373
- track(sig);
374
- if (value !== null && typeof value === "object") {
375
- const proto = Object.getPrototypeOf(value);
376
- if (proto === Object.prototype || proto === Array.prototype || proto === null) {
377
- if (!value[REACTIVE_MARKER]) {
378
- return createDeepReactiveForSignal(value, parentSignal);
681
+ const proxied = withParent(() => shouldProxy(newValue) ? proxy(newValue) : newValue);
682
+ set(s, proxied);
683
+ Reflect.set(target, prop, newValue, receiver);
684
+ if (isArray && prop === "length") {
685
+ const oldLength = s.v;
686
+ const newLength = newValue;
687
+ for (let i = newLength;i < oldLength; i++) {
688
+ const indexKey = String(i);
689
+ const indexSource = sources.get(indexKey);
690
+ if (indexSource !== undefined) {
691
+ set(indexSource, UNINITIALIZED);
692
+ } else if (i in target) {
693
+ const deletedSource = withParent(() => source(UNINITIALIZED));
694
+ sources.set(indexKey, deletedSource);
379
695
  }
380
696
  }
381
697
  }
382
- return value;
383
- },
384
- set(target2, prop, value, receiver) {
385
- const oldValue = target2[prop];
386
- const rawValue = value?.[REACTIVE_MARKER] ? proxyToRaw.get(value) ?? value : value;
387
- if (Object.is(oldValue, rawValue))
388
- return true;
389
- const result = Reflect.set(target2, prop, rawValue, receiver);
390
- if (result) {
391
- batch(() => {
392
- const sig = getPropSignal(prop);
393
- sig.v = rawValue;
394
- trigger(sig);
395
- trigger(parentSignal);
396
- if (Array.isArray(target2)) {
397
- internal.v = target2;
398
- trigger(internal);
698
+ if (isArray && typeof prop === "string") {
699
+ const index = Number(prop);
700
+ if (Number.isInteger(index) && index >= 0) {
701
+ const lengthSource = sources.get("length");
702
+ if (lengthSource !== undefined && index >= lengthSource.v) {
703
+ set(lengthSource, index + 1);
399
704
  }
400
- });
705
+ }
706
+ }
707
+ if (!exists) {
708
+ set(version, get(version) + 1);
401
709
  }
402
- return result;
710
+ return true;
403
711
  },
404
- deleteProperty(target2, prop) {
405
- const hadKey = prop in target2;
406
- const result = Reflect.deleteProperty(target2, prop);
407
- if (result && hadKey) {
408
- batch(() => {
409
- const sig = propSignals.get(prop);
410
- if (sig) {
411
- sig.v = undefined;
412
- trigger(sig);
413
- }
414
- trigger(parentSignal);
415
- trigger(internal);
416
- });
712
+ deleteProperty(target, prop) {
713
+ const exists = prop in target;
714
+ if (exists) {
715
+ let s = sources.get(prop);
716
+ if (s === undefined) {
717
+ s = withParent(() => source(UNINITIALIZED));
718
+ sources.set(prop, s);
719
+ } else {
720
+ set(s, UNINITIALIZED);
721
+ }
722
+ set(version, get(version) + 1);
417
723
  }
418
- return result;
724
+ return Reflect.deleteProperty(target, prop);
419
725
  },
420
- has(target2, prop) {
421
- if (prop === REACTIVE_MARKER)
726
+ has(target, prop) {
727
+ if (prop === STATE_SYMBOL) {
422
728
  return true;
423
- track(internal);
424
- return Reflect.has(target2, prop);
729
+ }
730
+ get(version);
731
+ const s = sources.get(prop);
732
+ if (s !== undefined) {
733
+ const val = get(s);
734
+ if (val === UNINITIALIZED) {
735
+ return false;
736
+ }
737
+ }
738
+ return Reflect.has(target, prop);
739
+ },
740
+ ownKeys(target) {
741
+ get(version);
742
+ const keys = Reflect.ownKeys(target).filter((key) => {
743
+ const s = sources.get(key);
744
+ return s === undefined || s.v !== UNINITIALIZED;
745
+ });
746
+ for (const [key, s] of sources) {
747
+ const k = key;
748
+ if (s.v !== UNINITIALIZED && !(key in target) && !keys.includes(k)) {
749
+ keys.push(k);
750
+ }
751
+ }
752
+ return keys;
425
753
  },
426
- ownKeys(target2) {
427
- track(internal);
428
- return Reflect.ownKeys(target2);
754
+ getOwnPropertyDescriptor(target, prop) {
755
+ const s = sources.get(prop);
756
+ if (s !== undefined && s.v === UNINITIALIZED) {
757
+ return;
758
+ }
759
+ return Reflect.getOwnPropertyDescriptor(target, prop);
429
760
  }
430
761
  });
431
- signalProxyCache.set(target, proxy);
432
- proxyToRaw.set(proxy, target);
433
- return proxy;
762
+ return proxyObj;
434
763
  }
435
- function toRaw(proxy) {
436
- if (proxy && typeof proxy === "object" && proxy[REACTIVE_MARKER]) {
437
- return proxyToRaw.get(proxy) ?? proxy;
764
+ function toRaw(value) {
765
+ if (value !== null && typeof value === "object" && STATE_SYMBOL in value) {
766
+ return value[STATE_SYMBOL];
438
767
  }
439
- return proxy;
768
+ return value;
440
769
  }
441
770
  function isReactive(value) {
442
- return value !== null && typeof value === "object" && value[REACTIVE_MARKER] === true;
771
+ return isProxy(value);
443
772
  }
444
-
773
+ // src/primitives/derived.ts
774
+ function createDerived(fn, options) {
775
+ let flags = DERIVED | DIRTY;
776
+ const parentDerived = activeReaction !== null && (activeReaction.f & DERIVED) !== 0 ? activeReaction : null;
777
+ if (activeEffect === null || parentDerived !== null && (parentDerived.f & UNOWNED) !== 0) {
778
+ flags |= UNOWNED;
779
+ }
780
+ const derived = {
781
+ f: flags,
782
+ fn,
783
+ v: UNINITIALIZED,
784
+ equals: options?.equals ?? equals,
785
+ reactions: null,
786
+ deps: null,
787
+ effects: null,
788
+ parent: parentDerived ?? activeEffect,
789
+ rv: 0,
790
+ wv: 0
791
+ };
792
+ return derived;
793
+ }
794
+ function executeDerived(derived) {
795
+ destroyDerivedEffects(derived);
796
+ const value = updateReaction(derived);
797
+ return value;
798
+ }
799
+ function updateDerived2(derived) {
800
+ const value = executeDerived(derived);
801
+ if (!derived.equals(derived.v, value)) {
802
+ derived.v = value;
803
+ derived.wv = incrementWriteVersion();
804
+ }
805
+ const status = (derived.f & UNOWNED) !== 0 && derived.deps !== null ? MAYBE_DIRTY : CLEAN;
806
+ setSignalStatus(derived, status);
807
+ }
808
+ setUpdateDerivedImpl(updateDerived2);
809
+ var destroyEffectImpl = () => {};
810
+ function setDestroyEffectImpl(impl) {
811
+ destroyEffectImpl = impl;
812
+ }
813
+ function destroyDerivedEffects(derived) {
814
+ const effects = derived.effects;
815
+ if (effects !== null) {
816
+ derived.effects = null;
817
+ for (let i = 0;i < effects.length; i++) {
818
+ destroyEffectImpl(effects[i]);
819
+ }
820
+ }
821
+ }
822
+ function derived(fn, options) {
823
+ const d = createDerived(fn, options);
824
+ return {
825
+ get value() {
826
+ return get(d);
827
+ }
828
+ };
829
+ }
830
+ derived.by = derived;
831
+ function disconnectDerived(derived2) {
832
+ removeReactions(derived2, 0);
833
+ derived2.deps = null;
834
+ derived2.reactions = null;
835
+ destroyDerivedEffects(derived2);
836
+ }
837
+ // src/primitives/effect.ts
838
+ function createEffect(type, fn, sync, push = true) {
839
+ const parent = activeEffect;
840
+ const effect = {
841
+ f: type | DIRTY,
842
+ fn,
843
+ deps: null,
844
+ teardown: null,
845
+ parent,
846
+ first: null,
847
+ last: null,
848
+ prev: null,
849
+ next: null,
850
+ wv: 0
851
+ };
852
+ if (sync) {
853
+ updateEffect(effect);
854
+ effect.f |= EFFECT_RAN;
855
+ } else if (fn !== null) {
856
+ scheduleEffect(effect);
857
+ }
858
+ if (push && parent !== null) {
859
+ pushEffect(effect, parent);
860
+ }
861
+ return effect;
862
+ }
863
+ function pushEffect(effect, parent) {
864
+ const parentLast = parent.last;
865
+ if (parentLast === null) {
866
+ parent.first = parent.last = effect;
867
+ } else {
868
+ parentLast.next = effect;
869
+ effect.prev = parentLast;
870
+ parent.last = effect;
871
+ }
872
+ }
873
+ function updateEffect(effect) {
874
+ if ((effect.f & DESTROYED) !== 0)
875
+ return;
876
+ setSignalStatus(effect, CLEAN);
877
+ const prevEffect = activeEffect;
878
+ setActiveEffect(effect);
879
+ try {
880
+ destroyEffectChildren(effect);
881
+ executeTeardown(effect);
882
+ const teardown = updateReaction(effect);
883
+ effect.teardown = typeof teardown === "function" ? teardown : null;
884
+ effect.wv = incrementWriteVersion();
885
+ } finally {
886
+ setActiveEffect(prevEffect);
887
+ }
888
+ }
889
+ setUpdateEffectImpl(updateEffect);
890
+ function destroyEffect(effect, removeFromParent = true) {
891
+ destroyEffectChildren(effect);
892
+ removeReactions(effect, 0);
893
+ setSignalStatus(effect, DESTROYED);
894
+ executeTeardown(effect);
895
+ if (removeFromParent && effect.parent !== null) {
896
+ unlinkEffect(effect);
897
+ }
898
+ effect.fn = null;
899
+ effect.teardown = null;
900
+ effect.deps = null;
901
+ effect.first = null;
902
+ effect.last = null;
903
+ effect.prev = null;
904
+ effect.next = null;
905
+ }
906
+ setDestroyEffectImpl(destroyEffect);
907
+ function destroyEffectChildren(effect) {
908
+ let child = effect.first;
909
+ effect.first = null;
910
+ effect.last = null;
911
+ while (child !== null) {
912
+ const next = child.next;
913
+ if ((child.f & (EFFECT_PRESERVED | ROOT_EFFECT)) === 0) {
914
+ destroyEffect(child, false);
915
+ }
916
+ child = next;
917
+ }
918
+ }
919
+ function executeTeardown(effect) {
920
+ const teardown = effect.teardown;
921
+ if (teardown !== null) {
922
+ effect.teardown = null;
923
+ teardown();
924
+ }
925
+ }
926
+ function unlinkEffect(effect) {
927
+ const { parent, prev, next } = effect;
928
+ if (prev !== null) {
929
+ prev.next = next;
930
+ }
931
+ if (next !== null) {
932
+ next.prev = prev;
933
+ }
934
+ if (parent !== null) {
935
+ if (parent.first === effect) {
936
+ parent.first = next;
937
+ }
938
+ if (parent.last === effect) {
939
+ parent.last = prev;
940
+ }
941
+ }
942
+ effect.prev = null;
943
+ effect.next = null;
944
+ }
945
+ function effect(fn) {
946
+ const eff = createEffect(EFFECT | USER_EFFECT, fn, false);
947
+ return () => destroyEffect(eff);
948
+ }
949
+ effect.pre = function effectPre(fn) {
950
+ const eff = createEffect(RENDER_EFFECT | USER_EFFECT, fn, true);
951
+ return () => destroyEffect(eff);
952
+ };
953
+ effect.root = function effectRoot(fn) {
954
+ const eff = createEffect(ROOT_EFFECT | EFFECT_PRESERVED, fn, true);
955
+ return () => destroyEffect(eff);
956
+ };
957
+ effect.tracking = function effectTracking() {
958
+ return activeEffect !== null;
959
+ };
960
+ // src/reactivity/batching.ts
961
+ function batch(fn) {
962
+ incrementBatchDepth();
963
+ try {
964
+ return fn();
965
+ } finally {
966
+ const depth = decrementBatchDepth();
967
+ if (depth === 0) {
968
+ flushPendingReactions();
969
+ }
970
+ }
971
+ }
972
+ function untrack(fn) {
973
+ const prev = setUntracking(true);
974
+ try {
975
+ return fn();
976
+ } finally {
977
+ setUntracking(prev);
978
+ }
979
+ }
980
+ var peek = untrack;
981
+ // src/collections/map.ts
445
982
  class ReactiveMap extends Map {
446
983
  #keySignals = new Map;
447
- #version = { v: 0, reactions: new Set, equals: defaultEquals };
448
- #size = { v: 0, reactions: new Set, equals: defaultEquals };
984
+ #version = source(0);
985
+ #size;
449
986
  constructor(entries) {
450
- super();
451
- if (entries) {
452
- for (const [key, value] of entries) {
453
- super.set(key, value);
454
- }
455
- this.#size.v = super.size;
456
- }
987
+ super(entries);
988
+ this.#size = source(super.size);
457
989
  }
458
990
  #getKeySignal(key) {
459
991
  let sig = this.#keySignals.get(key);
460
- if (!sig) {
461
- sig = { v: 0, reactions: new Set, equals: defaultEquals };
992
+ if (sig === undefined) {
993
+ sig = source(0);
462
994
  this.#keySignals.set(key, sig);
463
995
  }
464
996
  return sig;
465
997
  }
998
+ #increment(sig) {
999
+ set(sig, sig.v + 1);
1000
+ }
466
1001
  get size() {
467
- track(this.#size);
1002
+ get(this.#size);
468
1003
  return super.size;
469
1004
  }
470
1005
  has(key) {
471
- const sig = this.#getKeySignal(key);
472
- track(sig);
1006
+ const sig = this.#keySignals.get(key);
1007
+ if (sig === undefined) {
1008
+ if (!super.has(key)) {
1009
+ get(this.#version);
1010
+ return false;
1011
+ }
1012
+ const newSig = this.#getKeySignal(key);
1013
+ get(newSig);
1014
+ return true;
1015
+ }
1016
+ get(sig);
473
1017
  return super.has(key);
474
1018
  }
475
1019
  get(key) {
476
- const sig = this.#getKeySignal(key);
477
- track(sig);
1020
+ const sig = this.#keySignals.get(key);
1021
+ if (sig === undefined) {
1022
+ const val = super.get(key);
1023
+ if (val !== undefined) {
1024
+ const newSig = this.#getKeySignal(key);
1025
+ get(newSig);
1026
+ return val;
1027
+ }
1028
+ get(this.#version);
1029
+ return;
1030
+ }
1031
+ get(sig);
478
1032
  return super.get(key);
479
1033
  }
480
1034
  set(key, value) {
@@ -483,328 +1037,400 @@ class ReactiveMap extends Map {
483
1037
  super.set(key, value);
484
1038
  const sig = this.#getKeySignal(key);
485
1039
  if (isNew) {
486
- this.#size.v = super.size;
487
- trigger(this.#size);
488
- this.#version.v++;
489
- trigger(this.#version);
490
- sig.v++;
491
- trigger(sig);
1040
+ set(this.#size, super.size);
1041
+ this.#increment(this.#version);
1042
+ this.#increment(sig);
492
1043
  } else if (!Object.is(oldValue, value)) {
493
- sig.v++;
494
- trigger(sig);
1044
+ this.#increment(sig);
1045
+ const versionReactions = this.#version.reactions;
1046
+ const keyReactions = sig.reactions;
1047
+ if (keyReactions !== null && (versionReactions === null || !keyReactions.every((r) => versionReactions.includes(r)))) {
1048
+ this.#increment(this.#version);
1049
+ }
495
1050
  }
496
1051
  return this;
497
1052
  }
498
1053
  delete(key) {
499
- const had = super.has(key);
500
- const result = super.delete(key);
501
- if (had) {
1054
+ const existed = super.has(key);
1055
+ if (existed) {
1056
+ super.delete(key);
502
1057
  const sig = this.#keySignals.get(key);
503
- if (sig) {
504
- sig.v = -1;
505
- trigger(sig);
1058
+ if (sig !== undefined) {
1059
+ set(sig, -1);
506
1060
  this.#keySignals.delete(key);
507
1061
  }
508
- this.#size.v = super.size;
509
- trigger(this.#size);
510
- this.#version.v++;
511
- trigger(this.#version);
1062
+ set(this.#size, super.size);
1063
+ this.#increment(this.#version);
512
1064
  }
513
- return result;
1065
+ return existed;
514
1066
  }
515
1067
  clear() {
516
- if (super.size === 0)
517
- return;
518
- for (const sig of this.#keySignals.values()) {
519
- sig.v = -1;
520
- trigger(sig);
1068
+ if (super.size > 0) {
1069
+ for (const [key, sig] of this.#keySignals) {
1070
+ set(sig, -1);
1071
+ }
1072
+ this.#keySignals.clear();
1073
+ super.clear();
1074
+ set(this.#size, 0);
1075
+ this.#increment(this.#version);
521
1076
  }
522
- super.clear();
523
- this.#keySignals.clear();
524
- this.#size.v = 0;
525
- trigger(this.#size);
526
- this.#version.v++;
527
- trigger(this.#version);
528
- }
529
- forEach(callbackfn, thisArg) {
530
- track(this.#version);
531
- super.forEach(callbackfn, thisArg);
532
1077
  }
533
1078
  keys() {
534
- track(this.#version);
1079
+ get(this.#version);
535
1080
  return super.keys();
536
1081
  }
537
1082
  values() {
538
- track(this.#version);
1083
+ get(this.#version);
539
1084
  return super.values();
540
1085
  }
541
1086
  entries() {
542
- track(this.#version);
1087
+ get(this.#version);
543
1088
  return super.entries();
544
1089
  }
1090
+ forEach(callbackfn, thisArg) {
1091
+ get(this.#version);
1092
+ super.forEach(callbackfn, thisArg);
1093
+ }
545
1094
  [Symbol.iterator]() {
546
1095
  return this.entries();
547
1096
  }
548
1097
  }
549
-
1098
+ // src/collections/set.ts
550
1099
  class ReactiveSet extends Set {
551
1100
  #itemSignals = new Map;
552
- #version = { v: 0, reactions: new Set, equals: defaultEquals };
553
- #size = { v: 0, reactions: new Set, equals: defaultEquals };
1101
+ #version = source(0);
1102
+ #size;
554
1103
  constructor(values) {
555
- super();
556
- if (values) {
557
- for (const value of values) {
558
- super.add(value);
559
- }
560
- this.#size.v = super.size;
561
- }
1104
+ super(values);
1105
+ this.#size = source(super.size);
562
1106
  }
563
1107
  #getItemSignal(item) {
564
1108
  let sig = this.#itemSignals.get(item);
565
- if (!sig) {
566
- sig = { v: super.has(item), reactions: new Set, equals: defaultEquals };
1109
+ if (sig === undefined) {
1110
+ sig = source(super.has(item));
567
1111
  this.#itemSignals.set(item, sig);
568
1112
  }
569
1113
  return sig;
570
1114
  }
1115
+ #incrementVersion() {
1116
+ set(this.#version, this.#version.v + 1);
1117
+ }
571
1118
  get size() {
572
- track(this.#size);
1119
+ get(this.#size);
573
1120
  return super.size;
574
1121
  }
575
- has(value) {
576
- const sig = this.#getItemSignal(value);
577
- track(sig);
578
- return super.has(value);
579
- }
580
- add(value) {
581
- if (!super.has(value)) {
582
- super.add(value);
583
- const sig = this.#getItemSignal(value);
584
- sig.v = true;
585
- trigger(sig);
586
- this.#size.v = super.size;
587
- trigger(this.#size);
588
- this.#version.v++;
589
- trigger(this.#version);
1122
+ has(item) {
1123
+ const sig = this.#itemSignals.get(item);
1124
+ if (sig === undefined) {
1125
+ const exists = super.has(item);
1126
+ if (exists) {
1127
+ const newSig = this.#getItemSignal(item);
1128
+ get(newSig);
1129
+ return true;
1130
+ }
1131
+ get(this.#version);
1132
+ return false;
1133
+ }
1134
+ get(sig);
1135
+ return super.has(item);
1136
+ }
1137
+ add(item) {
1138
+ const isNew = !super.has(item);
1139
+ super.add(item);
1140
+ if (isNew) {
1141
+ const sig = this.#getItemSignal(item);
1142
+ set(sig, true);
1143
+ set(this.#size, super.size);
1144
+ this.#incrementVersion();
590
1145
  }
591
1146
  return this;
592
1147
  }
593
- delete(value) {
594
- const had = super.has(value);
595
- const result = super.delete(value);
596
- if (had) {
597
- const sig = this.#itemSignals.get(value);
598
- if (sig) {
599
- sig.v = false;
600
- trigger(sig);
601
- this.#itemSignals.delete(value);
602
- }
603
- this.#size.v = super.size;
604
- trigger(this.#size);
605
- this.#version.v++;
606
- trigger(this.#version);
1148
+ delete(item) {
1149
+ const existed = super.has(item);
1150
+ if (existed) {
1151
+ super.delete(item);
1152
+ const sig = this.#itemSignals.get(item);
1153
+ if (sig !== undefined) {
1154
+ set(sig, false);
1155
+ this.#itemSignals.delete(item);
1156
+ }
1157
+ set(this.#size, super.size);
1158
+ this.#incrementVersion();
607
1159
  }
608
- return result;
1160
+ return existed;
609
1161
  }
610
1162
  clear() {
611
- if (super.size === 0)
612
- return;
613
- for (const sig of this.#itemSignals.values()) {
614
- sig.v = false;
615
- trigger(sig);
1163
+ if (super.size > 0) {
1164
+ for (const [item, sig] of this.#itemSignals) {
1165
+ set(sig, false);
1166
+ }
1167
+ this.#itemSignals.clear();
1168
+ super.clear();
1169
+ set(this.#size, 0);
1170
+ this.#incrementVersion();
616
1171
  }
617
- super.clear();
618
- this.#itemSignals.clear();
619
- this.#size.v = 0;
620
- trigger(this.#size);
621
- this.#version.v++;
622
- trigger(this.#version);
623
- }
624
- forEach(callbackfn, thisArg) {
625
- track(this.#version);
626
- super.forEach(callbackfn, thisArg);
627
1172
  }
628
1173
  keys() {
629
- track(this.#version);
1174
+ get(this.#version);
630
1175
  return super.keys();
631
1176
  }
632
1177
  values() {
633
- track(this.#version);
1178
+ get(this.#version);
634
1179
  return super.values();
635
1180
  }
636
1181
  entries() {
637
- track(this.#version);
1182
+ get(this.#version);
638
1183
  return super.entries();
639
1184
  }
1185
+ forEach(callbackfn, thisArg) {
1186
+ get(this.#version);
1187
+ super.forEach(callbackfn, thisArg);
1188
+ }
640
1189
  [Symbol.iterator]() {
641
1190
  return this.values();
642
1191
  }
643
1192
  }
644
- function reactiveArray(initial = []) {
645
- const internal = {
646
- v: 0,
647
- reactions: new Set,
648
- equals: defaultEquals
649
- };
650
- const indexSignals = new Map;
651
- const lengthSignal = {
652
- v: initial.length,
653
- reactions: new Set,
654
- equals: defaultEquals
655
- };
656
- const getIndexSignal = (index) => {
657
- let sig = indexSignals.get(index);
658
- if (!sig) {
659
- sig = { v: initial[index], reactions: new Set, equals: defaultEquals };
660
- indexSignals.set(index, sig);
1193
+ // src/collections/date.ts
1194
+ class ReactiveDate extends Date {
1195
+ #time;
1196
+ constructor(...args) {
1197
+ super(...args);
1198
+ this.#time = source(super.getTime());
1199
+ }
1200
+ #update() {
1201
+ const time = super.getTime();
1202
+ set(this.#time, time);
1203
+ return time;
1204
+ }
1205
+ getTime() {
1206
+ get(this.#time);
1207
+ return super.getTime();
1208
+ }
1209
+ getFullYear() {
1210
+ get(this.#time);
1211
+ return super.getFullYear();
1212
+ }
1213
+ getMonth() {
1214
+ get(this.#time);
1215
+ return super.getMonth();
1216
+ }
1217
+ getDate() {
1218
+ get(this.#time);
1219
+ return super.getDate();
1220
+ }
1221
+ getDay() {
1222
+ get(this.#time);
1223
+ return super.getDay();
1224
+ }
1225
+ getHours() {
1226
+ get(this.#time);
1227
+ return super.getHours();
1228
+ }
1229
+ getMinutes() {
1230
+ get(this.#time);
1231
+ return super.getMinutes();
1232
+ }
1233
+ getSeconds() {
1234
+ get(this.#time);
1235
+ return super.getSeconds();
1236
+ }
1237
+ getMilliseconds() {
1238
+ get(this.#time);
1239
+ return super.getMilliseconds();
1240
+ }
1241
+ getUTCFullYear() {
1242
+ get(this.#time);
1243
+ return super.getUTCFullYear();
1244
+ }
1245
+ getUTCMonth() {
1246
+ get(this.#time);
1247
+ return super.getUTCMonth();
1248
+ }
1249
+ getUTCDate() {
1250
+ get(this.#time);
1251
+ return super.getUTCDate();
1252
+ }
1253
+ getUTCDay() {
1254
+ get(this.#time);
1255
+ return super.getUTCDay();
1256
+ }
1257
+ getUTCHours() {
1258
+ get(this.#time);
1259
+ return super.getUTCHours();
1260
+ }
1261
+ getUTCMinutes() {
1262
+ get(this.#time);
1263
+ return super.getUTCMinutes();
1264
+ }
1265
+ getUTCSeconds() {
1266
+ get(this.#time);
1267
+ return super.getUTCSeconds();
1268
+ }
1269
+ getUTCMilliseconds() {
1270
+ get(this.#time);
1271
+ return super.getUTCMilliseconds();
1272
+ }
1273
+ getTimezoneOffset() {
1274
+ get(this.#time);
1275
+ return super.getTimezoneOffset();
1276
+ }
1277
+ setTime(time) {
1278
+ super.setTime(time);
1279
+ return this.#update();
1280
+ }
1281
+ setFullYear(year, month, date) {
1282
+ if (date !== undefined) {
1283
+ super.setFullYear(year, month, date);
1284
+ } else if (month !== undefined) {
1285
+ super.setFullYear(year, month);
1286
+ } else {
1287
+ super.setFullYear(year);
661
1288
  }
662
- return sig;
663
- };
664
- const array = [...initial];
665
- const proxy = new Proxy(array, {
666
- get(target, prop, receiver) {
667
- if (prop === "length") {
668
- track(lengthSignal);
669
- return target.length;
670
- }
671
- const index = typeof prop === "string" ? parseInt(prop, 10) : NaN;
672
- if (!isNaN(index)) {
673
- const sig = getIndexSignal(index);
674
- track(sig);
675
- return target[index];
676
- }
677
- const value = Reflect.get(target, prop, receiver);
678
- if (typeof value === "function") {
679
- return function(...args) {
680
- const method = prop;
681
- if (["indexOf", "includes", "find", "findIndex", "some", "every", "forEach", "map", "filter", "reduce", "reduceRight", "join", "toString"].includes(method)) {
682
- track(internal);
683
- return value.apply(target, args);
684
- }
685
- const prevLength = target.length;
686
- const result = value.apply(target, args);
687
- const newLength = target.length;
688
- if (newLength !== prevLength) {
689
- lengthSignal.v = newLength;
690
- trigger(lengthSignal);
691
- }
692
- if (["push", "pop", "shift", "unshift", "splice", "sort", "reverse", "fill", "copyWithin"].includes(method)) {
693
- internal.v++;
694
- trigger(internal);
695
- for (let i = 0;i < Math.max(prevLength, newLength); i++) {
696
- const sig = indexSignals.get(i);
697
- if (sig && !Object.is(sig.v, target[i])) {
698
- sig.v = target[i];
699
- trigger(sig);
700
- }
701
- }
702
- }
703
- return result;
704
- };
705
- }
706
- return value;
707
- },
708
- set(target, prop, value, receiver) {
709
- if (prop === "length") {
710
- const oldLength = target.length;
711
- target.length = value;
712
- if (oldLength !== value) {
713
- lengthSignal.v = value;
714
- trigger(lengthSignal);
715
- internal.v++;
716
- trigger(internal);
717
- }
718
- return true;
719
- }
720
- const index = typeof prop === "string" ? parseInt(prop, 10) : NaN;
721
- if (!isNaN(index)) {
722
- const oldValue = target[index];
723
- if (!Object.is(oldValue, value)) {
724
- target[index] = value;
725
- const sig = getIndexSignal(index);
726
- sig.v = value;
727
- trigger(sig);
728
- if (index >= lengthSignal.v) {
729
- lengthSignal.v = target.length;
730
- trigger(lengthSignal);
731
- }
732
- internal.v++;
733
- trigger(internal);
734
- }
735
- return true;
736
- }
737
- return Reflect.set(target, prop, value, receiver);
1289
+ return this.#update();
1290
+ }
1291
+ setMonth(month, date) {
1292
+ if (date !== undefined) {
1293
+ super.setMonth(month, date);
1294
+ } else {
1295
+ super.setMonth(month);
738
1296
  }
739
- });
740
- return proxy;
741
- }
742
- function effectScope() {
743
- const disposers = [];
744
- let active = true;
745
- return {
746
- run(fn) {
747
- if (!active)
748
- return;
749
- const originalEffect = effect;
750
- globalThis.__signalEffect = effect;
751
- const wrappedEffect = (effectFn) => {
752
- const dispose = originalEffect(effectFn);
753
- disposers.push(dispose);
754
- return dispose;
755
- };
756
- const prevEffect = globalThis.__effectOverride;
757
- globalThis.__effectOverride = wrappedEffect;
758
- try {
759
- return fn();
760
- } finally {
761
- globalThis.__effectOverride = prevEffect;
762
- }
763
- },
764
- stop() {
765
- if (!active)
766
- return;
767
- active = false;
768
- for (const dispose of disposers) {
769
- dispose();
770
- }
771
- disposers.length = 0;
772
- },
773
- get active() {
774
- return active;
1297
+ return this.#update();
1298
+ }
1299
+ setDate(date) {
1300
+ super.setDate(date);
1301
+ return this.#update();
1302
+ }
1303
+ setHours(hours, min, sec, ms) {
1304
+ if (ms !== undefined) {
1305
+ super.setHours(hours, min, sec, ms);
1306
+ } else if (sec !== undefined) {
1307
+ super.setHours(hours, min, sec);
1308
+ } else if (min !== undefined) {
1309
+ super.setHours(hours, min);
1310
+ } else {
1311
+ super.setHours(hours);
775
1312
  }
776
- };
777
- }
778
- function watch(source, callback, options) {
779
- let oldValue;
780
- let cleanup;
781
- let first = true;
782
- return effect(() => {
783
- const newValue = source();
784
- if (first) {
785
- first = false;
786
- oldValue = newValue;
787
- if (options?.immediate) {
788
- cleanup = callback(newValue, undefined);
789
- }
790
- return;
1313
+ return this.#update();
1314
+ }
1315
+ setMinutes(min, sec, ms) {
1316
+ if (ms !== undefined) {
1317
+ super.setMinutes(min, sec, ms);
1318
+ } else if (sec !== undefined) {
1319
+ super.setMinutes(min, sec);
1320
+ } else {
1321
+ super.setMinutes(min);
791
1322
  }
792
- if (!Object.is(newValue, oldValue)) {
793
- if (typeof cleanup === "function") {
794
- cleanup();
795
- }
796
- cleanup = callback(newValue, oldValue);
797
- oldValue = newValue;
1323
+ return this.#update();
1324
+ }
1325
+ setSeconds(sec, ms) {
1326
+ if (ms !== undefined) {
1327
+ super.setSeconds(sec, ms);
1328
+ } else {
1329
+ super.setSeconds(sec);
798
1330
  }
799
- });
800
- }
801
- function readonly(sig) {
802
- return {
803
- get value() {
804
- return sig.value;
1331
+ return this.#update();
1332
+ }
1333
+ setMilliseconds(ms) {
1334
+ super.setMilliseconds(ms);
1335
+ return this.#update();
1336
+ }
1337
+ setUTCFullYear(year, month, date) {
1338
+ if (date !== undefined) {
1339
+ super.setUTCFullYear(year, month, date);
1340
+ } else if (month !== undefined) {
1341
+ super.setUTCFullYear(year, month);
1342
+ } else {
1343
+ super.setUTCFullYear(year);
805
1344
  }
806
- };
807
- }
808
- function peek(fn) {
809
- return untrack(fn);
1345
+ return this.#update();
1346
+ }
1347
+ setUTCMonth(month, date) {
1348
+ if (date !== undefined) {
1349
+ super.setUTCMonth(month, date);
1350
+ } else {
1351
+ super.setUTCMonth(month);
1352
+ }
1353
+ return this.#update();
1354
+ }
1355
+ setUTCDate(date) {
1356
+ super.setUTCDate(date);
1357
+ return this.#update();
1358
+ }
1359
+ setUTCHours(hours, min, sec, ms) {
1360
+ if (ms !== undefined) {
1361
+ super.setUTCHours(hours, min, sec, ms);
1362
+ } else if (sec !== undefined) {
1363
+ super.setUTCHours(hours, min, sec);
1364
+ } else if (min !== undefined) {
1365
+ super.setUTCHours(hours, min);
1366
+ } else {
1367
+ super.setUTCHours(hours);
1368
+ }
1369
+ return this.#update();
1370
+ }
1371
+ setUTCMinutes(min, sec, ms) {
1372
+ if (ms !== undefined) {
1373
+ super.setUTCMinutes(min, sec, ms);
1374
+ } else if (sec !== undefined) {
1375
+ super.setUTCMinutes(min, sec);
1376
+ } else {
1377
+ super.setUTCMinutes(min);
1378
+ }
1379
+ return this.#update();
1380
+ }
1381
+ setUTCSeconds(sec, ms) {
1382
+ if (ms !== undefined) {
1383
+ super.setUTCSeconds(sec, ms);
1384
+ } else {
1385
+ super.setUTCSeconds(sec);
1386
+ }
1387
+ return this.#update();
1388
+ }
1389
+ setUTCMilliseconds(ms) {
1390
+ super.setUTCMilliseconds(ms);
1391
+ return this.#update();
1392
+ }
1393
+ toString() {
1394
+ get(this.#time);
1395
+ return super.toString();
1396
+ }
1397
+ toDateString() {
1398
+ get(this.#time);
1399
+ return super.toDateString();
1400
+ }
1401
+ toTimeString() {
1402
+ get(this.#time);
1403
+ return super.toTimeString();
1404
+ }
1405
+ toISOString() {
1406
+ get(this.#time);
1407
+ return super.toISOString();
1408
+ }
1409
+ toUTCString() {
1410
+ get(this.#time);
1411
+ return super.toUTCString();
1412
+ }
1413
+ toLocaleString(locales, options) {
1414
+ get(this.#time);
1415
+ return super.toLocaleString(locales, options);
1416
+ }
1417
+ toLocaleDateString(locales, options) {
1418
+ get(this.#time);
1419
+ return super.toLocaleDateString(locales, options);
1420
+ }
1421
+ toLocaleTimeString(locales, options) {
1422
+ get(this.#time);
1423
+ return super.toLocaleTimeString(locales, options);
1424
+ }
1425
+ toJSON() {
1426
+ get(this.#time);
1427
+ return super.toJSON();
1428
+ }
1429
+ valueOf() {
1430
+ get(this.#time);
1431
+ return super.valueOf();
1432
+ }
810
1433
  }
1434
+
1435
+ // src/index.ts
1436
+ setProxyFn(proxy);