@zeix/cause-effect 0.15.1 → 0.16.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 +254 -0
- package/.cursorrules +54 -0
- package/.github/copilot-instructions.md +132 -0
- package/CLAUDE.md +319 -0
- package/README.md +167 -159
- package/eslint.config.js +1 -1
- package/index.dev.js +528 -407
- package/index.js +1 -1
- package/index.ts +36 -25
- package/package.json +1 -1
- package/src/computed.ts +41 -30
- package/src/diff.ts +57 -44
- package/src/effect.ts +15 -16
- package/src/errors.ts +64 -0
- package/src/match.ts +2 -2
- package/src/resolve.ts +2 -2
- package/src/signal.ts +27 -49
- package/src/state.ts +27 -19
- package/src/store.ts +410 -209
- package/src/system.ts +122 -0
- package/src/util.ts +45 -6
- package/test/batch.test.ts +18 -11
- package/test/benchmark.test.ts +4 -4
- package/test/computed.test.ts +508 -72
- package/test/diff.test.ts +321 -4
- package/test/effect.test.ts +61 -61
- package/test/match.test.ts +38 -28
- package/test/resolve.test.ts +16 -16
- package/test/signal.test.ts +19 -147
- package/test/state.test.ts +212 -25
- package/test/store.test.ts +1370 -134
- package/test/util/dependency-graph.ts +1 -1
- package/types/index.d.ts +10 -9
- package/types/src/collection.d.ts +26 -0
- package/types/src/computed.d.ts +9 -9
- package/types/src/diff.d.ts +5 -3
- package/types/src/effect.d.ts +3 -3
- package/types/src/errors.d.ts +22 -0
- package/types/src/match.d.ts +1 -1
- package/types/src/resolve.d.ts +1 -1
- package/types/src/signal.d.ts +12 -19
- package/types/src/state.d.ts +5 -5
- package/types/src/store.d.ts +40 -36
- package/types/src/system.d.ts +44 -0
- package/types/src/util.d.ts +7 -5
- package/index.d.ts +0 -36
- package/src/scheduler.ts +0 -172
- package/types/test-new-effect.d.ts +0 -1
package/index.dev.js
CHANGED
|
@@ -1,380 +1,82 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
var requestId;
|
|
7
|
-
var updateDOM = () => {
|
|
8
|
-
requestId = undefined;
|
|
9
|
-
const updates = Array.from(updateMap.values());
|
|
10
|
-
updateMap.clear();
|
|
11
|
-
for (const update of updates) {
|
|
12
|
-
update();
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
class CircularDependencyError extends Error {
|
|
3
|
+
constructor(where) {
|
|
4
|
+
super(`Circular dependency detected in ${where}`);
|
|
5
|
+
this.name = "CircularDependencyError";
|
|
13
6
|
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
queueMicrotask(updateDOM);
|
|
21
|
-
var watch = (notice) => {
|
|
22
|
-
const cleanups = new Set;
|
|
23
|
-
const w = notice;
|
|
24
|
-
w.off = (on) => {
|
|
25
|
-
cleanups.add(on);
|
|
26
|
-
};
|
|
27
|
-
w.cleanup = () => {
|
|
28
|
-
for (const cleanup of cleanups) {
|
|
29
|
-
cleanup();
|
|
30
|
-
}
|
|
31
|
-
cleanups.clear();
|
|
32
|
-
};
|
|
33
|
-
return w;
|
|
34
|
-
};
|
|
35
|
-
var subscribe = (watchers) => {
|
|
36
|
-
if (active && !watchers.has(active)) {
|
|
37
|
-
const watcher = active;
|
|
38
|
-
watchers.add(watcher);
|
|
39
|
-
active.off(() => {
|
|
40
|
-
watchers.delete(watcher);
|
|
41
|
-
});
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
class InvalidCallbackError extends TypeError {
|
|
10
|
+
constructor(where, value) {
|
|
11
|
+
super(`Invalid ${where} callback ${value}`);
|
|
12
|
+
this.name = "InvalidCallbackError";
|
|
42
13
|
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
watcher();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class InvalidSignalValueError extends TypeError {
|
|
17
|
+
constructor(where, value) {
|
|
18
|
+
super(`Invalid signal value ${value} in ${where}`);
|
|
19
|
+
this.name = "InvalidSignalValueError";
|
|
50
20
|
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
watcher();
|
|
58
|
-
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class NullishSignalValueError extends TypeError {
|
|
24
|
+
constructor(where) {
|
|
25
|
+
super(`Nullish signal values are not allowed in ${where}`);
|
|
26
|
+
this.name = "NullishSignalValueError";
|
|
59
27
|
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
flush();
|
|
67
|
-
batchDepth--;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class StoreKeyExistsError extends Error {
|
|
31
|
+
constructor(key, value) {
|
|
32
|
+
super(`Could not add store key "${key}" with value ${value} because it already exists`);
|
|
33
|
+
this.name = "StoreKeyExistsError";
|
|
68
34
|
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
} finally {
|
|
76
|
-
active = prev;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class StoreKeyRangeError extends RangeError {
|
|
38
|
+
constructor(index) {
|
|
39
|
+
super(`Could not remove store index ${String(index)} because it is out of range`);
|
|
40
|
+
this.name = "StoreKeyRangeError";
|
|
77
41
|
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
});
|
|
87
|
-
requestTick();
|
|
88
|
-
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class StoreKeyReadonlyError extends Error {
|
|
45
|
+
constructor(key, value) {
|
|
46
|
+
super(`Could not set store key "${key}" to ${value} because it is readonly`);
|
|
47
|
+
this.name = "StoreKeyReadonlyError";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
89
50
|
|
|
90
51
|
// src/util.ts
|
|
52
|
+
var UNSET = Symbol();
|
|
91
53
|
var isString = (value) => typeof value === "string";
|
|
92
54
|
var isNumber = (value) => typeof value === "number";
|
|
55
|
+
var isSymbol = (value) => typeof value === "symbol";
|
|
93
56
|
var isFunction = (fn) => typeof fn === "function";
|
|
94
57
|
var isAsyncFunction = (fn) => isFunction(fn) && fn.constructor.name === "AsyncFunction";
|
|
95
58
|
var isObjectOfType = (value, type) => Object.prototype.toString.call(value) === `[object ${type}]`;
|
|
96
59
|
var isRecord = (value) => isObjectOfType(value, "Object");
|
|
60
|
+
var isRecordOrArray = (value) => isRecord(value) || Array.isArray(value);
|
|
97
61
|
var validArrayIndexes = (keys) => {
|
|
98
62
|
if (!keys.length)
|
|
99
63
|
return null;
|
|
100
64
|
const indexes = keys.map((k) => isString(k) ? parseInt(k, 10) : isNumber(k) ? k : NaN);
|
|
101
65
|
return indexes.every((index) => Number.isFinite(index) && index >= 0) ? indexes.sort((a, b) => a - b) : null;
|
|
102
66
|
};
|
|
103
|
-
var hasMethod = (obj, methodName) => (methodName in obj) && isFunction(obj[methodName]);
|
|
104
67
|
var isAbortError = (error) => error instanceof DOMException && error.name === "AbortError";
|
|
105
68
|
var toError = (reason) => reason instanceof Error ? reason : Error(String(reason));
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
super(`Circular dependency in ${where} detected`);
|
|
110
|
-
this.name = "CircularDependencyError";
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// src/state.ts
|
|
115
|
-
var TYPE_STATE = "State";
|
|
116
|
-
var state = (initialValue) => {
|
|
117
|
-
const watchers = new Set;
|
|
118
|
-
let value = initialValue;
|
|
119
|
-
const s = {
|
|
120
|
-
[Symbol.toStringTag]: TYPE_STATE,
|
|
121
|
-
get: () => {
|
|
122
|
-
subscribe(watchers);
|
|
123
|
-
return value;
|
|
124
|
-
},
|
|
125
|
-
set: (v) => {
|
|
126
|
-
if (isEqual(value, v))
|
|
127
|
-
return;
|
|
128
|
-
value = v;
|
|
129
|
-
notify(watchers);
|
|
130
|
-
if (UNSET === value)
|
|
131
|
-
watchers.clear();
|
|
132
|
-
},
|
|
133
|
-
update: (fn) => {
|
|
134
|
-
s.set(fn(value));
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
return s;
|
|
138
|
-
};
|
|
139
|
-
var isState = (value) => isObjectOfType(value, TYPE_STATE);
|
|
140
|
-
|
|
141
|
-
// src/effect.ts
|
|
142
|
-
var effect = (callback) => {
|
|
143
|
-
const isAsync = isAsyncFunction(callback);
|
|
144
|
-
let running = false;
|
|
145
|
-
let controller;
|
|
146
|
-
const run = watch(() => observe(() => {
|
|
147
|
-
if (running)
|
|
148
|
-
throw new CircularDependencyError("effect");
|
|
149
|
-
running = true;
|
|
150
|
-
controller?.abort();
|
|
151
|
-
controller = undefined;
|
|
152
|
-
let cleanup;
|
|
153
|
-
try {
|
|
154
|
-
if (isAsync) {
|
|
155
|
-
controller = new AbortController;
|
|
156
|
-
const currentController = controller;
|
|
157
|
-
callback(controller.signal).then((cleanup2) => {
|
|
158
|
-
if (isFunction(cleanup2) && controller === currentController)
|
|
159
|
-
run.off(cleanup2);
|
|
160
|
-
}).catch((error) => {
|
|
161
|
-
if (!isAbortError(error))
|
|
162
|
-
console.error("Async effect error:", error);
|
|
163
|
-
});
|
|
164
|
-
} else {
|
|
165
|
-
cleanup = callback();
|
|
166
|
-
if (isFunction(cleanup))
|
|
167
|
-
run.off(cleanup);
|
|
168
|
-
}
|
|
169
|
-
} catch (error) {
|
|
170
|
-
if (!isAbortError(error))
|
|
171
|
-
console.error("Effect callback error:", error);
|
|
172
|
-
}
|
|
173
|
-
running = false;
|
|
174
|
-
}, run));
|
|
175
|
-
run();
|
|
176
|
-
return () => {
|
|
177
|
-
controller?.abort();
|
|
178
|
-
run.cleanup();
|
|
179
|
-
};
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
// src/store.ts
|
|
183
|
-
var TYPE_STORE = "Store";
|
|
184
|
-
var store = (initialValue) => {
|
|
185
|
-
const watchers = new Set;
|
|
186
|
-
const eventTarget = new EventTarget;
|
|
187
|
-
const signals = new Map;
|
|
188
|
-
const cleanups = new Map;
|
|
189
|
-
const size = state(0);
|
|
190
|
-
const current = () => {
|
|
191
|
-
const keys = Array.from(signals.keys());
|
|
192
|
-
const arrayIndexes = validArrayIndexes(keys);
|
|
193
|
-
if (arrayIndexes)
|
|
194
|
-
return arrayIndexes.map((index) => signals.get(String(index))?.get());
|
|
195
|
-
const record = {};
|
|
196
|
-
for (const [key, signal] of signals) {
|
|
197
|
-
record[key] = signal.get();
|
|
198
|
-
}
|
|
69
|
+
var recordToArray = (record) => {
|
|
70
|
+
const indexes = validArrayIndexes(Object.keys(record));
|
|
71
|
+
if (indexes === null)
|
|
199
72
|
return record;
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
signals.set(stringKey, signal);
|
|
206
|
-
const cleanup = effect(() => {
|
|
207
|
-
const currentValue = signal.get();
|
|
208
|
-
if (currentValue != null)
|
|
209
|
-
emit("store-change", { [key]: currentValue });
|
|
210
|
-
});
|
|
211
|
-
cleanups.set(stringKey, cleanup);
|
|
212
|
-
};
|
|
213
|
-
const removeProperty = (key) => {
|
|
214
|
-
const stringKey = String(key);
|
|
215
|
-
signals.delete(stringKey);
|
|
216
|
-
const cleanup = cleanups.get(stringKey);
|
|
217
|
-
if (cleanup)
|
|
218
|
-
cleanup();
|
|
219
|
-
cleanups.delete(stringKey);
|
|
220
|
-
};
|
|
221
|
-
const reconcile = (oldValue, newValue) => {
|
|
222
|
-
const changes = diff(oldValue, newValue);
|
|
223
|
-
batch(() => {
|
|
224
|
-
if (Object.keys(changes.add).length) {
|
|
225
|
-
for (const key in changes.add) {
|
|
226
|
-
const value = changes.add[key];
|
|
227
|
-
if (value != null)
|
|
228
|
-
addProperty(key, value);
|
|
229
|
-
}
|
|
230
|
-
emit("store-add", changes.add);
|
|
231
|
-
}
|
|
232
|
-
if (Object.keys(changes.change).length) {
|
|
233
|
-
for (const key in changes.change) {
|
|
234
|
-
const signal = signals.get(key);
|
|
235
|
-
const value = changes.change[key];
|
|
236
|
-
if (signal && value != null && hasMethod(signal, "set"))
|
|
237
|
-
signal.set(value);
|
|
238
|
-
}
|
|
239
|
-
emit("store-change", changes.change);
|
|
240
|
-
}
|
|
241
|
-
if (Object.keys(changes.remove).length) {
|
|
242
|
-
for (const key in changes.remove) {
|
|
243
|
-
removeProperty(key);
|
|
244
|
-
}
|
|
245
|
-
emit("store-remove", changes.remove);
|
|
246
|
-
}
|
|
247
|
-
size.set(signals.size);
|
|
248
|
-
});
|
|
249
|
-
return changes.changed;
|
|
250
|
-
};
|
|
251
|
-
reconcile({}, initialValue);
|
|
252
|
-
setTimeout(() => {
|
|
253
|
-
const initialAdditionsEvent = new CustomEvent("store-add", {
|
|
254
|
-
detail: initialValue
|
|
255
|
-
});
|
|
256
|
-
eventTarget.dispatchEvent(initialAdditionsEvent);
|
|
257
|
-
}, 0);
|
|
258
|
-
const storeProps = [
|
|
259
|
-
"add",
|
|
260
|
-
"get",
|
|
261
|
-
"remove",
|
|
262
|
-
"set",
|
|
263
|
-
"update",
|
|
264
|
-
"addEventListener",
|
|
265
|
-
"removeEventListener",
|
|
266
|
-
"dispatchEvent",
|
|
267
|
-
"size"
|
|
268
|
-
];
|
|
269
|
-
return new Proxy({}, {
|
|
270
|
-
get(_target, prop) {
|
|
271
|
-
switch (prop) {
|
|
272
|
-
case "add":
|
|
273
|
-
return (k, v) => {
|
|
274
|
-
if (!signals.has(k)) {
|
|
275
|
-
addProperty(k, v);
|
|
276
|
-
notify(watchers);
|
|
277
|
-
emit("store-add", {
|
|
278
|
-
[k]: v
|
|
279
|
-
});
|
|
280
|
-
size.set(signals.size);
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
case "get":
|
|
284
|
-
return () => {
|
|
285
|
-
subscribe(watchers);
|
|
286
|
-
return current();
|
|
287
|
-
};
|
|
288
|
-
case "remove":
|
|
289
|
-
return (k) => {
|
|
290
|
-
if (signals.has(k)) {
|
|
291
|
-
removeProperty(k);
|
|
292
|
-
notify(watchers);
|
|
293
|
-
emit("store-remove", { [k]: UNSET });
|
|
294
|
-
size.set(signals.size);
|
|
295
|
-
}
|
|
296
|
-
};
|
|
297
|
-
case "set":
|
|
298
|
-
return (v) => {
|
|
299
|
-
if (reconcile(current(), v)) {
|
|
300
|
-
notify(watchers);
|
|
301
|
-
if (UNSET === v)
|
|
302
|
-
watchers.clear();
|
|
303
|
-
}
|
|
304
|
-
};
|
|
305
|
-
case "update":
|
|
306
|
-
return (fn) => {
|
|
307
|
-
const oldValue = current();
|
|
308
|
-
const newValue = fn(oldValue);
|
|
309
|
-
if (reconcile(oldValue, newValue)) {
|
|
310
|
-
notify(watchers);
|
|
311
|
-
if (UNSET === newValue)
|
|
312
|
-
watchers.clear();
|
|
313
|
-
}
|
|
314
|
-
};
|
|
315
|
-
case "addEventListener":
|
|
316
|
-
return eventTarget.addEventListener.bind(eventTarget);
|
|
317
|
-
case "removeEventListener":
|
|
318
|
-
return eventTarget.removeEventListener.bind(eventTarget);
|
|
319
|
-
case "dispatchEvent":
|
|
320
|
-
return eventTarget.dispatchEvent.bind(eventTarget);
|
|
321
|
-
case "size":
|
|
322
|
-
return size;
|
|
323
|
-
}
|
|
324
|
-
if (prop === Symbol.toStringTag)
|
|
325
|
-
return TYPE_STORE;
|
|
326
|
-
if (prop === Symbol.iterator) {
|
|
327
|
-
return function* () {
|
|
328
|
-
for (const [key, signal] of signals) {
|
|
329
|
-
yield [key, signal];
|
|
330
|
-
}
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
return signals.get(String(prop));
|
|
334
|
-
},
|
|
335
|
-
has(_target, prop) {
|
|
336
|
-
const key = String(prop);
|
|
337
|
-
return signals.has(key) || storeProps.includes(key) || prop === Symbol.toStringTag || prop === Symbol.iterator;
|
|
338
|
-
},
|
|
339
|
-
ownKeys() {
|
|
340
|
-
return Array.from(signals.keys()).map((key) => String(key));
|
|
341
|
-
},
|
|
342
|
-
getOwnPropertyDescriptor(_target, prop) {
|
|
343
|
-
const signal = signals.get(String(prop));
|
|
344
|
-
return signal ? {
|
|
345
|
-
enumerable: true,
|
|
346
|
-
configurable: true,
|
|
347
|
-
writable: true,
|
|
348
|
-
value: signal
|
|
349
|
-
} : undefined;
|
|
350
|
-
}
|
|
351
|
-
});
|
|
73
|
+
const array = [];
|
|
74
|
+
for (const index of indexes) {
|
|
75
|
+
array.push(record[String(index)]);
|
|
76
|
+
}
|
|
77
|
+
return array;
|
|
352
78
|
};
|
|
353
|
-
var
|
|
354
|
-
|
|
355
|
-
// src/signal.ts
|
|
356
|
-
var UNSET = Symbol();
|
|
357
|
-
var isSignal = (value) => isState(value) || isComputed(value) || isStore(value);
|
|
358
|
-
function toSignal(value) {
|
|
359
|
-
if (isSignal(value))
|
|
360
|
-
return value;
|
|
361
|
-
if (isComputedCallback(value))
|
|
362
|
-
return computed(value);
|
|
363
|
-
if (Array.isArray(value))
|
|
364
|
-
return store(value);
|
|
365
|
-
if (Array.isArray(value) || isRecord(value))
|
|
366
|
-
return store(value);
|
|
367
|
-
return state(value);
|
|
368
|
-
}
|
|
369
|
-
function toMutableSignal(value) {
|
|
370
|
-
if (isState(value) || isStore(value))
|
|
371
|
-
return value;
|
|
372
|
-
if (Array.isArray(value))
|
|
373
|
-
return store(value);
|
|
374
|
-
if (isRecord(value))
|
|
375
|
-
return store(value);
|
|
376
|
-
return state(value);
|
|
377
|
-
}
|
|
79
|
+
var valueString = (value) => isString(value) ? `"${value}"` : !!value && typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
378
80
|
|
|
379
81
|
// src/diff.ts
|
|
380
82
|
var isEqual = (a, b, visited) => {
|
|
@@ -422,45 +124,118 @@ var isEqual = (a, b, visited) => {
|
|
|
422
124
|
}
|
|
423
125
|
};
|
|
424
126
|
var diff = (oldObj, newObj) => {
|
|
425
|
-
const
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
const
|
|
429
|
-
const remove = {};
|
|
430
|
-
const oldKeys = Object.keys(oldRecord);
|
|
431
|
-
const newKeys = Object.keys(newRecord);
|
|
432
|
-
const allKeys = new Set([...oldKeys, ...newKeys]);
|
|
433
|
-
for (const key of allKeys) {
|
|
434
|
-
const oldHas = key in oldRecord;
|
|
435
|
-
const newHas = key in newRecord;
|
|
436
|
-
if (!oldHas && newHas) {
|
|
437
|
-
add[key] = newRecord[key];
|
|
438
|
-
continue;
|
|
439
|
-
} else if (oldHas && !newHas) {
|
|
440
|
-
remove[key] = UNSET;
|
|
441
|
-
continue;
|
|
442
|
-
}
|
|
443
|
-
const oldValue = oldRecord[key];
|
|
444
|
-
const newValue = newRecord[key];
|
|
445
|
-
if (!isEqual(oldValue, newValue, visited))
|
|
446
|
-
change[key] = newValue;
|
|
447
|
-
}
|
|
448
|
-
const changed = Object.keys(add).length > 0 || Object.keys(change).length > 0 || Object.keys(remove).length > 0;
|
|
127
|
+
const oldValid = isRecordOrArray(oldObj);
|
|
128
|
+
const newValid = isRecordOrArray(newObj);
|
|
129
|
+
if (!oldValid || !newValid) {
|
|
130
|
+
const changed2 = !Object.is(oldObj, newObj);
|
|
449
131
|
return {
|
|
450
|
-
changed,
|
|
451
|
-
add,
|
|
452
|
-
change,
|
|
453
|
-
remove
|
|
132
|
+
changed: changed2,
|
|
133
|
+
add: changed2 && newValid ? newObj : {},
|
|
134
|
+
change: {},
|
|
135
|
+
remove: changed2 && oldValid ? oldObj : {}
|
|
454
136
|
};
|
|
137
|
+
}
|
|
138
|
+
const visited = new WeakSet;
|
|
139
|
+
const add = {};
|
|
140
|
+
const change = {};
|
|
141
|
+
const remove = {};
|
|
142
|
+
const oldKeys = Object.keys(oldObj);
|
|
143
|
+
const newKeys = Object.keys(newObj);
|
|
144
|
+
const allKeys = new Set([...oldKeys, ...newKeys]);
|
|
145
|
+
for (const key of allKeys) {
|
|
146
|
+
const oldHas = key in oldObj;
|
|
147
|
+
const newHas = key in newObj;
|
|
148
|
+
if (!oldHas && newHas) {
|
|
149
|
+
add[key] = newObj[key];
|
|
150
|
+
continue;
|
|
151
|
+
} else if (oldHas && !newHas) {
|
|
152
|
+
remove[key] = UNSET;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const oldValue = oldObj[key];
|
|
156
|
+
const newValue = newObj[key];
|
|
157
|
+
if (!isEqual(oldValue, newValue, visited))
|
|
158
|
+
change[key] = newValue;
|
|
159
|
+
}
|
|
160
|
+
const changed = Object.keys(add).length > 0 || Object.keys(change).length > 0 || Object.keys(remove).length > 0;
|
|
161
|
+
return {
|
|
162
|
+
changed,
|
|
163
|
+
add,
|
|
164
|
+
change,
|
|
165
|
+
remove
|
|
455
166
|
};
|
|
456
|
-
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// src/system.ts
|
|
170
|
+
var activeWatcher;
|
|
171
|
+
var pendingWatchers = new Set;
|
|
172
|
+
var batchDepth = 0;
|
|
173
|
+
var createWatcher = (watch) => {
|
|
174
|
+
const cleanups = new Set;
|
|
175
|
+
const w = watch;
|
|
176
|
+
w.unwatch = (cleanup) => {
|
|
177
|
+
cleanups.add(cleanup);
|
|
178
|
+
};
|
|
179
|
+
w.cleanup = () => {
|
|
180
|
+
for (const cleanup of cleanups)
|
|
181
|
+
cleanup();
|
|
182
|
+
cleanups.clear();
|
|
183
|
+
};
|
|
184
|
+
return w;
|
|
185
|
+
};
|
|
186
|
+
var subscribe = (watchers) => {
|
|
187
|
+
if (activeWatcher && !watchers.has(activeWatcher)) {
|
|
188
|
+
const watcher = activeWatcher;
|
|
189
|
+
watcher.unwatch(() => {
|
|
190
|
+
watchers.delete(watcher);
|
|
191
|
+
});
|
|
192
|
+
watchers.add(watcher);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
var notify = (watchers) => {
|
|
196
|
+
for (const watcher of watchers) {
|
|
197
|
+
if (batchDepth)
|
|
198
|
+
pendingWatchers.add(watcher);
|
|
199
|
+
else
|
|
200
|
+
watcher();
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
var flush = () => {
|
|
204
|
+
while (pendingWatchers.size) {
|
|
205
|
+
const watchers = Array.from(pendingWatchers);
|
|
206
|
+
pendingWatchers.clear();
|
|
207
|
+
for (const watcher of watchers)
|
|
208
|
+
watcher();
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
var batch = (fn) => {
|
|
212
|
+
batchDepth++;
|
|
213
|
+
try {
|
|
214
|
+
fn();
|
|
215
|
+
} finally {
|
|
216
|
+
flush();
|
|
217
|
+
batchDepth--;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
var observe = (run, watcher) => {
|
|
221
|
+
const prev = activeWatcher;
|
|
222
|
+
activeWatcher = watcher;
|
|
223
|
+
try {
|
|
224
|
+
run();
|
|
225
|
+
} finally {
|
|
226
|
+
activeWatcher = prev;
|
|
227
|
+
}
|
|
457
228
|
};
|
|
458
229
|
|
|
459
230
|
// src/computed.ts
|
|
460
231
|
var TYPE_COMPUTED = "Computed";
|
|
461
|
-
var
|
|
232
|
+
var createComputed = (callback, initialValue = UNSET) => {
|
|
233
|
+
if (!isComputedCallback(callback))
|
|
234
|
+
throw new InvalidCallbackError("computed", valueString(callback));
|
|
235
|
+
if (initialValue == null)
|
|
236
|
+
throw new NullishSignalValueError("computed");
|
|
462
237
|
const watchers = new Set;
|
|
463
|
-
let value =
|
|
238
|
+
let value = initialValue;
|
|
464
239
|
let error;
|
|
465
240
|
let controller;
|
|
466
241
|
let dirty = true;
|
|
@@ -485,29 +260,29 @@ var computed = (fn) => {
|
|
|
485
260
|
value = UNSET;
|
|
486
261
|
error = newError;
|
|
487
262
|
};
|
|
488
|
-
const settle = (
|
|
263
|
+
const settle = (fn) => (arg) => {
|
|
489
264
|
computing = false;
|
|
490
265
|
controller = undefined;
|
|
491
|
-
|
|
266
|
+
fn(arg);
|
|
492
267
|
if (changed)
|
|
493
268
|
notify(watchers);
|
|
494
269
|
};
|
|
495
|
-
const
|
|
270
|
+
const watcher = createWatcher(() => {
|
|
496
271
|
dirty = true;
|
|
497
272
|
controller?.abort();
|
|
498
273
|
if (watchers.size)
|
|
499
274
|
notify(watchers);
|
|
500
275
|
else
|
|
501
|
-
|
|
276
|
+
watcher.cleanup();
|
|
502
277
|
});
|
|
503
|
-
|
|
278
|
+
watcher.unwatch(() => {
|
|
504
279
|
controller?.abort();
|
|
505
280
|
});
|
|
506
281
|
const compute = () => observe(() => {
|
|
507
282
|
if (computing)
|
|
508
283
|
throw new CircularDependencyError("computed");
|
|
509
284
|
changed = false;
|
|
510
|
-
if (isAsyncFunction(
|
|
285
|
+
if (isAsyncFunction(callback)) {
|
|
511
286
|
if (controller)
|
|
512
287
|
return value;
|
|
513
288
|
controller = new AbortController;
|
|
@@ -522,7 +297,7 @@ var computed = (fn) => {
|
|
|
522
297
|
let result;
|
|
523
298
|
computing = true;
|
|
524
299
|
try {
|
|
525
|
-
result = controller ?
|
|
300
|
+
result = controller ? callback(value, controller.signal) : callback(value);
|
|
526
301
|
} catch (e) {
|
|
527
302
|
if (isAbortError(e))
|
|
528
303
|
nil();
|
|
@@ -538,8 +313,8 @@ var computed = (fn) => {
|
|
|
538
313
|
else
|
|
539
314
|
ok(result);
|
|
540
315
|
computing = false;
|
|
541
|
-
},
|
|
542
|
-
|
|
316
|
+
}, watcher);
|
|
317
|
+
return {
|
|
543
318
|
[Symbol.toStringTag]: TYPE_COMPUTED,
|
|
544
319
|
get: () => {
|
|
545
320
|
subscribe(watchers);
|
|
@@ -551,10 +326,51 @@ var computed = (fn) => {
|
|
|
551
326
|
return value;
|
|
552
327
|
}
|
|
553
328
|
};
|
|
554
|
-
return c;
|
|
555
329
|
};
|
|
556
330
|
var isComputed = (value) => isObjectOfType(value, TYPE_COMPUTED);
|
|
557
|
-
var isComputedCallback = (value) => isFunction(value) && value.length <
|
|
331
|
+
var isComputedCallback = (value) => isFunction(value) && value.length < 3;
|
|
332
|
+
// src/effect.ts
|
|
333
|
+
var createEffect = (callback) => {
|
|
334
|
+
if (!isFunction(callback) || callback.length > 1)
|
|
335
|
+
throw new InvalidCallbackError("effect", valueString(callback));
|
|
336
|
+
const isAsync = isAsyncFunction(callback);
|
|
337
|
+
let running = false;
|
|
338
|
+
let controller;
|
|
339
|
+
const watcher = createWatcher(() => observe(() => {
|
|
340
|
+
if (running)
|
|
341
|
+
throw new CircularDependencyError("effect");
|
|
342
|
+
running = true;
|
|
343
|
+
controller?.abort();
|
|
344
|
+
controller = undefined;
|
|
345
|
+
let cleanup;
|
|
346
|
+
try {
|
|
347
|
+
if (isAsync) {
|
|
348
|
+
controller = new AbortController;
|
|
349
|
+
const currentController = controller;
|
|
350
|
+
callback(controller.signal).then((cleanup2) => {
|
|
351
|
+
if (isFunction(cleanup2) && controller === currentController)
|
|
352
|
+
watcher.unwatch(cleanup2);
|
|
353
|
+
}).catch((error) => {
|
|
354
|
+
if (!isAbortError(error))
|
|
355
|
+
console.error("Async effect error:", error);
|
|
356
|
+
});
|
|
357
|
+
} else {
|
|
358
|
+
cleanup = callback();
|
|
359
|
+
if (isFunction(cleanup))
|
|
360
|
+
watcher.unwatch(cleanup);
|
|
361
|
+
}
|
|
362
|
+
} catch (error) {
|
|
363
|
+
if (!isAbortError(error))
|
|
364
|
+
console.error("Effect callback error:", error);
|
|
365
|
+
}
|
|
366
|
+
running = false;
|
|
367
|
+
}, watcher));
|
|
368
|
+
watcher();
|
|
369
|
+
return () => {
|
|
370
|
+
controller?.abort();
|
|
371
|
+
watcher.cleanup();
|
|
372
|
+
};
|
|
373
|
+
};
|
|
558
374
|
// src/match.ts
|
|
559
375
|
function match(result, handlers) {
|
|
560
376
|
try {
|
|
@@ -562,8 +378,8 @@ function match(result, handlers) {
|
|
|
562
378
|
handlers.nil?.();
|
|
563
379
|
else if (result.errors)
|
|
564
380
|
handlers.err?.(result.errors);
|
|
565
|
-
else
|
|
566
|
-
handlers.ok
|
|
381
|
+
else if (result.ok)
|
|
382
|
+
handlers.ok(result.values);
|
|
567
383
|
} catch (error) {
|
|
568
384
|
if (handlers.err && (!result.errors || !result.errors.includes(toError(error))))
|
|
569
385
|
handlers.err(result.errors ? [...result.errors, toError(error)] : [toError(error)]);
|
|
@@ -574,42 +390,339 @@ function match(result, handlers) {
|
|
|
574
390
|
// src/resolve.ts
|
|
575
391
|
function resolve(signals) {
|
|
576
392
|
const errors = [];
|
|
577
|
-
let
|
|
393
|
+
let pending = false;
|
|
578
394
|
const values = {};
|
|
579
395
|
for (const [key, signal] of Object.entries(signals)) {
|
|
580
396
|
try {
|
|
581
397
|
const value = signal.get();
|
|
582
398
|
if (value === UNSET)
|
|
583
|
-
|
|
399
|
+
pending = true;
|
|
584
400
|
else
|
|
585
401
|
values[key] = value;
|
|
586
402
|
} catch (e) {
|
|
587
403
|
errors.push(toError(e));
|
|
588
404
|
}
|
|
589
405
|
}
|
|
590
|
-
if (
|
|
406
|
+
if (pending)
|
|
591
407
|
return { ok: false, pending: true };
|
|
592
408
|
if (errors.length > 0)
|
|
593
409
|
return { ok: false, errors };
|
|
594
410
|
return { ok: true, values };
|
|
595
411
|
}
|
|
412
|
+
// src/state.ts
|
|
413
|
+
var TYPE_STATE = "State";
|
|
414
|
+
var createState = (initialValue) => {
|
|
415
|
+
if (initialValue == null)
|
|
416
|
+
throw new NullishSignalValueError("state");
|
|
417
|
+
const watchers = new Set;
|
|
418
|
+
let value = initialValue;
|
|
419
|
+
const state = {
|
|
420
|
+
[Symbol.toStringTag]: TYPE_STATE,
|
|
421
|
+
get: () => {
|
|
422
|
+
subscribe(watchers);
|
|
423
|
+
return value;
|
|
424
|
+
},
|
|
425
|
+
set: (newValue) => {
|
|
426
|
+
if (newValue == null)
|
|
427
|
+
throw new NullishSignalValueError("state");
|
|
428
|
+
if (isEqual(value, newValue))
|
|
429
|
+
return;
|
|
430
|
+
value = newValue;
|
|
431
|
+
notify(watchers);
|
|
432
|
+
if (UNSET === value)
|
|
433
|
+
watchers.clear();
|
|
434
|
+
},
|
|
435
|
+
update: (updater) => {
|
|
436
|
+
if (!isFunction(updater))
|
|
437
|
+
throw new InvalidCallbackError("state update", valueString(updater));
|
|
438
|
+
state.set(updater(value));
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
return state;
|
|
442
|
+
};
|
|
443
|
+
var isState = (value) => isObjectOfType(value, TYPE_STATE);
|
|
444
|
+
|
|
445
|
+
// src/store.ts
|
|
446
|
+
var TYPE_STORE = "Store";
|
|
447
|
+
var createStore = (initialValue) => {
|
|
448
|
+
if (initialValue == null)
|
|
449
|
+
throw new NullishSignalValueError("store");
|
|
450
|
+
const watchers = new Set;
|
|
451
|
+
const listeners = {
|
|
452
|
+
add: new Set,
|
|
453
|
+
change: new Set,
|
|
454
|
+
remove: new Set,
|
|
455
|
+
sort: new Set
|
|
456
|
+
};
|
|
457
|
+
const signals = new Map;
|
|
458
|
+
const signalWatchers = new Map;
|
|
459
|
+
const isArrayLike = Array.isArray(initialValue);
|
|
460
|
+
const size = createState(0);
|
|
461
|
+
const current = () => {
|
|
462
|
+
const record = {};
|
|
463
|
+
for (const [key, signal] of signals) {
|
|
464
|
+
record[key] = signal.get();
|
|
465
|
+
}
|
|
466
|
+
return record;
|
|
467
|
+
};
|
|
468
|
+
const emit = (key, changes) => {
|
|
469
|
+
Object.freeze(changes);
|
|
470
|
+
for (const listener of listeners[key]) {
|
|
471
|
+
listener(changes);
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
const getSortedIndexes = () => Array.from(signals.keys()).map((k) => Number(k)).filter((n) => Number.isInteger(n)).sort((a, b) => a - b);
|
|
475
|
+
const isValidValue = (key, value) => {
|
|
476
|
+
if (value == null)
|
|
477
|
+
throw new NullishSignalValueError(`store for key "${key}"`);
|
|
478
|
+
if (value === UNSET)
|
|
479
|
+
return true;
|
|
480
|
+
if (isSymbol(value) || isFunction(value) || isComputed(value))
|
|
481
|
+
throw new InvalidSignalValueError(`store for key "${key}"`, valueString(value));
|
|
482
|
+
return true;
|
|
483
|
+
};
|
|
484
|
+
const addProperty = (key, value, single = false) => {
|
|
485
|
+
if (!isValidValue(key, value))
|
|
486
|
+
return false;
|
|
487
|
+
const signal = isState(value) || isStore(value) ? value : isRecord(value) || Array.isArray(value) ? createStore(value) : createState(value);
|
|
488
|
+
signals.set(key, signal);
|
|
489
|
+
const watcher = createWatcher(() => observe(() => {
|
|
490
|
+
emit("change", {
|
|
491
|
+
[key]: signal.get()
|
|
492
|
+
});
|
|
493
|
+
}, watcher));
|
|
494
|
+
watcher();
|
|
495
|
+
signalWatchers.set(key, watcher);
|
|
496
|
+
if (single) {
|
|
497
|
+
size.set(signals.size);
|
|
498
|
+
notify(watchers);
|
|
499
|
+
emit("add", {
|
|
500
|
+
[key]: value
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
return true;
|
|
504
|
+
};
|
|
505
|
+
const removeProperty = (key, single = false) => {
|
|
506
|
+
const ok = signals.delete(key);
|
|
507
|
+
if (ok) {
|
|
508
|
+
const watcher = signalWatchers.get(key);
|
|
509
|
+
if (watcher)
|
|
510
|
+
watcher.cleanup();
|
|
511
|
+
signalWatchers.delete(key);
|
|
512
|
+
}
|
|
513
|
+
if (single) {
|
|
514
|
+
size.set(signals.size);
|
|
515
|
+
notify(watchers);
|
|
516
|
+
emit("remove", {
|
|
517
|
+
[key]: UNSET
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
return ok;
|
|
521
|
+
};
|
|
522
|
+
const reconcile = (oldValue, newValue, initialRun) => {
|
|
523
|
+
const changes = diff(oldValue, newValue);
|
|
524
|
+
batch(() => {
|
|
525
|
+
if (Object.keys(changes.add).length) {
|
|
526
|
+
for (const key in changes.add) {
|
|
527
|
+
const value = changes.add[key] ?? UNSET;
|
|
528
|
+
addProperty(key, value);
|
|
529
|
+
}
|
|
530
|
+
if (initialRun) {
|
|
531
|
+
setTimeout(() => {
|
|
532
|
+
emit("add", changes.add);
|
|
533
|
+
}, 0);
|
|
534
|
+
} else {
|
|
535
|
+
emit("add", changes.add);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
if (Object.keys(changes.change).length) {
|
|
539
|
+
for (const key in changes.change) {
|
|
540
|
+
const value = changes.change[key];
|
|
541
|
+
if (!isValidValue(key, value))
|
|
542
|
+
continue;
|
|
543
|
+
const signal = signals.get(key);
|
|
544
|
+
if (isMutableSignal(signal))
|
|
545
|
+
signal.set(value);
|
|
546
|
+
else
|
|
547
|
+
throw new StoreKeyReadonlyError(key, valueString(value));
|
|
548
|
+
}
|
|
549
|
+
emit("change", changes.change);
|
|
550
|
+
}
|
|
551
|
+
if (Object.keys(changes.remove).length) {
|
|
552
|
+
for (const key in changes.remove)
|
|
553
|
+
removeProperty(key);
|
|
554
|
+
emit("remove", changes.remove);
|
|
555
|
+
}
|
|
556
|
+
size.set(signals.size);
|
|
557
|
+
});
|
|
558
|
+
return changes.changed;
|
|
559
|
+
};
|
|
560
|
+
reconcile({}, initialValue, true);
|
|
561
|
+
const store = {
|
|
562
|
+
add: isArrayLike ? (v) => {
|
|
563
|
+
const nextIndex = signals.size;
|
|
564
|
+
const key = String(nextIndex);
|
|
565
|
+
addProperty(key, v, true);
|
|
566
|
+
} : (k, v) => {
|
|
567
|
+
if (!signals.has(k))
|
|
568
|
+
addProperty(k, v, true);
|
|
569
|
+
else
|
|
570
|
+
throw new StoreKeyExistsError(k, valueString(v));
|
|
571
|
+
},
|
|
572
|
+
get: () => {
|
|
573
|
+
subscribe(watchers);
|
|
574
|
+
return recordToArray(current());
|
|
575
|
+
},
|
|
576
|
+
remove: isArrayLike ? (index) => {
|
|
577
|
+
const currentArray = recordToArray(current());
|
|
578
|
+
const currentLength = signals.size;
|
|
579
|
+
if (!Array.isArray(currentArray) || index <= -currentLength || index >= currentLength)
|
|
580
|
+
throw new StoreKeyRangeError(index);
|
|
581
|
+
const newArray = [...currentArray];
|
|
582
|
+
newArray.splice(index, 1);
|
|
583
|
+
if (reconcile(currentArray, newArray))
|
|
584
|
+
notify(watchers);
|
|
585
|
+
} : (k) => {
|
|
586
|
+
if (signals.has(k))
|
|
587
|
+
removeProperty(k, true);
|
|
588
|
+
},
|
|
589
|
+
set: (v) => {
|
|
590
|
+
if (reconcile(current(), v)) {
|
|
591
|
+
notify(watchers);
|
|
592
|
+
if (UNSET === v)
|
|
593
|
+
watchers.clear();
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
update: (fn) => {
|
|
597
|
+
const oldValue = current();
|
|
598
|
+
const newValue = fn(recordToArray(oldValue));
|
|
599
|
+
if (reconcile(oldValue, newValue)) {
|
|
600
|
+
notify(watchers);
|
|
601
|
+
if (UNSET === newValue)
|
|
602
|
+
watchers.clear();
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
sort: (compareFn) => {
|
|
606
|
+
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])));
|
|
607
|
+
const newOrder = entries.map(([key]) => String(key));
|
|
608
|
+
const newSignals = new Map;
|
|
609
|
+
entries.forEach(([key], newIndex) => {
|
|
610
|
+
const oldKey = String(key);
|
|
611
|
+
const newKey = isArrayLike ? String(newIndex) : String(key);
|
|
612
|
+
const signal = signals.get(oldKey);
|
|
613
|
+
if (signal)
|
|
614
|
+
newSignals.set(newKey, signal);
|
|
615
|
+
});
|
|
616
|
+
signals.clear();
|
|
617
|
+
newSignals.forEach((signal, key) => signals.set(key, signal));
|
|
618
|
+
notify(watchers);
|
|
619
|
+
emit("sort", newOrder);
|
|
620
|
+
},
|
|
621
|
+
on: (type, listener) => {
|
|
622
|
+
listeners[type].add(listener);
|
|
623
|
+
return () => listeners[type].delete(listener);
|
|
624
|
+
},
|
|
625
|
+
size
|
|
626
|
+
};
|
|
627
|
+
return new Proxy({}, {
|
|
628
|
+
get(_target, prop) {
|
|
629
|
+
if (prop === Symbol.toStringTag)
|
|
630
|
+
return TYPE_STORE;
|
|
631
|
+
if (prop === Symbol.isConcatSpreadable)
|
|
632
|
+
return isArrayLike;
|
|
633
|
+
if (prop === Symbol.iterator)
|
|
634
|
+
return isArrayLike ? function* () {
|
|
635
|
+
const indexes = getSortedIndexes();
|
|
636
|
+
for (const index of indexes) {
|
|
637
|
+
const signal = signals.get(String(index));
|
|
638
|
+
if (signal)
|
|
639
|
+
yield signal;
|
|
640
|
+
}
|
|
641
|
+
} : function* () {
|
|
642
|
+
for (const [key, signal] of signals)
|
|
643
|
+
yield [key, signal];
|
|
644
|
+
};
|
|
645
|
+
if (isSymbol(prop))
|
|
646
|
+
return;
|
|
647
|
+
if (prop in store)
|
|
648
|
+
return store[prop];
|
|
649
|
+
if (prop === "length" && isArrayLike) {
|
|
650
|
+
subscribe(watchers);
|
|
651
|
+
return size.get();
|
|
652
|
+
}
|
|
653
|
+
return signals.get(prop);
|
|
654
|
+
},
|
|
655
|
+
has(_target, prop) {
|
|
656
|
+
const stringProp = String(prop);
|
|
657
|
+
return stringProp && signals.has(stringProp) || Object.keys(store).includes(stringProp) || prop === Symbol.toStringTag || prop === Symbol.iterator || prop === Symbol.isConcatSpreadable || prop === "length" && isArrayLike;
|
|
658
|
+
},
|
|
659
|
+
ownKeys() {
|
|
660
|
+
return isArrayLike ? getSortedIndexes().map((key) => String(key)).concat(["length"]) : Array.from(signals.keys()).map((key) => String(key));
|
|
661
|
+
},
|
|
662
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
663
|
+
const nonEnumerable = (value) => ({
|
|
664
|
+
enumerable: false,
|
|
665
|
+
configurable: true,
|
|
666
|
+
writable: false,
|
|
667
|
+
value
|
|
668
|
+
});
|
|
669
|
+
if (prop === "length" && isArrayLike)
|
|
670
|
+
return {
|
|
671
|
+
enumerable: true,
|
|
672
|
+
configurable: true,
|
|
673
|
+
writable: false,
|
|
674
|
+
value: size.get()
|
|
675
|
+
};
|
|
676
|
+
if (prop === Symbol.isConcatSpreadable)
|
|
677
|
+
return nonEnumerable(isArrayLike);
|
|
678
|
+
if (prop === Symbol.toStringTag)
|
|
679
|
+
return nonEnumerable(TYPE_STORE);
|
|
680
|
+
if (isSymbol(prop))
|
|
681
|
+
return;
|
|
682
|
+
if (Object.keys(store).includes(prop))
|
|
683
|
+
return nonEnumerable(store[prop]);
|
|
684
|
+
const signal = signals.get(prop);
|
|
685
|
+
return signal ? {
|
|
686
|
+
enumerable: true,
|
|
687
|
+
configurable: true,
|
|
688
|
+
writable: true,
|
|
689
|
+
value: signal
|
|
690
|
+
} : undefined;
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
};
|
|
694
|
+
var isStore = (value) => isObjectOfType(value, TYPE_STORE);
|
|
695
|
+
|
|
696
|
+
// src/signal.ts
|
|
697
|
+
var isSignal = (value) => isState(value) || isComputed(value) || isStore(value);
|
|
698
|
+
var isMutableSignal = (value) => isState(value) || isStore(value);
|
|
699
|
+
function toSignal(value) {
|
|
700
|
+
if (isSignal(value))
|
|
701
|
+
return value;
|
|
702
|
+
if (isComputedCallback(value))
|
|
703
|
+
return createComputed(value);
|
|
704
|
+
if (Array.isArray(value) || isRecord(value))
|
|
705
|
+
return createStore(value);
|
|
706
|
+
return createState(value);
|
|
707
|
+
}
|
|
596
708
|
export {
|
|
597
|
-
|
|
709
|
+
valueString,
|
|
598
710
|
toSignal,
|
|
599
|
-
toMutableSignal,
|
|
600
711
|
toError,
|
|
601
712
|
subscribe,
|
|
602
|
-
store,
|
|
603
|
-
state,
|
|
604
713
|
resolve,
|
|
605
714
|
observe,
|
|
606
715
|
notify,
|
|
607
716
|
match,
|
|
717
|
+
isSymbol,
|
|
608
718
|
isString,
|
|
609
719
|
isStore,
|
|
610
720
|
isState,
|
|
611
721
|
isSignal,
|
|
722
|
+
isRecordOrArray,
|
|
723
|
+
isRecord,
|
|
612
724
|
isNumber,
|
|
725
|
+
isMutableSignal,
|
|
613
726
|
isFunction,
|
|
614
727
|
isEqual,
|
|
615
728
|
isComputedCallback,
|
|
@@ -617,14 +730,22 @@ export {
|
|
|
617
730
|
isAsyncFunction,
|
|
618
731
|
isAbortError,
|
|
619
732
|
flush,
|
|
620
|
-
enqueue,
|
|
621
|
-
effect,
|
|
622
733
|
diff,
|
|
623
|
-
|
|
734
|
+
createWatcher,
|
|
735
|
+
createStore,
|
|
736
|
+
createState,
|
|
737
|
+
createEffect,
|
|
738
|
+
createComputed,
|
|
624
739
|
batch,
|
|
625
740
|
UNSET,
|
|
626
741
|
TYPE_STORE,
|
|
627
742
|
TYPE_STATE,
|
|
628
743
|
TYPE_COMPUTED,
|
|
744
|
+
StoreKeyReadonlyError,
|
|
745
|
+
StoreKeyRangeError,
|
|
746
|
+
StoreKeyExistsError,
|
|
747
|
+
NullishSignalValueError,
|
|
748
|
+
InvalidSignalValueError,
|
|
749
|
+
InvalidCallbackError,
|
|
629
750
|
CircularDependencyError
|
|
630
751
|
};
|