@but212/atom-effect 0.1.0 → 0.1.1
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 -2
- package/dist/core/effect/effect.d.ts +61 -0
- package/dist/core/effect/effect.d.ts.map +1 -1
- package/dist/errors/messages.d.ts +79 -0
- package/dist/errors/messages.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +665 -82
- package/dist/index.mjs.map +1 -1
- package/dist/scheduler/batch.d.ts +29 -0
- package/dist/scheduler/batch.d.ts.map +1 -1
- package/dist/scheduler/scheduler.d.ts +130 -0
- package/dist/scheduler/scheduler.d.ts.map +1 -1
- package/dist/tracking/context.d.ts +68 -0
- package/dist/tracking/context.d.ts.map +1 -1
- package/dist/tracking/dependency-manager.d.ts +203 -0
- package/dist/tracking/dependency-manager.d.ts.map +1 -1
- package/dist/tracking/untracked.d.ts +23 -0
- package/dist/tracking/untracked.d.ts.map +1 -1
- package/dist/utils/debug.d.ts +73 -2
- package/dist/utils/debug.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,19 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scheduler for managing reactive updates and batching operations.
|
|
3
|
+
*
|
|
4
|
+
* The Scheduler is responsible for coordinating when reactive computations
|
|
5
|
+
* are executed. It supports both immediate (microtask) execution and
|
|
6
|
+
* batched synchronous execution for optimal performance.
|
|
7
|
+
*
|
|
8
|
+
* Key features:
|
|
9
|
+
* - Deduplication of callbacks via Set
|
|
10
|
+
* - Nested batch support with depth tracking
|
|
11
|
+
* - Infinite loop protection with configurable iteration limit
|
|
12
|
+
* - Error isolation to prevent one callback from breaking others
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // Schedule a callback for microtask execution
|
|
17
|
+
* scheduler.schedule(() => console.log('Updated!'));
|
|
18
|
+
*
|
|
19
|
+
* // Batch multiple updates
|
|
20
|
+
* scheduler.startBatch();
|
|
21
|
+
* scheduler.schedule(() => console.log('Update 1'));
|
|
22
|
+
* scheduler.schedule(() => console.log('Update 2'));
|
|
23
|
+
* scheduler.endBatch(); // Both execute synchronously here
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
1
26
|
declare class Scheduler {
|
|
27
|
+
/** Queue of callbacks waiting for microtask execution */
|
|
2
28
|
private queue;
|
|
29
|
+
/** Whether the scheduler is currently processing the queue */
|
|
3
30
|
private isProcessing;
|
|
31
|
+
/** Whether batching is currently active */
|
|
4
32
|
isBatching: boolean;
|
|
33
|
+
/** Current nesting depth of batch operations */
|
|
5
34
|
private batchDepth;
|
|
35
|
+
/** Array of callbacks queued during batching */
|
|
6
36
|
private batchQueue;
|
|
37
|
+
/** Current size of the batch queue (for array reuse) */
|
|
7
38
|
private batchQueueSize;
|
|
39
|
+
/** Whether synchronous flush is in progress */
|
|
8
40
|
private isFlushingSync;
|
|
41
|
+
/** Maximum iterations allowed during flush to prevent infinite loops */
|
|
9
42
|
private maxFlushIterations;
|
|
43
|
+
/**
|
|
44
|
+
* Schedules a callback for execution.
|
|
45
|
+
*
|
|
46
|
+
* If batching is active or a sync flush is in progress, the callback
|
|
47
|
+
* is added to the batch queue. Otherwise, it's added to the main queue
|
|
48
|
+
* and a flush is triggered via microtask.
|
|
49
|
+
*
|
|
50
|
+
* @param callback - The function to schedule for execution
|
|
51
|
+
* @throws {SchedulerError} If callback is not a function
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* scheduler.schedule(() => {
|
|
56
|
+
* // This runs in the next microtask (or sync if batching)
|
|
57
|
+
* updateUI();
|
|
58
|
+
* });
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
10
61
|
schedule(callback: () => void): void;
|
|
62
|
+
/**
|
|
63
|
+
* Flushes the queue asynchronously via microtask.
|
|
64
|
+
*
|
|
65
|
+
* Executes all queued callbacks in a microtask, allowing the current
|
|
66
|
+
* synchronous execution to complete first. Errors in individual
|
|
67
|
+
* callbacks are caught and logged without interrupting others.
|
|
68
|
+
*
|
|
69
|
+
* @private
|
|
70
|
+
* @remarks
|
|
71
|
+
* This method is idempotent - calling it multiple times while
|
|
72
|
+
* processing is active has no effect.
|
|
73
|
+
*/
|
|
11
74
|
private flush;
|
|
75
|
+
/**
|
|
76
|
+
* Flushes all queued callbacks synchronously.
|
|
77
|
+
*
|
|
78
|
+
* This method is called when a batch ends. It processes all callbacks
|
|
79
|
+
* in the batch queue and main queue synchronously, allowing callbacks
|
|
80
|
+
* to schedule additional callbacks that are processed in the same flush.
|
|
81
|
+
*
|
|
82
|
+
* @private
|
|
83
|
+
* @remarks
|
|
84
|
+
* - Includes infinite loop protection via maxFlushIterations
|
|
85
|
+
* - Errors in callbacks are caught and logged individually
|
|
86
|
+
* - The isFlushingSync flag prevents re-entrancy issues
|
|
87
|
+
*/
|
|
12
88
|
private flushSync;
|
|
89
|
+
/**
|
|
90
|
+
* Starts a new batch operation.
|
|
91
|
+
*
|
|
92
|
+
* While batching is active, all scheduled callbacks are deferred
|
|
93
|
+
* until endBatch() is called. Batches can be nested - only the
|
|
94
|
+
* outermost endBatch() triggers execution.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* scheduler.startBatch();
|
|
99
|
+
* // All updates here are deferred
|
|
100
|
+
* atom1.value = 'a';
|
|
101
|
+
* atom2.value = 'b';
|
|
102
|
+
* scheduler.endBatch(); // Both updates processed together
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
13
105
|
startBatch(): void;
|
|
106
|
+
/**
|
|
107
|
+
* Ends a batch operation.
|
|
108
|
+
*
|
|
109
|
+
* Decrements the batch depth counter. When depth reaches zero,
|
|
110
|
+
* all queued callbacks are flushed synchronously and batching
|
|
111
|
+
* is disabled.
|
|
112
|
+
*
|
|
113
|
+
* @remarks
|
|
114
|
+
* Safe to call even if startBatch() wasn't called - depth is
|
|
115
|
+
* clamped to zero minimum.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* scheduler.startBatch();
|
|
120
|
+
* try {
|
|
121
|
+
* // ... batched operations
|
|
122
|
+
* } finally {
|
|
123
|
+
* scheduler.endBatch(); // Always end batch, even on error
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
14
127
|
endBatch(): void;
|
|
128
|
+
/**
|
|
129
|
+
* Sets the maximum number of flush iterations allowed.
|
|
130
|
+
*
|
|
131
|
+
* This limit prevents infinite loops when reactive dependencies
|
|
132
|
+
* form cycles. If exceeded, the queue is cleared and an error
|
|
133
|
+
* is logged.
|
|
134
|
+
*
|
|
135
|
+
* @param max - Maximum iterations (must be at least 10)
|
|
136
|
+
* @throws {SchedulerError} If max is less than 10
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* // Increase limit for complex dependency graphs
|
|
141
|
+
* scheduler.setMaxFlushIterations(5000);
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
15
144
|
setMaxFlushIterations(max: number): void;
|
|
16
145
|
}
|
|
146
|
+
/** Global scheduler instance for reactive updates */
|
|
17
147
|
export declare const scheduler: Scheduler;
|
|
18
148
|
export {};
|
|
19
149
|
//# sourceMappingURL=scheduler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/scheduler/scheduler.ts"],"names":[],"mappings":"AAEA,cAAM,SAAS;IACb,OAAO,CAAC,KAAK,CAA8B;
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/scheduler/scheduler.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,cAAM,SAAS;IACb,yDAAyD;IACzD,OAAO,CAAC,KAAK,CAA8B;IAE3C,8DAA8D;IAC9D,OAAO,CAAC,YAAY,CAAkB;IAEtC,2CAA2C;IACpC,UAAU,EAAE,OAAO,CAAS;IAEnC,gDAAgD;IAChD,OAAO,CAAC,UAAU,CAAa;IAE/B,gDAAgD;IAChD,OAAO,CAAC,UAAU,CAAyB;IAE3C,wDAAwD;IACxD,OAAO,CAAC,cAAc,CAAK;IAE3B,+CAA+C;IAC/C,OAAO,CAAC,cAAc,CAAkB;IAExC,wEAAwE;IACxE,OAAO,CAAC,kBAAkB,CAAgB;IAE1C;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAepC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,KAAK;IA0Bb;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,SAAS;IAoDjB;;;;;;;;;;;;;;;OAeG;IACH,UAAU,IAAI,IAAI;IAKlB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,IAAI,IAAI;IAShB;;;;;;;;;;;;;;;OAeG;IACH,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CAMzC;AAED,qDAAqD;AACrD,eAAO,MAAM,SAAS,WAAkB,CAAC"}
|
|
@@ -1,8 +1,76 @@
|
|
|
1
1
|
import { Listener } from './tracking.types';
|
|
2
|
+
/**
|
|
3
|
+
* Interface for the tracking context that manages dependency tracking.
|
|
4
|
+
*
|
|
5
|
+
* The tracking context is responsible for maintaining the current listener
|
|
6
|
+
* during reactive computations, enabling automatic dependency collection.
|
|
7
|
+
*
|
|
8
|
+
* @interface TrackingContext
|
|
9
|
+
*/
|
|
2
10
|
export interface TrackingContext {
|
|
11
|
+
/**
|
|
12
|
+
* The currently active listener being tracked.
|
|
13
|
+
* `null` when no tracking is in progress.
|
|
14
|
+
*/
|
|
3
15
|
current: Listener | null;
|
|
16
|
+
/**
|
|
17
|
+
* Executes a function within a tracking context.
|
|
18
|
+
*
|
|
19
|
+
* Sets the provided listener as the current tracking target,
|
|
20
|
+
* executes the function, and restores the previous context.
|
|
21
|
+
*
|
|
22
|
+
* @template T - The return type of the function
|
|
23
|
+
* @param listener - The listener to set as current during execution
|
|
24
|
+
* @param fn - The function to execute within the tracking context
|
|
25
|
+
* @returns The result of the executed function
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const result = trackingContext.run(myListener, () => {
|
|
30
|
+
* // Any atom access here will be tracked
|
|
31
|
+
* return someAtom.value + otherAtom.value;
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
4
35
|
run<T>(listener: Listener, fn: () => T): T;
|
|
36
|
+
/**
|
|
37
|
+
* Gets the currently active listener.
|
|
38
|
+
*
|
|
39
|
+
* @returns The current listener or `null` if no tracking is active
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const current = trackingContext.getCurrent();
|
|
44
|
+
* if (current) {
|
|
45
|
+
* // Dependency tracking is active
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
5
49
|
getCurrent(): Listener | null;
|
|
6
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Global tracking context singleton for dependency tracking.
|
|
53
|
+
*
|
|
54
|
+
* This object manages the current listener during reactive computations,
|
|
55
|
+
* enabling atoms and computed values to automatically track their dependencies.
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* - The context uses a stack-like behavior via the `run` method
|
|
59
|
+
* - Nested `run` calls properly restore the previous context
|
|
60
|
+
* - Thread-safe within a single JavaScript execution context
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* // Setting up tracking for a computed value
|
|
65
|
+
* const value = trackingContext.run(computedListener, () => {
|
|
66
|
+
* return atom1.value + atom2.value; // Both atoms are tracked
|
|
67
|
+
* });
|
|
68
|
+
*
|
|
69
|
+
* // Checking if tracking is active
|
|
70
|
+
* if (trackingContext.getCurrent()) {
|
|
71
|
+
* // Register this atom as a dependency
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
7
75
|
export declare const trackingContext: TrackingContext;
|
|
8
76
|
//# sourceMappingURL=context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/tracking/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/tracking/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IAEzB;;;;;;;;;;;;;;;;;;OAkBG;IACH,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IAE3C;;;;;;;;;;;;OAYG;IACH,UAAU,IAAI,QAAQ,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,eAAe,EAAE,eAsB7B,CAAC"}
|
|
@@ -1,17 +1,220 @@
|
|
|
1
1
|
import { Dependency } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Manages reactive dependencies with automatic cleanup and memory-efficient tracking.
|
|
4
|
+
*
|
|
5
|
+
* This class provides a centralized way to track dependencies between reactive
|
|
6
|
+
* primitives (atoms, computed values) and their subscribers. It uses WeakRef
|
|
7
|
+
* and WeakMap for memory-efficient storage that allows garbage collection
|
|
8
|
+
* of unused dependencies.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* - Uses WeakMap for O(1) lookup and automatic GC of unreferenced dependencies
|
|
12
|
+
* - Uses WeakRef array for iteration while allowing GC
|
|
13
|
+
* - Periodic cleanup removes stale WeakRefs to prevent memory leaks
|
|
14
|
+
* - Thread-safe for single-threaded JavaScript execution
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const manager = new DependencyManager();
|
|
19
|
+
*
|
|
20
|
+
* // Add a dependency with its unsubscribe callback
|
|
21
|
+
* const unsubscribe = atom.subscribe(() => recompute());
|
|
22
|
+
* manager.addDependency(atom, unsubscribe);
|
|
23
|
+
*
|
|
24
|
+
* // Check if dependency exists
|
|
25
|
+
* if (manager.hasDependency(atom)) {
|
|
26
|
+
* console.log('Dependency tracked');
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* // Remove specific dependency
|
|
30
|
+
* manager.removeDependency(atom);
|
|
31
|
+
*
|
|
32
|
+
* // Clean up all dependencies
|
|
33
|
+
* manager.unsubscribeAll();
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
2
36
|
export declare class DependencyManager {
|
|
37
|
+
/**
|
|
38
|
+
* WeakMap storing dependency -> unsubscribe function mappings.
|
|
39
|
+
* Allows O(1) lookup and automatic garbage collection.
|
|
40
|
+
*/
|
|
3
41
|
private depMap;
|
|
42
|
+
/**
|
|
43
|
+
* Array of WeakRefs for iteration over live dependencies.
|
|
44
|
+
* WeakRefs allow the referenced objects to be garbage collected.
|
|
45
|
+
*/
|
|
4
46
|
private depRefs;
|
|
47
|
+
/**
|
|
48
|
+
* Number of additions before triggering automatic cleanup.
|
|
49
|
+
* @defaultValue 100
|
|
50
|
+
*/
|
|
5
51
|
private cleanupThreshold;
|
|
52
|
+
/**
|
|
53
|
+
* Counter tracking additions since last cleanup.
|
|
54
|
+
*/
|
|
6
55
|
private addCount;
|
|
56
|
+
/**
|
|
57
|
+
* Adds a dependency with its associated unsubscribe callback.
|
|
58
|
+
*
|
|
59
|
+
* If the dependency already exists, the new unsubscribe callback is
|
|
60
|
+
* immediately called to prevent duplicate subscriptions.
|
|
61
|
+
*
|
|
62
|
+
* @param dep - The dependency to track (atom, computed, etc.)
|
|
63
|
+
* @param unsubscribe - Callback to invoke when removing the dependency
|
|
64
|
+
*
|
|
65
|
+
* @remarks
|
|
66
|
+
* - Duplicate dependencies are rejected with immediate unsubscribe
|
|
67
|
+
* - Automatic cleanup is triggered every `cleanupThreshold` additions
|
|
68
|
+
* - Time complexity: O(1) for add, O(n) when cleanup triggers
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const unsubscribe = atom.subscribe(() => markDirty());
|
|
73
|
+
* manager.addDependency(atom, unsubscribe);
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
7
76
|
addDependency(dep: Dependency, unsubscribe: () => void): void;
|
|
77
|
+
/**
|
|
78
|
+
* Removes a dependency and calls its unsubscribe callback.
|
|
79
|
+
*
|
|
80
|
+
* @param dep - The dependency to remove
|
|
81
|
+
* @returns `true` if the dependency was found and removed, `false` otherwise
|
|
82
|
+
*
|
|
83
|
+
* @remarks
|
|
84
|
+
* - Unsubscribe errors are caught and logged to prevent cascading failures
|
|
85
|
+
* - The WeakRef entry is not immediately removed (cleaned up lazily)
|
|
86
|
+
* - Time complexity: O(1)
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* const wasRemoved = manager.removeDependency(atom);
|
|
91
|
+
* if (wasRemoved) {
|
|
92
|
+
* console.log('Dependency successfully removed');
|
|
93
|
+
* }
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
8
96
|
removeDependency(dep: Dependency): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Checks if a dependency is currently being tracked.
|
|
99
|
+
*
|
|
100
|
+
* @param dep - The dependency to check
|
|
101
|
+
* @returns `true` if the dependency exists in the manager
|
|
102
|
+
*
|
|
103
|
+
* @remarks
|
|
104
|
+
* Time complexity: O(1)
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* if (manager.hasDependency(atom)) {
|
|
109
|
+
* // Dependency is already tracked
|
|
110
|
+
* }
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
9
113
|
hasDependency(dep: Dependency): boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Removes all dependencies and calls their unsubscribe callbacks.
|
|
116
|
+
*
|
|
117
|
+
* This method iterates through all tracked dependencies, calls their
|
|
118
|
+
* unsubscribe callbacks, and clears internal storage.
|
|
119
|
+
*
|
|
120
|
+
* @remarks
|
|
121
|
+
* - Errors during unsubscribe are caught and logged individually
|
|
122
|
+
* - Safe to call multiple times (idempotent after first call)
|
|
123
|
+
* - Time complexity: O(n) where n is the number of dependencies
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* // Clean up when disposing a computed value
|
|
128
|
+
* manager.unsubscribeAll();
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
10
131
|
unsubscribeAll(): void;
|
|
132
|
+
/**
|
|
133
|
+
* Removes stale WeakRefs from the internal array.
|
|
134
|
+
*
|
|
135
|
+
* WeakRefs whose targets have been garbage collected are filtered out
|
|
136
|
+
* to prevent unbounded growth of the depRefs array.
|
|
137
|
+
*
|
|
138
|
+
* @remarks
|
|
139
|
+
* - Called automatically every `cleanupThreshold` additions
|
|
140
|
+
* - Can be called manually for immediate cleanup
|
|
141
|
+
* - Time complexity: O(n) where n is the number of WeakRefs
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```typescript
|
|
145
|
+
* // Force immediate cleanup
|
|
146
|
+
* manager.cleanup();
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
11
149
|
cleanup(): void;
|
|
150
|
+
/**
|
|
151
|
+
* Gets the current number of live dependencies.
|
|
152
|
+
*
|
|
153
|
+
* @returns The count of dependencies that haven't been garbage collected
|
|
154
|
+
*
|
|
155
|
+
* @remarks
|
|
156
|
+
* - Triggers cleanup before counting for accurate results
|
|
157
|
+
* - Time complexity: O(n) due to cleanup
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* console.log(`Tracking ${manager.count} dependencies`);
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
12
164
|
get count(): number;
|
|
165
|
+
/**
|
|
166
|
+
* Gets an array of all live dependencies.
|
|
167
|
+
*
|
|
168
|
+
* @returns Array of dependencies that haven't been garbage collected
|
|
169
|
+
*
|
|
170
|
+
* @remarks
|
|
171
|
+
* - Returns a new array (safe to modify)
|
|
172
|
+
* - Does not trigger cleanup (may include some stale refs)
|
|
173
|
+
* - Time complexity: O(n)
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```typescript
|
|
177
|
+
* const deps = manager.getDependencies();
|
|
178
|
+
* deps.forEach(dep => console.log(dep));
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
13
181
|
getDependencies(): Dependency[];
|
|
182
|
+
/**
|
|
183
|
+
* Gets the internal WeakMap for advanced use cases.
|
|
184
|
+
*
|
|
185
|
+
* @returns The internal dependency -> unsubscribe WeakMap
|
|
186
|
+
*
|
|
187
|
+
* @remarks
|
|
188
|
+
* - Returns the actual internal map (not a copy)
|
|
189
|
+
* - Modifications will affect the manager's state
|
|
190
|
+
* - Use with caution in production code
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```typescript
|
|
194
|
+
* const map = manager.getDepMap();
|
|
195
|
+
* const unsubscribe = map.get(someDependency);
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
14
198
|
getDepMap(): WeakMap<Dependency, () => void>;
|
|
199
|
+
/**
|
|
200
|
+
* Sets the threshold for automatic cleanup triggering.
|
|
201
|
+
*
|
|
202
|
+
* @param threshold - Number of additions before cleanup (minimum 1)
|
|
203
|
+
*
|
|
204
|
+
* @remarks
|
|
205
|
+
* - Lower values mean more frequent cleanup (less memory, more CPU)
|
|
206
|
+
* - Higher values mean less frequent cleanup (more memory, less CPU)
|
|
207
|
+
* - Default is 100, suitable for most use cases
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```typescript
|
|
211
|
+
* // More aggressive cleanup for memory-constrained environments
|
|
212
|
+
* manager.setCleanupThreshold(50);
|
|
213
|
+
*
|
|
214
|
+
* // Less frequent cleanup for performance-critical paths
|
|
215
|
+
* manager.setCleanupThreshold(500);
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
15
218
|
setCleanupThreshold(threshold: number): void;
|
|
16
219
|
}
|
|
17
220
|
//# sourceMappingURL=dependency-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dependency-manager.d.ts","sourceRoot":"","sources":["../../src/tracking/dependency-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAyC;
|
|
1
|
+
{"version":3,"file":"dependency-manager.d.ts","sourceRoot":"","sources":["../../src/tracking/dependency-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,iBAAiB;IAC5B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAyC;IAEvD;;;OAGG;IACH,OAAO,CAAC,OAAO,CAA6B;IAE5C;;;OAGG;IACH,OAAO,CAAC,gBAAgB,CAAO;IAE/B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAK;IAErB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,IAAI,GAAG,IAAI;IAe7D;;;;;;;;;;;;;;;;;;OAkBG;IACH,gBAAgB,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO;IAc1C;;;;;;;;;;;;;;;OAeG;IACH,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO;IAIvC;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,IAAI,IAAI;IAmBtB;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,IAAI,IAAI;IAIf;;;;;;;;;;;;;OAaG;IACH,IAAI,KAAK,IAAI,MAAM,CAGlB;IAED;;;;;;;;;;;;;;;OAeG;IACH,eAAe,IAAI,UAAU,EAAE;IAW/B;;;;;;;;;;;;;;;OAeG;IACH,SAAS,IAAI,OAAO,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC;IAI5C;;;;;;;;;;;;;;;;;;OAkBG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAG7C"}
|
|
@@ -1,2 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Executes a function without tracking any reactive dependencies.
|
|
3
|
+
*
|
|
4
|
+
* This utility allows reading atom values without establishing
|
|
5
|
+
* a dependency relationship, useful for accessing values that
|
|
6
|
+
* shouldn't trigger recomputation when they change.
|
|
7
|
+
*
|
|
8
|
+
* @template T - The return type of the function
|
|
9
|
+
* @param fn - The function to execute without tracking
|
|
10
|
+
* @returns The result of the executed function
|
|
11
|
+
* @throws {AtomError} If the callback is not a function
|
|
12
|
+
* @throws {AtomError} If an error occurs during execution
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const count = atom(0);
|
|
17
|
+
* const doubled = computed(() => {
|
|
18
|
+
* // This read will NOT be tracked as a dependency
|
|
19
|
+
* const untrackedValue = untracked(() => count.value);
|
|
20
|
+
* return untrackedValue * 2;
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
1
24
|
export declare function untracked<T>(fn: () => T): T;
|
|
2
25
|
//# sourceMappingURL=untracked.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"untracked.d.ts","sourceRoot":"","sources":["../../src/tracking/untracked.ts"],"names":[],"mappings":"AAGA,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAe3C"}
|
|
1
|
+
{"version":3,"file":"untracked.d.ts","sourceRoot":"","sources":["../../src/tracking/untracked.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAe3C"}
|
package/dist/utils/debug.d.ts
CHANGED
|
@@ -1,14 +1,85 @@
|
|
|
1
1
|
import { DebugConfig } from '../types';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Symbol key for storing debug display name on reactive objects.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Using symbols prevents property name collisions with user-defined properties.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const atom = createAtom(0);
|
|
11
|
+
* console.log(atom[DEBUG_NAME]); // "atom_1"
|
|
12
|
+
* ```
|
|
4
13
|
*/
|
|
5
14
|
export declare const DEBUG_NAME: unique symbol;
|
|
15
|
+
/**
|
|
16
|
+
* Symbol key for storing unique identifier on reactive objects.
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* Each reactive object (atom, computed, effect) receives a unique numeric ID
|
|
20
|
+
* for debugging and tracking purposes.
|
|
21
|
+
*/
|
|
6
22
|
export declare const DEBUG_ID: unique symbol;
|
|
23
|
+
/**
|
|
24
|
+
* Symbol key for storing the type discriminator on reactive objects.
|
|
25
|
+
*
|
|
26
|
+
* @remarks
|
|
27
|
+
* Possible values: 'atom' | 'computed' | 'effect'
|
|
28
|
+
*/
|
|
7
29
|
export declare const DEBUG_TYPE: unique symbol;
|
|
8
30
|
/**
|
|
9
|
-
* Sentinel value to distinguish "no default value" from undefined
|
|
31
|
+
* Sentinel value to distinguish "no default value provided" from `undefined`.
|
|
32
|
+
*
|
|
33
|
+
* @remarks
|
|
34
|
+
* This allows computed values to differentiate between:
|
|
35
|
+
* - User explicitly passing `undefined` as default
|
|
36
|
+
* - User not providing any default value
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const hasDefault = options.defaultValue !== NO_DEFAULT_VALUE;
|
|
41
|
+
* ```
|
|
10
42
|
*/
|
|
11
43
|
export declare const NO_DEFAULT_VALUE: unique symbol;
|
|
44
|
+
/**
|
|
45
|
+
* Debug configuration instance with runtime utilities.
|
|
46
|
+
*
|
|
47
|
+
* Provides development-time features including:
|
|
48
|
+
* - Circular dependency detection (direct and indirect)
|
|
49
|
+
* - Large dependency graph warnings
|
|
50
|
+
* - Debug metadata attachment for inspection
|
|
51
|
+
*
|
|
52
|
+
* @remarks
|
|
53
|
+
* Most features are only active when `NODE_ENV === 'development'`
|
|
54
|
+
* to avoid performance overhead in production builds.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* // Check for circular dependencies
|
|
59
|
+
* debug.checkCircular(dependencyAtom, computedAtom);
|
|
60
|
+
*
|
|
61
|
+
* // Warn about potential issues
|
|
62
|
+
* debug.warn(count > 100, 'Large dependency count detected');
|
|
63
|
+
*
|
|
64
|
+
* // Attach debug info to a reactive object
|
|
65
|
+
* debug.attachDebugInfo(atom, 'atom', 42);
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
12
68
|
export declare const debug: DebugConfig;
|
|
69
|
+
/**
|
|
70
|
+
* Generates a unique numeric identifier for reactive objects.
|
|
71
|
+
*
|
|
72
|
+
* @returns A unique positive integer, incrementing with each call
|
|
73
|
+
*
|
|
74
|
+
* @remarks
|
|
75
|
+
* IDs are globally unique within a single runtime session.
|
|
76
|
+
* The counter resets when the module is reloaded.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* const atomId = generateId(); // 1
|
|
81
|
+
* const computedId = generateId(); // 2
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
13
84
|
export declare const generateId: () => number;
|
|
14
85
|
//# sourceMappingURL=debug.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../src/utils/debug.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../src/utils/debug.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,EAAE,OAAO,MAA4B,CAAC;AAE7D;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,EAAE,OAAO,MAAqB,CAAC;AAEpD;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,OAAO,MAAuB,CAAC;AAExD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB,EAAE,OAAO,MAAiC,CAAC;AAmBxE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,KAAK,EAAE,WAsKnB,CAAC;AASF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,UAAU,QAAO,MAAkB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@but212/atom-effect",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A reactive state management library that combines the power of `atom`, `computed`, and `effect` for seamless management of reactive state.",
|
|
6
6
|
"main": "dist/index.cjs",
|