@zeix/cause-effect 0.15.2 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ai-context.md +254 -0
- package/.cursorrules +54 -0
- package/.github/copilot-instructions.md +132 -0
- package/CLAUDE.md +319 -0
- package/README.md +136 -166
- package/eslint.config.js +1 -1
- package/index.dev.js +263 -262
- package/index.js +1 -1
- package/index.ts +24 -23
- package/package.json +1 -1
- package/src/computed.ts +54 -44
- package/src/diff.ts +24 -21
- package/src/effect.ts +15 -12
- package/src/errors.ts +8 -0
- package/src/signal.ts +6 -6
- package/src/state.ts +44 -48
- package/src/store.ts +236 -309
- package/src/system.ts +122 -0
- package/src/util.ts +3 -12
- package/test/batch.test.ts +18 -11
- package/test/benchmark.test.ts +4 -4
- package/test/computed.test.ts +508 -72
- package/test/effect.test.ts +61 -61
- package/test/match.test.ts +25 -25
- package/test/resolve.test.ts +16 -16
- package/test/signal.test.ts +9 -9
- package/test/state.test.ts +212 -25
- package/test/store.test.ts +1007 -1357
- package/test/util/dependency-graph.ts +1 -1
- package/types/index.d.ts +9 -9
- package/types/src/collection.d.ts +26 -0
- package/types/src/computed.d.ts +9 -9
- package/types/src/diff.d.ts +7 -7
- package/types/src/effect.d.ts +3 -3
- package/types/src/errors.d.ts +4 -1
- package/types/src/state.d.ts +5 -5
- package/types/src/store.d.ts +29 -44
- package/types/src/system.d.ts +44 -0
- package/types/src/util.d.ts +1 -2
- package/src/scheduler.ts +0 -172
package/index.dev.js
CHANGED
|
@@ -6,6 +6,13 @@ class CircularDependencyError extends Error {
|
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
class InvalidCallbackError extends TypeError {
|
|
10
|
+
constructor(where, value) {
|
|
11
|
+
super(`Invalid ${where} callback ${value}`);
|
|
12
|
+
this.name = "InvalidCallbackError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
9
16
|
class InvalidSignalValueError extends TypeError {
|
|
10
17
|
constructor(where, value) {
|
|
11
18
|
super(`Invalid signal value ${value} in ${where}`);
|
|
@@ -48,7 +55,6 @@ var isNumber = (value) => typeof value === "number";
|
|
|
48
55
|
var isSymbol = (value) => typeof value === "symbol";
|
|
49
56
|
var isFunction = (fn) => typeof fn === "function";
|
|
50
57
|
var isAsyncFunction = (fn) => isFunction(fn) && fn.constructor.name === "AsyncFunction";
|
|
51
|
-
var isDefinedObject = (value) => !!value && typeof value === "object";
|
|
52
58
|
var isObjectOfType = (value, type) => Object.prototype.toString.call(value) === `[object ${type}]`;
|
|
53
59
|
var isRecord = (value) => isObjectOfType(value, "Object");
|
|
54
60
|
var isRecordOrArray = (value) => isRecord(value) || Array.isArray(value);
|
|
@@ -65,12 +71,11 @@ var recordToArray = (record) => {
|
|
|
65
71
|
if (indexes === null)
|
|
66
72
|
return record;
|
|
67
73
|
const array = [];
|
|
68
|
-
for (const index of indexes)
|
|
74
|
+
for (const index of indexes)
|
|
69
75
|
array.push(record[String(index)]);
|
|
70
|
-
}
|
|
71
76
|
return array;
|
|
72
77
|
};
|
|
73
|
-
var valueString = (value) => isString(value) ? `"${value}"` :
|
|
78
|
+
var valueString = (value) => isString(value) ? `"${value}"` : !!value && typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
74
79
|
|
|
75
80
|
// src/diff.ts
|
|
76
81
|
var isEqual = (a, b, visited) => {
|
|
@@ -160,64 +165,46 @@ var diff = (oldObj, newObj) => {
|
|
|
160
165
|
};
|
|
161
166
|
};
|
|
162
167
|
|
|
163
|
-
// src/
|
|
164
|
-
var
|
|
165
|
-
var
|
|
168
|
+
// src/system.ts
|
|
169
|
+
var activeWatcher;
|
|
170
|
+
var pendingWatchers = new Set;
|
|
166
171
|
var batchDepth = 0;
|
|
167
|
-
var
|
|
168
|
-
var requestId;
|
|
169
|
-
var updateDOM = () => {
|
|
170
|
-
requestId = undefined;
|
|
171
|
-
const updates = Array.from(updateMap.values());
|
|
172
|
-
updateMap.clear();
|
|
173
|
-
for (const update of updates) {
|
|
174
|
-
update();
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
var requestTick = () => {
|
|
178
|
-
if (requestId)
|
|
179
|
-
cancelAnimationFrame(requestId);
|
|
180
|
-
requestId = requestAnimationFrame(updateDOM);
|
|
181
|
-
};
|
|
182
|
-
queueMicrotask(updateDOM);
|
|
183
|
-
var watch = (notice) => {
|
|
172
|
+
var createWatcher = (watch) => {
|
|
184
173
|
const cleanups = new Set;
|
|
185
|
-
const w =
|
|
186
|
-
w.
|
|
187
|
-
cleanups.add(
|
|
174
|
+
const w = watch;
|
|
175
|
+
w.unwatch = (cleanup) => {
|
|
176
|
+
cleanups.add(cleanup);
|
|
188
177
|
};
|
|
189
178
|
w.cleanup = () => {
|
|
190
|
-
for (const cleanup of cleanups)
|
|
179
|
+
for (const cleanup of cleanups)
|
|
191
180
|
cleanup();
|
|
192
|
-
}
|
|
193
181
|
cleanups.clear();
|
|
194
182
|
};
|
|
195
183
|
return w;
|
|
196
184
|
};
|
|
197
185
|
var subscribe = (watchers) => {
|
|
198
|
-
if (
|
|
199
|
-
const watcher =
|
|
200
|
-
|
|
201
|
-
active.off(() => {
|
|
186
|
+
if (activeWatcher && !watchers.has(activeWatcher)) {
|
|
187
|
+
const watcher = activeWatcher;
|
|
188
|
+
watcher.unwatch(() => {
|
|
202
189
|
watchers.delete(watcher);
|
|
203
190
|
});
|
|
191
|
+
watchers.add(watcher);
|
|
204
192
|
}
|
|
205
193
|
};
|
|
206
194
|
var notify = (watchers) => {
|
|
207
195
|
for (const watcher of watchers) {
|
|
208
196
|
if (batchDepth)
|
|
209
|
-
|
|
197
|
+
pendingWatchers.add(watcher);
|
|
210
198
|
else
|
|
211
199
|
watcher();
|
|
212
200
|
}
|
|
213
201
|
};
|
|
214
202
|
var flush = () => {
|
|
215
|
-
while (
|
|
216
|
-
const watchers = Array.from(
|
|
217
|
-
|
|
218
|
-
for (const watcher of watchers)
|
|
203
|
+
while (pendingWatchers.size) {
|
|
204
|
+
const watchers = Array.from(pendingWatchers);
|
|
205
|
+
pendingWatchers.clear();
|
|
206
|
+
for (const watcher of watchers)
|
|
219
207
|
watcher();
|
|
220
|
-
}
|
|
221
208
|
}
|
|
222
209
|
};
|
|
223
210
|
var batch = (fn) => {
|
|
@@ -230,30 +217,24 @@ var batch = (fn) => {
|
|
|
230
217
|
}
|
|
231
218
|
};
|
|
232
219
|
var observe = (run, watcher) => {
|
|
233
|
-
const prev =
|
|
234
|
-
|
|
220
|
+
const prev = activeWatcher;
|
|
221
|
+
activeWatcher = watcher;
|
|
235
222
|
try {
|
|
236
223
|
run();
|
|
237
224
|
} finally {
|
|
238
|
-
|
|
225
|
+
activeWatcher = prev;
|
|
239
226
|
}
|
|
240
227
|
};
|
|
241
|
-
var enqueue = (fn, dedupe) => new Promise((resolve, reject) => {
|
|
242
|
-
updateMap.set(dedupe || Symbol(), () => {
|
|
243
|
-
try {
|
|
244
|
-
resolve(fn());
|
|
245
|
-
} catch (error) {
|
|
246
|
-
reject(error);
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
requestTick();
|
|
250
|
-
});
|
|
251
228
|
|
|
252
229
|
// src/computed.ts
|
|
253
230
|
var TYPE_COMPUTED = "Computed";
|
|
254
|
-
var
|
|
231
|
+
var createComputed = (callback, initialValue = UNSET) => {
|
|
232
|
+
if (!isComputedCallback(callback))
|
|
233
|
+
throw new InvalidCallbackError("computed", valueString(callback));
|
|
234
|
+
if (initialValue == null)
|
|
235
|
+
throw new NullishSignalValueError("computed");
|
|
255
236
|
const watchers = new Set;
|
|
256
|
-
let value =
|
|
237
|
+
let value = initialValue;
|
|
257
238
|
let error;
|
|
258
239
|
let controller;
|
|
259
240
|
let dirty = true;
|
|
@@ -278,29 +259,29 @@ var computed = (fn) => {
|
|
|
278
259
|
value = UNSET;
|
|
279
260
|
error = newError;
|
|
280
261
|
};
|
|
281
|
-
const settle = (
|
|
262
|
+
const settle = (fn) => (arg) => {
|
|
282
263
|
computing = false;
|
|
283
264
|
controller = undefined;
|
|
284
|
-
|
|
265
|
+
fn(arg);
|
|
285
266
|
if (changed)
|
|
286
267
|
notify(watchers);
|
|
287
268
|
};
|
|
288
|
-
const
|
|
269
|
+
const watcher = createWatcher(() => {
|
|
289
270
|
dirty = true;
|
|
290
271
|
controller?.abort();
|
|
291
272
|
if (watchers.size)
|
|
292
273
|
notify(watchers);
|
|
293
274
|
else
|
|
294
|
-
|
|
275
|
+
watcher.cleanup();
|
|
295
276
|
});
|
|
296
|
-
|
|
277
|
+
watcher.unwatch(() => {
|
|
297
278
|
controller?.abort();
|
|
298
279
|
});
|
|
299
280
|
const compute = () => observe(() => {
|
|
300
281
|
if (computing)
|
|
301
282
|
throw new CircularDependencyError("computed");
|
|
302
283
|
changed = false;
|
|
303
|
-
if (isAsyncFunction(
|
|
284
|
+
if (isAsyncFunction(callback)) {
|
|
304
285
|
if (controller)
|
|
305
286
|
return value;
|
|
306
287
|
controller = new AbortController;
|
|
@@ -315,7 +296,7 @@ var computed = (fn) => {
|
|
|
315
296
|
let result;
|
|
316
297
|
computing = true;
|
|
317
298
|
try {
|
|
318
|
-
result = controller ?
|
|
299
|
+
result = controller ? callback(value, controller.signal) : callback(value);
|
|
319
300
|
} catch (e) {
|
|
320
301
|
if (isAbortError(e))
|
|
321
302
|
nil();
|
|
@@ -331,29 +312,36 @@ var computed = (fn) => {
|
|
|
331
312
|
else
|
|
332
313
|
ok(result);
|
|
333
314
|
computing = false;
|
|
334
|
-
},
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
315
|
+
}, watcher);
|
|
316
|
+
const computed = {};
|
|
317
|
+
Object.defineProperties(computed, {
|
|
318
|
+
[Symbol.toStringTag]: {
|
|
319
|
+
value: TYPE_COMPUTED
|
|
320
|
+
},
|
|
321
|
+
get: {
|
|
322
|
+
value: () => {
|
|
323
|
+
subscribe(watchers);
|
|
324
|
+
flush();
|
|
325
|
+
if (dirty)
|
|
326
|
+
compute();
|
|
327
|
+
if (error)
|
|
328
|
+
throw error;
|
|
329
|
+
return value;
|
|
330
|
+
}
|
|
345
331
|
}
|
|
346
|
-
};
|
|
347
|
-
return
|
|
332
|
+
});
|
|
333
|
+
return computed;
|
|
348
334
|
};
|
|
349
335
|
var isComputed = (value) => isObjectOfType(value, TYPE_COMPUTED);
|
|
350
|
-
var isComputedCallback = (value) => isFunction(value) && value.length <
|
|
336
|
+
var isComputedCallback = (value) => isFunction(value) && value.length < 3;
|
|
351
337
|
// src/effect.ts
|
|
352
|
-
var
|
|
338
|
+
var createEffect = (callback) => {
|
|
339
|
+
if (!isFunction(callback) || callback.length > 1)
|
|
340
|
+
throw new InvalidCallbackError("effect", valueString(callback));
|
|
353
341
|
const isAsync = isAsyncFunction(callback);
|
|
354
342
|
let running = false;
|
|
355
343
|
let controller;
|
|
356
|
-
const
|
|
344
|
+
const watcher = createWatcher(() => observe(() => {
|
|
357
345
|
if (running)
|
|
358
346
|
throw new CircularDependencyError("effect");
|
|
359
347
|
running = true;
|
|
@@ -366,7 +354,7 @@ var effect = (callback) => {
|
|
|
366
354
|
const currentController = controller;
|
|
367
355
|
callback(controller.signal).then((cleanup2) => {
|
|
368
356
|
if (isFunction(cleanup2) && controller === currentController)
|
|
369
|
-
|
|
357
|
+
watcher.unwatch(cleanup2);
|
|
370
358
|
}).catch((error) => {
|
|
371
359
|
if (!isAbortError(error))
|
|
372
360
|
console.error("Async effect error:", error);
|
|
@@ -374,18 +362,18 @@ var effect = (callback) => {
|
|
|
374
362
|
} else {
|
|
375
363
|
cleanup = callback();
|
|
376
364
|
if (isFunction(cleanup))
|
|
377
|
-
|
|
365
|
+
watcher.unwatch(cleanup);
|
|
378
366
|
}
|
|
379
367
|
} catch (error) {
|
|
380
368
|
if (!isAbortError(error))
|
|
381
369
|
console.error("Effect callback error:", error);
|
|
382
370
|
}
|
|
383
371
|
running = false;
|
|
384
|
-
},
|
|
385
|
-
|
|
372
|
+
}, watcher));
|
|
373
|
+
watcher();
|
|
386
374
|
return () => {
|
|
387
375
|
controller?.abort();
|
|
388
|
-
|
|
376
|
+
watcher.cleanup();
|
|
389
377
|
};
|
|
390
378
|
};
|
|
391
379
|
// src/match.ts
|
|
@@ -407,20 +395,20 @@ function match(result, handlers) {
|
|
|
407
395
|
// src/resolve.ts
|
|
408
396
|
function resolve(signals) {
|
|
409
397
|
const errors = [];
|
|
410
|
-
let
|
|
398
|
+
let pending = false;
|
|
411
399
|
const values = {};
|
|
412
400
|
for (const [key, signal] of Object.entries(signals)) {
|
|
413
401
|
try {
|
|
414
402
|
const value = signal.get();
|
|
415
403
|
if (value === UNSET)
|
|
416
|
-
|
|
404
|
+
pending = true;
|
|
417
405
|
else
|
|
418
406
|
values[key] = value;
|
|
419
407
|
} catch (e) {
|
|
420
408
|
errors.push(toError(e));
|
|
421
409
|
}
|
|
422
410
|
}
|
|
423
|
-
if (
|
|
411
|
+
if (pending)
|
|
424
412
|
return { ok: false, pending: true };
|
|
425
413
|
if (errors.length > 0)
|
|
426
414
|
return { ok: false, errors };
|
|
@@ -428,54 +416,75 @@ function resolve(signals) {
|
|
|
428
416
|
}
|
|
429
417
|
// src/state.ts
|
|
430
418
|
var TYPE_STATE = "State";
|
|
431
|
-
var
|
|
419
|
+
var createState = (initialValue) => {
|
|
420
|
+
if (initialValue == null)
|
|
421
|
+
throw new NullishSignalValueError("state");
|
|
432
422
|
const watchers = new Set;
|
|
433
423
|
let value = initialValue;
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
return
|
|
424
|
+
const setValue = (newValue) => {
|
|
425
|
+
if (newValue == null)
|
|
426
|
+
throw new NullishSignalValueError("state");
|
|
427
|
+
if (isEqual(value, newValue))
|
|
428
|
+
return;
|
|
429
|
+
value = newValue;
|
|
430
|
+
notify(watchers);
|
|
431
|
+
if (UNSET === value)
|
|
432
|
+
watchers.clear();
|
|
433
|
+
};
|
|
434
|
+
const state = {};
|
|
435
|
+
Object.defineProperties(state, {
|
|
436
|
+
[Symbol.toStringTag]: {
|
|
437
|
+
value: TYPE_STATE
|
|
439
438
|
},
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
439
|
+
get: {
|
|
440
|
+
value: () => {
|
|
441
|
+
subscribe(watchers);
|
|
442
|
+
return value;
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
set: {
|
|
446
|
+
value: (newValue) => {
|
|
447
|
+
setValue(newValue);
|
|
448
|
+
}
|
|
449
449
|
},
|
|
450
|
-
update:
|
|
451
|
-
|
|
450
|
+
update: {
|
|
451
|
+
value: (updater) => {
|
|
452
|
+
if (!isFunction(updater))
|
|
453
|
+
throw new InvalidCallbackError("state update", valueString(updater));
|
|
454
|
+
setValue(updater(value));
|
|
455
|
+
}
|
|
452
456
|
}
|
|
453
|
-
};
|
|
454
|
-
return
|
|
457
|
+
});
|
|
458
|
+
return state;
|
|
455
459
|
};
|
|
456
460
|
var isState = (value) => isObjectOfType(value, TYPE_STATE);
|
|
457
461
|
|
|
458
462
|
// src/store.ts
|
|
459
463
|
var TYPE_STORE = "Store";
|
|
460
|
-
var
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
var STORE_EVENT_SORT = "store-sort";
|
|
464
|
-
var store = (initialValue) => {
|
|
464
|
+
var createStore = (initialValue) => {
|
|
465
|
+
if (initialValue == null)
|
|
466
|
+
throw new NullishSignalValueError("store");
|
|
465
467
|
const watchers = new Set;
|
|
466
|
-
const
|
|
468
|
+
const listeners = {
|
|
469
|
+
add: new Set,
|
|
470
|
+
change: new Set,
|
|
471
|
+
remove: new Set,
|
|
472
|
+
sort: new Set
|
|
473
|
+
};
|
|
467
474
|
const signals = new Map;
|
|
468
|
-
const
|
|
475
|
+
const signalWatchers = new Map;
|
|
469
476
|
const isArrayLike = Array.isArray(initialValue);
|
|
470
|
-
const size = state(0);
|
|
471
477
|
const current = () => {
|
|
472
478
|
const record = {};
|
|
473
|
-
for (const [key, signal] of signals)
|
|
479
|
+
for (const [key, signal] of signals)
|
|
474
480
|
record[key] = signal.get();
|
|
475
|
-
}
|
|
476
481
|
return record;
|
|
477
482
|
};
|
|
478
|
-
const emit = (
|
|
483
|
+
const emit = (key, changes) => {
|
|
484
|
+
Object.freeze(changes);
|
|
485
|
+
for (const listener of listeners[key])
|
|
486
|
+
listener(changes);
|
|
487
|
+
};
|
|
479
488
|
const getSortedIndexes = () => Array.from(signals.keys()).map((k) => Number(k)).filter((n) => Number.isInteger(n)).sort((a, b) => a - b);
|
|
480
489
|
const isValidValue = (key, value) => {
|
|
481
490
|
if (value == null)
|
|
@@ -489,39 +498,30 @@ var store = (initialValue) => {
|
|
|
489
498
|
const addProperty = (key, value, single = false) => {
|
|
490
499
|
if (!isValidValue(key, value))
|
|
491
500
|
return false;
|
|
492
|
-
const signal = isState(value) || isStore(value) ? value : isRecord(value)
|
|
501
|
+
const signal = isState(value) || isStore(value) ? value : isRecord(value) || Array.isArray(value) ? createStore(value) : createState(value);
|
|
493
502
|
signals.set(key, signal);
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
});
|
|
500
|
-
});
|
|
501
|
-
cleanups.set(key, cleanup);
|
|
503
|
+
const watcher = createWatcher(() => observe(() => {
|
|
504
|
+
emit("change", { [key]: signal.get() });
|
|
505
|
+
}, watcher));
|
|
506
|
+
watcher();
|
|
507
|
+
signalWatchers.set(key, watcher);
|
|
502
508
|
if (single) {
|
|
503
|
-
size.set(signals.size);
|
|
504
509
|
notify(watchers);
|
|
505
|
-
emit(
|
|
506
|
-
[key]: value
|
|
507
|
-
});
|
|
510
|
+
emit("add", { [key]: value });
|
|
508
511
|
}
|
|
509
512
|
return true;
|
|
510
513
|
};
|
|
511
514
|
const removeProperty = (key, single = false) => {
|
|
512
515
|
const ok = signals.delete(key);
|
|
513
516
|
if (ok) {
|
|
514
|
-
const
|
|
515
|
-
if (
|
|
516
|
-
cleanup();
|
|
517
|
-
|
|
517
|
+
const watcher = signalWatchers.get(key);
|
|
518
|
+
if (watcher)
|
|
519
|
+
watcher.cleanup();
|
|
520
|
+
signalWatchers.delete(key);
|
|
518
521
|
}
|
|
519
522
|
if (single) {
|
|
520
|
-
size.set(signals.size);
|
|
521
523
|
notify(watchers);
|
|
522
|
-
emit(
|
|
523
|
-
[key]: UNSET
|
|
524
|
-
});
|
|
524
|
+
emit("remove", { [key]: UNSET });
|
|
525
525
|
}
|
|
526
526
|
return ok;
|
|
527
527
|
};
|
|
@@ -529,16 +529,14 @@ var store = (initialValue) => {
|
|
|
529
529
|
const changes = diff(oldValue, newValue);
|
|
530
530
|
batch(() => {
|
|
531
531
|
if (Object.keys(changes.add).length) {
|
|
532
|
-
for (const key in changes.add)
|
|
533
|
-
|
|
534
|
-
addProperty(key, value);
|
|
535
|
-
}
|
|
532
|
+
for (const key in changes.add)
|
|
533
|
+
addProperty(key, changes.add[key] ?? UNSET);
|
|
536
534
|
if (initialRun) {
|
|
537
535
|
setTimeout(() => {
|
|
538
|
-
emit(
|
|
536
|
+
emit("add", changes.add);
|
|
539
537
|
}, 0);
|
|
540
538
|
} else {
|
|
541
|
-
emit(
|
|
539
|
+
emit("add", changes.add);
|
|
542
540
|
}
|
|
543
541
|
}
|
|
544
542
|
if (Object.keys(changes.change).length) {
|
|
@@ -552,141 +550,142 @@ var store = (initialValue) => {
|
|
|
552
550
|
else
|
|
553
551
|
throw new StoreKeyReadonlyError(key, valueString(value));
|
|
554
552
|
}
|
|
555
|
-
emit(
|
|
553
|
+
emit("change", changes.change);
|
|
556
554
|
}
|
|
557
555
|
if (Object.keys(changes.remove).length) {
|
|
558
556
|
for (const key in changes.remove)
|
|
559
557
|
removeProperty(key);
|
|
560
|
-
emit(
|
|
558
|
+
emit("remove", changes.remove);
|
|
561
559
|
}
|
|
562
|
-
size.set(signals.size);
|
|
563
560
|
});
|
|
564
561
|
return changes.changed;
|
|
565
562
|
};
|
|
566
563
|
reconcile({}, initialValue, true);
|
|
567
|
-
const
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
addProperty(key, v, true);
|
|
572
|
-
} : (k, v) => {
|
|
573
|
-
if (!signals.has(k))
|
|
574
|
-
addProperty(k, v, true);
|
|
575
|
-
else
|
|
576
|
-
throw new StoreKeyExistsError(k, valueString(v));
|
|
564
|
+
const store = {};
|
|
565
|
+
Object.defineProperties(store, {
|
|
566
|
+
[Symbol.toStringTag]: {
|
|
567
|
+
value: TYPE_STORE
|
|
577
568
|
},
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
return recordToArray(current());
|
|
569
|
+
[Symbol.isConcatSpreadable]: {
|
|
570
|
+
value: isArrayLike
|
|
581
571
|
},
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
572
|
+
[Symbol.iterator]: {
|
|
573
|
+
value: isArrayLike ? function* () {
|
|
574
|
+
const indexes = getSortedIndexes();
|
|
575
|
+
for (const index of indexes) {
|
|
576
|
+
const signal = signals.get(String(index));
|
|
577
|
+
if (signal)
|
|
578
|
+
yield signal;
|
|
579
|
+
}
|
|
580
|
+
} : function* () {
|
|
581
|
+
for (const [key, signal] of signals)
|
|
582
|
+
yield [key, signal];
|
|
583
|
+
}
|
|
594
584
|
},
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
585
|
+
add: {
|
|
586
|
+
value: isArrayLike ? (v) => {
|
|
587
|
+
addProperty(String(signals.size), v, true);
|
|
588
|
+
} : (k, v) => {
|
|
589
|
+
if (!signals.has(k))
|
|
590
|
+
addProperty(k, v, true);
|
|
591
|
+
else
|
|
592
|
+
throw new StoreKeyExistsError(k, valueString(v));
|
|
593
|
+
}
|
|
594
|
+
},
|
|
595
|
+
get: {
|
|
596
|
+
value: () => {
|
|
597
|
+
subscribe(watchers);
|
|
598
|
+
return recordToArray(current());
|
|
599
|
+
}
|
|
600
|
+
},
|
|
601
|
+
remove: {
|
|
602
|
+
value: isArrayLike ? (index) => {
|
|
603
|
+
const currentArray = recordToArray(current());
|
|
604
|
+
const currentLength = signals.size;
|
|
605
|
+
if (!Array.isArray(currentArray) || index <= -currentLength || index >= currentLength)
|
|
606
|
+
throw new StoreKeyRangeError(index);
|
|
607
|
+
const newArray = [...currentArray];
|
|
608
|
+
newArray.splice(index, 1);
|
|
609
|
+
if (reconcile(currentArray, newArray))
|
|
610
|
+
notify(watchers);
|
|
611
|
+
} : (k) => {
|
|
612
|
+
if (signals.has(k))
|
|
613
|
+
removeProperty(k, true);
|
|
614
|
+
}
|
|
615
|
+
},
|
|
616
|
+
set: {
|
|
617
|
+
value: (v) => {
|
|
618
|
+
if (reconcile(current(), v)) {
|
|
619
|
+
notify(watchers);
|
|
620
|
+
if (UNSET === v)
|
|
621
|
+
watchers.clear();
|
|
622
|
+
}
|
|
600
623
|
}
|
|
601
624
|
},
|
|
602
|
-
update:
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
625
|
+
update: {
|
|
626
|
+
value: (fn) => {
|
|
627
|
+
const oldValue = current();
|
|
628
|
+
const newValue = fn(recordToArray(oldValue));
|
|
629
|
+
if (reconcile(oldValue, newValue)) {
|
|
630
|
+
notify(watchers);
|
|
631
|
+
if (UNSET === newValue)
|
|
632
|
+
watchers.clear();
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
},
|
|
636
|
+
sort: {
|
|
637
|
+
value: (compareFn) => {
|
|
638
|
+
const entries = Array.from(signals.entries()).map(([key, signal]) => [key, signal.get()]).sort(compareFn ? (a, b) => compareFn(a[1], b[1]) : (a, b) => String(a[1]).localeCompare(String(b[1])));
|
|
639
|
+
const newOrder = entries.map(([key]) => String(key));
|
|
640
|
+
const newSignals = new Map;
|
|
641
|
+
entries.forEach(([key], newIndex) => {
|
|
642
|
+
const oldKey = String(key);
|
|
643
|
+
const newKey = isArrayLike ? String(newIndex) : String(key);
|
|
644
|
+
const signal = signals.get(oldKey);
|
|
645
|
+
if (signal)
|
|
646
|
+
newSignals.set(newKey, signal);
|
|
647
|
+
});
|
|
648
|
+
signals.clear();
|
|
649
|
+
newSignals.forEach((signal, key) => signals.set(key, signal));
|
|
606
650
|
notify(watchers);
|
|
607
|
-
|
|
608
|
-
watchers.clear();
|
|
651
|
+
emit("sort", newOrder);
|
|
609
652
|
}
|
|
610
653
|
},
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
const oldKey = String(key);
|
|
617
|
-
const newKey = isArrayLike ? String(newIndex) : String(key);
|
|
618
|
-
const signal = signals.get(oldKey);
|
|
619
|
-
if (signal)
|
|
620
|
-
newSignals.set(newKey, signal);
|
|
621
|
-
});
|
|
622
|
-
signals.clear();
|
|
623
|
-
newSignals.forEach((signal, key) => signals.set(key, signal));
|
|
624
|
-
notify(watchers);
|
|
625
|
-
emit(STORE_EVENT_SORT, newOrder);
|
|
654
|
+
on: {
|
|
655
|
+
value: (type, listener) => {
|
|
656
|
+
listeners[type].add(listener);
|
|
657
|
+
return () => listeners[type].delete(listener);
|
|
658
|
+
}
|
|
626
659
|
},
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
dispatchEvent: eventTarget.dispatchEvent.bind(eventTarget),
|
|
630
|
-
size
|
|
631
|
-
};
|
|
632
|
-
return new Proxy({}, {
|
|
633
|
-
get(_target, prop) {
|
|
634
|
-
if (prop === Symbol.toStringTag)
|
|
635
|
-
return TYPE_STORE;
|
|
636
|
-
if (prop === Symbol.isConcatSpreadable)
|
|
637
|
-
return isArrayLike;
|
|
638
|
-
if (prop === Symbol.iterator)
|
|
639
|
-
return isArrayLike ? function* () {
|
|
640
|
-
const indexes = getSortedIndexes();
|
|
641
|
-
for (const index of indexes) {
|
|
642
|
-
const signal = signals.get(String(index));
|
|
643
|
-
if (signal)
|
|
644
|
-
yield signal;
|
|
645
|
-
}
|
|
646
|
-
} : function* () {
|
|
647
|
-
for (const [key, signal] of signals)
|
|
648
|
-
yield [key, signal];
|
|
649
|
-
};
|
|
650
|
-
if (isSymbol(prop))
|
|
651
|
-
return;
|
|
652
|
-
if (prop in s)
|
|
653
|
-
return s[prop];
|
|
654
|
-
if (prop === "length" && isArrayLike) {
|
|
660
|
+
length: {
|
|
661
|
+
get() {
|
|
655
662
|
subscribe(watchers);
|
|
656
|
-
return size
|
|
663
|
+
return signals.size;
|
|
657
664
|
}
|
|
665
|
+
}
|
|
666
|
+
});
|
|
667
|
+
return new Proxy(store, {
|
|
668
|
+
get(target, prop) {
|
|
669
|
+
if (prop in target)
|
|
670
|
+
return Reflect.get(target, prop);
|
|
671
|
+
if (isSymbol(prop))
|
|
672
|
+
return;
|
|
658
673
|
return signals.get(prop);
|
|
659
674
|
},
|
|
660
|
-
has(
|
|
661
|
-
|
|
662
|
-
|
|
675
|
+
has(target, prop) {
|
|
676
|
+
if (prop in target)
|
|
677
|
+
return true;
|
|
678
|
+
return signals.has(String(prop));
|
|
663
679
|
},
|
|
664
|
-
ownKeys() {
|
|
665
|
-
|
|
680
|
+
ownKeys(target) {
|
|
681
|
+
const staticKeys = Reflect.ownKeys(target);
|
|
682
|
+
const signalKeys = isArrayLike ? getSortedIndexes().map((key) => String(key)) : Array.from(signals.keys());
|
|
683
|
+
return [...new Set([...signalKeys, ...staticKeys])];
|
|
666
684
|
},
|
|
667
|
-
getOwnPropertyDescriptor(
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
writable: false,
|
|
672
|
-
value
|
|
673
|
-
});
|
|
674
|
-
if (prop === "length" && isArrayLike)
|
|
675
|
-
return {
|
|
676
|
-
enumerable: true,
|
|
677
|
-
configurable: true,
|
|
678
|
-
writable: false,
|
|
679
|
-
value: size.get()
|
|
680
|
-
};
|
|
681
|
-
if (prop === Symbol.isConcatSpreadable)
|
|
682
|
-
return nonEnumerable(isArrayLike);
|
|
683
|
-
if (prop === Symbol.toStringTag)
|
|
684
|
-
return nonEnumerable(TYPE_STORE);
|
|
685
|
-
if (isSymbol(prop))
|
|
686
|
-
return;
|
|
687
|
-
if (Object.keys(s).includes(prop))
|
|
688
|
-
return nonEnumerable(s[prop]);
|
|
689
|
-
const signal = signals.get(prop);
|
|
685
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
686
|
+
if (prop in target)
|
|
687
|
+
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
688
|
+
const signal = signals.get(String(prop));
|
|
690
689
|
return signal ? {
|
|
691
690
|
enumerable: true,
|
|
692
691
|
configurable: true,
|
|
@@ -705,18 +704,16 @@ function toSignal(value) {
|
|
|
705
704
|
if (isSignal(value))
|
|
706
705
|
return value;
|
|
707
706
|
if (isComputedCallback(value))
|
|
708
|
-
return
|
|
707
|
+
return createComputed(value);
|
|
709
708
|
if (Array.isArray(value) || isRecord(value))
|
|
710
|
-
return
|
|
711
|
-
return
|
|
709
|
+
return createStore(value);
|
|
710
|
+
return createState(value);
|
|
712
711
|
}
|
|
713
712
|
export {
|
|
714
|
-
|
|
713
|
+
valueString,
|
|
715
714
|
toSignal,
|
|
716
715
|
toError,
|
|
717
716
|
subscribe,
|
|
718
|
-
store,
|
|
719
|
-
state,
|
|
720
717
|
resolve,
|
|
721
718
|
observe,
|
|
722
719
|
notify,
|
|
@@ -728,6 +725,7 @@ export {
|
|
|
728
725
|
isSignal,
|
|
729
726
|
isRecordOrArray,
|
|
730
727
|
isRecord,
|
|
728
|
+
isObjectOfType,
|
|
731
729
|
isNumber,
|
|
732
730
|
isMutableSignal,
|
|
733
731
|
isFunction,
|
|
@@ -737,10 +735,12 @@ export {
|
|
|
737
735
|
isAsyncFunction,
|
|
738
736
|
isAbortError,
|
|
739
737
|
flush,
|
|
740
|
-
enqueue,
|
|
741
|
-
effect,
|
|
742
738
|
diff,
|
|
743
|
-
|
|
739
|
+
createWatcher,
|
|
740
|
+
createStore,
|
|
741
|
+
createState,
|
|
742
|
+
createEffect,
|
|
743
|
+
createComputed,
|
|
744
744
|
batch,
|
|
745
745
|
UNSET,
|
|
746
746
|
TYPE_STORE,
|
|
@@ -751,5 +751,6 @@ export {
|
|
|
751
751
|
StoreKeyExistsError,
|
|
752
752
|
NullishSignalValueError,
|
|
753
753
|
InvalidSignalValueError,
|
|
754
|
+
InvalidCallbackError,
|
|
754
755
|
CircularDependencyError
|
|
755
756
|
};
|