@legendapp/state 2.2.0-next.3 → 2.2.0-next.30
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 +15 -4
- package/index.js +534 -242
- package/index.js.map +1 -1
- package/index.mjs +533 -243
- 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.map +1 -1
- 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 +10 -2
- package/persist-plugins/local-storage.js.map +1 -1
- package/persist-plugins/local-storage.mjs +10 -2
- 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 +15 -1
- package/persist.js +365 -116
- package/persist.js.map +1 -1
- package/persist.mjs +366 -117
- 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 +11 -4
- 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 +60 -331
- 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 -12
- 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 +6 -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,118 @@ 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 createRetryTimeout(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
|
+
const e = { cancel: false };
|
|
941
|
+
let value = undefined;
|
|
942
|
+
if (waitFor) {
|
|
943
|
+
value = whenReady(waitFor, () => {
|
|
944
|
+
node.activationState.waitFor = undefined;
|
|
945
|
+
return fn(e);
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
else {
|
|
949
|
+
value = fn(e);
|
|
950
|
+
}
|
|
951
|
+
if (isPromise(value) && retry) {
|
|
952
|
+
let timeoutRetry;
|
|
953
|
+
return new Promise((resolve) => {
|
|
954
|
+
const run = () => {
|
|
955
|
+
value
|
|
956
|
+
.then((val) => {
|
|
957
|
+
node.activationState.persistedRetry = false;
|
|
958
|
+
resolve(val);
|
|
959
|
+
})
|
|
960
|
+
.catch(() => {
|
|
961
|
+
node.activationState.persistedRetry = true;
|
|
962
|
+
state.attemptNum++;
|
|
963
|
+
if (timeoutRetry) {
|
|
964
|
+
clearTimeout(timeoutRetry);
|
|
965
|
+
}
|
|
966
|
+
if (!e.cancel) {
|
|
967
|
+
timeoutRetry = createRetryTimeout(retry, state.attemptNum, () => {
|
|
968
|
+
value = fn(e);
|
|
969
|
+
run();
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
});
|
|
973
|
+
};
|
|
974
|
+
run();
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
return value;
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
const noop = () => { };
|
|
833
981
|
const ArrayModifiers = new Set([
|
|
834
982
|
'copyWithin',
|
|
835
983
|
'fill',
|
|
@@ -870,19 +1018,24 @@ if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
|
|
|
870
1018
|
}
|
|
871
1019
|
function collectionSetter(node, target, prop, ...args) {
|
|
872
1020
|
var _a;
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
const
|
|
878
|
-
const
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1021
|
+
if (prop === 'push' && args.length === 1) {
|
|
1022
|
+
setKey(node, target.length + '', args[0]);
|
|
1023
|
+
}
|
|
1024
|
+
else {
|
|
1025
|
+
const prevValue = target.slice();
|
|
1026
|
+
const ret = target[prop].apply(target, args);
|
|
1027
|
+
if (node) {
|
|
1028
|
+
const hasParent = isChildNodeValue(node);
|
|
1029
|
+
const key = hasParent ? node.key : '_';
|
|
1030
|
+
const parentValue = hasParent ? getNodeValue(node.parent) : node.root;
|
|
1031
|
+
// Set the object to the previous value first
|
|
1032
|
+
parentValue[key] = prevValue;
|
|
1033
|
+
// Then set with the new value so it notifies with the correct prevValue
|
|
1034
|
+
setKey((_a = node.parent) !== null && _a !== void 0 ? _a : node, key, target);
|
|
1035
|
+
}
|
|
1036
|
+
// Return the original value
|
|
1037
|
+
return ret;
|
|
1038
|
+
}
|
|
886
1039
|
}
|
|
887
1040
|
function getKeys(obj, isArr, isMap) {
|
|
888
1041
|
return isArr ? undefined : obj ? (isMap ? Array.from(obj.keys()) : Object.keys(obj)) : [];
|
|
@@ -917,8 +1070,9 @@ function updateNodes(parent, obj, prevValue) {
|
|
|
917
1070
|
let prevChildrenById;
|
|
918
1071
|
let moved;
|
|
919
1072
|
const isMap = obj instanceof Map;
|
|
1073
|
+
const isPrevMap = prevValue instanceof Map;
|
|
920
1074
|
const keys = getKeys(obj, isArr, isMap);
|
|
921
|
-
const keysPrev = getKeys(prevValue, isArr,
|
|
1075
|
+
const keysPrev = getKeys(prevValue, isArr, isPrevMap);
|
|
922
1076
|
const length = ((_a = (keys || obj)) === null || _a === void 0 ? void 0 : _a.length) || 0;
|
|
923
1077
|
const lengthPrev = ((_b = (keysPrev || prevValue)) === null || _b === void 0 ? void 0 : _b.length) || 0;
|
|
924
1078
|
let idField;
|
|
@@ -970,7 +1124,7 @@ function updateNodes(parent, obj, prevValue) {
|
|
|
970
1124
|
if (!keys.includes(key)) {
|
|
971
1125
|
hasADiff = true;
|
|
972
1126
|
const child = getChildNode(parent, key);
|
|
973
|
-
const prev =
|
|
1127
|
+
const prev = isPrevMap ? prevValue.get(key) : prevValue[key];
|
|
974
1128
|
if (prev !== undefined) {
|
|
975
1129
|
if (!isPrimitive(prev)) {
|
|
976
1130
|
updateNodes(child, undefined, prev);
|
|
@@ -989,7 +1143,7 @@ function updateNodes(parent, obj, prevValue) {
|
|
|
989
1143
|
for (let i = 0; i < length; i++) {
|
|
990
1144
|
const key = isArr ? i + '' : keys[i];
|
|
991
1145
|
const value = isMap ? obj.get(key) : obj[key];
|
|
992
|
-
const prev =
|
|
1146
|
+
const prev = isPrevMap ? prevValue === null || prevValue === void 0 ? void 0 : prevValue.get(key) : prevValue === null || prevValue === void 0 ? void 0 : prevValue[key];
|
|
993
1147
|
let isDiff = value !== prev;
|
|
994
1148
|
if (isDiff) {
|
|
995
1149
|
const id = idField && value
|
|
@@ -1027,7 +1181,10 @@ function updateNodes(parent, obj, prevValue) {
|
|
|
1027
1181
|
if (isDiff) {
|
|
1028
1182
|
// Array has a new / modified element
|
|
1029
1183
|
// If object iterate through its children
|
|
1030
|
-
if (
|
|
1184
|
+
if (isFunction(value)) {
|
|
1185
|
+
extractFunctionOrComputed(parent, obj, key, value);
|
|
1186
|
+
}
|
|
1187
|
+
else if (isPrimitive(value)) {
|
|
1031
1188
|
hasADiff = true;
|
|
1032
1189
|
}
|
|
1033
1190
|
else {
|
|
@@ -1075,6 +1232,15 @@ function getProxy(node, p, asFunction) {
|
|
|
1075
1232
|
// Create a proxy if not already cached and return it
|
|
1076
1233
|
return (node.proxy || (node.proxy = new Proxy(node, proxyHandler)));
|
|
1077
1234
|
}
|
|
1235
|
+
function flushPending() {
|
|
1236
|
+
// Need to short circuit the computed batching because the user called get() or peek()
|
|
1237
|
+
// in which case the set needs to run immediately so that the values are up to date.
|
|
1238
|
+
if (globalState.pendingNodes.size > 0) {
|
|
1239
|
+
const nodes = Array.from(globalState.pendingNodes.values());
|
|
1240
|
+
globalState.pendingNodes.clear();
|
|
1241
|
+
nodes.forEach((fn) => fn());
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1078
1244
|
const proxyHandler = {
|
|
1079
1245
|
get(node, p, receiver) {
|
|
1080
1246
|
var _a;
|
|
@@ -1102,6 +1268,9 @@ const proxyHandler = {
|
|
|
1102
1268
|
const fn = observableFns.get(p);
|
|
1103
1269
|
// If this is an observable function, call it
|
|
1104
1270
|
if (fn) {
|
|
1271
|
+
if (p === 'get' || p === 'peek') {
|
|
1272
|
+
flushPending();
|
|
1273
|
+
}
|
|
1105
1274
|
return function (a, b, c) {
|
|
1106
1275
|
const l = arguments.length;
|
|
1107
1276
|
// Array call and apply are slow so micro-optimize this hot path.
|
|
@@ -1207,10 +1376,6 @@ const proxyHandler = {
|
|
|
1207
1376
|
return vProp;
|
|
1208
1377
|
}
|
|
1209
1378
|
}
|
|
1210
|
-
// TODOV3: Remove "state"
|
|
1211
|
-
if (vProp === undefined && (p === 'state' || p === '_state') && node.state) {
|
|
1212
|
-
return node.state;
|
|
1213
|
-
}
|
|
1214
1379
|
// Return an observable proxy to the property
|
|
1215
1380
|
return getProxy(node, p);
|
|
1216
1381
|
},
|
|
@@ -1288,7 +1453,7 @@ function set(node, newValue) {
|
|
|
1288
1453
|
}
|
|
1289
1454
|
function toggle(node) {
|
|
1290
1455
|
const value = getNodeValue(node);
|
|
1291
|
-
if (value === undefined || isBoolean(value)) {
|
|
1456
|
+
if (value === undefined || value === null || isBoolean(value)) {
|
|
1292
1457
|
set(node, !value);
|
|
1293
1458
|
return !value;
|
|
1294
1459
|
}
|
|
@@ -1302,12 +1467,14 @@ function setKey(node, key, newValue, level) {
|
|
|
1302
1467
|
console.warn(`[legend-state] Set an HTMLElement into state. You probably don't want to do that.`);
|
|
1303
1468
|
}
|
|
1304
1469
|
}
|
|
1470
|
+
const isRoot = !node.parent && key === '_';
|
|
1471
|
+
// TODOv3 root locking will be removed with old computeds
|
|
1305
1472
|
if (node.root.locked && !node.root.set) {
|
|
1306
1473
|
// This happens when modifying a locked observable such as a computed.
|
|
1307
1474
|
// 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
1475
|
// This could happen during persistence local load for example.
|
|
1309
1476
|
if (globalState.isMerging) {
|
|
1310
|
-
return;
|
|
1477
|
+
return isRoot ? getProxy(node) : getProxy(node, key);
|
|
1311
1478
|
}
|
|
1312
1479
|
else {
|
|
1313
1480
|
throw new Error(process.env.NODE_ENV === 'development'
|
|
@@ -1315,18 +1482,28 @@ function setKey(node, key, newValue, level) {
|
|
|
1315
1482
|
: '[legend-state] Modified locked observable');
|
|
1316
1483
|
}
|
|
1317
1484
|
}
|
|
1318
|
-
|
|
1485
|
+
if (node.parent && !getNodeValue(node)) {
|
|
1486
|
+
return set(node, { [key]: newValue });
|
|
1487
|
+
}
|
|
1319
1488
|
// Get the child node for updating and notifying
|
|
1320
1489
|
const childNode = isRoot ? node : getChildNode(node, key, isFunction(newValue) ? newValue : undefined);
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1490
|
+
if (isObservable(newValue)) {
|
|
1491
|
+
setToObservable(childNode, newValue);
|
|
1492
|
+
}
|
|
1493
|
+
else {
|
|
1494
|
+
// Set the raw value on the parent object
|
|
1495
|
+
const { newValue: savedValue, prevValue, parentValue } = setNodeValue(childNode, newValue);
|
|
1496
|
+
const isFunc = isFunction(savedValue);
|
|
1497
|
+
const isPrim = isPrimitive(savedValue) || savedValue instanceof Date;
|
|
1498
|
+
if (savedValue !== prevValue) {
|
|
1499
|
+
updateNodesAndNotify(node, savedValue, prevValue, childNode, isPrim, isRoot, level);
|
|
1500
|
+
}
|
|
1501
|
+
extractFunctionOrComputed(node, parentValue, key, savedValue);
|
|
1502
|
+
if (isFunc) {
|
|
1503
|
+
return savedValue;
|
|
1504
|
+
}
|
|
1327
1505
|
}
|
|
1328
|
-
|
|
1329
|
-
return isFunc ? savedValue : isRoot ? getProxy(node) : getProxy(node, key);
|
|
1506
|
+
return isRoot ? getProxy(node) : getProxy(node, key);
|
|
1330
1507
|
}
|
|
1331
1508
|
function assign(node, value) {
|
|
1332
1509
|
const proxy = getProxy(node);
|
|
@@ -1431,7 +1608,7 @@ function handlerMapSet(node, p, value) {
|
|
|
1431
1608
|
function updateNodesAndNotify(node, newValue, prevValue, childNode, isPrim, isRoot, level) {
|
|
1432
1609
|
if (!childNode)
|
|
1433
1610
|
childNode = node;
|
|
1434
|
-
// Make sure we don't call too many listeners for
|
|
1611
|
+
// Make sure we don't call too many listeners for every property set
|
|
1435
1612
|
beginBatch();
|
|
1436
1613
|
let hasADiff = isPrim;
|
|
1437
1614
|
let whenOptimizedOnlyIf = false;
|
|
@@ -1452,7 +1629,7 @@ function updateNodesAndNotify(node, newValue, prevValue, childNode, isPrim, isRo
|
|
|
1452
1629
|
}
|
|
1453
1630
|
endBatch();
|
|
1454
1631
|
}
|
|
1455
|
-
function extractPromise(node, value) {
|
|
1632
|
+
function extractPromise(node, value, setter) {
|
|
1456
1633
|
if (!node.state) {
|
|
1457
1634
|
node.state = createObservable({
|
|
1458
1635
|
isLoaded: false,
|
|
@@ -1460,28 +1637,38 @@ function extractPromise(node, value) {
|
|
|
1460
1637
|
}
|
|
1461
1638
|
value
|
|
1462
1639
|
.then((value) => {
|
|
1463
|
-
set(node, value);
|
|
1464
|
-
node.state.
|
|
1640
|
+
setter ? setter({ value }) : set(node, value);
|
|
1641
|
+
node.state.assign({
|
|
1642
|
+
isLoaded: true,
|
|
1643
|
+
error: undefined,
|
|
1644
|
+
});
|
|
1465
1645
|
})
|
|
1466
1646
|
.catch((error) => {
|
|
1467
1647
|
node.state.error.set(error);
|
|
1468
1648
|
});
|
|
1469
1649
|
}
|
|
1470
1650
|
function extractFunctionOrComputed(node, obj, k, v) {
|
|
1651
|
+
var _a;
|
|
1471
1652
|
if (isPromise(v)) {
|
|
1472
1653
|
const childNode = getChildNode(node, k);
|
|
1473
1654
|
extractPromise(childNode, v);
|
|
1474
1655
|
setNodeValue(childNode, undefined);
|
|
1475
1656
|
}
|
|
1476
1657
|
else if (typeof v === 'function') {
|
|
1658
|
+
const childNode = (_a = node.children) === null || _a === void 0 ? void 0 : _a.get(k);
|
|
1477
1659
|
extractFunction(node, k, v);
|
|
1478
|
-
|
|
1660
|
+
// If child was previously activated, then peek the new linked observable to make sure it's activated
|
|
1661
|
+
if (childNode && !childNode.lazy) {
|
|
1662
|
+
if (isObservable(v)) {
|
|
1663
|
+
const vNode = getNode(v);
|
|
1664
|
+
peek(vNode);
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1479
1667
|
}
|
|
1480
1668
|
else if (typeof v == 'object' && v !== null && v !== undefined) {
|
|
1481
1669
|
const childNode = getNode(v);
|
|
1482
1670
|
if (childNode === null || childNode === void 0 ? void 0 : childNode.isComputed) {
|
|
1483
1671
|
extractFunction(node, k, v, childNode);
|
|
1484
|
-
delete obj[k];
|
|
1485
1672
|
}
|
|
1486
1673
|
else {
|
|
1487
1674
|
return true;
|
|
@@ -1495,177 +1682,316 @@ function get(node, options) {
|
|
|
1495
1682
|
return peek(node);
|
|
1496
1683
|
}
|
|
1497
1684
|
function peek(node) {
|
|
1498
|
-
|
|
1685
|
+
if (node.dirtyFn) {
|
|
1686
|
+
node.dirtyFn();
|
|
1687
|
+
globalState.dirtyNodes.delete(node);
|
|
1688
|
+
node.dirtyFn = undefined;
|
|
1689
|
+
}
|
|
1690
|
+
let value = getNodeValue(node);
|
|
1499
1691
|
// If node is not yet lazily computed go do that
|
|
1500
1692
|
const lazy = node.lazy;
|
|
1501
1693
|
if (lazy) {
|
|
1502
1694
|
delete node.lazy;
|
|
1503
1695
|
if (isFunction(node) || isFunction(lazy)) {
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
if (hasOwnProperty.call(value, key)) {
|
|
1509
|
-
extractFunctionOrComputed(node, value, key, value[key]);
|
|
1696
|
+
if (node.parent) {
|
|
1697
|
+
const parentValue = getNodeValue(node.parent);
|
|
1698
|
+
if (parentValue) {
|
|
1699
|
+
delete parentValue[node.key];
|
|
1510
1700
|
}
|
|
1511
1701
|
}
|
|
1702
|
+
value = activateNodeFunction(node, lazy);
|
|
1703
|
+
}
|
|
1704
|
+
for (const key in value) {
|
|
1705
|
+
if (hasOwnProperty.call(value, key)) {
|
|
1706
|
+
extractFunctionOrComputed(node, value, key, value[key]);
|
|
1707
|
+
}
|
|
1512
1708
|
}
|
|
1513
1709
|
}
|
|
1514
1710
|
// Check if computed needs to activate
|
|
1515
1711
|
checkActivate(node);
|
|
1516
1712
|
return value;
|
|
1517
1713
|
}
|
|
1518
|
-
function createNodeActivationParams(node) {
|
|
1519
|
-
node.activationState = {
|
|
1520
|
-
lastSync: {},
|
|
1521
|
-
};
|
|
1522
|
-
const state = node.activationState;
|
|
1523
|
-
// The onSet function handles the observable being set
|
|
1524
|
-
// and forwards the set elsewhere
|
|
1525
|
-
const onSet = (onSetFnParam) => {
|
|
1526
|
-
state.onSetFn = onSetFnParam;
|
|
1527
|
-
};
|
|
1528
|
-
// The onSet function handles the observable being set
|
|
1529
|
-
// and forwards the set elsewhere
|
|
1530
|
-
const updateLastSync = (fn) => {
|
|
1531
|
-
state.lastSync.value = fn;
|
|
1532
|
-
};
|
|
1533
|
-
// The subscribe function runs a function that listens to
|
|
1534
|
-
// a data source and sends updates into the observable
|
|
1535
|
-
const subscribe = (fn) => {
|
|
1536
|
-
if (!state.subscriber) {
|
|
1537
|
-
state.subscriber = fn;
|
|
1538
|
-
}
|
|
1539
|
-
};
|
|
1540
|
-
const cache = (fn) => {
|
|
1541
|
-
if (!state.cacheOptions) {
|
|
1542
|
-
state.cacheOptions = isFunction(fn) ? fn() : fn;
|
|
1543
|
-
}
|
|
1544
|
-
};
|
|
1545
|
-
const retry = (params) => {
|
|
1546
|
-
if (!state.retryOptions) {
|
|
1547
|
-
state.retryOptions = params;
|
|
1548
|
-
}
|
|
1549
|
-
};
|
|
1550
|
-
// The proxy function simply marks the node as a proxy with this function
|
|
1551
|
-
// so that child nodes will be created with this function, and then simply
|
|
1552
|
-
// activated as a function
|
|
1553
|
-
const proxy = (fn) => {
|
|
1554
|
-
node.proxyFn2 = fn;
|
|
1555
|
-
};
|
|
1556
|
-
return {
|
|
1557
|
-
onSet,
|
|
1558
|
-
proxy,
|
|
1559
|
-
cache,
|
|
1560
|
-
retry,
|
|
1561
|
-
subscribe,
|
|
1562
|
-
updateLastSync,
|
|
1563
|
-
};
|
|
1564
|
-
}
|
|
1565
1714
|
function activateNodeFunction(node, lazyFn) {
|
|
1566
|
-
let prevTarget
|
|
1567
|
-
let curTarget
|
|
1568
|
-
|
|
1715
|
+
// let prevTarget$: Observable<any>;
|
|
1716
|
+
// let curTarget$: Observable<any>;
|
|
1717
|
+
let update;
|
|
1569
1718
|
let wasPromise;
|
|
1570
|
-
const
|
|
1719
|
+
const activateFn = (isFunction(node) ? node : lazyFn);
|
|
1720
|
+
const doRetry = () => { var _a; return (_a = node.state) === null || _a === void 0 ? void 0 : _a.refreshNum.set((v) => v + 1); };
|
|
1721
|
+
let activatedValue;
|
|
1722
|
+
let disposes = [];
|
|
1723
|
+
let refreshFn;
|
|
1724
|
+
function markDirty() {
|
|
1725
|
+
node.dirtyFn = refreshFn;
|
|
1726
|
+
globalState.dirtyNodes.add(node);
|
|
1727
|
+
}
|
|
1571
1728
|
observe(() => {
|
|
1572
|
-
|
|
1729
|
+
var _a, _b, _c, _d;
|
|
1730
|
+
// const params = createNodeActivationParams(node);
|
|
1573
1731
|
// Run the function at this node
|
|
1574
|
-
let value =
|
|
1575
|
-
// If target is an observable,
|
|
1576
|
-
// and set up an onSet to write changes back to it
|
|
1732
|
+
let value = activateFn();
|
|
1733
|
+
// If target is an observable, make this node a link to it
|
|
1577
1734
|
if (isObservable(value)) {
|
|
1578
|
-
|
|
1579
|
-
curTarget$ = value;
|
|
1580
|
-
params.onSet(({ value: newValue, getPrevious }) => {
|
|
1581
|
-
// Don't set the target observable if the target has changed since the last run
|
|
1582
|
-
if (!prevTarget$ || curTarget$ === prevTarget$) {
|
|
1583
|
-
// Set the node value back to what it was before before setting it.
|
|
1584
|
-
// This is a workaround for linked objects because it might not notify
|
|
1585
|
-
// if setting a property of an object
|
|
1586
|
-
// TODO: Is there a way to not do this? Or at least only do it in a
|
|
1587
|
-
// small subset of cases?
|
|
1588
|
-
setNodeValue(getNode(curTarget$), getPrevious());
|
|
1589
|
-
// Set the value on the curTarget
|
|
1590
|
-
curTarget$.set(newValue);
|
|
1591
|
-
}
|
|
1592
|
-
});
|
|
1593
|
-
// Get the value from the observable because we still want the raw value
|
|
1594
|
-
// for the effect.
|
|
1595
|
-
value = value.get();
|
|
1735
|
+
value = setToObservable(node, value);
|
|
1596
1736
|
}
|
|
1597
|
-
|
|
1598
|
-
|
|
1737
|
+
if (isFunction(value)) {
|
|
1738
|
+
value = value();
|
|
1599
1739
|
}
|
|
1740
|
+
const activated = value === null || value === void 0 ? void 0 : value[symbolActivated];
|
|
1741
|
+
if (activated) {
|
|
1742
|
+
node.activationState = activated;
|
|
1743
|
+
value = undefined;
|
|
1744
|
+
}
|
|
1745
|
+
wasPromise = isPromise(value);
|
|
1600
1746
|
// Activate this node if not activated already (may be called recursively)
|
|
1601
1747
|
// TODO: Is calling recursively bad? If so can it be fixed?
|
|
1602
1748
|
if (!node.activated) {
|
|
1603
1749
|
node.activated = true;
|
|
1750
|
+
const isCached = !!((_a = node.activationState) === null || _a === void 0 ? void 0 : _a.cache);
|
|
1751
|
+
wasPromise = wasPromise || !!isCached;
|
|
1604
1752
|
const activateNodeFn = wasPromise ? globalState.activateNode : activateNodeBase;
|
|
1605
|
-
activateNodeFn(node,
|
|
1753
|
+
const { update: newUpdate, value: newValue } = activateNodeFn(node, doRetry, !!wasPromise, value);
|
|
1754
|
+
update = newUpdate;
|
|
1755
|
+
value = newValue !== null && newValue !== void 0 ? newValue : activated === null || activated === void 0 ? void 0 : activated.initial;
|
|
1756
|
+
}
|
|
1757
|
+
else if (node.activationState) {
|
|
1758
|
+
if (!node.activationState.persistedRetry && !node.activationState.waitFor) {
|
|
1759
|
+
const activated = node.activationState;
|
|
1760
|
+
// TODO Should this have lastSync and value somehow?
|
|
1761
|
+
value =
|
|
1762
|
+
(_c = (_b = activated.get) === null || _b === void 0 ? void 0 : _b.call(activated, {
|
|
1763
|
+
updateLastSync: noop,
|
|
1764
|
+
setMode: noop,
|
|
1765
|
+
lastSync: undefined,
|
|
1766
|
+
value: undefined,
|
|
1767
|
+
refresh: doRetry,
|
|
1768
|
+
})) !== null && _c !== void 0 ? _c : activated.initial;
|
|
1769
|
+
}
|
|
1606
1770
|
}
|
|
1607
|
-
|
|
1771
|
+
wasPromise = wasPromise || isPromise(value);
|
|
1772
|
+
get(getNode((_d = node.state) === null || _d === void 0 ? void 0 : _d.refreshNum));
|
|
1608
1773
|
return value;
|
|
1609
|
-
}, (
|
|
1610
|
-
|
|
1774
|
+
}, (e) => {
|
|
1775
|
+
const { value, nodes, refresh } = e;
|
|
1776
|
+
refreshFn = refresh;
|
|
1777
|
+
if (!wasPromise || !globalState.isLoadingRemote$.peek()) {
|
|
1611
1778
|
if (wasPromise) {
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1779
|
+
if (node.activationState) {
|
|
1780
|
+
const { initial } = node.activationState;
|
|
1781
|
+
if (value && isPromise(value)) {
|
|
1782
|
+
// Extract the promise to make it set the value/error when it comes in
|
|
1783
|
+
extractPromise(node, value, update);
|
|
1784
|
+
}
|
|
1785
|
+
// Set this to undefined only if it's replacing the activation function,
|
|
1786
|
+
// so we don't overwrite it if it already has real data from either local
|
|
1787
|
+
// cache or a previous run
|
|
1788
|
+
if (isFunction(getNodeValue(node))) {
|
|
1789
|
+
setNodeValue(node, initial !== null && initial !== void 0 ? initial : undefined);
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
else if (node.activated) {
|
|
1793
|
+
// Extract the promise to make it set the value/error when it comes in
|
|
1794
|
+
extractPromise(node, value, update);
|
|
1795
|
+
// Set this to undefined only if it's replacing the activation function,
|
|
1796
|
+
// so we don't overwrite it if it already has real data from either local
|
|
1797
|
+
// cache or a previous run
|
|
1798
|
+
if (isFunction(getNodeValue(node))) {
|
|
1799
|
+
setNodeValue(node, undefined);
|
|
1800
|
+
}
|
|
1619
1801
|
}
|
|
1620
1802
|
}
|
|
1621
1803
|
else {
|
|
1804
|
+
activatedValue = value;
|
|
1622
1805
|
set(node, value);
|
|
1623
|
-
node.state.
|
|
1806
|
+
node.state.assign({
|
|
1807
|
+
isLoaded: true,
|
|
1808
|
+
error: undefined,
|
|
1809
|
+
});
|
|
1624
1810
|
}
|
|
1625
1811
|
}
|
|
1626
|
-
|
|
1812
|
+
disposes.forEach((fn) => fn());
|
|
1813
|
+
disposes = [];
|
|
1814
|
+
nodes === null || nodes === void 0 ? void 0 : nodes.forEach(({ node }) => {
|
|
1815
|
+
disposes.push(onChange(node, markDirty, { immediate: true }));
|
|
1816
|
+
});
|
|
1817
|
+
e.cancel = true;
|
|
1818
|
+
}, { fromComputed: true });
|
|
1819
|
+
return activatedValue;
|
|
1627
1820
|
}
|
|
1628
|
-
const activateNodeBase = (globalState.activateNode = function activateNodeBase(node, refresh) {
|
|
1629
|
-
const { onSetFn, subscriber } = node.activationState;
|
|
1630
|
-
let isSetting = false;
|
|
1821
|
+
const activateNodeBase = (globalState.activateNode = function activateNodeBase(node, refresh, wasPromise, value) {
|
|
1631
1822
|
if (!node.state) {
|
|
1632
1823
|
node.state = createObservable({
|
|
1633
1824
|
isLoaded: false,
|
|
1634
1825
|
}, false, extractPromise, getProxy);
|
|
1635
1826
|
}
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1827
|
+
let isSetting = false;
|
|
1828
|
+
let isSettingFromSubscribe = false;
|
|
1829
|
+
let _mode = 'set';
|
|
1830
|
+
if (node.activationState) {
|
|
1831
|
+
const { onSet, subscribe, get: getFn, initial } = node.activationState;
|
|
1832
|
+
value = getFn
|
|
1833
|
+
? runWithRetry(node, { attemptNum: 0 }, () => {
|
|
1834
|
+
return getFn({
|
|
1835
|
+
updateLastSync: noop,
|
|
1836
|
+
setMode: (mode) => (_mode = mode),
|
|
1837
|
+
lastSync: undefined,
|
|
1838
|
+
value: undefined,
|
|
1839
|
+
refresh,
|
|
1840
|
+
});
|
|
1841
|
+
})
|
|
1842
|
+
: undefined;
|
|
1843
|
+
// TODO Should this have lastSync and value somehow?
|
|
1844
|
+
if (value == undefined || value === null) {
|
|
1845
|
+
value = initial;
|
|
1846
|
+
}
|
|
1847
|
+
if (onSet) {
|
|
1848
|
+
let allChanges = [];
|
|
1849
|
+
let latestValue = undefined;
|
|
1850
|
+
let runNumber = 0;
|
|
1851
|
+
const runChanges = (listenerParams) => {
|
|
1852
|
+
// Don't call the set if this is the first value coming in
|
|
1853
|
+
if (allChanges.length > 0) {
|
|
1854
|
+
let changes;
|
|
1855
|
+
let value;
|
|
1856
|
+
let getPrevious;
|
|
1857
|
+
if (listenerParams) {
|
|
1858
|
+
changes = listenerParams.changes;
|
|
1859
|
+
value = listenerParams.value;
|
|
1860
|
+
getPrevious = listenerParams.getPrevious;
|
|
1861
|
+
}
|
|
1862
|
+
else {
|
|
1863
|
+
// If this is called by flushPending then get the change array
|
|
1864
|
+
// that we've been building up.
|
|
1865
|
+
changes = allChanges;
|
|
1866
|
+
value = latestValue;
|
|
1867
|
+
getPrevious = createPreviousHandler(value, changes);
|
|
1868
|
+
}
|
|
1869
|
+
allChanges = [];
|
|
1870
|
+
latestValue = undefined;
|
|
1871
|
+
globalState.pendingNodes.delete(node);
|
|
1872
|
+
runNumber++;
|
|
1873
|
+
const thisRunNumber = runNumber;
|
|
1874
|
+
const run = () => {
|
|
1875
|
+
if (thisRunNumber !== runNumber) {
|
|
1876
|
+
// set may get called multiple times before it loads so ignore any previous runs
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
const retryAttempts = { attemptNum: 0 };
|
|
1880
|
+
return runWithRetry(node, retryAttempts, (eventRetry) => {
|
|
1881
|
+
const cancelRetry = () => {
|
|
1882
|
+
eventRetry.cancel = true;
|
|
1883
|
+
};
|
|
1884
|
+
return new Promise((resolve, reject) => {
|
|
1885
|
+
isSetting = true;
|
|
1886
|
+
batch(() => {
|
|
1887
|
+
try {
|
|
1888
|
+
return onSet({
|
|
1889
|
+
value,
|
|
1890
|
+
changes,
|
|
1891
|
+
getPrevious,
|
|
1892
|
+
node,
|
|
1893
|
+
update,
|
|
1894
|
+
refresh,
|
|
1895
|
+
retryNum: retryAttempts.attemptNum,
|
|
1896
|
+
cancelRetry,
|
|
1897
|
+
fromSubscribe: isSettingFromSubscribe,
|
|
1898
|
+
});
|
|
1899
|
+
}
|
|
1900
|
+
catch (e) {
|
|
1901
|
+
reject(e);
|
|
1902
|
+
}
|
|
1903
|
+
}, () => {
|
|
1904
|
+
isSetting = false;
|
|
1905
|
+
resolve();
|
|
1906
|
+
});
|
|
1907
|
+
});
|
|
1908
|
+
});
|
|
1909
|
+
};
|
|
1910
|
+
whenReady(node.state.isLoaded, run);
|
|
1645
1911
|
}
|
|
1646
|
-
}
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1912
|
+
};
|
|
1913
|
+
const onChangeImmediate = ({ value, changes }) => {
|
|
1914
|
+
if (!isSetting || isSettingFromSubscribe) {
|
|
1915
|
+
if (changes.length > 1 || !isFunction(changes[0].prevAtPath)) {
|
|
1916
|
+
latestValue = value;
|
|
1917
|
+
if (allChanges.length > 0) {
|
|
1918
|
+
changes = changes.filter((change) => !isArraySubset(allChanges[0].path, change.path));
|
|
1919
|
+
}
|
|
1920
|
+
allChanges.push(...changes);
|
|
1921
|
+
globalState.pendingNodes.set(node, runChanges);
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
};
|
|
1925
|
+
// Create an immediate listener to mark this node as pending. Then actually run
|
|
1926
|
+
// the changes at the end of the batch so everything is properly batched.
|
|
1927
|
+
// However, this can be short circuited if the user calls get() or peek()
|
|
1928
|
+
// in which case the set needs to run immediately so that the values are up to date.
|
|
1929
|
+
onChange(node, onChangeImmediate, { immediate: true });
|
|
1930
|
+
onChange(node, runChanges);
|
|
1931
|
+
}
|
|
1932
|
+
if (process.env.NODE_ENV === 'development' && node.activationState.cache) {
|
|
1933
|
+
// TODO Better message
|
|
1934
|
+
console.log('[legend-state] Using cache without setting up persistence first');
|
|
1935
|
+
}
|
|
1936
|
+
if (process.env.NODE_ENV === 'development' && node.activationState.retry) {
|
|
1937
|
+
// TODO Better message
|
|
1938
|
+
console.log('[legend-state] Using retry without setting up persistence first');
|
|
1939
|
+
}
|
|
1940
|
+
if (subscribe) {
|
|
1941
|
+
const updateFromSubscribe = (params) => {
|
|
1942
|
+
whenReady(node.state.isLoaded, () => {
|
|
1943
|
+
isSettingFromSubscribe = true;
|
|
1944
|
+
update(params);
|
|
1945
|
+
isSettingFromSubscribe = false;
|
|
1946
|
+
});
|
|
1947
|
+
};
|
|
1948
|
+
subscribe({ node, update: updateFromSubscribe, refresh });
|
|
1949
|
+
}
|
|
1657
1950
|
}
|
|
1658
|
-
const update = ({ value }) => {
|
|
1951
|
+
const update = ({ value, mode }) => {
|
|
1659
1952
|
// TODO: This isSetting might not be necessary? Tests still work if removing it.
|
|
1660
1953
|
// Write tests that would break it if removed? I'd guess a combination of subscribe and
|
|
1661
1954
|
if (!isSetting) {
|
|
1662
|
-
|
|
1955
|
+
isSetting = true;
|
|
1956
|
+
if (_mode === 'assign' || mode === 'assign') {
|
|
1957
|
+
assign(node, value);
|
|
1958
|
+
}
|
|
1959
|
+
else if (_mode === 'merge' || mode === 'merge') {
|
|
1960
|
+
mergeIntoObservable(getProxy(node), value);
|
|
1961
|
+
}
|
|
1962
|
+
else {
|
|
1963
|
+
set(node, value);
|
|
1964
|
+
}
|
|
1965
|
+
isSetting = false;
|
|
1663
1966
|
}
|
|
1664
1967
|
};
|
|
1665
|
-
|
|
1666
|
-
subscriber({ update, refresh });
|
|
1667
|
-
}
|
|
1968
|
+
return { update, value };
|
|
1668
1969
|
});
|
|
1970
|
+
function setToObservable(node, value) {
|
|
1971
|
+
// If the computed is a proxy to another observable
|
|
1972
|
+
// link it to the target observable
|
|
1973
|
+
const linkedNode = getNode(value);
|
|
1974
|
+
if (linkedNode !== node) {
|
|
1975
|
+
const prevNode = node.linkedToNode;
|
|
1976
|
+
node.linkedToNode = linkedNode;
|
|
1977
|
+
if (!linkedNode.linkedFromNodes) {
|
|
1978
|
+
linkedNode.linkedFromNodes = new Set();
|
|
1979
|
+
}
|
|
1980
|
+
linkedNode.linkedFromNodes.add(node);
|
|
1981
|
+
peek(linkedNode);
|
|
1982
|
+
onChange(linkedNode, ({ value: newValue }) => {
|
|
1983
|
+
value = newValue;
|
|
1984
|
+
set(node, value);
|
|
1985
|
+
}, { initial: true });
|
|
1986
|
+
// If the target observable is different then notify for the change
|
|
1987
|
+
if (prevNode) {
|
|
1988
|
+
const value = getNodeValue(linkedNode);
|
|
1989
|
+
const prevValue = getNodeValue(prevNode);
|
|
1990
|
+
notify(node, value, prevValue, 0);
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
return value;
|
|
1994
|
+
}
|
|
1669
1995
|
|
|
1670
1996
|
const fns = ['get', 'set', 'peek', 'onChange', 'toggle'];
|
|
1671
1997
|
function ObservablePrimitiveClass(node) {
|
|
@@ -1682,8 +2008,14 @@ function proto(key, fn) {
|
|
|
1682
2008
|
return fn.call(this, this._node, ...args);
|
|
1683
2009
|
};
|
|
1684
2010
|
}
|
|
1685
|
-
proto('peek',
|
|
1686
|
-
|
|
2011
|
+
proto('peek', (node) => {
|
|
2012
|
+
flushPending();
|
|
2013
|
+
return peek(node);
|
|
2014
|
+
});
|
|
2015
|
+
proto('get', (node, options) => {
|
|
2016
|
+
flushPending();
|
|
2017
|
+
return get(node, options);
|
|
2018
|
+
});
|
|
1687
2019
|
proto('set', set);
|
|
1688
2020
|
proto('onChange', onChange);
|
|
1689
2021
|
// Getters
|
|
@@ -1695,7 +2027,7 @@ Object.defineProperty(ObservablePrimitiveClass.prototype, symbolGetNode, {
|
|
|
1695
2027
|
});
|
|
1696
2028
|
ObservablePrimitiveClass.prototype.toggle = function () {
|
|
1697
2029
|
const value = this.peek();
|
|
1698
|
-
if (value === undefined || isBoolean(value)) {
|
|
2030
|
+
if (value === undefined || value === null || isBoolean(value)) {
|
|
1699
2031
|
this.set(!value);
|
|
1700
2032
|
}
|
|
1701
2033
|
else if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
|
|
@@ -1714,6 +2046,16 @@ function observable(value) {
|
|
|
1714
2046
|
function observablePrimitive(value) {
|
|
1715
2047
|
return createObservable(value, true, extractPromise, getProxy, ObservablePrimitiveClass);
|
|
1716
2048
|
}
|
|
2049
|
+
function syncState(obs) {
|
|
2050
|
+
const node = getNode(obs);
|
|
2051
|
+
if (!node.state) {
|
|
2052
|
+
peek(node);
|
|
2053
|
+
}
|
|
2054
|
+
if (!node.state) {
|
|
2055
|
+
node.state = observable({});
|
|
2056
|
+
}
|
|
2057
|
+
return node.state;
|
|
2058
|
+
}
|
|
1717
2059
|
globalState.isLoadingRemote$ = observable(false);
|
|
1718
2060
|
|
|
1719
2061
|
function computed(compute, set$1) {
|
|
@@ -1878,60 +2220,6 @@ function proxy(get, set) {
|
|
|
1878
2220
|
return obs;
|
|
1879
2221
|
}
|
|
1880
2222
|
|
|
1881
|
-
function _when(predicate, effect, checkReady) {
|
|
1882
|
-
// If predicate is a regular Promise skip all the observable stuff
|
|
1883
|
-
if (isPromise(predicate)) {
|
|
1884
|
-
return effect ? predicate.then(effect) : predicate;
|
|
1885
|
-
}
|
|
1886
|
-
let value;
|
|
1887
|
-
// Create a wrapping fn that calls the effect if predicate returns true
|
|
1888
|
-
function run(e) {
|
|
1889
|
-
const ret = computeSelector(predicate);
|
|
1890
|
-
if (!isPromise(ret) && (checkReady ? isObservableValueReady(ret) : ret)) {
|
|
1891
|
-
value = ret;
|
|
1892
|
-
// Set cancel so that observe does not track anymore
|
|
1893
|
-
e.cancel = true;
|
|
1894
|
-
}
|
|
1895
|
-
return value;
|
|
1896
|
-
}
|
|
1897
|
-
function doEffect() {
|
|
1898
|
-
// If value is truthy then run the effect
|
|
1899
|
-
effect === null || effect === void 0 ? void 0 : effect(value);
|
|
1900
|
-
}
|
|
1901
|
-
// Run in an observe
|
|
1902
|
-
observe(run, doEffect);
|
|
1903
|
-
// If first run resulted in a truthy value just return it.
|
|
1904
|
-
// It will have set e.cancel so no need to dispose
|
|
1905
|
-
if (isPromise(value)) {
|
|
1906
|
-
return effect ? value.then(effect) : value;
|
|
1907
|
-
}
|
|
1908
|
-
else if (value !== undefined) {
|
|
1909
|
-
return Promise.resolve(value);
|
|
1910
|
-
}
|
|
1911
|
-
else {
|
|
1912
|
-
// Wrap it in a promise
|
|
1913
|
-
const promise = new Promise((resolve) => {
|
|
1914
|
-
if (effect) {
|
|
1915
|
-
const originalEffect = effect;
|
|
1916
|
-
effect = (value) => {
|
|
1917
|
-
const effectValue = originalEffect(value);
|
|
1918
|
-
resolve(effectValue);
|
|
1919
|
-
};
|
|
1920
|
-
}
|
|
1921
|
-
else {
|
|
1922
|
-
effect = resolve;
|
|
1923
|
-
}
|
|
1924
|
-
});
|
|
1925
|
-
return promise;
|
|
1926
|
-
}
|
|
1927
|
-
}
|
|
1928
|
-
function when(predicate, effect) {
|
|
1929
|
-
return _when(predicate, effect, false);
|
|
1930
|
-
}
|
|
1931
|
-
function whenReady(predicate, effect) {
|
|
1932
|
-
return _when(predicate, effect, true);
|
|
1933
|
-
}
|
|
1934
|
-
|
|
1935
2223
|
const internal = {
|
|
1936
2224
|
ensureNodeValue,
|
|
1937
2225
|
findIDKey,
|
|
@@ -1942,11 +2230,13 @@ const internal = {
|
|
|
1942
2230
|
observableFns,
|
|
1943
2231
|
optimized,
|
|
1944
2232
|
peek,
|
|
2233
|
+
runWithRetry,
|
|
1945
2234
|
set,
|
|
1946
2235
|
setAtPath,
|
|
1947
2236
|
setNodeValue,
|
|
2237
|
+
symbolActivated,
|
|
1948
2238
|
symbolDelete,
|
|
1949
2239
|
};
|
|
1950
2240
|
|
|
1951
|
-
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 };
|
|
2241
|
+
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 };
|
|
1952
2242
|
//# sourceMappingURL=index.mjs.map
|