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