mutts 1.0.5 → 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 +1 -0
- 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-Cvxdw6Ax.js → index-CDCOjzTy.js} +396 -500
- package/dist/chunks/index-CDCOjzTy.js.map +1 -0
- package/dist/chunks/{index-qiWwozOc.esm.js → index-DiP0RXoZ.esm.js} +301 -403
- 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 +48 -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 +25 -0
- package/dist/reactive.esm.js +3 -3
- package/dist/reactive.js +4 -4
- 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/debugging.md +158 -0
- package/docs/reactive.md +6 -5
- package/package.json +16 -66
- package/src/decorator.ts +11 -9
- package/src/destroyable.ts +3 -3
- package/src/index.ts +46 -0
- package/src/reactive/change.ts +1 -1
- 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 +44 -16
- package/src/reactive/index.ts +1 -1
- package/src/reactive/interface.ts +9 -8
- package/src/reactive/memoize.ts +77 -31
- package/src/reactive/proxy.ts +4 -4
- package/src/reactive/registry.ts +67 -0
- package/src/reactive/tracking.ts +12 -41
- package/src/reactive/types.ts +37 -0
- package/src/std-decorators.ts +9 -9
- 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-Cvxdw6Ax.js.map +0 -1
- package/dist/chunks/index-qiWwozOc.esm.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var decorator = require('./decorator-
|
|
3
|
+
var decorator = require('./decorator-BQ2eBTCj.js');
|
|
4
4
|
var indexable = require('../indexable.js');
|
|
5
5
|
var _tslib = require('./_tslib-BgjropY9.js');
|
|
6
6
|
|
|
@@ -334,323 +334,6 @@ function mixin(mixinFunction, unwrapFunction) {
|
|
|
334
334
|
});
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
-
// biome-ignore-all lint/suspicious/noConfusingVoidType: Type 'void' is not assignable to type 'ScopedCallback | undefined'.
|
|
338
|
-
// Argument of type '() => void' is not assignable to parameter of type '(dep: DependencyFunction) => ScopedCallback | undefined'.
|
|
339
|
-
// Track native reactivity
|
|
340
|
-
const nativeReactive = Symbol('native-reactive');
|
|
341
|
-
/**
|
|
342
|
-
* Symbol to mark individual objects as non-reactive
|
|
343
|
-
*/
|
|
344
|
-
const nonReactiveMark = Symbol('non-reactive');
|
|
345
|
-
/**
|
|
346
|
-
* Symbol to mark class properties as non-reactive
|
|
347
|
-
*/
|
|
348
|
-
const unreactiveProperties = Symbol('unreactive-properties');
|
|
349
|
-
/**
|
|
350
|
-
* Symbol for prototype forwarding in reactive objects
|
|
351
|
-
*/
|
|
352
|
-
const prototypeForwarding = Symbol('prototype-forwarding');
|
|
353
|
-
/**
|
|
354
|
-
* Symbol representing all properties in reactive tracking
|
|
355
|
-
*/
|
|
356
|
-
const allProps = Symbol('all-props');
|
|
357
|
-
/**
|
|
358
|
-
* Symbol for accessing projection information on reactive objects
|
|
359
|
-
*/
|
|
360
|
-
const projectionInfo = Symbol('projection-info');
|
|
361
|
-
// Symbol to mark functions with their root function
|
|
362
|
-
const rootFunction = Symbol('root-function');
|
|
363
|
-
/**
|
|
364
|
-
* Structured error codes for machine-readable diagnosis
|
|
365
|
-
*/
|
|
366
|
-
var ReactiveErrorCode;
|
|
367
|
-
(function (ReactiveErrorCode) {
|
|
368
|
-
ReactiveErrorCode["CycleDetected"] = "CYCLE_DETECTED";
|
|
369
|
-
ReactiveErrorCode["MaxDepthExceeded"] = "MAX_DEPTH_EXCEEDED";
|
|
370
|
-
ReactiveErrorCode["MaxReactionExceeded"] = "MAX_REACTION_EXCEEDED";
|
|
371
|
-
ReactiveErrorCode["WriteInComputed"] = "WRITE_IN_COMPUTED";
|
|
372
|
-
ReactiveErrorCode["TrackingError"] = "TRACKING_ERROR";
|
|
373
|
-
})(ReactiveErrorCode || (ReactiveErrorCode = {}));
|
|
374
|
-
/**
|
|
375
|
-
* Error class for reactive system errors
|
|
376
|
-
*/
|
|
377
|
-
class ReactiveError extends Error {
|
|
378
|
-
constructor(message, debugInfo) {
|
|
379
|
-
super(message);
|
|
380
|
-
this.debugInfo = debugInfo;
|
|
381
|
-
this.name = 'ReactiveError';
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
// biome-ignore-start lint/correctness/noUnusedFunctionParameters: Interface declaration with empty defaults
|
|
385
|
-
/**
|
|
386
|
-
* Global options for the reactive system
|
|
387
|
-
*/
|
|
388
|
-
const options = {
|
|
389
|
-
/**
|
|
390
|
-
* Debug purpose: called when an effect is entered
|
|
391
|
-
* @param effect - The effect that is entered
|
|
392
|
-
*/
|
|
393
|
-
enter: (_effect) => { },
|
|
394
|
-
/**
|
|
395
|
-
* Debug purpose: called when an effect is left
|
|
396
|
-
* @param effect - The effect that is left
|
|
397
|
-
*/
|
|
398
|
-
leave: (_effect) => { },
|
|
399
|
-
/**
|
|
400
|
-
* Debug purpose: called when an effect is chained
|
|
401
|
-
* @param target - The effect that is being triggered
|
|
402
|
-
* @param caller - The effect that is calling the target
|
|
403
|
-
*/
|
|
404
|
-
chain: (_targets, _caller) => { },
|
|
405
|
-
/**
|
|
406
|
-
* Debug purpose: called when an effect chain is started
|
|
407
|
-
* @param target - The effect that is being triggered
|
|
408
|
-
*/
|
|
409
|
-
beginChain: (_targets) => { },
|
|
410
|
-
/**
|
|
411
|
-
* Debug purpose: called when an effect chain is ended
|
|
412
|
-
*/
|
|
413
|
-
endChain: () => { },
|
|
414
|
-
garbageCollected: (_fn) => { },
|
|
415
|
-
/**
|
|
416
|
-
* Debug purpose: called when an object is touched
|
|
417
|
-
* @param obj - The object that is touched
|
|
418
|
-
* @param evolution - The type of change
|
|
419
|
-
* @param props - The properties that changed
|
|
420
|
-
* @param deps - The dependencies that changed
|
|
421
|
-
*/
|
|
422
|
-
touched: (_obj, _evolution, _props, _deps) => { },
|
|
423
|
-
/**
|
|
424
|
-
* Debug purpose: called when an effect is skipped because it's already running
|
|
425
|
-
* @param effect - The effect that is already running
|
|
426
|
-
* @param runningChain - The array of effects from the detected one to the currently running one
|
|
427
|
-
*/
|
|
428
|
-
skipRunningEffect: (_effect, _runningChain) => { },
|
|
429
|
-
/**
|
|
430
|
-
* Debug purpose: maximum effect chain (like call stack max depth)
|
|
431
|
-
* Used to prevent infinite loops
|
|
432
|
-
* @default 100
|
|
433
|
-
*/
|
|
434
|
-
maxEffectChain: 100,
|
|
435
|
-
/**
|
|
436
|
-
* Maximum number of times an effect can be triggered by the same cause in a single batch
|
|
437
|
-
* Used to detect aggressive re-computation or infinite loops
|
|
438
|
-
* @default 10
|
|
439
|
-
*/
|
|
440
|
-
maxTriggerPerBatch: 10,
|
|
441
|
-
/**
|
|
442
|
-
* Debug purpose: maximum effect reaction (like call stack max depth)
|
|
443
|
-
* Used to prevent infinite loops
|
|
444
|
-
* @default 'throw'
|
|
445
|
-
*/
|
|
446
|
-
maxEffectReaction: 'throw',
|
|
447
|
-
/**
|
|
448
|
-
* How to handle cycles detected in effect batches
|
|
449
|
-
* - 'throw': Throw an error with cycle information (default, recommended for development)
|
|
450
|
-
* - 'warn': Log a warning and break the cycle by executing one effect
|
|
451
|
-
* - 'break': Silently break the cycle by executing one effect (recommended for production)
|
|
452
|
-
* - 'strict': Prevent cycle creation by checking graph before execution (throws error)
|
|
453
|
-
* @default 'throw'
|
|
454
|
-
*/
|
|
455
|
-
cycleHandling: 'throw',
|
|
456
|
-
/**
|
|
457
|
-
* Maximum depth for deep watching traversal
|
|
458
|
-
* Used to prevent infinite recursion in circular references
|
|
459
|
-
* @default 100
|
|
460
|
-
*/
|
|
461
|
-
maxDeepWatchDepth: 100,
|
|
462
|
-
/**
|
|
463
|
-
* Only react on instance members modification (not inherited properties)
|
|
464
|
-
* For instance, do not track class methods
|
|
465
|
-
* @default true
|
|
466
|
-
*/
|
|
467
|
-
instanceMembers: true,
|
|
468
|
-
/**
|
|
469
|
-
* Ignore accessors (getters and setters) and only track direct properties
|
|
470
|
-
* @default true
|
|
471
|
-
*/
|
|
472
|
-
ignoreAccessors: true,
|
|
473
|
-
/**
|
|
474
|
-
* Enable recursive touching when objects with the same prototype are replaced
|
|
475
|
-
* When enabled, replacing an object with another of the same prototype triggers
|
|
476
|
-
* recursive diffing instead of notifying parent effects
|
|
477
|
-
* @default true
|
|
478
|
-
*/
|
|
479
|
-
recursiveTouching: true,
|
|
480
|
-
/**
|
|
481
|
-
* Default async execution mode for effects that return Promises
|
|
482
|
-
* - 'cancel': Cancel previous async execution when dependencies change (default, enables async zone)
|
|
483
|
-
* - 'queue': Queue next execution to run after current completes (enables async zone)
|
|
484
|
-
* - 'ignore': Ignore new executions while async work is running (enables async zone)
|
|
485
|
-
* - false: Disable async zone and async mode handling (effects run concurrently)
|
|
486
|
-
*
|
|
487
|
-
* **When truthy:** Enables async zone (Promise.prototype wrapping) for automatic context
|
|
488
|
-
* preservation in Promise callbacks. Warning: This modifies Promise.prototype globally.
|
|
489
|
-
* Only enable if no other library modifies Promise.prototype.
|
|
490
|
-
*
|
|
491
|
-
* **When false:** Async zone is disabled. Use `tracked()` manually in Promise callbacks.
|
|
492
|
-
*
|
|
493
|
-
* Can be overridden per-effect via EffectOptions
|
|
494
|
-
* @default 'cancel'
|
|
495
|
-
*/
|
|
496
|
-
asyncMode: 'cancel',
|
|
497
|
-
// biome-ignore lint/suspicious/noConsole: This is the whole point here
|
|
498
|
-
warn: (...args) => console.warn(...args),
|
|
499
|
-
/**
|
|
500
|
-
* Configuration for the introspection system
|
|
501
|
-
*/
|
|
502
|
-
introspection: {
|
|
503
|
-
/**
|
|
504
|
-
* Whether to keep a history of mutations for debugging
|
|
505
|
-
* @default false
|
|
506
|
-
*/
|
|
507
|
-
enableHistory: false,
|
|
508
|
-
/**
|
|
509
|
-
* Number of mutations to keep in history
|
|
510
|
-
* @default 50
|
|
511
|
-
*/
|
|
512
|
-
historySize: 50,
|
|
513
|
-
},
|
|
514
|
-
/**
|
|
515
|
-
* Configuration for zone hooks - control which async APIs are hooked
|
|
516
|
-
* Each option controls whether the corresponding async API is wrapped to preserve effect context
|
|
517
|
-
* Only applies when asyncMode is enabled (truthy)
|
|
518
|
-
*/
|
|
519
|
-
zones: {
|
|
520
|
-
/**
|
|
521
|
-
* Hook setTimeout to preserve effect context
|
|
522
|
-
* @default true
|
|
523
|
-
*/
|
|
524
|
-
setTimeout: true,
|
|
525
|
-
/**
|
|
526
|
-
* Hook setInterval to preserve effect context
|
|
527
|
-
* @default true
|
|
528
|
-
*/
|
|
529
|
-
setInterval: true,
|
|
530
|
-
/**
|
|
531
|
-
* Hook requestAnimationFrame (runs in untracked context when hooked)
|
|
532
|
-
* @default true
|
|
533
|
-
*/
|
|
534
|
-
requestAnimationFrame: true,
|
|
535
|
-
/**
|
|
536
|
-
* Hook queueMicrotask to preserve effect context
|
|
537
|
-
* @default true
|
|
538
|
-
*/
|
|
539
|
-
queueMicrotask: true,
|
|
540
|
-
},
|
|
541
|
-
};
|
|
542
|
-
|
|
543
|
-
/**
|
|
544
|
-
* Effect context stack for nested tracking (front = active, next = parent)
|
|
545
|
-
*/
|
|
546
|
-
const stack = [];
|
|
547
|
-
function captureEffectStack() {
|
|
548
|
-
return stack.slice();
|
|
549
|
-
}
|
|
550
|
-
function isRunning(effect) {
|
|
551
|
-
const rootEffect = getRoot(effect);
|
|
552
|
-
// Check if the effect is directly in the stack
|
|
553
|
-
const rootIndex = stack.indexOf(rootEffect);
|
|
554
|
-
if (rootIndex !== -1) {
|
|
555
|
-
return stack.slice(0, rootIndex + 1).reverse();
|
|
556
|
-
}
|
|
557
|
-
// Check if any effect in the stack is a descendant of this effect
|
|
558
|
-
// (i.e., walk up the parent chain from each stack effect to see if we reach this effect)
|
|
559
|
-
for (let i = 0; i < stack.length; i++) {
|
|
560
|
-
const stackEffect = stack[i];
|
|
561
|
-
let current = stackEffect;
|
|
562
|
-
const visited = new WeakSet();
|
|
563
|
-
const ancestorChain = [];
|
|
564
|
-
// TODO: That's perhaps a lot of computations for an `assert`
|
|
565
|
-
// Walk up the parent chain to find if this effect is an ancestor
|
|
566
|
-
while (current && !visited.has(current)) {
|
|
567
|
-
visited.add(current);
|
|
568
|
-
const currentRoot = getRoot(current);
|
|
569
|
-
ancestorChain.push(currentRoot);
|
|
570
|
-
if (currentRoot === rootEffect) {
|
|
571
|
-
// Found a descendant - build the full chain from ancestor to active
|
|
572
|
-
// The ancestorChain contains [descendant, parent, ..., ancestor] (walking up)
|
|
573
|
-
// We need [ancestor (effect), ..., parent, descendant, ...stack from descendant to active]
|
|
574
|
-
const chainFromAncestor = ancestorChain.reverse(); // [ancestor, ..., descendant]
|
|
575
|
-
// Prepend the actual effect we're checking (in case current is a wrapper)
|
|
576
|
-
if (chainFromAncestor[0] !== rootEffect) {
|
|
577
|
-
chainFromAncestor.unshift(rootEffect);
|
|
578
|
-
}
|
|
579
|
-
// Append the rest of the stack from the descendant to the active effect
|
|
580
|
-
const stackFromDescendant = stack.slice(0, i + 1).reverse(); // [descendant, ..., active]
|
|
581
|
-
// Remove duplicate descendant (it's both at end of chainFromAncestor and start of stackFromDescendant)
|
|
582
|
-
if (chainFromAncestor.length > 0 && stackFromDescendant.length > 0) {
|
|
583
|
-
stackFromDescendant.shift(); // Remove duplicate descendant
|
|
584
|
-
}
|
|
585
|
-
return [...chainFromAncestor, ...stackFromDescendant];
|
|
586
|
-
}
|
|
587
|
-
current = effectParent.get(current);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
return false;
|
|
591
|
-
}
|
|
592
|
-
function withEffectStack(snapshot, fn) {
|
|
593
|
-
const previousStack = stack.slice();
|
|
594
|
-
assignStack(snapshot);
|
|
595
|
-
try {
|
|
596
|
-
return fn();
|
|
597
|
-
}
|
|
598
|
-
finally {
|
|
599
|
-
assignStack(previousStack);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
function getActiveEffect() {
|
|
603
|
-
return stack[0];
|
|
604
|
-
}
|
|
605
|
-
/**
|
|
606
|
-
* Executes a function with a specific effect context
|
|
607
|
-
* @param effect - The effect to use as context
|
|
608
|
-
* @param fn - The function to execute
|
|
609
|
-
* @param keepParent - Whether to keep the parent effect context
|
|
610
|
-
* @returns The result of the function
|
|
611
|
-
*/
|
|
612
|
-
function withEffect(effect, fn) {
|
|
613
|
-
// console.log('[Mutts] withEffect', effect ? 'Active' : 'NULL');
|
|
614
|
-
if (getRoot(effect) === getRoot(getActiveEffect()))
|
|
615
|
-
return fn();
|
|
616
|
-
stack.unshift(effect);
|
|
617
|
-
try {
|
|
618
|
-
return fn();
|
|
619
|
-
}
|
|
620
|
-
finally {
|
|
621
|
-
const recoveredEffect = stack.shift();
|
|
622
|
-
if (recoveredEffect !== effect)
|
|
623
|
-
throw new ReactiveError('[reactive] Effect stack mismatch');
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
function assignStack(values) {
|
|
627
|
-
stack.length = 0;
|
|
628
|
-
stack.push(...values);
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
const objectToProxy = new WeakMap();
|
|
632
|
-
const proxyToObject = new WeakMap();
|
|
633
|
-
function storeProxyRelationship(target, proxy) {
|
|
634
|
-
objectToProxy.set(target, proxy);
|
|
635
|
-
proxyToObject.set(proxy, target);
|
|
636
|
-
}
|
|
637
|
-
function getExistingProxy(target) {
|
|
638
|
-
return objectToProxy.get(target);
|
|
639
|
-
}
|
|
640
|
-
function trackProxyObject(proxy, target) {
|
|
641
|
-
proxyToObject.set(proxy, target);
|
|
642
|
-
}
|
|
643
|
-
function unwrap(obj) {
|
|
644
|
-
let current = obj;
|
|
645
|
-
while (current && typeof current === 'object' && current !== null && proxyToObject.has(current)) {
|
|
646
|
-
current = proxyToObject.get(current);
|
|
647
|
-
}
|
|
648
|
-
return current;
|
|
649
|
-
}
|
|
650
|
-
function isReactive(obj) {
|
|
651
|
-
return proxyToObject.has(obj);
|
|
652
|
-
}
|
|
653
|
-
|
|
654
337
|
// Track which effects are watching which reactive objects for cleanup
|
|
655
338
|
const effectToReactiveObjects = new WeakMap();
|
|
656
339
|
// Track effects per reactive object and property
|
|
@@ -659,15 +342,31 @@ const watchers = new WeakMap();
|
|
|
659
342
|
const effectChildren = new WeakMap();
|
|
660
343
|
// Track parent effect relationships for hierarchy traversal (used in deep touch filtering)
|
|
661
344
|
const effectParent = new WeakMap();
|
|
345
|
+
// Track reverse mapping to ensure unicity: One Root -> One Function
|
|
346
|
+
const reverseRoots = new WeakMap();
|
|
662
347
|
/**
|
|
663
348
|
* Marks a function with its root function for effect tracking
|
|
349
|
+
* Enforces strict unicity: A root function can only identify ONE function.
|
|
664
350
|
* @param fn - The function to mark
|
|
665
351
|
* @param root - The root function
|
|
666
352
|
* @returns The marked function
|
|
667
353
|
*/
|
|
668
354
|
function markWithRoot(fn, root) {
|
|
355
|
+
// Check for collision
|
|
356
|
+
const existingRef = reverseRoots.get(root);
|
|
357
|
+
const existing = existingRef?.deref();
|
|
358
|
+
if (existing && existing !== fn) {
|
|
359
|
+
const rootName = root.name || 'anonymous';
|
|
360
|
+
const existingName = existing.name || 'anonymous';
|
|
361
|
+
const fnName = fn.name || 'anonymous';
|
|
362
|
+
throw new Error(`[reactive] Abusive Shared Root detected: Root '${rootName}' is already identifying function '${existingName}'. ` +
|
|
363
|
+
`Cannot reuse it for '${fnName}'. Shared roots cause lost updates and broken identity logic.`);
|
|
364
|
+
}
|
|
365
|
+
// Always update the map so subsequent checks find this one
|
|
366
|
+
// (Last writer wins for the check)
|
|
367
|
+
reverseRoots.set(root, new WeakRef(fn));
|
|
669
368
|
// Mark fn with the new root
|
|
670
|
-
return Object.defineProperty(fn, rootFunction, {
|
|
369
|
+
return Object.defineProperty(fn, decorator.rootFunction, {
|
|
671
370
|
value: getRoot(root),
|
|
672
371
|
writable: false,
|
|
673
372
|
});
|
|
@@ -678,64 +377,15 @@ function markWithRoot(fn, root) {
|
|
|
678
377
|
* @returns The root function
|
|
679
378
|
*/
|
|
680
379
|
function getRoot(fn) {
|
|
681
|
-
|
|
380
|
+
while (fn && decorator.rootFunction in fn)
|
|
381
|
+
fn = fn[decorator.rootFunction];
|
|
382
|
+
return fn;
|
|
682
383
|
}
|
|
683
384
|
// Flag to disable dependency tracking for the current active effect (not globally)
|
|
684
385
|
const trackingDisabledEffects = new WeakSet();
|
|
685
386
|
let globalTrackingDisabled = false;
|
|
686
|
-
function
|
|
687
|
-
|
|
688
|
-
if (!active)
|
|
689
|
-
return globalTrackingDisabled;
|
|
690
|
-
return trackingDisabledEffects.has(getRoot(active));
|
|
691
|
-
}
|
|
692
|
-
function setTrackingDisabled(value) {
|
|
693
|
-
const active = getActiveEffect();
|
|
694
|
-
if (!active) {
|
|
695
|
-
globalTrackingDisabled = value;
|
|
696
|
-
return;
|
|
697
|
-
}
|
|
698
|
-
const root = getRoot(active);
|
|
699
|
-
if (value)
|
|
700
|
-
trackingDisabledEffects.add(root);
|
|
701
|
-
else
|
|
702
|
-
trackingDisabledEffects.delete(root);
|
|
703
|
-
}
|
|
704
|
-
/**
|
|
705
|
-
* Marks a property as a dependency of the current effect
|
|
706
|
-
* @param obj - The object containing the property
|
|
707
|
-
* @param prop - The property name (defaults to allProps)
|
|
708
|
-
*/
|
|
709
|
-
function dependant(obj, prop = allProps) {
|
|
710
|
-
obj = unwrap(obj);
|
|
711
|
-
const currentActiveEffect = getActiveEffect();
|
|
712
|
-
// Early return if no active effect, tracking disabled, or invalid prop
|
|
713
|
-
if (!currentActiveEffect ||
|
|
714
|
-
getTrackingDisabled() ||
|
|
715
|
-
(typeof prop === 'symbol' && prop !== allProps))
|
|
716
|
-
return;
|
|
717
|
-
registerDependency(obj, prop, currentActiveEffect);
|
|
718
|
-
}
|
|
719
|
-
function registerDependency(obj, prop, currentActiveEffect) {
|
|
720
|
-
let objectWatchers = watchers.get(obj);
|
|
721
|
-
if (!objectWatchers) {
|
|
722
|
-
objectWatchers = new Map();
|
|
723
|
-
watchers.set(obj, objectWatchers);
|
|
724
|
-
}
|
|
725
|
-
let deps = objectWatchers.get(prop);
|
|
726
|
-
if (!deps) {
|
|
727
|
-
deps = new Set();
|
|
728
|
-
objectWatchers.set(prop, deps);
|
|
729
|
-
}
|
|
730
|
-
deps.add(currentActiveEffect);
|
|
731
|
-
// Track which reactive objects this effect is watching
|
|
732
|
-
const effectObjects = effectToReactiveObjects.get(currentActiveEffect);
|
|
733
|
-
if (effectObjects) {
|
|
734
|
-
effectObjects.add(obj);
|
|
735
|
-
}
|
|
736
|
-
else {
|
|
737
|
-
effectToReactiveObjects.set(currentActiveEffect, new Set([obj]));
|
|
738
|
-
}
|
|
387
|
+
function setGlobalTrackingDisabled(value) {
|
|
388
|
+
globalTrackingDisabled = value;
|
|
739
389
|
}
|
|
740
390
|
|
|
741
391
|
/**
|
|
@@ -776,7 +426,7 @@ function ensureObjectName(obj) {
|
|
|
776
426
|
}
|
|
777
427
|
function describeProp(obj, prop) {
|
|
778
428
|
const objectName = ensureObjectName(obj);
|
|
779
|
-
if (prop === allProps)
|
|
429
|
+
if (prop === decorator.allProps)
|
|
780
430
|
return `${objectName}.*`;
|
|
781
431
|
if (typeof prop === 'symbol')
|
|
782
432
|
return `${objectName}.${prop.description ?? prop.toString()}`;
|
|
@@ -873,7 +523,7 @@ function registerObjectForDebug(obj) {
|
|
|
873
523
|
* @param evolution - The type of change (set/add/del/bunch)
|
|
874
524
|
*/
|
|
875
525
|
function recordTriggerLink(source, target, obj, prop, evolution) {
|
|
876
|
-
if (options.introspection.enableHistory) {
|
|
526
|
+
if (decorator.options.introspection.enableHistory) {
|
|
877
527
|
addToMutationHistory(source, target, obj, prop, evolution);
|
|
878
528
|
}
|
|
879
529
|
if (!devtoolsEnabled)
|
|
@@ -1085,11 +735,176 @@ function addToMutationHistory(source, target, obj, prop, evolution) {
|
|
|
1085
735
|
type: evolution.type,
|
|
1086
736
|
};
|
|
1087
737
|
mutationHistory.push(record);
|
|
1088
|
-
if (mutationHistory.length > options.introspection.historySize) {
|
|
738
|
+
if (mutationHistory.length > decorator.options.introspection.historySize) {
|
|
1089
739
|
mutationHistory.shift();
|
|
1090
740
|
}
|
|
1091
741
|
}
|
|
1092
742
|
|
|
743
|
+
/**
|
|
744
|
+
* Effect context stack for nested tracking (front = active, next = parent)
|
|
745
|
+
*/
|
|
746
|
+
const stack = [];
|
|
747
|
+
function captureEffectStack() {
|
|
748
|
+
return stack.slice();
|
|
749
|
+
}
|
|
750
|
+
function isRunning(effect) {
|
|
751
|
+
const rootEffect = getRoot(effect);
|
|
752
|
+
// Check if the effect is directly in the stack
|
|
753
|
+
const rootIndex = stack.indexOf(rootEffect);
|
|
754
|
+
if (rootIndex !== -1) {
|
|
755
|
+
return stack.slice(0, rootIndex + 1).reverse();
|
|
756
|
+
}
|
|
757
|
+
// Check if any effect in the stack is a descendant of this effect
|
|
758
|
+
// (i.e., walk up the parent chain from each stack effect to see if we reach this effect)
|
|
759
|
+
for (let i = 0; i < stack.length; i++) {
|
|
760
|
+
const stackEffect = stack[i];
|
|
761
|
+
let current = stackEffect;
|
|
762
|
+
const visited = new WeakSet();
|
|
763
|
+
const ancestorChain = [];
|
|
764
|
+
// TODO: That's perhaps a lot of computations for an `assert`
|
|
765
|
+
// Walk up the parent chain to find if this effect is an ancestor
|
|
766
|
+
while (current && !visited.has(current)) {
|
|
767
|
+
visited.add(current);
|
|
768
|
+
const currentRoot = getRoot(current);
|
|
769
|
+
ancestorChain.push(currentRoot);
|
|
770
|
+
if (currentRoot === rootEffect) {
|
|
771
|
+
// Found a descendant - build the full chain from ancestor to active
|
|
772
|
+
// The ancestorChain contains [descendant, parent, ..., ancestor] (walking up)
|
|
773
|
+
// We need [ancestor (effect), ..., parent, descendant, ...stack from descendant to active]
|
|
774
|
+
const chainFromAncestor = ancestorChain.reverse(); // [ancestor, ..., descendant]
|
|
775
|
+
// Prepend the actual effect we're checking (in case current is a wrapper)
|
|
776
|
+
if (chainFromAncestor[0] !== rootEffect) {
|
|
777
|
+
chainFromAncestor.unshift(rootEffect);
|
|
778
|
+
}
|
|
779
|
+
// Append the rest of the stack from the descendant to the active effect
|
|
780
|
+
const stackFromDescendant = stack.slice(0, i + 1).reverse(); // [descendant, ..., active]
|
|
781
|
+
// Remove duplicate descendant (it's both at end of chainFromAncestor and start of stackFromDescendant)
|
|
782
|
+
if (chainFromAncestor.length > 0 && stackFromDescendant.length > 0) {
|
|
783
|
+
stackFromDescendant.shift(); // Remove duplicate descendant
|
|
784
|
+
}
|
|
785
|
+
return [...chainFromAncestor, ...stackFromDescendant];
|
|
786
|
+
}
|
|
787
|
+
current = effectParent.get(current);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
return false;
|
|
791
|
+
}
|
|
792
|
+
function withEffectStack(snapshot, fn) {
|
|
793
|
+
const previousStack = stack.slice();
|
|
794
|
+
assignStack(snapshot);
|
|
795
|
+
try {
|
|
796
|
+
return fn();
|
|
797
|
+
}
|
|
798
|
+
finally {
|
|
799
|
+
assignStack(previousStack);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
function getActiveEffect() {
|
|
803
|
+
return stack[0];
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Executes a function with a specific effect context
|
|
807
|
+
* @param effect - The effect to use as context
|
|
808
|
+
* @param fn - The function to execute
|
|
809
|
+
* @param keepParent - Whether to keep the parent effect context
|
|
810
|
+
* @returns The result of the function
|
|
811
|
+
*/
|
|
812
|
+
function withEffect(effect, fn) {
|
|
813
|
+
if (getRoot(effect) === getRoot(getActiveEffect()))
|
|
814
|
+
return fn();
|
|
815
|
+
stack.unshift(effect);
|
|
816
|
+
try {
|
|
817
|
+
return fn();
|
|
818
|
+
}
|
|
819
|
+
finally {
|
|
820
|
+
const recoveredEffect = stack.shift();
|
|
821
|
+
if (recoveredEffect !== effect)
|
|
822
|
+
throw new decorator.ReactiveError('[reactive] Effect stack mismatch');
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
function assignStack(values) {
|
|
826
|
+
stack.length = 0;
|
|
827
|
+
stack.push(...values);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
const objectToProxy = new WeakMap();
|
|
831
|
+
const proxyToObject = new WeakMap();
|
|
832
|
+
function storeProxyRelationship(target, proxy) {
|
|
833
|
+
objectToProxy.set(target, proxy);
|
|
834
|
+
proxyToObject.set(proxy, target);
|
|
835
|
+
}
|
|
836
|
+
function getExistingProxy(target) {
|
|
837
|
+
return objectToProxy.get(target);
|
|
838
|
+
}
|
|
839
|
+
function trackProxyObject(proxy, target) {
|
|
840
|
+
proxyToObject.set(proxy, target);
|
|
841
|
+
}
|
|
842
|
+
function unwrap(obj) {
|
|
843
|
+
let current = obj;
|
|
844
|
+
while (current && typeof current === 'object' && current !== null && proxyToObject.has(current)) {
|
|
845
|
+
current = proxyToObject.get(current);
|
|
846
|
+
}
|
|
847
|
+
return current;
|
|
848
|
+
}
|
|
849
|
+
function isReactive(obj) {
|
|
850
|
+
return proxyToObject.has(obj);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
function getTrackingDisabled() {
|
|
854
|
+
const active = getActiveEffect();
|
|
855
|
+
if (!active)
|
|
856
|
+
return globalTrackingDisabled;
|
|
857
|
+
return trackingDisabledEffects.has(getRoot(active));
|
|
858
|
+
}
|
|
859
|
+
function setTrackingDisabled(value) {
|
|
860
|
+
const active = getActiveEffect();
|
|
861
|
+
if (!active) {
|
|
862
|
+
setGlobalTrackingDisabled(value);
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
const root = getRoot(active);
|
|
866
|
+
if (value)
|
|
867
|
+
trackingDisabledEffects.add(root);
|
|
868
|
+
else
|
|
869
|
+
trackingDisabledEffects.delete(root);
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Marks a property as a dependency of the current effect
|
|
873
|
+
* @param obj - The object containing the property
|
|
874
|
+
* @param prop - The property name (defaults to allProps)
|
|
875
|
+
*/
|
|
876
|
+
function dependant(obj, prop = decorator.allProps) {
|
|
877
|
+
obj = unwrap(obj);
|
|
878
|
+
const currentActiveEffect = getActiveEffect();
|
|
879
|
+
// Early return if no active effect, tracking disabled, or invalid prop
|
|
880
|
+
if (!currentActiveEffect ||
|
|
881
|
+
getTrackingDisabled() ||
|
|
882
|
+
(typeof prop === 'symbol' && prop !== decorator.allProps))
|
|
883
|
+
return;
|
|
884
|
+
registerDependency(obj, prop, currentActiveEffect);
|
|
885
|
+
}
|
|
886
|
+
function registerDependency(obj, prop, currentActiveEffect) {
|
|
887
|
+
let objectWatchers = watchers.get(obj);
|
|
888
|
+
if (!objectWatchers) {
|
|
889
|
+
objectWatchers = new Map();
|
|
890
|
+
watchers.set(obj, objectWatchers);
|
|
891
|
+
}
|
|
892
|
+
let deps = objectWatchers.get(prop);
|
|
893
|
+
if (!deps) {
|
|
894
|
+
deps = new Set();
|
|
895
|
+
objectWatchers.set(prop, deps);
|
|
896
|
+
}
|
|
897
|
+
deps.add(currentActiveEffect);
|
|
898
|
+
// Track which reactive objects this effect is watching
|
|
899
|
+
const effectObjects = effectToReactiveObjects.get(currentActiveEffect);
|
|
900
|
+
if (effectObjects) {
|
|
901
|
+
effectObjects.add(obj);
|
|
902
|
+
}
|
|
903
|
+
else {
|
|
904
|
+
effectToReactiveObjects.set(currentActiveEffect, new Set([obj]));
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
1093
908
|
/**
|
|
1094
909
|
* Zone-like async context preservation for reactive effects
|
|
1095
910
|
*
|
|
@@ -1130,7 +945,7 @@ let batchFn;
|
|
|
1130
945
|
function ensureZoneHooked(batch) {
|
|
1131
946
|
if (batch)
|
|
1132
947
|
batchFn = batch;
|
|
1133
|
-
if (zoneHooked || !options.asyncMode)
|
|
948
|
+
if (zoneHooked || !decorator.options.asyncMode)
|
|
1134
949
|
return;
|
|
1135
950
|
hookZone();
|
|
1136
951
|
zoneHooked = true;
|
|
@@ -1154,7 +969,7 @@ function hookZone() {
|
|
|
1154
969
|
};
|
|
1155
970
|
// Hook setTimeout - preserve original function properties for Node.js compatibility
|
|
1156
971
|
const wrappedSetTimeout = ((callback, delay, ...args) => {
|
|
1157
|
-
const capturedStack = options.zones.setTimeout ? captureEffectStack() : undefined;
|
|
972
|
+
const capturedStack = decorator.options.zones.setTimeout ? captureEffectStack() : undefined;
|
|
1158
973
|
return originalSetTimeout.apply(globalThis, [
|
|
1159
974
|
wrapCallback(callback, capturedStack),
|
|
1160
975
|
delay,
|
|
@@ -1165,7 +980,7 @@ function hookZone() {
|
|
|
1165
980
|
globalThis.setTimeout = wrappedSetTimeout;
|
|
1166
981
|
// Hook setInterval - preserve original function properties for Node.js compatibility
|
|
1167
982
|
const wrappedSetInterval = ((callback, delay, ...args) => {
|
|
1168
|
-
const capturedStack = options.zones.setInterval ? captureEffectStack() : undefined;
|
|
983
|
+
const capturedStack = decorator.options.zones.setInterval ? captureEffectStack() : undefined;
|
|
1169
984
|
return originalSetInterval.apply(globalThis, [
|
|
1170
985
|
wrapCallback(callback, capturedStack),
|
|
1171
986
|
delay,
|
|
@@ -1177,14 +992,14 @@ function hookZone() {
|
|
|
1177
992
|
// Hook requestAnimationFrame if available
|
|
1178
993
|
if (originalRequestAnimationFrame) {
|
|
1179
994
|
globalThis.requestAnimationFrame = ((callback) => {
|
|
1180
|
-
const capturedStack = options.zones.requestAnimationFrame ? captureEffectStack() : undefined;
|
|
995
|
+
const capturedStack = decorator.options.zones.requestAnimationFrame ? captureEffectStack() : undefined;
|
|
1181
996
|
return originalRequestAnimationFrame.call(globalThis, wrapCallback(callback, capturedStack));
|
|
1182
997
|
});
|
|
1183
998
|
}
|
|
1184
999
|
// Hook queueMicrotask if available
|
|
1185
1000
|
if (originalQueueMicrotask) {
|
|
1186
1001
|
globalThis.queueMicrotask = ((callback) => {
|
|
1187
|
-
const capturedStack = options.zones.queueMicrotask ? captureEffectStack() : undefined;
|
|
1002
|
+
const capturedStack = decorator.options.zones.queueMicrotask ? captureEffectStack() : undefined;
|
|
1188
1003
|
originalQueueMicrotask.call(globalThis, wrapCallback(callback, capturedStack));
|
|
1189
1004
|
});
|
|
1190
1005
|
}
|
|
@@ -1301,17 +1116,17 @@ function recordActivation(effect, obj, evolution, prop) {
|
|
|
1301
1116
|
prop,
|
|
1302
1117
|
});
|
|
1303
1118
|
activationLog.pop();
|
|
1304
|
-
if (count >= options.maxTriggerPerBatch) {
|
|
1119
|
+
if (count >= decorator.options.maxTriggerPerBatch) {
|
|
1305
1120
|
const effectName = root?.name || 'anonymous';
|
|
1306
1121
|
const message = `Aggressive trigger detected: effect "${effectName}" triggered ${count} times in the batch by the same cause.`;
|
|
1307
|
-
if (options.maxEffectReaction === 'throw') {
|
|
1308
|
-
throw new ReactiveError(message, {
|
|
1309
|
-
code: ReactiveErrorCode.MaxReactionExceeded,
|
|
1122
|
+
if (decorator.options.maxEffectReaction === 'throw') {
|
|
1123
|
+
throw new decorator.ReactiveError(message, {
|
|
1124
|
+
code: decorator.ReactiveErrorCode.MaxReactionExceeded,
|
|
1310
1125
|
count,
|
|
1311
1126
|
effect: effectName,
|
|
1312
1127
|
});
|
|
1313
1128
|
}
|
|
1314
|
-
options.warn(`[reactive] ${message}`);
|
|
1129
|
+
decorator.options.warn(`[reactive] ${message}`);
|
|
1315
1130
|
}
|
|
1316
1131
|
}
|
|
1317
1132
|
/**
|
|
@@ -1475,6 +1290,7 @@ function addGraphEdge(callerRoot, targetRoot) {
|
|
|
1475
1290
|
* @param end - Target node
|
|
1476
1291
|
* @param exclude - Node to exclude from the path
|
|
1477
1292
|
* @returns true if a path exists without going through the excluded node
|
|
1293
|
+
* @todo Can be REALLY costly - optimise or make optional or ...
|
|
1478
1294
|
*/
|
|
1479
1295
|
function hasPathExcluding(start, end, exclude) {
|
|
1480
1296
|
if (start === end)
|
|
@@ -1762,6 +1578,12 @@ function wouldCreateCycle(callerRoot, targetRoot) {
|
|
|
1762
1578
|
* @param immediate - If true, don't create edges in the dependency graph
|
|
1763
1579
|
*/
|
|
1764
1580
|
function addToBatch(effect, caller, immediate) {
|
|
1581
|
+
const cleanupFn = effect[decorator.cleanup];
|
|
1582
|
+
if (cleanupFn)
|
|
1583
|
+
cleanupFn();
|
|
1584
|
+
// If the effect was stopped during cleanup (e.g. lazy memoization), don't add it to the batch
|
|
1585
|
+
if (effect[decorator.stopped])
|
|
1586
|
+
return;
|
|
1765
1587
|
if (!batchQueue)
|
|
1766
1588
|
return;
|
|
1767
1589
|
const root = getRoot(effect);
|
|
@@ -1780,14 +1602,14 @@ function addToBatch(effect, caller, immediate) {
|
|
|
1780
1602
|
const cycleMessage = cyclePath.length > 0
|
|
1781
1603
|
? `Cycle detected: ${cyclePath.map((r) => r.name || r.toString()).join(' → ')}`
|
|
1782
1604
|
: `Cycle detected: ${callerRoot.name || callerRoot.toString()} → ${root.name || root.toString()} (and back)`;
|
|
1783
|
-
const cycleHandling = options.cycleHandling;
|
|
1605
|
+
const cycleHandling = decorator.options.cycleHandling;
|
|
1784
1606
|
// In strict mode, we throw immediately on detection
|
|
1785
1607
|
if (cycleHandling === 'strict') {
|
|
1786
1608
|
batchQueue.all.delete(root);
|
|
1787
1609
|
const causalChain = getTriggerChain(effect);
|
|
1788
1610
|
const creationStack = effectCreationStacks.get(root);
|
|
1789
|
-
throw new ReactiveError(`[reactive] Strict Cycle Prevention: ${cycleMessage}`, {
|
|
1790
|
-
code: ReactiveErrorCode.CycleDetected,
|
|
1611
|
+
throw new decorator.ReactiveError(`[reactive] Strict Cycle Prevention: ${cycleMessage}`, {
|
|
1612
|
+
code: decorator.ReactiveErrorCode.CycleDetected,
|
|
1791
1613
|
cycle: cyclePath.map((r) => r.name || r.toString()),
|
|
1792
1614
|
details: cycleMessage,
|
|
1793
1615
|
causalChain,
|
|
@@ -1800,8 +1622,8 @@ function addToBatch(effect, caller, immediate) {
|
|
|
1800
1622
|
batchQueue.all.delete(root);
|
|
1801
1623
|
const causalChain = getTriggerChain(effect);
|
|
1802
1624
|
const creationStack = effectCreationStacks.get(root);
|
|
1803
|
-
throw new ReactiveError(`[reactive] ${cycleMessage}`, {
|
|
1804
|
-
code: ReactiveErrorCode.CycleDetected,
|
|
1625
|
+
throw new decorator.ReactiveError(`[reactive] ${cycleMessage}`, {
|
|
1626
|
+
code: decorator.ReactiveErrorCode.CycleDetected,
|
|
1805
1627
|
cycle: cyclePath.map((r) => r.name || r.toString()),
|
|
1806
1628
|
details: cycleMessage,
|
|
1807
1629
|
causalChain,
|
|
@@ -1809,7 +1631,7 @@ function addToBatch(effect, caller, immediate) {
|
|
|
1809
1631
|
});
|
|
1810
1632
|
}
|
|
1811
1633
|
case 'warn':
|
|
1812
|
-
options.warn(`[reactive] ${cycleMessage}`);
|
|
1634
|
+
decorator.options.warn(`[reactive] ${cycleMessage}`);
|
|
1813
1635
|
// Don't add the edge, break the cycle
|
|
1814
1636
|
batchQueue.all.delete(root);
|
|
1815
1637
|
return;
|
|
@@ -1958,12 +1780,12 @@ function executeNext(effectuatedRoots) {
|
|
|
1958
1780
|
const cycleMessage = cycle.length > 0
|
|
1959
1781
|
? `Cycle detected: ${cycle.map((r) => r.name || '<anonymous>').join(' → ')}`
|
|
1960
1782
|
: 'Cycle detected in effect batch - all effects have dependencies that prevent execution';
|
|
1961
|
-
const cycleHandling = options.cycleHandling;
|
|
1783
|
+
const cycleHandling = decorator.options.cycleHandling;
|
|
1962
1784
|
switch (cycleHandling) {
|
|
1963
1785
|
case 'throw':
|
|
1964
|
-
throw new ReactiveError(`[reactive] ${cycleMessage}`);
|
|
1786
|
+
throw new decorator.ReactiveError(`[reactive] ${cycleMessage}`);
|
|
1965
1787
|
case 'warn': {
|
|
1966
|
-
options.warn(`[reactive] ${cycleMessage}`);
|
|
1788
|
+
decorator.options.warn(`[reactive] ${cycleMessage}`);
|
|
1967
1789
|
// Break the cycle by executing one effect anyway
|
|
1968
1790
|
const firstEffect = batchQueue.all.values().next().value;
|
|
1969
1791
|
if (firstEffect) {
|
|
@@ -2006,7 +1828,7 @@ function batch(effect, immediate) {
|
|
|
2006
1828
|
const roots = effect.map(getRoot);
|
|
2007
1829
|
if (batchQueue) {
|
|
2008
1830
|
// Nested batch - add to existing
|
|
2009
|
-
options?.chain(roots, getRoot(getActiveEffect()));
|
|
1831
|
+
decorator.options?.chain(roots, getRoot(getActiveEffect()));
|
|
2010
1832
|
const caller = getActiveEffect();
|
|
2011
1833
|
for (let i = 0; i < effect.length; i++) {
|
|
2012
1834
|
addToBatch(effect[i], caller, immediate === 'immediate');
|
|
@@ -2035,7 +1857,7 @@ function batch(effect, immediate) {
|
|
|
2035
1857
|
activationRegistry = new Map();
|
|
2036
1858
|
else
|
|
2037
1859
|
throw new Error('Batch already in progress');
|
|
2038
|
-
options.beginChain(roots);
|
|
1860
|
+
decorator.options.beginChain(roots);
|
|
2039
1861
|
batchQueue = {
|
|
2040
1862
|
all: new Map(),
|
|
2041
1863
|
inDegrees: new Map(),
|
|
@@ -2065,7 +1887,7 @@ function batch(effect, immediate) {
|
|
|
2065
1887
|
// After immediate execution, execute any effects that were triggered during execution
|
|
2066
1888
|
// This is important for @atomic decorator - effects triggered inside should still run
|
|
2067
1889
|
while (batchQueue.all.size > 0) {
|
|
2068
|
-
if (effectuatedRoots.length > options.maxEffectChain) {
|
|
1890
|
+
if (effectuatedRoots.length > decorator.options.maxEffectChain) {
|
|
2069
1891
|
const cycle = findCycleInChain(effectuatedRoots);
|
|
2070
1892
|
const trace = formatRoots(effectuatedRoots);
|
|
2071
1893
|
const message = cycle
|
|
@@ -2074,11 +1896,11 @@ function batch(effect, immediate) {
|
|
|
2074
1896
|
const queuedRoots = batchQueue ? Array.from(batchQueue.all.keys()) : [];
|
|
2075
1897
|
const queued = queuedRoots.map((r) => r.name || '<anonymous>');
|
|
2076
1898
|
const debugInfo = {
|
|
2077
|
-
code: ReactiveErrorCode.MaxDepthExceeded,
|
|
1899
|
+
code: decorator.ReactiveErrorCode.MaxDepthExceeded,
|
|
2078
1900
|
effectuatedRoots,
|
|
2079
1901
|
cycle,
|
|
2080
1902
|
trace,
|
|
2081
|
-
maxEffectChain: options.maxEffectChain,
|
|
1903
|
+
maxEffectChain: decorator.options.maxEffectChain,
|
|
2082
1904
|
queued: queued.slice(0, 50),
|
|
2083
1905
|
queuedCount: queued.length,
|
|
2084
1906
|
// Try to get causation for the last effect
|
|
@@ -2086,15 +1908,15 @@ function batch(effect, immediate) {
|
|
|
2086
1908
|
? getTriggerChain(batchQueue.all.get(effectuatedRoots[effectuatedRoots.length - 1]))
|
|
2087
1909
|
: [],
|
|
2088
1910
|
};
|
|
2089
|
-
switch (options.maxEffectReaction) {
|
|
1911
|
+
switch (decorator.options.maxEffectReaction) {
|
|
2090
1912
|
case 'throw':
|
|
2091
|
-
throw new ReactiveError(`[reactive] ${message}`, debugInfo);
|
|
1913
|
+
throw new decorator.ReactiveError(`[reactive] ${message}`, debugInfo);
|
|
2092
1914
|
case 'debug':
|
|
2093
1915
|
// biome-ignore lint/suspicious/noDebugger: This is the whole point here
|
|
2094
1916
|
debugger;
|
|
2095
|
-
throw new ReactiveError(`[reactive] ${message}`, debugInfo);
|
|
1917
|
+
throw new decorator.ReactiveError(`[reactive] ${message}`, debugInfo);
|
|
2096
1918
|
case 'warn':
|
|
2097
|
-
options.warn(`[reactive] ${message} (queued: ${queued.slice(0, 10).join(', ')}${queued.length > 10 ? ', …' : ''})`);
|
|
1919
|
+
decorator.options.warn(`[reactive] ${message} (queued: ${queued.slice(0, 10).join(', ')}${queued.length > 10 ? ', …' : ''})`);
|
|
2098
1920
|
break;
|
|
2099
1921
|
}
|
|
2100
1922
|
}
|
|
@@ -2115,7 +1937,7 @@ function batch(effect, immediate) {
|
|
|
2115
1937
|
finally {
|
|
2116
1938
|
activationRegistry = undefined;
|
|
2117
1939
|
batchQueue = undefined;
|
|
2118
|
-
options.endChain();
|
|
1940
|
+
decorator.options.endChain();
|
|
2119
1941
|
}
|
|
2120
1942
|
}
|
|
2121
1943
|
else {
|
|
@@ -2127,7 +1949,7 @@ function batch(effect, immediate) {
|
|
|
2127
1949
|
while (batchQueue.all.size > 0 || batchCleanups.size > 0) {
|
|
2128
1950
|
// Inner loop: execute all pending effects
|
|
2129
1951
|
while (batchQueue.all.size > 0) {
|
|
2130
|
-
if (effectuatedRoots.length > options.maxEffectChain) {
|
|
1952
|
+
if (effectuatedRoots.length > decorator.options.maxEffectChain) {
|
|
2131
1953
|
const cycle = findCycleInChain(effectuatedRoots);
|
|
2132
1954
|
const trace = formatRoots(effectuatedRoots);
|
|
2133
1955
|
const message = cycle
|
|
@@ -2136,11 +1958,11 @@ function batch(effect, immediate) {
|
|
|
2136
1958
|
const queuedRoots = batchQueue ? Array.from(batchQueue.all.keys()) : [];
|
|
2137
1959
|
const queued = queuedRoots.map((r) => r.name || '<anonymous>');
|
|
2138
1960
|
const debugInfo = {
|
|
2139
|
-
code: ReactiveErrorCode.MaxDepthExceeded,
|
|
1961
|
+
code: decorator.ReactiveErrorCode.MaxDepthExceeded,
|
|
2140
1962
|
effectuatedRoots,
|
|
2141
1963
|
cycle,
|
|
2142
1964
|
trace,
|
|
2143
|
-
maxEffectChain: options.maxEffectChain,
|
|
1965
|
+
maxEffectChain: decorator.options.maxEffectChain,
|
|
2144
1966
|
queued: queued.slice(0, 50),
|
|
2145
1967
|
queuedCount: queued.length,
|
|
2146
1968
|
// Try to get causation for the last effect
|
|
@@ -2148,15 +1970,15 @@ function batch(effect, immediate) {
|
|
|
2148
1970
|
? getTriggerChain(batchQueue.all.get(effectuatedRoots[effectuatedRoots.length - 1]))
|
|
2149
1971
|
: [],
|
|
2150
1972
|
};
|
|
2151
|
-
switch (options.maxEffectReaction) {
|
|
1973
|
+
switch (decorator.options.maxEffectReaction) {
|
|
2152
1974
|
case 'throw':
|
|
2153
|
-
throw new ReactiveError(`[reactive] ${message}`, debugInfo);
|
|
1975
|
+
throw new decorator.ReactiveError(`[reactive] ${message}`, debugInfo);
|
|
2154
1976
|
case 'debug':
|
|
2155
1977
|
// biome-ignore lint/suspicious/noDebugger: This is the whole point here
|
|
2156
1978
|
debugger;
|
|
2157
|
-
throw new ReactiveError(`[reactive] ${message}`, debugInfo);
|
|
1979
|
+
throw new decorator.ReactiveError(`[reactive] ${message}`, debugInfo);
|
|
2158
1980
|
case 'warn':
|
|
2159
|
-
options.warn(`[reactive] ${message} (queued: ${queued.slice(0, 10).join(', ')}${queued.length > 10 ? ', …' : ''})`);
|
|
1981
|
+
decorator.options.warn(`[reactive] ${message} (queued: ${queued.slice(0, 10).join(', ')}${queued.length > 10 ? ', …' : ''})`);
|
|
2160
1982
|
break;
|
|
2161
1983
|
}
|
|
2162
1984
|
}
|
|
@@ -2186,7 +2008,7 @@ function batch(effect, immediate) {
|
|
|
2186
2008
|
finally {
|
|
2187
2009
|
activationRegistry = undefined;
|
|
2188
2010
|
batchQueue = undefined;
|
|
2189
|
-
options.endChain();
|
|
2011
|
+
decorator.options.endChain();
|
|
2190
2012
|
}
|
|
2191
2013
|
}
|
|
2192
2014
|
}
|
|
@@ -2197,12 +2019,18 @@ function batch(effect, immediate) {
|
|
|
2197
2019
|
const atomic = decorator.decorator({
|
|
2198
2020
|
method(original) {
|
|
2199
2021
|
return function (...args) {
|
|
2200
|
-
|
|
2022
|
+
const atomicEffect = () => original.apply(this, args);
|
|
2023
|
+
// Debug: helpful to have a name
|
|
2024
|
+
Object.defineProperty(atomicEffect, 'name', { value: `atomic(${original.name})` });
|
|
2025
|
+
return batch(atomicEffect, 'immediate');
|
|
2201
2026
|
};
|
|
2202
2027
|
},
|
|
2203
2028
|
default(original) {
|
|
2204
2029
|
return function (...args) {
|
|
2205
|
-
|
|
2030
|
+
const atomicEffect = () => original.apply(this, args);
|
|
2031
|
+
// Debug: helpful to have a name
|
|
2032
|
+
Object.defineProperty(atomicEffect, 'name', { value: `atomic(${original.name})` });
|
|
2033
|
+
return batch(atomicEffect, 'immediate');
|
|
2206
2034
|
};
|
|
2207
2035
|
},
|
|
2208
2036
|
});
|
|
@@ -2224,8 +2052,8 @@ fn, effectOptions) {
|
|
|
2224
2052
|
// Inject batch function to allow atomic game loops in requestAnimationFrame
|
|
2225
2053
|
ensureZoneHooked(batch);
|
|
2226
2054
|
// Use per-effect asyncMode or fall back to global option
|
|
2227
|
-
const asyncMode = effectOptions?.asyncMode ?? options.asyncMode ?? 'cancel';
|
|
2228
|
-
if (options.introspection.enableHistory) {
|
|
2055
|
+
const asyncMode = effectOptions?.asyncMode ?? decorator.options.asyncMode ?? 'cancel';
|
|
2056
|
+
if (decorator.options.introspection.enableHistory) {
|
|
2229
2057
|
const stack = new Error().stack;
|
|
2230
2058
|
if (stack) {
|
|
2231
2059
|
// Clean up the stack trace to remove internal frames
|
|
@@ -2236,7 +2064,7 @@ fn, effectOptions) {
|
|
|
2236
2064
|
let cleanup = null;
|
|
2237
2065
|
// capture the parent effect at creation time for ascend
|
|
2238
2066
|
const parentsForAscend = captureEffectStack();
|
|
2239
|
-
const tracked =
|
|
2067
|
+
const tracked = (cb) => withEffect(runEffect, cb);
|
|
2240
2068
|
const ascend = (cb) => withEffectStack(parentsForAscend, cb);
|
|
2241
2069
|
let effectStopped = false;
|
|
2242
2070
|
let hasReacted = false;
|
|
@@ -2266,7 +2094,7 @@ fn, effectOptions) {
|
|
|
2266
2094
|
// The effect has been stopped after having been planned
|
|
2267
2095
|
if (effectStopped)
|
|
2268
2096
|
return;
|
|
2269
|
-
options.enter(getRoot(fn));
|
|
2097
|
+
decorator.options.enter(getRoot(fn));
|
|
2270
2098
|
let reactionCleanup;
|
|
2271
2099
|
let result;
|
|
2272
2100
|
try {
|
|
@@ -2274,7 +2102,7 @@ fn, effectOptions) {
|
|
|
2274
2102
|
if (result &&
|
|
2275
2103
|
typeof result !== 'function' &&
|
|
2276
2104
|
(typeof result !== 'object' || !('then' in result)))
|
|
2277
|
-
throw new ReactiveError(`[reactive] Effect returned a non-function value: ${result}`);
|
|
2105
|
+
throw new decorator.ReactiveError(`[reactive] Effect returned a non-function value: ${result}`);
|
|
2278
2106
|
// Check if result is a Promise (async effect)
|
|
2279
2107
|
if (result && typeof result === 'object' && typeof result.then === 'function') {
|
|
2280
2108
|
const originalPromise = result;
|
|
@@ -2283,7 +2111,7 @@ fn, effectOptions) {
|
|
|
2283
2111
|
const cancelPromise = new Promise((_, reject) => {
|
|
2284
2112
|
cancelReject = reject;
|
|
2285
2113
|
});
|
|
2286
|
-
const cancelError = new ReactiveError('[reactive] Effect canceled due to dependency change');
|
|
2114
|
+
const cancelError = new decorator.ReactiveError('[reactive] Effect canceled due to dependency change');
|
|
2287
2115
|
// Race between the actual promise and cancellation
|
|
2288
2116
|
// If canceled, the race rejects, which will propagate through any promise chain
|
|
2289
2117
|
runningPromise = Promise.race([originalPromise, cancelPromise]);
|
|
@@ -2305,7 +2133,7 @@ fn, effectOptions) {
|
|
|
2305
2133
|
}
|
|
2306
2134
|
finally {
|
|
2307
2135
|
hasReacted = true;
|
|
2308
|
-
options.leave(fn);
|
|
2136
|
+
decorator.options.leave(fn);
|
|
2309
2137
|
}
|
|
2310
2138
|
// Create cleanup function for next run
|
|
2311
2139
|
cleanup = () => {
|
|
@@ -2369,11 +2197,28 @@ fn, effectOptions) {
|
|
|
2369
2197
|
cleanupEffectFromGraph(runEffect);
|
|
2370
2198
|
fr.unregister(stopEffect);
|
|
2371
2199
|
};
|
|
2200
|
+
function augmentedRv(rv) {
|
|
2201
|
+
Object.defineProperty(rv, decorator.stopped, {
|
|
2202
|
+
get() {
|
|
2203
|
+
return effectStopped;
|
|
2204
|
+
},
|
|
2205
|
+
});
|
|
2206
|
+
Object.defineProperty(rv, decorator.cleanup, {
|
|
2207
|
+
value: () => {
|
|
2208
|
+
if (cleanup) {
|
|
2209
|
+
const prevCleanup = cleanup;
|
|
2210
|
+
cleanup = null;
|
|
2211
|
+
withEffect(undefined, () => prevCleanup());
|
|
2212
|
+
}
|
|
2213
|
+
},
|
|
2214
|
+
});
|
|
2215
|
+
return rv;
|
|
2216
|
+
}
|
|
2372
2217
|
if (isRootEffect) {
|
|
2373
|
-
const callIfCollected = () => stopEffect();
|
|
2218
|
+
const callIfCollected = augmentedRv(() => stopEffect());
|
|
2374
2219
|
fr.register(callIfCollected, () => {
|
|
2375
2220
|
stopEffect();
|
|
2376
|
-
options.garbageCollected(fn);
|
|
2221
|
+
decorator.options.garbageCollected(fn);
|
|
2377
2222
|
}, stopEffect);
|
|
2378
2223
|
return callIfCollected;
|
|
2379
2224
|
}
|
|
@@ -2383,14 +2228,14 @@ fn, effectOptions) {
|
|
|
2383
2228
|
children = new Set();
|
|
2384
2229
|
effectChildren.set(parent, children);
|
|
2385
2230
|
}
|
|
2386
|
-
const subEffectCleanup = () => {
|
|
2231
|
+
const subEffectCleanup = augmentedRv(() => {
|
|
2387
2232
|
children.delete(subEffectCleanup);
|
|
2388
2233
|
if (children.size === 0) {
|
|
2389
2234
|
effectChildren.delete(parent);
|
|
2390
2235
|
}
|
|
2391
2236
|
// Execute this child effect cleanup (which triggers its own mainCleanup)
|
|
2392
2237
|
stopEffect();
|
|
2393
|
-
};
|
|
2238
|
+
});
|
|
2394
2239
|
children.add(subEffectCleanup);
|
|
2395
2240
|
return subEffectCleanup;
|
|
2396
2241
|
}
|
|
@@ -2551,7 +2396,7 @@ function collectEffects(obj, evolution, effects, objectWatchers, ...keyChains) {
|
|
|
2551
2396
|
for (const effect of deps) {
|
|
2552
2397
|
const runningChain = isRunning(effect);
|
|
2553
2398
|
if (runningChain) {
|
|
2554
|
-
options.skipRunningEffect(effect, runningChain);
|
|
2399
|
+
decorator.options.skipRunningEffect(effect, runningChain);
|
|
2555
2400
|
continue;
|
|
2556
2401
|
}
|
|
2557
2402
|
if (!effects.has(effect)) {
|
|
@@ -2592,10 +2437,10 @@ function touched(obj, evolution, props) {
|
|
|
2592
2437
|
// Note: we have to collect effects to remove duplicates in the specific case when no batch is running
|
|
2593
2438
|
const effects = new Set();
|
|
2594
2439
|
if (props)
|
|
2595
|
-
collectEffects(obj, evolution, effects, objectWatchers, [allProps], props);
|
|
2440
|
+
collectEffects(obj, evolution, effects, objectWatchers, [decorator.allProps], props);
|
|
2596
2441
|
else
|
|
2597
2442
|
collectEffects(obj, evolution, effects, objectWatchers, objectWatchers.keys());
|
|
2598
|
-
options.touched(obj, evolution, props, effects);
|
|
2443
|
+
decorator.options.touched(obj, evolution, props, effects);
|
|
2599
2444
|
batch(Array.from(effects));
|
|
2600
2445
|
}
|
|
2601
2446
|
// Bubble up changes if this object has deep watchers
|
|
@@ -2622,7 +2467,7 @@ function touchedOpaque(obj, evolution, prop) {
|
|
|
2622
2467
|
continue;
|
|
2623
2468
|
const runningChain = isRunning(effect);
|
|
2624
2469
|
if (runningChain) {
|
|
2625
|
-
options.skipRunningEffect(effect, runningChain);
|
|
2470
|
+
decorator.options.skipRunningEffect(effect, runningChain);
|
|
2626
2471
|
continue;
|
|
2627
2472
|
}
|
|
2628
2473
|
effects.add(effect);
|
|
@@ -2636,7 +2481,7 @@ function touchedOpaque(obj, evolution, prop) {
|
|
|
2636
2481
|
}
|
|
2637
2482
|
}
|
|
2638
2483
|
if (effects.size > 0) {
|
|
2639
|
-
options.touched(obj, evolution, [prop], effects);
|
|
2484
|
+
decorator.options.touched(obj, evolution, [prop], effects);
|
|
2640
2485
|
batch(Array.from(effects));
|
|
2641
2486
|
}
|
|
2642
2487
|
}
|
|
@@ -2647,7 +2492,7 @@ const absent = Symbol('absent');
|
|
|
2647
2492
|
function markNonReactive(...obj) {
|
|
2648
2493
|
for (const o of obj) {
|
|
2649
2494
|
try {
|
|
2650
|
-
Object.defineProperty(o, nonReactiveMark, {
|
|
2495
|
+
Object.defineProperty(o, decorator.nonReactiveMark, {
|
|
2651
2496
|
value: true,
|
|
2652
2497
|
writable: false,
|
|
2653
2498
|
enumerable: false,
|
|
@@ -2655,7 +2500,7 @@ function markNonReactive(...obj) {
|
|
|
2655
2500
|
});
|
|
2656
2501
|
}
|
|
2657
2502
|
catch { }
|
|
2658
|
-
if (!(nonReactiveMark in o))
|
|
2503
|
+
if (!(decorator.nonReactiveMark in o))
|
|
2659
2504
|
nonReactiveObjects.add(o);
|
|
2660
2505
|
}
|
|
2661
2506
|
return obj[0];
|
|
@@ -2663,7 +2508,7 @@ function markNonReactive(...obj) {
|
|
|
2663
2508
|
function nonReactiveClass(...cls) {
|
|
2664
2509
|
for (const c of cls)
|
|
2665
2510
|
if (c)
|
|
2666
|
-
c.prototype[nonReactiveMark] = true;
|
|
2511
|
+
c.prototype[decorator.nonReactiveMark] = true;
|
|
2667
2512
|
return cls[0];
|
|
2668
2513
|
}
|
|
2669
2514
|
function isNonReactive(obj) {
|
|
@@ -2671,7 +2516,7 @@ function isNonReactive(obj) {
|
|
|
2671
2516
|
return true;
|
|
2672
2517
|
if (nonReactiveObjects.has(obj))
|
|
2673
2518
|
return true;
|
|
2674
|
-
if (obj[nonReactiveMark])
|
|
2519
|
+
if (obj[decorator.nonReactiveMark])
|
|
2675
2520
|
return true;
|
|
2676
2521
|
for (const fn of immutables)
|
|
2677
2522
|
if (fn(obj))
|
|
@@ -2679,7 +2524,7 @@ function isNonReactive(obj) {
|
|
|
2679
2524
|
return false;
|
|
2680
2525
|
}
|
|
2681
2526
|
function registerNativeReactivity(originalClass, reactiveClass) {
|
|
2682
|
-
originalClass.prototype[nativeReactive] = reactiveClass;
|
|
2527
|
+
originalClass.prototype[decorator.nativeReactive] = reactiveClass;
|
|
2683
2528
|
nonReactiveClass(reactiveClass);
|
|
2684
2529
|
}
|
|
2685
2530
|
nonReactiveClass(Date, RegExp, Error, Promise, Function);
|
|
@@ -2725,7 +2570,7 @@ function shouldRecurseTouch(oldValue, newValue) {
|
|
|
2725
2570
|
*/
|
|
2726
2571
|
function notifyPropertyChange(targetObj, prop, oldValue, newValue, hadProperty) {
|
|
2727
2572
|
const evolution = { type: hadProperty ? 'set' : 'add', prop };
|
|
2728
|
-
if (options.recursiveTouching &&
|
|
2573
|
+
if (decorator.options.recursiveTouching &&
|
|
2729
2574
|
oldValue !== undefined &&
|
|
2730
2575
|
shouldRecurseTouch(oldValue, newValue)) {
|
|
2731
2576
|
const unwrappedObj = unwrap(targetObj);
|
|
@@ -2862,7 +2707,7 @@ function dispatchNotifications(notifications) {
|
|
|
2862
2707
|
const originWatchers = watchers.get(origin.obj);
|
|
2863
2708
|
if (originWatchers) {
|
|
2864
2709
|
const originEffects = new Set();
|
|
2865
|
-
collectEffects(origin.obj, { type: 'set', prop: origin.prop }, originEffects, originWatchers, [allProps], [origin.prop]);
|
|
2710
|
+
collectEffects(origin.obj, { type: 'set', prop: origin.prop }, originEffects, originWatchers, [decorator.allProps], [origin.prop]);
|
|
2866
2711
|
for (const effect of originEffects)
|
|
2867
2712
|
allowedEffects.add(effect);
|
|
2868
2713
|
}
|
|
@@ -2880,7 +2725,7 @@ function dispatchNotifications(notifications) {
|
|
|
2880
2725
|
const propsArray = [prop];
|
|
2881
2726
|
if (objectWatchers) {
|
|
2882
2727
|
currentEffects = new Set();
|
|
2883
|
-
collectEffects(obj, evolution, currentEffects, objectWatchers, [allProps], propsArray);
|
|
2728
|
+
collectEffects(obj, evolution, currentEffects, objectWatchers, [decorator.allProps], propsArray);
|
|
2884
2729
|
// Filter effects by ancestor chain if origin exists
|
|
2885
2730
|
// Include effects that either directly depend on origin or have an ancestor that does
|
|
2886
2731
|
if (origin && allowedEffects) {
|
|
@@ -2896,7 +2741,7 @@ function dispatchNotifications(notifications) {
|
|
|
2896
2741
|
for (const effect of currentEffects)
|
|
2897
2742
|
combinedEffects.add(effect);
|
|
2898
2743
|
}
|
|
2899
|
-
options.touched(obj, evolution, propsArray, currentEffects);
|
|
2744
|
+
decorator.options.touched(obj, evolution, propsArray, currentEffects);
|
|
2900
2745
|
if (objectsWithDeepWatchers.has(obj))
|
|
2901
2746
|
bubbleUpChange(obj);
|
|
2902
2747
|
}
|
|
@@ -2908,18 +2753,18 @@ const hasReentry = [];
|
|
|
2908
2753
|
const reactiveHandlers = {
|
|
2909
2754
|
[Symbol.toStringTag]: 'MutTs Reactive',
|
|
2910
2755
|
get(obj, prop, receiver) {
|
|
2911
|
-
if (prop === nonReactiveMark)
|
|
2756
|
+
if (prop === decorator.nonReactiveMark)
|
|
2912
2757
|
return false;
|
|
2913
2758
|
const unwrappedObj = unwrap(obj);
|
|
2914
2759
|
// Check if this property is marked as unreactive
|
|
2915
|
-
if (unwrappedObj[unreactiveProperties]?.has(prop) || typeof prop === 'symbol')
|
|
2760
|
+
if (unwrappedObj[decorator.unreactiveProperties]?.has(prop) || typeof prop === 'symbol')
|
|
2916
2761
|
return decorator.ReflectGet(obj, prop, receiver);
|
|
2917
2762
|
// Special-case: array wrappers use prototype forwarding + numeric accessors.
|
|
2918
2763
|
// With options.instanceMembers=true, inherited reads are normally not tracked, which breaks
|
|
2919
2764
|
// reactivity for array indices/length (they appear inherited on the proxy).
|
|
2920
|
-
const isArrayCase = prototypeForwarding in obj &&
|
|
2765
|
+
const isArrayCase = decorator.prototypeForwarding in obj &&
|
|
2921
2766
|
// biome-ignore lint/suspicious/useIsArray: This is the whole point here
|
|
2922
|
-
obj[prototypeForwarding] instanceof Array &&
|
|
2767
|
+
obj[decorator.prototypeForwarding] instanceof Array &&
|
|
2923
2768
|
typeof prop === 'string' &&
|
|
2924
2769
|
(prop === 'length' || !Number.isNaN(Number(prop)));
|
|
2925
2770
|
if (isArrayCase) {
|
|
@@ -2931,16 +2776,16 @@ const reactiveHandlers = {
|
|
|
2931
2776
|
const isInheritedAccess = hasProp && !isOwnProp;
|
|
2932
2777
|
// For accessor properties, check the unwrapped object to see if it's an accessor
|
|
2933
2778
|
// This ensures ignoreAccessors works correctly even after operations like Object.setPrototypeOf
|
|
2934
|
-
const shouldIgnoreAccessor = options.ignoreAccessors &&
|
|
2779
|
+
const shouldIgnoreAccessor = decorator.options.ignoreAccessors &&
|
|
2935
2780
|
isOwnProp &&
|
|
2936
2781
|
(decorator.isOwnAccessor(receiver, prop) || decorator.isOwnAccessor(unwrappedObj, prop));
|
|
2937
2782
|
// Depend if...
|
|
2938
2783
|
if (!hasProp ||
|
|
2939
|
-
(!(options.instanceMembers && isInheritedAccess && obj instanceof Object) &&
|
|
2784
|
+
(!(decorator.options.instanceMembers && isInheritedAccess && obj instanceof Object) &&
|
|
2940
2785
|
!shouldIgnoreAccessor))
|
|
2941
2786
|
dependant(obj, prop);
|
|
2942
2787
|
// Watch the whole prototype chain when requested or for null-proto objects
|
|
2943
|
-
if (isInheritedAccess && (!options.instanceMembers || !(obj instanceof Object))) {
|
|
2788
|
+
if (isInheritedAccess && (!decorator.options.instanceMembers || !(obj instanceof Object))) {
|
|
2944
2789
|
let current = reactiveObject(Object.getPrototypeOf(obj));
|
|
2945
2790
|
while (current && current !== Object.prototype) {
|
|
2946
2791
|
dependant(current, prop);
|
|
@@ -2969,12 +2814,12 @@ const reactiveHandlers = {
|
|
|
2969
2814
|
const unwrappedObj = unwrap(obj);
|
|
2970
2815
|
const unwrappedReceiver = unwrap(receiver);
|
|
2971
2816
|
// Check if this property is marked as unreactive
|
|
2972
|
-
if (unwrappedObj[unreactiveProperties]?.has(prop) || unwrappedObj !== unwrappedReceiver)
|
|
2817
|
+
if (unwrappedObj[decorator.unreactiveProperties]?.has(prop) || unwrappedObj !== unwrappedReceiver)
|
|
2973
2818
|
return decorator.ReflectSet(obj, prop, value, receiver);
|
|
2974
2819
|
// Really specific case for when Array is forwarder, in order to let it manage the reactivity
|
|
2975
|
-
const isArrayCase = prototypeForwarding in obj &&
|
|
2820
|
+
const isArrayCase = decorator.prototypeForwarding in obj &&
|
|
2976
2821
|
// biome-ignore lint/suspicious/useIsArray: This is the whole point here
|
|
2977
|
-
obj[prototypeForwarding] instanceof Array &&
|
|
2822
|
+
obj[decorator.prototypeForwarding] instanceof Array &&
|
|
2978
2823
|
(!Number.isNaN(Number(prop)) || prop === 'length');
|
|
2979
2824
|
const newValue = unwrap(value);
|
|
2980
2825
|
if (isArrayCase) {
|
|
@@ -2989,13 +2834,13 @@ const reactiveHandlers = {
|
|
|
2989
2834
|
const receiverDesc = Object.getOwnPropertyDescriptor(unwrappedReceiver, prop);
|
|
2990
2835
|
const targetDesc = Object.getOwnPropertyDescriptor(unwrappedObj, prop);
|
|
2991
2836
|
const desc = receiverDesc || targetDesc;
|
|
2992
|
-
//
|
|
2993
|
-
//
|
|
2837
|
+
// We *need* to use `receiver` and not `unwrappedObj` here, otherwise we break
|
|
2838
|
+
// the dependency tracking for memoized getters
|
|
2994
2839
|
if (desc?.get && !desc?.set) {
|
|
2995
|
-
oldVal = withEffect(undefined, () => Reflect.get(unwrappedObj, prop,
|
|
2840
|
+
oldVal = withEffect(undefined, () => Reflect.get(unwrappedObj, prop, receiver));
|
|
2996
2841
|
}
|
|
2997
2842
|
else {
|
|
2998
|
-
oldVal = Reflect.get(unwrappedObj, prop,
|
|
2843
|
+
oldVal = withEffect(undefined, () => Reflect.get(unwrappedObj, prop, receiver));
|
|
2999
2844
|
}
|
|
3000
2845
|
}
|
|
3001
2846
|
if (objectsWithDeepWatchers.has(obj)) {
|
|
@@ -3018,8 +2863,8 @@ const reactiveHandlers = {
|
|
|
3018
2863
|
},
|
|
3019
2864
|
has(obj, prop) {
|
|
3020
2865
|
if (hasReentry.includes(obj))
|
|
3021
|
-
throw new ReactiveError(`[reactive] Circular dependency detected in 'has' check for property '${String(prop)}'`, {
|
|
3022
|
-
code: ReactiveErrorCode.CycleDetected,
|
|
2866
|
+
throw new decorator.ReactiveError(`[reactive] Circular dependency detected in 'has' check for property '${String(prop)}'`, {
|
|
2867
|
+
code: decorator.ReactiveErrorCode.CycleDetected,
|
|
3023
2868
|
cycle: [], // We don't have the full cycle here, but we know it involves obj
|
|
3024
2869
|
});
|
|
3025
2870
|
hasReentry.push(obj);
|
|
@@ -3045,18 +2890,18 @@ const reactiveHandlers = {
|
|
|
3045
2890
|
return true;
|
|
3046
2891
|
},
|
|
3047
2892
|
getPrototypeOf(obj) {
|
|
3048
|
-
if (prototypeForwarding in obj)
|
|
3049
|
-
return obj[prototypeForwarding];
|
|
2893
|
+
if (decorator.prototypeForwarding in obj)
|
|
2894
|
+
return obj[decorator.prototypeForwarding];
|
|
3050
2895
|
return Object.getPrototypeOf(obj);
|
|
3051
2896
|
},
|
|
3052
2897
|
setPrototypeOf(obj, proto) {
|
|
3053
|
-
if (prototypeForwarding in obj)
|
|
2898
|
+
if (decorator.prototypeForwarding in obj)
|
|
3054
2899
|
return false;
|
|
3055
2900
|
Object.setPrototypeOf(obj, proto);
|
|
3056
2901
|
return true;
|
|
3057
2902
|
},
|
|
3058
2903
|
ownKeys(obj) {
|
|
3059
|
-
dependant(obj, allProps);
|
|
2904
|
+
dependant(obj, decorator.allProps);
|
|
3060
2905
|
return Reflect.ownKeys(obj);
|
|
3061
2906
|
},
|
|
3062
2907
|
};
|
|
@@ -3092,8 +2937,8 @@ function reactiveObject(anyTarget) {
|
|
|
3092
2937
|
const existing = getExistingProxy(target);
|
|
3093
2938
|
if (existing !== undefined)
|
|
3094
2939
|
return existing;
|
|
3095
|
-
const proxied = nativeReactive in target && !(target instanceof target[nativeReactive])
|
|
3096
|
-
? new target[nativeReactive](target)
|
|
2940
|
+
const proxied = decorator.nativeReactive in target && !(target instanceof target[decorator.nativeReactive])
|
|
2941
|
+
? new target[decorator.nativeReactive](target)
|
|
3097
2942
|
: target;
|
|
3098
2943
|
if (proxied !== target)
|
|
3099
2944
|
trackProxyObject(proxied, target);
|
|
@@ -3116,7 +2961,7 @@ const reactive = decorator.decorator({
|
|
|
3116
2961
|
constructor(...args) {
|
|
3117
2962
|
super(...args);
|
|
3118
2963
|
if (new.target !== Reactive && !reactiveClasses.has(new.target))
|
|
3119
|
-
options.warn(`${original.name} has been inherited by ${this.constructor.name} that is not reactive.
|
|
2964
|
+
decorator.options.warn(`${original.name} has been inherited by ${this.constructor.name} that is not reactive.
|
|
3120
2965
|
@reactive decorator must be applied to the leaf class OR classes have to extend ReactiveBase.`);
|
|
3121
2966
|
// biome-ignore lint/correctness/noConstructorReturn: This is the whole point here
|
|
3122
2967
|
return reactive(this);
|
|
@@ -3173,7 +3018,7 @@ function deepWatch(target, callback, { immediate = false } = {}) {
|
|
|
3173
3018
|
const visited = new WeakSet();
|
|
3174
3019
|
function traverseAndTrack(obj, depth = 0) {
|
|
3175
3020
|
// Prevent infinite recursion and excessive depth
|
|
3176
|
-
if (!obj || visited.has(obj) || !isObject(obj) || depth > options.maxDeepWatchDepth)
|
|
3021
|
+
if (!obj || visited.has(obj) || !isObject(obj) || depth > decorator.options.maxDeepWatchDepth)
|
|
3177
3022
|
return;
|
|
3178
3023
|
// Do not traverse into unreactive objects
|
|
3179
3024
|
if (isNonReactive(obj))
|
|
@@ -3285,12 +3130,12 @@ function watchObject(value, changed, { immediate = false, deep = false } = {}) {
|
|
|
3285
3130
|
const myParentEffect = getActiveEffect();
|
|
3286
3131
|
if (deep)
|
|
3287
3132
|
return deepWatch(value, changed, { immediate });
|
|
3288
|
-
return effect(
|
|
3133
|
+
return effect(function watchObjectEffect() {
|
|
3289
3134
|
dependant(value);
|
|
3290
3135
|
if (immediate)
|
|
3291
3136
|
withEffect(myParentEffect, () => changed(value));
|
|
3292
3137
|
immediate = true;
|
|
3293
|
-
}
|
|
3138
|
+
});
|
|
3294
3139
|
}
|
|
3295
3140
|
function watchCallBack(value, changed, { immediate = false, deep = false } = {}) {
|
|
3296
3141
|
const myParentEffect = getActiveEffect();
|
|
@@ -3299,7 +3144,7 @@ function watchCallBack(value, changed, { immediate = false, deep = false } = {})
|
|
|
3299
3144
|
const cbCleanup = effect(markWithRoot(function watchCallBackEffect(access) {
|
|
3300
3145
|
const newValue = value(access);
|
|
3301
3146
|
if (oldValue !== newValue)
|
|
3302
|
-
withEffect(myParentEffect,
|
|
3147
|
+
withEffect(myParentEffect, () => {
|
|
3303
3148
|
if (oldValue === unsetYet) {
|
|
3304
3149
|
if (immediate)
|
|
3305
3150
|
changed(newValue);
|
|
@@ -3310,9 +3155,9 @@ function watchCallBack(value, changed, { immediate = false, deep = false } = {})
|
|
|
3310
3155
|
if (deep) {
|
|
3311
3156
|
if (deepCleanup)
|
|
3312
3157
|
deepCleanup();
|
|
3313
|
-
deepCleanup = deepWatch(newValue,
|
|
3158
|
+
deepCleanup = deepWatch(newValue, (value) => changed(value, value));
|
|
3314
3159
|
}
|
|
3315
|
-
}
|
|
3160
|
+
});
|
|
3316
3161
|
}, value));
|
|
3317
3162
|
return () => {
|
|
3318
3163
|
cbCleanup();
|
|
@@ -3331,7 +3176,7 @@ function deepNonReactive(obj) {
|
|
|
3331
3176
|
if (isNonReactive(obj))
|
|
3332
3177
|
return obj;
|
|
3333
3178
|
try {
|
|
3334
|
-
Object.defineProperty(obj, nonReactiveMark, {
|
|
3179
|
+
Object.defineProperty(obj, decorator.nonReactiveMark, {
|
|
3335
3180
|
value: true,
|
|
3336
3181
|
writable: false,
|
|
3337
3182
|
enumerable: false,
|
|
@@ -3339,7 +3184,7 @@ function deepNonReactive(obj) {
|
|
|
3339
3184
|
});
|
|
3340
3185
|
}
|
|
3341
3186
|
catch { }
|
|
3342
|
-
if (!(nonReactiveMark in obj))
|
|
3187
|
+
if (!(decorator.nonReactiveMark in obj))
|
|
3343
3188
|
nonReactiveObjects.add(obj);
|
|
3344
3189
|
//for (const key in obj) deepNonReactive(obj[key])
|
|
3345
3190
|
return obj;
|
|
@@ -3349,11 +3194,11 @@ function unreactiveApplication(arg1, ...args) {
|
|
|
3349
3194
|
? deepNonReactive(arg1)
|
|
3350
3195
|
: ((original) => {
|
|
3351
3196
|
// Copy the parent's unreactive properties if they exist
|
|
3352
|
-
original.prototype[unreactiveProperties] = new Set(original.prototype[unreactiveProperties] || []);
|
|
3197
|
+
original.prototype[decorator.unreactiveProperties] = new Set(original.prototype[decorator.unreactiveProperties] || []);
|
|
3353
3198
|
// Add all arguments (including the first one)
|
|
3354
|
-
original.prototype[unreactiveProperties].add(arg1);
|
|
3199
|
+
original.prototype[decorator.unreactiveProperties].add(arg1);
|
|
3355
3200
|
for (const arg of args)
|
|
3356
|
-
original.prototype[unreactiveProperties].add(arg);
|
|
3201
|
+
original.prototype[decorator.unreactiveProperties].add(arg);
|
|
3357
3202
|
return original; // Return the class
|
|
3358
3203
|
});
|
|
3359
3204
|
}
|
|
@@ -3385,9 +3230,9 @@ function cleanedBy(obj, cleanupFn) {
|
|
|
3385
3230
|
*/
|
|
3386
3231
|
function derived(compute) {
|
|
3387
3232
|
const rv = { value: undefined };
|
|
3388
|
-
return cleanedBy(rv, untracked(() => effect(
|
|
3233
|
+
return cleanedBy(rv, untracked(() => effect(function derivedEffect(access) {
|
|
3389
3234
|
rv.value = compute(access);
|
|
3390
|
-
}
|
|
3235
|
+
})));
|
|
3391
3236
|
}
|
|
3392
3237
|
|
|
3393
3238
|
/**
|
|
@@ -3417,8 +3262,8 @@ const isArray = Array.isArray;
|
|
|
3417
3262
|
Array.isArray = ((value) => isArray(value) ||
|
|
3418
3263
|
(value &&
|
|
3419
3264
|
typeof value === 'object' &&
|
|
3420
|
-
prototypeForwarding in value &&
|
|
3421
|
-
Array.isArray(value[prototypeForwarding])));
|
|
3265
|
+
decorator.prototypeForwarding in value &&
|
|
3266
|
+
Array.isArray(value[decorator.prototypeForwarding])));
|
|
3422
3267
|
class ReactiveBaseArray {
|
|
3423
3268
|
// Safe array access with negative indices
|
|
3424
3269
|
at(index) {
|
|
@@ -3631,7 +3476,7 @@ class ReactiveArray extends indexable.Indexable(ReactiveBaseArray, {
|
|
|
3631
3476
|
Object.defineProperties(this, {
|
|
3632
3477
|
// We have to make it double, as [native] must be `unique symbol` - impossible through import
|
|
3633
3478
|
[native$2]: { value: original },
|
|
3634
|
-
[prototypeForwarding]: { value: original },
|
|
3479
|
+
[decorator.prototypeForwarding]: { value: original },
|
|
3635
3480
|
});
|
|
3636
3481
|
}
|
|
3637
3482
|
push(...items) {
|
|
@@ -3762,7 +3607,7 @@ class ReactiveReadOnlyArrayClass extends indexable.Indexable(ReactiveBaseArray,
|
|
|
3762
3607
|
Object.defineProperties(this, {
|
|
3763
3608
|
// We have to make it double, as [native] must be `unique symbol` - impossible through import
|
|
3764
3609
|
[native$2]: { value: original },
|
|
3765
|
-
[prototypeForwarding]: { value: original },
|
|
3610
|
+
[decorator.prototypeForwarding]: { value: original },
|
|
3766
3611
|
});
|
|
3767
3612
|
}
|
|
3768
3613
|
push(..._items) {
|
|
@@ -3843,6 +3688,7 @@ function reduced(inputs, compute) {
|
|
|
3843
3688
|
}
|
|
3844
3689
|
|
|
3845
3690
|
const memoizedRegistry = new WeakMap();
|
|
3691
|
+
const wrapperRegistry = new WeakMap();
|
|
3846
3692
|
function getBranch(tree, key) {
|
|
3847
3693
|
tree.branches ?? (tree.branches = new WeakMap());
|
|
3848
3694
|
let branch = tree.branches.get(key);
|
|
@@ -3863,15 +3709,30 @@ function memoizeFunction(fn) {
|
|
|
3863
3709
|
if (localArgs.some((arg) => !(arg && ['object', 'symbol', 'function'].includes(typeof arg))))
|
|
3864
3710
|
throw new Error('memoize expects non-null object arguments');
|
|
3865
3711
|
let node = cacheRoot;
|
|
3712
|
+
// Note: decorators add `this` as first argument
|
|
3866
3713
|
for (const arg of localArgs) {
|
|
3867
3714
|
node = getBranch(node, arg);
|
|
3868
3715
|
}
|
|
3869
3716
|
dependant(node, 'memoize');
|
|
3870
|
-
if ('result' in node)
|
|
3717
|
+
if ('result' in node) {
|
|
3718
|
+
if (decorator.options.onMemoizationDiscrepancy) {
|
|
3719
|
+
const wasVerification = decorator.options.isVerificationRun;
|
|
3720
|
+
decorator.options.isVerificationRun = true;
|
|
3721
|
+
try {
|
|
3722
|
+
const fresh = untracked(() => fn(...localArgs));
|
|
3723
|
+
if (!decorator.deepCompare(node.result, fresh)) {
|
|
3724
|
+
decorator.options.onMemoizationDiscrepancy(node.result, fresh, fn, localArgs, 'calculation');
|
|
3725
|
+
}
|
|
3726
|
+
}
|
|
3727
|
+
finally {
|
|
3728
|
+
decorator.options.isVerificationRun = wasVerification;
|
|
3729
|
+
}
|
|
3730
|
+
}
|
|
3871
3731
|
return node.result;
|
|
3732
|
+
}
|
|
3872
3733
|
// Create memoize internal effect to track dependencies and invalidate cache
|
|
3873
3734
|
// Use untracked to prevent the effect creation from being affected by parent effects
|
|
3874
|
-
node.cleanup = root(() => effect(
|
|
3735
|
+
node.cleanup = root(() => effect(() => {
|
|
3875
3736
|
// Execute the function and track its dependencies
|
|
3876
3737
|
// The function execution will automatically track dependencies on reactive objects
|
|
3877
3738
|
node.result = fn(...localArgs);
|
|
@@ -3879,8 +3740,27 @@ function memoizeFunction(fn) {
|
|
|
3879
3740
|
// When dependencies change, clear the cache and notify consumers
|
|
3880
3741
|
delete node.result;
|
|
3881
3742
|
touched1(node, { type: 'invalidate', prop: localArgs }, 'memoize');
|
|
3743
|
+
// Lazy memoization: stop the effect so it doesn't re-run immediately.
|
|
3744
|
+
// It will be re-created on next access.
|
|
3745
|
+
if (node.cleanup) {
|
|
3746
|
+
node.cleanup();
|
|
3747
|
+
node.cleanup = undefined;
|
|
3748
|
+
}
|
|
3882
3749
|
};
|
|
3883
|
-
},
|
|
3750
|
+
}, { opaque: true }));
|
|
3751
|
+
if (decorator.options.onMemoizationDiscrepancy) {
|
|
3752
|
+
const wasVerification = decorator.options.isVerificationRun;
|
|
3753
|
+
decorator.options.isVerificationRun = true;
|
|
3754
|
+
try {
|
|
3755
|
+
const fresh = untracked(() => fn(...localArgs));
|
|
3756
|
+
if (!decorator.deepCompare(node.result, fresh)) {
|
|
3757
|
+
decorator.options.onMemoizationDiscrepancy(node.result, fresh, fn, localArgs, 'comparison');
|
|
3758
|
+
}
|
|
3759
|
+
}
|
|
3760
|
+
finally {
|
|
3761
|
+
decorator.options.isVerificationRun = wasVerification;
|
|
3762
|
+
}
|
|
3763
|
+
}
|
|
3884
3764
|
return node.result;
|
|
3885
3765
|
}, fn);
|
|
3886
3766
|
memoizedRegistry.set(fnRoot, memoized);
|
|
@@ -3888,19 +3768,37 @@ function memoizeFunction(fn) {
|
|
|
3888
3768
|
return memoized;
|
|
3889
3769
|
}
|
|
3890
3770
|
const memoize = decorator.decorator({
|
|
3891
|
-
getter(original, propertyKey) {
|
|
3892
|
-
const memoized = memoizeFunction(markWithRoot(decorator.renamed((that) => {
|
|
3893
|
-
return original.call(that);
|
|
3894
|
-
}, `${String(this.constructor.name)}.${String(propertyKey)}`), original));
|
|
3771
|
+
getter(original, target, propertyKey) {
|
|
3895
3772
|
return function () {
|
|
3773
|
+
let wrapper = wrapperRegistry.get(original);
|
|
3774
|
+
if (!wrapper) {
|
|
3775
|
+
wrapper = markWithRoot(decorator.renamed((that) => {
|
|
3776
|
+
return original.call(that);
|
|
3777
|
+
}, `${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(propertyKey)}`), {
|
|
3778
|
+
method: original,
|
|
3779
|
+
propertyKey,
|
|
3780
|
+
...(original[decorator.rootFunction] ? { [decorator.rootFunction]: original[decorator.rootFunction] } : {}),
|
|
3781
|
+
});
|
|
3782
|
+
wrapperRegistry.set(original, wrapper);
|
|
3783
|
+
}
|
|
3784
|
+
const memoized = memoizeFunction(wrapper);
|
|
3896
3785
|
return memoized(this);
|
|
3897
3786
|
};
|
|
3898
3787
|
},
|
|
3899
|
-
method(original, name) {
|
|
3900
|
-
const memoized = memoizeFunction(markWithRoot(decorator.renamed((that, ...args) => {
|
|
3901
|
-
return original.call(that, ...args);
|
|
3902
|
-
}, `${String(this.constructor.name)}.${String(name)}`), original));
|
|
3788
|
+
method(original, target, name) {
|
|
3903
3789
|
return function (...args) {
|
|
3790
|
+
let wrapper = wrapperRegistry.get(original);
|
|
3791
|
+
if (!wrapper) {
|
|
3792
|
+
wrapper = markWithRoot(decorator.renamed((that, ...args) => {
|
|
3793
|
+
return original.call(that, ...args);
|
|
3794
|
+
}, `${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(name)}`), {
|
|
3795
|
+
method: original,
|
|
3796
|
+
propertyKey: name,
|
|
3797
|
+
...(original[decorator.rootFunction] ? { [decorator.rootFunction]: original[decorator.rootFunction] } : {}),
|
|
3798
|
+
});
|
|
3799
|
+
wrapperRegistry.set(original, wrapper);
|
|
3800
|
+
}
|
|
3801
|
+
const memoized = memoizeFunction(wrapper);
|
|
3904
3802
|
return memoized(this, ...args);
|
|
3905
3803
|
};
|
|
3906
3804
|
},
|
|
@@ -3962,7 +3860,7 @@ let RegisterClass = (() => {
|
|
|
3962
3860
|
_tslib.__classPrivateFieldSet(this, _RegisterClass_keys, reactive([]), "f");
|
|
3963
3861
|
_tslib.__classPrivateFieldSet(this, _RegisterClass_values, reactive(new Map()), "f");
|
|
3964
3862
|
Object.defineProperties(this, {
|
|
3965
|
-
[prototypeForwarding]: { value: _tslib.__classPrivateFieldGet(this, _RegisterClass_keys, "f") },
|
|
3863
|
+
[decorator.prototypeForwarding]: { value: _tslib.__classPrivateFieldGet(this, _RegisterClass_keys, "f") },
|
|
3966
3864
|
});
|
|
3967
3865
|
if (initial)
|
|
3968
3866
|
this.push(...initial);
|
|
@@ -4331,7 +4229,7 @@ function defineAccessValue(access) {
|
|
|
4331
4229
|
}
|
|
4332
4230
|
function makeCleanup(target, effectMap, onDispose, metadata) {
|
|
4333
4231
|
if (metadata) {
|
|
4334
|
-
Object.defineProperty(target, projectionInfo, {
|
|
4232
|
+
Object.defineProperty(target, decorator.projectionInfo, {
|
|
4335
4233
|
value: metadata,
|
|
4336
4234
|
writable: false,
|
|
4337
4235
|
enumerable: false,
|
|
@@ -4738,7 +4636,7 @@ class ReactiveWeakMap {
|
|
|
4738
4636
|
constructor(original) {
|
|
4739
4637
|
Object.defineProperties(this, {
|
|
4740
4638
|
[native$1]: { value: original },
|
|
4741
|
-
[prototypeForwarding]: { value: original },
|
|
4639
|
+
[decorator.prototypeForwarding]: { value: original },
|
|
4742
4640
|
content: { value: Symbol('WeakMapContent') },
|
|
4743
4641
|
[Symbol.toStringTag]: { value: 'ReactiveWeakMap' },
|
|
4744
4642
|
});
|
|
@@ -4778,7 +4676,7 @@ class ReactiveMap {
|
|
|
4778
4676
|
constructor(original) {
|
|
4779
4677
|
Object.defineProperties(this, {
|
|
4780
4678
|
[native$1]: { value: original },
|
|
4781
|
-
[prototypeForwarding]: { value: original },
|
|
4679
|
+
[decorator.prototypeForwarding]: { value: original },
|
|
4782
4680
|
content: { value: Symbol('MapContent') },
|
|
4783
4681
|
[Symbol.toStringTag]: { value: 'ReactiveMap' },
|
|
4784
4682
|
});
|
|
@@ -4873,7 +4771,7 @@ class ReactiveWeakSet {
|
|
|
4873
4771
|
constructor(original) {
|
|
4874
4772
|
Object.defineProperties(this, {
|
|
4875
4773
|
[native]: { value: original },
|
|
4876
|
-
[prototypeForwarding]: { value: original },
|
|
4774
|
+
[decorator.prototypeForwarding]: { value: original },
|
|
4877
4775
|
content: { value: Symbol('WeakSetContent') },
|
|
4878
4776
|
[Symbol.toStringTag]: { value: 'ReactiveWeakSet' },
|
|
4879
4777
|
});
|
|
@@ -4908,7 +4806,7 @@ class ReactiveSet {
|
|
|
4908
4806
|
constructor(original) {
|
|
4909
4807
|
Object.defineProperties(this, {
|
|
4910
4808
|
[native]: { value: original },
|
|
4911
|
-
[prototypeForwarding]: { value: original },
|
|
4809
|
+
[decorator.prototypeForwarding]: { value: original },
|
|
4912
4810
|
content: { value: Symbol('SetContent') },
|
|
4913
4811
|
[Symbol.toStringTag]: { value: 'ReactiveSet' },
|
|
4914
4812
|
});
|
|
@@ -5008,7 +4906,6 @@ const profileInfo = {
|
|
|
5008
4906
|
exports.IterableWeakMap = IterableWeakMap;
|
|
5009
4907
|
exports.IterableWeakSet = IterableWeakSet;
|
|
5010
4908
|
exports.ReactiveBase = ReactiveBase;
|
|
5011
|
-
exports.ReactiveError = ReactiveError;
|
|
5012
4909
|
exports.ReadOnlyError = ReadOnlyError;
|
|
5013
4910
|
exports.Register = Register;
|
|
5014
4911
|
exports.addBatchCleanup = addBatchCleanup;
|
|
@@ -5035,7 +4932,6 @@ exports.isZoneEnabled = isZoneEnabled;
|
|
|
5035
4932
|
exports.mapped = mapped;
|
|
5036
4933
|
exports.memoize = memoize;
|
|
5037
4934
|
exports.mixin = mixin;
|
|
5038
|
-
exports.options = options;
|
|
5039
4935
|
exports.organize = organize;
|
|
5040
4936
|
exports.organized = organized;
|
|
5041
4937
|
exports.profileInfo = profileInfo;
|
|
@@ -5057,4 +4953,4 @@ exports.unreactive = unreactive;
|
|
|
5057
4953
|
exports.untracked = untracked;
|
|
5058
4954
|
exports.unwrap = unwrap;
|
|
5059
4955
|
exports.watch = watch;
|
|
5060
|
-
//# sourceMappingURL=index-
|
|
4956
|
+
//# sourceMappingURL=index-CDCOjzTy.js.map
|