@legendapp/state 2.1.2 → 2.2.0-next.10
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/config/enableDirectAccess.d.ts +1 -1
- package/config/enableDirectPeek.d.ts +1 -1
- package/config/enableReactTracking.d.ts +4 -3
- package/config/enableReactTracking.js.map +1 -1
- package/config/enableReactTracking.mjs.map +1 -1
- package/config/enableReactUse.d.ts +1 -1
- package/helpers/fetch.d.ts +4 -3
- package/helpers/fetch.js.map +1 -1
- package/helpers/fetch.mjs.map +1 -1
- package/helpers/time.d.ts +2 -2
- package/history.js +1 -1
- package/history.js.map +1 -1
- package/history.mjs +1 -1
- package/history.mjs.map +1 -1
- package/index.d.ts +16 -8
- package/index.js +834 -492
- package/index.js.map +1 -1
- package/index.mjs +834 -493
- package/index.mjs.map +1 -1
- package/package.json +2 -10
- package/persist-plugins/async-storage.js +3 -4
- package/persist-plugins/async-storage.js.map +1 -1
- package/persist-plugins/async-storage.mjs +4 -5
- package/persist-plugins/async-storage.mjs.map +1 -1
- package/persist-plugins/firebase.js +9 -6
- package/persist-plugins/firebase.js.map +1 -1
- package/persist-plugins/firebase.mjs +10 -7
- package/persist-plugins/firebase.mjs.map +1 -1
- package/persist-plugins/local-storage.js +2 -3
- package/persist-plugins/local-storage.js.map +1 -1
- package/persist-plugins/local-storage.mjs +3 -4
- package/persist-plugins/local-storage.mjs.map +1 -1
- package/persist-plugins/mmkv.js +2 -3
- package/persist-plugins/mmkv.js.map +1 -1
- package/persist-plugins/mmkv.mjs +3 -4
- package/persist-plugins/mmkv.mjs.map +1 -1
- package/persist.d.ts +17 -2
- package/persist.js +261 -82
- package/persist.js.map +1 -1
- package/persist.mjs +263 -82
- package/persist.mjs.map +1 -1
- package/react-hooks/createObservableHook.js +1 -1
- package/react-hooks/createObservableHook.js.map +1 -1
- package/react-hooks/createObservableHook.mjs +1 -1
- package/react-hooks/createObservableHook.mjs.map +1 -1
- package/react-hooks/useFetch.d.ts +4 -3
- package/react-hooks/useFetch.js.map +1 -1
- package/react-hooks/useFetch.mjs.map +1 -1
- package/react-hooks/useObservableQuery.js.map +1 -1
- package/react-hooks/useObservableQuery.mjs.map +1 -1
- package/react.js +2 -0
- package/react.js.map +1 -1
- package/react.mjs +2 -0
- package/react.mjs.map +1 -1
- package/src/ObservableObject.d.ts +8 -4
- package/src/ObservablePrimitive.d.ts +2 -1
- package/src/activated.d.ts +3 -0
- package/src/computed.d.ts +1 -1
- package/src/config/enableDirectAccess.d.ts +1 -1
- package/src/config/enableDirectPeek.d.ts +1 -1
- package/src/config/enableReactTracking.d.ts +4 -3
- package/src/config/enableReactUse.d.ts +1 -1
- package/src/createObservable.d.ts +2 -2
- package/src/globals.d.ts +14 -3
- package/src/helpers/fetch.d.ts +4 -3
- package/src/helpers/time.d.ts +2 -2
- package/src/helpers.d.ts +4 -10
- package/src/history/trackHistory.d.ts +1 -1
- package/src/observable.d.ts +9 -3
- package/src/observableInterfaces.d.ts +67 -302
- package/src/observableTypes.d.ts +92 -0
- package/src/persist/persistActivateNode.d.ts +1 -0
- package/src/persist/persistObservable.d.ts +2 -5
- package/src/persistTypes.d.ts +224 -0
- package/src/proxy.d.ts +2 -1
- package/src/react/Computed.d.ts +1 -1
- package/src/react/reactInterfaces.d.ts +2 -1
- package/src/react/usePauseProvider.d.ts +3 -3
- package/src/react-hooks/useFetch.d.ts +4 -3
- package/src/retry.d.ts +9 -0
- package/src/trackSelector.d.ts +3 -2
package/index.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { noop } from '@babel/types';
|
|
2
|
+
|
|
1
3
|
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
2
4
|
function isArray(obj) {
|
|
3
5
|
return Array.isArray(obj);
|
|
@@ -53,14 +55,25 @@ const symbolGetNode = Symbol('getNode');
|
|
|
53
55
|
const symbolDelete = /* @__PURE__ */ Symbol('delete');
|
|
54
56
|
const symbolOpaque = Symbol('opaque');
|
|
55
57
|
const optimized = Symbol('optimized');
|
|
58
|
+
const symbolActivated = Symbol('activated');
|
|
56
59
|
// TODOV3 Remove these
|
|
57
60
|
const extraPrimitiveActivators = new Map();
|
|
58
61
|
const extraPrimitiveProps = new Map();
|
|
59
62
|
const globalState = {
|
|
60
63
|
isLoadingLocal: false,
|
|
61
|
-
isLoadingRemote: false,
|
|
62
64
|
isMerging: false,
|
|
65
|
+
isLoadingRemote$: undefined,
|
|
66
|
+
activateNode: undefined,
|
|
67
|
+
pendingNodes: new Map(),
|
|
68
|
+
dirtyNodes: new Set(),
|
|
63
69
|
};
|
|
70
|
+
function isObservable(obs) {
|
|
71
|
+
return !!obs && !!obs[symbolGetNode];
|
|
72
|
+
}
|
|
73
|
+
function isComputed(obs) {
|
|
74
|
+
var _a;
|
|
75
|
+
return obs && ((_a = obs[symbolGetNode]) === null || _a === void 0 ? void 0 : _a.isComputed);
|
|
76
|
+
}
|
|
64
77
|
function checkActivate(node) {
|
|
65
78
|
var _a;
|
|
66
79
|
const root = node.root;
|
|
@@ -87,12 +100,13 @@ function setNodeValue(node, newValue) {
|
|
|
87
100
|
const prevValue = parentValue[key];
|
|
88
101
|
const isFunc = isFunction(newValue);
|
|
89
102
|
// Compute newValue if newValue is a function or an observable
|
|
90
|
-
newValue =
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
newValue = !parentNode.isAssigning && isFunc ? newValue(prevValue) : newValue;
|
|
104
|
+
// If setting an observable, set a link to the observable instead
|
|
105
|
+
if (isObservable(newValue) && !isComputed(newValue)) {
|
|
106
|
+
const val = newValue;
|
|
107
|
+
node.lazy = () => val;
|
|
108
|
+
newValue = undefined;
|
|
109
|
+
}
|
|
96
110
|
try {
|
|
97
111
|
parentNode.isSetting = (parentNode.isSetting || 0) + 1;
|
|
98
112
|
// Save the new value
|
|
@@ -126,7 +140,13 @@ function getNodeValue(node) {
|
|
|
126
140
|
}
|
|
127
141
|
return child;
|
|
128
142
|
}
|
|
129
|
-
|
|
143
|
+
const cloneFunction = (originalFunction) => {
|
|
144
|
+
const length = originalFunction.length;
|
|
145
|
+
return length > 1
|
|
146
|
+
? (arg1, arg2) => originalFunction(arg1, arg2)
|
|
147
|
+
: (...args) => originalFunction(...args);
|
|
148
|
+
};
|
|
149
|
+
function getChildNode(node, key, asFunction) {
|
|
130
150
|
var _a;
|
|
131
151
|
// Get the child by key
|
|
132
152
|
let child = (_a = node.children) === null || _a === void 0 ? void 0 : _a.get(key);
|
|
@@ -138,6 +158,20 @@ function getChildNode(node, key) {
|
|
|
138
158
|
key,
|
|
139
159
|
lazy: true,
|
|
140
160
|
};
|
|
161
|
+
if (asFunction) {
|
|
162
|
+
child = Object.assign(cloneFunction(asFunction), child);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
if (node.activationState) {
|
|
166
|
+
const { lookup } = node.activationState;
|
|
167
|
+
if (lookup) {
|
|
168
|
+
child = Object.assign(lookup.bind(node, key), child);
|
|
169
|
+
if (isFunction(child)) {
|
|
170
|
+
extractFunction(node, key, child);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
141
175
|
if (!node.children) {
|
|
142
176
|
node.children = new Map();
|
|
143
177
|
}
|
|
@@ -159,6 +193,7 @@ function ensureNodeValue(node) {
|
|
|
159
193
|
return value;
|
|
160
194
|
}
|
|
161
195
|
function findIDKey(obj, node) {
|
|
196
|
+
var _a, _b;
|
|
162
197
|
let idKey = isObject(obj)
|
|
163
198
|
? 'id' in obj
|
|
164
199
|
? 'id'
|
|
@@ -171,7 +206,8 @@ function findIDKey(obj, node) {
|
|
|
171
206
|
: undefined
|
|
172
207
|
: undefined;
|
|
173
208
|
if (!idKey && node.parent) {
|
|
174
|
-
const
|
|
209
|
+
const k = node.key + '_keyExtractor';
|
|
210
|
+
const keyExtractor = (_b = (_a = node.functions) === null || _a === void 0 ? void 0 : _a.get(k)) !== null && _b !== void 0 ? _b : getNodeValue(node.parent)[node.key + '_keyExtractor'];
|
|
175
211
|
if (keyExtractor && isFunction(keyExtractor)) {
|
|
176
212
|
idKey = keyExtractor;
|
|
177
213
|
}
|
|
@@ -179,9 +215,11 @@ function findIDKey(obj, node) {
|
|
|
179
215
|
return idKey;
|
|
180
216
|
}
|
|
181
217
|
function extractFunction(node, key, fnOrComputed, computedChildNode) {
|
|
218
|
+
var _a;
|
|
182
219
|
if (!node.functions) {
|
|
183
220
|
node.functions = new Map();
|
|
184
221
|
}
|
|
222
|
+
(_a = node.children) === null || _a === void 0 ? void 0 : _a.delete(key);
|
|
185
223
|
node.functions.set(key, fnOrComputed);
|
|
186
224
|
if (computedChildNode) {
|
|
187
225
|
computedChildNode.parentOther = getChildNode(node, key);
|
|
@@ -192,226 +230,10 @@ function extractFunction(node, key, fnOrComputed, computedChildNode) {
|
|
|
192
230
|
}
|
|
193
231
|
}
|
|
194
232
|
|
|
195
|
-
function
|
|
196
|
-
return
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
var _a;
|
|
200
|
-
return obs && ((_a = obs[symbolGetNode]) === null || _a === void 0 ? void 0 : _a.isEvent);
|
|
201
|
-
}
|
|
202
|
-
function computeSelector(selector, e, retainObservable) {
|
|
203
|
-
let c = selector;
|
|
204
|
-
if (isFunction(c)) {
|
|
205
|
-
c = e ? c(e) : c();
|
|
206
|
-
}
|
|
207
|
-
return isObservable(c) && !retainObservable ? c.get() : c;
|
|
208
|
-
}
|
|
209
|
-
function getObservableIndex(obs) {
|
|
210
|
-
const node = getNode(obs);
|
|
211
|
-
const n = +node.key;
|
|
212
|
-
return n - n < 1 ? +n : -1;
|
|
213
|
-
}
|
|
214
|
-
function opaqueObject(value) {
|
|
215
|
-
if (value) {
|
|
216
|
-
value[symbolOpaque] = true;
|
|
217
|
-
}
|
|
218
|
-
return value;
|
|
219
|
-
}
|
|
220
|
-
function lockObservable(obs, value) {
|
|
221
|
-
var _a;
|
|
222
|
-
const root = (_a = getNode(obs)) === null || _a === void 0 ? void 0 : _a.root;
|
|
223
|
-
if (root) {
|
|
224
|
-
root.locked = value;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
function setAtPath(obj, path, pathTypes, value, fullObj, restore) {
|
|
228
|
-
let o = obj;
|
|
229
|
-
let oFull = fullObj;
|
|
230
|
-
if (path.length > 0) {
|
|
231
|
-
for (let i = 0; i < path.length; i++) {
|
|
232
|
-
const p = path[i];
|
|
233
|
-
if (i === path.length - 1) {
|
|
234
|
-
// Don't set if the value is the same. This prevents creating a new key
|
|
235
|
-
// when setting undefined on an object without this key
|
|
236
|
-
if (o[p] !== value) {
|
|
237
|
-
o[p] = value;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
else if (o[p] === symbolDelete) {
|
|
241
|
-
// If this was previously deleted, restore it
|
|
242
|
-
if (oFull) {
|
|
243
|
-
o[p] = oFull[p];
|
|
244
|
-
restore === null || restore === void 0 ? void 0 : restore(path.slice(0, i + 1), o[p]);
|
|
245
|
-
}
|
|
246
|
-
break;
|
|
247
|
-
}
|
|
248
|
-
else if (o[p] === undefined || o[p] === null) {
|
|
249
|
-
o[p] = initializePathType(pathTypes[i]);
|
|
250
|
-
}
|
|
251
|
-
o = o[p];
|
|
252
|
-
if (oFull) {
|
|
253
|
-
oFull = oFull[p];
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
else {
|
|
258
|
-
obj = value;
|
|
259
|
-
}
|
|
260
|
-
return obj;
|
|
261
|
-
}
|
|
262
|
-
function setInObservableAtPath(obs, path, pathTypes, value, mode) {
|
|
263
|
-
let o = obs;
|
|
264
|
-
let v = value;
|
|
265
|
-
for (let i = 0; i < path.length; i++) {
|
|
266
|
-
const p = path[i];
|
|
267
|
-
if (!o.peek()[p]) {
|
|
268
|
-
o[p].set(initializePathType(pathTypes[i]));
|
|
269
|
-
}
|
|
270
|
-
o = o[p];
|
|
271
|
-
v = v[p];
|
|
272
|
-
}
|
|
273
|
-
if (v === symbolDelete) {
|
|
274
|
-
o.delete();
|
|
275
|
-
}
|
|
276
|
-
// Assign if possible, or set otherwise
|
|
277
|
-
else if (mode === 'assign' && o.assign && isObject(o.peek())) {
|
|
278
|
-
o.assign(v);
|
|
279
|
-
}
|
|
280
|
-
else {
|
|
281
|
-
o.set(v);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
function mergeIntoObservable(target, ...sources) {
|
|
285
|
-
beginBatch();
|
|
286
|
-
globalState.isMerging = true;
|
|
287
|
-
for (let i = 0; i < sources.length; i++) {
|
|
288
|
-
target = _mergeIntoObservable(target, sources[i]);
|
|
289
|
-
}
|
|
290
|
-
globalState.isMerging = false;
|
|
291
|
-
endBatch();
|
|
292
|
-
return target;
|
|
293
|
-
}
|
|
294
|
-
function _mergeIntoObservable(target, source) {
|
|
295
|
-
var _a;
|
|
296
|
-
const needsSet = isObservable(target);
|
|
297
|
-
const targetValue = needsSet ? target.peek() : target;
|
|
298
|
-
const isTargetArr = isArray(targetValue);
|
|
299
|
-
const isTargetObj = !isTargetArr && isObject(targetValue);
|
|
300
|
-
if ((isTargetObj && isObject(source) && !isEmpty(targetValue)) ||
|
|
301
|
-
(isTargetArr && isArray(source) && targetValue.length > 0)) {
|
|
302
|
-
const keys = Object.keys(source);
|
|
303
|
-
for (let i = 0; i < keys.length; i++) {
|
|
304
|
-
const key = keys[i];
|
|
305
|
-
const sourceValue = source[key];
|
|
306
|
-
if (sourceValue === symbolDelete) {
|
|
307
|
-
needsSet && ((_a = target[key]) === null || _a === void 0 ? void 0 : _a.delete) ? target[key].delete() : delete target[key];
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
310
|
-
const isObj = isObject(sourceValue);
|
|
311
|
-
const isArr = !isObj && isArray(sourceValue);
|
|
312
|
-
const targetChild = target[key];
|
|
313
|
-
if ((isObj || isArr) && targetChild && (needsSet || !isEmpty(targetChild))) {
|
|
314
|
-
if (!needsSet && (!targetChild || (isObj ? !isObject(targetChild) : !isArray(targetChild)))) {
|
|
315
|
-
target[key] = sourceValue;
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
_mergeIntoObservable(targetChild, sourceValue);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
else {
|
|
322
|
-
needsSet
|
|
323
|
-
? targetChild.set(sourceValue)
|
|
324
|
-
: (target[key] = sourceValue);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
else if (source !== undefined) {
|
|
330
|
-
needsSet ? target.set(source) : (target = source);
|
|
331
|
-
}
|
|
332
|
-
return target;
|
|
333
|
-
}
|
|
334
|
-
function constructObjectWithPath(path, pathTypes, value) {
|
|
335
|
-
let out;
|
|
336
|
-
if (path.length > 0) {
|
|
337
|
-
let o = (out = {});
|
|
338
|
-
for (let i = 0; i < path.length; i++) {
|
|
339
|
-
const p = path[i];
|
|
340
|
-
o[p] = i === path.length - 1 ? value : initializePathType(pathTypes[i]);
|
|
341
|
-
o = o[p];
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
else {
|
|
345
|
-
out = value;
|
|
346
|
-
}
|
|
347
|
-
return out;
|
|
348
|
-
}
|
|
349
|
-
function deconstructObjectWithPath(path, pathTypes, value) {
|
|
350
|
-
let o = value;
|
|
351
|
-
for (let i = 0; i < path.length; i++) {
|
|
352
|
-
const p = path[i];
|
|
353
|
-
o = o ? o[p] : initializePathType(pathTypes[i]);
|
|
354
|
-
}
|
|
355
|
-
return o;
|
|
356
|
-
}
|
|
357
|
-
function isObservableValueReady(value) {
|
|
358
|
-
return !!value && ((!isObject(value) && !isArray(value)) || !isEmpty(value));
|
|
359
|
-
}
|
|
360
|
-
function setSilently(obs, newValue) {
|
|
361
|
-
const node = getNode(obs);
|
|
362
|
-
return setNodeValue(node, newValue).newValue;
|
|
363
|
-
}
|
|
364
|
-
function getPathType(value) {
|
|
365
|
-
return isArray(value) ? 'array' : value instanceof Map ? 'map' : value instanceof Set ? 'set' : 'object';
|
|
366
|
-
}
|
|
367
|
-
function initializePathType(pathType) {
|
|
368
|
-
switch (pathType) {
|
|
369
|
-
case 'array':
|
|
370
|
-
return [];
|
|
371
|
-
case 'object':
|
|
372
|
-
return {};
|
|
373
|
-
case 'map':
|
|
374
|
-
return new Map();
|
|
375
|
-
case 'set':
|
|
376
|
-
return new Set();
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
function replacer(_, value) {
|
|
380
|
-
if (value instanceof Map) {
|
|
381
|
-
return {
|
|
382
|
-
__LSType: 'Map',
|
|
383
|
-
value: Array.from(value.entries()), // or with spread: value: [...value]
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
else if (value instanceof Set) {
|
|
387
|
-
return {
|
|
388
|
-
__LSType: 'Set',
|
|
389
|
-
value: Array.from(value), // or with spread: value: [...value]
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
else {
|
|
393
|
-
return value;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
function reviver(_, value) {
|
|
397
|
-
if (typeof value === 'object' && value) {
|
|
398
|
-
if (value.__LSType === 'Map') {
|
|
399
|
-
return new Map(value.value);
|
|
400
|
-
}
|
|
401
|
-
else if (value.__LSType === 'Set') {
|
|
402
|
-
return new Set(value.value);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
return value;
|
|
406
|
-
}
|
|
407
|
-
function safeStringify(value) {
|
|
408
|
-
return JSON.stringify(value, replacer);
|
|
409
|
-
}
|
|
410
|
-
function safeParse(value) {
|
|
411
|
-
return JSON.parse(value, reviver);
|
|
412
|
-
}
|
|
413
|
-
function clone(value) {
|
|
414
|
-
return safeParse(safeStringify(value));
|
|
233
|
+
function activated(params) {
|
|
234
|
+
return (() => ({
|
|
235
|
+
[symbolActivated]: params,
|
|
236
|
+
}));
|
|
415
237
|
}
|
|
416
238
|
|
|
417
239
|
let timeout;
|
|
@@ -439,28 +261,22 @@ function isArraySubset(mainArr, subsetArr) {
|
|
|
439
261
|
}
|
|
440
262
|
function createPreviousHandlerInner(value, changes) {
|
|
441
263
|
// Clones the current state and inject the previous data at the changed path
|
|
442
|
-
let
|
|
264
|
+
let clone = value ? JSON.parse(JSON.stringify(value)) : {};
|
|
443
265
|
for (let i = 0; i < changes.length; i++) {
|
|
444
266
|
const { path, prevAtPath } = changes[i];
|
|
445
|
-
let o =
|
|
267
|
+
let o = clone;
|
|
446
268
|
if (path.length > 0) {
|
|
447
269
|
let i;
|
|
448
270
|
for (i = 0; i < path.length - 1; i++) {
|
|
449
271
|
o = o[path[i]];
|
|
450
272
|
}
|
|
451
|
-
|
|
452
|
-
if (o instanceof Map) {
|
|
453
|
-
o.set(key, prevAtPath);
|
|
454
|
-
}
|
|
455
|
-
else {
|
|
456
|
-
o[key] = prevAtPath;
|
|
457
|
-
}
|
|
273
|
+
o[path[i]] = prevAtPath;
|
|
458
274
|
}
|
|
459
275
|
else {
|
|
460
|
-
|
|
276
|
+
clone = prevAtPath;
|
|
461
277
|
}
|
|
462
278
|
}
|
|
463
|
-
return
|
|
279
|
+
return clone;
|
|
464
280
|
}
|
|
465
281
|
function createPreviousHandler(value, changes) {
|
|
466
282
|
// Create a function that generates the previous state
|
|
@@ -530,7 +346,7 @@ function computeChangesRecursive(changesInBatch, node, value, path, pathTypes, v
|
|
|
530
346
|
const parent = node.parent;
|
|
531
347
|
if (parent) {
|
|
532
348
|
const parentValue = getNodeValue(parent);
|
|
533
|
-
computeChangesRecursive(changesInBatch, parent, parentValue, [node.key].concat(path), [
|
|
349
|
+
computeChangesRecursive(changesInBatch, parent, parentValue, [node.key].concat(path), [(isArray(value) ? 'array' : 'object')].concat(pathTypes), valueAtPath, prevAtPath, immediate, level + 1, whenOptimizedOnlyIf);
|
|
534
350
|
}
|
|
535
351
|
}
|
|
536
352
|
}
|
|
@@ -569,6 +385,13 @@ function batchNotifyChanges(changesInBatch, immediate) {
|
|
|
569
385
|
});
|
|
570
386
|
}
|
|
571
387
|
function runBatch() {
|
|
388
|
+
const dirtyNodes = Array.from(globalState.dirtyNodes);
|
|
389
|
+
globalState.dirtyNodes.clear();
|
|
390
|
+
dirtyNodes.forEach((node) => {
|
|
391
|
+
var _a;
|
|
392
|
+
(_a = node.dirtyFn) === null || _a === void 0 ? void 0 : _a.call(node);
|
|
393
|
+
node.dirtyFn = undefined;
|
|
394
|
+
});
|
|
572
395
|
// Save batch locally and reset _batchMap first because a new batch could begin while looping over callbacks.
|
|
573
396
|
// This can happen with observableComputed for example.
|
|
574
397
|
const map = _batchMap;
|
|
@@ -655,68 +478,261 @@ function endBatch(force) {
|
|
|
655
478
|
}
|
|
656
479
|
}
|
|
657
480
|
|
|
658
|
-
function createObservable(value, makePrimitive, createObject, createPrimitive) {
|
|
481
|
+
function createObservable(value, makePrimitive, extractPromise, createObject, createPrimitive) {
|
|
659
482
|
const valueIsPromise = isPromise(value);
|
|
483
|
+
const valueIsFunction = isFunction(value);
|
|
660
484
|
const root = {
|
|
661
485
|
_: value,
|
|
662
486
|
};
|
|
663
|
-
|
|
487
|
+
let node = {
|
|
664
488
|
root,
|
|
665
489
|
lazy: true,
|
|
666
490
|
};
|
|
491
|
+
if (valueIsFunction) {
|
|
492
|
+
node = Object.assign(cloneFunction(value), node);
|
|
493
|
+
}
|
|
667
494
|
const prim = makePrimitive || isActualPrimitive(value);
|
|
668
495
|
const obs = prim
|
|
669
496
|
? new createPrimitive(node)
|
|
670
497
|
: createObject(node);
|
|
671
498
|
if (valueIsPromise) {
|
|
499
|
+
setNodeValue(node, undefined);
|
|
672
500
|
extractPromise(node, value);
|
|
673
501
|
}
|
|
674
502
|
return obs;
|
|
675
503
|
}
|
|
676
504
|
|
|
677
|
-
function
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
}
|
|
686
|
-
else {
|
|
687
|
-
node.listeners = listeners;
|
|
688
|
-
}
|
|
505
|
+
function isEvent(obs) {
|
|
506
|
+
var _a;
|
|
507
|
+
return obs && ((_a = obs[symbolGetNode]) === null || _a === void 0 ? void 0 : _a.isEvent);
|
|
508
|
+
}
|
|
509
|
+
function computeSelector(selector, e, retainObservable) {
|
|
510
|
+
let c = selector;
|
|
511
|
+
if (!isObservable(c) && isFunction(c)) {
|
|
512
|
+
c = e ? c(e) : c();
|
|
689
513
|
}
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
value,
|
|
701
|
-
changes: [
|
|
702
|
-
{
|
|
703
|
-
path: [],
|
|
704
|
-
pathTypes: [],
|
|
705
|
-
prevAtPath: value,
|
|
706
|
-
valueAtPath: value,
|
|
707
|
-
},
|
|
708
|
-
],
|
|
709
|
-
getPrevious: () => undefined,
|
|
710
|
-
});
|
|
514
|
+
return isObservable(c) && !retainObservable ? c.get() : c;
|
|
515
|
+
}
|
|
516
|
+
function getObservableIndex(obs) {
|
|
517
|
+
const node = getNode(obs);
|
|
518
|
+
const n = +node.key;
|
|
519
|
+
return n - n < 1 ? +n : -1;
|
|
520
|
+
}
|
|
521
|
+
function opaqueObject(value) {
|
|
522
|
+
if (value) {
|
|
523
|
+
value[symbolOpaque] = true;
|
|
711
524
|
}
|
|
712
|
-
return
|
|
525
|
+
return value;
|
|
713
526
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
const
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
}
|
|
527
|
+
function lockObservable(obs, value) {
|
|
528
|
+
var _a;
|
|
529
|
+
const root = (_a = getNode(obs)) === null || _a === void 0 ? void 0 : _a.root;
|
|
530
|
+
if (root) {
|
|
531
|
+
root.locked = value;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
function setAtPath(obj, path, pathTypes, value, fullObj, restore) {
|
|
535
|
+
let o = obj;
|
|
536
|
+
let oFull = fullObj;
|
|
537
|
+
if (path.length > 0) {
|
|
538
|
+
for (let i = 0; i < path.length; i++) {
|
|
539
|
+
const p = path[i];
|
|
540
|
+
if (i === path.length - 1) {
|
|
541
|
+
// Don't set if the value is the same. This prevents creating a new key
|
|
542
|
+
// when setting undefined on an object without this key
|
|
543
|
+
if (o[p] !== value) {
|
|
544
|
+
o[p] = value;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
else if (o[p] === symbolDelete) {
|
|
548
|
+
// If this was previously deleted, restore it
|
|
549
|
+
if (oFull) {
|
|
550
|
+
o[p] = oFull[p];
|
|
551
|
+
restore === null || restore === void 0 ? void 0 : restore(path.slice(0, i + 1), o[p]);
|
|
552
|
+
}
|
|
553
|
+
break;
|
|
554
|
+
}
|
|
555
|
+
else if (o[p] === undefined || o[p] === null) {
|
|
556
|
+
o[p] = pathTypes[i] === 'array' ? [] : {};
|
|
557
|
+
}
|
|
558
|
+
o = o[p];
|
|
559
|
+
if (oFull) {
|
|
560
|
+
oFull = oFull[p];
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
obj = value;
|
|
566
|
+
}
|
|
567
|
+
return obj;
|
|
568
|
+
}
|
|
569
|
+
function setInObservableAtPath(obs, path, pathTypes, value, mode) {
|
|
570
|
+
let o = obs;
|
|
571
|
+
let v = value;
|
|
572
|
+
for (let i = 0; i < path.length; i++) {
|
|
573
|
+
const p = path[i];
|
|
574
|
+
if (!o.peek()[p] && pathTypes[i] === 'array') {
|
|
575
|
+
o[p].set([]);
|
|
576
|
+
}
|
|
577
|
+
o = o[p];
|
|
578
|
+
v = v[p];
|
|
579
|
+
}
|
|
580
|
+
if (v === symbolDelete) {
|
|
581
|
+
o.delete();
|
|
582
|
+
}
|
|
583
|
+
// Assign if possible, or set otherwise
|
|
584
|
+
else if (mode === 'assign' && o.assign && isObject(o.peek())) {
|
|
585
|
+
o.assign(v);
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
o.set(v);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
function mergeIntoObservable(target, ...sources) {
|
|
592
|
+
beginBatch();
|
|
593
|
+
globalState.isMerging = true;
|
|
594
|
+
for (let i = 0; i < sources.length; i++) {
|
|
595
|
+
target = _mergeIntoObservable(target, sources[i]);
|
|
596
|
+
}
|
|
597
|
+
globalState.isMerging = false;
|
|
598
|
+
endBatch();
|
|
599
|
+
return target;
|
|
600
|
+
}
|
|
601
|
+
function _mergeIntoObservable(target, source) {
|
|
602
|
+
var _a;
|
|
603
|
+
if (isObservable(source)) {
|
|
604
|
+
source = source.peek();
|
|
605
|
+
}
|
|
606
|
+
const needsSet = isObservable(target);
|
|
607
|
+
const targetValue = needsSet ? target.peek() : target;
|
|
608
|
+
const isTargetArr = isArray(targetValue);
|
|
609
|
+
const isTargetObj = !isTargetArr && isObject(targetValue);
|
|
610
|
+
if ((isTargetObj && isObject(source) && !isEmpty(targetValue)) || (isTargetArr && targetValue.length > 0)) {
|
|
611
|
+
const keys = Object.keys(source);
|
|
612
|
+
for (let i = 0; i < keys.length; i++) {
|
|
613
|
+
const key = keys[i];
|
|
614
|
+
const sourceValue = source[key];
|
|
615
|
+
if (sourceValue === symbolDelete) {
|
|
616
|
+
needsSet && ((_a = target[key]) === null || _a === void 0 ? void 0 : _a.delete)
|
|
617
|
+
? target[key].delete()
|
|
618
|
+
: delete target[key];
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
const isObj = isObject(sourceValue);
|
|
622
|
+
const isArr = !isObj && isArray(sourceValue);
|
|
623
|
+
const targetChild = target[key];
|
|
624
|
+
if ((isObj || isArr) && targetChild && (needsSet || !isEmpty(targetChild))) {
|
|
625
|
+
if (!needsSet && (!targetChild || (isObj ? !isObject(targetChild) : !isArray(targetChild)))) {
|
|
626
|
+
target[key] = sourceValue;
|
|
627
|
+
}
|
|
628
|
+
else {
|
|
629
|
+
_mergeIntoObservable(targetChild, sourceValue);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
needsSet
|
|
634
|
+
? targetChild.set(sourceValue)
|
|
635
|
+
: (target[key] = sourceValue);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
else if (source !== undefined) {
|
|
641
|
+
needsSet ? target.set(source) : (target = source);
|
|
642
|
+
}
|
|
643
|
+
return target;
|
|
644
|
+
}
|
|
645
|
+
function constructObjectWithPath(path, pathTypes, value) {
|
|
646
|
+
let out;
|
|
647
|
+
if (path.length > 0) {
|
|
648
|
+
let o = (out = {});
|
|
649
|
+
for (let i = 0; i < path.length; i++) {
|
|
650
|
+
const p = path[i];
|
|
651
|
+
o[p] = i === path.length - 1 ? value : pathTypes[i] === 'array' ? [] : {};
|
|
652
|
+
o = o[p];
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
out = value;
|
|
657
|
+
}
|
|
658
|
+
return out;
|
|
659
|
+
}
|
|
660
|
+
function deconstructObjectWithPath(path, pathTypes, value) {
|
|
661
|
+
let o = value;
|
|
662
|
+
for (let i = 0; i < path.length; i++) {
|
|
663
|
+
const p = path[i];
|
|
664
|
+
o = o ? o[p] : pathTypes[i] === 'array' ? [] : {};
|
|
665
|
+
}
|
|
666
|
+
return o;
|
|
667
|
+
}
|
|
668
|
+
function isObservableValueReady(value) {
|
|
669
|
+
return !!value && ((!isObject(value) && !isArray(value)) || !isEmpty(value));
|
|
670
|
+
}
|
|
671
|
+
function setSilently(obs, newValue) {
|
|
672
|
+
const node = getNode(obs);
|
|
673
|
+
return setNodeValue(node, newValue).newValue;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function onChange(node, callback, options = {}) {
|
|
677
|
+
const { initial, immediate, noArgs } = options;
|
|
678
|
+
const { trackingType } = options;
|
|
679
|
+
let listeners = immediate ? node.listenersImmediate : node.listeners;
|
|
680
|
+
if (!listeners) {
|
|
681
|
+
listeners = new Set();
|
|
682
|
+
if (immediate) {
|
|
683
|
+
node.listenersImmediate = listeners;
|
|
684
|
+
}
|
|
685
|
+
else {
|
|
686
|
+
node.listeners = listeners;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
checkActivate(node);
|
|
690
|
+
const listener = {
|
|
691
|
+
listener: callback,
|
|
692
|
+
track: trackingType,
|
|
693
|
+
noArgs,
|
|
694
|
+
};
|
|
695
|
+
listeners.add(listener);
|
|
696
|
+
if (initial) {
|
|
697
|
+
const value = getNodeValue(node);
|
|
698
|
+
callback({
|
|
699
|
+
value,
|
|
700
|
+
changes: [
|
|
701
|
+
{
|
|
702
|
+
path: [],
|
|
703
|
+
pathTypes: [],
|
|
704
|
+
prevAtPath: value,
|
|
705
|
+
valueAtPath: value,
|
|
706
|
+
},
|
|
707
|
+
],
|
|
708
|
+
getPrevious: () => undefined,
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
return () => listeners.delete(listener);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
function setupTracking(nodes, update, noArgs, immediate) {
|
|
715
|
+
let listeners = [];
|
|
716
|
+
// Listen to tracked nodes
|
|
717
|
+
nodes === null || nodes === void 0 ? void 0 : nodes.forEach((tracked) => {
|
|
718
|
+
const { node, track } = tracked;
|
|
719
|
+
listeners.push(onChange(node, update, { trackingType: track, immediate, noArgs }));
|
|
720
|
+
});
|
|
721
|
+
return () => {
|
|
722
|
+
if (listeners) {
|
|
723
|
+
for (let i = 0; i < listeners.length; i++) {
|
|
724
|
+
listeners[i]();
|
|
725
|
+
}
|
|
726
|
+
listeners = undefined;
|
|
727
|
+
}
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
let trackCount = 0;
|
|
732
|
+
const trackingQueue = [];
|
|
733
|
+
const tracking = {
|
|
734
|
+
current: undefined,
|
|
735
|
+
};
|
|
720
736
|
function beginTracking() {
|
|
721
737
|
// Keep a copy of the previous tracking context so it can be restored
|
|
722
738
|
// when this context is complete
|
|
@@ -745,11 +761,194 @@ function updateTracking(node, track) {
|
|
|
745
761
|
existing.num++;
|
|
746
762
|
}
|
|
747
763
|
else {
|
|
748
|
-
tracker.nodes.set(node, { node, track, num: 1 });
|
|
764
|
+
tracker.nodes.set(node, { node, track, num: 1 });
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
function trackSelector(selector, update, observeEvent, observeOptions, createResubscribe) {
|
|
771
|
+
var _a;
|
|
772
|
+
let nodes;
|
|
773
|
+
let value;
|
|
774
|
+
let dispose;
|
|
775
|
+
let tracker;
|
|
776
|
+
let resubscribe;
|
|
777
|
+
let updateFn = update;
|
|
778
|
+
if (isObservable(selector)) {
|
|
779
|
+
value = selector.peek();
|
|
780
|
+
dispose = selector.onChange(update);
|
|
781
|
+
resubscribe = createResubscribe ? selector.onChange(update) : undefined;
|
|
782
|
+
}
|
|
783
|
+
else {
|
|
784
|
+
// Compute the selector inside a tracking context
|
|
785
|
+
beginTracking();
|
|
786
|
+
value = selector ? computeSelector(selector, observeEvent, observeOptions === null || observeOptions === void 0 ? void 0 : observeOptions.fromComputed) : selector;
|
|
787
|
+
tracker = tracking.current;
|
|
788
|
+
nodes = tracker.nodes;
|
|
789
|
+
endTracking();
|
|
790
|
+
if ((process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') && tracker && nodes) {
|
|
791
|
+
(_a = tracker.traceListeners) === null || _a === void 0 ? void 0 : _a.call(tracker, nodes);
|
|
792
|
+
if (tracker.traceUpdates) {
|
|
793
|
+
updateFn = tracker.traceUpdates(update);
|
|
794
|
+
}
|
|
795
|
+
// Clear tracing so it doesn't leak to other components
|
|
796
|
+
tracker.traceListeners = undefined;
|
|
797
|
+
tracker.traceUpdates = undefined;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
if (!(observeEvent === null || observeEvent === void 0 ? void 0 : observeEvent.cancel)) {
|
|
801
|
+
// Do tracing if it was requested
|
|
802
|
+
// useSyncExternalStore doesn't subscribe until after the component mount.
|
|
803
|
+
// We want to subscribe immediately so we don't miss any updates
|
|
804
|
+
dispose = setupTracking(nodes, updateFn, false, observeOptions === null || observeOptions === void 0 ? void 0 : observeOptions.immediate);
|
|
805
|
+
resubscribe = createResubscribe ? () => setupTracking(nodes, updateFn) : undefined;
|
|
806
|
+
}
|
|
807
|
+
return { value, nodes, dispose, resubscribe };
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
function observe(selectorOrRun, reactionOrOptions, options) {
|
|
811
|
+
let reaction;
|
|
812
|
+
if (isFunction(reactionOrOptions)) {
|
|
813
|
+
reaction = reactionOrOptions;
|
|
814
|
+
}
|
|
815
|
+
else {
|
|
816
|
+
options = reactionOrOptions;
|
|
817
|
+
}
|
|
818
|
+
let dispose;
|
|
819
|
+
const e = { num: 0 };
|
|
820
|
+
// Wrap it in a function so it doesn't pass all the arguments to run()
|
|
821
|
+
const update = function () {
|
|
822
|
+
if (e.onCleanup) {
|
|
823
|
+
e.onCleanup();
|
|
824
|
+
e.onCleanup = undefined;
|
|
825
|
+
}
|
|
826
|
+
// Run in a batch so changes don't happen until we're done tracking here
|
|
827
|
+
beginBatch();
|
|
828
|
+
// Run the function/selector
|
|
829
|
+
delete e.value;
|
|
830
|
+
// Dispose listeners from previous run
|
|
831
|
+
dispose === null || dispose === void 0 ? void 0 : dispose();
|
|
832
|
+
const { dispose: _dispose, value, nodes } = trackSelector(selectorOrRun, update, e, options);
|
|
833
|
+
dispose = _dispose;
|
|
834
|
+
e.value = value;
|
|
835
|
+
e.nodes = nodes;
|
|
836
|
+
e.refresh = update;
|
|
837
|
+
if (e.onCleanupReaction) {
|
|
838
|
+
e.onCleanupReaction();
|
|
839
|
+
e.onCleanupReaction = undefined;
|
|
840
|
+
}
|
|
841
|
+
endBatch();
|
|
842
|
+
// Call the reaction if there is one and the value changed
|
|
843
|
+
if (reaction &&
|
|
844
|
+
((options === null || options === void 0 ? void 0 : options.fromComputed) || ((e.num > 0 || !isEvent(selectorOrRun)) && e.previous !== e.value))) {
|
|
845
|
+
reaction(e);
|
|
846
|
+
}
|
|
847
|
+
// Update the previous value
|
|
848
|
+
e.previous = e.value;
|
|
849
|
+
// Increment the counter
|
|
850
|
+
e.num++;
|
|
851
|
+
};
|
|
852
|
+
update();
|
|
853
|
+
// Return function calling dispose because dispose may be changed in update()
|
|
854
|
+
return () => {
|
|
855
|
+
var _a, _b;
|
|
856
|
+
(_a = e.onCleanup) === null || _a === void 0 ? void 0 : _a.call(e);
|
|
857
|
+
e.onCleanup = undefined;
|
|
858
|
+
(_b = e.onCleanupReaction) === null || _b === void 0 ? void 0 : _b.call(e);
|
|
859
|
+
e.onCleanupReaction = undefined;
|
|
860
|
+
dispose === null || dispose === void 0 ? void 0 : dispose();
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
function setupRetry(retryOptions, refresh, attemptNum) {
|
|
865
|
+
const timeout = {};
|
|
866
|
+
// let didGiveUp = false;
|
|
867
|
+
const { backoff, delay = 1000, infinite, times = 3, maxDelay = 30000 } = retryOptions;
|
|
868
|
+
let handleError;
|
|
869
|
+
attemptNum.current++;
|
|
870
|
+
if (infinite || attemptNum.current < times) {
|
|
871
|
+
const delayTime = Math.min(delay * (backoff === 'constant' ? 1 : 2 ** attemptNum.current), maxDelay);
|
|
872
|
+
handleError = () => {
|
|
873
|
+
timeout.current = setTimeout(refresh, delayTime);
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
handleError = () => {
|
|
878
|
+
// didGiveUp = true;
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
// TODO: Make an easy way to opt into this if
|
|
882
|
+
// if (typeof window !== 'undefined') {
|
|
883
|
+
// window.addEventListener('online', () => {
|
|
884
|
+
// if (didGiveUp || timeout) {
|
|
885
|
+
// if (timeout) {
|
|
886
|
+
// clearTimeout(timeout.current);
|
|
887
|
+
// timeout.current = undefined;
|
|
888
|
+
// }
|
|
889
|
+
// // Restart the backoff when coming back online
|
|
890
|
+
// attemptNum.current = 0;
|
|
891
|
+
// didGiveUp = false;
|
|
892
|
+
// refresh();
|
|
893
|
+
// }
|
|
894
|
+
// });
|
|
895
|
+
// }
|
|
896
|
+
return { handleError, timeout };
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
function _when(predicate, effect, checkReady) {
|
|
900
|
+
// If predicate is a regular Promise skip all the observable stuff
|
|
901
|
+
if (isPromise(predicate)) {
|
|
902
|
+
return effect ? predicate.then(effect) : predicate;
|
|
903
|
+
}
|
|
904
|
+
let value;
|
|
905
|
+
// Create a wrapping fn that calls the effect if predicate returns true
|
|
906
|
+
function run(e) {
|
|
907
|
+
const ret = computeSelector(predicate);
|
|
908
|
+
if (!isPromise(ret) && (checkReady ? isObservableValueReady(ret) : ret)) {
|
|
909
|
+
value = ret;
|
|
910
|
+
// Set cancel so that observe does not track anymore
|
|
911
|
+
e.cancel = true;
|
|
912
|
+
}
|
|
913
|
+
return value;
|
|
914
|
+
}
|
|
915
|
+
function doEffect() {
|
|
916
|
+
// If value is truthy then run the effect
|
|
917
|
+
effect === null || effect === void 0 ? void 0 : effect(value);
|
|
918
|
+
}
|
|
919
|
+
// Run in an observe
|
|
920
|
+
observe(run, doEffect);
|
|
921
|
+
// If first run resulted in a truthy value just return it.
|
|
922
|
+
// It will have set e.cancel so no need to dispose
|
|
923
|
+
if (isPromise(value)) {
|
|
924
|
+
return effect ? value.then(effect) : value;
|
|
925
|
+
}
|
|
926
|
+
else if (value !== undefined) {
|
|
927
|
+
return Promise.resolve(value);
|
|
928
|
+
}
|
|
929
|
+
else {
|
|
930
|
+
// Wrap it in a promise
|
|
931
|
+
const promise = new Promise((resolve) => {
|
|
932
|
+
if (effect) {
|
|
933
|
+
const originalEffect = effect;
|
|
934
|
+
effect = (value) => {
|
|
935
|
+
const effectValue = originalEffect(value);
|
|
936
|
+
resolve(effectValue);
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
else {
|
|
940
|
+
effect = resolve;
|
|
749
941
|
}
|
|
750
|
-
}
|
|
942
|
+
});
|
|
943
|
+
return promise;
|
|
751
944
|
}
|
|
752
945
|
}
|
|
946
|
+
function when(predicate, effect) {
|
|
947
|
+
return _when(predicate, effect, false);
|
|
948
|
+
}
|
|
949
|
+
function whenReady(predicate, effect) {
|
|
950
|
+
return _when(predicate, effect, true);
|
|
951
|
+
}
|
|
753
952
|
|
|
754
953
|
const ArrayModifiers = new Set([
|
|
755
954
|
'copyWithin',
|
|
@@ -791,19 +990,24 @@ if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
|
|
|
791
990
|
}
|
|
792
991
|
function collectionSetter(node, target, prop, ...args) {
|
|
793
992
|
var _a;
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
const
|
|
799
|
-
const
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
993
|
+
if (prop === 'push') {
|
|
994
|
+
setKey(node, target.length + '', args[0]);
|
|
995
|
+
}
|
|
996
|
+
else {
|
|
997
|
+
const prevValue = target.slice();
|
|
998
|
+
const ret = target[prop].apply(target, args);
|
|
999
|
+
if (node) {
|
|
1000
|
+
const hasParent = isChildNodeValue(node);
|
|
1001
|
+
const key = hasParent ? node.key : '_';
|
|
1002
|
+
const parentValue = hasParent ? getNodeValue(node.parent) : node.root;
|
|
1003
|
+
// Set the object to the previous value first
|
|
1004
|
+
parentValue[key] = prevValue;
|
|
1005
|
+
// Then set with the new value so it notifies with the correct prevValue
|
|
1006
|
+
setKey((_a = node.parent) !== null && _a !== void 0 ? _a : node, key, target);
|
|
1007
|
+
}
|
|
1008
|
+
// Return the original value
|
|
1009
|
+
return ret;
|
|
1010
|
+
}
|
|
807
1011
|
}
|
|
808
1012
|
function getKeys(obj, isArr, isMap) {
|
|
809
1013
|
return isArr ? undefined : obj ? (isMap ? Array.from(obj.keys()) : Object.keys(obj)) : [];
|
|
@@ -989,13 +1193,22 @@ function updateNodes(parent, obj, prevValue) {
|
|
|
989
1193
|
}
|
|
990
1194
|
return retValue !== null && retValue !== void 0 ? retValue : false;
|
|
991
1195
|
}
|
|
992
|
-
function getProxy(node, p) {
|
|
1196
|
+
function getProxy(node, p, asFunction) {
|
|
993
1197
|
// Get the child node if p prop
|
|
994
1198
|
if (p !== undefined)
|
|
995
|
-
node = getChildNode(node, p);
|
|
1199
|
+
node = getChildNode(node, p, asFunction);
|
|
996
1200
|
// Create a proxy if not already cached and return it
|
|
997
1201
|
return (node.proxy || (node.proxy = new Proxy(node, proxyHandler)));
|
|
998
1202
|
}
|
|
1203
|
+
function flushPending() {
|
|
1204
|
+
// Need to short circuit the computed batching because the user called get() or peek()
|
|
1205
|
+
// in which case the set needs to run immediately so that the values are up to date.
|
|
1206
|
+
if (globalState.pendingNodes.size > 0) {
|
|
1207
|
+
const nodes = Array.from(globalState.pendingNodes.values());
|
|
1208
|
+
globalState.pendingNodes.clear();
|
|
1209
|
+
nodes.forEach((fn) => fn());
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
999
1212
|
const proxyHandler = {
|
|
1000
1213
|
get(node, p, receiver) {
|
|
1001
1214
|
var _a;
|
|
@@ -1023,6 +1236,9 @@ const proxyHandler = {
|
|
|
1023
1236
|
const fn = observableFns.get(p);
|
|
1024
1237
|
// If this is an observable function, call it
|
|
1025
1238
|
if (fn) {
|
|
1239
|
+
if (p === 'get' || p === 'peek') {
|
|
1240
|
+
flushPending();
|
|
1241
|
+
}
|
|
1026
1242
|
return function (a, b, c) {
|
|
1027
1243
|
const l = arguments.length;
|
|
1028
1244
|
// Array call and apply are slow so micro-optimize this hot path.
|
|
@@ -1070,6 +1286,15 @@ const proxyHandler = {
|
|
|
1070
1286
|
if (isObject(value) && value[symbolOpaque]) {
|
|
1071
1287
|
return vProp;
|
|
1072
1288
|
}
|
|
1289
|
+
const fnOrComputed = (_a = node.functions) === null || _a === void 0 ? void 0 : _a.get(p);
|
|
1290
|
+
if (fnOrComputed) {
|
|
1291
|
+
if (isObservable(fnOrComputed)) {
|
|
1292
|
+
return fnOrComputed;
|
|
1293
|
+
}
|
|
1294
|
+
else {
|
|
1295
|
+
return getProxy(node, p, fnOrComputed);
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1073
1298
|
// Handle function calls
|
|
1074
1299
|
if (isFunction(vProp)) {
|
|
1075
1300
|
if (isArray(value)) {
|
|
@@ -1116,15 +1341,9 @@ const proxyHandler = {
|
|
|
1116
1341
|
// Update that this primitive node was accessed for observers
|
|
1117
1342
|
if (isArray(value) && p === 'length') {
|
|
1118
1343
|
updateTracking(node, true);
|
|
1119
|
-
// } else if (!isPrimitive(value)) {
|
|
1120
|
-
// updateTracking(getChildNode(node, p));
|
|
1121
1344
|
return vProp;
|
|
1122
1345
|
}
|
|
1123
1346
|
}
|
|
1124
|
-
const fnOrComputed = (_a = node.functions) === null || _a === void 0 ? void 0 : _a.get(p);
|
|
1125
|
-
if (fnOrComputed) {
|
|
1126
|
-
return fnOrComputed;
|
|
1127
|
-
}
|
|
1128
1347
|
// TODOV3: Remove "state"
|
|
1129
1348
|
if (vProp === undefined && (p === 'state' || p === '_state') && node.state) {
|
|
1130
1349
|
return node.state;
|
|
@@ -1191,6 +1410,10 @@ const proxyHandler = {
|
|
|
1191
1410
|
const value = getNodeValue(node);
|
|
1192
1411
|
return Reflect.has(value, prop);
|
|
1193
1412
|
},
|
|
1413
|
+
apply(target, thisArg, argArray) {
|
|
1414
|
+
// If it's a function call it as a function
|
|
1415
|
+
return Reflect.apply(target, thisArg, argArray);
|
|
1416
|
+
},
|
|
1194
1417
|
};
|
|
1195
1418
|
function set(node, newValue) {
|
|
1196
1419
|
if (node.parent) {
|
|
@@ -1216,12 +1439,14 @@ function setKey(node, key, newValue, level) {
|
|
|
1216
1439
|
console.warn(`[legend-state] Set an HTMLElement into state. You probably don't want to do that.`);
|
|
1217
1440
|
}
|
|
1218
1441
|
}
|
|
1442
|
+
const isRoot = !node.parent && key === '_';
|
|
1443
|
+
// TODOv3 root locking will be removed with old computeds
|
|
1219
1444
|
if (node.root.locked && !node.root.set) {
|
|
1220
1445
|
// This happens when modifying a locked observable such as a computed.
|
|
1221
1446
|
// If merging this could be happening deep in a hierarchy so we don't want to throw errors so we'll just do nothing.
|
|
1222
1447
|
// This could happen during persistence local load for example.
|
|
1223
1448
|
if (globalState.isMerging) {
|
|
1224
|
-
return;
|
|
1449
|
+
return isRoot ? getProxy(node) : getProxy(node, key);
|
|
1225
1450
|
}
|
|
1226
1451
|
else {
|
|
1227
1452
|
throw new Error(process.env.NODE_ENV === 'development'
|
|
@@ -1229,9 +1454,11 @@ function setKey(node, key, newValue, level) {
|
|
|
1229
1454
|
: '[legend-state] Modified locked observable');
|
|
1230
1455
|
}
|
|
1231
1456
|
}
|
|
1232
|
-
|
|
1457
|
+
if (node.parent && !getNodeValue(node)) {
|
|
1458
|
+
return set(node, { [key]: newValue });
|
|
1459
|
+
}
|
|
1233
1460
|
// Get the child node for updating and notifying
|
|
1234
|
-
const childNode = isRoot ? node : getChildNode(node, key);
|
|
1461
|
+
const childNode = isRoot ? node : getChildNode(node, key, isFunction(newValue) ? newValue : undefined);
|
|
1235
1462
|
// Set the raw value on the parent object
|
|
1236
1463
|
const { newValue: savedValue, prevValue, parentValue } = setNodeValue(childNode, newValue);
|
|
1237
1464
|
const isFunc = isFunction(savedValue);
|
|
@@ -1347,9 +1574,6 @@ function updateNodesAndNotify(node, newValue, prevValue, childNode, isPrim, isRo
|
|
|
1347
1574
|
childNode = node;
|
|
1348
1575
|
// Make sure we don't call too many listeners for ever property set
|
|
1349
1576
|
beginBatch();
|
|
1350
|
-
if (isPrim === undefined) {
|
|
1351
|
-
isPrim = isPrimitive(newValue);
|
|
1352
|
-
}
|
|
1353
1577
|
let hasADiff = isPrim;
|
|
1354
1578
|
let whenOptimizedOnlyIf = false;
|
|
1355
1579
|
// If new value is an object or array update notify down the tree
|
|
@@ -1369,27 +1593,36 @@ function updateNodesAndNotify(node, newValue, prevValue, childNode, isPrim, isRo
|
|
|
1369
1593
|
}
|
|
1370
1594
|
endBatch();
|
|
1371
1595
|
}
|
|
1372
|
-
function extractPromise(node, value) {
|
|
1596
|
+
function extractPromise(node, value, setter, handleError) {
|
|
1373
1597
|
if (!node.state) {
|
|
1374
1598
|
node.state = createObservable({
|
|
1375
1599
|
isLoaded: false,
|
|
1376
|
-
}, false, getProxy);
|
|
1600
|
+
}, false, extractPromise, getProxy);
|
|
1377
1601
|
}
|
|
1378
1602
|
value
|
|
1379
1603
|
.then((value) => {
|
|
1380
|
-
set(node, value);
|
|
1381
|
-
node.state.
|
|
1604
|
+
setter ? setter({ value }) : set(node, value);
|
|
1605
|
+
node.state.assign({
|
|
1606
|
+
isLoaded: true,
|
|
1607
|
+
error: undefined,
|
|
1608
|
+
});
|
|
1382
1609
|
})
|
|
1383
1610
|
.catch((error) => {
|
|
1384
1611
|
node.state.error.set(error);
|
|
1612
|
+
if (handleError) {
|
|
1613
|
+
handleError(error);
|
|
1614
|
+
}
|
|
1385
1615
|
});
|
|
1386
1616
|
}
|
|
1387
1617
|
function extractFunctionOrComputed(node, obj, k, v) {
|
|
1388
1618
|
if (isPromise(v)) {
|
|
1389
|
-
|
|
1619
|
+
const childNode = getChildNode(node, k);
|
|
1620
|
+
extractPromise(childNode, v);
|
|
1621
|
+
setNodeValue(childNode, undefined);
|
|
1390
1622
|
}
|
|
1391
1623
|
else if (typeof v === 'function') {
|
|
1392
1624
|
extractFunction(node, k, v);
|
|
1625
|
+
delete obj[k];
|
|
1393
1626
|
}
|
|
1394
1627
|
else if (typeof v == 'object' && v !== null && v !== undefined) {
|
|
1395
1628
|
const childNode = getNode(v);
|
|
@@ -1409,10 +1642,19 @@ function get(node, options) {
|
|
|
1409
1642
|
return peek(node);
|
|
1410
1643
|
}
|
|
1411
1644
|
function peek(node) {
|
|
1412
|
-
|
|
1645
|
+
if (node.dirtyFn) {
|
|
1646
|
+
node.dirtyFn();
|
|
1647
|
+
globalState.dirtyNodes.delete(node);
|
|
1648
|
+
node.dirtyFn = undefined;
|
|
1649
|
+
}
|
|
1650
|
+
let value = getNodeValue(node);
|
|
1413
1651
|
// If node is not yet lazily computed go do that
|
|
1414
|
-
|
|
1652
|
+
const lazy = node.lazy;
|
|
1653
|
+
if (lazy) {
|
|
1415
1654
|
delete node.lazy;
|
|
1655
|
+
if (isFunction(node) || isFunction(lazy)) {
|
|
1656
|
+
value = activateNodeFunction(node, lazy);
|
|
1657
|
+
}
|
|
1416
1658
|
for (const key in value) {
|
|
1417
1659
|
if (hasOwnProperty.call(value, key)) {
|
|
1418
1660
|
extractFunctionOrComputed(node, value, key, value[key]);
|
|
@@ -1423,6 +1665,265 @@ function peek(node) {
|
|
|
1423
1665
|
checkActivate(node);
|
|
1424
1666
|
return value;
|
|
1425
1667
|
}
|
|
1668
|
+
function activateNodeFunction(node, lazyFn) {
|
|
1669
|
+
// let prevTarget$: Observable<any>;
|
|
1670
|
+
// let curTarget$: Observable<any>;
|
|
1671
|
+
let update;
|
|
1672
|
+
let wasPromise;
|
|
1673
|
+
let timeoutRetry;
|
|
1674
|
+
const attemptNum = { current: 0 };
|
|
1675
|
+
const activateFn = (isFunction(node) ? node : lazyFn);
|
|
1676
|
+
const doRetry = () => { var _a; return (_a = node.state) === null || _a === void 0 ? void 0 : _a.refreshNum.set((v) => v + 1); };
|
|
1677
|
+
let activatedValue;
|
|
1678
|
+
let disposes = [];
|
|
1679
|
+
let refreshFn;
|
|
1680
|
+
function markDirty() {
|
|
1681
|
+
node.dirtyFn = refreshFn;
|
|
1682
|
+
globalState.dirtyNodes.add(node);
|
|
1683
|
+
}
|
|
1684
|
+
observe(() => {
|
|
1685
|
+
var _a, _b, _c, _d;
|
|
1686
|
+
// const params = createNodeActivationParams(node);
|
|
1687
|
+
// Run the function at this node
|
|
1688
|
+
let value = activateFn();
|
|
1689
|
+
// If target is an observable, make this node a link to it
|
|
1690
|
+
if (isObservable(value)) {
|
|
1691
|
+
// If the computed is a proxy to another observable
|
|
1692
|
+
// link it to the target observable
|
|
1693
|
+
const linkedNode = getNode(value);
|
|
1694
|
+
const prevNode = node.linkedToNode;
|
|
1695
|
+
node.linkedToNode = linkedNode;
|
|
1696
|
+
if (!linkedNode.linkedFromNodes) {
|
|
1697
|
+
linkedNode.linkedFromNodes = new Set();
|
|
1698
|
+
}
|
|
1699
|
+
linkedNode.linkedFromNodes.add(node);
|
|
1700
|
+
onChange(linkedNode, ({ value: newValue }) => {
|
|
1701
|
+
value = newValue;
|
|
1702
|
+
set(node, value);
|
|
1703
|
+
}, { initial: true });
|
|
1704
|
+
// If the target observable is different then notify for the change
|
|
1705
|
+
if (prevNode) {
|
|
1706
|
+
const value = getNodeValue(linkedNode);
|
|
1707
|
+
const prevValue = getNodeValue(prevNode);
|
|
1708
|
+
notify(node, value, prevValue, 0);
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
if (isFunction(value)) {
|
|
1712
|
+
value = value();
|
|
1713
|
+
}
|
|
1714
|
+
const activated = value === null || value === void 0 ? void 0 : value[symbolActivated];
|
|
1715
|
+
if (activated) {
|
|
1716
|
+
node.activationState = activated;
|
|
1717
|
+
value = activated.initial;
|
|
1718
|
+
}
|
|
1719
|
+
wasPromise = isPromise(value);
|
|
1720
|
+
// Activate this node if not activated already (may be called recursively)
|
|
1721
|
+
// TODO: Is calling recursively bad? If so can it be fixed?
|
|
1722
|
+
if (!node.activated) {
|
|
1723
|
+
node.activated = true;
|
|
1724
|
+
const isCached = !!((_a = node.activationState) === null || _a === void 0 ? void 0 : _a.cache);
|
|
1725
|
+
wasPromise = wasPromise || !!isCached;
|
|
1726
|
+
const activateNodeFn = wasPromise ? globalState.activateNode : activateNodeBase;
|
|
1727
|
+
const { update: newUpdate, value: newValue } = activateNodeFn(node, doRetry, !!wasPromise, value);
|
|
1728
|
+
update = newUpdate;
|
|
1729
|
+
value = newValue;
|
|
1730
|
+
}
|
|
1731
|
+
else if (node.activationState) {
|
|
1732
|
+
if (!node.activationState.persistedRetry) {
|
|
1733
|
+
const activated = node.activationState;
|
|
1734
|
+
value = (_c = (_b = activated.get) === null || _b === void 0 ? void 0 : _b.call(activated, {})) !== null && _c !== void 0 ? _c : activated.initial;
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
wasPromise = wasPromise || isPromise(value);
|
|
1738
|
+
get(getNode((_d = node.state) === null || _d === void 0 ? void 0 : _d.refreshNum));
|
|
1739
|
+
return value;
|
|
1740
|
+
}, (e) => {
|
|
1741
|
+
const { value, nodes, refresh } = e;
|
|
1742
|
+
refreshFn = refresh;
|
|
1743
|
+
if (!globalState.isLoadingRemote$.peek()) {
|
|
1744
|
+
if (wasPromise) {
|
|
1745
|
+
if (node.activationState) {
|
|
1746
|
+
const { retry, initial } = node.activationState;
|
|
1747
|
+
let onError;
|
|
1748
|
+
if (retry) {
|
|
1749
|
+
if (timeoutRetry === null || timeoutRetry === void 0 ? void 0 : timeoutRetry.current) {
|
|
1750
|
+
clearTimeout(timeoutRetry.current);
|
|
1751
|
+
}
|
|
1752
|
+
const { handleError, timeout } = setupRetry(retry, doRetry, attemptNum);
|
|
1753
|
+
onError = handleError;
|
|
1754
|
+
timeoutRetry = timeout;
|
|
1755
|
+
node.activationState.onError = onError;
|
|
1756
|
+
}
|
|
1757
|
+
if (value && isPromise(value)) {
|
|
1758
|
+
// Extract the promise to make it set the value/error when it comes in
|
|
1759
|
+
extractPromise(node, value, update, onError);
|
|
1760
|
+
}
|
|
1761
|
+
// Set this to undefined only if it's replacing the activation function,
|
|
1762
|
+
// so we don't overwrite it if it already has real data from either local
|
|
1763
|
+
// cache or a previous run
|
|
1764
|
+
if (isFunction(getNodeValue(node))) {
|
|
1765
|
+
setNodeValue(node, initial !== null && initial !== void 0 ? initial : undefined);
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
else if (node.activated) {
|
|
1769
|
+
let onError;
|
|
1770
|
+
// Extract the promise to make it set the value/error when it comes in
|
|
1771
|
+
extractPromise(node, value, update, onError);
|
|
1772
|
+
// Set this to undefined only if it's replacing the activation function,
|
|
1773
|
+
// so we don't overwrite it if it already has real data from either local
|
|
1774
|
+
// cache or a previous run
|
|
1775
|
+
if (isFunction(getNodeValue(node))) {
|
|
1776
|
+
setNodeValue(node, undefined);
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
else {
|
|
1781
|
+
activatedValue = value;
|
|
1782
|
+
set(node, value);
|
|
1783
|
+
node.state.assign({
|
|
1784
|
+
isLoaded: true,
|
|
1785
|
+
error: undefined,
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
disposes.forEach((fn) => fn());
|
|
1790
|
+
disposes = [];
|
|
1791
|
+
nodes === null || nodes === void 0 ? void 0 : nodes.forEach(({ node }) => {
|
|
1792
|
+
disposes.push(onChange(node, markDirty, { immediate: true }));
|
|
1793
|
+
});
|
|
1794
|
+
e.cancel = true;
|
|
1795
|
+
}, { fromComputed: true });
|
|
1796
|
+
return activatedValue;
|
|
1797
|
+
}
|
|
1798
|
+
const activateNodeBase = (globalState.activateNode = function activateNodeBase(node, refresh, wasPromise, value) {
|
|
1799
|
+
if (!node.state) {
|
|
1800
|
+
node.state = createObservable({
|
|
1801
|
+
isLoaded: false,
|
|
1802
|
+
}, false, extractPromise, getProxy);
|
|
1803
|
+
}
|
|
1804
|
+
let isSetting = false;
|
|
1805
|
+
let isSettingFromSubscribe = false;
|
|
1806
|
+
let _mode = 'set';
|
|
1807
|
+
if (node.activationState) {
|
|
1808
|
+
const { onSet, subscribe, get: getFn, initial, retry, waitFor } = node.activationState;
|
|
1809
|
+
// @ts-expect-error asdf
|
|
1810
|
+
const run = () => getFn({ updateLastSync: noop, setMode: (mode) => (_mode = mode) });
|
|
1811
|
+
value = getFn
|
|
1812
|
+
? waitFor
|
|
1813
|
+
? new Promise((resolve) => {
|
|
1814
|
+
whenReady(waitFor, () => {
|
|
1815
|
+
resolve(run());
|
|
1816
|
+
});
|
|
1817
|
+
})
|
|
1818
|
+
: run()
|
|
1819
|
+
: undefined;
|
|
1820
|
+
if (value == undefined || value === null) {
|
|
1821
|
+
value = initial;
|
|
1822
|
+
}
|
|
1823
|
+
let timeoutRetry;
|
|
1824
|
+
if (onSet) {
|
|
1825
|
+
let allChanges = [];
|
|
1826
|
+
let latestValue = undefined;
|
|
1827
|
+
const runChanges = (listenerParams) => {
|
|
1828
|
+
// Don't call the set if this is the first value coming in
|
|
1829
|
+
if (allChanges.length > 0) {
|
|
1830
|
+
let changes;
|
|
1831
|
+
let value;
|
|
1832
|
+
if (listenerParams) {
|
|
1833
|
+
changes = listenerParams.changes;
|
|
1834
|
+
value = listenerParams.value;
|
|
1835
|
+
}
|
|
1836
|
+
else {
|
|
1837
|
+
// If this is called by flushPending then get the change array
|
|
1838
|
+
// that we've been building up.
|
|
1839
|
+
changes = allChanges;
|
|
1840
|
+
value = latestValue;
|
|
1841
|
+
}
|
|
1842
|
+
allChanges = [];
|
|
1843
|
+
latestValue = undefined;
|
|
1844
|
+
globalState.pendingNodes.delete(node);
|
|
1845
|
+
const attemptNum = { current: 0 };
|
|
1846
|
+
const run = () => {
|
|
1847
|
+
let onError;
|
|
1848
|
+
if (retry) {
|
|
1849
|
+
if (timeoutRetry === null || timeoutRetry === void 0 ? void 0 : timeoutRetry.current) {
|
|
1850
|
+
clearTimeout(timeoutRetry.current);
|
|
1851
|
+
}
|
|
1852
|
+
const { handleError, timeout } = setupRetry(retry, run, attemptNum);
|
|
1853
|
+
onError = handleError;
|
|
1854
|
+
timeoutRetry = timeout;
|
|
1855
|
+
}
|
|
1856
|
+
isSetting = true;
|
|
1857
|
+
batch(() => onSet({
|
|
1858
|
+
value,
|
|
1859
|
+
changes,
|
|
1860
|
+
getPrevious: () => {
|
|
1861
|
+
// TODO
|
|
1862
|
+
// debugger;
|
|
1863
|
+
},
|
|
1864
|
+
}, {
|
|
1865
|
+
node,
|
|
1866
|
+
update,
|
|
1867
|
+
refresh,
|
|
1868
|
+
onError,
|
|
1869
|
+
fromSubscribe: isSettingFromSubscribe,
|
|
1870
|
+
}), () => {
|
|
1871
|
+
isSetting = false;
|
|
1872
|
+
});
|
|
1873
|
+
};
|
|
1874
|
+
run();
|
|
1875
|
+
}
|
|
1876
|
+
};
|
|
1877
|
+
const onChangeImmediate = ({ value, changes }) => {
|
|
1878
|
+
if (!isSetting || isSettingFromSubscribe) {
|
|
1879
|
+
if (get(getNode(node.state.isLoaded)) &&
|
|
1880
|
+
(changes.length > 1 || !isFunction(changes[0].prevAtPath))) {
|
|
1881
|
+
latestValue = value;
|
|
1882
|
+
allChanges.push(...changes);
|
|
1883
|
+
globalState.pendingNodes.set(node, runChanges);
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
};
|
|
1887
|
+
// Create an immediate listener to mark this node as pending. Then actually run
|
|
1888
|
+
// the changes at the end of the batch so everything is properly batched.
|
|
1889
|
+
// However, this can be short circuited if the user calls get() or peek()
|
|
1890
|
+
// in which case the set needs to run immediately so that the values are up to date.
|
|
1891
|
+
onChange(node, onChangeImmediate, { immediate: true });
|
|
1892
|
+
onChange(node, runChanges);
|
|
1893
|
+
}
|
|
1894
|
+
if (process.env.NODE_ENV === 'development' && node.activationState.cache) {
|
|
1895
|
+
// TODO Better message
|
|
1896
|
+
console.log('[legend-state] Using cache without setting up persistence first');
|
|
1897
|
+
}
|
|
1898
|
+
if (process.env.NODE_ENV === 'development' && node.activationState.retry) {
|
|
1899
|
+
// TODO Better message
|
|
1900
|
+
console.log('[legend-state] Using retry without setting up persistence first');
|
|
1901
|
+
}
|
|
1902
|
+
if (subscribe) {
|
|
1903
|
+
const updateFromSubscribe = (params) => {
|
|
1904
|
+
isSettingFromSubscribe = true;
|
|
1905
|
+
update(params);
|
|
1906
|
+
isSettingFromSubscribe = false;
|
|
1907
|
+
};
|
|
1908
|
+
subscribe({ node, update: updateFromSubscribe, refresh });
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
const update = ({ value, mode }) => {
|
|
1912
|
+
// TODO: This isSetting might not be necessary? Tests still work if removing it.
|
|
1913
|
+
// Write tests that would break it if removed? I'd guess a combination of subscribe and
|
|
1914
|
+
if (!isSetting) {
|
|
1915
|
+
isSetting = true;
|
|
1916
|
+
if (_mode === 'assign' || mode === 'assign') {
|
|
1917
|
+
assign(node, value);
|
|
1918
|
+
}
|
|
1919
|
+
else {
|
|
1920
|
+
set(node, value);
|
|
1921
|
+
}
|
|
1922
|
+
isSetting = false;
|
|
1923
|
+
}
|
|
1924
|
+
};
|
|
1925
|
+
return { update, value };
|
|
1926
|
+
});
|
|
1426
1927
|
|
|
1427
1928
|
const fns = ['get', 'set', 'peek', 'onChange', 'toggle'];
|
|
1428
1929
|
function ObservablePrimitiveClass(node) {
|
|
@@ -1439,8 +1940,14 @@ function proto(key, fn) {
|
|
|
1439
1940
|
return fn.call(this, this._node, ...args);
|
|
1440
1941
|
};
|
|
1441
1942
|
}
|
|
1442
|
-
proto('peek',
|
|
1443
|
-
|
|
1943
|
+
proto('peek', (node) => {
|
|
1944
|
+
flushPending();
|
|
1945
|
+
return peek(node);
|
|
1946
|
+
});
|
|
1947
|
+
proto('get', (node, options) => {
|
|
1948
|
+
flushPending();
|
|
1949
|
+
return get(node, options);
|
|
1950
|
+
});
|
|
1444
1951
|
proto('set', set);
|
|
1445
1952
|
proto('onChange', onChange);
|
|
1446
1953
|
// Getters
|
|
@@ -1466,121 +1973,12 @@ ObservablePrimitiveClass.prototype.delete = function () {
|
|
|
1466
1973
|
};
|
|
1467
1974
|
|
|
1468
1975
|
function observable(value) {
|
|
1469
|
-
return createObservable(value, false, getProxy, ObservablePrimitiveClass);
|
|
1976
|
+
return createObservable(value, false, extractPromise, getProxy, ObservablePrimitiveClass);
|
|
1470
1977
|
}
|
|
1471
1978
|
function observablePrimitive(value) {
|
|
1472
|
-
return createObservable(value, true, getProxy, ObservablePrimitiveClass);
|
|
1473
|
-
}
|
|
1474
|
-
|
|
1475
|
-
function setupTracking(nodes, update, noArgs, immediate) {
|
|
1476
|
-
let listeners = [];
|
|
1477
|
-
// Listen to tracked nodes
|
|
1478
|
-
nodes === null || nodes === void 0 ? void 0 : nodes.forEach((tracked) => {
|
|
1479
|
-
const { node, track } = tracked;
|
|
1480
|
-
listeners.push(onChange(node, update, { trackingType: track, immediate, noArgs }));
|
|
1481
|
-
});
|
|
1482
|
-
return () => {
|
|
1483
|
-
if (listeners) {
|
|
1484
|
-
for (let i = 0; i < listeners.length; i++) {
|
|
1485
|
-
listeners[i]();
|
|
1486
|
-
}
|
|
1487
|
-
listeners = undefined;
|
|
1488
|
-
}
|
|
1489
|
-
};
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
|
-
function trackSelector(selector, update, observeEvent, observeOptions, createResubscribe) {
|
|
1493
|
-
var _a;
|
|
1494
|
-
let nodes;
|
|
1495
|
-
let value;
|
|
1496
|
-
let dispose;
|
|
1497
|
-
let tracker;
|
|
1498
|
-
let resubscribe;
|
|
1499
|
-
let updateFn = update;
|
|
1500
|
-
if (isObservable(selector)) {
|
|
1501
|
-
value = selector.peek();
|
|
1502
|
-
dispose = selector.onChange(update);
|
|
1503
|
-
resubscribe = createResubscribe ? selector.onChange(update) : undefined;
|
|
1504
|
-
}
|
|
1505
|
-
else {
|
|
1506
|
-
// Compute the selector inside a tracking context
|
|
1507
|
-
beginTracking();
|
|
1508
|
-
value = selector ? computeSelector(selector, observeEvent, observeOptions === null || observeOptions === void 0 ? void 0 : observeOptions.fromComputed) : selector;
|
|
1509
|
-
tracker = tracking.current;
|
|
1510
|
-
nodes = tracker.nodes;
|
|
1511
|
-
endTracking();
|
|
1512
|
-
if ((process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') && tracker && nodes) {
|
|
1513
|
-
(_a = tracker.traceListeners) === null || _a === void 0 ? void 0 : _a.call(tracker, nodes);
|
|
1514
|
-
if (tracker.traceUpdates) {
|
|
1515
|
-
updateFn = tracker.traceUpdates(update);
|
|
1516
|
-
}
|
|
1517
|
-
// Clear tracing so it doesn't leak to other components
|
|
1518
|
-
tracker.traceListeners = undefined;
|
|
1519
|
-
tracker.traceUpdates = undefined;
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
if (!(observeEvent === null || observeEvent === void 0 ? void 0 : observeEvent.cancel)) {
|
|
1523
|
-
// Do tracing if it was requested
|
|
1524
|
-
// useSyncExternalStore doesn't subscribe until after the component mount.
|
|
1525
|
-
// We want to subscribe immediately so we don't miss any updates
|
|
1526
|
-
dispose = setupTracking(nodes, updateFn, false, observeOptions === null || observeOptions === void 0 ? void 0 : observeOptions.immediate);
|
|
1527
|
-
resubscribe = createResubscribe ? () => setupTracking(nodes, updateFn) : undefined;
|
|
1528
|
-
}
|
|
1529
|
-
return { value, dispose, resubscribe };
|
|
1530
|
-
}
|
|
1531
|
-
|
|
1532
|
-
function observe(selectorOrRun, reactionOrOptions, options) {
|
|
1533
|
-
let reaction;
|
|
1534
|
-
if (isFunction(reactionOrOptions)) {
|
|
1535
|
-
reaction = reactionOrOptions;
|
|
1536
|
-
}
|
|
1537
|
-
else {
|
|
1538
|
-
options = reactionOrOptions;
|
|
1539
|
-
}
|
|
1540
|
-
let dispose;
|
|
1541
|
-
const e = { num: 0 };
|
|
1542
|
-
// Wrap it in a function so it doesn't pass all the arguments to run()
|
|
1543
|
-
const update = function () {
|
|
1544
|
-
if (e.onCleanup) {
|
|
1545
|
-
e.onCleanup();
|
|
1546
|
-
e.onCleanup = undefined;
|
|
1547
|
-
}
|
|
1548
|
-
// Run in a batch so changes don't happen until we're done tracking here
|
|
1549
|
-
beginBatch();
|
|
1550
|
-
// Run the function/selector
|
|
1551
|
-
delete e.value;
|
|
1552
|
-
// Dispose listeners from previous run
|
|
1553
|
-
dispose === null || dispose === void 0 ? void 0 : dispose();
|
|
1554
|
-
const { dispose: _dispose, value } = trackSelector(selectorOrRun, update, e, options);
|
|
1555
|
-
dispose = _dispose;
|
|
1556
|
-
e.value = value;
|
|
1557
|
-
if (e.onCleanupReaction) {
|
|
1558
|
-
e.onCleanupReaction();
|
|
1559
|
-
e.onCleanupReaction = undefined;
|
|
1560
|
-
}
|
|
1561
|
-
endBatch();
|
|
1562
|
-
// Call the reaction if there is one and the value changed
|
|
1563
|
-
if (reaction &&
|
|
1564
|
-
(e.num > 0 || !isEvent(selectorOrRun)) &&
|
|
1565
|
-
(e.previous !== e.value || (options === null || options === void 0 ? void 0 : options.fromComputed))) {
|
|
1566
|
-
reaction(e);
|
|
1567
|
-
}
|
|
1568
|
-
// Update the previous value
|
|
1569
|
-
e.previous = e.value;
|
|
1570
|
-
// Increment the counter
|
|
1571
|
-
e.num++;
|
|
1572
|
-
};
|
|
1573
|
-
update();
|
|
1574
|
-
// Return function calling dispose because dispose may be changed in update()
|
|
1575
|
-
return () => {
|
|
1576
|
-
var _a, _b;
|
|
1577
|
-
(_a = e.onCleanup) === null || _a === void 0 ? void 0 : _a.call(e);
|
|
1578
|
-
e.onCleanup = undefined;
|
|
1579
|
-
(_b = e.onCleanupReaction) === null || _b === void 0 ? void 0 : _b.call(e);
|
|
1580
|
-
e.onCleanupReaction = undefined;
|
|
1581
|
-
dispose === null || dispose === void 0 ? void 0 : dispose();
|
|
1582
|
-
};
|
|
1979
|
+
return createObservable(value, true, extractPromise, getProxy, ObservablePrimitiveClass);
|
|
1583
1980
|
}
|
|
1981
|
+
globalState.isLoadingRemote$ = observable(false);
|
|
1584
1982
|
|
|
1585
1983
|
function computed(compute, set$1) {
|
|
1586
1984
|
// Create an observable for this computed variable
|
|
@@ -1744,80 +2142,23 @@ function proxy(get, set) {
|
|
|
1744
2142
|
return obs;
|
|
1745
2143
|
}
|
|
1746
2144
|
|
|
1747
|
-
function _when(predicate, effect, checkReady) {
|
|
1748
|
-
// If predicate is a regular Promise skip all the observable stuff
|
|
1749
|
-
if (isPromise(predicate)) {
|
|
1750
|
-
return effect ? predicate.then(effect) : predicate;
|
|
1751
|
-
}
|
|
1752
|
-
let value;
|
|
1753
|
-
// Create a wrapping fn that calls the effect if predicate returns true
|
|
1754
|
-
function run(e) {
|
|
1755
|
-
const ret = computeSelector(predicate);
|
|
1756
|
-
if (!isPromise(ret) && (checkReady ? isObservableValueReady(ret) : ret)) {
|
|
1757
|
-
value = ret;
|
|
1758
|
-
// Set cancel so that observe does not track anymore
|
|
1759
|
-
e.cancel = true;
|
|
1760
|
-
}
|
|
1761
|
-
return value;
|
|
1762
|
-
}
|
|
1763
|
-
function doEffect() {
|
|
1764
|
-
// If value is truthy then run the effect
|
|
1765
|
-
effect === null || effect === void 0 ? void 0 : effect(value);
|
|
1766
|
-
}
|
|
1767
|
-
// Run in an observe
|
|
1768
|
-
observe(run, doEffect);
|
|
1769
|
-
// If first run resulted in a truthy value just return it.
|
|
1770
|
-
// It will have set e.cancel so no need to dispose
|
|
1771
|
-
if (isPromise(value)) {
|
|
1772
|
-
return effect ? value.then(effect) : value;
|
|
1773
|
-
}
|
|
1774
|
-
else if (value !== undefined) {
|
|
1775
|
-
return Promise.resolve(value);
|
|
1776
|
-
}
|
|
1777
|
-
else {
|
|
1778
|
-
// Wrap it in a promise
|
|
1779
|
-
const promise = new Promise((resolve) => {
|
|
1780
|
-
if (effect) {
|
|
1781
|
-
const originalEffect = effect;
|
|
1782
|
-
effect = (value) => {
|
|
1783
|
-
const effectValue = originalEffect(value);
|
|
1784
|
-
resolve(effectValue);
|
|
1785
|
-
};
|
|
1786
|
-
}
|
|
1787
|
-
else {
|
|
1788
|
-
effect = resolve;
|
|
1789
|
-
}
|
|
1790
|
-
});
|
|
1791
|
-
return promise;
|
|
1792
|
-
}
|
|
1793
|
-
}
|
|
1794
|
-
function when(predicate, effect) {
|
|
1795
|
-
return _when(predicate, effect, false);
|
|
1796
|
-
}
|
|
1797
|
-
function whenReady(predicate, effect) {
|
|
1798
|
-
return _when(predicate, effect, true);
|
|
1799
|
-
}
|
|
1800
|
-
|
|
1801
2145
|
const internal = {
|
|
1802
|
-
clone,
|
|
1803
2146
|
ensureNodeValue,
|
|
1804
2147
|
findIDKey,
|
|
1805
2148
|
get,
|
|
1806
2149
|
getNode,
|
|
1807
|
-
getPathType,
|
|
1808
2150
|
getProxy,
|
|
1809
2151
|
globalState,
|
|
1810
|
-
initializePathType,
|
|
1811
2152
|
observableFns,
|
|
1812
2153
|
optimized,
|
|
1813
2154
|
peek,
|
|
1814
|
-
safeParse,
|
|
1815
|
-
safeStringify,
|
|
1816
2155
|
set,
|
|
1817
2156
|
setAtPath,
|
|
1818
2157
|
setNodeValue,
|
|
2158
|
+
setupRetry,
|
|
2159
|
+
symbolActivated,
|
|
1819
2160
|
symbolDelete,
|
|
1820
2161
|
};
|
|
1821
2162
|
|
|
1822
|
-
export { ObservablePrimitiveClass, batch, beginBatch, beginTracking, checkActivate, computeSelector, computed, configureLegendState, constructObjectWithPath, deconstructObjectWithPath, endBatch, endTracking, event, extraPrimitiveActivators, extraPrimitiveProps, findIDKey, getNode, getNodeValue, getObservableIndex, hasOwnProperty, internal, isArray, isBoolean, isEmpty, isFunction, isObject, isObservable, isObservableValueReady, isPrimitive, isPromise, isString, isSymbol, lockObservable, mergeIntoObservable, observable, observablePrimitive, observe, opaqueObject, optimized, proxy, setAtPath, setInObservableAtPath, setSilently, setupTracking, symbolDelete, trackSelector, tracking, updateTracking, when, whenReady };
|
|
2163
|
+
export { ObservablePrimitiveClass, activated, batch, beginBatch, beginTracking, checkActivate, computeSelector, computed, configureLegendState, constructObjectWithPath, deconstructObjectWithPath, endBatch, endTracking, event, extraPrimitiveActivators, extraPrimitiveProps, findIDKey, getNode, getNodeValue, getObservableIndex, hasOwnProperty, internal, isArray, isBoolean, isEmpty, isFunction, isObject, isObservable, isObservableValueReady, isPrimitive, isPromise, isString, isSymbol, lockObservable, mergeIntoObservable, observable, observablePrimitive, observe, opaqueObject, optimized, proxy, setAtPath, setInObservableAtPath, setSilently, setupTracking, symbolDelete, trackSelector, tracking, updateTracking, when, whenReady };
|
|
1823
2164
|
//# sourceMappingURL=index.mjs.map
|