mutts 1.0.4 → 1.0.6
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/README.md +2 -1
- package/dist/chunks/{_tslib-Mzh1rNsX.esm.js → _tslib-MCKDzsSq.esm.js} +2 -2
- package/dist/chunks/_tslib-MCKDzsSq.esm.js.map +1 -0
- package/dist/chunks/decorator-BGILvPtN.esm.js +627 -0
- package/dist/chunks/decorator-BGILvPtN.esm.js.map +1 -0
- package/dist/chunks/decorator-BQ2eBTCj.js +651 -0
- package/dist/chunks/decorator-BQ2eBTCj.js.map +1 -0
- package/dist/chunks/{index-GRBSx0mB.js → index-CDCOjzTy.js} +543 -495
- package/dist/chunks/index-CDCOjzTy.js.map +1 -0
- package/dist/chunks/{index-79Kk8D6e.esm.js → index-DiP0RXoZ.esm.js} +452 -404
- package/dist/chunks/index-DiP0RXoZ.esm.js.map +1 -0
- package/dist/decorator.d.ts +3 -3
- package/dist/decorator.esm.js +1 -1
- package/dist/decorator.js +1 -1
- package/dist/destroyable.esm.js +4 -4
- package/dist/destroyable.esm.js.map +1 -1
- package/dist/destroyable.js +4 -4
- package/dist/destroyable.js.map +1 -1
- package/dist/devtools/panel.js.map +1 -1
- package/dist/eventful.esm.js +1 -1
- package/dist/index.esm.js +48 -3
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +50 -4
- package/dist/index.js.map +1 -1
- package/dist/mutts.umd.js +1 -1
- package/dist/mutts.umd.js.map +1 -1
- package/dist/mutts.umd.min.js +1 -1
- package/dist/mutts.umd.min.js.map +1 -1
- package/dist/reactive.d.ts +54 -1
- package/dist/reactive.esm.js +3 -3
- package/dist/reactive.js +6 -4
- package/dist/reactive.js.map +1 -1
- package/dist/std-decorators.d.ts +1 -1
- package/dist/std-decorators.esm.js +10 -10
- package/dist/std-decorators.esm.js.map +1 -1
- package/dist/std-decorators.js +10 -10
- package/dist/std-decorators.js.map +1 -1
- package/docs/ai/manual.md +14 -95
- package/docs/reactive/advanced.md +6 -107
- package/docs/reactive/core.md +16 -16
- package/docs/reactive/debugging.md +158 -0
- package/docs/reactive.md +8 -0
- package/package.json +16 -66
- package/src/decorator.ts +11 -9
- package/src/destroyable.ts +5 -5
- package/src/index.ts +46 -0
- package/src/reactive/array.ts +3 -5
- package/src/reactive/change.ts +7 -3
- package/src/reactive/debug.ts +1 -1
- package/src/reactive/deep-touch.ts +1 -1
- package/src/reactive/deep-watch.ts +1 -1
- package/src/reactive/effect-context.ts +2 -2
- package/src/reactive/effects.ts +114 -17
- package/src/reactive/index.ts +3 -2
- package/src/reactive/interface.ts +10 -9
- package/src/reactive/map.ts +6 -6
- package/src/reactive/mapped.ts +2 -3
- package/src/reactive/memoize.ts +77 -31
- package/src/reactive/project.ts +103 -6
- package/src/reactive/proxy.ts +4 -4
- package/src/reactive/registry.ts +67 -0
- package/src/reactive/set.ts +6 -6
- package/src/reactive/tracking.ts +12 -41
- package/src/reactive/types.ts +59 -0
- package/src/reactive/zone.ts +1 -1
- package/src/std-decorators.ts +10 -10
- package/src/utils.ts +141 -0
- package/dist/chunks/_tslib-Mzh1rNsX.esm.js.map +0 -1
- package/dist/chunks/decorator-DLvrD0UF.js +0 -265
- package/dist/chunks/decorator-DLvrD0UF.js.map +0 -1
- package/dist/chunks/decorator-DqiszP7i.esm.js +0 -253
- package/dist/chunks/decorator-DqiszP7i.esm.js.map +0 -1
- package/dist/chunks/index-79Kk8D6e.esm.js.map +0 -1
- package/dist/chunks/index-GRBSx0mB.js.map +0 -1
- /package/{src/reactive/project.project.md → docs/reactive/project.md} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { i as isConstructor,
|
|
1
|
+
import { i as isConstructor, a as ReflectGet, g as rootFunction, o as options, h as allProps, R as ReactiveError, j as ReactiveErrorCode, k as cleanup$1, s as stopped, d as decorator, n as nonReactiveMark, p as nativeReactive, q as prototypeForwarding, u as unreactiveProperties, b as ReflectSet, f as isOwnAccessor, r as renamed, e as deepCompare, t as projectionInfo } from './decorator-BGILvPtN.esm.js';
|
|
2
2
|
import { Indexable, setAt, getAt, ArrayReadForward, forwardArray } from '../indexable.esm.js';
|
|
3
|
-
import {
|
|
3
|
+
import { _ as __setFunctionName, a as __esDecorate, b as __runInitializers, c as __classPrivateFieldSet, d as __classPrivateFieldGet } from './_tslib-MCKDzsSq.esm.js';
|
|
4
4
|
|
|
5
5
|
/// <reference lib="esnext.collection" />
|
|
6
6
|
var _a, _b;
|
|
@@ -332,313 +332,6 @@ function mixin(mixinFunction, unwrapFunction) {
|
|
|
332
332
|
});
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
-
// biome-ignore-all lint/suspicious/noConfusingVoidType: Type 'void' is not assignable to type 'ScopedCallback | undefined'.
|
|
336
|
-
// Argument of type '() => void' is not assignable to parameter of type '(dep: DependencyFunction) => ScopedCallback | undefined'.
|
|
337
|
-
// Track native reactivity
|
|
338
|
-
const nativeReactive = Symbol('native-reactive');
|
|
339
|
-
/**
|
|
340
|
-
* Symbol to mark individual objects as non-reactive
|
|
341
|
-
*/
|
|
342
|
-
const nonReactiveMark = Symbol('non-reactive');
|
|
343
|
-
/**
|
|
344
|
-
* Symbol to mark class properties as non-reactive
|
|
345
|
-
*/
|
|
346
|
-
const unreactiveProperties = Symbol('unreactive-properties');
|
|
347
|
-
/**
|
|
348
|
-
* Symbol for prototype forwarding in reactive objects
|
|
349
|
-
*/
|
|
350
|
-
const prototypeForwarding = Symbol('prototype-forwarding');
|
|
351
|
-
/**
|
|
352
|
-
* Symbol representing all properties in reactive tracking
|
|
353
|
-
*/
|
|
354
|
-
const allProps = Symbol('all-props');
|
|
355
|
-
// Symbol to mark functions with their root function
|
|
356
|
-
const rootFunction = Symbol('root-function');
|
|
357
|
-
/**
|
|
358
|
-
* Structured error codes for machine-readable diagnosis
|
|
359
|
-
*/
|
|
360
|
-
var ReactiveErrorCode;
|
|
361
|
-
(function (ReactiveErrorCode) {
|
|
362
|
-
ReactiveErrorCode["CycleDetected"] = "CYCLE_DETECTED";
|
|
363
|
-
ReactiveErrorCode["MaxDepthExceeded"] = "MAX_DEPTH_EXCEEDED";
|
|
364
|
-
ReactiveErrorCode["MaxReactionExceeded"] = "MAX_REACTION_EXCEEDED";
|
|
365
|
-
ReactiveErrorCode["WriteInComputed"] = "WRITE_IN_COMPUTED";
|
|
366
|
-
ReactiveErrorCode["TrackingError"] = "TRACKING_ERROR";
|
|
367
|
-
})(ReactiveErrorCode || (ReactiveErrorCode = {}));
|
|
368
|
-
/**
|
|
369
|
-
* Error class for reactive system errors
|
|
370
|
-
*/
|
|
371
|
-
class ReactiveError extends Error {
|
|
372
|
-
constructor(message, debugInfo) {
|
|
373
|
-
super(message);
|
|
374
|
-
this.debugInfo = debugInfo;
|
|
375
|
-
this.name = 'ReactiveError';
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
// biome-ignore-start lint/correctness/noUnusedFunctionParameters: Interface declaration with empty defaults
|
|
379
|
-
/**
|
|
380
|
-
* Global options for the reactive system
|
|
381
|
-
*/
|
|
382
|
-
const options = {
|
|
383
|
-
/**
|
|
384
|
-
* Debug purpose: called when an effect is entered
|
|
385
|
-
* @param effect - The effect that is entered
|
|
386
|
-
*/
|
|
387
|
-
enter: (_effect) => { },
|
|
388
|
-
/**
|
|
389
|
-
* Debug purpose: called when an effect is left
|
|
390
|
-
* @param effect - The effect that is left
|
|
391
|
-
*/
|
|
392
|
-
leave: (_effect) => { },
|
|
393
|
-
/**
|
|
394
|
-
* Debug purpose: called when an effect is chained
|
|
395
|
-
* @param target - The effect that is being triggered
|
|
396
|
-
* @param caller - The effect that is calling the target
|
|
397
|
-
*/
|
|
398
|
-
chain: (_targets, _caller) => { },
|
|
399
|
-
/**
|
|
400
|
-
* Debug purpose: called when an effect chain is started
|
|
401
|
-
* @param target - The effect that is being triggered
|
|
402
|
-
*/
|
|
403
|
-
beginChain: (_targets) => { },
|
|
404
|
-
/**
|
|
405
|
-
* Debug purpose: called when an effect chain is ended
|
|
406
|
-
*/
|
|
407
|
-
endChain: () => { },
|
|
408
|
-
garbageCollected: (_fn) => { },
|
|
409
|
-
/**
|
|
410
|
-
* Debug purpose: called when an object is touched
|
|
411
|
-
* @param obj - The object that is touched
|
|
412
|
-
* @param evolution - The type of change
|
|
413
|
-
* @param props - The properties that changed
|
|
414
|
-
* @param deps - The dependencies that changed
|
|
415
|
-
*/
|
|
416
|
-
touched: (_obj, _evolution, _props, _deps) => { },
|
|
417
|
-
/**
|
|
418
|
-
* Debug purpose: called when an effect is skipped because it's already running
|
|
419
|
-
* @param effect - The effect that is already running
|
|
420
|
-
* @param runningChain - The array of effects from the detected one to the currently running one
|
|
421
|
-
*/
|
|
422
|
-
skipRunningEffect: (_effect, _runningChain) => { },
|
|
423
|
-
/**
|
|
424
|
-
* Debug purpose: maximum effect chain (like call stack max depth)
|
|
425
|
-
* Used to prevent infinite loops
|
|
426
|
-
* @default 100
|
|
427
|
-
*/
|
|
428
|
-
maxEffectChain: 100,
|
|
429
|
-
/**
|
|
430
|
-
* Debug purpose: maximum effect reaction (like call stack max depth)
|
|
431
|
-
* Used to prevent infinite loops
|
|
432
|
-
* @default 'throw'
|
|
433
|
-
*/
|
|
434
|
-
maxEffectReaction: 'throw',
|
|
435
|
-
/**
|
|
436
|
-
* How to handle cycles detected in effect batches
|
|
437
|
-
* - 'throw': Throw an error with cycle information (default, recommended for development)
|
|
438
|
-
* - 'warn': Log a warning and break the cycle by executing one effect
|
|
439
|
-
* - 'break': Silently break the cycle by executing one effect (recommended for production)
|
|
440
|
-
* - 'strict': Prevent cycle creation by checking graph before execution (throws error)
|
|
441
|
-
* @default 'throw'
|
|
442
|
-
*/
|
|
443
|
-
cycleHandling: 'throw',
|
|
444
|
-
/**
|
|
445
|
-
* Maximum depth for deep watching traversal
|
|
446
|
-
* Used to prevent infinite recursion in circular references
|
|
447
|
-
* @default 100
|
|
448
|
-
*/
|
|
449
|
-
maxDeepWatchDepth: 100,
|
|
450
|
-
/**
|
|
451
|
-
* Only react on instance members modification (not inherited properties)
|
|
452
|
-
* For instance, do not track class methods
|
|
453
|
-
* @default true
|
|
454
|
-
*/
|
|
455
|
-
instanceMembers: true,
|
|
456
|
-
/**
|
|
457
|
-
* Ignore accessors (getters and setters) and only track direct properties
|
|
458
|
-
* @default true
|
|
459
|
-
*/
|
|
460
|
-
ignoreAccessors: true,
|
|
461
|
-
/**
|
|
462
|
-
* Enable recursive touching when objects with the same prototype are replaced
|
|
463
|
-
* When enabled, replacing an object with another of the same prototype triggers
|
|
464
|
-
* recursive diffing instead of notifying parent effects
|
|
465
|
-
* @default true
|
|
466
|
-
*/
|
|
467
|
-
recursiveTouching: true,
|
|
468
|
-
/**
|
|
469
|
-
* Default async execution mode for effects that return Promises
|
|
470
|
-
* - 'cancel': Cancel previous async execution when dependencies change (default, enables async zone)
|
|
471
|
-
* - 'queue': Queue next execution to run after current completes (enables async zone)
|
|
472
|
-
* - 'ignore': Ignore new executions while async work is running (enables async zone)
|
|
473
|
-
* - false: Disable async zone and async mode handling (effects run concurrently)
|
|
474
|
-
*
|
|
475
|
-
* **When truthy:** Enables async zone (Promise.prototype wrapping) for automatic context
|
|
476
|
-
* preservation in Promise callbacks. Warning: This modifies Promise.prototype globally.
|
|
477
|
-
* Only enable if no other library modifies Promise.prototype.
|
|
478
|
-
*
|
|
479
|
-
* **When false:** Async zone is disabled. Use `tracked()` manually in Promise callbacks.
|
|
480
|
-
*
|
|
481
|
-
* Can be overridden per-effect via EffectOptions
|
|
482
|
-
* @default 'cancel'
|
|
483
|
-
*/
|
|
484
|
-
asyncMode: 'cancel',
|
|
485
|
-
// biome-ignore lint/suspicious/noConsole: This is the whole point here
|
|
486
|
-
warn: (...args) => console.warn(...args),
|
|
487
|
-
/**
|
|
488
|
-
* Configuration for the introspection system
|
|
489
|
-
*/
|
|
490
|
-
introspection: {
|
|
491
|
-
/**
|
|
492
|
-
* Whether to keep a history of mutations for debugging
|
|
493
|
-
* @default false
|
|
494
|
-
*/
|
|
495
|
-
enableHistory: false,
|
|
496
|
-
/**
|
|
497
|
-
* Number of mutations to keep in history
|
|
498
|
-
* @default 50
|
|
499
|
-
*/
|
|
500
|
-
historySize: 50,
|
|
501
|
-
},
|
|
502
|
-
/**
|
|
503
|
-
* Configuration for zone hooks - control which async APIs are hooked
|
|
504
|
-
* Each option controls whether the corresponding async API is wrapped to preserve effect context
|
|
505
|
-
* Only applies when asyncMode is enabled (truthy)
|
|
506
|
-
*/
|
|
507
|
-
zones: {
|
|
508
|
-
/**
|
|
509
|
-
* Hook setTimeout to preserve effect context
|
|
510
|
-
* @default true
|
|
511
|
-
*/
|
|
512
|
-
setTimeout: true,
|
|
513
|
-
/**
|
|
514
|
-
* Hook setInterval to preserve effect context
|
|
515
|
-
* @default true
|
|
516
|
-
*/
|
|
517
|
-
setInterval: true,
|
|
518
|
-
/**
|
|
519
|
-
* Hook requestAnimationFrame (runs in untracked context when hooked)
|
|
520
|
-
* @default true
|
|
521
|
-
*/
|
|
522
|
-
requestAnimationFrame: true,
|
|
523
|
-
/**
|
|
524
|
-
* Hook queueMicrotask to preserve effect context
|
|
525
|
-
* @default true
|
|
526
|
-
*/
|
|
527
|
-
queueMicrotask: true,
|
|
528
|
-
},
|
|
529
|
-
};
|
|
530
|
-
|
|
531
|
-
/**
|
|
532
|
-
* Effect context stack for nested tracking (front = active, next = parent)
|
|
533
|
-
*/
|
|
534
|
-
const stack = [];
|
|
535
|
-
function captureEffectStack() {
|
|
536
|
-
return stack.slice();
|
|
537
|
-
}
|
|
538
|
-
function isRunning(effect) {
|
|
539
|
-
const rootEffect = getRoot(effect);
|
|
540
|
-
// Check if the effect is directly in the stack
|
|
541
|
-
const rootIndex = stack.indexOf(rootEffect);
|
|
542
|
-
if (rootIndex !== -1) {
|
|
543
|
-
return stack.slice(0, rootIndex + 1).reverse();
|
|
544
|
-
}
|
|
545
|
-
// Check if any effect in the stack is a descendant of this effect
|
|
546
|
-
// (i.e., walk up the parent chain from each stack effect to see if we reach this effect)
|
|
547
|
-
for (let i = 0; i < stack.length; i++) {
|
|
548
|
-
const stackEffect = stack[i];
|
|
549
|
-
let current = stackEffect;
|
|
550
|
-
const visited = new WeakSet();
|
|
551
|
-
const ancestorChain = [];
|
|
552
|
-
// TODO: That's perhaps a lot of computations for an `assert`
|
|
553
|
-
// Walk up the parent chain to find if this effect is an ancestor
|
|
554
|
-
while (current && !visited.has(current)) {
|
|
555
|
-
visited.add(current);
|
|
556
|
-
const currentRoot = getRoot(current);
|
|
557
|
-
ancestorChain.push(currentRoot);
|
|
558
|
-
if (currentRoot === rootEffect) {
|
|
559
|
-
// Found a descendant - build the full chain from ancestor to active
|
|
560
|
-
// The ancestorChain contains [descendant, parent, ..., ancestor] (walking up)
|
|
561
|
-
// We need [ancestor (effect), ..., parent, descendant, ...stack from descendant to active]
|
|
562
|
-
const chainFromAncestor = ancestorChain.reverse(); // [ancestor, ..., descendant]
|
|
563
|
-
// Prepend the actual effect we're checking (in case current is a wrapper)
|
|
564
|
-
if (chainFromAncestor[0] !== rootEffect) {
|
|
565
|
-
chainFromAncestor.unshift(rootEffect);
|
|
566
|
-
}
|
|
567
|
-
// Append the rest of the stack from the descendant to the active effect
|
|
568
|
-
const stackFromDescendant = stack.slice(0, i + 1).reverse(); // [descendant, ..., active]
|
|
569
|
-
// Remove duplicate descendant (it's both at end of chainFromAncestor and start of stackFromDescendant)
|
|
570
|
-
if (chainFromAncestor.length > 0 && stackFromDescendant.length > 0) {
|
|
571
|
-
stackFromDescendant.shift(); // Remove duplicate descendant
|
|
572
|
-
}
|
|
573
|
-
return [...chainFromAncestor, ...stackFromDescendant];
|
|
574
|
-
}
|
|
575
|
-
current = effectParent.get(current);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
return false;
|
|
579
|
-
}
|
|
580
|
-
function withEffectStack(snapshot, fn) {
|
|
581
|
-
const previousStack = stack.slice();
|
|
582
|
-
assignStack(snapshot);
|
|
583
|
-
try {
|
|
584
|
-
return fn();
|
|
585
|
-
}
|
|
586
|
-
finally {
|
|
587
|
-
assignStack(previousStack);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
function getActiveEffect() {
|
|
591
|
-
return stack[0];
|
|
592
|
-
}
|
|
593
|
-
/**
|
|
594
|
-
* Executes a function with a specific effect context
|
|
595
|
-
* @param effect - The effect to use as context
|
|
596
|
-
* @param fn - The function to execute
|
|
597
|
-
* @param keepParent - Whether to keep the parent effect context
|
|
598
|
-
* @returns The result of the function
|
|
599
|
-
*/
|
|
600
|
-
function withEffect(effect, fn) {
|
|
601
|
-
// console.log('[Mutts] withEffect', effect ? 'Active' : 'NULL');
|
|
602
|
-
if (getRoot(effect) === getRoot(getActiveEffect()))
|
|
603
|
-
return fn();
|
|
604
|
-
stack.unshift(effect);
|
|
605
|
-
try {
|
|
606
|
-
return fn();
|
|
607
|
-
}
|
|
608
|
-
finally {
|
|
609
|
-
const recoveredEffect = stack.shift();
|
|
610
|
-
if (recoveredEffect !== effect)
|
|
611
|
-
throw new ReactiveError('[reactive] Effect stack mismatch');
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
function assignStack(values) {
|
|
615
|
-
stack.length = 0;
|
|
616
|
-
stack.push(...values);
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
const objectToProxy = new WeakMap();
|
|
620
|
-
const proxyToObject = new WeakMap();
|
|
621
|
-
function storeProxyRelationship(target, proxy) {
|
|
622
|
-
objectToProxy.set(target, proxy);
|
|
623
|
-
proxyToObject.set(proxy, target);
|
|
624
|
-
}
|
|
625
|
-
function getExistingProxy(target) {
|
|
626
|
-
return objectToProxy.get(target);
|
|
627
|
-
}
|
|
628
|
-
function trackProxyObject(proxy, target) {
|
|
629
|
-
proxyToObject.set(proxy, target);
|
|
630
|
-
}
|
|
631
|
-
function unwrap(obj) {
|
|
632
|
-
let current = obj;
|
|
633
|
-
while (current && typeof current === 'object' && current !== null && proxyToObject.has(current)) {
|
|
634
|
-
current = proxyToObject.get(current);
|
|
635
|
-
}
|
|
636
|
-
return current;
|
|
637
|
-
}
|
|
638
|
-
function isReactive(obj) {
|
|
639
|
-
return proxyToObject.has(obj);
|
|
640
|
-
}
|
|
641
|
-
|
|
642
335
|
// Track which effects are watching which reactive objects for cleanup
|
|
643
336
|
const effectToReactiveObjects = new WeakMap();
|
|
644
337
|
// Track effects per reactive object and property
|
|
@@ -647,13 +340,29 @@ const watchers = new WeakMap();
|
|
|
647
340
|
const effectChildren = new WeakMap();
|
|
648
341
|
// Track parent effect relationships for hierarchy traversal (used in deep touch filtering)
|
|
649
342
|
const effectParent = new WeakMap();
|
|
343
|
+
// Track reverse mapping to ensure unicity: One Root -> One Function
|
|
344
|
+
const reverseRoots = new WeakMap();
|
|
650
345
|
/**
|
|
651
346
|
* Marks a function with its root function for effect tracking
|
|
347
|
+
* Enforces strict unicity: A root function can only identify ONE function.
|
|
652
348
|
* @param fn - The function to mark
|
|
653
349
|
* @param root - The root function
|
|
654
350
|
* @returns The marked function
|
|
655
351
|
*/
|
|
656
352
|
function markWithRoot(fn, root) {
|
|
353
|
+
// Check for collision
|
|
354
|
+
const existingRef = reverseRoots.get(root);
|
|
355
|
+
const existing = existingRef?.deref();
|
|
356
|
+
if (existing && existing !== fn) {
|
|
357
|
+
const rootName = root.name || 'anonymous';
|
|
358
|
+
const existingName = existing.name || 'anonymous';
|
|
359
|
+
const fnName = fn.name || 'anonymous';
|
|
360
|
+
throw new Error(`[reactive] Abusive Shared Root detected: Root '${rootName}' is already identifying function '${existingName}'. ` +
|
|
361
|
+
`Cannot reuse it for '${fnName}'. Shared roots cause lost updates and broken identity logic.`);
|
|
362
|
+
}
|
|
363
|
+
// Always update the map so subsequent checks find this one
|
|
364
|
+
// (Last writer wins for the check)
|
|
365
|
+
reverseRoots.set(root, new WeakRef(fn));
|
|
657
366
|
// Mark fn with the new root
|
|
658
367
|
return Object.defineProperty(fn, rootFunction, {
|
|
659
368
|
value: getRoot(root),
|
|
@@ -666,64 +375,15 @@ function markWithRoot(fn, root) {
|
|
|
666
375
|
* @returns The root function
|
|
667
376
|
*/
|
|
668
377
|
function getRoot(fn) {
|
|
669
|
-
|
|
378
|
+
while (fn && rootFunction in fn)
|
|
379
|
+
fn = fn[rootFunction];
|
|
380
|
+
return fn;
|
|
670
381
|
}
|
|
671
382
|
// Flag to disable dependency tracking for the current active effect (not globally)
|
|
672
383
|
const trackingDisabledEffects = new WeakSet();
|
|
673
384
|
let globalTrackingDisabled = false;
|
|
674
|
-
function
|
|
675
|
-
|
|
676
|
-
if (!active)
|
|
677
|
-
return globalTrackingDisabled;
|
|
678
|
-
return trackingDisabledEffects.has(getRoot(active));
|
|
679
|
-
}
|
|
680
|
-
function setTrackingDisabled(value) {
|
|
681
|
-
const active = getActiveEffect();
|
|
682
|
-
if (!active) {
|
|
683
|
-
globalTrackingDisabled = value;
|
|
684
|
-
return;
|
|
685
|
-
}
|
|
686
|
-
const root = getRoot(active);
|
|
687
|
-
if (value)
|
|
688
|
-
trackingDisabledEffects.add(root);
|
|
689
|
-
else
|
|
690
|
-
trackingDisabledEffects.delete(root);
|
|
691
|
-
}
|
|
692
|
-
/**
|
|
693
|
-
* Marks a property as a dependency of the current effect
|
|
694
|
-
* @param obj - The object containing the property
|
|
695
|
-
* @param prop - The property name (defaults to allProps)
|
|
696
|
-
*/
|
|
697
|
-
function dependant(obj, prop = allProps) {
|
|
698
|
-
obj = unwrap(obj);
|
|
699
|
-
const currentActiveEffect = getActiveEffect();
|
|
700
|
-
// Early return if no active effect, tracking disabled, or invalid prop
|
|
701
|
-
if (!currentActiveEffect ||
|
|
702
|
-
getTrackingDisabled() ||
|
|
703
|
-
(typeof prop === 'symbol' && prop !== allProps))
|
|
704
|
-
return;
|
|
705
|
-
registerDependency(obj, prop, currentActiveEffect);
|
|
706
|
-
}
|
|
707
|
-
function registerDependency(obj, prop, currentActiveEffect) {
|
|
708
|
-
let objectWatchers = watchers.get(obj);
|
|
709
|
-
if (!objectWatchers) {
|
|
710
|
-
objectWatchers = new Map();
|
|
711
|
-
watchers.set(obj, objectWatchers);
|
|
712
|
-
}
|
|
713
|
-
let deps = objectWatchers.get(prop);
|
|
714
|
-
if (!deps) {
|
|
715
|
-
deps = new Set();
|
|
716
|
-
objectWatchers.set(prop, deps);
|
|
717
|
-
}
|
|
718
|
-
deps.add(currentActiveEffect);
|
|
719
|
-
// Track which reactive objects this effect is watching
|
|
720
|
-
const effectObjects = effectToReactiveObjects.get(currentActiveEffect);
|
|
721
|
-
if (effectObjects) {
|
|
722
|
-
effectObjects.add(obj);
|
|
723
|
-
}
|
|
724
|
-
else {
|
|
725
|
-
effectToReactiveObjects.set(currentActiveEffect, new Set([obj]));
|
|
726
|
-
}
|
|
385
|
+
function setGlobalTrackingDisabled(value) {
|
|
386
|
+
globalTrackingDisabled = value;
|
|
727
387
|
}
|
|
728
388
|
|
|
729
389
|
/**
|
|
@@ -1078,6 +738,171 @@ function addToMutationHistory(source, target, obj, prop, evolution) {
|
|
|
1078
738
|
}
|
|
1079
739
|
}
|
|
1080
740
|
|
|
741
|
+
/**
|
|
742
|
+
* Effect context stack for nested tracking (front = active, next = parent)
|
|
743
|
+
*/
|
|
744
|
+
const stack = [];
|
|
745
|
+
function captureEffectStack() {
|
|
746
|
+
return stack.slice();
|
|
747
|
+
}
|
|
748
|
+
function isRunning(effect) {
|
|
749
|
+
const rootEffect = getRoot(effect);
|
|
750
|
+
// Check if the effect is directly in the stack
|
|
751
|
+
const rootIndex = stack.indexOf(rootEffect);
|
|
752
|
+
if (rootIndex !== -1) {
|
|
753
|
+
return stack.slice(0, rootIndex + 1).reverse();
|
|
754
|
+
}
|
|
755
|
+
// Check if any effect in the stack is a descendant of this effect
|
|
756
|
+
// (i.e., walk up the parent chain from each stack effect to see if we reach this effect)
|
|
757
|
+
for (let i = 0; i < stack.length; i++) {
|
|
758
|
+
const stackEffect = stack[i];
|
|
759
|
+
let current = stackEffect;
|
|
760
|
+
const visited = new WeakSet();
|
|
761
|
+
const ancestorChain = [];
|
|
762
|
+
// TODO: That's perhaps a lot of computations for an `assert`
|
|
763
|
+
// Walk up the parent chain to find if this effect is an ancestor
|
|
764
|
+
while (current && !visited.has(current)) {
|
|
765
|
+
visited.add(current);
|
|
766
|
+
const currentRoot = getRoot(current);
|
|
767
|
+
ancestorChain.push(currentRoot);
|
|
768
|
+
if (currentRoot === rootEffect) {
|
|
769
|
+
// Found a descendant - build the full chain from ancestor to active
|
|
770
|
+
// The ancestorChain contains [descendant, parent, ..., ancestor] (walking up)
|
|
771
|
+
// We need [ancestor (effect), ..., parent, descendant, ...stack from descendant to active]
|
|
772
|
+
const chainFromAncestor = ancestorChain.reverse(); // [ancestor, ..., descendant]
|
|
773
|
+
// Prepend the actual effect we're checking (in case current is a wrapper)
|
|
774
|
+
if (chainFromAncestor[0] !== rootEffect) {
|
|
775
|
+
chainFromAncestor.unshift(rootEffect);
|
|
776
|
+
}
|
|
777
|
+
// Append the rest of the stack from the descendant to the active effect
|
|
778
|
+
const stackFromDescendant = stack.slice(0, i + 1).reverse(); // [descendant, ..., active]
|
|
779
|
+
// Remove duplicate descendant (it's both at end of chainFromAncestor and start of stackFromDescendant)
|
|
780
|
+
if (chainFromAncestor.length > 0 && stackFromDescendant.length > 0) {
|
|
781
|
+
stackFromDescendant.shift(); // Remove duplicate descendant
|
|
782
|
+
}
|
|
783
|
+
return [...chainFromAncestor, ...stackFromDescendant];
|
|
784
|
+
}
|
|
785
|
+
current = effectParent.get(current);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
return false;
|
|
789
|
+
}
|
|
790
|
+
function withEffectStack(snapshot, fn) {
|
|
791
|
+
const previousStack = stack.slice();
|
|
792
|
+
assignStack(snapshot);
|
|
793
|
+
try {
|
|
794
|
+
return fn();
|
|
795
|
+
}
|
|
796
|
+
finally {
|
|
797
|
+
assignStack(previousStack);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
function getActiveEffect() {
|
|
801
|
+
return stack[0];
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Executes a function with a specific effect context
|
|
805
|
+
* @param effect - The effect to use as context
|
|
806
|
+
* @param fn - The function to execute
|
|
807
|
+
* @param keepParent - Whether to keep the parent effect context
|
|
808
|
+
* @returns The result of the function
|
|
809
|
+
*/
|
|
810
|
+
function withEffect(effect, fn) {
|
|
811
|
+
if (getRoot(effect) === getRoot(getActiveEffect()))
|
|
812
|
+
return fn();
|
|
813
|
+
stack.unshift(effect);
|
|
814
|
+
try {
|
|
815
|
+
return fn();
|
|
816
|
+
}
|
|
817
|
+
finally {
|
|
818
|
+
const recoveredEffect = stack.shift();
|
|
819
|
+
if (recoveredEffect !== effect)
|
|
820
|
+
throw new ReactiveError('[reactive] Effect stack mismatch');
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
function assignStack(values) {
|
|
824
|
+
stack.length = 0;
|
|
825
|
+
stack.push(...values);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
const objectToProxy = new WeakMap();
|
|
829
|
+
const proxyToObject = new WeakMap();
|
|
830
|
+
function storeProxyRelationship(target, proxy) {
|
|
831
|
+
objectToProxy.set(target, proxy);
|
|
832
|
+
proxyToObject.set(proxy, target);
|
|
833
|
+
}
|
|
834
|
+
function getExistingProxy(target) {
|
|
835
|
+
return objectToProxy.get(target);
|
|
836
|
+
}
|
|
837
|
+
function trackProxyObject(proxy, target) {
|
|
838
|
+
proxyToObject.set(proxy, target);
|
|
839
|
+
}
|
|
840
|
+
function unwrap(obj) {
|
|
841
|
+
let current = obj;
|
|
842
|
+
while (current && typeof current === 'object' && current !== null && proxyToObject.has(current)) {
|
|
843
|
+
current = proxyToObject.get(current);
|
|
844
|
+
}
|
|
845
|
+
return current;
|
|
846
|
+
}
|
|
847
|
+
function isReactive(obj) {
|
|
848
|
+
return proxyToObject.has(obj);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
function getTrackingDisabled() {
|
|
852
|
+
const active = getActiveEffect();
|
|
853
|
+
if (!active)
|
|
854
|
+
return globalTrackingDisabled;
|
|
855
|
+
return trackingDisabledEffects.has(getRoot(active));
|
|
856
|
+
}
|
|
857
|
+
function setTrackingDisabled(value) {
|
|
858
|
+
const active = getActiveEffect();
|
|
859
|
+
if (!active) {
|
|
860
|
+
setGlobalTrackingDisabled(value);
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
const root = getRoot(active);
|
|
864
|
+
if (value)
|
|
865
|
+
trackingDisabledEffects.add(root);
|
|
866
|
+
else
|
|
867
|
+
trackingDisabledEffects.delete(root);
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Marks a property as a dependency of the current effect
|
|
871
|
+
* @param obj - The object containing the property
|
|
872
|
+
* @param prop - The property name (defaults to allProps)
|
|
873
|
+
*/
|
|
874
|
+
function dependant(obj, prop = allProps) {
|
|
875
|
+
obj = unwrap(obj);
|
|
876
|
+
const currentActiveEffect = getActiveEffect();
|
|
877
|
+
// Early return if no active effect, tracking disabled, or invalid prop
|
|
878
|
+
if (!currentActiveEffect ||
|
|
879
|
+
getTrackingDisabled() ||
|
|
880
|
+
(typeof prop === 'symbol' && prop !== allProps))
|
|
881
|
+
return;
|
|
882
|
+
registerDependency(obj, prop, currentActiveEffect);
|
|
883
|
+
}
|
|
884
|
+
function registerDependency(obj, prop, currentActiveEffect) {
|
|
885
|
+
let objectWatchers = watchers.get(obj);
|
|
886
|
+
if (!objectWatchers) {
|
|
887
|
+
objectWatchers = new Map();
|
|
888
|
+
watchers.set(obj, objectWatchers);
|
|
889
|
+
}
|
|
890
|
+
let deps = objectWatchers.get(prop);
|
|
891
|
+
if (!deps) {
|
|
892
|
+
deps = new Set();
|
|
893
|
+
objectWatchers.set(prop, deps);
|
|
894
|
+
}
|
|
895
|
+
deps.add(currentActiveEffect);
|
|
896
|
+
// Track which reactive objects this effect is watching
|
|
897
|
+
const effectObjects = effectToReactiveObjects.get(currentActiveEffect);
|
|
898
|
+
if (effectObjects) {
|
|
899
|
+
effectObjects.add(obj);
|
|
900
|
+
}
|
|
901
|
+
else {
|
|
902
|
+
effectToReactiveObjects.set(currentActiveEffect, new Set([obj]));
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
1081
906
|
/**
|
|
1082
907
|
* Zone-like async context preservation for reactive effects
|
|
1083
908
|
*
|
|
@@ -1258,6 +1083,50 @@ function formatRoots(roots, limit = 20) {
|
|
|
1258
1083
|
const end = names.slice(-10);
|
|
1259
1084
|
return `${start.join(' → ')} ... (${names.length - 15} more) ... ${end.join(' → ')}`;
|
|
1260
1085
|
}
|
|
1086
|
+
// Nested map structure for efficient counting and batch cleanup
|
|
1087
|
+
// batchId -> effect root -> obj -> prop -> count
|
|
1088
|
+
let activationRegistry;
|
|
1089
|
+
const activationLog = new Array(100);
|
|
1090
|
+
function getActivationLog() {
|
|
1091
|
+
return activationLog;
|
|
1092
|
+
}
|
|
1093
|
+
function recordActivation(effect, obj, evolution, prop) {
|
|
1094
|
+
const root = getRoot(effect);
|
|
1095
|
+
if (!activationRegistry)
|
|
1096
|
+
return;
|
|
1097
|
+
let effectData = activationRegistry.get(root);
|
|
1098
|
+
if (!effectData) {
|
|
1099
|
+
effectData = new Map();
|
|
1100
|
+
activationRegistry.set(root, effectData);
|
|
1101
|
+
}
|
|
1102
|
+
let objData = effectData.get(obj);
|
|
1103
|
+
if (!objData) {
|
|
1104
|
+
objData = new Map();
|
|
1105
|
+
effectData.set(obj, objData);
|
|
1106
|
+
}
|
|
1107
|
+
const count = (objData.get(prop) ?? 0) + 1;
|
|
1108
|
+
objData.set(prop, count);
|
|
1109
|
+
// Keep a limited history for diagnostics
|
|
1110
|
+
activationLog.unshift({
|
|
1111
|
+
effect,
|
|
1112
|
+
obj,
|
|
1113
|
+
evolution,
|
|
1114
|
+
prop,
|
|
1115
|
+
});
|
|
1116
|
+
activationLog.pop();
|
|
1117
|
+
if (count >= options.maxTriggerPerBatch) {
|
|
1118
|
+
const effectName = root?.name || 'anonymous';
|
|
1119
|
+
const message = `Aggressive trigger detected: effect "${effectName}" triggered ${count} times in the batch by the same cause.`;
|
|
1120
|
+
if (options.maxEffectReaction === 'throw') {
|
|
1121
|
+
throw new ReactiveError(message, {
|
|
1122
|
+
code: ReactiveErrorCode.MaxReactionExceeded,
|
|
1123
|
+
count,
|
|
1124
|
+
effect: effectName,
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
1127
|
+
options.warn(`[reactive] ${message}`);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1261
1130
|
/**
|
|
1262
1131
|
* Registers a debug callback that is called when the current effect is triggered by a dependency change
|
|
1263
1132
|
*
|
|
@@ -1419,6 +1288,7 @@ function addGraphEdge(callerRoot, targetRoot) {
|
|
|
1419
1288
|
* @param end - Target node
|
|
1420
1289
|
* @param exclude - Node to exclude from the path
|
|
1421
1290
|
* @returns true if a path exists without going through the excluded node
|
|
1291
|
+
* @todo Can be REALLY costly - optimise or make optional or ...
|
|
1422
1292
|
*/
|
|
1423
1293
|
function hasPathExcluding(start, end, exclude) {
|
|
1424
1294
|
if (start === end)
|
|
@@ -1547,6 +1417,9 @@ function cleanupEffectFromGraph(effect) {
|
|
|
1547
1417
|
// Track currently executing effects to prevent re-execution
|
|
1548
1418
|
// These are all the effects triggered under `activeEffect`
|
|
1549
1419
|
let batchQueue;
|
|
1420
|
+
function hasBatched(effect) {
|
|
1421
|
+
return batchQueue?.all.has(getRoot(effect));
|
|
1422
|
+
}
|
|
1550
1423
|
const batchCleanups = new Set();
|
|
1551
1424
|
/**
|
|
1552
1425
|
* Computes and caches in-degrees for all effects in the batch
|
|
@@ -1703,6 +1576,12 @@ function wouldCreateCycle(callerRoot, targetRoot) {
|
|
|
1703
1576
|
* @param immediate - If true, don't create edges in the dependency graph
|
|
1704
1577
|
*/
|
|
1705
1578
|
function addToBatch(effect, caller, immediate) {
|
|
1579
|
+
const cleanupFn = effect[cleanup$1];
|
|
1580
|
+
if (cleanupFn)
|
|
1581
|
+
cleanupFn();
|
|
1582
|
+
// If the effect was stopped during cleanup (e.g. lazy memoization), don't add it to the batch
|
|
1583
|
+
if (effect[stopped])
|
|
1584
|
+
return;
|
|
1706
1585
|
if (!batchQueue)
|
|
1707
1586
|
return;
|
|
1708
1587
|
const root = getRoot(effect);
|
|
@@ -1972,6 +1851,10 @@ function batch(effect, immediate) {
|
|
|
1972
1851
|
}
|
|
1973
1852
|
else {
|
|
1974
1853
|
// New batch - initialize
|
|
1854
|
+
if (!activationRegistry)
|
|
1855
|
+
activationRegistry = new Map();
|
|
1856
|
+
else
|
|
1857
|
+
throw new Error('Batch already in progress');
|
|
1975
1858
|
options.beginChain(roots);
|
|
1976
1859
|
batchQueue = {
|
|
1977
1860
|
all: new Map(),
|
|
@@ -2050,6 +1933,7 @@ function batch(effect, immediate) {
|
|
|
2050
1933
|
return firstReturn.value;
|
|
2051
1934
|
}
|
|
2052
1935
|
finally {
|
|
1936
|
+
activationRegistry = undefined;
|
|
2053
1937
|
batchQueue = undefined;
|
|
2054
1938
|
options.endChain();
|
|
2055
1939
|
}
|
|
@@ -2120,6 +2004,7 @@ function batch(effect, immediate) {
|
|
|
2120
2004
|
return firstReturn.value;
|
|
2121
2005
|
}
|
|
2122
2006
|
finally {
|
|
2007
|
+
activationRegistry = undefined;
|
|
2123
2008
|
batchQueue = undefined;
|
|
2124
2009
|
options.endChain();
|
|
2125
2010
|
}
|
|
@@ -2132,12 +2017,18 @@ function batch(effect, immediate) {
|
|
|
2132
2017
|
const atomic = decorator({
|
|
2133
2018
|
method(original) {
|
|
2134
2019
|
return function (...args) {
|
|
2135
|
-
|
|
2020
|
+
const atomicEffect = () => original.apply(this, args);
|
|
2021
|
+
// Debug: helpful to have a name
|
|
2022
|
+
Object.defineProperty(atomicEffect, 'name', { value: `atomic(${original.name})` });
|
|
2023
|
+
return batch(atomicEffect, 'immediate');
|
|
2136
2024
|
};
|
|
2137
2025
|
},
|
|
2138
2026
|
default(original) {
|
|
2139
2027
|
return function (...args) {
|
|
2140
|
-
|
|
2028
|
+
const atomicEffect = () => original.apply(this, args);
|
|
2029
|
+
// Debug: helpful to have a name
|
|
2030
|
+
Object.defineProperty(atomicEffect, 'name', { value: `atomic(${original.name})` });
|
|
2031
|
+
return batch(atomicEffect, 'immediate');
|
|
2141
2032
|
};
|
|
2142
2033
|
},
|
|
2143
2034
|
});
|
|
@@ -2171,7 +2062,7 @@ fn, effectOptions) {
|
|
|
2171
2062
|
let cleanup = null;
|
|
2172
2063
|
// capture the parent effect at creation time for ascend
|
|
2173
2064
|
const parentsForAscend = captureEffectStack();
|
|
2174
|
-
const tracked =
|
|
2065
|
+
const tracked = (cb) => withEffect(runEffect, cb);
|
|
2175
2066
|
const ascend = (cb) => withEffectStack(parentsForAscend, cb);
|
|
2176
2067
|
let effectStopped = false;
|
|
2177
2068
|
let hasReacted = false;
|
|
@@ -2304,8 +2195,25 @@ fn, effectOptions) {
|
|
|
2304
2195
|
cleanupEffectFromGraph(runEffect);
|
|
2305
2196
|
fr.unregister(stopEffect);
|
|
2306
2197
|
};
|
|
2198
|
+
function augmentedRv(rv) {
|
|
2199
|
+
Object.defineProperty(rv, stopped, {
|
|
2200
|
+
get() {
|
|
2201
|
+
return effectStopped;
|
|
2202
|
+
},
|
|
2203
|
+
});
|
|
2204
|
+
Object.defineProperty(rv, cleanup$1, {
|
|
2205
|
+
value: () => {
|
|
2206
|
+
if (cleanup) {
|
|
2207
|
+
const prevCleanup = cleanup;
|
|
2208
|
+
cleanup = null;
|
|
2209
|
+
withEffect(undefined, () => prevCleanup());
|
|
2210
|
+
}
|
|
2211
|
+
},
|
|
2212
|
+
});
|
|
2213
|
+
return rv;
|
|
2214
|
+
}
|
|
2307
2215
|
if (isRootEffect) {
|
|
2308
|
-
const callIfCollected = () => stopEffect();
|
|
2216
|
+
const callIfCollected = augmentedRv(() => stopEffect());
|
|
2309
2217
|
fr.register(callIfCollected, () => {
|
|
2310
2218
|
stopEffect();
|
|
2311
2219
|
options.garbageCollected(fn);
|
|
@@ -2318,14 +2226,14 @@ fn, effectOptions) {
|
|
|
2318
2226
|
children = new Set();
|
|
2319
2227
|
effectChildren.set(parent, children);
|
|
2320
2228
|
}
|
|
2321
|
-
const subEffectCleanup = () => {
|
|
2229
|
+
const subEffectCleanup = augmentedRv(() => {
|
|
2322
2230
|
children.delete(subEffectCleanup);
|
|
2323
2231
|
if (children.size === 0) {
|
|
2324
2232
|
effectChildren.delete(parent);
|
|
2325
2233
|
}
|
|
2326
2234
|
// Execute this child effect cleanup (which triggers its own mainCleanup)
|
|
2327
2235
|
stopEffect();
|
|
2328
|
-
};
|
|
2236
|
+
});
|
|
2329
2237
|
children.add(subEffectCleanup);
|
|
2330
2238
|
return subEffectCleanup;
|
|
2331
2239
|
}
|
|
@@ -2489,7 +2397,11 @@ function collectEffects(obj, evolution, effects, objectWatchers, ...keyChains) {
|
|
|
2489
2397
|
options.skipRunningEffect(effect, runningChain);
|
|
2490
2398
|
continue;
|
|
2491
2399
|
}
|
|
2492
|
-
effects.
|
|
2400
|
+
if (!effects.has(effect)) {
|
|
2401
|
+
effects.add(effect);
|
|
2402
|
+
if (!hasBatched(effect))
|
|
2403
|
+
recordActivation(effect, obj, evolution, key);
|
|
2404
|
+
}
|
|
2493
2405
|
const trackers = effectTrackers.get(effect);
|
|
2494
2406
|
recordTriggerLink(sourceEffect, effect, obj, key, evolution);
|
|
2495
2407
|
if (trackers) {
|
|
@@ -2557,6 +2469,7 @@ function touchedOpaque(obj, evolution, prop) {
|
|
|
2557
2469
|
continue;
|
|
2558
2470
|
}
|
|
2559
2471
|
effects.add(effect);
|
|
2472
|
+
recordActivation(effect, obj, evolution, prop);
|
|
2560
2473
|
const trackers = effectTrackers.get(effect);
|
|
2561
2474
|
recordTriggerLink(sourceEffect, effect, obj, prop, evolution);
|
|
2562
2475
|
if (trackers) {
|
|
@@ -2919,13 +2832,13 @@ const reactiveHandlers = {
|
|
|
2919
2832
|
const receiverDesc = Object.getOwnPropertyDescriptor(unwrappedReceiver, prop);
|
|
2920
2833
|
const targetDesc = Object.getOwnPropertyDescriptor(unwrappedObj, prop);
|
|
2921
2834
|
const desc = receiverDesc || targetDesc;
|
|
2922
|
-
//
|
|
2923
|
-
//
|
|
2835
|
+
// We *need* to use `receiver` and not `unwrappedObj` here, otherwise we break
|
|
2836
|
+
// the dependency tracking for memoized getters
|
|
2924
2837
|
if (desc?.get && !desc?.set) {
|
|
2925
|
-
oldVal = withEffect(undefined, () => Reflect.get(unwrappedObj, prop,
|
|
2838
|
+
oldVal = withEffect(undefined, () => Reflect.get(unwrappedObj, prop, receiver));
|
|
2926
2839
|
}
|
|
2927
2840
|
else {
|
|
2928
|
-
oldVal = Reflect.get(unwrappedObj, prop,
|
|
2841
|
+
oldVal = withEffect(undefined, () => Reflect.get(unwrappedObj, prop, receiver));
|
|
2929
2842
|
}
|
|
2930
2843
|
}
|
|
2931
2844
|
if (objectsWithDeepWatchers.has(obj)) {
|
|
@@ -3215,12 +3128,12 @@ function watchObject(value, changed, { immediate = false, deep = false } = {}) {
|
|
|
3215
3128
|
const myParentEffect = getActiveEffect();
|
|
3216
3129
|
if (deep)
|
|
3217
3130
|
return deepWatch(value, changed, { immediate });
|
|
3218
|
-
return effect(
|
|
3131
|
+
return effect(function watchObjectEffect() {
|
|
3219
3132
|
dependant(value);
|
|
3220
3133
|
if (immediate)
|
|
3221
3134
|
withEffect(myParentEffect, () => changed(value));
|
|
3222
3135
|
immediate = true;
|
|
3223
|
-
}
|
|
3136
|
+
});
|
|
3224
3137
|
}
|
|
3225
3138
|
function watchCallBack(value, changed, { immediate = false, deep = false } = {}) {
|
|
3226
3139
|
const myParentEffect = getActiveEffect();
|
|
@@ -3229,7 +3142,7 @@ function watchCallBack(value, changed, { immediate = false, deep = false } = {})
|
|
|
3229
3142
|
const cbCleanup = effect(markWithRoot(function watchCallBackEffect(access) {
|
|
3230
3143
|
const newValue = value(access);
|
|
3231
3144
|
if (oldValue !== newValue)
|
|
3232
|
-
withEffect(myParentEffect,
|
|
3145
|
+
withEffect(myParentEffect, () => {
|
|
3233
3146
|
if (oldValue === unsetYet) {
|
|
3234
3147
|
if (immediate)
|
|
3235
3148
|
changed(newValue);
|
|
@@ -3240,9 +3153,9 @@ function watchCallBack(value, changed, { immediate = false, deep = false } = {})
|
|
|
3240
3153
|
if (deep) {
|
|
3241
3154
|
if (deepCleanup)
|
|
3242
3155
|
deepCleanup();
|
|
3243
|
-
deepCleanup = deepWatch(newValue,
|
|
3156
|
+
deepCleanup = deepWatch(newValue, (value) => changed(value, value));
|
|
3244
3157
|
}
|
|
3245
|
-
}
|
|
3158
|
+
});
|
|
3246
3159
|
}, value));
|
|
3247
3160
|
return () => {
|
|
3248
3161
|
cbCleanup();
|
|
@@ -3315,9 +3228,9 @@ function cleanedBy(obj, cleanupFn) {
|
|
|
3315
3228
|
*/
|
|
3316
3229
|
function derived(compute) {
|
|
3317
3230
|
const rv = { value: undefined };
|
|
3318
|
-
return cleanedBy(rv, untracked(() => effect(
|
|
3231
|
+
return cleanedBy(rv, untracked(() => effect(function derivedEffect(access) {
|
|
3319
3232
|
rv.value = compute(access);
|
|
3320
|
-
}
|
|
3233
|
+
})));
|
|
3321
3234
|
}
|
|
3322
3235
|
|
|
3323
3236
|
/**
|
|
@@ -3345,7 +3258,6 @@ function* makeReactiveEntriesIterator(iterator) {
|
|
|
3345
3258
|
const native$2 = Symbol('native');
|
|
3346
3259
|
const isArray = Array.isArray;
|
|
3347
3260
|
Array.isArray = ((value) => isArray(value) ||
|
|
3348
|
-
// biome-ignore lint/suspicious/useIsArray: We are defining it
|
|
3349
3261
|
(value &&
|
|
3350
3262
|
typeof value === 'object' &&
|
|
3351
3263
|
prototypeForwarding in value &&
|
|
@@ -3774,6 +3686,7 @@ function reduced(inputs, compute) {
|
|
|
3774
3686
|
}
|
|
3775
3687
|
|
|
3776
3688
|
const memoizedRegistry = new WeakMap();
|
|
3689
|
+
const wrapperRegistry = new WeakMap();
|
|
3777
3690
|
function getBranch(tree, key) {
|
|
3778
3691
|
tree.branches ?? (tree.branches = new WeakMap());
|
|
3779
3692
|
let branch = tree.branches.get(key);
|
|
@@ -3794,15 +3707,30 @@ function memoizeFunction(fn) {
|
|
|
3794
3707
|
if (localArgs.some((arg) => !(arg && ['object', 'symbol', 'function'].includes(typeof arg))))
|
|
3795
3708
|
throw new Error('memoize expects non-null object arguments');
|
|
3796
3709
|
let node = cacheRoot;
|
|
3710
|
+
// Note: decorators add `this` as first argument
|
|
3797
3711
|
for (const arg of localArgs) {
|
|
3798
3712
|
node = getBranch(node, arg);
|
|
3799
3713
|
}
|
|
3800
3714
|
dependant(node, 'memoize');
|
|
3801
|
-
if ('result' in node)
|
|
3715
|
+
if ('result' in node) {
|
|
3716
|
+
if (options.onMemoizationDiscrepancy) {
|
|
3717
|
+
const wasVerification = options.isVerificationRun;
|
|
3718
|
+
options.isVerificationRun = true;
|
|
3719
|
+
try {
|
|
3720
|
+
const fresh = untracked(() => fn(...localArgs));
|
|
3721
|
+
if (!deepCompare(node.result, fresh)) {
|
|
3722
|
+
options.onMemoizationDiscrepancy(node.result, fresh, fn, localArgs, 'calculation');
|
|
3723
|
+
}
|
|
3724
|
+
}
|
|
3725
|
+
finally {
|
|
3726
|
+
options.isVerificationRun = wasVerification;
|
|
3727
|
+
}
|
|
3728
|
+
}
|
|
3802
3729
|
return node.result;
|
|
3730
|
+
}
|
|
3803
3731
|
// Create memoize internal effect to track dependencies and invalidate cache
|
|
3804
3732
|
// Use untracked to prevent the effect creation from being affected by parent effects
|
|
3805
|
-
node.cleanup = root(() => effect(
|
|
3733
|
+
node.cleanup = root(() => effect(() => {
|
|
3806
3734
|
// Execute the function and track its dependencies
|
|
3807
3735
|
// The function execution will automatically track dependencies on reactive objects
|
|
3808
3736
|
node.result = fn(...localArgs);
|
|
@@ -3810,8 +3738,27 @@ function memoizeFunction(fn) {
|
|
|
3810
3738
|
// When dependencies change, clear the cache and notify consumers
|
|
3811
3739
|
delete node.result;
|
|
3812
3740
|
touched1(node, { type: 'invalidate', prop: localArgs }, 'memoize');
|
|
3741
|
+
// Lazy memoization: stop the effect so it doesn't re-run immediately.
|
|
3742
|
+
// It will be re-created on next access.
|
|
3743
|
+
if (node.cleanup) {
|
|
3744
|
+
node.cleanup();
|
|
3745
|
+
node.cleanup = undefined;
|
|
3746
|
+
}
|
|
3813
3747
|
};
|
|
3814
|
-
},
|
|
3748
|
+
}, { opaque: true }));
|
|
3749
|
+
if (options.onMemoizationDiscrepancy) {
|
|
3750
|
+
const wasVerification = options.isVerificationRun;
|
|
3751
|
+
options.isVerificationRun = true;
|
|
3752
|
+
try {
|
|
3753
|
+
const fresh = untracked(() => fn(...localArgs));
|
|
3754
|
+
if (!deepCompare(node.result, fresh)) {
|
|
3755
|
+
options.onMemoizationDiscrepancy(node.result, fresh, fn, localArgs, 'comparison');
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
finally {
|
|
3759
|
+
options.isVerificationRun = wasVerification;
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3815
3762
|
return node.result;
|
|
3816
3763
|
}, fn);
|
|
3817
3764
|
memoizedRegistry.set(fnRoot, memoized);
|
|
@@ -3819,19 +3766,37 @@ function memoizeFunction(fn) {
|
|
|
3819
3766
|
return memoized;
|
|
3820
3767
|
}
|
|
3821
3768
|
const memoize = decorator({
|
|
3822
|
-
getter(original, propertyKey) {
|
|
3823
|
-
const memoized = memoizeFunction(markWithRoot(renamed((that) => {
|
|
3824
|
-
return original.call(that);
|
|
3825
|
-
}, `${String(this.constructor.name)}.${String(propertyKey)}`), original));
|
|
3769
|
+
getter(original, target, propertyKey) {
|
|
3826
3770
|
return function () {
|
|
3771
|
+
let wrapper = wrapperRegistry.get(original);
|
|
3772
|
+
if (!wrapper) {
|
|
3773
|
+
wrapper = markWithRoot(renamed((that) => {
|
|
3774
|
+
return original.call(that);
|
|
3775
|
+
}, `${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(propertyKey)}`), {
|
|
3776
|
+
method: original,
|
|
3777
|
+
propertyKey,
|
|
3778
|
+
...(original[rootFunction] ? { [rootFunction]: original[rootFunction] } : {}),
|
|
3779
|
+
});
|
|
3780
|
+
wrapperRegistry.set(original, wrapper);
|
|
3781
|
+
}
|
|
3782
|
+
const memoized = memoizeFunction(wrapper);
|
|
3827
3783
|
return memoized(this);
|
|
3828
3784
|
};
|
|
3829
3785
|
},
|
|
3830
|
-
method(original, name) {
|
|
3831
|
-
const memoized = memoizeFunction(markWithRoot(renamed((that, ...args) => {
|
|
3832
|
-
return original.call(that, ...args);
|
|
3833
|
-
}, `${String(this.constructor.name)}.${String(name)}`), original));
|
|
3786
|
+
method(original, target, name) {
|
|
3834
3787
|
return function (...args) {
|
|
3788
|
+
let wrapper = wrapperRegistry.get(original);
|
|
3789
|
+
if (!wrapper) {
|
|
3790
|
+
wrapper = markWithRoot(renamed((that, ...args) => {
|
|
3791
|
+
return original.call(that, ...args);
|
|
3792
|
+
}, `${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(name)}`), {
|
|
3793
|
+
method: original,
|
|
3794
|
+
propertyKey: name,
|
|
3795
|
+
...(original[rootFunction] ? { [rootFunction]: original[rootFunction] } : {}),
|
|
3796
|
+
});
|
|
3797
|
+
wrapperRegistry.set(original, wrapper);
|
|
3798
|
+
}
|
|
3799
|
+
const memoized = memoizeFunction(wrapper);
|
|
3835
3800
|
return memoized(this, ...args);
|
|
3836
3801
|
};
|
|
3837
3802
|
},
|
|
@@ -4241,6 +4206,17 @@ function register(keyFn, initial) {
|
|
|
4241
4206
|
return new RegisterClass(keyFn, initial);
|
|
4242
4207
|
}
|
|
4243
4208
|
|
|
4209
|
+
/**
|
|
4210
|
+
* Maps projection effects (item effects) to their projection context
|
|
4211
|
+
*/
|
|
4212
|
+
const effectProjectionMetadata = new WeakMap();
|
|
4213
|
+
/**
|
|
4214
|
+
* Returns the projection context of the currently running effect, if any.
|
|
4215
|
+
*/
|
|
4216
|
+
function getActiveProjection() {
|
|
4217
|
+
const active = getActiveEffect();
|
|
4218
|
+
return active ? effectProjectionMetadata.get(active) : undefined;
|
|
4219
|
+
}
|
|
4244
4220
|
function defineAccessValue(access) {
|
|
4245
4221
|
Object.defineProperty(access, 'value', {
|
|
4246
4222
|
get: access.get,
|
|
@@ -4249,7 +4225,15 @@ function defineAccessValue(access) {
|
|
|
4249
4225
|
enumerable: true,
|
|
4250
4226
|
});
|
|
4251
4227
|
}
|
|
4252
|
-
function makeCleanup(target, effectMap, onDispose) {
|
|
4228
|
+
function makeCleanup(target, effectMap, onDispose, metadata) {
|
|
4229
|
+
if (metadata) {
|
|
4230
|
+
Object.defineProperty(target, projectionInfo, {
|
|
4231
|
+
value: metadata,
|
|
4232
|
+
writable: false,
|
|
4233
|
+
enumerable: false,
|
|
4234
|
+
configurable: true,
|
|
4235
|
+
});
|
|
4236
|
+
}
|
|
4253
4237
|
return cleanedBy(target, () => {
|
|
4254
4238
|
onDispose();
|
|
4255
4239
|
for (const stop of effectMap.values())
|
|
@@ -4272,6 +4256,8 @@ function projectArray(source, apply) {
|
|
|
4272
4256
|
Reflect.deleteProperty(target, index);
|
|
4273
4257
|
}
|
|
4274
4258
|
}
|
|
4259
|
+
const parent = getActiveProjection();
|
|
4260
|
+
const depth = parent ? parent.depth + 1 : 0;
|
|
4275
4261
|
const cleanupLength = effect(function projectArrayLengthEffect({ ascend }) {
|
|
4276
4262
|
const length = observedSource.length;
|
|
4277
4263
|
normalizeTargetLength(length);
|
|
@@ -4294,6 +4280,14 @@ function projectArray(source, apply) {
|
|
|
4294
4280
|
const produced = apply(accessBase, target);
|
|
4295
4281
|
target[index] = produced;
|
|
4296
4282
|
});
|
|
4283
|
+
setEffectName(stop, `project[${depth}]:${index}`);
|
|
4284
|
+
effectProjectionMetadata.set(stop, {
|
|
4285
|
+
source: observedSource,
|
|
4286
|
+
key: index,
|
|
4287
|
+
target,
|
|
4288
|
+
depth,
|
|
4289
|
+
parent,
|
|
4290
|
+
});
|
|
4297
4291
|
indexEffects.set(i, stop);
|
|
4298
4292
|
});
|
|
4299
4293
|
}
|
|
@@ -4301,7 +4295,13 @@ function projectArray(source, apply) {
|
|
|
4301
4295
|
if (index >= length)
|
|
4302
4296
|
disposeIndex(index);
|
|
4303
4297
|
});
|
|
4304
|
-
return makeCleanup(target, indexEffects, () => cleanupLength()
|
|
4298
|
+
return makeCleanup(target, indexEffects, () => cleanupLength(), {
|
|
4299
|
+
source: observedSource,
|
|
4300
|
+
target,
|
|
4301
|
+
apply,
|
|
4302
|
+
depth,
|
|
4303
|
+
parent,
|
|
4304
|
+
});
|
|
4305
4305
|
}
|
|
4306
4306
|
function projectRegister(source, apply) {
|
|
4307
4307
|
const observedSource = reactive(source);
|
|
@@ -4316,6 +4316,8 @@ function projectRegister(source, apply) {
|
|
|
4316
4316
|
target.delete(key);
|
|
4317
4317
|
}
|
|
4318
4318
|
}
|
|
4319
|
+
const parent = getActiveProjection();
|
|
4320
|
+
const depth = parent ? parent.depth + 1 : 0;
|
|
4319
4321
|
const cleanupKeys = effect(function projectRegisterEffect({ ascend }) {
|
|
4320
4322
|
const keys = new Set();
|
|
4321
4323
|
for (const key of observedSource.mapKeys())
|
|
@@ -4340,6 +4342,14 @@ function projectRegister(source, apply) {
|
|
|
4340
4342
|
const produced = apply(accessBase, target);
|
|
4341
4343
|
target.set(key, produced);
|
|
4342
4344
|
});
|
|
4345
|
+
setEffectName(stop, `project[${depth}]:${String(key)}`);
|
|
4346
|
+
effectProjectionMetadata.set(stop, {
|
|
4347
|
+
source: observedSource,
|
|
4348
|
+
key,
|
|
4349
|
+
target,
|
|
4350
|
+
depth,
|
|
4351
|
+
parent,
|
|
4352
|
+
});
|
|
4343
4353
|
keyEffects.set(key, stop);
|
|
4344
4354
|
});
|
|
4345
4355
|
}
|
|
@@ -4347,7 +4357,13 @@ function projectRegister(source, apply) {
|
|
|
4347
4357
|
if (!keys.has(key))
|
|
4348
4358
|
disposeKey(key);
|
|
4349
4359
|
});
|
|
4350
|
-
return makeCleanup(target, keyEffects, () => cleanupKeys()
|
|
4360
|
+
return makeCleanup(target, keyEffects, () => cleanupKeys(), {
|
|
4361
|
+
source: observedSource,
|
|
4362
|
+
target,
|
|
4363
|
+
apply,
|
|
4364
|
+
depth,
|
|
4365
|
+
parent,
|
|
4366
|
+
});
|
|
4351
4367
|
}
|
|
4352
4368
|
function projectRecord(source, apply) {
|
|
4353
4369
|
const observedSource = reactive(source);
|
|
@@ -4361,6 +4377,8 @@ function projectRecord(source, apply) {
|
|
|
4361
4377
|
Reflect.deleteProperty(target, key);
|
|
4362
4378
|
}
|
|
4363
4379
|
}
|
|
4380
|
+
const parent = getActiveProjection();
|
|
4381
|
+
const depth = parent ? parent.depth + 1 : 0;
|
|
4364
4382
|
const cleanupKeys = effect(function projectRecordEffect({ ascend }) {
|
|
4365
4383
|
const keys = new Set();
|
|
4366
4384
|
for (const key in observedSource)
|
|
@@ -4386,6 +4404,14 @@ function projectRecord(source, apply) {
|
|
|
4386
4404
|
const produced = apply(accessBase, target);
|
|
4387
4405
|
target[sourceKey] = produced;
|
|
4388
4406
|
});
|
|
4407
|
+
setEffectName(stop, `project[${depth}]:${String(key)}`);
|
|
4408
|
+
effectProjectionMetadata.set(stop, {
|
|
4409
|
+
source: observedSource,
|
|
4410
|
+
key,
|
|
4411
|
+
target,
|
|
4412
|
+
depth,
|
|
4413
|
+
parent,
|
|
4414
|
+
});
|
|
4389
4415
|
keyEffects.set(key, stop);
|
|
4390
4416
|
});
|
|
4391
4417
|
}
|
|
@@ -4393,7 +4419,13 @@ function projectRecord(source, apply) {
|
|
|
4393
4419
|
if (!keys.has(key))
|
|
4394
4420
|
disposeKey(key);
|
|
4395
4421
|
});
|
|
4396
|
-
return makeCleanup(target, keyEffects, () => cleanupKeys()
|
|
4422
|
+
return makeCleanup(target, keyEffects, () => cleanupKeys(), {
|
|
4423
|
+
source: observedSource,
|
|
4424
|
+
target,
|
|
4425
|
+
apply,
|
|
4426
|
+
depth,
|
|
4427
|
+
parent,
|
|
4428
|
+
});
|
|
4397
4429
|
}
|
|
4398
4430
|
function projectMap(source, apply) {
|
|
4399
4431
|
const observedSource = reactive(source);
|
|
@@ -4408,6 +4440,8 @@ function projectMap(source, apply) {
|
|
|
4408
4440
|
target.delete(key);
|
|
4409
4441
|
}
|
|
4410
4442
|
}
|
|
4443
|
+
const parent = getActiveProjection();
|
|
4444
|
+
const depth = parent ? parent.depth + 1 : 0;
|
|
4411
4445
|
const cleanupKeys = effect(function projectMapEffect({ ascend }) {
|
|
4412
4446
|
const keys = new Set();
|
|
4413
4447
|
for (const key of observedSource.keys())
|
|
@@ -4432,6 +4466,14 @@ function projectMap(source, apply) {
|
|
|
4432
4466
|
const produced = apply(accessBase, target);
|
|
4433
4467
|
target.set(key, produced);
|
|
4434
4468
|
});
|
|
4469
|
+
setEffectName(stop, `project[${depth}]:${String(key)}`);
|
|
4470
|
+
effectProjectionMetadata.set(stop, {
|
|
4471
|
+
source: observedSource,
|
|
4472
|
+
key,
|
|
4473
|
+
target,
|
|
4474
|
+
depth,
|
|
4475
|
+
parent,
|
|
4476
|
+
});
|
|
4435
4477
|
keyEffects.set(key, stop);
|
|
4436
4478
|
});
|
|
4437
4479
|
}
|
|
@@ -4439,7 +4481,13 @@ function projectMap(source, apply) {
|
|
|
4439
4481
|
if (!keys.has(key))
|
|
4440
4482
|
disposeKey(key);
|
|
4441
4483
|
});
|
|
4442
|
-
return makeCleanup(target, keyEffects, () => cleanupKeys()
|
|
4484
|
+
return makeCleanup(target, keyEffects, () => cleanupKeys(), {
|
|
4485
|
+
source: observedSource,
|
|
4486
|
+
target,
|
|
4487
|
+
apply,
|
|
4488
|
+
depth,
|
|
4489
|
+
parent,
|
|
4490
|
+
});
|
|
4443
4491
|
}
|
|
4444
4492
|
function projectCore(source, apply) {
|
|
4445
4493
|
if (Array.isArray(source))
|
|
@@ -4587,7 +4635,7 @@ class ReactiveWeakMap {
|
|
|
4587
4635
|
Object.defineProperties(this, {
|
|
4588
4636
|
[native$1]: { value: original },
|
|
4589
4637
|
[prototypeForwarding]: { value: original },
|
|
4590
|
-
content: { value: Symbol('
|
|
4638
|
+
content: { value: Symbol('WeakMapContent') },
|
|
4591
4639
|
[Symbol.toStringTag]: { value: 'ReactiveWeakMap' },
|
|
4592
4640
|
});
|
|
4593
4641
|
}
|
|
@@ -4627,7 +4675,7 @@ class ReactiveMap {
|
|
|
4627
4675
|
Object.defineProperties(this, {
|
|
4628
4676
|
[native$1]: { value: original },
|
|
4629
4677
|
[prototypeForwarding]: { value: original },
|
|
4630
|
-
content: { value: Symbol('
|
|
4678
|
+
content: { value: Symbol('MapContent') },
|
|
4631
4679
|
[Symbol.toStringTag]: { value: 'ReactiveMap' },
|
|
4632
4680
|
});
|
|
4633
4681
|
}
|
|
@@ -4722,7 +4770,7 @@ class ReactiveWeakSet {
|
|
|
4722
4770
|
Object.defineProperties(this, {
|
|
4723
4771
|
[native]: { value: original },
|
|
4724
4772
|
[prototypeForwarding]: { value: original },
|
|
4725
|
-
content: { value: Symbol('
|
|
4773
|
+
content: { value: Symbol('WeakSetContent') },
|
|
4726
4774
|
[Symbol.toStringTag]: { value: 'ReactiveWeakSet' },
|
|
4727
4775
|
});
|
|
4728
4776
|
}
|
|
@@ -4757,7 +4805,7 @@ class ReactiveSet {
|
|
|
4757
4805
|
Object.defineProperties(this, {
|
|
4758
4806
|
[native]: { value: original },
|
|
4759
4807
|
[prototypeForwarding]: { value: original },
|
|
4760
|
-
content: { value: Symbol('
|
|
4808
|
+
content: { value: Symbol('SetContent') },
|
|
4761
4809
|
[Symbol.toStringTag]: { value: 'ReactiveSet' },
|
|
4762
4810
|
});
|
|
4763
4811
|
}
|
|
@@ -4853,5 +4901,5 @@ const profileInfo = {
|
|
|
4853
4901
|
nonReactiveObjects,
|
|
4854
4902
|
};
|
|
4855
4903
|
|
|
4856
|
-
export {
|
|
4857
|
-
//# sourceMappingURL=index-
|
|
4904
|
+
export { mixin as A, organize as B, organized as C, profileInfo as D, project as E, reactive as F, reduced as G, register as H, IterableWeakMap as I, registerEffectForDebug as J, registerNativeReactivity as K, registerObjectForDebug as L, root as M, setEffectName as N, setObjectName as O, setZoneEnabled as P, touched as Q, ReactiveBase as R, touched1 as S, trackEffect as T, unreactive as U, untracked as V, unwrap as W, watch as X, IterableWeakSet as a, ReadOnlyError as b, Register as c, addBatchCleanup as d, atomic as e, batch as f, biDi as g, buildReactivityGraph as h, cleanedBy as i, cleanup as j, deepWatch as k, defer as l, derived as m, effect as n, enableDevTools as o, getActivationLog as p, getActiveEffect as q, getActiveProjection as r, getState as s, immutables as t, isDevtoolsEnabled as u, isNonReactive as v, isReactive as w, isZoneEnabled as x, mapped as y, memoize as z };
|
|
4905
|
+
//# sourceMappingURL=index-DiP0RXoZ.esm.js.map
|