mutts 1.0.4 → 1.0.5

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.
Files changed (39) hide show
  1. package/README.md +1 -1
  2. package/dist/chunks/{index-GRBSx0mB.js → index-Cvxdw6Ax.js} +164 -12
  3. package/dist/chunks/index-Cvxdw6Ax.js.map +1 -0
  4. package/dist/chunks/{index-79Kk8D6e.esm.js → index-qiWwozOc.esm.js} +163 -13
  5. package/dist/chunks/index-qiWwozOc.esm.js.map +1 -0
  6. package/dist/destroyable.esm.js.map +1 -1
  7. package/dist/destroyable.js.map +1 -1
  8. package/dist/index.esm.js +1 -1
  9. package/dist/index.js +3 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/mutts.umd.js +1 -1
  12. package/dist/mutts.umd.js.map +1 -1
  13. package/dist/mutts.umd.min.js +1 -1
  14. package/dist/mutts.umd.min.js.map +1 -1
  15. package/dist/reactive.d.ts +29 -1
  16. package/dist/reactive.esm.js +1 -1
  17. package/dist/reactive.js +3 -1
  18. package/dist/reactive.js.map +1 -1
  19. package/dist/std-decorators.esm.js.map +1 -1
  20. package/dist/std-decorators.js.map +1 -1
  21. package/docs/reactive/core.md +16 -16
  22. package/docs/reactive.md +7 -0
  23. package/package.json +1 -1
  24. package/src/destroyable.ts +2 -2
  25. package/src/reactive/array.ts +3 -5
  26. package/src/reactive/change.ts +6 -2
  27. package/src/reactive/effects.ts +70 -1
  28. package/src/reactive/index.ts +2 -1
  29. package/src/reactive/interface.ts +1 -1
  30. package/src/reactive/map.ts +6 -6
  31. package/src/reactive/mapped.ts +2 -3
  32. package/src/reactive/project.ts +103 -6
  33. package/src/reactive/set.ts +6 -6
  34. package/src/reactive/types.ts +22 -0
  35. package/src/reactive/zone.ts +1 -1
  36. package/src/std-decorators.ts +1 -1
  37. package/dist/chunks/index-79Kk8D6e.esm.js.map +0 -1
  38. package/dist/chunks/index-GRBSx0mB.js.map +0 -1
  39. /package/{src/reactive/project.project.md → docs/reactive/project.md} +0 -0
@@ -107,6 +107,16 @@ type State = {
107
107
  evolution: Evolution;
108
108
  next: State;
109
109
  } | {};
110
+ /**
111
+ * Context for a running projection item effect
112
+ */
113
+ interface ProjectionContext {
114
+ source: any;
115
+ key?: any;
116
+ target: any;
117
+ depth: number;
118
+ parent?: ProjectionContext;
119
+ }
110
120
  /**
111
121
  * Structured error codes for machine-readable diagnosis
112
122
  */
@@ -196,6 +206,12 @@ declare const options: {
196
206
  * @default 100
197
207
  */
198
208
  maxEffectChain: number;
209
+ /**
210
+ * Maximum number of times an effect can be triggered by the same cause in a single batch
211
+ * Used to detect aggressive re-computation or infinite loops
212
+ * @default 10
213
+ */
214
+ maxTriggerPerBatch: number;
199
215
  /**
200
216
  * Debug purpose: maximum effect reaction (like call stack max depth)
201
217
  * Used to prevent infinite loops
@@ -406,6 +422,14 @@ declare function getActiveEffect(): ScopedCallback;
406
422
 
407
423
  type EffectTracking = (obj: any, evolution: Evolution, prop: any) => void;
408
424
 
425
+ interface ActivationRecord {
426
+ effect: ScopedCallback;
427
+ obj: any;
428
+ evolution: Evolution;
429
+ prop: any;
430
+ batchId: number;
431
+ }
432
+ declare function getActivationLog(): Omit<ActivationRecord, "batchId">[];
409
433
  /**
410
434
  * Registers a debug callback that is called when the current effect is triggered by a dependency change
411
435
  *
@@ -674,6 +698,10 @@ type Register<T, K extends PropertyKey = PropertyKey> = RegisterClass<T, K> & T[
674
698
  declare const Register: new <T, K extends PropertyKey = PropertyKey>(keyFn: KeyFunction<T, K>, initial?: Iterable<T>) => Register<T, K>;
675
699
  declare function register<T, K extends PropertyKey = PropertyKey>(keyFn: KeyFunction<T, K>, initial?: Iterable<T>): Register<T, K>;
676
700
 
701
+ /**
702
+ * Returns the projection context of the currently running effect, if any.
703
+ */
704
+ declare function getActiveProjection(): ProjectionContext | undefined;
677
705
  type ProjectOldValue<Target> = Target extends readonly (infer Item)[] ? Item : Target extends Map<any, infer Item> ? Item : Target extends Record<PropertyKey, infer Item> ? Item : unknown;
678
706
  type ProjectAccess<SourceValue, Key, SourceType, Target> = {
679
707
  readonly key: Key;
@@ -853,5 +881,5 @@ declare function isZoneEnabled(): boolean;
853
881
  */
854
882
  declare const profileInfo: any;
855
883
 
856
- export { ReactiveBase, ReactiveError, ReadOnlyError, Register, addBatchCleanup, atomic, batch, biDi, buildReactivityGraph, cleanedBy, cleanup, deepWatch, defer, derived, effect, enableDevTools, getActiveEffect, getState, immutables, isDevtoolsEnabled, isNonReactive, isReactive, isZoneEnabled, mapped, memoize, organize, organized, profileInfo, project, reactive, options as reactiveOptions, reduced, register, registerEffectForDebug, registerNativeReactivity, registerObjectForDebug, root, setEffectName, setObjectName, setZoneEnabled, touched, touched1, trackEffect, unreactive, untracked, unwrap, watch };
884
+ export { ReactiveBase, ReactiveError, ReadOnlyError, Register, addBatchCleanup, atomic, batch, biDi, buildReactivityGraph, cleanedBy, cleanup, deepWatch, defer, derived, effect, enableDevTools, getActivationLog, getActiveEffect, getActiveProjection, getState, immutables, isDevtoolsEnabled, isNonReactive, isReactive, isZoneEnabled, mapped, memoize, organize, organized, profileInfo, project, reactive, options as reactiveOptions, reduced, register, registerEffectForDebug, registerNativeReactivity, registerObjectForDebug, root, setEffectName, setObjectName, setZoneEnabled, touched, touched1, trackEffect, unreactive, untracked, unwrap, watch };
857
885
  export type { DependencyAccess, DependencyFunction, Evolution, Memoizable, ReactivityGraph, ScopedCallback };
@@ -1,4 +1,4 @@
1
- export { M as ReactiveBase, V as ReactiveError, R as ReadOnlyError, S as Register, j as addBatchCleanup, k as atomic, l as batch, n as biDi, c as buildReactivityGraph, y as cleanedBy, z as cleanup, h as deepWatch, o as defer, A as derived, q as effect, e as enableDevTools, u as getActiveEffect, g as getState, G as immutables, i as isDevtoolsEnabled, H as isNonReactive, L as isReactive, W as isZoneEnabled, D as mapped, F as memoize, P as organize, Q as organized, p as profileInfo, K as project, N as reactive, U as reactiveOptions, E as reduced, T as register, r as registerEffectForDebug, J as registerNativeReactivity, d as registerObjectForDebug, v as root, s as setEffectName, f as setObjectName, X as setZoneEnabled, t as touched, b as touched1, w as trackEffect, B as unreactive, x as untracked, O as unwrap, C as watch } from './chunks/index-79Kk8D6e.esm.js';
1
+ export { O as ReactiveBase, X as ReactiveError, R as ReadOnlyError, U as Register, j as addBatchCleanup, k as atomic, l as batch, n as biDi, c as buildReactivityGraph, z as cleanedBy, A as cleanup, h as deepWatch, o as defer, B as derived, q as effect, e as enableDevTools, u as getActivationLog, v as getActiveEffect, L as getActiveProjection, g as getState, H as immutables, i as isDevtoolsEnabled, J as isNonReactive, N as isReactive, Y as isZoneEnabled, E as mapped, G as memoize, S as organize, T as organized, p as profileInfo, M as project, P as reactive, W as reactiveOptions, F as reduced, V as register, r as registerEffectForDebug, K as registerNativeReactivity, d as registerObjectForDebug, w as root, s as setEffectName, f as setObjectName, Z as setZoneEnabled, t as touched, b as touched1, x as trackEffect, C as unreactive, y as untracked, Q as unwrap, D as watch } from './chunks/index-qiWwozOc.esm.js';
2
2
  import './chunks/decorator-DqiszP7i.esm.js';
3
3
  import './indexable.esm.js';
4
4
  import './chunks/_tslib-Mzh1rNsX.esm.js';
package/dist/reactive.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var reactive = require('./chunks/index-GRBSx0mB.js');
3
+ var reactive = require('./chunks/index-Cvxdw6Ax.js');
4
4
  require('./chunks/decorator-DLvrD0UF.js');
5
5
  require('./indexable.js');
6
6
  require('./chunks/_tslib-BgjropY9.js');
@@ -23,7 +23,9 @@ exports.defer = reactive.defer;
23
23
  exports.derived = reactive.derived;
24
24
  exports.effect = reactive.effect;
25
25
  exports.enableDevTools = reactive.enableDevTools;
26
+ exports.getActivationLog = reactive.getActivationLog;
26
27
  exports.getActiveEffect = reactive.getActiveEffect;
28
+ exports.getActiveProjection = reactive.getActiveProjection;
27
29
  exports.getState = reactive.getState;
28
30
  exports.immutables = reactive.immutables;
29
31
  exports.isDevtoolsEnabled = reactive.isDevtoolsEnabled;
@@ -1 +1 @@
1
- {"version":3,"file":"reactive.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"reactive.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"std-decorators.esm.js","sources":["../src/std-decorators.ts"],"sourcesContent":["import { decorator, GenericClassDecorator } from './decorator'\n\n// In order to avoid async re-entrance, we could use zone.js or something like that.\nconst syncCalculating: { object: object; prop: PropertyKey }[] = []\n/**\n * Decorator that caches the result of a getter method and only recomputes when dependencies change\n * Prevents circular dependencies and provides automatic cache invalidation\n */\nexport const cached = decorator({\n\tgetter(original, propertyKey) {\n\t\treturn function (this: any) {\n\t\t\tconst alreadyCalculating = syncCalculating.findIndex(\n\t\t\t\t(c) => c.object === this && c.prop === propertyKey\n\t\t\t)\n\t\t\tif (alreadyCalculating > -1)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Circular dependency detected: ${syncCalculating\n\t\t\t\t\t\t.slice(alreadyCalculating)\n\t\t\t\t\t\t.map((c) => `${c.object.constructor.name}.${String(c.prop)}`)\n\t\t\t\t\t\t.join(' -> ')} -> again`\n\t\t\t\t)\n\t\t\tsyncCalculating.push({ object: this, prop: propertyKey })\n\t\t\ttry {\n\t\t\t\tconst rv = original.call(this)\n\t\t\t\tcache(this, propertyKey, rv)\n\t\t\t\treturn rv\n\t\t\t} finally {\n\t\t\t\tsyncCalculating.pop()\n\t\t\t}\n\t\t}\n\t},\n})\n\n/**\n * Checks if a property is cached (has a cached value)\n * @param object - The object to check\n * @param propertyKey - The property key to check\n * @returns True if the property has a cached value\n */\nexport function isCached(object: Object, propertyKey: PropertyKey) {\n\treturn !!Object.getOwnPropertyDescriptor(object, propertyKey)\n}\n\n/**\n * Caches a value for a property on an object\n * @param object - The object to cache the value on\n * @param propertyKey - The property key to cache\n * @param value - The value to cache\n */\nexport function cache(object: Object, propertyKey: PropertyKey, value: any) {\n\tObject.defineProperty(object, propertyKey, { value })\n}\n\n/**\n * Creates a decorator that modifies property descriptors for specified properties\n * @param descriptor - The descriptor properties to apply\n * @returns A class decorator that applies the descriptor to specified properties\n */\nexport function describe(descriptor: {\n\tenumerable?: boolean\n\tconfigurable?: boolean // Not modifiable once the property has been defined ?\n\twritable?: boolean\n}) {\n\treturn <T>(...properties: (keyof T)[]): GenericClassDecorator<T> =>\n\t\t(Base) => {\n\t\t\treturn class extends Base {\n\t\t\t\tconstructor(...args: any[]) {\n\t\t\t\t\tsuper(...args)\n\t\t\t\t\tfor (const key of properties) {\n\t\t\t\t\t\tObject.defineProperty(this, key, {\n\t\t\t\t\t\t\t...Object.getOwnPropertyDescriptor(this, key),\n\t\t\t\t\t\t\t...descriptor,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n}\n\n/**\n * Decorator that marks methods, properties, or classes as deprecated\n * Provides warning messages when deprecated items are used\n */\nexport const deprecated = Object.assign(\n\tdecorator({\n\t\tmethod(original, propertyKey) {\n\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\tdeprecated.warn(this, propertyKey)\n\t\t\t\treturn original.apply(this, args)\n\t\t\t}\n\t\t},\n\t\tgetter(original, propertyKey) {\n\t\t\treturn function (this: any) {\n\t\t\t\tdeprecated.warn(this, propertyKey)\n\t\t\t\treturn original.call(this)\n\t\t\t}\n\t\t},\n\t\tsetter(original, propertyKey) {\n\t\t\treturn function (this: any, value: any) {\n\t\t\t\tdeprecated.warn(this, propertyKey)\n\t\t\t\treturn original.call(this, value)\n\t\t\t}\n\t\t},\n\t\tclass(original) {\n\t\t\treturn class extends original {\n\t\t\t\tconstructor(...args: any[]) {\n\t\t\t\t\tsuper(...args)\n\t\t\t\t\tdeprecated.warn(this, 'constructor')\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tdefault(message: string) {\n\t\t\treturn decorator({\n\t\t\t\tmethod(original, propertyKey) {\n\t\t\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\t\t\tdeprecated.warn(this, propertyKey, message)\n\t\t\t\t\t\treturn original.apply(this, args)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tgetter(original, propertyKey) {\n\t\t\t\t\treturn function (this: any) {\n\t\t\t\t\t\tdeprecated.warn(this, propertyKey, message)\n\t\t\t\t\t\treturn original.call(this)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tsetter(original, propertyKey) {\n\t\t\t\t\treturn function (this: any, value: any) {\n\t\t\t\t\t\tdeprecated.warn(this, propertyKey, message)\n\t\t\t\t\t\treturn original.call(this, value)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tclass(original) {\n\t\t\t\t\treturn class extends original {\n\t\t\t\t\t\tconstructor(...args: any[]) {\n\t\t\t\t\t\t\tsuper(...args)\n\t\t\t\t\t\t\tdeprecated.warn(this, 'constructor', message)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t})\n\t\t},\n\t}),\n\t{\n\t\twarn: (target: any, propertyKey: PropertyKey, message?: string) => {\n\t\t\t// biome-ignore lint/suspicious/noConsole: To be overridden\n\t\t\tconsole.warn(\n\t\t\t\t`${target.constructor.name}.${String(propertyKey)} is deprecated${message ? `: ${message}` : ''}`\n\t\t\t)\n\t\t},\n\t}\n)\n\n/**\n * Creates a debounced method decorator that delays execution until after the delay period has passed\n * @param delay - The delay in milliseconds\n * @returns A method decorator that debounces method calls\n */\nexport function debounce(delay: number) {\n\treturn decorator({\n\t\tmethod(original, _propertyKey) {\n\t\t\tlet timeoutId: ReturnType<typeof setTimeout> | null = null\n\n\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\t// Clear existing timeout\n\t\t\t\tif (timeoutId) {\n\t\t\t\t\tclearTimeout(timeoutId)\n\t\t\t\t}\n\n\t\t\t\t// Set new timeout\n\t\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\t\toriginal.apply(this, args)\n\t\t\t\t\ttimeoutId = null\n\t\t\t\t}, delay)\n\t\t\t}\n\t\t},\n\t})\n}\n\n/**\n * Creates a throttled method decorator that limits execution to once per delay period\n * @param delay - The delay in milliseconds\n * @returns A method decorator that throttles method calls\n */\nexport function throttle(delay: number) {\n\treturn decorator({\n\t\tmethod(original, _propertyKey) {\n\t\t\tlet lastCallTime = 0\n\t\t\tlet timeoutId: ReturnType<typeof setTimeout> | null = null\n\n\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\tconst now = Date.now()\n\n\t\t\t\t// If enough time has passed since last call, execute immediately\n\t\t\t\tif (now - lastCallTime >= delay) {\n\t\t\t\t\t// Clear any pending timeout since we're executing now\n\t\t\t\t\tif (timeoutId) {\n\t\t\t\t\t\tclearTimeout(timeoutId)\n\t\t\t\t\t\ttimeoutId = null\n\t\t\t\t\t}\n\t\t\t\t\tlastCallTime = now\n\t\t\t\t\treturn original.apply(this, args)\n\t\t\t\t}\n\n\t\t\t\t// Otherwise, schedule execution for when the delay period ends\n\t\t\t\tif (!timeoutId) {\n\t\t\t\t\tconst remainingTime = delay - (now - lastCallTime)\n\t\t\t\t\tconst scheduledArgs = [...args] // Capture args at scheduling time\n\t\t\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\t\t\tlastCallTime = Date.now()\n\t\t\t\t\t\toriginal.apply(this, scheduledArgs)\n\t\t\t\t\t\ttimeoutId = null\n\t\t\t\t\t}, remainingTime)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t})\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"std-decorators.esm.js","sources":["../src/std-decorators.ts"],"sourcesContent":["import { decorator, type GenericClassDecorator } from './decorator'\n\n// In order to avoid async re-entrance, we could use zone.js or something like that.\nconst syncCalculating: { object: object; prop: PropertyKey }[] = []\n/**\n * Decorator that caches the result of a getter method and only recomputes when dependencies change\n * Prevents circular dependencies and provides automatic cache invalidation\n */\nexport const cached = decorator({\n\tgetter(original, propertyKey) {\n\t\treturn function (this: any) {\n\t\t\tconst alreadyCalculating = syncCalculating.findIndex(\n\t\t\t\t(c) => c.object === this && c.prop === propertyKey\n\t\t\t)\n\t\t\tif (alreadyCalculating > -1)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Circular dependency detected: ${syncCalculating\n\t\t\t\t\t\t.slice(alreadyCalculating)\n\t\t\t\t\t\t.map((c) => `${c.object.constructor.name}.${String(c.prop)}`)\n\t\t\t\t\t\t.join(' -> ')} -> again`\n\t\t\t\t)\n\t\t\tsyncCalculating.push({ object: this, prop: propertyKey })\n\t\t\ttry {\n\t\t\t\tconst rv = original.call(this)\n\t\t\t\tcache(this, propertyKey, rv)\n\t\t\t\treturn rv\n\t\t\t} finally {\n\t\t\t\tsyncCalculating.pop()\n\t\t\t}\n\t\t}\n\t},\n})\n\n/**\n * Checks if a property is cached (has a cached value)\n * @param object - The object to check\n * @param propertyKey - The property key to check\n * @returns True if the property has a cached value\n */\nexport function isCached(object: Object, propertyKey: PropertyKey) {\n\treturn !!Object.getOwnPropertyDescriptor(object, propertyKey)\n}\n\n/**\n * Caches a value for a property on an object\n * @param object - The object to cache the value on\n * @param propertyKey - The property key to cache\n * @param value - The value to cache\n */\nexport function cache(object: Object, propertyKey: PropertyKey, value: any) {\n\tObject.defineProperty(object, propertyKey, { value })\n}\n\n/**\n * Creates a decorator that modifies property descriptors for specified properties\n * @param descriptor - The descriptor properties to apply\n * @returns A class decorator that applies the descriptor to specified properties\n */\nexport function describe(descriptor: {\n\tenumerable?: boolean\n\tconfigurable?: boolean // Not modifiable once the property has been defined ?\n\twritable?: boolean\n}) {\n\treturn <T>(...properties: (keyof T)[]): GenericClassDecorator<T> =>\n\t\t(Base) => {\n\t\t\treturn class extends Base {\n\t\t\t\tconstructor(...args: any[]) {\n\t\t\t\t\tsuper(...args)\n\t\t\t\t\tfor (const key of properties) {\n\t\t\t\t\t\tObject.defineProperty(this, key, {\n\t\t\t\t\t\t\t...Object.getOwnPropertyDescriptor(this, key),\n\t\t\t\t\t\t\t...descriptor,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n}\n\n/**\n * Decorator that marks methods, properties, or classes as deprecated\n * Provides warning messages when deprecated items are used\n */\nexport const deprecated = Object.assign(\n\tdecorator({\n\t\tmethod(original, propertyKey) {\n\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\tdeprecated.warn(this, propertyKey)\n\t\t\t\treturn original.apply(this, args)\n\t\t\t}\n\t\t},\n\t\tgetter(original, propertyKey) {\n\t\t\treturn function (this: any) {\n\t\t\t\tdeprecated.warn(this, propertyKey)\n\t\t\t\treturn original.call(this)\n\t\t\t}\n\t\t},\n\t\tsetter(original, propertyKey) {\n\t\t\treturn function (this: any, value: any) {\n\t\t\t\tdeprecated.warn(this, propertyKey)\n\t\t\t\treturn original.call(this, value)\n\t\t\t}\n\t\t},\n\t\tclass(original) {\n\t\t\treturn class extends original {\n\t\t\t\tconstructor(...args: any[]) {\n\t\t\t\t\tsuper(...args)\n\t\t\t\t\tdeprecated.warn(this, 'constructor')\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tdefault(message: string) {\n\t\t\treturn decorator({\n\t\t\t\tmethod(original, propertyKey) {\n\t\t\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\t\t\tdeprecated.warn(this, propertyKey, message)\n\t\t\t\t\t\treturn original.apply(this, args)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tgetter(original, propertyKey) {\n\t\t\t\t\treturn function (this: any) {\n\t\t\t\t\t\tdeprecated.warn(this, propertyKey, message)\n\t\t\t\t\t\treturn original.call(this)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tsetter(original, propertyKey) {\n\t\t\t\t\treturn function (this: any, value: any) {\n\t\t\t\t\t\tdeprecated.warn(this, propertyKey, message)\n\t\t\t\t\t\treturn original.call(this, value)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tclass(original) {\n\t\t\t\t\treturn class extends original {\n\t\t\t\t\t\tconstructor(...args: any[]) {\n\t\t\t\t\t\t\tsuper(...args)\n\t\t\t\t\t\t\tdeprecated.warn(this, 'constructor', message)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t})\n\t\t},\n\t}),\n\t{\n\t\twarn: (target: any, propertyKey: PropertyKey, message?: string) => {\n\t\t\t// biome-ignore lint/suspicious/noConsole: To be overridden\n\t\t\tconsole.warn(\n\t\t\t\t`${target.constructor.name}.${String(propertyKey)} is deprecated${message ? `: ${message}` : ''}`\n\t\t\t)\n\t\t},\n\t}\n)\n\n/**\n * Creates a debounced method decorator that delays execution until after the delay period has passed\n * @param delay - The delay in milliseconds\n * @returns A method decorator that debounces method calls\n */\nexport function debounce(delay: number) {\n\treturn decorator({\n\t\tmethod(original, _propertyKey) {\n\t\t\tlet timeoutId: ReturnType<typeof setTimeout> | null = null\n\n\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\t// Clear existing timeout\n\t\t\t\tif (timeoutId) {\n\t\t\t\t\tclearTimeout(timeoutId)\n\t\t\t\t}\n\n\t\t\t\t// Set new timeout\n\t\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\t\toriginal.apply(this, args)\n\t\t\t\t\ttimeoutId = null\n\t\t\t\t}, delay)\n\t\t\t}\n\t\t},\n\t})\n}\n\n/**\n * Creates a throttled method decorator that limits execution to once per delay period\n * @param delay - The delay in milliseconds\n * @returns A method decorator that throttles method calls\n */\nexport function throttle(delay: number) {\n\treturn decorator({\n\t\tmethod(original, _propertyKey) {\n\t\t\tlet lastCallTime = 0\n\t\t\tlet timeoutId: ReturnType<typeof setTimeout> | null = null\n\n\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\tconst now = Date.now()\n\n\t\t\t\t// If enough time has passed since last call, execute immediately\n\t\t\t\tif (now - lastCallTime >= delay) {\n\t\t\t\t\t// Clear any pending timeout since we're executing now\n\t\t\t\t\tif (timeoutId) {\n\t\t\t\t\t\tclearTimeout(timeoutId)\n\t\t\t\t\t\ttimeoutId = null\n\t\t\t\t\t}\n\t\t\t\t\tlastCallTime = now\n\t\t\t\t\treturn original.apply(this, args)\n\t\t\t\t}\n\n\t\t\t\t// Otherwise, schedule execution for when the delay period ends\n\t\t\t\tif (!timeoutId) {\n\t\t\t\t\tconst remainingTime = delay - (now - lastCallTime)\n\t\t\t\t\tconst scheduledArgs = [...args] // Capture args at scheduling time\n\t\t\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\t\t\tlastCallTime = Date.now()\n\t\t\t\t\t\toriginal.apply(this, scheduledArgs)\n\t\t\t\t\t\ttimeoutId = null\n\t\t\t\t\t}, remainingTime)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t})\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"std-decorators.js","sources":["../src/std-decorators.ts"],"sourcesContent":["import { decorator, GenericClassDecorator } from './decorator'\n\n// In order to avoid async re-entrance, we could use zone.js or something like that.\nconst syncCalculating: { object: object; prop: PropertyKey }[] = []\n/**\n * Decorator that caches the result of a getter method and only recomputes when dependencies change\n * Prevents circular dependencies and provides automatic cache invalidation\n */\nexport const cached = decorator({\n\tgetter(original, propertyKey) {\n\t\treturn function (this: any) {\n\t\t\tconst alreadyCalculating = syncCalculating.findIndex(\n\t\t\t\t(c) => c.object === this && c.prop === propertyKey\n\t\t\t)\n\t\t\tif (alreadyCalculating > -1)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Circular dependency detected: ${syncCalculating\n\t\t\t\t\t\t.slice(alreadyCalculating)\n\t\t\t\t\t\t.map((c) => `${c.object.constructor.name}.${String(c.prop)}`)\n\t\t\t\t\t\t.join(' -> ')} -> again`\n\t\t\t\t)\n\t\t\tsyncCalculating.push({ object: this, prop: propertyKey })\n\t\t\ttry {\n\t\t\t\tconst rv = original.call(this)\n\t\t\t\tcache(this, propertyKey, rv)\n\t\t\t\treturn rv\n\t\t\t} finally {\n\t\t\t\tsyncCalculating.pop()\n\t\t\t}\n\t\t}\n\t},\n})\n\n/**\n * Checks if a property is cached (has a cached value)\n * @param object - The object to check\n * @param propertyKey - The property key to check\n * @returns True if the property has a cached value\n */\nexport function isCached(object: Object, propertyKey: PropertyKey) {\n\treturn !!Object.getOwnPropertyDescriptor(object, propertyKey)\n}\n\n/**\n * Caches a value for a property on an object\n * @param object - The object to cache the value on\n * @param propertyKey - The property key to cache\n * @param value - The value to cache\n */\nexport function cache(object: Object, propertyKey: PropertyKey, value: any) {\n\tObject.defineProperty(object, propertyKey, { value })\n}\n\n/**\n * Creates a decorator that modifies property descriptors for specified properties\n * @param descriptor - The descriptor properties to apply\n * @returns A class decorator that applies the descriptor to specified properties\n */\nexport function describe(descriptor: {\n\tenumerable?: boolean\n\tconfigurable?: boolean // Not modifiable once the property has been defined ?\n\twritable?: boolean\n}) {\n\treturn <T>(...properties: (keyof T)[]): GenericClassDecorator<T> =>\n\t\t(Base) => {\n\t\t\treturn class extends Base {\n\t\t\t\tconstructor(...args: any[]) {\n\t\t\t\t\tsuper(...args)\n\t\t\t\t\tfor (const key of properties) {\n\t\t\t\t\t\tObject.defineProperty(this, key, {\n\t\t\t\t\t\t\t...Object.getOwnPropertyDescriptor(this, key),\n\t\t\t\t\t\t\t...descriptor,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n}\n\n/**\n * Decorator that marks methods, properties, or classes as deprecated\n * Provides warning messages when deprecated items are used\n */\nexport const deprecated = Object.assign(\n\tdecorator({\n\t\tmethod(original, propertyKey) {\n\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\tdeprecated.warn(this, propertyKey)\n\t\t\t\treturn original.apply(this, args)\n\t\t\t}\n\t\t},\n\t\tgetter(original, propertyKey) {\n\t\t\treturn function (this: any) {\n\t\t\t\tdeprecated.warn(this, propertyKey)\n\t\t\t\treturn original.call(this)\n\t\t\t}\n\t\t},\n\t\tsetter(original, propertyKey) {\n\t\t\treturn function (this: any, value: any) {\n\t\t\t\tdeprecated.warn(this, propertyKey)\n\t\t\t\treturn original.call(this, value)\n\t\t\t}\n\t\t},\n\t\tclass(original) {\n\t\t\treturn class extends original {\n\t\t\t\tconstructor(...args: any[]) {\n\t\t\t\t\tsuper(...args)\n\t\t\t\t\tdeprecated.warn(this, 'constructor')\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tdefault(message: string) {\n\t\t\treturn decorator({\n\t\t\t\tmethod(original, propertyKey) {\n\t\t\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\t\t\tdeprecated.warn(this, propertyKey, message)\n\t\t\t\t\t\treturn original.apply(this, args)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tgetter(original, propertyKey) {\n\t\t\t\t\treturn function (this: any) {\n\t\t\t\t\t\tdeprecated.warn(this, propertyKey, message)\n\t\t\t\t\t\treturn original.call(this)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tsetter(original, propertyKey) {\n\t\t\t\t\treturn function (this: any, value: any) {\n\t\t\t\t\t\tdeprecated.warn(this, propertyKey, message)\n\t\t\t\t\t\treturn original.call(this, value)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tclass(original) {\n\t\t\t\t\treturn class extends original {\n\t\t\t\t\t\tconstructor(...args: any[]) {\n\t\t\t\t\t\t\tsuper(...args)\n\t\t\t\t\t\t\tdeprecated.warn(this, 'constructor', message)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t})\n\t\t},\n\t}),\n\t{\n\t\twarn: (target: any, propertyKey: PropertyKey, message?: string) => {\n\t\t\t// biome-ignore lint/suspicious/noConsole: To be overridden\n\t\t\tconsole.warn(\n\t\t\t\t`${target.constructor.name}.${String(propertyKey)} is deprecated${message ? `: ${message}` : ''}`\n\t\t\t)\n\t\t},\n\t}\n)\n\n/**\n * Creates a debounced method decorator that delays execution until after the delay period has passed\n * @param delay - The delay in milliseconds\n * @returns A method decorator that debounces method calls\n */\nexport function debounce(delay: number) {\n\treturn decorator({\n\t\tmethod(original, _propertyKey) {\n\t\t\tlet timeoutId: ReturnType<typeof setTimeout> | null = null\n\n\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\t// Clear existing timeout\n\t\t\t\tif (timeoutId) {\n\t\t\t\t\tclearTimeout(timeoutId)\n\t\t\t\t}\n\n\t\t\t\t// Set new timeout\n\t\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\t\toriginal.apply(this, args)\n\t\t\t\t\ttimeoutId = null\n\t\t\t\t}, delay)\n\t\t\t}\n\t\t},\n\t})\n}\n\n/**\n * Creates a throttled method decorator that limits execution to once per delay period\n * @param delay - The delay in milliseconds\n * @returns A method decorator that throttles method calls\n */\nexport function throttle(delay: number) {\n\treturn decorator({\n\t\tmethod(original, _propertyKey) {\n\t\t\tlet lastCallTime = 0\n\t\t\tlet timeoutId: ReturnType<typeof setTimeout> | null = null\n\n\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\tconst now = Date.now()\n\n\t\t\t\t// If enough time has passed since last call, execute immediately\n\t\t\t\tif (now - lastCallTime >= delay) {\n\t\t\t\t\t// Clear any pending timeout since we're executing now\n\t\t\t\t\tif (timeoutId) {\n\t\t\t\t\t\tclearTimeout(timeoutId)\n\t\t\t\t\t\ttimeoutId = null\n\t\t\t\t\t}\n\t\t\t\t\tlastCallTime = now\n\t\t\t\t\treturn original.apply(this, args)\n\t\t\t\t}\n\n\t\t\t\t// Otherwise, schedule execution for when the delay period ends\n\t\t\t\tif (!timeoutId) {\n\t\t\t\t\tconst remainingTime = delay - (now - lastCallTime)\n\t\t\t\t\tconst scheduledArgs = [...args] // Capture args at scheduling time\n\t\t\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\t\t\tlastCallTime = Date.now()\n\t\t\t\t\t\toriginal.apply(this, scheduledArgs)\n\t\t\t\t\t\ttimeoutId = null\n\t\t\t\t\t}, remainingTime)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t})\n}\n"],"names":["decorator"],"mappings":"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"}
1
+ {"version":3,"file":"std-decorators.js","sources":["../src/std-decorators.ts"],"sourcesContent":["import { decorator, type GenericClassDecorator } from './decorator'\n\n// In order to avoid async re-entrance, we could use zone.js or something like that.\nconst syncCalculating: { object: object; prop: PropertyKey }[] = []\n/**\n * Decorator that caches the result of a getter method and only recomputes when dependencies change\n * Prevents circular dependencies and provides automatic cache invalidation\n */\nexport const cached = decorator({\n\tgetter(original, propertyKey) {\n\t\treturn function (this: any) {\n\t\t\tconst alreadyCalculating = syncCalculating.findIndex(\n\t\t\t\t(c) => c.object === this && c.prop === propertyKey\n\t\t\t)\n\t\t\tif (alreadyCalculating > -1)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Circular dependency detected: ${syncCalculating\n\t\t\t\t\t\t.slice(alreadyCalculating)\n\t\t\t\t\t\t.map((c) => `${c.object.constructor.name}.${String(c.prop)}`)\n\t\t\t\t\t\t.join(' -> ')} -> again`\n\t\t\t\t)\n\t\t\tsyncCalculating.push({ object: this, prop: propertyKey })\n\t\t\ttry {\n\t\t\t\tconst rv = original.call(this)\n\t\t\t\tcache(this, propertyKey, rv)\n\t\t\t\treturn rv\n\t\t\t} finally {\n\t\t\t\tsyncCalculating.pop()\n\t\t\t}\n\t\t}\n\t},\n})\n\n/**\n * Checks if a property is cached (has a cached value)\n * @param object - The object to check\n * @param propertyKey - The property key to check\n * @returns True if the property has a cached value\n */\nexport function isCached(object: Object, propertyKey: PropertyKey) {\n\treturn !!Object.getOwnPropertyDescriptor(object, propertyKey)\n}\n\n/**\n * Caches a value for a property on an object\n * @param object - The object to cache the value on\n * @param propertyKey - The property key to cache\n * @param value - The value to cache\n */\nexport function cache(object: Object, propertyKey: PropertyKey, value: any) {\n\tObject.defineProperty(object, propertyKey, { value })\n}\n\n/**\n * Creates a decorator that modifies property descriptors for specified properties\n * @param descriptor - The descriptor properties to apply\n * @returns A class decorator that applies the descriptor to specified properties\n */\nexport function describe(descriptor: {\n\tenumerable?: boolean\n\tconfigurable?: boolean // Not modifiable once the property has been defined ?\n\twritable?: boolean\n}) {\n\treturn <T>(...properties: (keyof T)[]): GenericClassDecorator<T> =>\n\t\t(Base) => {\n\t\t\treturn class extends Base {\n\t\t\t\tconstructor(...args: any[]) {\n\t\t\t\t\tsuper(...args)\n\t\t\t\t\tfor (const key of properties) {\n\t\t\t\t\t\tObject.defineProperty(this, key, {\n\t\t\t\t\t\t\t...Object.getOwnPropertyDescriptor(this, key),\n\t\t\t\t\t\t\t...descriptor,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n}\n\n/**\n * Decorator that marks methods, properties, or classes as deprecated\n * Provides warning messages when deprecated items are used\n */\nexport const deprecated = Object.assign(\n\tdecorator({\n\t\tmethod(original, propertyKey) {\n\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\tdeprecated.warn(this, propertyKey)\n\t\t\t\treturn original.apply(this, args)\n\t\t\t}\n\t\t},\n\t\tgetter(original, propertyKey) {\n\t\t\treturn function (this: any) {\n\t\t\t\tdeprecated.warn(this, propertyKey)\n\t\t\t\treturn original.call(this)\n\t\t\t}\n\t\t},\n\t\tsetter(original, propertyKey) {\n\t\t\treturn function (this: any, value: any) {\n\t\t\t\tdeprecated.warn(this, propertyKey)\n\t\t\t\treturn original.call(this, value)\n\t\t\t}\n\t\t},\n\t\tclass(original) {\n\t\t\treturn class extends original {\n\t\t\t\tconstructor(...args: any[]) {\n\t\t\t\t\tsuper(...args)\n\t\t\t\t\tdeprecated.warn(this, 'constructor')\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tdefault(message: string) {\n\t\t\treturn decorator({\n\t\t\t\tmethod(original, propertyKey) {\n\t\t\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\t\t\tdeprecated.warn(this, propertyKey, message)\n\t\t\t\t\t\treturn original.apply(this, args)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tgetter(original, propertyKey) {\n\t\t\t\t\treturn function (this: any) {\n\t\t\t\t\t\tdeprecated.warn(this, propertyKey, message)\n\t\t\t\t\t\treturn original.call(this)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tsetter(original, propertyKey) {\n\t\t\t\t\treturn function (this: any, value: any) {\n\t\t\t\t\t\tdeprecated.warn(this, propertyKey, message)\n\t\t\t\t\t\treturn original.call(this, value)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tclass(original) {\n\t\t\t\t\treturn class extends original {\n\t\t\t\t\t\tconstructor(...args: any[]) {\n\t\t\t\t\t\t\tsuper(...args)\n\t\t\t\t\t\t\tdeprecated.warn(this, 'constructor', message)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t})\n\t\t},\n\t}),\n\t{\n\t\twarn: (target: any, propertyKey: PropertyKey, message?: string) => {\n\t\t\t// biome-ignore lint/suspicious/noConsole: To be overridden\n\t\t\tconsole.warn(\n\t\t\t\t`${target.constructor.name}.${String(propertyKey)} is deprecated${message ? `: ${message}` : ''}`\n\t\t\t)\n\t\t},\n\t}\n)\n\n/**\n * Creates a debounced method decorator that delays execution until after the delay period has passed\n * @param delay - The delay in milliseconds\n * @returns A method decorator that debounces method calls\n */\nexport function debounce(delay: number) {\n\treturn decorator({\n\t\tmethod(original, _propertyKey) {\n\t\t\tlet timeoutId: ReturnType<typeof setTimeout> | null = null\n\n\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\t// Clear existing timeout\n\t\t\t\tif (timeoutId) {\n\t\t\t\t\tclearTimeout(timeoutId)\n\t\t\t\t}\n\n\t\t\t\t// Set new timeout\n\t\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\t\toriginal.apply(this, args)\n\t\t\t\t\ttimeoutId = null\n\t\t\t\t}, delay)\n\t\t\t}\n\t\t},\n\t})\n}\n\n/**\n * Creates a throttled method decorator that limits execution to once per delay period\n * @param delay - The delay in milliseconds\n * @returns A method decorator that throttles method calls\n */\nexport function throttle(delay: number) {\n\treturn decorator({\n\t\tmethod(original, _propertyKey) {\n\t\t\tlet lastCallTime = 0\n\t\t\tlet timeoutId: ReturnType<typeof setTimeout> | null = null\n\n\t\t\treturn function (this: any, ...args: any[]) {\n\t\t\t\tconst now = Date.now()\n\n\t\t\t\t// If enough time has passed since last call, execute immediately\n\t\t\t\tif (now - lastCallTime >= delay) {\n\t\t\t\t\t// Clear any pending timeout since we're executing now\n\t\t\t\t\tif (timeoutId) {\n\t\t\t\t\t\tclearTimeout(timeoutId)\n\t\t\t\t\t\ttimeoutId = null\n\t\t\t\t\t}\n\t\t\t\t\tlastCallTime = now\n\t\t\t\t\treturn original.apply(this, args)\n\t\t\t\t}\n\n\t\t\t\t// Otherwise, schedule execution for when the delay period ends\n\t\t\t\tif (!timeoutId) {\n\t\t\t\t\tconst remainingTime = delay - (now - lastCallTime)\n\t\t\t\t\tconst scheduledArgs = [...args] // Capture args at scheduling time\n\t\t\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\t\t\tlastCallTime = Date.now()\n\t\t\t\t\t\toriginal.apply(this, scheduledArgs)\n\t\t\t\t\t\ttimeoutId = null\n\t\t\t\t\t}, remainingTime)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t})\n}\n"],"names":["decorator"],"mappings":"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"}
@@ -7,22 +7,22 @@
7
7
  - [5-Minute Quick Start](#5-minute-quick-start)
8
8
  - [Core API](#core-api)
9
9
  - [Effect System](#effect-system)
10
- - [Atomic Operations](#atomic-operations)
11
- - [Advanced Effects](#advanced-effects)
12
- - [Evolution Tracking](#evolution-tracking)
13
- - [Prototype Chains and Pure Objects](#prototype-chains-and-pure-objects)
14
- - [Recursive Touching](#recursive-touching)
15
- - [Why Not Deep Watching?](#why-not-deep-watching)
16
- - [Collections](#collections)
17
- - [Register](#register)
18
- - [Class Reactivity](#class-reactivity)
19
- - [Non-Reactive System](#non-reactive-system)
20
- - [Array Mapping](#array-mapping)
21
- - [Projection](#projection)
22
- - [Record Organization](#record-organization)
23
- - [Memoization](#memoization)
24
- - [Debugging and Development](#debugging-and-development)
25
- - [Cycle Detection](#cycle-detection)
10
+ - [Atomic Operations](./advanced.md#atomic-operations)
11
+ - [Advanced Effects](./advanced.md#advanced-effects)
12
+ - [Evolution Tracking](./advanced.md#evolution-tracking)
13
+ - [Prototype Chains and Pure Objects](./advanced.md#prototype-chains-and-pure-objects)
14
+ - [Recursive Touching](./advanced.md#recursive-touching)
15
+ - [Why Not Deep Watching?](./advanced.md#why-not-deep-watching)
16
+ - [Collections](./advanced.md#collections)
17
+ - [Register](./advanced.md#register)
18
+ - [Class Reactivity](./advanced.md#class-reactivity)
19
+ - [Non-Reactive System](./advanced.md#non-reactive-system)
20
+ - [Array Mapping](./advanced.md#array-mapping)
21
+ - [Projection](./advanced.md#projection)
22
+ - [Record Organization](./advanced.md#record-organization)
23
+ - [Memoization](./advanced.md#memoization)
24
+ - [Debugging and Development](./advanced.md#debugging-and-development)
25
+ - [Cycle Detection](./advanced.md#cycle-detection)
26
26
 
27
27
  ## Introduction
28
28
 
package/docs/reactive.md CHANGED
@@ -19,3 +19,10 @@ The Mutts Reactive System documentation has been split into focused sections for
19
19
  * **[Prototype Chains](./reactive/advanced.md#prototype-chains-and-pure-objects)**: Advanced inheritance patterns
20
20
  * **[Memoization](./reactive/advanced.md#memoization)**: Caching strategies
21
21
  * **[Debugging](./reactive/advanced.md#debugging-and-development)**: Cycle detection and troubleshooting
22
+
23
+ ## Debugging tools
24
+
25
+ The reactive system is currently in a gamma state. The interface is quite fixed, the debugging tools are in place but :
26
+ - still unfinished
27
+ - not deactivatable
28
+ - harming the performances of the application
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mutts",
3
3
  "description": "Modern UTility TS: A collection of TypeScript utilities",
4
- "version": "1.0.4",
4
+ "version": "1.0.5",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",
7
7
  "types": "dist/index.d.ts",
@@ -117,7 +117,7 @@ export function Destroyable<
117
117
  base = undefined
118
118
  }
119
119
  if (!base) {
120
- base = class {} as T
120
+ base = class { } as T
121
121
  }
122
122
 
123
123
  return class Destroyable extends (base as T) {
@@ -139,7 +139,7 @@ export function Destroyable<
139
139
  return Destroyable.destructors.has(obj)
140
140
  }
141
141
 
142
- declare [forwardProperties]: PropertyKey[]
142
+ [forwardProperties]!: PropertyKey[]
143
143
  readonly [allocatedValues]: Allocated
144
144
  constructor(...args: any[]) {
145
145
  super(...args)
@@ -10,13 +10,12 @@ export const native = Symbol('native')
10
10
  const isArray = Array.isArray
11
11
  Array.isArray = ((value: any) =>
12
12
  isArray(value) ||
13
- // biome-ignore lint/suspicious/useIsArray: We are defining it
14
13
  (value &&
15
14
  typeof value === 'object' &&
16
15
  prototypeForwarding in value &&
17
16
  Array.isArray(value[prototypeForwarding]))) as any
18
17
  export class ReactiveBaseArray {
19
- declare readonly [native]: any[]
18
+ readonly [native]!: any[]
20
19
 
21
20
  // Safe array access with negative indices
22
21
  at(index: number): any {
@@ -293,7 +292,6 @@ export class ReactiveArray extends Indexable(ReactiveBaseArray, {
293
292
  }
294
293
  },
295
294
  }) {
296
- declare length: number
297
295
  constructor(original: any[]) {
298
296
  super()
299
297
  Object.defineProperties(this, {
@@ -364,8 +362,8 @@ export class ReactiveArray extends Indexable(ReactiveBaseArray, {
364
362
  deleteCount === items.length
365
363
  ? range(start, start + deleteCount)
366
364
  : range(start, oldLength + Math.max(items.length - deleteCount, 0), {
367
- length: true,
368
- })
365
+ length: true,
366
+ })
369
367
  )
370
368
  }
371
369
  }
@@ -1,7 +1,7 @@
1
1
  import { recordTriggerLink } from './debug'
2
2
  import { bubbleUpChange, objectsWithDeepWatchers } from './deep-watch-state'
3
3
  import { getActiveEffect, isRunning } from './effect-context'
4
- import { batch, effectTrackers, opaqueEffects } from './effects'
4
+ import { batch, effectTrackers, hasBatched, opaqueEffects, recordActivation } from './effects'
5
5
  import { unwrap } from './proxy-state'
6
6
  import { watchers } from './tracking'
7
7
  import { allProps, type Evolution, options, type ScopedCallback, type State } from './types'
@@ -49,7 +49,10 @@ export function collectEffects(
49
49
  options.skipRunningEffect(effect, runningChain as any)
50
50
  continue
51
51
  }
52
- effects.add(effect)
52
+ if (!effects.has(effect)) {
53
+ effects.add(effect)
54
+ if (!hasBatched(effect)) recordActivation(effect, obj, evolution, key)
55
+ }
53
56
  const trackers = effectTrackers.get(effect)
54
57
  recordTriggerLink(sourceEffect, effect, obj, key, evolution)
55
58
  if (trackers) {
@@ -119,6 +122,7 @@ export function touchedOpaque(obj: any, evolution: Evolution, prop: any) {
119
122
  continue
120
123
  }
121
124
  effects.add(effect)
125
+ recordActivation(effect, obj, evolution, prop)
122
126
  const trackers = effectTrackers.get(effect)
123
127
  recordTriggerLink(sourceEffect, effect, obj, prop, evolution)
124
128
  if (trackers) {
@@ -60,6 +60,69 @@ import { ensureZoneHooked } from './zone'
60
60
  type EffectTracking = (obj: any, evolution: Evolution, prop: any) => void
61
61
 
62
62
  export { captureEffectStack, withEffectStack, getActiveEffect, effectStack }
63
+ export interface ActivationRecord {
64
+ effect: ScopedCallback
65
+ obj: any
66
+ evolution: Evolution
67
+ prop: any
68
+ batchId: number
69
+ }
70
+
71
+ // Nested map structure for efficient counting and batch cleanup
72
+ // batchId -> effect root -> obj -> prop -> count
73
+ let activationRegistry: Map<Function, Map<any, Map<any, number>>> | undefined
74
+
75
+ export const activationLog: Omit<ActivationRecord, 'batchId'>[] = new Array(100)
76
+
77
+ export function getActivationLog() {
78
+ return activationLog
79
+ }
80
+
81
+ export function recordActivation(
82
+ effect: ScopedCallback,
83
+ obj: any,
84
+ evolution: Evolution,
85
+ prop: any
86
+ ) {
87
+ const root = getRoot(effect)
88
+
89
+ if (!activationRegistry) return
90
+ let effectData = activationRegistry.get(root)
91
+ if (!effectData) {
92
+ effectData = new Map()
93
+ activationRegistry.set(root, effectData)
94
+ }
95
+ let objData = effectData.get(obj)
96
+ if (!objData) {
97
+ objData = new Map()
98
+ effectData.set(obj, objData)
99
+ }
100
+ const count = (objData.get(prop) ?? 0) + 1
101
+ objData.set(prop, count)
102
+
103
+ // Keep a limited history for diagnostics
104
+ activationLog.unshift({
105
+ effect,
106
+ obj,
107
+ evolution,
108
+ prop,
109
+ })
110
+ activationLog.pop()
111
+
112
+ if (count >= options.maxTriggerPerBatch) {
113
+ const effectName = (root as any)?.name || 'anonymous'
114
+ const message = `Aggressive trigger detected: effect "${effectName}" triggered ${count} times in the batch by the same cause.`
115
+ if (options.maxEffectReaction === 'throw') {
116
+ throw new ReactiveError(message, {
117
+ code: ReactiveErrorCode.MaxReactionExceeded,
118
+ count,
119
+ effect: effectName,
120
+ })
121
+ }
122
+ options.warn(`[reactive] ${message}`)
123
+ }
124
+ }
125
+
63
126
  /**
64
127
  * Registers a debug callback that is called when the current effect is triggered by a dependency change
65
128
  *
@@ -380,6 +443,9 @@ interface BatchQueue {
380
443
  // Track currently executing effects to prevent re-execution
381
444
  // These are all the effects triggered under `activeEffect`
382
445
  let batchQueue: BatchQueue | undefined
446
+ export function hasBatched(effect: ScopedCallback) {
447
+ return batchQueue?.all.has(getRoot(effect))
448
+ }
383
449
  const batchCleanups = new Set<ScopedCallback>()
384
450
 
385
451
  /**
@@ -851,6 +917,8 @@ export function batch(effect: ScopedCallback | ScopedCallback[], immediate?: 'im
851
917
  // Otherwise, effects will be picked up in next executeNext() call
852
918
  } else {
853
919
  // New batch - initialize
920
+ if (!activationRegistry) activationRegistry = new Map()
921
+ else throw new Error('Batch already in progress')
854
922
  options.beginChain(roots)
855
923
  batchQueue = {
856
924
  all: new Map(),
@@ -931,6 +999,7 @@ export function batch(effect: ScopedCallback | ScopedCallback[], immediate?: 'im
931
999
  for (const cleanup of cleanups) cleanup()
932
1000
  return firstReturn.value
933
1001
  } finally {
1002
+ activationRegistry = undefined
934
1003
  batchQueue = undefined
935
1004
  options.endChain()
936
1005
  }
@@ -1003,11 +1072,11 @@ export function batch(effect: ScopedCallback | ScopedCallback[], immediate?: 'im
1003
1072
  }
1004
1073
  return firstReturn.value
1005
1074
  } finally {
1075
+ activationRegistry = undefined
1006
1076
  batchQueue = undefined
1007
1077
  options.endChain()
1008
1078
  }
1009
1079
  }
1010
-
1011
1080
  }
1012
1081
  }
1013
1082
 
@@ -17,6 +17,7 @@ export {
17
17
  biDi,
18
18
  defer,
19
19
  effect,
20
+ getActivationLog,
20
21
  getActiveEffect,
21
22
  root,
22
23
  trackEffect,
@@ -26,7 +27,7 @@ export { cleanedBy, cleanup, derived, unreactive, watch } from './interface'
26
27
  export { mapped, ReadOnlyError, reduced } from './mapped'
27
28
  export { type Memoizable, memoize } from './memoize'
28
29
  export { immutables, isNonReactive, registerNativeReactivity } from './non-reactive'
29
- export { project } from './project'
30
+ export { getActiveProjection, project } from './project'
30
31
  export { isReactive, ReactiveBase, reactive, unwrap } from './proxy'
31
32
  export { organize, organized } from './record'
32
33
  export { Register, register } from './register'
@@ -1,4 +1,4 @@
1
- import { decorator, GenericClassDecorator } from '../decorator'
1
+ import { decorator, type GenericClassDecorator } from '../decorator'
2
2
  import { deepWatch } from './deep-watch'
3
3
  import { withEffect } from './effect-context'
4
4
  import { effect, getActiveEffect, untracked } from './effects'
@@ -12,13 +12,13 @@ const native = Symbol('native')
12
12
  * Only tracks individual key operations, no size tracking (WeakMap limitation)
13
13
  */
14
14
  export class ReactiveWeakMap<K extends object, V> {
15
- declare readonly [native]: WeakMap<K, V>
16
- declare readonly content: symbol
15
+ readonly [native]!: WeakMap<K, V>
16
+ readonly content!: symbol
17
17
  constructor(original: WeakMap<K, V>) {
18
18
  Object.defineProperties(this, {
19
19
  [native]: { value: original },
20
20
  [prototypeForwarding]: { value: original },
21
- content: { value: Symbol('content') },
21
+ content: { value: Symbol('WeakMapContent') },
22
22
  [Symbol.toStringTag]: { value: 'ReactiveWeakMap' },
23
23
  })
24
24
  }
@@ -62,14 +62,14 @@ export class ReactiveWeakMap<K extends object, V> {
62
62
  * Tracks size changes, individual key operations, and collection-wide operations
63
63
  */
64
64
  export class ReactiveMap<K, V> {
65
- declare readonly [native]: Map<K, V>
66
- declare readonly content: symbol
65
+ readonly [native]!: Map<K, V>
66
+ readonly content!: symbol
67
67
 
68
68
  constructor(original: Map<K, V>) {
69
69
  Object.defineProperties(this, {
70
70
  [native]: { value: original },
71
71
  [prototypeForwarding]: { value: original },
72
- content: { value: Symbol('content') },
72
+ content: { value: Symbol('MapContent') },
73
73
  [Symbol.toStringTag]: { value: 'ReactiveMap' },
74
74
  })
75
75
  }
@@ -5,10 +5,10 @@ import { effect, untracked } from './effects'
5
5
  import { cleanedBy } from './interface'
6
6
  import { reactive } from './proxy'
7
7
  import { dependant } from './tracking'
8
- import { prototypeForwarding, ScopedCallback } from './types'
8
+ import { prototypeForwarding, type ScopedCallback } from './types'
9
9
 
10
10
  // TODO: Lazy reactivity ?
11
- export class ReadOnlyError extends Error {}
11
+ export class ReadOnlyError extends Error { }
12
12
  /**
13
13
  * Reactive wrapper around JavaScript's Array class with full array method support
14
14
  * Tracks length changes, individual index operations, and collection-wide operations
@@ -29,7 +29,6 @@ class ReactiveReadOnlyArrayClass extends Indexable(ReactiveBaseArray, {
29
29
  throw new ReadOnlyError(`Setting length to ${value} on a read-only array`)
30
30
  },
31
31
  }) {
32
- declare length: number
33
32
  constructor(original: any[]) {
34
33
  super()
35
34
  Object.defineProperties(this, {