@zeix/cause-effect 0.17.3 → 0.18.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/.ai-context.md +169 -227
- package/.cursorrules +41 -35
- package/.github/copilot-instructions.md +176 -116
- package/ARCHITECTURE.md +276 -0
- package/CHANGELOG.md +29 -0
- package/CLAUDE.md +201 -143
- package/GUIDE.md +298 -0
- package/README.md +246 -193
- package/REQUIREMENTS.md +100 -0
- package/bench/reactivity.bench.ts +577 -0
- package/context7.json +4 -0
- package/examples/events-sensor.ts +187 -0
- package/examples/selector-sensor.ts +173 -0
- package/index.dev.js +1390 -1008
- package/index.js +1 -1
- package/index.ts +60 -74
- package/package.json +5 -2
- package/skills/changelog-keeper/SKILL.md +59 -0
- package/skills/changelog-keeper/agents/openai.yaml +4 -0
- package/src/errors.ts +118 -74
- package/src/graph.ts +612 -0
- package/src/nodes/collection.ts +512 -0
- package/src/nodes/effect.ts +149 -0
- package/src/nodes/list.ts +589 -0
- package/src/nodes/memo.ts +148 -0
- package/src/nodes/sensor.ts +149 -0
- package/src/nodes/state.ts +135 -0
- package/src/nodes/store.ts +378 -0
- package/src/nodes/task.ts +174 -0
- package/src/signal.ts +112 -66
- package/src/util.ts +26 -57
- package/test/batch.test.ts +96 -62
- package/test/benchmark.test.ts +473 -487
- package/test/collection.test.ts +456 -707
- package/test/effect.test.ts +293 -696
- package/test/list.test.ts +335 -592
- package/test/memo.test.ts +574 -0
- package/test/regression.test.ts +156 -0
- package/test/scope.test.ts +191 -0
- package/test/sensor.test.ts +454 -0
- package/test/signal.test.ts +220 -213
- package/test/state.test.ts +217 -265
- package/test/store.test.ts +346 -446
- package/test/task.test.ts +529 -0
- package/test/untrack.test.ts +167 -0
- package/types/index.d.ts +13 -15
- package/types/src/errors.d.ts +73 -17
- package/types/src/graph.d.ts +218 -0
- package/types/src/nodes/collection.d.ts +69 -0
- package/types/src/nodes/effect.d.ts +48 -0
- package/types/src/nodes/list.d.ts +66 -0
- package/types/src/nodes/memo.d.ts +63 -0
- package/types/src/nodes/sensor.d.ts +81 -0
- package/types/src/nodes/state.d.ts +78 -0
- package/types/src/nodes/store.d.ts +51 -0
- package/types/src/nodes/task.d.ts +79 -0
- package/types/src/signal.d.ts +43 -29
- package/types/src/util.d.ts +9 -16
- package/archive/benchmark.ts +0 -683
- package/archive/collection.ts +0 -253
- package/archive/composite.ts +0 -85
- package/archive/computed.ts +0 -195
- package/archive/list.ts +0 -483
- package/archive/memo.ts +0 -139
- package/archive/state.ts +0 -90
- package/archive/store.ts +0 -298
- package/archive/task.ts +0 -189
- package/src/classes/collection.ts +0 -245
- package/src/classes/computed.ts +0 -349
- package/src/classes/list.ts +0 -343
- package/src/classes/ref.ts +0 -70
- package/src/classes/state.ts +0 -102
- package/src/classes/store.ts +0 -262
- package/src/diff.ts +0 -138
- package/src/effect.ts +0 -93
- package/src/match.ts +0 -45
- package/src/resolve.ts +0 -49
- package/src/system.ts +0 -257
- package/test/computed.test.ts +0 -1108
- package/test/diff.test.ts +0 -955
- package/test/match.test.ts +0 -388
- package/test/ref.test.ts +0 -353
- package/test/resolve.test.ts +0 -154
- package/types/src/classes/collection.d.ts +0 -45
- package/types/src/classes/computed.d.ts +0 -94
- package/types/src/classes/list.d.ts +0 -43
- package/types/src/classes/ref.d.ts +0 -35
- package/types/src/classes/state.d.ts +0 -49
- package/types/src/classes/store.d.ts +0 -52
- package/types/src/diff.d.ts +0 -28
- package/types/src/effect.d.ts +0 -15
- package/types/src/match.d.ts +0 -21
- package/types/src/resolve.d.ts +0 -29
- package/types/src/system.d.ts +0 -78
package/types/index.d.ts
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @name Cause & Effect
|
|
3
|
-
* @version 0.
|
|
3
|
+
* @version 0.18.1
|
|
4
4
|
* @author Esther Brunner
|
|
5
5
|
*/
|
|
6
|
-
export {
|
|
7
|
-
export { type
|
|
8
|
-
export { type
|
|
9
|
-
export {
|
|
10
|
-
export {
|
|
11
|
-
export {
|
|
12
|
-
export {
|
|
13
|
-
export {
|
|
14
|
-
export {
|
|
15
|
-
export {
|
|
16
|
-
export { type
|
|
17
|
-
export {
|
|
18
|
-
export { batch, type Cleanup, createWatcher, flush, notifyOf, type SignalOptions, subscribeTo, track, UNSET, untrack, type Watcher, } from './src/system';
|
|
19
|
-
export { isAbortError, isAsyncFunction, isFunction, isNumber, isObjectOfType, isRecord, isRecordOrArray, isString, isSymbol, valueString, } from './src/util';
|
|
6
|
+
export { CircularDependencyError, type Guard, InvalidCallbackError, InvalidSignalValueError, NullishSignalValueError, RequiredOwnerError, UnsetSignalValueError, } from './src/errors';
|
|
7
|
+
export { batch, type Cleanup, type ComputedOptions, createScope, type EffectCallback, type MaybeCleanup, type MemoCallback, type Signal, type SignalOptions, SKIP_EQUALITY, type TaskCallback, untrack, } from './src/graph';
|
|
8
|
+
export { type Collection, type CollectionCallback, type CollectionChanges, type CollectionOptions, createCollection, type DeriveCollectionCallback, isCollection, } from './src/nodes/collection';
|
|
9
|
+
export { createEffect, type MatchHandlers, type MaybePromise, match, } from './src/nodes/effect';
|
|
10
|
+
export { createList, isEqual, isList, type KeyConfig, type List, type ListOptions, } from './src/nodes/list';
|
|
11
|
+
export { createMemo, isMemo, type Memo } from './src/nodes/memo';
|
|
12
|
+
export { createSensor, isSensor, type Sensor, type SensorCallback, type SensorOptions, } from './src/nodes/sensor';
|
|
13
|
+
export { createState, isState, type State, type UpdateCallback, } from './src/nodes/state';
|
|
14
|
+
export { createStore, isStore, type Store, type StoreOptions, } from './src/nodes/store';
|
|
15
|
+
export { createTask, isTask, type Task } from './src/nodes/task';
|
|
16
|
+
export { createComputed, createMutableSignal, createSignal, isComputed, isMutableSignal, isSignal, type MutableSignal, } from './src/signal';
|
|
17
|
+
export { isAsyncFunction, isFunction, isObjectOfType, isRecord, valueString, } from './src/util';
|
package/types/src/errors.d.ts
CHANGED
|
@@ -1,29 +1,85 @@
|
|
|
1
|
-
|
|
2
|
-
type
|
|
1
|
+
/**
|
|
2
|
+
* A type guard function that validates whether an unknown value is of type T.
|
|
3
|
+
* Used to ensure type safety when updating signals.
|
|
4
|
+
*
|
|
5
|
+
* @template T - The type to guard against
|
|
6
|
+
* @param value - The value to check
|
|
7
|
+
* @returns True if the value is of type T
|
|
8
|
+
*/
|
|
9
|
+
type Guard<T extends {}> = (value: unknown) => value is T;
|
|
10
|
+
/**
|
|
11
|
+
* Error thrown on re-entrance on an already running function.
|
|
12
|
+
*/
|
|
3
13
|
declare class CircularDependencyError extends Error {
|
|
14
|
+
/**
|
|
15
|
+
* Constructs a new CircularDependencyError.
|
|
16
|
+
*
|
|
17
|
+
* @param where - The location where the error occurred.
|
|
18
|
+
*/
|
|
4
19
|
constructor(where: string);
|
|
5
20
|
}
|
|
6
|
-
|
|
7
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Error thrown when a signal value is null or undefined.
|
|
23
|
+
*/
|
|
24
|
+
declare class NullishSignalValueError extends TypeError {
|
|
25
|
+
/**
|
|
26
|
+
* Constructs a new NullishSignalValueError.
|
|
27
|
+
*
|
|
28
|
+
* @param where - The location where the error occurred.
|
|
29
|
+
*/
|
|
30
|
+
constructor(where: string);
|
|
8
31
|
}
|
|
9
|
-
|
|
10
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Error thrown when a signal is read before it has a value.
|
|
34
|
+
*/
|
|
35
|
+
declare class UnsetSignalValueError extends Error {
|
|
36
|
+
/**
|
|
37
|
+
* Constructs a new UnsetSignalValueError.
|
|
38
|
+
*
|
|
39
|
+
* @param where - The location where the error occurred.
|
|
40
|
+
*/
|
|
41
|
+
constructor(where: string);
|
|
11
42
|
}
|
|
12
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Error thrown when a signal value is invalid.
|
|
45
|
+
*/
|
|
46
|
+
declare class InvalidSignalValueError extends TypeError {
|
|
47
|
+
/**
|
|
48
|
+
* Constructs a new InvalidSignalValueError.
|
|
49
|
+
*
|
|
50
|
+
* @param where - The location where the error occurred.
|
|
51
|
+
* @param value - The invalid value.
|
|
52
|
+
*/
|
|
13
53
|
constructor(where: string, value: unknown);
|
|
14
54
|
}
|
|
15
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Error thrown when a callback is invalid.
|
|
57
|
+
*/
|
|
58
|
+
declare class InvalidCallbackError extends TypeError {
|
|
59
|
+
/**
|
|
60
|
+
* Constructs a new InvalidCallbackError.
|
|
61
|
+
*
|
|
62
|
+
* @param where - The location where the error occurred.
|
|
63
|
+
* @param value - The invalid value.
|
|
64
|
+
*/
|
|
16
65
|
constructor(where: string, value: unknown);
|
|
17
66
|
}
|
|
18
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Error thrown when an API requiring an owner is called without one.
|
|
69
|
+
*/
|
|
70
|
+
declare class RequiredOwnerError extends Error {
|
|
71
|
+
/**
|
|
72
|
+
* Constructs a new RequiredOwnerError.
|
|
73
|
+
*
|
|
74
|
+
* @param where - The location where the error occurred.
|
|
75
|
+
*/
|
|
19
76
|
constructor(where: string);
|
|
20
77
|
}
|
|
21
|
-
declare class
|
|
22
|
-
constructor(
|
|
78
|
+
declare class DuplicateKeyError extends Error {
|
|
79
|
+
constructor(where: string, key: string, value?: unknown);
|
|
23
80
|
}
|
|
24
|
-
declare function
|
|
25
|
-
declare
|
|
26
|
-
declare
|
|
27
|
-
declare
|
|
28
|
-
|
|
29
|
-
export { type Guard, CircularDependencyError, DuplicateKeyError, InvalidCallbackError, InvalidCollectionSourceError, InvalidSignalValueError, NullishSignalValueError, ReadonlySignalError, assert, createError, validateCallback, validateSignalValue, guardMutableSignal, };
|
|
81
|
+
declare function validateSignalValue<T extends {}>(where: string, value: unknown, guard?: Guard<T>): asserts value is T;
|
|
82
|
+
declare function validateReadValue<T extends {}>(where: string, value: T | null | undefined): asserts value is T;
|
|
83
|
+
declare function validateCallback(where: string, value: unknown): asserts value is (...args: unknown[]) => unknown;
|
|
84
|
+
declare function validateCallback<T>(where: string, value: unknown, guard: (value: unknown) => value is T): asserts value is T;
|
|
85
|
+
export { type Guard, CircularDependencyError, NullishSignalValueError, InvalidSignalValueError, UnsetSignalValueError, InvalidCallbackError, RequiredOwnerError, DuplicateKeyError, validateSignalValue, validateReadValue, validateCallback, };
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { type Guard } from './errors';
|
|
2
|
+
type SourceFields<T extends {}> = {
|
|
3
|
+
value: T;
|
|
4
|
+
sinks: Edge | null;
|
|
5
|
+
sinksTail: Edge | null;
|
|
6
|
+
stop?: Cleanup;
|
|
7
|
+
};
|
|
8
|
+
type OptionsFields<T extends {}> = {
|
|
9
|
+
equals: (a: T, b: T) => boolean;
|
|
10
|
+
guard?: Guard<T>;
|
|
11
|
+
};
|
|
12
|
+
type SinkFields = {
|
|
13
|
+
fn: unknown;
|
|
14
|
+
flags: number;
|
|
15
|
+
sources: Edge | null;
|
|
16
|
+
sourcesTail: Edge | null;
|
|
17
|
+
};
|
|
18
|
+
type OwnerFields = {
|
|
19
|
+
cleanup: Cleanup | Cleanup[] | null;
|
|
20
|
+
};
|
|
21
|
+
type AsyncFields = {
|
|
22
|
+
controller: AbortController | undefined;
|
|
23
|
+
error: Error | undefined;
|
|
24
|
+
};
|
|
25
|
+
type StateNode<T extends {}> = SourceFields<T> & OptionsFields<T>;
|
|
26
|
+
type MemoNode<T extends {}> = SourceFields<T> & OptionsFields<T> & SinkFields & {
|
|
27
|
+
fn: MemoCallback<T>;
|
|
28
|
+
error: Error | undefined;
|
|
29
|
+
};
|
|
30
|
+
type TaskNode<T extends {}> = SourceFields<T> & OptionsFields<T> & SinkFields & AsyncFields & {
|
|
31
|
+
fn: (prev: T, abort: AbortSignal) => Promise<T>;
|
|
32
|
+
};
|
|
33
|
+
type EffectNode = SinkFields & OwnerFields & {
|
|
34
|
+
fn: EffectCallback;
|
|
35
|
+
};
|
|
36
|
+
type Scope = OwnerFields;
|
|
37
|
+
type SourceNode = SourceFields<unknown & {}>;
|
|
38
|
+
type SinkNode = MemoNode<unknown & {}> | TaskNode<unknown & {}> | EffectNode;
|
|
39
|
+
type OwnerNode = EffectNode | Scope;
|
|
40
|
+
type Edge = {
|
|
41
|
+
source: SourceNode;
|
|
42
|
+
sink: SinkNode;
|
|
43
|
+
nextSource: Edge | null;
|
|
44
|
+
prevSink: Edge | null;
|
|
45
|
+
nextSink: Edge | null;
|
|
46
|
+
};
|
|
47
|
+
type Signal<T extends {}> = {
|
|
48
|
+
get(): T;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* A cleanup function that can be called to dispose of resources.
|
|
52
|
+
*/
|
|
53
|
+
type Cleanup = () => void;
|
|
54
|
+
type MaybeCleanup = Cleanup | undefined | void;
|
|
55
|
+
/**
|
|
56
|
+
* Options for configuring signal behavior.
|
|
57
|
+
*
|
|
58
|
+
* @template T - The type of value in the signal
|
|
59
|
+
*/
|
|
60
|
+
type SignalOptions<T extends {}> = {
|
|
61
|
+
/**
|
|
62
|
+
* Optional type guard to validate values.
|
|
63
|
+
* If provided, will throw an error if an invalid value is set.
|
|
64
|
+
*/
|
|
65
|
+
guard?: Guard<T>;
|
|
66
|
+
/**
|
|
67
|
+
* Optional custom equality function.
|
|
68
|
+
* Used to determine if a new value is different from the old value.
|
|
69
|
+
* Defaults to reference equality (===).
|
|
70
|
+
*/
|
|
71
|
+
equals?: (a: T, b: T) => boolean;
|
|
72
|
+
};
|
|
73
|
+
type ComputedOptions<T extends {}> = SignalOptions<T> & {
|
|
74
|
+
/**
|
|
75
|
+
* Optional initial value.
|
|
76
|
+
* Useful for reducer patterns so that calculations start with a value of correct type.
|
|
77
|
+
*/
|
|
78
|
+
value?: T;
|
|
79
|
+
/**
|
|
80
|
+
* Optional callback invoked when the signal is first watched by an effect.
|
|
81
|
+
* Receives an `invalidate` function that marks the signal dirty and triggers re-evaluation.
|
|
82
|
+
* Must return a cleanup function that is called when the signal is no longer watched.
|
|
83
|
+
*
|
|
84
|
+
* This enables lazy resource activation for computed signals that need to
|
|
85
|
+
* react to external events (e.g. DOM mutations, timers) in addition to
|
|
86
|
+
* tracked signal dependencies.
|
|
87
|
+
*/
|
|
88
|
+
watched?: (invalidate: () => void) => Cleanup;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* A callback function for memos that computes a value based on the previous value.
|
|
92
|
+
*
|
|
93
|
+
* @template T - The type of value computed
|
|
94
|
+
* @param prev - The previous computed value
|
|
95
|
+
* @returns The new computed value
|
|
96
|
+
*/
|
|
97
|
+
type MemoCallback<T extends {}> = (prev: T | undefined) => T;
|
|
98
|
+
/**
|
|
99
|
+
* A callback function for tasks that asynchronously computes a value.
|
|
100
|
+
*
|
|
101
|
+
* @template T - The type of value computed
|
|
102
|
+
* @param prev - The previous computed value
|
|
103
|
+
* @param signal - An AbortSignal that will be triggered if the task is aborted
|
|
104
|
+
* @returns A promise that resolves to the new computed value
|
|
105
|
+
*/
|
|
106
|
+
type TaskCallback<T extends {}> = (prev: T | undefined, signal: AbortSignal) => Promise<T>;
|
|
107
|
+
/**
|
|
108
|
+
* A callback function for effects that can perform side effects.
|
|
109
|
+
*
|
|
110
|
+
* @returns An optional cleanup function that will be called before the effect re-runs or is disposed
|
|
111
|
+
*/
|
|
112
|
+
type EffectCallback = () => MaybeCleanup;
|
|
113
|
+
declare const TYPE_STATE = "State";
|
|
114
|
+
declare const TYPE_MEMO = "Memo";
|
|
115
|
+
declare const TYPE_TASK = "Task";
|
|
116
|
+
declare const TYPE_SENSOR = "Sensor";
|
|
117
|
+
declare const TYPE_LIST = "List";
|
|
118
|
+
declare const TYPE_COLLECTION = "Collection";
|
|
119
|
+
declare const TYPE_STORE = "Store";
|
|
120
|
+
declare const FLAG_CLEAN = 0;
|
|
121
|
+
declare const FLAG_DIRTY: number;
|
|
122
|
+
declare let activeSink: SinkNode | null;
|
|
123
|
+
declare let activeOwner: OwnerNode | null;
|
|
124
|
+
declare let batchDepth: number;
|
|
125
|
+
declare const DEFAULT_EQUALITY: <T extends {}>(a: T, b: T) => boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Equality function that always returns false, causing propagation on every update.
|
|
128
|
+
* Use with `createSensor` for observing mutable objects where the reference stays the same
|
|
129
|
+
* but internal state changes (e.g., DOM elements observed via MutationObserver).
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```ts
|
|
133
|
+
* const el = createSensor<HTMLElement>((set) => {
|
|
134
|
+
* const node = document.getElementById('box')!;
|
|
135
|
+
* set(node);
|
|
136
|
+
* const obs = new MutationObserver(() => set(node));
|
|
137
|
+
* obs.observe(node, { attributes: true });
|
|
138
|
+
* return () => obs.disconnect();
|
|
139
|
+
* }, { value: node, equals: SKIP_EQUALITY });
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
declare const SKIP_EQUALITY: (_a?: unknown, _b?: unknown) => boolean;
|
|
143
|
+
declare function link(source: SourceNode, sink: SinkNode): void;
|
|
144
|
+
declare function unlink(edge: Edge): Edge | null;
|
|
145
|
+
declare function trimSources(node: SinkNode): void;
|
|
146
|
+
declare function propagate(node: SinkNode, newFlag?: number): void;
|
|
147
|
+
declare function setState<T extends {}>(node: StateNode<T>, next: T): void;
|
|
148
|
+
declare function registerCleanup(owner: OwnerNode, fn: Cleanup): void;
|
|
149
|
+
declare function runCleanup(owner: OwnerNode): void;
|
|
150
|
+
declare function runEffect(node: EffectNode): void;
|
|
151
|
+
declare function refresh(node: SinkNode): void;
|
|
152
|
+
declare function flush(): void;
|
|
153
|
+
/**
|
|
154
|
+
* Batches multiple signal updates together.
|
|
155
|
+
* Effects will not run until the batch completes.
|
|
156
|
+
* Batches can be nested; effects run when the outermost batch completes.
|
|
157
|
+
*
|
|
158
|
+
* @param fn - The function to execute within the batch
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* const count = createState(0);
|
|
163
|
+
* const double = createMemo(() => count.get() * 2);
|
|
164
|
+
*
|
|
165
|
+
* batch(() => {
|
|
166
|
+
* count.set(1);
|
|
167
|
+
* count.set(2);
|
|
168
|
+
* count.set(3);
|
|
169
|
+
* // Effects run only once at the end with count = 3
|
|
170
|
+
* });
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
declare function batch(fn: () => void): void;
|
|
174
|
+
/**
|
|
175
|
+
* Runs a callback without tracking dependencies.
|
|
176
|
+
* Any signal reads inside the callback will not create edges to the current active sink.
|
|
177
|
+
*
|
|
178
|
+
* @param fn - The function to execute without tracking
|
|
179
|
+
* @returns The return value of the function
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```ts
|
|
183
|
+
* const count = createState(0);
|
|
184
|
+
* const label = createState('Count');
|
|
185
|
+
*
|
|
186
|
+
* createEffect(() => {
|
|
187
|
+
* // Only re-runs when count changes, not when label changes
|
|
188
|
+
* const name = untrack(() => label.get());
|
|
189
|
+
* console.log(`${name}: ${count.get()}`);
|
|
190
|
+
* });
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
declare function untrack<T>(fn: () => T): T;
|
|
194
|
+
/**
|
|
195
|
+
* Creates a new ownership scope for managing cleanup of nested effects and resources.
|
|
196
|
+
* All effects created within the scope will be automatically disposed when the scope is disposed.
|
|
197
|
+
* Scopes can be nested - disposing a parent scope disposes all child scopes.
|
|
198
|
+
*
|
|
199
|
+
* @param fn - The function to execute within the scope, may return a cleanup function
|
|
200
|
+
* @returns A dispose function that cleans up the scope
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```ts
|
|
204
|
+
* const dispose = createScope(() => {
|
|
205
|
+
* const count = createState(0);
|
|
206
|
+
*
|
|
207
|
+
* createEffect(() => {
|
|
208
|
+
* console.log(count.get());
|
|
209
|
+
* });
|
|
210
|
+
*
|
|
211
|
+
* return () => console.log('Scope disposed');
|
|
212
|
+
* });
|
|
213
|
+
*
|
|
214
|
+
* dispose(); // Cleans up the effect and runs cleanup callbacks
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
declare function createScope(fn: () => MaybeCleanup): Cleanup;
|
|
218
|
+
export { type Cleanup, type ComputedOptions, type EffectCallback, type EffectNode, type MaybeCleanup, type MemoCallback, type MemoNode, type Scope, type Signal, type SignalOptions, type SinkNode, type StateNode, type TaskCallback, type TaskNode, activeOwner, activeSink, batch, batchDepth, createScope, DEFAULT_EQUALITY, SKIP_EQUALITY, FLAG_CLEAN, FLAG_DIRTY, flush, link, propagate, refresh, registerCleanup, runCleanup, runEffect, setState, trimSources, TYPE_COLLECTION, TYPE_LIST, TYPE_MEMO, TYPE_SENSOR, TYPE_STATE, TYPE_STORE, TYPE_TASK, unlink, untrack, };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type Cleanup, type Signal } from '../graph';
|
|
2
|
+
import { type KeyConfig, type List } from './list';
|
|
3
|
+
type CollectionSource<T extends {}> = List<T> | Collection<T>;
|
|
4
|
+
type DeriveCollectionCallback<T extends {}, U extends {}> = ((sourceValue: U) => T) | ((sourceValue: U, abort: AbortSignal) => Promise<T>);
|
|
5
|
+
type Collection<T extends {}> = {
|
|
6
|
+
readonly [Symbol.toStringTag]: 'Collection';
|
|
7
|
+
readonly [Symbol.isConcatSpreadable]: true;
|
|
8
|
+
[Symbol.iterator](): IterableIterator<Signal<T>>;
|
|
9
|
+
keys(): IterableIterator<string>;
|
|
10
|
+
get(): T[];
|
|
11
|
+
at(index: number): Signal<T> | undefined;
|
|
12
|
+
byKey(key: string): Signal<T> | undefined;
|
|
13
|
+
keyAt(index: number): string | undefined;
|
|
14
|
+
indexOfKey(key: string): number;
|
|
15
|
+
deriveCollection<R extends {}>(callback: (sourceValue: T) => R): Collection<R>;
|
|
16
|
+
deriveCollection<R extends {}>(callback: (sourceValue: T, abort: AbortSignal) => Promise<R>): Collection<R>;
|
|
17
|
+
readonly length: number;
|
|
18
|
+
};
|
|
19
|
+
type CollectionChanges<T> = {
|
|
20
|
+
add?: T[];
|
|
21
|
+
change?: T[];
|
|
22
|
+
remove?: T[];
|
|
23
|
+
};
|
|
24
|
+
type CollectionOptions<T extends {}> = {
|
|
25
|
+
value?: T[];
|
|
26
|
+
keyConfig?: KeyConfig<T>;
|
|
27
|
+
createItem?: (value: T) => Signal<T>;
|
|
28
|
+
};
|
|
29
|
+
type CollectionCallback<T extends {}> = (apply: (changes: CollectionChanges<T>) => void) => Cleanup;
|
|
30
|
+
/**
|
|
31
|
+
* Creates a derived Collection from a List or another Collection with item-level memoization.
|
|
32
|
+
* Sync callbacks use createMemo, async callbacks use createTask.
|
|
33
|
+
* Structural changes are tracked reactively via the source's keys.
|
|
34
|
+
*
|
|
35
|
+
* @since 0.18.0
|
|
36
|
+
* @param source - The source List or Collection to derive from
|
|
37
|
+
* @param callback - Transformation function applied to each item
|
|
38
|
+
* @returns A Collection signal
|
|
39
|
+
*/
|
|
40
|
+
declare function deriveCollection<T extends {}, U extends {}>(source: CollectionSource<U>, callback: (sourceValue: U) => T): Collection<T>;
|
|
41
|
+
declare function deriveCollection<T extends {}, U extends {}>(source: CollectionSource<U>, callback: (sourceValue: U, abort: AbortSignal) => Promise<T>): Collection<T>;
|
|
42
|
+
/**
|
|
43
|
+
* Creates an externally-driven Collection with a watched lifecycle.
|
|
44
|
+
* Items are managed via the `applyChanges(changes)` helper passed to the watched callback.
|
|
45
|
+
* The collection activates when first accessed by an effect and deactivates when no longer watched.
|
|
46
|
+
*
|
|
47
|
+
* @since 0.18.0
|
|
48
|
+
* @param watched - Callback invoked when the collection starts being watched, receives applyChanges helper
|
|
49
|
+
* @param options - Optional configuration including initial value, key generation, and item signal creation
|
|
50
|
+
* @returns A read-only Collection signal
|
|
51
|
+
*/
|
|
52
|
+
declare function createCollection<T extends {}>(watched: CollectionCallback<T>, options?: CollectionOptions<T>): Collection<T>;
|
|
53
|
+
/**
|
|
54
|
+
* Checks if a value is a Collection signal.
|
|
55
|
+
*
|
|
56
|
+
* @since 0.17.2
|
|
57
|
+
* @param value - The value to check
|
|
58
|
+
* @returns True if the value is a Collection
|
|
59
|
+
*/
|
|
60
|
+
declare function isCollection<T extends {}>(value: unknown): value is Collection<T>;
|
|
61
|
+
/**
|
|
62
|
+
* Checks if a value is a valid Collection source (List or Collection).
|
|
63
|
+
*
|
|
64
|
+
* @since 0.17.2
|
|
65
|
+
* @param value - The value to check
|
|
66
|
+
* @returns True if the value is a List or Collection
|
|
67
|
+
*/
|
|
68
|
+
declare function isCollectionSource<T extends {}>(value: unknown): value is CollectionSource<T>;
|
|
69
|
+
export { createCollection, deriveCollection, isCollection, isCollectionSource, type Collection, type CollectionCallback, type CollectionChanges, type CollectionOptions, type CollectionSource, type DeriveCollectionCallback, };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type Cleanup, type EffectCallback, type MaybeCleanup, type Signal } from '../graph';
|
|
2
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
3
|
+
type MatchHandlers<T extends Signal<unknown & {}>[]> = {
|
|
4
|
+
ok: (values: {
|
|
5
|
+
[K in keyof T]: T[K] extends Signal<infer V> ? V : never;
|
|
6
|
+
}) => MaybePromise<MaybeCleanup>;
|
|
7
|
+
err?: (errors: readonly Error[]) => MaybePromise<MaybeCleanup>;
|
|
8
|
+
nil?: () => MaybePromise<MaybeCleanup>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Creates a reactive effect that automatically runs when its dependencies change.
|
|
12
|
+
* Effects run immediately upon creation and re-run when any tracked signal changes.
|
|
13
|
+
* Effects are executed during the flush phase, after all updates have been batched.
|
|
14
|
+
*
|
|
15
|
+
* @since 0.1.0
|
|
16
|
+
* @param fn - The effect function that can track dependencies and register cleanup callbacks
|
|
17
|
+
* @returns A cleanup function that can be called to dispose of the effect
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const count = createState(0);
|
|
22
|
+
* const dispose = createEffect(() => {
|
|
23
|
+
* console.log('Count is:', count.get());
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* count.set(1); // Logs: "Count is: 1"
|
|
27
|
+
* dispose(); // Stop the effect
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* // With cleanup
|
|
33
|
+
* createEffect(() => {
|
|
34
|
+
* const timer = setInterval(() => console.log(count.get()), 1000);
|
|
35
|
+
* return () => clearInterval(timer);
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
declare function createEffect(fn: EffectCallback): Cleanup;
|
|
40
|
+
/**
|
|
41
|
+
* Runs handlers based on the current values of signals.
|
|
42
|
+
* Must be called within an active owner (effect or scope) so async cleanup can be registered.
|
|
43
|
+
*
|
|
44
|
+
* @since 0.15.0
|
|
45
|
+
* @throws RequiredOwnerError If called without an active owner.
|
|
46
|
+
*/
|
|
47
|
+
declare function match<T extends Signal<unknown & {}>[]>(signals: T, handlers: MatchHandlers<T>): MaybeCleanup;
|
|
48
|
+
export { type MaybePromise, type MatchHandlers, createEffect, match };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type Cleanup, TYPE_LIST } from '../graph';
|
|
2
|
+
import { type Collection } from './collection';
|
|
3
|
+
import { type State } from './state';
|
|
4
|
+
type UnknownRecord = Record<string, unknown>;
|
|
5
|
+
type DiffResult = {
|
|
6
|
+
changed: boolean;
|
|
7
|
+
add: UnknownRecord;
|
|
8
|
+
change: UnknownRecord;
|
|
9
|
+
remove: UnknownRecord;
|
|
10
|
+
};
|
|
11
|
+
type KeyConfig<T> = string | ((item: T) => string | undefined);
|
|
12
|
+
type ListOptions<T extends {}> = {
|
|
13
|
+
keyConfig?: KeyConfig<T>;
|
|
14
|
+
watched?: () => Cleanup;
|
|
15
|
+
};
|
|
16
|
+
type List<T extends {}> = {
|
|
17
|
+
readonly [Symbol.toStringTag]: 'List';
|
|
18
|
+
readonly [Symbol.isConcatSpreadable]: true;
|
|
19
|
+
[Symbol.iterator](): IterableIterator<State<T>>;
|
|
20
|
+
readonly length: number;
|
|
21
|
+
get(): T[];
|
|
22
|
+
set(next: T[]): void;
|
|
23
|
+
update(fn: (prev: T[]) => T[]): void;
|
|
24
|
+
at(index: number): State<T> | undefined;
|
|
25
|
+
keys(): IterableIterator<string>;
|
|
26
|
+
byKey(key: string): State<T> | undefined;
|
|
27
|
+
keyAt(index: number): string | undefined;
|
|
28
|
+
indexOfKey(key: string): number;
|
|
29
|
+
add(value: T): string;
|
|
30
|
+
remove(keyOrIndex: string | number): void;
|
|
31
|
+
sort(compareFn?: (a: T, b: T) => number): void;
|
|
32
|
+
splice(start: number, deleteCount?: number, ...items: T[]): T[];
|
|
33
|
+
deriveCollection<R extends {}>(callback: (sourceValue: T) => R): Collection<R>;
|
|
34
|
+
deriveCollection<R extends {}>(callback: (sourceValue: T, abort: AbortSignal) => Promise<R>): Collection<R>;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Checks if two values are equal with cycle detection
|
|
38
|
+
*
|
|
39
|
+
* @since 0.15.0
|
|
40
|
+
* @param a - First value to compare
|
|
41
|
+
* @param b - Second value to compare
|
|
42
|
+
* @param visited - Set to track visited objects for cycle detection
|
|
43
|
+
* @returns Whether the two values are equal
|
|
44
|
+
*/
|
|
45
|
+
declare function isEqual<T>(a: T, b: T, visited?: WeakSet<object>): boolean;
|
|
46
|
+
/** Shallow equality check for string arrays */
|
|
47
|
+
declare function keysEqual(a: string[], b: string[]): boolean;
|
|
48
|
+
declare function getKeyGenerator<T extends {}>(keyConfig?: KeyConfig<T>): [(item: T) => string, boolean];
|
|
49
|
+
/**
|
|
50
|
+
* Creates a reactive list with stable keys and per-item reactivity.
|
|
51
|
+
*
|
|
52
|
+
* @since 0.18.0
|
|
53
|
+
* @param value - Initial array of items
|
|
54
|
+
* @param options - Optional configuration for key generation and watch lifecycle
|
|
55
|
+
* @returns A List signal
|
|
56
|
+
*/
|
|
57
|
+
declare function createList<T extends {}>(value: T[], options?: ListOptions<T>): List<T>;
|
|
58
|
+
/**
|
|
59
|
+
* Checks if a value is a List signal.
|
|
60
|
+
*
|
|
61
|
+
* @since 0.15.0
|
|
62
|
+
* @param value - The value to check
|
|
63
|
+
* @returns True if the value is a List
|
|
64
|
+
*/
|
|
65
|
+
declare function isList<T extends {}>(value: unknown): value is List<T>;
|
|
66
|
+
export { type DiffResult, type KeyConfig, type List, type ListOptions, type UnknownRecord, createList, isEqual, isList, getKeyGenerator, keysEqual, TYPE_LIST, };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type ComputedOptions, type MemoCallback } from '../graph';
|
|
2
|
+
/**
|
|
3
|
+
* A derived reactive computation that caches its result.
|
|
4
|
+
* Automatically tracks dependencies and recomputes when they change.
|
|
5
|
+
*
|
|
6
|
+
* @template T - The type of value computed by the memo
|
|
7
|
+
*/
|
|
8
|
+
type Memo<T extends {}> = {
|
|
9
|
+
readonly [Symbol.toStringTag]: 'Memo';
|
|
10
|
+
/**
|
|
11
|
+
* Gets the current value of the memo.
|
|
12
|
+
* Recomputes if dependencies have changed since last access.
|
|
13
|
+
* When called inside another reactive context, creates a dependency.
|
|
14
|
+
* @returns The computed value
|
|
15
|
+
* @throws UnsetSignalValueError If the memo value is still unset when read.
|
|
16
|
+
*/
|
|
17
|
+
get(): T;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Creates a derived reactive computation that caches its result.
|
|
21
|
+
* The computation automatically tracks dependencies and recomputes when they change.
|
|
22
|
+
* Uses lazy evaluation - only computes when the value is accessed.
|
|
23
|
+
*
|
|
24
|
+
* @since 0.18.0
|
|
25
|
+
* @template T - The type of value computed by the memo
|
|
26
|
+
* @param fn - The computation function that receives the previous value
|
|
27
|
+
* @param options - Optional configuration for the memo
|
|
28
|
+
* @param options.value - Optional initial value for reducer patterns
|
|
29
|
+
* @param options.equals - Optional equality function. Defaults to strict equality (`===`)
|
|
30
|
+
* @param options.guard - Optional type guard to validate values
|
|
31
|
+
* @param options.watched - Optional callback invoked when the memo is first watched by an effect.
|
|
32
|
+
* Receives an `invalidate` function to mark the memo dirty and trigger recomputation.
|
|
33
|
+
* Must return a cleanup function called when no effects are watching.
|
|
34
|
+
* @returns A Memo object with a get() method
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* const count = createState(0);
|
|
39
|
+
* const doubled = createMemo(() => count.get() * 2);
|
|
40
|
+
* console.log(doubled.get()); // 0
|
|
41
|
+
* count.set(5);
|
|
42
|
+
* console.log(doubled.get()); // 10
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* // Using previous value
|
|
48
|
+
* const sum = createMemo((prev) => prev + count.get(), { value: 0, equals: Object.is });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
declare function createMemo<T extends {}>(fn: (prev: T) => T, options: ComputedOptions<T> & {
|
|
52
|
+
value: T;
|
|
53
|
+
}): Memo<T>;
|
|
54
|
+
declare function createMemo<T extends {}>(fn: MemoCallback<T>, options?: ComputedOptions<T>): Memo<T>;
|
|
55
|
+
/**
|
|
56
|
+
* Checks if a value is a Memo signal.
|
|
57
|
+
*
|
|
58
|
+
* @since 0.18.0
|
|
59
|
+
* @param value - The value to check
|
|
60
|
+
* @returns True if the value is a Memo
|
|
61
|
+
*/
|
|
62
|
+
declare function isMemo<T extends {} = unknown & {}>(value: unknown): value is Memo<T>;
|
|
63
|
+
export { createMemo, isMemo, type Memo };
|