@zeix/cause-effect 0.16.1 → 0.17.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.
Files changed (66) hide show
  1. package/.ai-context.md +85 -21
  2. package/.cursorrules +11 -5
  3. package/.github/copilot-instructions.md +64 -13
  4. package/CLAUDE.md +143 -163
  5. package/LICENSE +1 -1
  6. package/README.md +248 -333
  7. package/archive/benchmark.ts +688 -0
  8. package/archive/collection.ts +312 -0
  9. package/{src → archive}/computed.ts +21 -21
  10. package/archive/list.ts +551 -0
  11. package/archive/memo.ts +139 -0
  12. package/{src → archive}/state.ts +13 -11
  13. package/archive/store.ts +368 -0
  14. package/archive/task.ts +194 -0
  15. package/eslint.config.js +1 -0
  16. package/index.dev.js +938 -509
  17. package/index.js +1 -1
  18. package/index.ts +50 -23
  19. package/package.json +1 -1
  20. package/src/classes/collection.ts +282 -0
  21. package/src/classes/composite.ts +176 -0
  22. package/src/classes/computed.ts +333 -0
  23. package/src/classes/list.ts +305 -0
  24. package/src/classes/ref.ts +68 -0
  25. package/src/classes/state.ts +98 -0
  26. package/src/classes/store.ts +210 -0
  27. package/src/diff.ts +26 -53
  28. package/src/effect.ts +9 -9
  29. package/src/errors.ts +71 -25
  30. package/src/match.ts +5 -12
  31. package/src/resolve.ts +3 -2
  32. package/src/signal.ts +58 -41
  33. package/src/system.ts +79 -42
  34. package/src/util.ts +16 -34
  35. package/test/batch.test.ts +15 -17
  36. package/test/benchmark.test.ts +4 -4
  37. package/test/collection.test.ts +853 -0
  38. package/test/computed.test.ts +138 -130
  39. package/test/diff.test.ts +2 -2
  40. package/test/effect.test.ts +36 -35
  41. package/test/list.test.ts +754 -0
  42. package/test/match.test.ts +25 -25
  43. package/test/ref.test.ts +227 -0
  44. package/test/resolve.test.ts +17 -19
  45. package/test/signal.test.ts +70 -119
  46. package/test/state.test.ts +44 -44
  47. package/test/store.test.ts +253 -929
  48. package/types/index.d.ts +12 -9
  49. package/types/src/classes/collection.d.ts +46 -0
  50. package/types/src/classes/composite.d.ts +15 -0
  51. package/types/src/classes/computed.d.ts +97 -0
  52. package/types/src/classes/list.d.ts +41 -0
  53. package/types/src/classes/ref.d.ts +39 -0
  54. package/types/src/classes/state.d.ts +52 -0
  55. package/types/src/classes/store.d.ts +51 -0
  56. package/types/src/diff.d.ts +8 -12
  57. package/types/src/errors.d.ts +17 -11
  58. package/types/src/signal.d.ts +27 -14
  59. package/types/src/system.d.ts +41 -20
  60. package/types/src/util.d.ts +6 -4
  61. package/src/store.ts +0 -474
  62. package/types/src/collection.d.ts +0 -26
  63. package/types/src/computed.d.ts +0 -33
  64. package/types/src/scheduler.d.ts +0 -55
  65. package/types/src/state.d.ts +0 -24
  66. package/types/src/store.d.ts +0 -65
package/types/index.d.ts CHANGED
@@ -1,16 +1,19 @@
1
1
  /**
2
2
  * @name Cause & Effect
3
- * @version 0.16.1
3
+ * @version 0.17.1
4
4
  * @author Esther Brunner
5
5
  */
6
- export { type Computed, type ComputedCallback, createComputed, isComputed, isComputedCallback, TYPE_COMPUTED, } from './src/computed';
7
- export { type DiffResult, diff, isEqual, type PartialRecord, type UnknownArray, type UnknownRecord, } from './src/diff';
6
+ export { type Collection, type CollectionCallback, type CollectionSource, DerivedCollection, isCollection, TYPE_COLLECTION, } from './src/classes/collection';
7
+ export { type Computed, createComputed, isComputed, isMemoCallback, isTaskCallback, Memo, type MemoCallback, Task, type TaskCallback, TYPE_COMPUTED, } from './src/classes/computed';
8
+ export { type ArrayToRecord, isList, type KeyConfig, List, TYPE_LIST, } from './src/classes/list';
9
+ export { isRef, Ref, TYPE_REF } from './src/classes/ref';
10
+ export { isState, State, TYPE_STATE } from './src/classes/state';
11
+ export { BaseStore, createStore, isStore, type Store, TYPE_STORE, } from './src/classes/store';
12
+ export { type DiffResult, diff, isEqual, type UnknownArray, type UnknownRecord, } from './src/diff';
8
13
  export { createEffect, type EffectCallback, type MaybeCleanup, } from './src/effect';
9
- export { CircularDependencyError, InvalidCallbackError, InvalidSignalValueError, NullishSignalValueError, StoreKeyExistsError, StoreKeyRangeError, StoreKeyReadonlyError, } from './src/errors';
14
+ export { CircularDependencyError, createError, DuplicateKeyError, type Guard, guardMutableSignal, InvalidCallbackError, InvalidCollectionSourceError, InvalidSignalValueError, NullishSignalValueError, ReadonlySignalError, validateCallback, validateSignalValue, } from './src/errors';
10
15
  export { type MatchHandlers, match } from './src/match';
11
16
  export { type ResolveResult, resolve } from './src/resolve';
12
- export { isMutableSignal, isSignal, type Signal, type SignalValues, toSignal, type UnknownSignalRecord, } from './src/signal';
13
- export { createState, isState, type State, TYPE_STATE } from './src/state';
14
- export { createStore, isStore, type Store, type StoreChanges, TYPE_STORE, } from './src/store';
15
- export { batch, type Cleanup, createWatcher, flush, notify, observe, subscribe, type Watcher, } from './src/system';
16
- export { isAbortError, isAsyncFunction, isFunction, isNumber, isObjectOfType, isRecord, isRecordOrArray, isString, isSymbol, toError, UNSET, valueString, } from './src/util';
17
+ export { createSignal, isMutableSignal, isSignal, type Signal, type SignalValues, type UnknownSignalRecord, } from './src/signal';
18
+ export { batchSignalWrites, type Cleanup, createWatcher, emitNotification, flushPendingReactions, type Listener, type Listeners, type Notifications, notifyWatchers, subscribeActiveWatcher, trackSignalReads, type Watcher, } from './src/system';
19
+ export { isAbortError, isAsyncFunction, isFunction, isNumber, isObjectOfType, isRecord, isRecordOrArray, isString, isSymbol, UNSET, valueString, } from './src/util';
@@ -0,0 +1,46 @@
1
+ import type { Signal } from '../signal';
2
+ import { type Cleanup, type Listener, type Listeners } from '../system';
3
+ import { type Computed } from './computed';
4
+ import { type List } from './list';
5
+ type CollectionSource<T extends {}> = List<T> | Collection<T>;
6
+ type CollectionCallback<T extends {}, U extends {}> = ((sourceValue: U) => T) | ((sourceValue: U, abort: AbortSignal) => Promise<T>);
7
+ type Collection<T extends {}> = {
8
+ readonly [Symbol.toStringTag]: 'Collection';
9
+ readonly [Symbol.isConcatSpreadable]: true;
10
+ [Symbol.iterator](): IterableIterator<Signal<T>>;
11
+ get: () => T[];
12
+ at: (index: number) => Signal<T> | undefined;
13
+ byKey: (key: string) => Signal<T> | undefined;
14
+ keyAt: (index: number) => string | undefined;
15
+ indexOfKey: (key: string) => number | undefined;
16
+ on: <K extends keyof Listeners>(type: K, listener: Listener<K>) => Cleanup;
17
+ deriveCollection: <R extends {}>(callback: CollectionCallback<R, T>) => DerivedCollection<R, T>;
18
+ readonly length: number;
19
+ };
20
+ declare const TYPE_COLLECTION: "Collection";
21
+ declare class DerivedCollection<T extends {}, U extends {}> implements Collection<T> {
22
+ #private;
23
+ constructor(source: CollectionSource<U> | (() => CollectionSource<U>), callback: CollectionCallback<T, U>);
24
+ get [Symbol.toStringTag](): 'Collection';
25
+ get [Symbol.isConcatSpreadable](): true;
26
+ [Symbol.iterator](): IterableIterator<Computed<T>>;
27
+ get length(): number;
28
+ get(): T[];
29
+ at(index: number): Computed<T> | undefined;
30
+ keys(): IterableIterator<string>;
31
+ byKey(key: string): Computed<T> | undefined;
32
+ keyAt(index: number): string | undefined;
33
+ indexOfKey(key: string): number;
34
+ on<K extends keyof Listeners>(type: K, listener: Listener<K>): Cleanup;
35
+ deriveCollection<R extends {}>(callback: (sourceValue: T) => R): DerivedCollection<R, T>;
36
+ deriveCollection<R extends {}>(callback: (sourceValue: T, abort: AbortSignal) => Promise<R>): DerivedCollection<R, T>;
37
+ }
38
+ /**
39
+ * Check if a value is a collection signal
40
+ *
41
+ * @since 0.17.0
42
+ * @param {unknown} value - Value to check
43
+ * @returns {boolean} - True if value is a collection signal, false otherwise
44
+ */
45
+ declare const isCollection: <T extends {}, U extends {}>(value: unknown) => value is DerivedCollection<T, U>;
46
+ export { type Collection, type CollectionSource, type CollectionCallback, DerivedCollection, isCollection, TYPE_COLLECTION, };
@@ -0,0 +1,15 @@
1
+ import type { DiffResult, UnknownRecord } from '../diff';
2
+ import type { Signal } from '../signal';
3
+ import { type Cleanup, type Listener, type Listeners } from '../system';
4
+ type CompositeListeners = Pick<Listeners, 'add' | 'change' | 'remove'>;
5
+ declare class Composite<T extends UnknownRecord, S extends Signal<T[keyof T] & {}>> {
6
+ #private;
7
+ signals: Map<string, S>;
8
+ constructor(values: T, validate: <K extends keyof T & string>(key: K, value: unknown) => value is T[K] & {}, create: <V extends T[keyof T] & {}>(value: V) => S);
9
+ add<K extends keyof T & string>(key: K, value: T[K]): boolean;
10
+ remove<K extends keyof T & string>(key: K): boolean;
11
+ change(changes: DiffResult, initialRun?: boolean): boolean;
12
+ clear(): boolean;
13
+ on<K extends keyof CompositeListeners>(type: K, listener: Listener<K>): Cleanup;
14
+ }
15
+ export { Composite, type CompositeListeners };
@@ -0,0 +1,97 @@
1
+ type Computed<T extends {}> = {
2
+ readonly [Symbol.toStringTag]: 'Computed';
3
+ get(): T;
4
+ };
5
+ type MemoCallback<T extends {} & {
6
+ then?: undefined;
7
+ }> = (oldValue: T) => T;
8
+ type TaskCallback<T extends {} & {
9
+ then?: undefined;
10
+ }> = (oldValue: T, abort: AbortSignal) => Promise<T>;
11
+ declare const TYPE_COMPUTED: "Computed";
12
+ /**
13
+ * Create a new memoized signal for a synchronous function.
14
+ *
15
+ * @since 0.17.0
16
+ */
17
+ declare class Memo<T extends {}> {
18
+ #private;
19
+ /**
20
+ * Create a new memoized signal.
21
+ *
22
+ * @param {MemoCallback<T>} callback - Callback function to compute the memoized value
23
+ * @param {T} [initialValue = UNSET] - Initial value of the signal
24
+ * @throws {InvalidCallbackError} If the callback is not an sync function
25
+ * @throws {InvalidSignalValueError} If the initial value is not valid
26
+ */
27
+ constructor(callback: MemoCallback<T>, initialValue?: T);
28
+ get [Symbol.toStringTag](): 'Computed';
29
+ /**
30
+ * Return the memoized value after computing it if necessary.
31
+ *
32
+ * @returns {T}
33
+ * @throws {CircularDependencyError} If a circular dependency is detected
34
+ * @throws {Error} If an error occurs during computation
35
+ */
36
+ get(): T;
37
+ }
38
+ /**
39
+ * Create a new task signals that memoizes the result of an asynchronous function.
40
+ *
41
+ * @since 0.17.0
42
+ */
43
+ declare class Task<T extends {}> {
44
+ #private;
45
+ /**
46
+ * Create a new task signal for an asynchronous function.
47
+ *
48
+ * @param {TaskCallback<T>} callback - The asynchronous function to compute the memoized value
49
+ * @param {T} [initialValue = UNSET] - Initial value of the signal
50
+ * @throws {InvalidCallbackError} If the callback is not an async function
51
+ * @throws {InvalidSignalValueError} If the initial value is not valid
52
+ */
53
+ constructor(callback: TaskCallback<T>, initialValue?: T);
54
+ get [Symbol.toStringTag](): 'Computed';
55
+ /**
56
+ * Return the memoized value after executing the async function if necessary.
57
+ *
58
+ * @returns {T}
59
+ * @throws {CircularDependencyError} If a circular dependency is detected
60
+ * @throws {Error} If an error occurs during computation
61
+ */
62
+ get(): T;
63
+ }
64
+ /**
65
+ * Create a derived signal from existing signals
66
+ *
67
+ * @since 0.9.0
68
+ * @param {MemoCallback<T> | TaskCallback<T>} callback - Computation callback function
69
+ */
70
+ declare const createComputed: <T extends {}>(callback: TaskCallback<T> | MemoCallback<T>, initialValue?: T) => Task<T> | Memo<T>;
71
+ /**
72
+ * Check if a value is a computed signal
73
+ *
74
+ * @since 0.9.0
75
+ * @param {unknown} value - Value to check
76
+ * @returns {boolean} - True if value is a computed signal, false otherwise
77
+ */
78
+ declare const isComputed: <T extends {}>(value: unknown) => value is Memo<T>;
79
+ /**
80
+ * Check if the provided value is a callback that may be used as input for createSignal() to derive a computed state
81
+ *
82
+ * @since 0.12.0
83
+ * @param {unknown} value - Value to check
84
+ * @returns {boolean} - True if value is a sync callback, false otherwise
85
+ */
86
+ declare const isMemoCallback: <T extends {} & {
87
+ then?: undefined;
88
+ }>(value: unknown) => value is MemoCallback<T>;
89
+ /**
90
+ * Check if the provided value is a callback that may be used as input for createSignal() to derive a computed state
91
+ *
92
+ * @since 0.17.0
93
+ * @param {unknown} value - Value to check
94
+ * @returns {boolean} - True if value is an async callback, false otherwise
95
+ */
96
+ declare const isTaskCallback: <T extends {}>(value: unknown) => value is TaskCallback<T>;
97
+ export { TYPE_COMPUTED, createComputed, isComputed, isMemoCallback, isTaskCallback, Memo, Task, type Computed, type MemoCallback, type TaskCallback, };
@@ -0,0 +1,41 @@
1
+ import { type UnknownArray } from '../diff';
2
+ import { type Cleanup, type Listener, type Notifications } from '../system';
3
+ import { DerivedCollection } from './collection';
4
+ import { State } from './state';
5
+ type ArrayToRecord<T extends UnknownArray> = {
6
+ [key: string]: T extends Array<infer U extends {}> ? U : never;
7
+ };
8
+ type KeyConfig<T> = string | ((item: T) => string);
9
+ declare const TYPE_LIST: "List";
10
+ declare class List<T extends {}> {
11
+ #private;
12
+ constructor(initialValue: T[], keyConfig?: KeyConfig<T>);
13
+ get [Symbol.toStringTag](): 'List';
14
+ get [Symbol.isConcatSpreadable](): true;
15
+ [Symbol.iterator](): IterableIterator<State<T>>;
16
+ get length(): number;
17
+ get(): T[];
18
+ set(newValue: T[]): void;
19
+ update(fn: (oldValue: T[]) => T[]): void;
20
+ at(index: number): State<T> | undefined;
21
+ keys(): IterableIterator<string>;
22
+ byKey(key: string): State<T> | undefined;
23
+ keyAt(index: number): string | undefined;
24
+ indexOfKey(key: string): number;
25
+ add(value: T): string;
26
+ remove(keyOrIndex: string | number): void;
27
+ sort(compareFn?: (a: T, b: T) => number): void;
28
+ splice(start: number, deleteCount?: number, ...items: T[]): T[];
29
+ on<K extends keyof Notifications>(type: K, listener: Listener<K>): Cleanup;
30
+ deriveCollection<R extends {}>(callback: (sourceValue: T) => R): DerivedCollection<R, T>;
31
+ deriveCollection<R extends {}>(callback: (sourceValue: T, abort: AbortSignal) => Promise<R>): DerivedCollection<R, T>;
32
+ }
33
+ /**
34
+ * Check if the provided value is a List instance
35
+ *
36
+ * @since 0.15.0
37
+ * @param {unknown} value - Value to check
38
+ * @returns {boolean} - True if the value is a List instance, false otherwise
39
+ */
40
+ declare const isList: <T extends {}>(value: unknown) => value is List<T>;
41
+ export { isList, List, TYPE_LIST, type ArrayToRecord, type KeyConfig };
@@ -0,0 +1,39 @@
1
+ import { type Guard } from '../errors';
2
+ declare const TYPE_REF = "Ref";
3
+ /**
4
+ * Create a new ref signal.
5
+ *
6
+ * @since 0.17.1
7
+ */
8
+ declare class Ref<T extends {}> {
9
+ #private;
10
+ /**
11
+ * Create a new ref signal.
12
+ *
13
+ * @param {T} value - Reference to external object
14
+ * @param {Guard<T>} guard - Optional guard function to validate the value
15
+ * @throws {NullishSignalValueError} - If the value is null or undefined
16
+ * @throws {InvalidSignalValueError} - If the value is invalid
17
+ */
18
+ constructor(value: T, guard?: Guard<T>);
19
+ get [Symbol.toStringTag](): string;
20
+ /**
21
+ * Get the value of the ref signal.
22
+ *
23
+ * @returns {T} - Object reference
24
+ */
25
+ get(): T;
26
+ /**
27
+ * Notify watchers of relevant changes in the external reference
28
+ */
29
+ notify(): void;
30
+ }
31
+ /**
32
+ * Check if the provided value is a Ref instance
33
+ *
34
+ * @since 0.17.1
35
+ * @param {unknown} value - Value to check
36
+ * @returns {boolean} - True if the value is a Ref instance, false otherwise
37
+ */
38
+ declare const isRef: <T extends {}>(value: unknown) => value is Ref<T>;
39
+ export { TYPE_REF, Ref, isRef };
@@ -0,0 +1,52 @@
1
+ declare const TYPE_STATE: "State";
2
+ /**
3
+ * Create a new state signal.
4
+ *
5
+ * @since 0.17.0
6
+ */
7
+ declare class State<T extends {}> {
8
+ #private;
9
+ /**
10
+ * Create a new state signal.
11
+ *
12
+ * @param {T} initialValue - Initial value of the state
13
+ * @throws {NullishSignalValueError} - If the initial value is null or undefined
14
+ * @throws {InvalidSignalValueError} - If the initial value is invalid
15
+ */
16
+ constructor(initialValue: T);
17
+ get [Symbol.toStringTag](): string;
18
+ /**
19
+ * Get the current value of the state signal.
20
+ *
21
+ * @returns {T} - Current value of the state
22
+ */
23
+ get(): T;
24
+ /**
25
+ * Set the value of the state signal.
26
+ *
27
+ * @param {T} newValue - New value of the state
28
+ * @returns {void}
29
+ * @throws {NullishSignalValueError} - If the initial value is null or undefined
30
+ * @throws {InvalidSignalValueError} - If the initial value is invalid
31
+ */
32
+ set(newValue: T): void;
33
+ /**
34
+ * Update the value of the state signal.
35
+ *
36
+ * @param {Function} updater - Function that takes the current value and returns the new value
37
+ * @returns {void}
38
+ * @throws {InvalidCallbackError} - If the updater function is not a function
39
+ * @throws {NullishSignalValueError} - If the initial value is null or undefined
40
+ * @throws {InvalidSignalValueError} - If the initial value is invalid
41
+ */
42
+ update(updater: (oldValue: T) => T): void;
43
+ }
44
+ /**
45
+ * Check if the provided value is a State instance
46
+ *
47
+ * @since 0.9.0
48
+ * @param {unknown} value - Value to check
49
+ * @returns {boolean} - True if the value is a State instance, false otherwise
50
+ */
51
+ declare const isState: <T extends {}>(value: unknown) => value is State<T>;
52
+ export { TYPE_STATE, isState, State };
@@ -0,0 +1,51 @@
1
+ import { type UnknownRecord } from '../diff';
2
+ import { type MutableSignal } from '../signal';
3
+ import { type Cleanup, type Listener, type Listeners } from '../system';
4
+ import type { List } from './list';
5
+ import type { State } from './state';
6
+ type Store<T extends UnknownRecord> = BaseStore<T> & {
7
+ [K in keyof T]: T[K] extends readonly (infer U extends {})[] ? List<U> : T[K] extends UnknownRecord ? Store<T[K]> : State<T[K] & {}>;
8
+ };
9
+ declare const TYPE_STORE: "Store";
10
+ declare class BaseStore<T extends UnknownRecord> {
11
+ #private;
12
+ /**
13
+ * Create a new store with the given initial value.
14
+ *
15
+ * @param {T} initialValue - The initial value of the store
16
+ * @throws {NullishSignalValueError} - If the initial value is null or undefined
17
+ * @throws {InvalidSignalValueError} - If the initial value is not an object
18
+ */
19
+ constructor(initialValue: T);
20
+ get [Symbol.toStringTag](): 'Store';
21
+ get [Symbol.isConcatSpreadable](): boolean;
22
+ [Symbol.iterator](): IterableIterator<[
23
+ string,
24
+ MutableSignal<T[keyof T] & {}>
25
+ ]>;
26
+ get(): T;
27
+ set(newValue: T): void;
28
+ keys(): IterableIterator<string>;
29
+ byKey<K extends keyof T & string>(key: K): T[K] extends readonly (infer U extends {})[] ? List<U> : T[K] extends UnknownRecord ? Store<T[K]> : T[K] extends unknown & {} ? State<T[K] & {}> : State<T[K] & {}> | undefined;
30
+ update(fn: (oldValue: T) => T): void;
31
+ add<K extends keyof T & string>(key: K, value: T[K]): K;
32
+ remove(key: string): void;
33
+ on<K extends keyof Omit<Listeners, 'sort'>>(type: K, listener: Listener<K>): Cleanup;
34
+ }
35
+ /**
36
+ * Create a new store with deeply nested reactive properties
37
+ *
38
+ * @since 0.15.0
39
+ * @param {T} initialValue - Initial object or array value of the store
40
+ * @returns {Store<T>} - New store with reactive properties that preserves the original type T
41
+ */
42
+ declare const createStore: <T extends UnknownRecord>(initialValue: T) => Store<T>;
43
+ /**
44
+ * Check if the provided value is a Store instance
45
+ *
46
+ * @since 0.15.0
47
+ * @param {unknown} value - Value to check
48
+ * @returns {boolean} - True if the value is a Store instance, false otherwise
49
+ */
50
+ declare const isStore: <T extends UnknownRecord>(value: unknown) => value is BaseStore<T>;
51
+ export { createStore, isStore, BaseStore, TYPE_STORE, type Store };
@@ -1,14 +1,10 @@
1
- type UnknownRecord = Record<string, unknown & {}>;
1
+ type UnknownRecord = Record<string, unknown>;
2
2
  type UnknownArray = ReadonlyArray<unknown & {}>;
3
- type ArrayToRecord<T extends UnknownArray> = {
4
- [key: string]: T extends Array<infer U extends {}> ? U : never;
5
- };
6
- type PartialRecord<T> = T extends UnknownArray ? Partial<ArrayToRecord<T>> : Partial<T>;
7
- type DiffResult<T extends UnknownRecord | UnknownArray = UnknownRecord> = {
3
+ type DiffResult = {
8
4
  changed: boolean;
9
- add: PartialRecord<T>;
10
- change: PartialRecord<T>;
11
- remove: PartialRecord<T>;
5
+ add: UnknownRecord;
6
+ change: UnknownRecord;
7
+ remove: UnknownRecord;
12
8
  };
13
9
  /**
14
10
  * Checks if two values are equal with cycle detection
@@ -26,7 +22,7 @@ declare const isEqual: <T>(a: T, b: T, visited?: WeakSet<object>) => boolean;
26
22
  * @since 0.15.0
27
23
  * @param {T} oldObj - The old record to compare
28
24
  * @param {T} newObj - The new record to compare
29
- * @returns {DiffResult<T>} The result of the comparison
25
+ * @returns {DiffResult} The result of the comparison
30
26
  */
31
- declare const diff: <T extends UnknownRecord | UnknownArray>(oldObj: T extends UnknownArray ? ArrayToRecord<T> : T, newObj: T extends UnknownArray ? ArrayToRecord<T> : T) => DiffResult<T>;
32
- export { type ArrayToRecord, type DiffResult, diff, isEqual, type UnknownRecord, type UnknownArray, type PartialRecord, };
27
+ declare const diff: <T extends UnknownRecord>(oldObj: T, newObj: T) => DiffResult;
28
+ export { type DiffResult, diff, isEqual, type UnknownRecord, type UnknownArray };
@@ -1,22 +1,28 @@
1
+ import { type MutableSignal } from './signal';
2
+ type Guard<T> = (value: unknown) => value is T;
1
3
  declare class CircularDependencyError extends Error {
2
4
  constructor(where: string);
3
5
  }
6
+ declare class DuplicateKeyError extends Error {
7
+ constructor(where: string, key: string, value?: unknown);
8
+ }
4
9
  declare class InvalidCallbackError extends TypeError {
5
- constructor(where: string, value: string);
10
+ constructor(where: string, value: unknown);
11
+ }
12
+ declare class InvalidCollectionSourceError extends TypeError {
13
+ constructor(where: string, value: unknown);
6
14
  }
7
15
  declare class InvalidSignalValueError extends TypeError {
8
- constructor(where: string, value: string);
16
+ constructor(where: string, value: unknown);
9
17
  }
10
18
  declare class NullishSignalValueError extends TypeError {
11
19
  constructor(where: string);
12
20
  }
13
- declare class StoreKeyExistsError extends Error {
14
- constructor(key: string, value: string);
15
- }
16
- declare class StoreKeyRangeError extends RangeError {
17
- constructor(index: number);
18
- }
19
- declare class StoreKeyReadonlyError extends Error {
20
- constructor(key: string, value: string);
21
+ declare class ReadonlySignalError extends Error {
22
+ constructor(what: string, value: unknown);
21
23
  }
22
- export { CircularDependencyError, InvalidCallbackError, InvalidSignalValueError, NullishSignalValueError, StoreKeyExistsError, StoreKeyRangeError, StoreKeyReadonlyError, };
24
+ declare const createError: (reason: unknown) => Error;
25
+ declare const validateCallback: (where: string, value: unknown, guard?: (value: unknown) => boolean) => void;
26
+ declare const validateSignalValue: (where: string, value: unknown, guard?: (value: unknown) => boolean) => void;
27
+ declare const guardMutableSignal: <T extends {}>(what: string, value: unknown, signal: unknown) => signal is MutableSignal<T>;
28
+ export { type Guard, CircularDependencyError, DuplicateKeyError, InvalidCallbackError, InvalidCollectionSourceError, InvalidSignalValueError, NullishSignalValueError, ReadonlySignalError, createError, validateCallback, validateSignalValue, guardMutableSignal, };
@@ -1,9 +1,13 @@
1
- import { type Computed, type ComputedCallback } from './computed';
2
- import { type State } from './state';
3
- import { type Store } from './store';
1
+ import { type Computed } from './classes/computed';
2
+ import { List } from './classes/list';
3
+ import { State } from './classes/state';
4
+ import { type Store } from './classes/store';
5
+ import type { UnknownRecord } from './diff';
4
6
  type Signal<T extends {}> = {
5
7
  get(): T;
6
8
  };
9
+ type MutableSignal<T extends {}> = T extends readonly (infer U extends {})[] ? List<U> : T extends UnknownRecord ? Store<T> : State<T>;
10
+ type ReadonlySignal<T extends {}> = Computed<T>;
7
11
  type UnknownSignalRecord = Record<string, Signal<unknown & {}>>;
8
12
  type SignalValues<S extends UnknownSignalRecord> = {
9
13
  [K in keyof S]: S[K] extends Signal<infer T> ? T : never;
@@ -17,21 +21,30 @@ type SignalValues<S extends UnknownSignalRecord> = {
17
21
  */
18
22
  declare const isSignal: <T extends {}>(value: unknown) => value is Signal<T>;
19
23
  /**
20
- * Check whether a value is a State or Store
24
+ * Check whether a value is a State, Store, or List
21
25
  *
22
26
  * @since 0.15.2
23
- * @param {unknown} value - value to check
24
- * @returns {boolean} - true if value is a State or Store, false otherwise
27
+ * @param {unknown} value - Value to check
28
+ * @returns {boolean} - True if value is a State, Store, or List, false otherwise
25
29
  */
26
- declare const isMutableSignal: <T extends {}>(value: unknown) => value is State<T> | Store<T>;
30
+ declare const isMutableSignal: (value: unknown) => value is MutableSignal<unknown & {}>;
27
31
  /**
28
- * Convert a value to a Signal if it's not already a Signal
32
+ * Convert a value to a Signal.
29
33
  *
30
34
  * @since 0.9.6
31
- * @param {T} value - value to convert
32
- * @returns {Signal<T>} - Signal instance
33
35
  */
34
- declare function toSignal<T extends {}>(value: T): T extends Store<infer U> ? Store<U> : T extends State<infer U> ? State<U> : T extends Computed<infer U> ? Computed<U> : T extends Signal<infer U> ? Signal<U> : T extends ReadonlyArray<infer U extends {}> ? Store<U[]> : T extends Record<string, unknown & {}> ? Store<{
35
- [K in keyof T]: T[K];
36
- }> : T extends ComputedCallback<infer U extends {}> ? Computed<U> : State<T>;
37
- export { type Signal, type UnknownSignalRecord, type SignalValues, isSignal, isMutableSignal, toSignal, };
36
+ declare function createSignal<T extends {}>(value: readonly T[]): List<T>;
37
+ declare function createSignal<T extends {}>(value: T[]): List<T>;
38
+ declare function createSignal<T extends UnknownRecord>(value: T): Store<T>;
39
+ declare function createSignal<T extends {}>(value: () => T): Computed<T>;
40
+ declare function createSignal<T extends {}>(value: T): State<T>;
41
+ /**
42
+ * Convert a value to a MutableSignal.
43
+ *
44
+ * @since 0.17.0
45
+ */
46
+ declare function createMutableSignal<T extends {}>(value: readonly T[]): List<T>;
47
+ declare function createMutableSignal<T extends {}>(value: T[]): List<T>;
48
+ declare function createMutableSignal<T extends UnknownRecord>(value: T): Store<T>;
49
+ declare function createMutableSignal<T extends {}>(value: T): State<T>;
50
+ export { createMutableSignal, createSignal, isMutableSignal, isSignal, type MutableSignal, type ReadonlySignal, type Signal, type SignalValues, type UnknownSignalRecord, };
@@ -1,44 +1,65 @@
1
1
  type Cleanup = () => void;
2
2
  type Watcher = {
3
3
  (): void;
4
- unwatch(cleanup: Cleanup): void;
5
- cleanup(): void;
4
+ onCleanup(cleanup: Cleanup): void;
5
+ stop(): void;
6
+ };
7
+ type Notifications = {
8
+ add: readonly string[];
9
+ change: readonly string[];
10
+ remove: readonly string[];
11
+ sort: readonly string[];
12
+ };
13
+ type Listener<K extends keyof Notifications> = (payload: Notifications[K]) => void;
14
+ type Listeners = {
15
+ [K in keyof Notifications]: Set<Listener<K>>;
6
16
  };
7
17
  /**
8
18
  * Create a watcher that can be used to observe changes to a signal
9
19
  *
20
+ * A watcher is a reaction function with onCleanup and stop methods
21
+ *
10
22
  * @since 0.14.1
11
- * @param {() => void} watch - Function to be called when the state changes
23
+ * @param {() => void} react - Function to be called when the state changes
12
24
  * @returns {Watcher} - Watcher object with off and cleanup methods
13
25
  */
14
- declare const createWatcher: (watch: () => void) => Watcher;
26
+ declare const createWatcher: (react: () => void) => Watcher;
15
27
  /**
16
- * Add active watcher to the Set of watchers
28
+ * Subscribe by adding active watcher to the Set of watchers of a signal
17
29
  *
18
- * @param {Set<Watcher>} watchers - watchers of the signal
30
+ * @param {Set<Watcher>} watchers - Watchers of the signal
19
31
  */
20
- declare const subscribe: (watchers: Set<Watcher>) => void;
32
+ declare const subscribeActiveWatcher: (watchers: Set<Watcher>) => void;
21
33
  /**
22
- * Add watchers to the pending set of change notifications
34
+ * Notify watchers of a signal change
23
35
  *
24
- * @param {Set<Watcher>} watchers - watchers of the signal
36
+ * @param {Set<Watcher>} watchers - Watchers of the signal
25
37
  */
26
- declare const notify: (watchers: Set<Watcher>) => void;
38
+ declare const notifyWatchers: (watchers: Set<Watcher>) => void;
27
39
  /**
28
- * Flush all pending changes to notify watchers
40
+ * Flush all pending reactions of enqueued watchers
41
+ */
42
+ declare const flushPendingReactions: () => void;
43
+ /**
44
+ * Batch multiple signal writes
45
+ *
46
+ * @param {() => void} callback - Function with multiple signal writes to be batched
29
47
  */
30
- declare const flush: () => void;
48
+ declare const batchSignalWrites: (callback: () => void) => void;
31
49
  /**
32
- * Batch multiple changes in a single signal graph and DOM update cycle
50
+ * Run a function with signal reads in a tracking context (or temporarily untrack)
33
51
  *
34
- * @param {() => void} fn - function with multiple signal writes to be batched
52
+ * @param {Watcher | false} watcher - Watcher to be called when the signal changes
53
+ * or false for temporary untracking while inserting auto-hydrating DOM nodes
54
+ * that might read signals (e.g., Web Components)
55
+ * @param {() => void} run - Function to run the computation or effect
35
56
  */
36
- declare const batch: (fn: () => void) => void;
57
+ declare const trackSignalReads: (watcher: Watcher | false, run: () => void) => void;
37
58
  /**
38
- * Run a function in a reactive context
59
+ * Emit a notification to listeners
39
60
  *
40
- * @param {() => void} run - function to run the computation or effect
41
- * @param {Watcher} watcher - function to be called when the state changes or undefined for temporary unwatching while inserting auto-hydrating DOM nodes that might read signals (e.g., web components)
61
+ * @param {Set<Listener>} listeners - Listeners to be notified
62
+ * @param {Notifications[K]} payload - Payload to be sent to listeners
42
63
  */
43
- declare const observe: (run: () => void, watcher?: Watcher) => void;
44
- export { type Cleanup, type Watcher, subscribe, notify, flush, batch, createWatcher, observe, };
64
+ declare const emitNotification: <T extends keyof Notifications>(listeners: Set<Listener<T>>, payload: Notifications[T]) => void;
65
+ export { type Cleanup, type Watcher, type Notifications, type Listener, type Listeners, createWatcher, subscribeActiveWatcher, notifyWatchers, flushPendingReactions, batchSignalWrites, trackSignalReads, emitNotification, };
@@ -4,13 +4,15 @@ declare const isNumber: (value: unknown) => value is number;
4
4
  declare const isSymbol: (value: unknown) => value is symbol;
5
5
  declare const isFunction: <T>(fn: unknown) => fn is (...args: unknown[]) => T;
6
6
  declare const isAsyncFunction: <T>(fn: unknown) => fn is (...args: unknown[]) => Promise<T>;
7
+ declare const isSyncFunction: <T extends unknown & {
8
+ then?: undefined;
9
+ }>(fn: unknown) => fn is (...args: unknown[]) => T;
10
+ declare const isNonNullObject: (value: unknown) => value is NonNullable<object>;
7
11
  declare const isObjectOfType: <T>(value: unknown, type: string) => value is T;
8
12
  declare const isRecord: <T extends Record<string, unknown>>(value: unknown) => value is T;
9
13
  declare const isRecordOrArray: <T extends Record<string | number, unknown> | ReadonlyArray<unknown>>(value: unknown) => value is T;
14
+ declare const isUniformArray: <T>(value: unknown, guard?: (item: T) => item is T & {}) => value is T[];
10
15
  declare const hasMethod: <T extends object & Record<string, (...args: unknown[]) => unknown>>(obj: T, methodName: string) => obj is T & Record<string, (...args: unknown[]) => unknown>;
11
16
  declare const isAbortError: (error: unknown) => boolean;
12
- declare const toError: (reason: unknown) => Error;
13
- declare const arrayToRecord: <T>(array: T[]) => Record<string, T>;
14
- declare const recordToArray: <T>(record: Record<string | number, T>) => Record<string, T> | T[];
15
17
  declare const valueString: (value: unknown) => string;
16
- export { UNSET, isString, isNumber, isSymbol, isFunction, isAsyncFunction, isObjectOfType, isRecord, isRecordOrArray, hasMethod, isAbortError, toError, arrayToRecord, recordToArray, valueString, };
18
+ export { UNSET, isString, isNumber, isSymbol, isFunction, isAsyncFunction, isSyncFunction, isNonNullObject, isObjectOfType, isRecord, isRecordOrArray, isUniformArray, hasMethod, isAbortError, valueString, };