@zeix/cause-effect 0.17.3 → 0.18.0
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 +163 -232
- package/.cursorrules +41 -35
- package/.github/copilot-instructions.md +166 -116
- package/ARCHITECTURE.md +274 -0
- package/CLAUDE.md +199 -143
- package/COLLECTION_REFACTORING.md +161 -0
- package/GUIDE.md +298 -0
- package/README.md +232 -197
- package/REQUIREMENTS.md +100 -0
- package/bench/reactivity.bench.ts +577 -0
- package/index.dev.js +1325 -997
- package/index.js +1 -1
- package/index.ts +58 -74
- package/package.json +4 -1
- package/src/errors.ts +118 -74
- package/src/graph.ts +601 -0
- package/src/nodes/collection.ts +474 -0
- package/src/nodes/effect.ts +149 -0
- package/src/nodes/list.ts +588 -0
- package/src/nodes/memo.ts +120 -0
- package/src/nodes/sensor.ts +139 -0
- package/src/nodes/state.ts +135 -0
- package/src/nodes/store.ts +383 -0
- package/src/nodes/task.ts +146 -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 +466 -706
- package/test/effect.test.ts +293 -696
- package/test/list.test.ts +335 -592
- package/test/memo.test.ts +380 -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 +395 -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 +208 -0
- package/types/src/nodes/collection.d.ts +64 -0
- package/types/src/nodes/effect.d.ts +48 -0
- package/types/src/nodes/list.d.ts +65 -0
- package/types/src/nodes/memo.d.ts +57 -0
- package/types/src/nodes/sensor.d.ts +75 -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 +73 -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/src/system.ts
DELETED
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
import { assert, type Guard } from './errors'
|
|
2
|
-
import type { UnknownSignal } from './signal'
|
|
3
|
-
|
|
4
|
-
/* === Types === */
|
|
5
|
-
|
|
6
|
-
type Cleanup = () => void
|
|
7
|
-
|
|
8
|
-
// biome-ignore lint/suspicious/noConfusingVoidType: optional Cleanup return type
|
|
9
|
-
type MaybeCleanup = Cleanup | undefined | void
|
|
10
|
-
|
|
11
|
-
type Watcher = {
|
|
12
|
-
(): void
|
|
13
|
-
run(): void
|
|
14
|
-
onCleanup(cleanup: Cleanup): void
|
|
15
|
-
stop(): void
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
type SignalOptions<T extends unknown & {}> = {
|
|
19
|
-
guard?: Guard<T>
|
|
20
|
-
watched?: () => void
|
|
21
|
-
unwatched?: () => void
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/* === Internal === */
|
|
25
|
-
|
|
26
|
-
// Currently active watcher
|
|
27
|
-
let activeWatcher: Watcher | undefined
|
|
28
|
-
|
|
29
|
-
const watchersMap = new WeakMap<UnknownSignal, Set<Watcher>>()
|
|
30
|
-
const watchedCallbackMap = new WeakMap<object, () => void>()
|
|
31
|
-
const unwatchedCallbackMap = new WeakMap<object, () => void>()
|
|
32
|
-
|
|
33
|
-
// Queue of pending watcher reactions for batched change notifications
|
|
34
|
-
const pendingReactions = new Set<() => void>()
|
|
35
|
-
let batchDepth = 0
|
|
36
|
-
|
|
37
|
-
/* === Constants === */
|
|
38
|
-
|
|
39
|
-
// biome-ignore lint/suspicious/noExplicitAny: Deliberately using any to be used as a placeholder value in any signal
|
|
40
|
-
const UNSET: any = Symbol()
|
|
41
|
-
|
|
42
|
-
/* === Functions === */
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Create a watcher to observe changes in signals.
|
|
46
|
-
*
|
|
47
|
-
* A watcher combines push and pull reaction functions with onCleanup and stop methods
|
|
48
|
-
*
|
|
49
|
-
* @since 0.17.3
|
|
50
|
-
* @param {() => void} push - Function to be called when the state changes (push)
|
|
51
|
-
* @param {() => void} pull - Function to be called on demand from consumers (pull)
|
|
52
|
-
* @returns {Watcher} - Watcher object with off and cleanup methods
|
|
53
|
-
*/
|
|
54
|
-
const createWatcher = (push: () => void, pull: () => void): Watcher => {
|
|
55
|
-
const cleanups = new Set<Cleanup>()
|
|
56
|
-
const watcher = push as Partial<Watcher>
|
|
57
|
-
watcher.run = () => {
|
|
58
|
-
const prev = activeWatcher
|
|
59
|
-
activeWatcher = watcher as Watcher
|
|
60
|
-
try {
|
|
61
|
-
pull()
|
|
62
|
-
} finally {
|
|
63
|
-
activeWatcher = prev
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
watcher.onCleanup = (cleanup: Cleanup) => {
|
|
67
|
-
cleanups.add(cleanup)
|
|
68
|
-
}
|
|
69
|
-
watcher.stop = () => {
|
|
70
|
-
try {
|
|
71
|
-
for (const cleanup of cleanups) cleanup()
|
|
72
|
-
} finally {
|
|
73
|
-
cleanups.clear()
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return watcher as Watcher
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Run a function with signal reads in a non-tracking context.
|
|
81
|
-
*
|
|
82
|
-
* @param {() => void} callback - Callback
|
|
83
|
-
*/
|
|
84
|
-
const untrack = (callback: () => void): void => {
|
|
85
|
-
const prev = activeWatcher
|
|
86
|
-
activeWatcher = undefined
|
|
87
|
-
try {
|
|
88
|
-
callback()
|
|
89
|
-
} finally {
|
|
90
|
-
activeWatcher = prev
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const registerWatchCallbacks = (
|
|
95
|
-
signal: UnknownSignal,
|
|
96
|
-
watched: () => void,
|
|
97
|
-
unwatched?: () => void,
|
|
98
|
-
) => {
|
|
99
|
-
watchedCallbackMap.set(signal, watched)
|
|
100
|
-
if (unwatched) unwatchedCallbackMap.set(signal, unwatched)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Subscribe active watcher to a signal.
|
|
105
|
-
*
|
|
106
|
-
* @param {UnknownSignal} signal - Signal to subscribe to
|
|
107
|
-
* @returns {boolean} - true if the active watcher was subscribed,
|
|
108
|
-
* false if the watcher was already subscribed or there was no active watcher
|
|
109
|
-
*/
|
|
110
|
-
const subscribeTo = (signal: UnknownSignal): boolean => {
|
|
111
|
-
if (!activeWatcher || watchersMap.get(signal)?.has(activeWatcher))
|
|
112
|
-
return false
|
|
113
|
-
|
|
114
|
-
const watcher = activeWatcher
|
|
115
|
-
if (!watchersMap.has(signal)) watchersMap.set(signal, new Set<Watcher>())
|
|
116
|
-
|
|
117
|
-
const watchers = watchersMap.get(signal)
|
|
118
|
-
assert(watchers)
|
|
119
|
-
if (!watchers.size) {
|
|
120
|
-
const watchedCallback = watchedCallbackMap.get(signal)
|
|
121
|
-
if (watchedCallback) untrack(watchedCallback)
|
|
122
|
-
}
|
|
123
|
-
watchers.add(watcher)
|
|
124
|
-
watcher.onCleanup(() => {
|
|
125
|
-
watchers.delete(watcher)
|
|
126
|
-
if (!watchers.size) {
|
|
127
|
-
const unwatchedCallback = unwatchedCallbackMap.get(signal)
|
|
128
|
-
if (unwatchedCallback) untrack(unwatchedCallback)
|
|
129
|
-
}
|
|
130
|
-
})
|
|
131
|
-
return true
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const subscribeActiveWatcher = (watchers: Set<Watcher>) => {
|
|
135
|
-
if (!activeWatcher || watchers.has(activeWatcher)) return false
|
|
136
|
-
|
|
137
|
-
const watcher = activeWatcher
|
|
138
|
-
watchers.add(watcher)
|
|
139
|
-
if (!watchers.size) {
|
|
140
|
-
const watchedCallback = watchedCallbackMap.get(watchers)
|
|
141
|
-
if (watchedCallback) untrack(watchedCallback)
|
|
142
|
-
}
|
|
143
|
-
watcher.onCleanup(() => {
|
|
144
|
-
watchers.delete(watcher)
|
|
145
|
-
if (!watchers.size) {
|
|
146
|
-
const unwatchedCallback = unwatchedCallbackMap.get(watchers)
|
|
147
|
-
if (unwatchedCallback) untrack(unwatchedCallback)
|
|
148
|
-
}
|
|
149
|
-
})
|
|
150
|
-
return true
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Unsubscribe all watchers from a signal so it can be garbage collected.
|
|
155
|
-
*
|
|
156
|
-
* @param {UnknownSignal} signal - Signal to unsubscribe from
|
|
157
|
-
* @returns {void}
|
|
158
|
-
*/
|
|
159
|
-
const unsubscribeAllFrom = (signal: UnknownSignal): void => {
|
|
160
|
-
const watchers = watchersMap.get(signal)
|
|
161
|
-
if (!watchers) return
|
|
162
|
-
|
|
163
|
-
for (const watcher of watchers) watcher.stop()
|
|
164
|
-
watchers.clear()
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Notify watchers of a signal change.
|
|
169
|
-
*
|
|
170
|
-
* @param {UnknownSignal} signal - Signal to notify watchers of
|
|
171
|
-
* @returns {boolean} - Whether any watchers were notified
|
|
172
|
-
*/
|
|
173
|
-
const notifyOf = (signal: UnknownSignal): boolean => {
|
|
174
|
-
const watchers = watchersMap.get(signal)
|
|
175
|
-
if (!watchers?.size) return false
|
|
176
|
-
|
|
177
|
-
for (const react of watchers) {
|
|
178
|
-
if (batchDepth) pendingReactions.add(react)
|
|
179
|
-
else react()
|
|
180
|
-
}
|
|
181
|
-
return true
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const notifyWatchers = (watchers: Set<Watcher>): boolean => {
|
|
185
|
-
if (!watchers.size) return false
|
|
186
|
-
|
|
187
|
-
for (const react of watchers) {
|
|
188
|
-
if (batchDepth) pendingReactions.add(react)
|
|
189
|
-
else react()
|
|
190
|
-
}
|
|
191
|
-
return true
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Flush all pending reactions of enqueued watchers.
|
|
196
|
-
*/
|
|
197
|
-
const flush = () => {
|
|
198
|
-
while (pendingReactions.size) {
|
|
199
|
-
const watchers = Array.from(pendingReactions)
|
|
200
|
-
pendingReactions.clear()
|
|
201
|
-
for (const react of watchers) react()
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Batch multiple signal writes.
|
|
207
|
-
*
|
|
208
|
-
* @param {() => void} callback - Function with multiple signal writes to be batched
|
|
209
|
-
*/
|
|
210
|
-
const batch = (callback: () => void) => {
|
|
211
|
-
batchDepth++
|
|
212
|
-
try {
|
|
213
|
-
callback()
|
|
214
|
-
} finally {
|
|
215
|
-
flush()
|
|
216
|
-
batchDepth--
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Run a function with signal reads in a tracking context (or temporarily untrack).
|
|
222
|
-
*
|
|
223
|
-
* @param {Watcher | false} watcher - Watcher to be called when the signal changes
|
|
224
|
-
* or false for temporary untracking while inserting auto-hydrating DOM nodes
|
|
225
|
-
* that might read signals (e.g., Web Components)
|
|
226
|
-
* @param {() => void} run - Function to run the computation or effect
|
|
227
|
-
*/
|
|
228
|
-
const track = (watcher: Watcher | false, run: () => void): void => {
|
|
229
|
-
const prev = activeWatcher
|
|
230
|
-
activeWatcher = watcher || undefined
|
|
231
|
-
try {
|
|
232
|
-
run()
|
|
233
|
-
} finally {
|
|
234
|
-
activeWatcher = prev
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/* === Exports === */
|
|
239
|
-
|
|
240
|
-
export {
|
|
241
|
-
type Cleanup,
|
|
242
|
-
type MaybeCleanup,
|
|
243
|
-
type Watcher,
|
|
244
|
-
type SignalOptions,
|
|
245
|
-
UNSET,
|
|
246
|
-
createWatcher,
|
|
247
|
-
registerWatchCallbacks,
|
|
248
|
-
subscribeTo,
|
|
249
|
-
subscribeActiveWatcher,
|
|
250
|
-
unsubscribeAllFrom,
|
|
251
|
-
notifyOf,
|
|
252
|
-
notifyWatchers,
|
|
253
|
-
flush,
|
|
254
|
-
batch,
|
|
255
|
-
track,
|
|
256
|
-
untrack,
|
|
257
|
-
}
|