@legendapp/state 2.2.0-next.2 → 2.2.0-next.21
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/babel.js.map +1 -1
- package/config/enableDirectAccess.d.ts +1 -1
- package/config/enableDirectPeek.d.ts +1 -1
- package/config/enableReactDirectRender.js.map +1 -1
- package/config/enableReactDirectRender.mjs.map +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/pageHash.js.map +1 -1
- package/helpers/pageHash.mjs.map +1 -1
- package/helpers/pageHashParams.js.map +1 -1
- package/helpers/pageHashParams.mjs.map +1 -1
- package/helpers/time.d.ts +2 -2
- package/helpers/time.js.map +1 -1
- package/helpers/time.mjs.map +1 -1
- package/history.js.map +1 -1
- package/history.mjs.map +1 -1
- package/index.d.ts +14 -9
- package/index.js +522 -226
- package/index.js.map +1 -1
- package/index.mjs +521 -227
- package/index.mjs.map +1 -1
- package/package.json +2 -10
- package/persist-plugins/async-storage.js.map +1 -1
- package/persist-plugins/async-storage.mjs.map +1 -1
- package/persist-plugins/fetch.js.map +1 -1
- package/persist-plugins/fetch.mjs.map +1 -1
- package/persist-plugins/firebase.js +3 -3
- package/persist-plugins/firebase.js.map +1 -1
- package/persist-plugins/firebase.mjs +3 -3
- package/persist-plugins/firebase.mjs.map +1 -1
- package/persist-plugins/indexeddb.js.map +1 -1
- package/persist-plugins/indexeddb.mjs.map +1 -1
- package/persist-plugins/local-storage.js +1 -1
- package/persist-plugins/local-storage.js.map +1 -1
- package/persist-plugins/local-storage.mjs +1 -1
- package/persist-plugins/local-storage.mjs.map +1 -1
- package/persist-plugins/mmkv.js.map +1 -1
- package/persist-plugins/mmkv.mjs.map +1 -1
- package/persist-plugins/query.js.map +1 -1
- package/persist-plugins/query.mjs.map +1 -1
- package/persist.d.ts +16 -1
- package/persist.js +406 -138
- package/persist.js.map +1 -1
- package/persist.mjs +407 -139
- 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/useHover.js.map +1 -1
- package/react-hooks/useHover.mjs.map +1 -1
- package/react-hooks/useMeasure.js.map +1 -1
- package/react-hooks/useMeasure.mjs.map +1 -1
- package/react-hooks/useObservableNextRouter.js.map +1 -1
- package/react-hooks/useObservableNextRouter.mjs.map +1 -1
- package/react-hooks/useObservableQuery.js.map +1 -1
- package/react-hooks/useObservableQuery.mjs.map +1 -1
- package/react-hooks/usePersistedObservable.d.ts +2 -2
- package/react-hooks/usePersistedObservable.js +3 -3
- package/react-hooks/usePersistedObservable.js.map +1 -1
- package/react-hooks/usePersistedObservable.mjs +3 -3
- package/react-hooks/usePersistedObservable.mjs.map +1 -1
- package/react.js +13 -8
- package/react.js.map +1 -1
- package/react.mjs +14 -9
- 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/batching.d.ts +3 -1
- 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 +10 -9
- package/src/helpers/fetch.d.ts +4 -3
- package/src/helpers/time.d.ts +2 -2
- package/src/helpers.d.ts +3 -2
- package/src/history/trackHistory.d.ts +1 -1
- package/src/observable.d.ts +6 -15
- package/src/observableInterfaces.d.ts +68 -315
- package/src/observableTypes.d.ts +93 -0
- package/src/persist/observablePersistRemoteFunctionsAdapter.d.ts +1 -1
- package/src/persist/persistActivateNode.d.ts +1 -0
- package/src/persist/persistHelpers.d.ts +1 -1
- package/src/persist/persistObservable.d.ts +3 -3
- package/src/persistTypes.d.ts +229 -0
- package/src/proxy.d.ts +2 -1
- package/src/react/Computed.d.ts +1 -1
- package/src/react/Switch.d.ts +3 -3
- package/src/react/reactInterfaces.d.ts +2 -1
- package/src/react/usePauseProvider.d.ts +3 -3
- package/src/react/useWhen.d.ts +2 -2
- package/src/react-hooks/useFetch.d.ts +4 -3
- package/src/react-hooks/usePersistedObservable.d.ts +2 -2
- package/src/retry.d.ts +4 -0
- package/src/trackSelector.d.ts +3 -2
- package/src/when.d.ts +6 -2
- package/trace.js.map +1 -1
- package/trace.mjs.map +1 -1
package/index.mjs
CHANGED
|
@@ -6,7 +6,7 @@ function isString(obj) {
|
|
|
6
6
|
return typeof obj === 'string';
|
|
7
7
|
}
|
|
8
8
|
function isObject(obj) {
|
|
9
|
-
return !!obj && typeof obj === 'object' && !isArray(obj);
|
|
9
|
+
return !!obj && typeof obj === 'object' && !(obj instanceof Date) && !isArray(obj);
|
|
10
10
|
}
|
|
11
11
|
function isFunction(obj) {
|
|
12
12
|
return typeof obj === 'function';
|
|
@@ -53,6 +53,7 @@ const symbolGetNode = Symbol('getNode');
|
|
|
53
53
|
const symbolDelete = /* @__PURE__ */ Symbol('delete');
|
|
54
54
|
const symbolOpaque = Symbol('opaque');
|
|
55
55
|
const optimized = Symbol('optimized');
|
|
56
|
+
const symbolActivated = Symbol('activated');
|
|
56
57
|
// TODOV3 Remove these
|
|
57
58
|
const extraPrimitiveActivators = new Map();
|
|
58
59
|
const extraPrimitiveProps = new Map();
|
|
@@ -61,6 +62,8 @@ const globalState = {
|
|
|
61
62
|
isMerging: false,
|
|
62
63
|
isLoadingRemote$: undefined,
|
|
63
64
|
activateNode: undefined,
|
|
65
|
+
pendingNodes: new Map(),
|
|
66
|
+
dirtyNodes: new Set(),
|
|
64
67
|
};
|
|
65
68
|
function isObservable(obs) {
|
|
66
69
|
return !!obs && !!obs[symbolGetNode];
|
|
@@ -156,8 +159,16 @@ function getChildNode(node, key, asFunction) {
|
|
|
156
159
|
if (asFunction) {
|
|
157
160
|
child = Object.assign(cloneFunction(asFunction), child);
|
|
158
161
|
}
|
|
159
|
-
else
|
|
160
|
-
|
|
162
|
+
else {
|
|
163
|
+
if (node.activationState) {
|
|
164
|
+
const { lookup } = node.activationState;
|
|
165
|
+
if (lookup) {
|
|
166
|
+
child = Object.assign(lookup.bind(node, key), child);
|
|
167
|
+
if (isFunction(child)) {
|
|
168
|
+
extractFunction(node, key, child);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
161
172
|
}
|
|
162
173
|
if (!node.children) {
|
|
163
174
|
node.children = new Map();
|
|
@@ -202,9 +213,11 @@ function findIDKey(obj, node) {
|
|
|
202
213
|
return idKey;
|
|
203
214
|
}
|
|
204
215
|
function extractFunction(node, key, fnOrComputed, computedChildNode) {
|
|
216
|
+
var _a;
|
|
205
217
|
if (!node.functions) {
|
|
206
218
|
node.functions = new Map();
|
|
207
219
|
}
|
|
220
|
+
(_a = node.children) === null || _a === void 0 ? void 0 : _a.delete(key);
|
|
208
221
|
node.functions.set(key, fnOrComputed);
|
|
209
222
|
if (computedChildNode) {
|
|
210
223
|
computedChildNode.parentOther = getChildNode(node, key);
|
|
@@ -215,6 +228,12 @@ function extractFunction(node, key, fnOrComputed, computedChildNode) {
|
|
|
215
228
|
}
|
|
216
229
|
}
|
|
217
230
|
|
|
231
|
+
function activated(params) {
|
|
232
|
+
return (() => ({
|
|
233
|
+
[symbolActivated]: params,
|
|
234
|
+
}));
|
|
235
|
+
}
|
|
236
|
+
|
|
218
237
|
let timeout;
|
|
219
238
|
let numInBatch = 0;
|
|
220
239
|
let isRunningBatch = false;
|
|
@@ -239,23 +258,28 @@ function isArraySubset(mainArr, subsetArr) {
|
|
|
239
258
|
return true;
|
|
240
259
|
}
|
|
241
260
|
function createPreviousHandlerInner(value, changes) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
261
|
+
try {
|
|
262
|
+
// Clones the current state and inject the previous data at the changed path
|
|
263
|
+
let clone = value ? JSON.parse(JSON.stringify(value)) : {};
|
|
264
|
+
for (let i = 0; i < changes.length; i++) {
|
|
265
|
+
const { path, prevAtPath } = changes[i];
|
|
266
|
+
let o = clone;
|
|
267
|
+
if (path.length > 0) {
|
|
268
|
+
let i;
|
|
269
|
+
for (i = 0; i < path.length - 1; i++) {
|
|
270
|
+
o = o[path[i]];
|
|
271
|
+
}
|
|
272
|
+
o[path[i]] = prevAtPath;
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
clone = prevAtPath;
|
|
251
276
|
}
|
|
252
|
-
o[path[i]] = prevAtPath;
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
clone = prevAtPath;
|
|
256
277
|
}
|
|
278
|
+
return clone;
|
|
279
|
+
}
|
|
280
|
+
catch (_a) {
|
|
281
|
+
return undefined;
|
|
257
282
|
}
|
|
258
|
-
return clone;
|
|
259
283
|
}
|
|
260
284
|
function createPreviousHandler(value, changes) {
|
|
261
285
|
// Create a function that generates the previous state
|
|
@@ -364,6 +388,13 @@ function batchNotifyChanges(changesInBatch, immediate) {
|
|
|
364
388
|
});
|
|
365
389
|
}
|
|
366
390
|
function runBatch() {
|
|
391
|
+
const dirtyNodes = Array.from(globalState.dirtyNodes);
|
|
392
|
+
globalState.dirtyNodes.clear();
|
|
393
|
+
dirtyNodes.forEach((node) => {
|
|
394
|
+
var _a;
|
|
395
|
+
(_a = node.dirtyFn) === null || _a === void 0 ? void 0 : _a.call(node);
|
|
396
|
+
node.dirtyFn = undefined;
|
|
397
|
+
});
|
|
367
398
|
// Save batch locally and reset _batchMap first because a new batch could begin while looping over callbacks.
|
|
368
399
|
// This can happen with observableComputed for example.
|
|
369
400
|
const map = _batchMap;
|
|
@@ -480,7 +511,7 @@ function isEvent(obs) {
|
|
|
480
511
|
}
|
|
481
512
|
function computeSelector(selector, e, retainObservable) {
|
|
482
513
|
let c = selector;
|
|
483
|
-
if (isFunction(c)) {
|
|
514
|
+
if (!isObservable(c) && isFunction(c)) {
|
|
484
515
|
c = e ? c(e) : c();
|
|
485
516
|
}
|
|
486
517
|
return isObservable(c) && !retainObservable ? c.get() : c;
|
|
@@ -579,14 +610,15 @@ function _mergeIntoObservable(target, source) {
|
|
|
579
610
|
const targetValue = needsSet ? target.peek() : target;
|
|
580
611
|
const isTargetArr = isArray(targetValue);
|
|
581
612
|
const isTargetObj = !isTargetArr && isObject(targetValue);
|
|
582
|
-
if ((isTargetObj && isObject(source) && !isEmpty(targetValue)) ||
|
|
583
|
-
(isTargetArr && isArray(source) && targetValue.length > 0)) {
|
|
613
|
+
if ((isTargetObj && isObject(source) && !isEmpty(targetValue)) || (isTargetArr && targetValue.length > 0)) {
|
|
584
614
|
const keys = Object.keys(source);
|
|
585
615
|
for (let i = 0; i < keys.length; i++) {
|
|
586
616
|
const key = keys[i];
|
|
587
617
|
const sourceValue = source[key];
|
|
588
618
|
if (sourceValue === symbolDelete) {
|
|
589
|
-
needsSet && ((_a = target[key]) === null || _a === void 0 ? void 0 : _a.delete)
|
|
619
|
+
needsSet && ((_a = target[key]) === null || _a === void 0 ? void 0 : _a.delete)
|
|
620
|
+
? target[key].delete()
|
|
621
|
+
: delete target[key];
|
|
590
622
|
}
|
|
591
623
|
else {
|
|
592
624
|
const isObj = isObject(sourceValue);
|
|
@@ -775,7 +807,7 @@ function trackSelector(selector, update, observeEvent, observeOptions, createRes
|
|
|
775
807
|
dispose = setupTracking(nodes, updateFn, false, observeOptions === null || observeOptions === void 0 ? void 0 : observeOptions.immediate);
|
|
776
808
|
resubscribe = createResubscribe ? () => setupTracking(nodes, updateFn) : undefined;
|
|
777
809
|
}
|
|
778
|
-
return { value, dispose, resubscribe };
|
|
810
|
+
return { value, nodes, dispose, resubscribe };
|
|
779
811
|
}
|
|
780
812
|
|
|
781
813
|
function observe(selectorOrRun, reactionOrOptions, options) {
|
|
@@ -800,9 +832,11 @@ function observe(selectorOrRun, reactionOrOptions, options) {
|
|
|
800
832
|
delete e.value;
|
|
801
833
|
// Dispose listeners from previous run
|
|
802
834
|
dispose === null || dispose === void 0 ? void 0 : dispose();
|
|
803
|
-
const { dispose: _dispose, value } = trackSelector(selectorOrRun, update, e, options);
|
|
835
|
+
const { dispose: _dispose, value, nodes } = trackSelector(selectorOrRun, update, e, options);
|
|
804
836
|
dispose = _dispose;
|
|
805
837
|
e.value = value;
|
|
838
|
+
e.nodes = nodes;
|
|
839
|
+
e.refresh = update;
|
|
806
840
|
if (e.onCleanupReaction) {
|
|
807
841
|
e.onCleanupReaction();
|
|
808
842
|
e.onCleanupReaction = undefined;
|
|
@@ -810,7 +844,9 @@ function observe(selectorOrRun, reactionOrOptions, options) {
|
|
|
810
844
|
endBatch();
|
|
811
845
|
// Call the reaction if there is one and the value changed
|
|
812
846
|
if (reaction &&
|
|
813
|
-
((options === null || options === void 0 ? void 0 : options.fromComputed) ||
|
|
847
|
+
((options === null || options === void 0 ? void 0 : options.fromComputed) ||
|
|
848
|
+
((e.num > 0 || !isEvent(selectorOrRun)) &&
|
|
849
|
+
(e.previous !== e.value || typeof e.value === 'object')))) {
|
|
814
850
|
reaction(e);
|
|
815
851
|
}
|
|
816
852
|
// Update the previous value
|
|
@@ -830,6 +866,115 @@ function observe(selectorOrRun, reactionOrOptions, options) {
|
|
|
830
866
|
};
|
|
831
867
|
}
|
|
832
868
|
|
|
869
|
+
function _when(predicate, effect, checkReady) {
|
|
870
|
+
// If predicate is a regular Promise skip all the observable stuff
|
|
871
|
+
if (isPromise(predicate)) {
|
|
872
|
+
return effect ? predicate.then(effect) : predicate;
|
|
873
|
+
}
|
|
874
|
+
let value;
|
|
875
|
+
let effectValue;
|
|
876
|
+
// Create a wrapping fn that calls the effect if predicate returns true
|
|
877
|
+
function run(e) {
|
|
878
|
+
const ret = computeSelector(predicate);
|
|
879
|
+
if (!isPromise(ret) && (checkReady ? isObservableValueReady(ret) : ret)) {
|
|
880
|
+
value = ret;
|
|
881
|
+
// Set cancel so that observe does not track anymore
|
|
882
|
+
e.cancel = true;
|
|
883
|
+
}
|
|
884
|
+
return value;
|
|
885
|
+
}
|
|
886
|
+
function doEffect() {
|
|
887
|
+
// If value is truthy then run the effect
|
|
888
|
+
effectValue = effect === null || effect === void 0 ? void 0 : effect(value);
|
|
889
|
+
}
|
|
890
|
+
// Run in an observe
|
|
891
|
+
observe(run, doEffect);
|
|
892
|
+
// If first run resulted in a truthy value just return it.
|
|
893
|
+
// It will have set e.cancel so no need to dispose
|
|
894
|
+
if (isPromise(value)) {
|
|
895
|
+
return effect ? value.then(effect) : value;
|
|
896
|
+
}
|
|
897
|
+
else if (value !== undefined) {
|
|
898
|
+
return effect ? effectValue : Promise.resolve(value);
|
|
899
|
+
}
|
|
900
|
+
else {
|
|
901
|
+
// Wrap it in a promise
|
|
902
|
+
const promise = new Promise((resolve) => {
|
|
903
|
+
if (effect) {
|
|
904
|
+
const originalEffect = effect;
|
|
905
|
+
effect = ((value) => {
|
|
906
|
+
const effectValue = originalEffect(value);
|
|
907
|
+
resolve(isPromise(effectValue) ? effectValue.then((value) => value) : effectValue);
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
else {
|
|
911
|
+
effect = resolve;
|
|
912
|
+
}
|
|
913
|
+
});
|
|
914
|
+
return promise;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
function when(predicate, effect) {
|
|
918
|
+
return _when(predicate, effect, false);
|
|
919
|
+
}
|
|
920
|
+
function whenReady(predicate, effect) {
|
|
921
|
+
return _when(predicate, effect, true);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
function calculateRetryDelay(retryOptions, attemptNum) {
|
|
925
|
+
const { backoff, delay = 1000, infinite, times = 3, maxDelay = 30000 } = retryOptions;
|
|
926
|
+
if (infinite || attemptNum < times) {
|
|
927
|
+
const delayTime = Math.min(delay * (backoff === 'constant' ? 1 : 2 ** attemptNum), maxDelay);
|
|
928
|
+
return delayTime;
|
|
929
|
+
}
|
|
930
|
+
return null;
|
|
931
|
+
}
|
|
932
|
+
function createRetryTimout(retryOptions, attemptNum, fn) {
|
|
933
|
+
const delayTime = calculateRetryDelay(retryOptions, attemptNum);
|
|
934
|
+
if (delayTime) {
|
|
935
|
+
return setTimeout(fn, delayTime);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
function runWithRetry(node, state, fn) {
|
|
939
|
+
const { retry, waitFor } = node.activationState;
|
|
940
|
+
let value = undefined;
|
|
941
|
+
if (waitFor) {
|
|
942
|
+
value = whenReady(waitFor, () => {
|
|
943
|
+
node.activationState.waitFor = undefined;
|
|
944
|
+
return fn();
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
else {
|
|
948
|
+
value = fn();
|
|
949
|
+
}
|
|
950
|
+
if (isPromise(value) && retry) {
|
|
951
|
+
let timeoutRetry;
|
|
952
|
+
return new Promise((resolve) => {
|
|
953
|
+
const run = () => {
|
|
954
|
+
value
|
|
955
|
+
.then((val) => {
|
|
956
|
+
node.activationState.persistedRetry = false;
|
|
957
|
+
resolve(val);
|
|
958
|
+
})
|
|
959
|
+
.catch(() => {
|
|
960
|
+
node.activationState.persistedRetry = true;
|
|
961
|
+
state.attemptNum++;
|
|
962
|
+
if (timeoutRetry) {
|
|
963
|
+
clearTimeout(timeoutRetry);
|
|
964
|
+
}
|
|
965
|
+
timeoutRetry = createRetryTimout(retry, state.attemptNum, () => {
|
|
966
|
+
value = fn();
|
|
967
|
+
run();
|
|
968
|
+
});
|
|
969
|
+
});
|
|
970
|
+
};
|
|
971
|
+
run();
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
return value;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
const noop = () => { };
|
|
833
978
|
const ArrayModifiers = new Set([
|
|
834
979
|
'copyWithin',
|
|
835
980
|
'fill',
|
|
@@ -870,19 +1015,24 @@ if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
|
|
|
870
1015
|
}
|
|
871
1016
|
function collectionSetter(node, target, prop, ...args) {
|
|
872
1017
|
var _a;
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
const
|
|
878
|
-
const
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1018
|
+
if (prop === 'push') {
|
|
1019
|
+
setKey(node, target.length + '', args[0]);
|
|
1020
|
+
}
|
|
1021
|
+
else {
|
|
1022
|
+
const prevValue = target.slice();
|
|
1023
|
+
const ret = target[prop].apply(target, args);
|
|
1024
|
+
if (node) {
|
|
1025
|
+
const hasParent = isChildNodeValue(node);
|
|
1026
|
+
const key = hasParent ? node.key : '_';
|
|
1027
|
+
const parentValue = hasParent ? getNodeValue(node.parent) : node.root;
|
|
1028
|
+
// Set the object to the previous value first
|
|
1029
|
+
parentValue[key] = prevValue;
|
|
1030
|
+
// Then set with the new value so it notifies with the correct prevValue
|
|
1031
|
+
setKey((_a = node.parent) !== null && _a !== void 0 ? _a : node, key, target);
|
|
1032
|
+
}
|
|
1033
|
+
// Return the original value
|
|
1034
|
+
return ret;
|
|
1035
|
+
}
|
|
886
1036
|
}
|
|
887
1037
|
function getKeys(obj, isArr, isMap) {
|
|
888
1038
|
return isArr ? undefined : obj ? (isMap ? Array.from(obj.keys()) : Object.keys(obj)) : [];
|
|
@@ -917,8 +1067,9 @@ function updateNodes(parent, obj, prevValue) {
|
|
|
917
1067
|
let prevChildrenById;
|
|
918
1068
|
let moved;
|
|
919
1069
|
const isMap = obj instanceof Map;
|
|
1070
|
+
const isPrevMap = prevValue instanceof Map;
|
|
920
1071
|
const keys = getKeys(obj, isArr, isMap);
|
|
921
|
-
const keysPrev = getKeys(prevValue, isArr,
|
|
1072
|
+
const keysPrev = getKeys(prevValue, isArr, isPrevMap);
|
|
922
1073
|
const length = ((_a = (keys || obj)) === null || _a === void 0 ? void 0 : _a.length) || 0;
|
|
923
1074
|
const lengthPrev = ((_b = (keysPrev || prevValue)) === null || _b === void 0 ? void 0 : _b.length) || 0;
|
|
924
1075
|
let idField;
|
|
@@ -970,7 +1121,7 @@ function updateNodes(parent, obj, prevValue) {
|
|
|
970
1121
|
if (!keys.includes(key)) {
|
|
971
1122
|
hasADiff = true;
|
|
972
1123
|
const child = getChildNode(parent, key);
|
|
973
|
-
const prev =
|
|
1124
|
+
const prev = isPrevMap ? prevValue.get(key) : prevValue[key];
|
|
974
1125
|
if (prev !== undefined) {
|
|
975
1126
|
if (!isPrimitive(prev)) {
|
|
976
1127
|
updateNodes(child, undefined, prev);
|
|
@@ -989,7 +1140,7 @@ function updateNodes(parent, obj, prevValue) {
|
|
|
989
1140
|
for (let i = 0; i < length; i++) {
|
|
990
1141
|
const key = isArr ? i + '' : keys[i];
|
|
991
1142
|
const value = isMap ? obj.get(key) : obj[key];
|
|
992
|
-
const prev =
|
|
1143
|
+
const prev = isPrevMap ? prevValue === null || prevValue === void 0 ? void 0 : prevValue.get(key) : prevValue === null || prevValue === void 0 ? void 0 : prevValue[key];
|
|
993
1144
|
let isDiff = value !== prev;
|
|
994
1145
|
if (isDiff) {
|
|
995
1146
|
const id = idField && value
|
|
@@ -1027,7 +1178,10 @@ function updateNodes(parent, obj, prevValue) {
|
|
|
1027
1178
|
if (isDiff) {
|
|
1028
1179
|
// Array has a new / modified element
|
|
1029
1180
|
// If object iterate through its children
|
|
1030
|
-
if (
|
|
1181
|
+
if (isFunction(value)) {
|
|
1182
|
+
extractFunctionOrComputed(parent, obj, key, value);
|
|
1183
|
+
}
|
|
1184
|
+
else if (isPrimitive(value)) {
|
|
1031
1185
|
hasADiff = true;
|
|
1032
1186
|
}
|
|
1033
1187
|
else {
|
|
@@ -1075,6 +1229,15 @@ function getProxy(node, p, asFunction) {
|
|
|
1075
1229
|
// Create a proxy if not already cached and return it
|
|
1076
1230
|
return (node.proxy || (node.proxy = new Proxy(node, proxyHandler)));
|
|
1077
1231
|
}
|
|
1232
|
+
function flushPending() {
|
|
1233
|
+
// Need to short circuit the computed batching because the user called get() or peek()
|
|
1234
|
+
// in which case the set needs to run immediately so that the values are up to date.
|
|
1235
|
+
if (globalState.pendingNodes.size > 0) {
|
|
1236
|
+
const nodes = Array.from(globalState.pendingNodes.values());
|
|
1237
|
+
globalState.pendingNodes.clear();
|
|
1238
|
+
nodes.forEach((fn) => fn());
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1078
1241
|
const proxyHandler = {
|
|
1079
1242
|
get(node, p, receiver) {
|
|
1080
1243
|
var _a;
|
|
@@ -1102,6 +1265,9 @@ const proxyHandler = {
|
|
|
1102
1265
|
const fn = observableFns.get(p);
|
|
1103
1266
|
// If this is an observable function, call it
|
|
1104
1267
|
if (fn) {
|
|
1268
|
+
if (p === 'get' || p === 'peek') {
|
|
1269
|
+
flushPending();
|
|
1270
|
+
}
|
|
1105
1271
|
return function (a, b, c) {
|
|
1106
1272
|
const l = arguments.length;
|
|
1107
1273
|
// Array call and apply are slow so micro-optimize this hot path.
|
|
@@ -1207,10 +1373,6 @@ const proxyHandler = {
|
|
|
1207
1373
|
return vProp;
|
|
1208
1374
|
}
|
|
1209
1375
|
}
|
|
1210
|
-
// TODOV3: Remove "state"
|
|
1211
|
-
if (vProp === undefined && (p === 'state' || p === '_state') && node.state) {
|
|
1212
|
-
return node.state;
|
|
1213
|
-
}
|
|
1214
1376
|
// Return an observable proxy to the property
|
|
1215
1377
|
return getProxy(node, p);
|
|
1216
1378
|
},
|
|
@@ -1302,12 +1464,14 @@ function setKey(node, key, newValue, level) {
|
|
|
1302
1464
|
console.warn(`[legend-state] Set an HTMLElement into state. You probably don't want to do that.`);
|
|
1303
1465
|
}
|
|
1304
1466
|
}
|
|
1467
|
+
const isRoot = !node.parent && key === '_';
|
|
1468
|
+
// TODOv3 root locking will be removed with old computeds
|
|
1305
1469
|
if (node.root.locked && !node.root.set) {
|
|
1306
1470
|
// This happens when modifying a locked observable such as a computed.
|
|
1307
1471
|
// If merging this could be happening deep in a hierarchy so we don't want to throw errors so we'll just do nothing.
|
|
1308
1472
|
// This could happen during persistence local load for example.
|
|
1309
1473
|
if (globalState.isMerging) {
|
|
1310
|
-
return;
|
|
1474
|
+
return isRoot ? getProxy(node) : getProxy(node, key);
|
|
1311
1475
|
}
|
|
1312
1476
|
else {
|
|
1313
1477
|
throw new Error(process.env.NODE_ENV === 'development'
|
|
@@ -1315,18 +1479,28 @@ function setKey(node, key, newValue, level) {
|
|
|
1315
1479
|
: '[legend-state] Modified locked observable');
|
|
1316
1480
|
}
|
|
1317
1481
|
}
|
|
1318
|
-
|
|
1482
|
+
if (node.parent && !getNodeValue(node)) {
|
|
1483
|
+
return set(node, { [key]: newValue });
|
|
1484
|
+
}
|
|
1319
1485
|
// Get the child node for updating and notifying
|
|
1320
1486
|
const childNode = isRoot ? node : getChildNode(node, key, isFunction(newValue) ? newValue : undefined);
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
const isFunc = isFunction(savedValue);
|
|
1324
|
-
const isPrim = isPrimitive(savedValue) || savedValue instanceof Date;
|
|
1325
|
-
if (savedValue !== prevValue) {
|
|
1326
|
-
updateNodesAndNotify(node, savedValue, prevValue, childNode, isPrim, isRoot, level);
|
|
1487
|
+
if (isObservable(newValue)) {
|
|
1488
|
+
setToObservable(childNode, newValue);
|
|
1327
1489
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1490
|
+
else {
|
|
1491
|
+
// Set the raw value on the parent object
|
|
1492
|
+
const { newValue: savedValue, prevValue, parentValue } = setNodeValue(childNode, newValue);
|
|
1493
|
+
const isFunc = isFunction(savedValue);
|
|
1494
|
+
const isPrim = isPrimitive(savedValue) || savedValue instanceof Date;
|
|
1495
|
+
if (savedValue !== prevValue) {
|
|
1496
|
+
updateNodesAndNotify(node, savedValue, prevValue, childNode, isPrim, isRoot, level);
|
|
1497
|
+
}
|
|
1498
|
+
extractFunctionOrComputed(node, parentValue, key, savedValue);
|
|
1499
|
+
if (isFunc) {
|
|
1500
|
+
return savedValue;
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
return isRoot ? getProxy(node) : getProxy(node, key);
|
|
1330
1504
|
}
|
|
1331
1505
|
function assign(node, value) {
|
|
1332
1506
|
const proxy = getProxy(node);
|
|
@@ -1431,7 +1605,7 @@ function handlerMapSet(node, p, value) {
|
|
|
1431
1605
|
function updateNodesAndNotify(node, newValue, prevValue, childNode, isPrim, isRoot, level) {
|
|
1432
1606
|
if (!childNode)
|
|
1433
1607
|
childNode = node;
|
|
1434
|
-
// Make sure we don't call too many listeners for
|
|
1608
|
+
// Make sure we don't call too many listeners for every property set
|
|
1435
1609
|
beginBatch();
|
|
1436
1610
|
let hasADiff = isPrim;
|
|
1437
1611
|
let whenOptimizedOnlyIf = false;
|
|
@@ -1452,7 +1626,7 @@ function updateNodesAndNotify(node, newValue, prevValue, childNode, isPrim, isRo
|
|
|
1452
1626
|
}
|
|
1453
1627
|
endBatch();
|
|
1454
1628
|
}
|
|
1455
|
-
function extractPromise(node, value) {
|
|
1629
|
+
function extractPromise(node, value, setter) {
|
|
1456
1630
|
if (!node.state) {
|
|
1457
1631
|
node.state = createObservable({
|
|
1458
1632
|
isLoaded: false,
|
|
@@ -1460,26 +1634,38 @@ function extractPromise(node, value) {
|
|
|
1460
1634
|
}
|
|
1461
1635
|
value
|
|
1462
1636
|
.then((value) => {
|
|
1463
|
-
set(node, value);
|
|
1464
|
-
node.state.
|
|
1637
|
+
setter ? setter({ value }) : set(node, value);
|
|
1638
|
+
node.state.assign({
|
|
1639
|
+
isLoaded: true,
|
|
1640
|
+
error: undefined,
|
|
1641
|
+
});
|
|
1465
1642
|
})
|
|
1466
1643
|
.catch((error) => {
|
|
1467
1644
|
node.state.error.set(error);
|
|
1468
1645
|
});
|
|
1469
1646
|
}
|
|
1470
1647
|
function extractFunctionOrComputed(node, obj, k, v) {
|
|
1648
|
+
var _a;
|
|
1471
1649
|
if (isPromise(v)) {
|
|
1472
|
-
|
|
1650
|
+
const childNode = getChildNode(node, k);
|
|
1651
|
+
extractPromise(childNode, v);
|
|
1652
|
+
setNodeValue(childNode, undefined);
|
|
1473
1653
|
}
|
|
1474
1654
|
else if (typeof v === 'function') {
|
|
1655
|
+
const childNode = (_a = node.children) === null || _a === void 0 ? void 0 : _a.get(k);
|
|
1475
1656
|
extractFunction(node, k, v);
|
|
1476
|
-
|
|
1657
|
+
// If child was previously activated, then peek the new linked observable to make sure it's activated
|
|
1658
|
+
if (childNode && !childNode.lazy) {
|
|
1659
|
+
if (isObservable(v)) {
|
|
1660
|
+
const vNode = getNode(v);
|
|
1661
|
+
peek(vNode);
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1477
1664
|
}
|
|
1478
1665
|
else if (typeof v == 'object' && v !== null && v !== undefined) {
|
|
1479
1666
|
const childNode = getNode(v);
|
|
1480
1667
|
if (childNode === null || childNode === void 0 ? void 0 : childNode.isComputed) {
|
|
1481
1668
|
extractFunction(node, k, v, childNode);
|
|
1482
|
-
delete obj[k];
|
|
1483
1669
|
}
|
|
1484
1670
|
else {
|
|
1485
1671
|
return true;
|
|
@@ -1493,20 +1679,29 @@ function get(node, options) {
|
|
|
1493
1679
|
return peek(node);
|
|
1494
1680
|
}
|
|
1495
1681
|
function peek(node) {
|
|
1496
|
-
|
|
1682
|
+
if (node.dirtyFn) {
|
|
1683
|
+
node.dirtyFn();
|
|
1684
|
+
globalState.dirtyNodes.delete(node);
|
|
1685
|
+
node.dirtyFn = undefined;
|
|
1686
|
+
}
|
|
1687
|
+
let value = getNodeValue(node);
|
|
1497
1688
|
// If node is not yet lazily computed go do that
|
|
1498
1689
|
const lazy = node.lazy;
|
|
1499
1690
|
if (lazy) {
|
|
1500
1691
|
delete node.lazy;
|
|
1501
1692
|
if (isFunction(node) || isFunction(lazy)) {
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
if (hasOwnProperty.call(value, key)) {
|
|
1507
|
-
extractFunctionOrComputed(node, value, key, value[key]);
|
|
1693
|
+
if (node.parent) {
|
|
1694
|
+
const parentValue = getNodeValue(node.parent);
|
|
1695
|
+
if (parentValue) {
|
|
1696
|
+
delete parentValue[node.key];
|
|
1508
1697
|
}
|
|
1509
1698
|
}
|
|
1699
|
+
value = activateNodeFunction(node, lazy);
|
|
1700
|
+
}
|
|
1701
|
+
for (const key in value) {
|
|
1702
|
+
if (hasOwnProperty.call(value, key)) {
|
|
1703
|
+
extractFunctionOrComputed(node, value, key, value[key]);
|
|
1704
|
+
}
|
|
1510
1705
|
}
|
|
1511
1706
|
}
|
|
1512
1707
|
// Check if computed needs to activate
|
|
@@ -1514,137 +1709,272 @@ function peek(node) {
|
|
|
1514
1709
|
return value;
|
|
1515
1710
|
}
|
|
1516
1711
|
function activateNodeFunction(node, lazyFn) {
|
|
1517
|
-
let
|
|
1712
|
+
// let prevTarget$: Observable<any>;
|
|
1713
|
+
// let curTarget$: Observable<any>;
|
|
1518
1714
|
let update;
|
|
1519
|
-
let subscriber;
|
|
1520
|
-
const lastSync = {};
|
|
1521
|
-
let cacheOptions;
|
|
1522
|
-
// The onSet function handles the observable being set
|
|
1523
|
-
// and forwards the set elsewhere
|
|
1524
|
-
const onSet = (setterParam) => {
|
|
1525
|
-
setter = setterParam;
|
|
1526
|
-
};
|
|
1527
|
-
// The onSet function handles the observable being set
|
|
1528
|
-
// and forwards the set elsewhere
|
|
1529
|
-
const updateLastSync = (fn) => {
|
|
1530
|
-
lastSync.value = fn;
|
|
1531
|
-
};
|
|
1532
|
-
// The subscribe function runs a function that listens to
|
|
1533
|
-
// a data source and sends updates into the observable
|
|
1534
|
-
const subscribe = (fn) => {
|
|
1535
|
-
if (!subscriber) {
|
|
1536
|
-
subscriber = fn;
|
|
1537
|
-
}
|
|
1538
|
-
};
|
|
1539
|
-
const cache = (fn) => {
|
|
1540
|
-
if (!cacheOptions) {
|
|
1541
|
-
cacheOptions = isFunction(fn) ? fn() : fn;
|
|
1542
|
-
}
|
|
1543
|
-
};
|
|
1544
|
-
// The proxy function simply marks the node as a proxy with this function
|
|
1545
|
-
// so that child nodes will be created with this function, and then simply
|
|
1546
|
-
// activated as a function
|
|
1547
|
-
const proxy = (fn) => {
|
|
1548
|
-
node.proxyFn2 = fn;
|
|
1549
|
-
};
|
|
1550
|
-
let prevTarget$;
|
|
1551
|
-
let curTarget$;
|
|
1552
|
-
const activator = (isFunction(node) ? node : lazyFn);
|
|
1553
1715
|
let wasPromise;
|
|
1554
|
-
|
|
1716
|
+
const activateFn = (isFunction(node) ? node : lazyFn);
|
|
1717
|
+
const doRetry = () => { var _a; return (_a = node.state) === null || _a === void 0 ? void 0 : _a.refreshNum.set((v) => v + 1); };
|
|
1718
|
+
let activatedValue;
|
|
1719
|
+
let disposes = [];
|
|
1720
|
+
let refreshFn;
|
|
1721
|
+
function markDirty() {
|
|
1722
|
+
node.dirtyFn = refreshFn;
|
|
1723
|
+
globalState.dirtyNodes.add(node);
|
|
1724
|
+
}
|
|
1555
1725
|
observe(() => {
|
|
1726
|
+
var _a, _b, _c, _d;
|
|
1727
|
+
// const params = createNodeActivationParams(node);
|
|
1556
1728
|
// Run the function at this node
|
|
1557
|
-
let value =
|
|
1558
|
-
// If target is an observable,
|
|
1559
|
-
// and set up an onSet to write changes back to it
|
|
1729
|
+
let value = activateFn();
|
|
1730
|
+
// If target is an observable, make this node a link to it
|
|
1560
1731
|
if (isObservable(value)) {
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
// small subset of cases?
|
|
1571
|
-
setNodeValue(getNode(curTarget$), getPrevious());
|
|
1572
|
-
// Set the value on the curTarget
|
|
1573
|
-
curTarget$.set(newValue);
|
|
1574
|
-
}
|
|
1575
|
-
});
|
|
1576
|
-
// Get the value from the observable because we still want the raw value
|
|
1577
|
-
// for the effect.
|
|
1578
|
-
value = value.get();
|
|
1732
|
+
value = setToObservable(node, value);
|
|
1733
|
+
}
|
|
1734
|
+
if (isFunction(value)) {
|
|
1735
|
+
value = value();
|
|
1736
|
+
}
|
|
1737
|
+
const activated = value === null || value === void 0 ? void 0 : value[symbolActivated];
|
|
1738
|
+
if (activated) {
|
|
1739
|
+
node.activationState = activated;
|
|
1740
|
+
value = undefined;
|
|
1579
1741
|
}
|
|
1580
|
-
wasPromise = isPromise(value)
|
|
1742
|
+
wasPromise = isPromise(value);
|
|
1743
|
+
// Activate this node if not activated already (may be called recursively)
|
|
1744
|
+
// TODO: Is calling recursively bad? If so can it be fixed?
|
|
1581
1745
|
if (!node.activated) {
|
|
1582
1746
|
node.activated = true;
|
|
1747
|
+
const isCached = !!((_a = node.activationState) === null || _a === void 0 ? void 0 : _a.cache);
|
|
1748
|
+
wasPromise = wasPromise || !!isCached;
|
|
1583
1749
|
const activateNodeFn = wasPromise ? globalState.activateNode : activateNodeBase;
|
|
1584
|
-
update = activateNodeFn(node,
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1750
|
+
const { update: newUpdate, value: newValue } = activateNodeFn(node, doRetry, !!wasPromise, value);
|
|
1751
|
+
update = newUpdate;
|
|
1752
|
+
value = newValue !== null && newValue !== void 0 ? newValue : activated === null || activated === void 0 ? void 0 : activated.initial;
|
|
1753
|
+
}
|
|
1754
|
+
else if (node.activationState) {
|
|
1755
|
+
if (!node.activationState.persistedRetry && !node.activationState.waitFor) {
|
|
1756
|
+
const activated = node.activationState;
|
|
1757
|
+
// TODO Should this have lastSync and value somehow?
|
|
1758
|
+
value =
|
|
1759
|
+
(_c = (_b = activated.get) === null || _b === void 0 ? void 0 : _b.call(activated, {
|
|
1760
|
+
updateLastSync: noop,
|
|
1761
|
+
setMode: noop,
|
|
1762
|
+
lastSync: undefined,
|
|
1763
|
+
value: undefined,
|
|
1764
|
+
})) !== null && _c !== void 0 ? _c : activated.initial;
|
|
1765
|
+
}
|
|
1588
1766
|
}
|
|
1767
|
+
wasPromise = wasPromise || isPromise(value);
|
|
1768
|
+
get(getNode((_d = node.state) === null || _d === void 0 ? void 0 : _d.refreshNum));
|
|
1589
1769
|
return value;
|
|
1590
|
-
}, (
|
|
1591
|
-
|
|
1770
|
+
}, (e) => {
|
|
1771
|
+
const { value, nodes, refresh } = e;
|
|
1772
|
+
refreshFn = refresh;
|
|
1773
|
+
if (!wasPromise || !globalState.isLoadingRemote$.peek()) {
|
|
1592
1774
|
if (wasPromise) {
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1775
|
+
if (node.activationState) {
|
|
1776
|
+
const { initial } = node.activationState;
|
|
1777
|
+
if (value && isPromise(value)) {
|
|
1778
|
+
// Extract the promise to make it set the value/error when it comes in
|
|
1779
|
+
extractPromise(node, value, update);
|
|
1780
|
+
}
|
|
1781
|
+
// Set this to undefined only if it's replacing the activation function,
|
|
1782
|
+
// so we don't overwrite it if it already has real data from either local
|
|
1783
|
+
// cache or a previous run
|
|
1784
|
+
if (isFunction(getNodeValue(node))) {
|
|
1785
|
+
setNodeValue(node, initial !== null && initial !== void 0 ? initial : undefined);
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
else if (node.activated) {
|
|
1789
|
+
// Extract the promise to make it set the value/error when it comes in
|
|
1790
|
+
extractPromise(node, value, update);
|
|
1791
|
+
// Set this to undefined only if it's replacing the activation function,
|
|
1792
|
+
// so we don't overwrite it if it already has real data from either local
|
|
1793
|
+
// cache or a previous run
|
|
1794
|
+
if (isFunction(getNodeValue(node))) {
|
|
1795
|
+
setNodeValue(node, undefined);
|
|
1796
|
+
}
|
|
1599
1797
|
}
|
|
1600
1798
|
}
|
|
1601
1799
|
else {
|
|
1800
|
+
activatedValue = value;
|
|
1602
1801
|
set(node, value);
|
|
1603
|
-
node.state.
|
|
1802
|
+
node.state.assign({
|
|
1803
|
+
isLoaded: true,
|
|
1804
|
+
error: undefined,
|
|
1805
|
+
});
|
|
1604
1806
|
}
|
|
1605
1807
|
}
|
|
1606
|
-
|
|
1607
|
-
|
|
1808
|
+
disposes.forEach((fn) => fn());
|
|
1809
|
+
disposes = [];
|
|
1810
|
+
nodes === null || nodes === void 0 ? void 0 : nodes.forEach(({ node }) => {
|
|
1811
|
+
disposes.push(onChange(node, markDirty, { immediate: true }));
|
|
1812
|
+
});
|
|
1813
|
+
e.cancel = true;
|
|
1814
|
+
}, { fromComputed: true });
|
|
1815
|
+
return activatedValue;
|
|
1608
1816
|
}
|
|
1609
|
-
const activateNodeBase = (globalState.activateNode = function activateNodeBase(node,
|
|
1610
|
-
let isSetting = false;
|
|
1817
|
+
const activateNodeBase = (globalState.activateNode = function activateNodeBase(node, refresh, wasPromise, value) {
|
|
1611
1818
|
if (!node.state) {
|
|
1612
1819
|
node.state = createObservable({
|
|
1613
1820
|
isLoaded: false,
|
|
1614
1821
|
}, false, extractPromise, getProxy);
|
|
1615
1822
|
}
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1823
|
+
let isSetting = false;
|
|
1824
|
+
let isSettingFromSubscribe = false;
|
|
1825
|
+
let _mode = 'set';
|
|
1826
|
+
if (node.activationState) {
|
|
1827
|
+
const { onSet, subscribe, get: getFn, initial } = node.activationState;
|
|
1828
|
+
value = getFn
|
|
1829
|
+
? runWithRetry(node, { attemptNum: 0 }, () => {
|
|
1830
|
+
return getFn({
|
|
1831
|
+
updateLastSync: noop,
|
|
1832
|
+
setMode: (mode) => (_mode = mode),
|
|
1833
|
+
lastSync: undefined,
|
|
1834
|
+
value: undefined,
|
|
1835
|
+
});
|
|
1836
|
+
})
|
|
1837
|
+
: undefined;
|
|
1838
|
+
// TODO Should this have lastSync and value somehow?
|
|
1839
|
+
if (value == undefined || value === null) {
|
|
1840
|
+
value = initial;
|
|
1841
|
+
}
|
|
1842
|
+
if (onSet) {
|
|
1843
|
+
let allChanges = [];
|
|
1844
|
+
let latestValue = undefined;
|
|
1845
|
+
let runNumber = 0;
|
|
1846
|
+
const runChanges = (listenerParams) => {
|
|
1847
|
+
// Don't call the set if this is the first value coming in
|
|
1848
|
+
if (allChanges.length > 0) {
|
|
1849
|
+
let changes;
|
|
1850
|
+
let value;
|
|
1851
|
+
let getPrevious;
|
|
1852
|
+
if (listenerParams) {
|
|
1853
|
+
changes = listenerParams.changes;
|
|
1854
|
+
value = listenerParams.value;
|
|
1855
|
+
getPrevious = listenerParams.getPrevious;
|
|
1856
|
+
}
|
|
1857
|
+
else {
|
|
1858
|
+
// If this is called by flushPending then get the change array
|
|
1859
|
+
// that we've been building up.
|
|
1860
|
+
changes = allChanges;
|
|
1861
|
+
value = latestValue;
|
|
1862
|
+
getPrevious = createPreviousHandler(value, changes);
|
|
1863
|
+
}
|
|
1864
|
+
allChanges = [];
|
|
1865
|
+
latestValue = undefined;
|
|
1866
|
+
globalState.pendingNodes.delete(node);
|
|
1867
|
+
runNumber++;
|
|
1868
|
+
const thisRunNumber = runNumber;
|
|
1869
|
+
const run = () => {
|
|
1870
|
+
if (thisRunNumber !== runNumber) {
|
|
1871
|
+
// set may get called multiple times before it loads so ignore any previous runs
|
|
1872
|
+
return;
|
|
1873
|
+
}
|
|
1874
|
+
return runWithRetry(node, { attemptNum: 0 }, () => {
|
|
1875
|
+
return new Promise((resolve, reject) => {
|
|
1876
|
+
isSetting = true;
|
|
1877
|
+
batch(() => onSet({
|
|
1878
|
+
value,
|
|
1879
|
+
changes,
|
|
1880
|
+
getPrevious,
|
|
1881
|
+
node,
|
|
1882
|
+
update,
|
|
1883
|
+
refresh,
|
|
1884
|
+
onError: reject,
|
|
1885
|
+
fromSubscribe: isSettingFromSubscribe,
|
|
1886
|
+
}), () => {
|
|
1887
|
+
isSetting = false;
|
|
1888
|
+
resolve();
|
|
1889
|
+
});
|
|
1890
|
+
});
|
|
1891
|
+
});
|
|
1892
|
+
};
|
|
1893
|
+
whenReady(node.state.isLoaded, run);
|
|
1625
1894
|
}
|
|
1626
|
-
}
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1895
|
+
};
|
|
1896
|
+
const onChangeImmediate = ({ value, changes }) => {
|
|
1897
|
+
if (!isSetting || isSettingFromSubscribe) {
|
|
1898
|
+
if (changes.length > 1 || !isFunction(changes[0].prevAtPath)) {
|
|
1899
|
+
latestValue = value;
|
|
1900
|
+
if (allChanges.length > 0) {
|
|
1901
|
+
changes = changes.filter((change) => !isArraySubset(allChanges[0].path, change.path));
|
|
1902
|
+
}
|
|
1903
|
+
allChanges.push(...changes);
|
|
1904
|
+
globalState.pendingNodes.set(node, runChanges);
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
};
|
|
1908
|
+
// Create an immediate listener to mark this node as pending. Then actually run
|
|
1909
|
+
// the changes at the end of the batch so everything is properly batched.
|
|
1910
|
+
// However, this can be short circuited if the user calls get() or peek()
|
|
1911
|
+
// in which case the set needs to run immediately so that the values are up to date.
|
|
1912
|
+
onChange(node, onChangeImmediate, { immediate: true });
|
|
1913
|
+
onChange(node, runChanges);
|
|
1914
|
+
}
|
|
1915
|
+
if (process.env.NODE_ENV === 'development' && node.activationState.cache) {
|
|
1916
|
+
// TODO Better message
|
|
1917
|
+
console.log('[legend-state] Using cache without setting up persistence first');
|
|
1918
|
+
}
|
|
1919
|
+
if (process.env.NODE_ENV === 'development' && node.activationState.retry) {
|
|
1920
|
+
// TODO Better message
|
|
1921
|
+
console.log('[legend-state] Using retry without setting up persistence first');
|
|
1922
|
+
}
|
|
1923
|
+
if (subscribe) {
|
|
1924
|
+
const updateFromSubscribe = (params) => {
|
|
1925
|
+
whenReady(node.state.isLoaded, () => {
|
|
1926
|
+
isSettingFromSubscribe = true;
|
|
1927
|
+
update(params);
|
|
1928
|
+
isSettingFromSubscribe = false;
|
|
1929
|
+
});
|
|
1930
|
+
};
|
|
1931
|
+
subscribe({ node, update: updateFromSubscribe, refresh });
|
|
1932
|
+
}
|
|
1633
1933
|
}
|
|
1634
|
-
const update = ({ value }) => {
|
|
1934
|
+
const update = ({ value, mode }) => {
|
|
1935
|
+
// TODO: This isSetting might not be necessary? Tests still work if removing it.
|
|
1936
|
+
// Write tests that would break it if removed? I'd guess a combination of subscribe and
|
|
1635
1937
|
if (!isSetting) {
|
|
1636
|
-
|
|
1938
|
+
isSetting = true;
|
|
1939
|
+
if (_mode === 'assign' || mode === 'assign') {
|
|
1940
|
+
assign(node, value);
|
|
1941
|
+
}
|
|
1942
|
+
else if (_mode === 'merge' || mode === 'merge') {
|
|
1943
|
+
mergeIntoObservable(getProxy(node), value);
|
|
1944
|
+
}
|
|
1945
|
+
else {
|
|
1946
|
+
set(node, value);
|
|
1947
|
+
}
|
|
1948
|
+
isSetting = false;
|
|
1637
1949
|
}
|
|
1638
1950
|
};
|
|
1639
|
-
|
|
1640
|
-
if (isProm) {
|
|
1641
|
-
extractPromise(node, newValue);
|
|
1642
|
-
}
|
|
1643
|
-
if (subscriber) {
|
|
1644
|
-
subscriber({ update });
|
|
1645
|
-
}
|
|
1646
|
-
return { update };
|
|
1951
|
+
return { update, value };
|
|
1647
1952
|
});
|
|
1953
|
+
function setToObservable(node, value) {
|
|
1954
|
+
// If the computed is a proxy to another observable
|
|
1955
|
+
// link it to the target observable
|
|
1956
|
+
const linkedNode = getNode(value);
|
|
1957
|
+
if (linkedNode !== node) {
|
|
1958
|
+
const prevNode = node.linkedToNode;
|
|
1959
|
+
node.linkedToNode = linkedNode;
|
|
1960
|
+
if (!linkedNode.linkedFromNodes) {
|
|
1961
|
+
linkedNode.linkedFromNodes = new Set();
|
|
1962
|
+
}
|
|
1963
|
+
linkedNode.linkedFromNodes.add(node);
|
|
1964
|
+
peek(linkedNode);
|
|
1965
|
+
onChange(linkedNode, ({ value: newValue }) => {
|
|
1966
|
+
value = newValue;
|
|
1967
|
+
set(node, value);
|
|
1968
|
+
}, { initial: true });
|
|
1969
|
+
// If the target observable is different then notify for the change
|
|
1970
|
+
if (prevNode) {
|
|
1971
|
+
const value = getNodeValue(linkedNode);
|
|
1972
|
+
const prevValue = getNodeValue(prevNode);
|
|
1973
|
+
notify(node, value, prevValue, 0);
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
return value;
|
|
1977
|
+
}
|
|
1648
1978
|
|
|
1649
1979
|
const fns = ['get', 'set', 'peek', 'onChange', 'toggle'];
|
|
1650
1980
|
function ObservablePrimitiveClass(node) {
|
|
@@ -1661,8 +1991,14 @@ function proto(key, fn) {
|
|
|
1661
1991
|
return fn.call(this, this._node, ...args);
|
|
1662
1992
|
};
|
|
1663
1993
|
}
|
|
1664
|
-
proto('peek',
|
|
1665
|
-
|
|
1994
|
+
proto('peek', (node) => {
|
|
1995
|
+
flushPending();
|
|
1996
|
+
return peek(node);
|
|
1997
|
+
});
|
|
1998
|
+
proto('get', (node, options) => {
|
|
1999
|
+
flushPending();
|
|
2000
|
+
return get(node, options);
|
|
2001
|
+
});
|
|
1666
2002
|
proto('set', set);
|
|
1667
2003
|
proto('onChange', onChange);
|
|
1668
2004
|
// Getters
|
|
@@ -1693,6 +2029,16 @@ function observable(value) {
|
|
|
1693
2029
|
function observablePrimitive(value) {
|
|
1694
2030
|
return createObservable(value, true, extractPromise, getProxy, ObservablePrimitiveClass);
|
|
1695
2031
|
}
|
|
2032
|
+
function syncState(obs) {
|
|
2033
|
+
const node = getNode(obs);
|
|
2034
|
+
if (!node.state) {
|
|
2035
|
+
peek(node);
|
|
2036
|
+
}
|
|
2037
|
+
if (!node.state) {
|
|
2038
|
+
node.state = observable({});
|
|
2039
|
+
}
|
|
2040
|
+
return node.state;
|
|
2041
|
+
}
|
|
1696
2042
|
globalState.isLoadingRemote$ = observable(false);
|
|
1697
2043
|
|
|
1698
2044
|
function computed(compute, set$1) {
|
|
@@ -1857,60 +2203,6 @@ function proxy(get, set) {
|
|
|
1857
2203
|
return obs;
|
|
1858
2204
|
}
|
|
1859
2205
|
|
|
1860
|
-
function _when(predicate, effect, checkReady) {
|
|
1861
|
-
// If predicate is a regular Promise skip all the observable stuff
|
|
1862
|
-
if (isPromise(predicate)) {
|
|
1863
|
-
return effect ? predicate.then(effect) : predicate;
|
|
1864
|
-
}
|
|
1865
|
-
let value;
|
|
1866
|
-
// Create a wrapping fn that calls the effect if predicate returns true
|
|
1867
|
-
function run(e) {
|
|
1868
|
-
const ret = computeSelector(predicate);
|
|
1869
|
-
if (!isPromise(ret) && (checkReady ? isObservableValueReady(ret) : ret)) {
|
|
1870
|
-
value = ret;
|
|
1871
|
-
// Set cancel so that observe does not track anymore
|
|
1872
|
-
e.cancel = true;
|
|
1873
|
-
}
|
|
1874
|
-
return value;
|
|
1875
|
-
}
|
|
1876
|
-
function doEffect() {
|
|
1877
|
-
// If value is truthy then run the effect
|
|
1878
|
-
effect === null || effect === void 0 ? void 0 : effect(value);
|
|
1879
|
-
}
|
|
1880
|
-
// Run in an observe
|
|
1881
|
-
observe(run, doEffect);
|
|
1882
|
-
// If first run resulted in a truthy value just return it.
|
|
1883
|
-
// It will have set e.cancel so no need to dispose
|
|
1884
|
-
if (isPromise(value)) {
|
|
1885
|
-
return effect ? value.then(effect) : value;
|
|
1886
|
-
}
|
|
1887
|
-
else if (value !== undefined) {
|
|
1888
|
-
return Promise.resolve(value);
|
|
1889
|
-
}
|
|
1890
|
-
else {
|
|
1891
|
-
// Wrap it in a promise
|
|
1892
|
-
const promise = new Promise((resolve) => {
|
|
1893
|
-
if (effect) {
|
|
1894
|
-
const originalEffect = effect;
|
|
1895
|
-
effect = (value) => {
|
|
1896
|
-
const effectValue = originalEffect(value);
|
|
1897
|
-
resolve(effectValue);
|
|
1898
|
-
};
|
|
1899
|
-
}
|
|
1900
|
-
else {
|
|
1901
|
-
effect = resolve;
|
|
1902
|
-
}
|
|
1903
|
-
});
|
|
1904
|
-
return promise;
|
|
1905
|
-
}
|
|
1906
|
-
}
|
|
1907
|
-
function when(predicate, effect) {
|
|
1908
|
-
return _when(predicate, effect, false);
|
|
1909
|
-
}
|
|
1910
|
-
function whenReady(predicate, effect) {
|
|
1911
|
-
return _when(predicate, effect, true);
|
|
1912
|
-
}
|
|
1913
|
-
|
|
1914
2206
|
const internal = {
|
|
1915
2207
|
ensureNodeValue,
|
|
1916
2208
|
findIDKey,
|
|
@@ -1921,11 +2213,13 @@ const internal = {
|
|
|
1921
2213
|
observableFns,
|
|
1922
2214
|
optimized,
|
|
1923
2215
|
peek,
|
|
2216
|
+
runWithRetry,
|
|
1924
2217
|
set,
|
|
1925
2218
|
setAtPath,
|
|
1926
2219
|
setNodeValue,
|
|
2220
|
+
symbolActivated,
|
|
1927
2221
|
symbolDelete,
|
|
1928
2222
|
};
|
|
1929
2223
|
|
|
1930
|
-
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 };
|
|
2224
|
+
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, syncState, trackSelector, tracking, updateTracking, when, whenReady };
|
|
1931
2225
|
//# sourceMappingURL=index.mjs.map
|