@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/index.dev.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// src/util.ts
|
|
2
|
-
var UNSET = Symbol();
|
|
3
2
|
var isString = (value) => typeof value === "string";
|
|
4
3
|
var isNumber = (value) => typeof value === "number";
|
|
5
4
|
var isSymbol = (value) => typeof value === "symbol";
|
|
@@ -12,9 +11,145 @@ var isRecord = (value) => isObjectOfType(value, "Object");
|
|
|
12
11
|
var isRecordOrArray = (value) => isRecord(value) || Array.isArray(value);
|
|
13
12
|
var isUniformArray = (value, guard = (item) => item != null) => Array.isArray(value) && value.every(guard);
|
|
14
13
|
var isAbortError = (error) => error instanceof DOMException && error.name === "AbortError";
|
|
15
|
-
var toError = (reason) => reason instanceof Error ? reason : Error(String(reason));
|
|
16
14
|
var valueString = (value) => isString(value) ? `"${value}"` : !!value && typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
17
15
|
|
|
16
|
+
// src/system.ts
|
|
17
|
+
var activeWatcher;
|
|
18
|
+
var unwatchMap = new WeakMap;
|
|
19
|
+
var pendingReactions = new Set;
|
|
20
|
+
var batchDepth = 0;
|
|
21
|
+
var UNSET = Symbol();
|
|
22
|
+
var HOOK_ADD = "add";
|
|
23
|
+
var HOOK_CHANGE = "change";
|
|
24
|
+
var HOOK_CLEANUP = "cleanup";
|
|
25
|
+
var HOOK_REMOVE = "remove";
|
|
26
|
+
var HOOK_SORT = "sort";
|
|
27
|
+
var HOOK_WATCH = "watch";
|
|
28
|
+
var createWatcher = (react) => {
|
|
29
|
+
const cleanups = new Set;
|
|
30
|
+
const watcher = react;
|
|
31
|
+
watcher.on = (type, cleanup) => {
|
|
32
|
+
if (type === HOOK_CLEANUP)
|
|
33
|
+
cleanups.add(cleanup);
|
|
34
|
+
else
|
|
35
|
+
throw new InvalidHookError("watcher", type);
|
|
36
|
+
};
|
|
37
|
+
watcher.stop = () => {
|
|
38
|
+
try {
|
|
39
|
+
for (const cleanup of cleanups)
|
|
40
|
+
cleanup();
|
|
41
|
+
} finally {
|
|
42
|
+
cleanups.clear();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
return watcher;
|
|
46
|
+
};
|
|
47
|
+
var subscribeActiveWatcher = (watchers, watchHookCallbacks) => {
|
|
48
|
+
if (!watchers.size && watchHookCallbacks?.size) {
|
|
49
|
+
const unwatch = triggerHook(watchHookCallbacks);
|
|
50
|
+
if (unwatch) {
|
|
51
|
+
const unwatchCallbacks = unwatchMap.get(watchers) ?? new Set;
|
|
52
|
+
unwatchCallbacks.add(unwatch);
|
|
53
|
+
if (!unwatchMap.has(watchers))
|
|
54
|
+
unwatchMap.set(watchers, unwatchCallbacks);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (activeWatcher && !watchers.has(activeWatcher)) {
|
|
58
|
+
const watcher = activeWatcher;
|
|
59
|
+
watcher.on(HOOK_CLEANUP, () => {
|
|
60
|
+
watchers.delete(watcher);
|
|
61
|
+
if (!watchers.size) {
|
|
62
|
+
const unwatchCallbacks = unwatchMap.get(watchers);
|
|
63
|
+
if (unwatchCallbacks) {
|
|
64
|
+
try {
|
|
65
|
+
for (const unwatch of unwatchCallbacks)
|
|
66
|
+
unwatch();
|
|
67
|
+
} finally {
|
|
68
|
+
unwatchCallbacks.clear();
|
|
69
|
+
unwatchMap.delete(watchers);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
watchers.add(watcher);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
var notifyWatchers = (watchers) => {
|
|
78
|
+
if (!watchers.size)
|
|
79
|
+
return false;
|
|
80
|
+
for (const react of watchers) {
|
|
81
|
+
if (batchDepth)
|
|
82
|
+
pendingReactions.add(react);
|
|
83
|
+
else
|
|
84
|
+
react();
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
};
|
|
88
|
+
var flushPendingReactions = () => {
|
|
89
|
+
while (pendingReactions.size) {
|
|
90
|
+
const watchers = Array.from(pendingReactions);
|
|
91
|
+
pendingReactions.clear();
|
|
92
|
+
for (const watcher of watchers)
|
|
93
|
+
watcher();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
var batchSignalWrites = (callback) => {
|
|
97
|
+
batchDepth++;
|
|
98
|
+
try {
|
|
99
|
+
callback();
|
|
100
|
+
} finally {
|
|
101
|
+
flushPendingReactions();
|
|
102
|
+
batchDepth--;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
var trackSignalReads = (watcher, run) => {
|
|
106
|
+
const prev = activeWatcher;
|
|
107
|
+
activeWatcher = watcher || undefined;
|
|
108
|
+
try {
|
|
109
|
+
run();
|
|
110
|
+
} finally {
|
|
111
|
+
activeWatcher = prev;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
var triggerHook = (callbacks, payload) => {
|
|
115
|
+
if (!callbacks)
|
|
116
|
+
return;
|
|
117
|
+
const cleanups = [];
|
|
118
|
+
const errors = [];
|
|
119
|
+
const throwError = (inCleanup) => {
|
|
120
|
+
if (errors.length) {
|
|
121
|
+
if (errors.length === 1)
|
|
122
|
+
throw errors[0];
|
|
123
|
+
throw new AggregateError(errors, `Errors in hook ${inCleanup ? "cleanup" : "callback"}:`);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
for (const callback of callbacks) {
|
|
127
|
+
try {
|
|
128
|
+
const cleanup = callback(payload);
|
|
129
|
+
if (isFunction(cleanup))
|
|
130
|
+
cleanups.push(cleanup);
|
|
131
|
+
} catch (error) {
|
|
132
|
+
errors.push(createError(error));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
throwError();
|
|
136
|
+
if (!cleanups.length)
|
|
137
|
+
return;
|
|
138
|
+
if (cleanups.length === 1)
|
|
139
|
+
return cleanups[0];
|
|
140
|
+
return () => {
|
|
141
|
+
for (const cleanup of cleanups) {
|
|
142
|
+
try {
|
|
143
|
+
cleanup();
|
|
144
|
+
} catch (error) {
|
|
145
|
+
errors.push(createError(error));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
throwError(true);
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
var isHandledHook = (type, handled) => handled.includes(type);
|
|
152
|
+
|
|
18
153
|
// src/diff.ts
|
|
19
154
|
var isEqual = (a, b, visited) => {
|
|
20
155
|
if (Object.is(a, b))
|
|
@@ -102,73 +237,6 @@ var diff = (oldObj, newObj) => {
|
|
|
102
237
|
};
|
|
103
238
|
};
|
|
104
239
|
|
|
105
|
-
// src/system.ts
|
|
106
|
-
var activeWatcher;
|
|
107
|
-
var pendingReactions = new Set;
|
|
108
|
-
var batchDepth = 0;
|
|
109
|
-
var createWatcher = (react) => {
|
|
110
|
-
const cleanups = new Set;
|
|
111
|
-
const watcher = react;
|
|
112
|
-
watcher.onCleanup = (cleanup) => {
|
|
113
|
-
cleanups.add(cleanup);
|
|
114
|
-
};
|
|
115
|
-
watcher.stop = () => {
|
|
116
|
-
for (const cleanup of cleanups)
|
|
117
|
-
cleanup();
|
|
118
|
-
cleanups.clear();
|
|
119
|
-
};
|
|
120
|
-
return watcher;
|
|
121
|
-
};
|
|
122
|
-
var subscribeActiveWatcher = (watchers) => {
|
|
123
|
-
if (activeWatcher && !watchers.has(activeWatcher)) {
|
|
124
|
-
const watcher = activeWatcher;
|
|
125
|
-
watcher.onCleanup(() => watchers.delete(watcher));
|
|
126
|
-
watchers.add(watcher);
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
var notifyWatchers = (watchers) => {
|
|
130
|
-
for (const react of watchers) {
|
|
131
|
-
if (batchDepth)
|
|
132
|
-
pendingReactions.add(react);
|
|
133
|
-
else
|
|
134
|
-
react();
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
var flushPendingReactions = () => {
|
|
138
|
-
while (pendingReactions.size) {
|
|
139
|
-
const watchers = Array.from(pendingReactions);
|
|
140
|
-
pendingReactions.clear();
|
|
141
|
-
for (const watcher of watchers)
|
|
142
|
-
watcher();
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
var batchSignalWrites = (callback) => {
|
|
146
|
-
batchDepth++;
|
|
147
|
-
try {
|
|
148
|
-
callback();
|
|
149
|
-
} finally {
|
|
150
|
-
flushPendingReactions();
|
|
151
|
-
batchDepth--;
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
var trackSignalReads = (watcher, run) => {
|
|
155
|
-
const prev = activeWatcher;
|
|
156
|
-
activeWatcher = watcher || undefined;
|
|
157
|
-
try {
|
|
158
|
-
run();
|
|
159
|
-
} finally {
|
|
160
|
-
activeWatcher = prev;
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
var emitNotification = (listeners, payload) => {
|
|
164
|
-
for (const listener of listeners) {
|
|
165
|
-
if (batchDepth)
|
|
166
|
-
pendingReactions.add(() => listener(payload));
|
|
167
|
-
else
|
|
168
|
-
listener(payload);
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
|
|
172
240
|
// src/classes/computed.ts
|
|
173
241
|
var TYPE_COMPUTED = "Computed";
|
|
174
242
|
|
|
@@ -180,27 +248,35 @@ class Memo {
|
|
|
180
248
|
#dirty = true;
|
|
181
249
|
#computing = false;
|
|
182
250
|
#watcher;
|
|
251
|
+
#watchHookCallbacks;
|
|
183
252
|
constructor(callback, initialValue = UNSET) {
|
|
184
|
-
validateCallback(
|
|
185
|
-
validateSignalValue(
|
|
253
|
+
validateCallback(this.constructor.name, callback, isMemoCallback);
|
|
254
|
+
validateSignalValue(this.constructor.name, initialValue);
|
|
186
255
|
this.#callback = callback;
|
|
187
256
|
this.#value = initialValue;
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
this.#
|
|
194
|
-
|
|
257
|
+
}
|
|
258
|
+
#getWatcher() {
|
|
259
|
+
if (!this.#watcher) {
|
|
260
|
+
this.#watcher = createWatcher(() => {
|
|
261
|
+
this.#dirty = true;
|
|
262
|
+
if (!notifyWatchers(this.#watchers))
|
|
263
|
+
this.#watcher?.stop();
|
|
264
|
+
});
|
|
265
|
+
this.#watcher.on(HOOK_CLEANUP, () => {
|
|
266
|
+
this.#watcher = undefined;
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
return this.#watcher;
|
|
195
270
|
}
|
|
196
271
|
get [Symbol.toStringTag]() {
|
|
197
272
|
return TYPE_COMPUTED;
|
|
198
273
|
}
|
|
199
274
|
get() {
|
|
200
|
-
subscribeActiveWatcher(this.#watchers);
|
|
275
|
+
subscribeActiveWatcher(this.#watchers, this.#watchHookCallbacks);
|
|
201
276
|
flushPendingReactions();
|
|
202
277
|
if (this.#dirty) {
|
|
203
|
-
|
|
278
|
+
const watcher = this.#getWatcher();
|
|
279
|
+
trackSignalReads(watcher, () => {
|
|
204
280
|
if (this.#computing)
|
|
205
281
|
throw new CircularDependencyError("memo");
|
|
206
282
|
let result;
|
|
@@ -209,7 +285,7 @@ class Memo {
|
|
|
209
285
|
result = this.#callback(this.#value);
|
|
210
286
|
} catch (e) {
|
|
211
287
|
this.#value = UNSET;
|
|
212
|
-
this.#error =
|
|
288
|
+
this.#error = createError(e);
|
|
213
289
|
this.#computing = false;
|
|
214
290
|
return;
|
|
215
291
|
}
|
|
@@ -228,6 +304,16 @@ class Memo {
|
|
|
228
304
|
throw this.#error;
|
|
229
305
|
return this.#value;
|
|
230
306
|
}
|
|
307
|
+
on(type, callback) {
|
|
308
|
+
if (type === HOOK_WATCH) {
|
|
309
|
+
this.#watchHookCallbacks ||= new Set;
|
|
310
|
+
this.#watchHookCallbacks.add(callback);
|
|
311
|
+
return () => {
|
|
312
|
+
this.#watchHookCallbacks?.delete(callback);
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
throw new InvalidHookError(this.constructor.name, type);
|
|
316
|
+
}
|
|
231
317
|
}
|
|
232
318
|
|
|
233
319
|
class Task {
|
|
@@ -240,28 +326,34 @@ class Task {
|
|
|
240
326
|
#changed = false;
|
|
241
327
|
#watcher;
|
|
242
328
|
#controller;
|
|
329
|
+
#watchHookCallbacks;
|
|
243
330
|
constructor(callback, initialValue = UNSET) {
|
|
244
|
-
validateCallback(
|
|
245
|
-
validateSignalValue(
|
|
331
|
+
validateCallback(this.constructor.name, callback, isTaskCallback);
|
|
332
|
+
validateSignalValue(this.constructor.name, initialValue);
|
|
246
333
|
this.#callback = callback;
|
|
247
334
|
this.#value = initialValue;
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
this.#
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
this.#
|
|
258
|
-
|
|
335
|
+
}
|
|
336
|
+
#getWatcher() {
|
|
337
|
+
if (!this.#watcher) {
|
|
338
|
+
this.#watcher = createWatcher(() => {
|
|
339
|
+
this.#dirty = true;
|
|
340
|
+
this.#controller?.abort();
|
|
341
|
+
if (!notifyWatchers(this.#watchers))
|
|
342
|
+
this.#watcher?.stop();
|
|
343
|
+
});
|
|
344
|
+
this.#watcher.on(HOOK_CLEANUP, () => {
|
|
345
|
+
this.#controller?.abort();
|
|
346
|
+
this.#controller = undefined;
|
|
347
|
+
this.#watcher = undefined;
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
return this.#watcher;
|
|
259
351
|
}
|
|
260
352
|
get [Symbol.toStringTag]() {
|
|
261
353
|
return TYPE_COMPUTED;
|
|
262
354
|
}
|
|
263
355
|
get() {
|
|
264
|
-
subscribeActiveWatcher(this.#watchers);
|
|
356
|
+
subscribeActiveWatcher(this.#watchers, this.#watchHookCallbacks);
|
|
265
357
|
flushPendingReactions();
|
|
266
358
|
const ok = (v) => {
|
|
267
359
|
if (!isEqual(v, this.#value)) {
|
|
@@ -277,7 +369,7 @@ class Task {
|
|
|
277
369
|
this.#error = undefined;
|
|
278
370
|
};
|
|
279
371
|
const err = (e) => {
|
|
280
|
-
const newError =
|
|
372
|
+
const newError = createError(e);
|
|
281
373
|
this.#changed = !this.#error || newError.name !== this.#error.name || newError.message !== this.#error.message;
|
|
282
374
|
this.#value = UNSET;
|
|
283
375
|
this.#error = newError;
|
|
@@ -286,10 +378,10 @@ class Task {
|
|
|
286
378
|
this.#computing = false;
|
|
287
379
|
this.#controller = undefined;
|
|
288
380
|
fn(arg);
|
|
289
|
-
if (this.#changed)
|
|
290
|
-
|
|
381
|
+
if (this.#changed && !notifyWatchers(this.#watchers))
|
|
382
|
+
this.#watcher?.stop();
|
|
291
383
|
};
|
|
292
|
-
const compute = () => trackSignalReads(this.#
|
|
384
|
+
const compute = () => trackSignalReads(this.#getWatcher(), () => {
|
|
293
385
|
if (this.#computing)
|
|
294
386
|
throw new CircularDependencyError("task");
|
|
295
387
|
this.#changed = false;
|
|
@@ -329,6 +421,16 @@ class Task {
|
|
|
329
421
|
throw this.#error;
|
|
330
422
|
return this.#value;
|
|
331
423
|
}
|
|
424
|
+
on(type, callback) {
|
|
425
|
+
if (type === HOOK_WATCH) {
|
|
426
|
+
this.#watchHookCallbacks ||= new Set;
|
|
427
|
+
this.#watchHookCallbacks.add(callback);
|
|
428
|
+
return () => {
|
|
429
|
+
this.#watchHookCallbacks?.delete(callback);
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
throw new InvalidHookError(this.constructor.name, type);
|
|
433
|
+
}
|
|
332
434
|
}
|
|
333
435
|
var createComputed = (callback, initialValue = UNSET) => isAsyncFunction(callback) ? new Task(callback, initialValue) : new Memo(callback, initialValue);
|
|
334
436
|
var isComputed = (value) => isObjectOfType(value, TYPE_COMPUTED);
|
|
@@ -341,11 +443,7 @@ class Composite {
|
|
|
341
443
|
#validate;
|
|
342
444
|
#create;
|
|
343
445
|
#watchers = new Map;
|
|
344
|
-
#
|
|
345
|
-
add: new Set,
|
|
346
|
-
change: new Set,
|
|
347
|
-
remove: new Set
|
|
348
|
-
};
|
|
446
|
+
#hookCallbacks = {};
|
|
349
447
|
#batching = false;
|
|
350
448
|
constructor(values, validate, create) {
|
|
351
449
|
this.#validate = validate;
|
|
@@ -362,7 +460,7 @@ class Composite {
|
|
|
362
460
|
trackSignalReads(watcher, () => {
|
|
363
461
|
this.signals.get(key)?.get();
|
|
364
462
|
if (!this.#batching)
|
|
365
|
-
|
|
463
|
+
triggerHook(this.#hookCallbacks.change, [key]);
|
|
366
464
|
});
|
|
367
465
|
});
|
|
368
466
|
this.#watchers.set(key, watcher);
|
|
@@ -372,10 +470,10 @@ class Composite {
|
|
|
372
470
|
if (!this.#validate(key, value))
|
|
373
471
|
return false;
|
|
374
472
|
this.signals.set(key, this.#create(value));
|
|
375
|
-
if (this.#
|
|
473
|
+
if (this.#hookCallbacks.change?.size)
|
|
376
474
|
this.#addWatcher(key);
|
|
377
475
|
if (!this.#batching)
|
|
378
|
-
|
|
476
|
+
triggerHook(this.#hookCallbacks.add, [key]);
|
|
379
477
|
return true;
|
|
380
478
|
}
|
|
381
479
|
remove(key) {
|
|
@@ -388,7 +486,7 @@ class Composite {
|
|
|
388
486
|
this.#watchers.delete(key);
|
|
389
487
|
}
|
|
390
488
|
if (!this.#batching)
|
|
391
|
-
|
|
489
|
+
triggerHook(this.#hookCallbacks.remove, [key]);
|
|
392
490
|
return true;
|
|
393
491
|
}
|
|
394
492
|
change(changes, initialRun) {
|
|
@@ -396,7 +494,7 @@ class Composite {
|
|
|
396
494
|
if (Object.keys(changes.add).length) {
|
|
397
495
|
for (const key in changes.add)
|
|
398
496
|
this.add(key, changes.add[key]);
|
|
399
|
-
const notify = () =>
|
|
497
|
+
const notify = () => triggerHook(this.#hookCallbacks.add, Object.keys(changes.add));
|
|
400
498
|
if (initialRun)
|
|
401
499
|
setTimeout(notify, 0);
|
|
402
500
|
else
|
|
@@ -413,12 +511,12 @@ class Composite {
|
|
|
413
511
|
signal.set(value);
|
|
414
512
|
}
|
|
415
513
|
});
|
|
416
|
-
|
|
514
|
+
triggerHook(this.#hookCallbacks.change, Object.keys(changes.change));
|
|
417
515
|
}
|
|
418
516
|
if (Object.keys(changes.remove).length) {
|
|
419
517
|
for (const key in changes.remove)
|
|
420
518
|
this.remove(key);
|
|
421
|
-
|
|
519
|
+
triggerHook(this.#hookCallbacks.remove, Object.keys(changes.remove));
|
|
422
520
|
}
|
|
423
521
|
this.#batching = false;
|
|
424
522
|
return changes.changed;
|
|
@@ -427,20 +525,23 @@ class Composite {
|
|
|
427
525
|
const keys = Array.from(this.signals.keys());
|
|
428
526
|
this.signals.clear();
|
|
429
527
|
this.#watchers.clear();
|
|
430
|
-
|
|
528
|
+
triggerHook(this.#hookCallbacks.remove, keys);
|
|
431
529
|
return true;
|
|
432
530
|
}
|
|
433
|
-
on(type,
|
|
434
|
-
|
|
435
|
-
|
|
531
|
+
on(type, callback) {
|
|
532
|
+
if (!isHandledHook(type, [HOOK_ADD, HOOK_CHANGE, HOOK_REMOVE]))
|
|
533
|
+
throw new InvalidHookError("Composite", type);
|
|
534
|
+
this.#hookCallbacks[type] ||= new Set;
|
|
535
|
+
this.#hookCallbacks[type].add(callback);
|
|
536
|
+
if (type === HOOK_CHANGE && !this.#watchers.size) {
|
|
436
537
|
this.#batching = true;
|
|
437
538
|
for (const key of this.signals.keys())
|
|
438
539
|
this.#addWatcher(key);
|
|
439
540
|
this.#batching = false;
|
|
440
541
|
}
|
|
441
542
|
return () => {
|
|
442
|
-
this.#
|
|
443
|
-
if (type ===
|
|
543
|
+
this.#hookCallbacks[type]?.delete(callback);
|
|
544
|
+
if (type === HOOK_CHANGE && !this.#hookCallbacks.change?.size) {
|
|
444
545
|
if (this.#watchers.size) {
|
|
445
546
|
for (const watcher of this.#watchers.values())
|
|
446
547
|
watcher.stop();
|
|
@@ -457,30 +558,42 @@ var TYPE_STATE = "State";
|
|
|
457
558
|
class State {
|
|
458
559
|
#watchers = new Set;
|
|
459
560
|
#value;
|
|
561
|
+
#watchHookCallbacks;
|
|
460
562
|
constructor(initialValue) {
|
|
461
|
-
validateSignalValue(
|
|
563
|
+
validateSignalValue(TYPE_STATE, initialValue);
|
|
462
564
|
this.#value = initialValue;
|
|
463
565
|
}
|
|
464
566
|
get [Symbol.toStringTag]() {
|
|
465
567
|
return TYPE_STATE;
|
|
466
568
|
}
|
|
467
569
|
get() {
|
|
468
|
-
subscribeActiveWatcher(this.#watchers);
|
|
570
|
+
subscribeActiveWatcher(this.#watchers, this.#watchHookCallbacks);
|
|
469
571
|
return this.#value;
|
|
470
572
|
}
|
|
471
573
|
set(newValue) {
|
|
472
|
-
validateSignalValue(
|
|
574
|
+
validateSignalValue(TYPE_STATE, newValue);
|
|
473
575
|
if (isEqual(this.#value, newValue))
|
|
474
576
|
return;
|
|
475
577
|
this.#value = newValue;
|
|
476
|
-
|
|
578
|
+
if (this.#watchers.size)
|
|
579
|
+
notifyWatchers(this.#watchers);
|
|
477
580
|
if (UNSET === this.#value)
|
|
478
581
|
this.#watchers.clear();
|
|
479
582
|
}
|
|
480
583
|
update(updater) {
|
|
481
|
-
validateCallback(
|
|
584
|
+
validateCallback(`${TYPE_STATE} update`, updater);
|
|
482
585
|
this.set(updater(this.#value));
|
|
483
586
|
}
|
|
587
|
+
on(type, callback) {
|
|
588
|
+
if (type === HOOK_WATCH) {
|
|
589
|
+
this.#watchHookCallbacks ||= new Set;
|
|
590
|
+
this.#watchHookCallbacks.add(callback);
|
|
591
|
+
return () => {
|
|
592
|
+
this.#watchHookCallbacks?.delete(callback);
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
throw new InvalidHookError(this.constructor.name, type);
|
|
596
|
+
}
|
|
484
597
|
}
|
|
485
598
|
var isState = (value) => isObjectOfType(value, TYPE_STATE);
|
|
486
599
|
|
|
@@ -490,17 +603,15 @@ var TYPE_LIST = "List";
|
|
|
490
603
|
class List {
|
|
491
604
|
#composite;
|
|
492
605
|
#watchers = new Set;
|
|
493
|
-
#
|
|
494
|
-
sort: new Set
|
|
495
|
-
};
|
|
606
|
+
#hookCallbacks = {};
|
|
496
607
|
#order = [];
|
|
497
608
|
#generateKey;
|
|
498
609
|
constructor(initialValue, keyConfig) {
|
|
499
|
-
validateSignalValue(
|
|
610
|
+
validateSignalValue(TYPE_LIST, initialValue, Array.isArray);
|
|
500
611
|
let keyCounter = 0;
|
|
501
612
|
this.#generateKey = isString(keyConfig) ? () => `${keyConfig}${keyCounter++}` : isFunction(keyConfig) ? (item) => keyConfig(item) : () => String(keyCounter++);
|
|
502
613
|
this.#composite = new Composite(this.#toRecord(initialValue), (key, value) => {
|
|
503
|
-
validateSignalValue(
|
|
614
|
+
validateSignalValue(`${TYPE_LIST} for key "${key}"`, value);
|
|
504
615
|
return true;
|
|
505
616
|
}, (value) => new State(value));
|
|
506
617
|
}
|
|
@@ -536,11 +647,11 @@ class List {
|
|
|
536
647
|
}
|
|
537
648
|
}
|
|
538
649
|
get length() {
|
|
539
|
-
subscribeActiveWatcher(this.#watchers);
|
|
650
|
+
subscribeActiveWatcher(this.#watchers, this.#hookCallbacks[HOOK_WATCH]);
|
|
540
651
|
return this.#order.length;
|
|
541
652
|
}
|
|
542
653
|
get() {
|
|
543
|
-
subscribeActiveWatcher(this.#watchers);
|
|
654
|
+
subscribeActiveWatcher(this.#watchers, this.#hookCallbacks[HOOK_WATCH]);
|
|
544
655
|
return this.#value;
|
|
545
656
|
}
|
|
546
657
|
set(newValue) {
|
|
@@ -610,7 +721,7 @@ class List {
|
|
|
610
721
|
if (!isEqual(this.#order, newOrder)) {
|
|
611
722
|
this.#order = newOrder;
|
|
612
723
|
notifyWatchers(this.#watchers);
|
|
613
|
-
|
|
724
|
+
triggerHook(this.#hookCallbacks.sort, this.#order);
|
|
614
725
|
}
|
|
615
726
|
}
|
|
616
727
|
splice(start, deleteCount, ...items) {
|
|
@@ -648,15 +759,20 @@ class List {
|
|
|
648
759
|
}
|
|
649
760
|
return Object.values(remove);
|
|
650
761
|
}
|
|
651
|
-
on(type,
|
|
652
|
-
if (type
|
|
653
|
-
this.#
|
|
654
|
-
|
|
762
|
+
on(type, callback) {
|
|
763
|
+
if (isHandledHook(type, [HOOK_SORT, HOOK_WATCH])) {
|
|
764
|
+
this.#hookCallbacks[type] ||= new Set;
|
|
765
|
+
this.#hookCallbacks[type].add(callback);
|
|
766
|
+
return () => {
|
|
767
|
+
this.#hookCallbacks[type]?.delete(callback);
|
|
768
|
+
};
|
|
769
|
+
} else if (isHandledHook(type, [HOOK_ADD, HOOK_CHANGE, HOOK_REMOVE])) {
|
|
770
|
+
return this.#composite.on(type, callback);
|
|
655
771
|
}
|
|
656
|
-
|
|
772
|
+
throw new InvalidHookError(TYPE_LIST, type);
|
|
657
773
|
}
|
|
658
774
|
deriveCollection(callback) {
|
|
659
|
-
return new
|
|
775
|
+
return new DerivedCollection(this, callback);
|
|
660
776
|
}
|
|
661
777
|
}
|
|
662
778
|
var isList = (value) => isObjectOfType(value, TYPE_LIST);
|
|
@@ -667,10 +783,11 @@ var TYPE_STORE = "Store";
|
|
|
667
783
|
class BaseStore {
|
|
668
784
|
#composite;
|
|
669
785
|
#watchers = new Set;
|
|
786
|
+
#watchHookCallbacks;
|
|
670
787
|
constructor(initialValue) {
|
|
671
|
-
validateSignalValue(
|
|
788
|
+
validateSignalValue(TYPE_STORE, initialValue, isRecord);
|
|
672
789
|
this.#composite = new Composite(initialValue, (key, value) => {
|
|
673
|
-
validateSignalValue(
|
|
790
|
+
validateSignalValue(`${TYPE_STORE} for key "${key}"`, value);
|
|
674
791
|
return true;
|
|
675
792
|
}, (value) => createMutableSignal(value));
|
|
676
793
|
}
|
|
@@ -690,8 +807,14 @@ class BaseStore {
|
|
|
690
807
|
for (const [key, signal] of this.#composite.signals.entries())
|
|
691
808
|
yield [key, signal];
|
|
692
809
|
}
|
|
810
|
+
keys() {
|
|
811
|
+
return this.#composite.signals.keys();
|
|
812
|
+
}
|
|
813
|
+
byKey(key) {
|
|
814
|
+
return this.#composite.signals.get(key);
|
|
815
|
+
}
|
|
693
816
|
get() {
|
|
694
|
-
subscribeActiveWatcher(this.#watchers);
|
|
817
|
+
subscribeActiveWatcher(this.#watchers, this.#watchHookCallbacks);
|
|
695
818
|
return this.#value;
|
|
696
819
|
}
|
|
697
820
|
set(newValue) {
|
|
@@ -706,18 +829,12 @@ class BaseStore {
|
|
|
706
829
|
if (changed)
|
|
707
830
|
notifyWatchers(this.#watchers);
|
|
708
831
|
}
|
|
709
|
-
keys() {
|
|
710
|
-
return this.#composite.signals.keys();
|
|
711
|
-
}
|
|
712
|
-
byKey(key) {
|
|
713
|
-
return this.#composite.signals.get(key);
|
|
714
|
-
}
|
|
715
832
|
update(fn) {
|
|
716
833
|
this.set(fn(this.get()));
|
|
717
834
|
}
|
|
718
835
|
add(key, value) {
|
|
719
836
|
if (this.#composite.signals.has(key))
|
|
720
|
-
throw new DuplicateKeyError(
|
|
837
|
+
throw new DuplicateKeyError(TYPE_STORE, key, value);
|
|
721
838
|
const ok = this.#composite.add(key, value);
|
|
722
839
|
if (ok)
|
|
723
840
|
notifyWatchers(this.#watchers);
|
|
@@ -728,8 +845,17 @@ class BaseStore {
|
|
|
728
845
|
if (ok)
|
|
729
846
|
notifyWatchers(this.#watchers);
|
|
730
847
|
}
|
|
731
|
-
on(type,
|
|
732
|
-
|
|
848
|
+
on(type, callback) {
|
|
849
|
+
if (type === HOOK_WATCH) {
|
|
850
|
+
this.#watchHookCallbacks ||= new Set;
|
|
851
|
+
this.#watchHookCallbacks.add(callback);
|
|
852
|
+
return () => {
|
|
853
|
+
this.#watchHookCallbacks?.delete(callback);
|
|
854
|
+
};
|
|
855
|
+
} else if (isHandledHook(type, [HOOK_ADD, HOOK_CHANGE, HOOK_REMOVE])) {
|
|
856
|
+
return this.#composite.on(type, callback);
|
|
857
|
+
}
|
|
858
|
+
throw new InvalidHookError(TYPE_STORE, type);
|
|
733
859
|
}
|
|
734
860
|
}
|
|
735
861
|
var createStore = (initialValue) => {
|
|
@@ -812,6 +938,20 @@ class InvalidCallbackError extends TypeError {
|
|
|
812
938
|
}
|
|
813
939
|
}
|
|
814
940
|
|
|
941
|
+
class InvalidCollectionSourceError extends TypeError {
|
|
942
|
+
constructor(where, value) {
|
|
943
|
+
super(`Invalid ${where} source ${valueString(value)}`);
|
|
944
|
+
this.name = "InvalidCollectionSourceError";
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
class InvalidHookError extends TypeError {
|
|
949
|
+
constructor(where, type) {
|
|
950
|
+
super(`Invalid hook "${type}" in ${where}`);
|
|
951
|
+
this.name = "InvalidHookError";
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
815
955
|
class InvalidSignalValueError extends TypeError {
|
|
816
956
|
constructor(where, value) {
|
|
817
957
|
super(`Invalid signal value ${valueString(value)} in ${where}`);
|
|
@@ -832,6 +972,7 @@ class ReadonlySignalError extends Error {
|
|
|
832
972
|
this.name = "ReadonlySignalError";
|
|
833
973
|
}
|
|
834
974
|
}
|
|
975
|
+
var createError = (reason) => reason instanceof Error ? reason : Error(String(reason));
|
|
835
976
|
var validateCallback = (where, value, guard = isFunction) => {
|
|
836
977
|
if (!guard(value))
|
|
837
978
|
throw new InvalidCallbackError(where, value);
|
|
@@ -851,25 +992,20 @@ var guardMutableSignal = (what, value, signal) => {
|
|
|
851
992
|
// src/classes/collection.ts
|
|
852
993
|
var TYPE_COLLECTION = "Collection";
|
|
853
994
|
|
|
854
|
-
class
|
|
995
|
+
class DerivedCollection {
|
|
855
996
|
#watchers = new Set;
|
|
856
997
|
#source;
|
|
857
998
|
#callback;
|
|
858
999
|
#signals = new Map;
|
|
859
1000
|
#ownWatchers = new Map;
|
|
860
|
-
#
|
|
861
|
-
add: new Set,
|
|
862
|
-
change: new Set,
|
|
863
|
-
remove: new Set,
|
|
864
|
-
sort: new Set
|
|
865
|
-
};
|
|
1001
|
+
#hookCallbacks = {};
|
|
866
1002
|
#order = [];
|
|
867
1003
|
constructor(source, callback) {
|
|
868
|
-
validateCallback(
|
|
1004
|
+
validateCallback(TYPE_COLLECTION, callback);
|
|
869
1005
|
if (isFunction(source))
|
|
870
1006
|
source = source();
|
|
871
1007
|
if (!isCollectionSource(source))
|
|
872
|
-
throw new
|
|
1008
|
+
throw new InvalidCollectionSourceError(TYPE_COLLECTION, source);
|
|
873
1009
|
this.#source = source;
|
|
874
1010
|
this.#callback = callback;
|
|
875
1011
|
for (let i = 0;i < this.#source.length; i++) {
|
|
@@ -878,7 +1014,9 @@ class Collection {
|
|
|
878
1014
|
continue;
|
|
879
1015
|
this.#add(key);
|
|
880
1016
|
}
|
|
881
|
-
this.#source.on(
|
|
1017
|
+
this.#source.on(HOOK_ADD, (additions) => {
|
|
1018
|
+
if (!additions)
|
|
1019
|
+
return;
|
|
882
1020
|
for (const key of additions) {
|
|
883
1021
|
if (!this.#signals.has(key)) {
|
|
884
1022
|
this.#add(key);
|
|
@@ -888,9 +1026,11 @@ class Collection {
|
|
|
888
1026
|
}
|
|
889
1027
|
}
|
|
890
1028
|
notifyWatchers(this.#watchers);
|
|
891
|
-
|
|
1029
|
+
triggerHook(this.#hookCallbacks.add, additions);
|
|
892
1030
|
});
|
|
893
|
-
this.#source.on(
|
|
1031
|
+
this.#source.on(HOOK_REMOVE, (removals) => {
|
|
1032
|
+
if (!removals)
|
|
1033
|
+
return;
|
|
894
1034
|
for (const key of removals) {
|
|
895
1035
|
if (!this.#signals.has(key))
|
|
896
1036
|
continue;
|
|
@@ -898,35 +1038,31 @@ class Collection {
|
|
|
898
1038
|
const index = this.#order.indexOf(key);
|
|
899
1039
|
if (index >= 0)
|
|
900
1040
|
this.#order.splice(index, 1);
|
|
901
|
-
this.#
|
|
1041
|
+
const watcher = this.#ownWatchers.get(key);
|
|
1042
|
+
if (watcher) {
|
|
1043
|
+
watcher.stop();
|
|
1044
|
+
this.#ownWatchers.delete(key);
|
|
1045
|
+
}
|
|
902
1046
|
}
|
|
903
1047
|
this.#order = this.#order.filter(() => true);
|
|
904
1048
|
notifyWatchers(this.#watchers);
|
|
905
|
-
|
|
1049
|
+
triggerHook(this.#hookCallbacks.remove, removals);
|
|
906
1050
|
});
|
|
907
|
-
this.#source.on(
|
|
908
|
-
|
|
1051
|
+
this.#source.on(HOOK_SORT, (newOrder) => {
|
|
1052
|
+
if (newOrder)
|
|
1053
|
+
this.#order = [...newOrder];
|
|
909
1054
|
notifyWatchers(this.#watchers);
|
|
910
|
-
|
|
1055
|
+
triggerHook(this.#hookCallbacks.sort, newOrder);
|
|
911
1056
|
});
|
|
912
1057
|
}
|
|
913
|
-
get #value() {
|
|
914
|
-
return this.#order.map((key) => this.#signals.get(key)?.get()).filter((v) => v != null && v !== UNSET);
|
|
915
|
-
}
|
|
916
1058
|
#add(key) {
|
|
917
1059
|
const computedCallback = isAsyncCollectionCallback(this.#callback) ? async (_, abort) => {
|
|
918
|
-
const
|
|
919
|
-
if (!sourceSignal)
|
|
920
|
-
return UNSET;
|
|
921
|
-
const sourceValue = sourceSignal.get();
|
|
1060
|
+
const sourceValue = this.#source.byKey(key)?.get();
|
|
922
1061
|
if (sourceValue === UNSET)
|
|
923
1062
|
return UNSET;
|
|
924
1063
|
return this.#callback(sourceValue, abort);
|
|
925
1064
|
} : () => {
|
|
926
|
-
const
|
|
927
|
-
if (!sourceSignal)
|
|
928
|
-
return UNSET;
|
|
929
|
-
const sourceValue = sourceSignal.get();
|
|
1065
|
+
const sourceValue = this.#source.byKey(key)?.get();
|
|
930
1066
|
if (sourceValue === UNSET)
|
|
931
1067
|
return UNSET;
|
|
932
1068
|
return this.#callback(sourceValue);
|
|
@@ -935,7 +1071,7 @@ class Collection {
|
|
|
935
1071
|
this.#signals.set(key, signal);
|
|
936
1072
|
if (!this.#order.includes(key))
|
|
937
1073
|
this.#order.push(key);
|
|
938
|
-
if (this.#
|
|
1074
|
+
if (this.#hookCallbacks.change?.size)
|
|
939
1075
|
this.#addWatcher(key);
|
|
940
1076
|
return true;
|
|
941
1077
|
}
|
|
@@ -948,13 +1084,6 @@ class Collection {
|
|
|
948
1084
|
this.#ownWatchers.set(key, watcher);
|
|
949
1085
|
watcher();
|
|
950
1086
|
}
|
|
951
|
-
#removeWatcher(key) {
|
|
952
|
-
const watcher = this.#ownWatchers.get(key);
|
|
953
|
-
if (watcher) {
|
|
954
|
-
watcher.stop();
|
|
955
|
-
this.#ownWatchers.delete(key);
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
1087
|
get [Symbol.toStringTag]() {
|
|
959
1088
|
return TYPE_COLLECTION;
|
|
960
1089
|
}
|
|
@@ -968,20 +1097,16 @@ class Collection {
|
|
|
968
1097
|
yield signal;
|
|
969
1098
|
}
|
|
970
1099
|
}
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
return this.#order.length;
|
|
1100
|
+
keys() {
|
|
1101
|
+
return this.#order.values();
|
|
974
1102
|
}
|
|
975
1103
|
get() {
|
|
976
|
-
subscribeActiveWatcher(this.#watchers);
|
|
977
|
-
return this.#
|
|
1104
|
+
subscribeActiveWatcher(this.#watchers, this.#hookCallbacks[HOOK_WATCH]);
|
|
1105
|
+
return this.#order.map((key) => this.#signals.get(key)?.get()).filter((v) => v != null && v !== UNSET);
|
|
978
1106
|
}
|
|
979
1107
|
at(index) {
|
|
980
1108
|
return this.#signals.get(this.#order[index]);
|
|
981
1109
|
}
|
|
982
|
-
keys() {
|
|
983
|
-
return this.#order.values();
|
|
984
|
-
}
|
|
985
1110
|
byKey(key) {
|
|
986
1111
|
return this.#signals.get(key);
|
|
987
1112
|
}
|
|
@@ -991,30 +1116,77 @@ class Collection {
|
|
|
991
1116
|
indexOfKey(key) {
|
|
992
1117
|
return this.#order.indexOf(key);
|
|
993
1118
|
}
|
|
994
|
-
on(type,
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
this.#
|
|
1007
|
-
}
|
|
1119
|
+
on(type, callback) {
|
|
1120
|
+
if (isHandledHook(type, [
|
|
1121
|
+
HOOK_ADD,
|
|
1122
|
+
HOOK_CHANGE,
|
|
1123
|
+
HOOK_REMOVE,
|
|
1124
|
+
HOOK_SORT,
|
|
1125
|
+
HOOK_WATCH
|
|
1126
|
+
])) {
|
|
1127
|
+
this.#hookCallbacks[type] ||= new Set;
|
|
1128
|
+
this.#hookCallbacks[type].add(callback);
|
|
1129
|
+
if (type === HOOK_CHANGE && !this.#ownWatchers.size) {
|
|
1130
|
+
for (const key of this.#signals.keys())
|
|
1131
|
+
this.#addWatcher(key);
|
|
1008
1132
|
}
|
|
1009
|
-
|
|
1133
|
+
return () => {
|
|
1134
|
+
this.#hookCallbacks[type]?.delete(callback);
|
|
1135
|
+
if (type === HOOK_CHANGE && !this.#hookCallbacks.change?.size) {
|
|
1136
|
+
if (this.#ownWatchers.size) {
|
|
1137
|
+
for (const watcher of this.#ownWatchers.values())
|
|
1138
|
+
watcher.stop();
|
|
1139
|
+
this.#ownWatchers.clear();
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
throw new InvalidHookError(TYPE_COLLECTION, type);
|
|
1010
1145
|
}
|
|
1011
1146
|
deriveCollection(callback) {
|
|
1012
|
-
return new
|
|
1147
|
+
return new DerivedCollection(this, callback);
|
|
1148
|
+
}
|
|
1149
|
+
get length() {
|
|
1150
|
+
subscribeActiveWatcher(this.#watchers, this.#hookCallbacks[HOOK_WATCH]);
|
|
1151
|
+
return this.#order.length;
|
|
1013
1152
|
}
|
|
1014
1153
|
}
|
|
1015
1154
|
var isCollection = (value) => isObjectOfType(value, TYPE_COLLECTION);
|
|
1016
1155
|
var isCollectionSource = (value) => isList(value) || isCollection(value);
|
|
1017
1156
|
var isAsyncCollectionCallback = (callback) => isAsyncFunction(callback);
|
|
1157
|
+
// src/classes/ref.ts
|
|
1158
|
+
var TYPE_REF = "Ref";
|
|
1159
|
+
|
|
1160
|
+
class Ref {
|
|
1161
|
+
#watchers = new Set;
|
|
1162
|
+
#value;
|
|
1163
|
+
#watchHookCallbacks;
|
|
1164
|
+
constructor(value, guard) {
|
|
1165
|
+
validateSignalValue(TYPE_REF, value, guard);
|
|
1166
|
+
this.#value = value;
|
|
1167
|
+
}
|
|
1168
|
+
get [Symbol.toStringTag]() {
|
|
1169
|
+
return TYPE_REF;
|
|
1170
|
+
}
|
|
1171
|
+
get() {
|
|
1172
|
+
subscribeActiveWatcher(this.#watchers, this.#watchHookCallbacks);
|
|
1173
|
+
return this.#value;
|
|
1174
|
+
}
|
|
1175
|
+
notify() {
|
|
1176
|
+
notifyWatchers(this.#watchers);
|
|
1177
|
+
}
|
|
1178
|
+
on(type, callback) {
|
|
1179
|
+
if (type === HOOK_WATCH) {
|
|
1180
|
+
this.#watchHookCallbacks ||= new Set;
|
|
1181
|
+
this.#watchHookCallbacks.add(callback);
|
|
1182
|
+
return () => {
|
|
1183
|
+
this.#watchHookCallbacks?.delete(callback);
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
throw new InvalidHookError(TYPE_REF, type);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
var isRef = (value) => isObjectOfType(value, TYPE_REF);
|
|
1018
1190
|
// src/effect.ts
|
|
1019
1191
|
var createEffect = (callback) => {
|
|
1020
1192
|
if (!isFunction(callback) || callback.length > 1)
|
|
@@ -1035,26 +1207,30 @@ var createEffect = (callback) => {
|
|
|
1035
1207
|
const currentController = controller;
|
|
1036
1208
|
callback(controller.signal).then((cleanup2) => {
|
|
1037
1209
|
if (isFunction(cleanup2) && controller === currentController)
|
|
1038
|
-
watcher.
|
|
1210
|
+
watcher.on(HOOK_CLEANUP, cleanup2);
|
|
1039
1211
|
}).catch((error) => {
|
|
1040
1212
|
if (!isAbortError(error))
|
|
1041
|
-
console.error("
|
|
1213
|
+
console.error("Error in async effect callback:", error);
|
|
1042
1214
|
});
|
|
1043
1215
|
} else {
|
|
1044
1216
|
cleanup = callback();
|
|
1045
1217
|
if (isFunction(cleanup))
|
|
1046
|
-
watcher.
|
|
1218
|
+
watcher.on(HOOK_CLEANUP, cleanup);
|
|
1047
1219
|
}
|
|
1048
1220
|
} catch (error) {
|
|
1049
1221
|
if (!isAbortError(error))
|
|
1050
|
-
console.error("
|
|
1222
|
+
console.error("Error in effect callback:", error);
|
|
1051
1223
|
}
|
|
1052
1224
|
running = false;
|
|
1053
1225
|
}));
|
|
1054
1226
|
watcher();
|
|
1055
1227
|
return () => {
|
|
1056
1228
|
controller?.abort();
|
|
1057
|
-
|
|
1229
|
+
try {
|
|
1230
|
+
watcher.stop();
|
|
1231
|
+
} catch (error) {
|
|
1232
|
+
console.error("Error in effect cleanup:", error);
|
|
1233
|
+
}
|
|
1058
1234
|
};
|
|
1059
1235
|
};
|
|
1060
1236
|
// src/match.ts
|
|
@@ -1066,9 +1242,10 @@ function match(result, handlers) {
|
|
|
1066
1242
|
handlers.err?.(result.errors);
|
|
1067
1243
|
else if (result.ok)
|
|
1068
1244
|
handlers.ok(result.values);
|
|
1069
|
-
} catch (
|
|
1070
|
-
|
|
1071
|
-
|
|
1245
|
+
} catch (e) {
|
|
1246
|
+
const error = createError(e);
|
|
1247
|
+
if (handlers.err && (!result.errors || !result.errors.includes(error)))
|
|
1248
|
+
handlers.err(result.errors ? [...result.errors, error] : [error]);
|
|
1072
1249
|
else
|
|
1073
1250
|
throw error;
|
|
1074
1251
|
}
|
|
@@ -1086,7 +1263,7 @@ function resolve(signals) {
|
|
|
1086
1263
|
else
|
|
1087
1264
|
values[key] = value;
|
|
1088
1265
|
} catch (e) {
|
|
1089
|
-
errors.push(
|
|
1266
|
+
errors.push(createError(e));
|
|
1090
1267
|
}
|
|
1091
1268
|
}
|
|
1092
1269
|
if (pending)
|
|
@@ -1097,8 +1274,10 @@ function resolve(signals) {
|
|
|
1097
1274
|
}
|
|
1098
1275
|
export {
|
|
1099
1276
|
valueString,
|
|
1277
|
+
validateSignalValue,
|
|
1278
|
+
validateCallback,
|
|
1279
|
+
triggerHook,
|
|
1100
1280
|
trackSignalReads,
|
|
1101
|
-
toError,
|
|
1102
1281
|
subscribeActiveWatcher,
|
|
1103
1282
|
resolve,
|
|
1104
1283
|
notifyWatchers,
|
|
@@ -1109,6 +1288,7 @@ export {
|
|
|
1109
1288
|
isStore,
|
|
1110
1289
|
isState,
|
|
1111
1290
|
isSignal,
|
|
1291
|
+
isRef,
|
|
1112
1292
|
isRecordOrArray,
|
|
1113
1293
|
isRecord,
|
|
1114
1294
|
isObjectOfType,
|
|
@@ -1116,18 +1296,20 @@ export {
|
|
|
1116
1296
|
isMutableSignal,
|
|
1117
1297
|
isMemoCallback,
|
|
1118
1298
|
isList,
|
|
1299
|
+
isHandledHook,
|
|
1119
1300
|
isFunction,
|
|
1120
1301
|
isEqual,
|
|
1121
1302
|
isComputed,
|
|
1122
1303
|
isCollection,
|
|
1123
1304
|
isAsyncFunction,
|
|
1124
1305
|
isAbortError,
|
|
1306
|
+
guardMutableSignal,
|
|
1125
1307
|
flushPendingReactions,
|
|
1126
|
-
emitNotification,
|
|
1127
1308
|
diff,
|
|
1128
1309
|
createWatcher,
|
|
1129
1310
|
createStore,
|
|
1130
1311
|
createSignal,
|
|
1312
|
+
createError,
|
|
1131
1313
|
createEffect,
|
|
1132
1314
|
createComputed,
|
|
1133
1315
|
batchSignalWrites,
|
|
@@ -1135,18 +1317,27 @@ export {
|
|
|
1135
1317
|
Task,
|
|
1136
1318
|
TYPE_STORE,
|
|
1137
1319
|
TYPE_STATE,
|
|
1320
|
+
TYPE_REF,
|
|
1138
1321
|
TYPE_LIST,
|
|
1139
1322
|
TYPE_COMPUTED,
|
|
1140
1323
|
TYPE_COLLECTION,
|
|
1141
1324
|
State,
|
|
1325
|
+
Ref,
|
|
1142
1326
|
ReadonlySignalError,
|
|
1143
1327
|
NullishSignalValueError,
|
|
1144
1328
|
Memo,
|
|
1145
1329
|
List,
|
|
1146
1330
|
InvalidSignalValueError,
|
|
1331
|
+
InvalidCollectionSourceError,
|
|
1147
1332
|
InvalidCallbackError,
|
|
1333
|
+
HOOK_WATCH,
|
|
1334
|
+
HOOK_SORT,
|
|
1335
|
+
HOOK_REMOVE,
|
|
1336
|
+
HOOK_CLEANUP,
|
|
1337
|
+
HOOK_CHANGE,
|
|
1338
|
+
HOOK_ADD,
|
|
1148
1339
|
DuplicateKeyError,
|
|
1149
|
-
|
|
1340
|
+
DerivedCollection,
|
|
1150
1341
|
CircularDependencyError,
|
|
1151
1342
|
BaseStore
|
|
1152
1343
|
};
|