@zeix/cause-effect 0.17.0 → 0.17.2
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 +26 -5
- package/.cursorrules +8 -3
- package/.github/copilot-instructions.md +13 -4
- package/CLAUDE.md +191 -262
- package/README.md +268 -420
- package/archive/collection.ts +23 -25
- package/archive/computed.ts +5 -4
- package/archive/list.ts +21 -28
- package/archive/memo.ts +4 -2
- package/archive/state.ts +2 -1
- package/archive/store.ts +21 -32
- package/archive/task.ts +6 -9
- package/index.dev.js +411 -220
- package/index.js +1 -1
- package/index.ts +25 -8
- package/package.json +1 -1
- package/src/classes/collection.ts +103 -77
- package/src/classes/composite.ts +28 -33
- package/src/classes/computed.ts +90 -31
- package/src/classes/list.ts +39 -33
- package/src/classes/ref.ts +96 -0
- package/src/classes/state.ts +41 -8
- package/src/classes/store.ts +47 -30
- package/src/diff.ts +2 -1
- package/src/effect.ts +19 -9
- package/src/errors.ts +31 -1
- package/src/match.ts +5 -12
- package/src/resolve.ts +3 -2
- package/src/signal.ts +0 -1
- package/src/system.ts +159 -43
- package/src/util.ts +0 -10
- package/test/collection.test.ts +383 -67
- package/test/computed.test.ts +268 -11
- package/test/effect.test.ts +2 -2
- package/test/list.test.ts +249 -21
- package/test/ref.test.ts +381 -0
- package/test/state.test.ts +13 -13
- package/test/store.test.ts +473 -28
- package/types/index.d.ts +6 -5
- package/types/src/classes/collection.d.ts +27 -12
- package/types/src/classes/composite.d.ts +4 -4
- package/types/src/classes/computed.d.ts +17 -0
- package/types/src/classes/list.d.ts +6 -6
- package/types/src/classes/ref.d.ts +48 -0
- package/types/src/classes/state.d.ts +9 -0
- package/types/src/classes/store.d.ts +4 -4
- package/types/src/effect.d.ts +1 -2
- package/types/src/errors.d.ts +9 -1
- package/types/src/system.d.ts +40 -24
- package/types/src/util.d.ts +1 -3
package/archive/collection.ts
CHANGED
|
@@ -5,16 +5,17 @@ import type { Signal } from '../src/signal'
|
|
|
5
5
|
import {
|
|
6
6
|
type Cleanup,
|
|
7
7
|
createWatcher,
|
|
8
|
-
|
|
9
|
-
type
|
|
10
|
-
type
|
|
11
|
-
type
|
|
8
|
+
triggerHook,
|
|
9
|
+
type HookCallback,
|
|
10
|
+
type HookCallbacks,
|
|
11
|
+
type Hook,
|
|
12
12
|
notifyWatchers,
|
|
13
13
|
subscribeActiveWatcher,
|
|
14
14
|
trackSignalReads,
|
|
15
15
|
type Watcher,
|
|
16
|
+
UNSET,
|
|
16
17
|
} from '../src/system'
|
|
17
|
-
import { isAsyncFunction, isObjectOfType, isSymbol
|
|
18
|
+
import { isAsyncFunction, isObjectOfType, isSymbol } from '../src/util'
|
|
18
19
|
import { type Computed, createComputed } from './computed'
|
|
19
20
|
import type { List } from './list'
|
|
20
21
|
|
|
@@ -39,7 +40,7 @@ type Collection<T extends {}> = {
|
|
|
39
40
|
get(): T[]
|
|
40
41
|
keyAt(index: number): string | undefined
|
|
41
42
|
indexOfKey(key: string): number
|
|
42
|
-
on
|
|
43
|
+
on(type: Hook, callback: HookCallback): Cleanup
|
|
43
44
|
sort(compareFn?: (a: T, b: T) => number): void
|
|
44
45
|
}
|
|
45
46
|
|
|
@@ -66,12 +67,7 @@ const createCollection = <T extends {}, O extends {}>(
|
|
|
66
67
|
callback: CollectionCallback<T, O>,
|
|
67
68
|
): Collection<T> => {
|
|
68
69
|
const watchers = new Set<Watcher>()
|
|
69
|
-
const
|
|
70
|
-
add: new Set<Listener<'add'>>(),
|
|
71
|
-
change: new Set<Listener<'change'>>(),
|
|
72
|
-
remove: new Set<Listener<'remove'>>(),
|
|
73
|
-
sort: new Set<Listener<'sort'>>(),
|
|
74
|
-
}
|
|
70
|
+
const hookCallbacks: HookCallbacks = {}
|
|
75
71
|
const signals = new Map<string, Signal<T>>()
|
|
76
72
|
const signalWatchers = new Map<string, Watcher>()
|
|
77
73
|
|
|
@@ -121,7 +117,7 @@ const createCollection = <T extends {}, O extends {}>(
|
|
|
121
117
|
const watcher = createWatcher(() =>
|
|
122
118
|
trackSignalReads(watcher, () => {
|
|
123
119
|
signal.get() // Subscribe to the signal
|
|
124
|
-
|
|
120
|
+
triggerHook(hookCallbacks.change, [key])
|
|
125
121
|
}),
|
|
126
122
|
)
|
|
127
123
|
watcher()
|
|
@@ -152,25 +148,29 @@ const createCollection = <T extends {}, O extends {}>(
|
|
|
152
148
|
addProperty(key)
|
|
153
149
|
}
|
|
154
150
|
origin.on('add', additions => {
|
|
151
|
+
if (!additions?.length) return
|
|
155
152
|
for (const key of additions) {
|
|
156
153
|
if (!signals.has(key)) addProperty(key)
|
|
157
154
|
}
|
|
158
155
|
notifyWatchers(watchers)
|
|
159
|
-
|
|
156
|
+
triggerHook(hookCallbacks.add, additions)
|
|
160
157
|
})
|
|
161
158
|
origin.on('remove', removals => {
|
|
159
|
+
if (!removals?.length) return
|
|
162
160
|
for (const key of Object.keys(removals)) {
|
|
163
161
|
if (!signals.has(key)) continue
|
|
164
162
|
removeProperty(key)
|
|
165
163
|
}
|
|
166
164
|
order = order.filter(() => true) // Compact array
|
|
167
165
|
notifyWatchers(watchers)
|
|
168
|
-
|
|
166
|
+
triggerHook(hookCallbacks.remove, removals)
|
|
169
167
|
})
|
|
170
168
|
origin.on('sort', newOrder => {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
169
|
+
if (newOrder) {
|
|
170
|
+
order = [...newOrder]
|
|
171
|
+
notifyWatchers(watchers)
|
|
172
|
+
triggerHook(hookCallbacks.sort, newOrder)
|
|
173
|
+
}
|
|
174
174
|
})
|
|
175
175
|
|
|
176
176
|
// Get signal by key or index
|
|
@@ -247,16 +247,14 @@ const createCollection = <T extends {}, O extends {}>(
|
|
|
247
247
|
order = entries.map(([_, key]) => key)
|
|
248
248
|
|
|
249
249
|
notifyWatchers(watchers)
|
|
250
|
-
|
|
250
|
+
triggerHook(hookCallbacks.sort, order)
|
|
251
251
|
},
|
|
252
252
|
},
|
|
253
253
|
on: {
|
|
254
|
-
value:
|
|
255
|
-
type
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
listeners[type].add(listener)
|
|
259
|
-
return () => listeners[type].delete(listener)
|
|
254
|
+
value: (type: Hook, callback: HookCallback): Cleanup => {
|
|
255
|
+
hookCallbacks[type] ||= new Set()
|
|
256
|
+
hookCallbacks[type].add(callback)
|
|
257
|
+
return () => hookCallbacks[type]?.delete(callback)
|
|
260
258
|
},
|
|
261
259
|
},
|
|
262
260
|
length: {
|
package/archive/computed.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { isEqual } from '../src/diff'
|
|
2
2
|
import {
|
|
3
3
|
CircularDependencyError,
|
|
4
|
+
createError,
|
|
4
5
|
InvalidCallbackError,
|
|
5
6
|
NullishSignalValueError,
|
|
6
7
|
} from '../src/errors'
|
|
7
8
|
import {
|
|
8
9
|
createWatcher,
|
|
9
10
|
flushPendingReactions,
|
|
11
|
+
HOOK_CLEANUP,
|
|
10
12
|
notifyWatchers,
|
|
11
13
|
subscribeActiveWatcher,
|
|
12
14
|
trackSignalReads,
|
|
15
|
+
UNSET,
|
|
13
16
|
type Watcher,
|
|
14
17
|
} from '../src/system'
|
|
15
18
|
import {
|
|
@@ -17,8 +20,6 @@ import {
|
|
|
17
20
|
isAsyncFunction,
|
|
18
21
|
isFunction,
|
|
19
22
|
isObjectOfType,
|
|
20
|
-
toError,
|
|
21
|
-
UNSET,
|
|
22
23
|
} from '../src/util'
|
|
23
24
|
|
|
24
25
|
/* === Types === */
|
|
@@ -78,7 +79,7 @@ const createComputed = <T extends {}>(
|
|
|
78
79
|
error = undefined
|
|
79
80
|
}
|
|
80
81
|
const err = (e: unknown): undefined => {
|
|
81
|
-
const newError =
|
|
82
|
+
const newError = createError(e)
|
|
82
83
|
changed =
|
|
83
84
|
!error ||
|
|
84
85
|
newError.name !== error.name ||
|
|
@@ -102,7 +103,7 @@ const createComputed = <T extends {}>(
|
|
|
102
103
|
if (watchers.size) notifyWatchers(watchers)
|
|
103
104
|
else watcher.stop()
|
|
104
105
|
})
|
|
105
|
-
watcher.
|
|
106
|
+
watcher.on(HOOK_CLEANUP, () => {
|
|
106
107
|
controller?.abort()
|
|
107
108
|
})
|
|
108
109
|
|
package/archive/list.ts
CHANGED
|
@@ -10,13 +10,14 @@ import {
|
|
|
10
10
|
batchSignalWrites,
|
|
11
11
|
type Cleanup,
|
|
12
12
|
createWatcher,
|
|
13
|
-
|
|
14
|
-
type
|
|
15
|
-
type
|
|
16
|
-
type Notifications,
|
|
13
|
+
type Hook,
|
|
14
|
+
type HookCallback,
|
|
15
|
+
type HookCallbacks,
|
|
17
16
|
notifyWatchers,
|
|
18
17
|
subscribeActiveWatcher,
|
|
19
18
|
trackSignalReads,
|
|
19
|
+
triggerHook,
|
|
20
|
+
UNSET,
|
|
20
21
|
type Watcher,
|
|
21
22
|
} from '../src/system'
|
|
22
23
|
import {
|
|
@@ -26,7 +27,6 @@ import {
|
|
|
26
27
|
isRecord,
|
|
27
28
|
isString,
|
|
28
29
|
isSymbol,
|
|
29
|
-
UNSET,
|
|
30
30
|
} from '../src/util'
|
|
31
31
|
import {
|
|
32
32
|
type Collection,
|
|
@@ -63,7 +63,7 @@ type List<T extends {}> = {
|
|
|
63
63
|
update(fn: (value: T) => T): void
|
|
64
64
|
sort<U = T>(compareFn?: (a: U, b: U) => number): void
|
|
65
65
|
splice(start: number, deleteCount?: number, ...items: T[]): T[]
|
|
66
|
-
on
|
|
66
|
+
on(type: Hook, callback: HookCallback): Cleanup
|
|
67
67
|
remove(index: number): void
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -90,12 +90,7 @@ const createList = <T extends {}>(
|
|
|
90
90
|
if (initialValue == null) throw new NullishSignalValueError('store')
|
|
91
91
|
|
|
92
92
|
const watchers = new Set<Watcher>()
|
|
93
|
-
const
|
|
94
|
-
add: new Set<Listener<'add'>>(),
|
|
95
|
-
change: new Set<Listener<'change'>>(),
|
|
96
|
-
remove: new Set<Listener<'remove'>>(),
|
|
97
|
-
sort: new Set<Listener<'sort'>>(),
|
|
98
|
-
}
|
|
93
|
+
const hookCallbacks: HookCallbacks = {}
|
|
99
94
|
const signals = new Map<string, MutableSignal<T>>()
|
|
100
95
|
const ownWatchers = new Map<string, Watcher>()
|
|
101
96
|
|
|
@@ -163,7 +158,7 @@ const createList = <T extends {}>(
|
|
|
163
158
|
const watcher = createWatcher(() => {
|
|
164
159
|
trackSignalReads(watcher, () => {
|
|
165
160
|
signal.get() // Subscribe to the signal
|
|
166
|
-
|
|
161
|
+
triggerHook(hookCallbacks.change, [key])
|
|
167
162
|
})
|
|
168
163
|
})
|
|
169
164
|
ownWatchers.set(key, watcher)
|
|
@@ -191,11 +186,11 @@ const createList = <T extends {}>(
|
|
|
191
186
|
signals.set(key, signal)
|
|
192
187
|
if (!order.includes(key)) order.push(key)
|
|
193
188
|
// @ts-expect-error ignore
|
|
194
|
-
if (
|
|
189
|
+
if (hookCallbacks.change?.size) addOwnWatcher(key, signal)
|
|
195
190
|
|
|
196
191
|
if (single) {
|
|
197
192
|
notifyWatchers(watchers)
|
|
198
|
-
|
|
193
|
+
triggerHook(hookCallbacks.add, [key])
|
|
199
194
|
}
|
|
200
195
|
return true
|
|
201
196
|
}
|
|
@@ -218,7 +213,7 @@ const createList = <T extends {}>(
|
|
|
218
213
|
if (single) {
|
|
219
214
|
order = order.filter(() => true) // Compact array
|
|
220
215
|
notifyWatchers(watchers)
|
|
221
|
-
|
|
216
|
+
triggerHook(hookCallbacks.remove, [key])
|
|
222
217
|
}
|
|
223
218
|
}
|
|
224
219
|
|
|
@@ -233,9 +228,9 @@ const createList = <T extends {}>(
|
|
|
233
228
|
// Queue initial additions event to allow listeners to be added first
|
|
234
229
|
if (initialRun)
|
|
235
230
|
setTimeout(() => {
|
|
236
|
-
|
|
231
|
+
triggerHook(hookCallbacks.add, Object.keys(changes.add))
|
|
237
232
|
}, 0)
|
|
238
|
-
else
|
|
233
|
+
else triggerHook(hookCallbacks.add, Object.keys(changes.add))
|
|
239
234
|
}
|
|
240
235
|
|
|
241
236
|
// Changes
|
|
@@ -249,7 +244,7 @@ const createList = <T extends {}>(
|
|
|
249
244
|
if (isMutableSignal(signal)) signal.set(value)
|
|
250
245
|
else throw new ReadonlySignalError(key, value)
|
|
251
246
|
}
|
|
252
|
-
|
|
247
|
+
triggerHook(hookCallbacks.change, Object.keys(changes.change))
|
|
253
248
|
})
|
|
254
249
|
}
|
|
255
250
|
|
|
@@ -257,7 +252,7 @@ const createList = <T extends {}>(
|
|
|
257
252
|
if (Object.keys(changes.remove).length) {
|
|
258
253
|
for (const key in changes.remove) removeProperty(key)
|
|
259
254
|
order = order.filter(() => true)
|
|
260
|
-
|
|
255
|
+
triggerHook(hookCallbacks.remove, Object.keys(changes.remove))
|
|
261
256
|
}
|
|
262
257
|
|
|
263
258
|
return changes.changed
|
|
@@ -401,7 +396,7 @@ const createList = <T extends {}>(
|
|
|
401
396
|
if (!isEqual(newOrder, order)) {
|
|
402
397
|
order = newOrder
|
|
403
398
|
notifyWatchers(watchers)
|
|
404
|
-
|
|
399
|
+
triggerHook(hookCallbacks.sort, order)
|
|
405
400
|
}
|
|
406
401
|
},
|
|
407
402
|
},
|
|
@@ -473,18 +468,16 @@ const createList = <T extends {}>(
|
|
|
473
468
|
},
|
|
474
469
|
},
|
|
475
470
|
on: {
|
|
476
|
-
value:
|
|
477
|
-
type
|
|
478
|
-
|
|
479
|
-
): Cleanup => {
|
|
480
|
-
listeners[type].add(listener)
|
|
471
|
+
value: (type: Hook, callback: HookCallback): Cleanup => {
|
|
472
|
+
hookCallbacks[type] ||= new Set()
|
|
473
|
+
hookCallbacks[type].add(callback)
|
|
481
474
|
if (type === 'change' && !ownWatchers.size) {
|
|
482
475
|
for (const [key, signal] of signals)
|
|
483
476
|
addOwnWatcher(key, signal)
|
|
484
477
|
}
|
|
485
478
|
return () => {
|
|
486
|
-
|
|
487
|
-
if (type === 'change' && !
|
|
479
|
+
hookCallbacks[type]?.delete(callback)
|
|
480
|
+
if (type === 'change' && !hookCallbacks.change?.size) {
|
|
488
481
|
if (ownWatchers.size) {
|
|
489
482
|
for (const watcher of ownWatchers.values())
|
|
490
483
|
watcher.stop()
|
package/archive/memo.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CircularDependencyError,
|
|
3
|
+
createError,
|
|
3
4
|
InvalidCallbackError,
|
|
4
5
|
NullishSignalValueError,
|
|
5
6
|
} from '../src/errors'
|
|
@@ -9,9 +10,10 @@ import {
|
|
|
9
10
|
notifyWatchers,
|
|
10
11
|
subscribeActiveWatcher,
|
|
11
12
|
trackSignalReads,
|
|
13
|
+
UNSET,
|
|
12
14
|
type Watcher,
|
|
13
15
|
} from '../src/system'
|
|
14
|
-
import { isObjectOfType, isSyncFunction
|
|
16
|
+
import { isObjectOfType, isSyncFunction } from '../src/util'
|
|
15
17
|
|
|
16
18
|
/* === Types === */
|
|
17
19
|
|
|
@@ -69,7 +71,7 @@ const createMemo = <T extends {}>(
|
|
|
69
71
|
} catch (e) {
|
|
70
72
|
// Err track
|
|
71
73
|
value = UNSET
|
|
72
|
-
error =
|
|
74
|
+
error = createError(e)
|
|
73
75
|
computing = false
|
|
74
76
|
return
|
|
75
77
|
}
|
package/archive/state.ts
CHANGED
|
@@ -3,9 +3,10 @@ import { InvalidCallbackError, NullishSignalValueError } from '../src/errors'
|
|
|
3
3
|
import {
|
|
4
4
|
notifyWatchers,
|
|
5
5
|
subscribeActiveWatcher,
|
|
6
|
+
UNSET,
|
|
6
7
|
type Watcher,
|
|
7
8
|
} from '../src/system'
|
|
8
|
-
import { isFunction, isObjectOfType
|
|
9
|
+
import { isFunction, isObjectOfType } from '../src/util'
|
|
9
10
|
|
|
10
11
|
/* === Types === */
|
|
11
12
|
|
package/archive/store.ts
CHANGED
|
@@ -10,22 +10,17 @@ import {
|
|
|
10
10
|
batchSignalWrites,
|
|
11
11
|
type Cleanup,
|
|
12
12
|
createWatcher,
|
|
13
|
-
|
|
14
|
-
type
|
|
15
|
-
type
|
|
16
|
-
type Notifications,
|
|
13
|
+
type HookCallback,
|
|
14
|
+
type HookCallbacks,
|
|
15
|
+
type Hook,
|
|
17
16
|
notifyWatchers,
|
|
18
17
|
subscribeActiveWatcher,
|
|
19
18
|
trackSignalReads,
|
|
20
19
|
type Watcher,
|
|
21
|
-
} from '../src/system'
|
|
22
|
-
import {
|
|
23
|
-
isFunction,
|
|
24
|
-
isObjectOfType,
|
|
25
|
-
isRecord,
|
|
26
|
-
isSymbol,
|
|
27
20
|
UNSET,
|
|
28
|
-
|
|
21
|
+
triggerHook,
|
|
22
|
+
} from '../src/system'
|
|
23
|
+
import { isFunction, isObjectOfType, isRecord, isSymbol } from '../src/util'
|
|
29
24
|
import { isComputed } from './computed'
|
|
30
25
|
import { createList, isList, type List } from './list'
|
|
31
26
|
import { createState, isState, type State } from './state'
|
|
@@ -62,7 +57,7 @@ type Store<T extends UnknownRecord> = {
|
|
|
62
57
|
sort<U = T[Extract<keyof T, string>]>(
|
|
63
58
|
compareFn?: (a: U, b: U) => number,
|
|
64
59
|
): void
|
|
65
|
-
on
|
|
60
|
+
on(type: Hook, callback: HookCallback): Cleanup
|
|
66
61
|
remove<K extends Extract<keyof T, string>>(key: K): void
|
|
67
62
|
}
|
|
68
63
|
|
|
@@ -92,11 +87,7 @@ const createStore = <T extends UnknownRecord>(initialValue: T): Store<T> => {
|
|
|
92
87
|
if (initialValue == null) throw new NullishSignalValueError('store')
|
|
93
88
|
|
|
94
89
|
const watchers = new Set<Watcher>()
|
|
95
|
-
const
|
|
96
|
-
add: new Set<Listener<'add'>>(),
|
|
97
|
-
change: new Set<Listener<'change'>>(),
|
|
98
|
-
remove: new Set<Listener<'remove'>>(),
|
|
99
|
-
}
|
|
90
|
+
const hookCallbacks: HookCallbacks = {}
|
|
100
91
|
const signals = new Map<
|
|
101
92
|
string,
|
|
102
93
|
MutableSignal<T[Extract<keyof T, string>] & {}>
|
|
@@ -131,7 +122,7 @@ const createStore = <T extends UnknownRecord>(initialValue: T): Store<T> => {
|
|
|
131
122
|
const watcher = createWatcher(() => {
|
|
132
123
|
trackSignalReads(watcher, () => {
|
|
133
124
|
signal.get() // Subscribe to the signal
|
|
134
|
-
|
|
125
|
+
triggerHook(hookCallbacks.change, [key])
|
|
135
126
|
})
|
|
136
127
|
})
|
|
137
128
|
ownWatchers.set(key, watcher)
|
|
@@ -159,11 +150,11 @@ const createStore = <T extends UnknownRecord>(initialValue: T): Store<T> => {
|
|
|
159
150
|
// Set internal states
|
|
160
151
|
// @ts-expect-error non-matching signal types
|
|
161
152
|
signals.set(key, signal)
|
|
162
|
-
if (
|
|
153
|
+
if (hookCallbacks.change?.size) addOwnWatcher(key, signal)
|
|
163
154
|
|
|
164
155
|
if (single) {
|
|
165
156
|
notifyWatchers(watchers)
|
|
166
|
-
|
|
157
|
+
triggerHook(hookCallbacks.add, [key])
|
|
167
158
|
}
|
|
168
159
|
return true
|
|
169
160
|
}
|
|
@@ -183,7 +174,7 @@ const createStore = <T extends UnknownRecord>(initialValue: T): Store<T> => {
|
|
|
183
174
|
|
|
184
175
|
if (single) {
|
|
185
176
|
notifyWatchers(watchers)
|
|
186
|
-
|
|
177
|
+
triggerHook(hookCallbacks.remove, [key])
|
|
187
178
|
}
|
|
188
179
|
}
|
|
189
180
|
|
|
@@ -201,9 +192,9 @@ const createStore = <T extends UnknownRecord>(initialValue: T): Store<T> => {
|
|
|
201
192
|
// Queue initial additions event to allow listeners to be added first
|
|
202
193
|
if (initialRun)
|
|
203
194
|
setTimeout(() => {
|
|
204
|
-
|
|
195
|
+
triggerHook(hookCallbacks.add, Object.keys(changes.add))
|
|
205
196
|
}, 0)
|
|
206
|
-
else
|
|
197
|
+
else triggerHook(hookCallbacks.add, Object.keys(changes.add))
|
|
207
198
|
}
|
|
208
199
|
|
|
209
200
|
// Changes
|
|
@@ -220,14 +211,14 @@ const createStore = <T extends UnknownRecord>(initialValue: T): Store<T> => {
|
|
|
220
211
|
if (isMutableSignal(signal)) signal.set(value)
|
|
221
212
|
else throw new ReadonlySignalError(key, value)
|
|
222
213
|
}
|
|
223
|
-
|
|
214
|
+
triggerHook(hookCallbacks.change, Object.keys(changes.change))
|
|
224
215
|
})
|
|
225
216
|
}
|
|
226
217
|
|
|
227
218
|
// Removals
|
|
228
219
|
if (Object.keys(changes.remove).length) {
|
|
229
220
|
for (const key in changes.remove) removeProperty(key)
|
|
230
|
-
|
|
221
|
+
triggerHook(hookCallbacks.remove, Object.keys(changes.remove))
|
|
231
222
|
}
|
|
232
223
|
|
|
233
224
|
return changes.changed
|
|
@@ -296,19 +287,17 @@ const createStore = <T extends UnknownRecord>(initialValue: T): Store<T> => {
|
|
|
296
287
|
},
|
|
297
288
|
},
|
|
298
289
|
on: {
|
|
299
|
-
value:
|
|
300
|
-
type
|
|
301
|
-
|
|
302
|
-
): Cleanup => {
|
|
303
|
-
listeners[type].add(listener)
|
|
290
|
+
value: (type: Hook, callback: HookCallback): Cleanup => {
|
|
291
|
+
hookCallbacks[type] ||= new Set()
|
|
292
|
+
hookCallbacks[type].add(callback)
|
|
304
293
|
if (type === 'change' && !ownWatchers.size) {
|
|
305
294
|
for (const [key, signal] of signals)
|
|
306
295
|
// @ts-expect-error ignore
|
|
307
296
|
addOwnWatcher(key, signal)
|
|
308
297
|
}
|
|
309
298
|
return () => {
|
|
310
|
-
|
|
311
|
-
if (type === 'change' && !
|
|
299
|
+
hookCallbacks[type]?.delete(callback)
|
|
300
|
+
if (type === 'change' && !hookCallbacks.change?.size) {
|
|
312
301
|
if (ownWatchers.size) {
|
|
313
302
|
for (const watcher of ownWatchers.values())
|
|
314
303
|
watcher.stop()
|
package/archive/task.ts
CHANGED
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
import { isEqual } from '../src/diff'
|
|
2
2
|
import {
|
|
3
3
|
CircularDependencyError,
|
|
4
|
+
createError,
|
|
4
5
|
InvalidCallbackError,
|
|
5
6
|
NullishSignalValueError,
|
|
6
7
|
} from '../src/errors'
|
|
7
8
|
import {
|
|
8
9
|
createWatcher,
|
|
9
10
|
flushPendingReactions,
|
|
11
|
+
HOOK_CLEANUP,
|
|
10
12
|
notifyWatchers,
|
|
11
13
|
subscribeActiveWatcher,
|
|
12
14
|
trackSignalReads,
|
|
15
|
+
UNSET,
|
|
13
16
|
type Watcher,
|
|
14
17
|
} from '../src/system'
|
|
15
|
-
import {
|
|
16
|
-
isAbortError,
|
|
17
|
-
isAsyncFunction,
|
|
18
|
-
isObjectOfType,
|
|
19
|
-
toError,
|
|
20
|
-
UNSET,
|
|
21
|
-
} from '../src/util'
|
|
18
|
+
import { isAbortError, isAsyncFunction, isObjectOfType } from '../src/util'
|
|
22
19
|
|
|
23
20
|
/* === Types === */
|
|
24
21
|
|
|
@@ -78,7 +75,7 @@ const createTask = <T extends {}>(
|
|
|
78
75
|
error = undefined
|
|
79
76
|
}
|
|
80
77
|
const err = (e: unknown): undefined => {
|
|
81
|
-
const newError =
|
|
78
|
+
const newError = createError(e)
|
|
82
79
|
changed =
|
|
83
80
|
!error ||
|
|
84
81
|
newError.name !== error.name ||
|
|
@@ -102,7 +99,7 @@ const createTask = <T extends {}>(
|
|
|
102
99
|
if (watchers.size) notifyWatchers(watchers)
|
|
103
100
|
else watcher.stop()
|
|
104
101
|
})
|
|
105
|
-
watcher.
|
|
102
|
+
watcher.on(HOOK_CLEANUP, () => {
|
|
106
103
|
controller?.abort()
|
|
107
104
|
})
|
|
108
105
|
|