opshot 0.3.1 → 0.3.3
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/README.md +2 -1
- package/dist/index.js +196 -128
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -122,9 +122,10 @@ It can't track:
|
|
|
122
122
|
|
|
123
123
|
- Internal slots (language level features like in Map)
|
|
124
124
|
- #private fields (hidden at the language level)
|
|
125
|
-
- Arrow methods on classes (they write to the original object, not the tracked one)
|
|
126
125
|
- Array subclasses (the prototype is lost when copied)
|
|
127
126
|
|
|
127
|
+
And `this` for arrow methods on classes refers to the original and **not** the tracked state.
|
|
128
|
+
|
|
128
129
|
Use `ignore` or `unsafeTrack` when dealing with these.
|
|
129
130
|
|
|
130
131
|
## Tracked collections
|
package/dist/index.js
CHANGED
|
@@ -337,65 +337,6 @@ function unstable_replaceInternalFunction(name, fn) {
|
|
|
337
337
|
}
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
-
// src/react/wrapperRegistry.ts
|
|
341
|
-
var wrapperTargets = /* @__PURE__ */ new WeakMap();
|
|
342
|
-
var registerWrapperTarget = (wrapper, target) => {
|
|
343
|
-
wrapperTargets.set(wrapper, target);
|
|
344
|
-
};
|
|
345
|
-
var getRegisteredWrapperTarget = (wrapper) => wrapperTargets.get(wrapper);
|
|
346
|
-
|
|
347
|
-
// src/identity.ts
|
|
348
|
-
var isObjectLike = (value) => value !== null && (typeof value === "object" || typeof value === "function");
|
|
349
|
-
var targetRegistry = /* @__PURE__ */ new WeakMap();
|
|
350
|
-
var identityTokenRegistry = /* @__PURE__ */ new WeakMap();
|
|
351
|
-
var { proxyStateMap: proxyStateMap2 } = unstable_getInternalStates();
|
|
352
|
-
function registerSnapshotCopy(copy, target) {
|
|
353
|
-
targetRegistry.set(copy, target);
|
|
354
|
-
}
|
|
355
|
-
function getRegisteredTarget(copy) {
|
|
356
|
-
return targetRegistry.get(copy);
|
|
357
|
-
}
|
|
358
|
-
function peelIdentityLayer(current) {
|
|
359
|
-
const untracked = getUntracked(current);
|
|
360
|
-
if (untracked !== null && untracked !== current) return untracked;
|
|
361
|
-
const wrapperTarget = getRegisteredWrapperTarget(current);
|
|
362
|
-
if (wrapperTarget !== void 0 && wrapperTarget !== current) return wrapperTarget;
|
|
363
|
-
const registeredTarget = targetRegistry.get(current);
|
|
364
|
-
if (registeredTarget !== void 0 && registeredTarget !== current) return registeredTarget;
|
|
365
|
-
return void 0;
|
|
366
|
-
}
|
|
367
|
-
function resolveIdentity(value) {
|
|
368
|
-
let current = value;
|
|
369
|
-
while (isObjectLike(current)) {
|
|
370
|
-
const peeled = peelIdentityLayer(current);
|
|
371
|
-
if (peeled !== void 0) {
|
|
372
|
-
current = peeled;
|
|
373
|
-
continue;
|
|
374
|
-
}
|
|
375
|
-
const proxyState = proxyStateMap2.get(current);
|
|
376
|
-
if (proxyState !== void 0 && proxyState[0] !== current) {
|
|
377
|
-
current = proxyState[0];
|
|
378
|
-
continue;
|
|
379
|
-
}
|
|
380
|
-
break;
|
|
381
|
-
}
|
|
382
|
-
return current;
|
|
383
|
-
}
|
|
384
|
-
function identify(value) {
|
|
385
|
-
const target = resolveIdentity(value);
|
|
386
|
-
if (!isObjectLike(target)) return value;
|
|
387
|
-
const existing = identityTokenRegistry.get(target);
|
|
388
|
-
if (existing !== void 0) return existing;
|
|
389
|
-
const token = Object.freeze({});
|
|
390
|
-
identityTokenRegistry.set(target, token);
|
|
391
|
-
return token;
|
|
392
|
-
}
|
|
393
|
-
function isSameIdentity(first, second) {
|
|
394
|
-
const resolvedFirst = resolveIdentity(first);
|
|
395
|
-
const resolvedSecond = resolveIdentity(second);
|
|
396
|
-
return resolvedFirst === resolvedSecond || resolvedFirst !== resolvedFirst && resolvedSecond !== resolvedSecond;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
340
|
// src/unsafeTrack.ts
|
|
400
341
|
var unsafeTrackedSet = /* @__PURE__ */ new WeakSet();
|
|
401
342
|
function unsafeTrack(value) {
|
|
@@ -512,6 +453,65 @@ var cloneValue = (value, memo2, path) => {
|
|
|
512
453
|
return clone;
|
|
513
454
|
};
|
|
514
455
|
|
|
456
|
+
// src/react/wrapperRegistry.ts
|
|
457
|
+
var wrapperTargets = /* @__PURE__ */ new WeakMap();
|
|
458
|
+
var registerWrapperTarget = (wrapper, target) => {
|
|
459
|
+
wrapperTargets.set(wrapper, target);
|
|
460
|
+
};
|
|
461
|
+
var getRegisteredWrapperTarget = (wrapper) => wrapperTargets.get(wrapper);
|
|
462
|
+
|
|
463
|
+
// src/identity.ts
|
|
464
|
+
var isObjectLike = (value) => value !== null && (typeof value === "object" || typeof value === "function");
|
|
465
|
+
var targetRegistry = /* @__PURE__ */ new WeakMap();
|
|
466
|
+
var identityTokenRegistry = /* @__PURE__ */ new WeakMap();
|
|
467
|
+
var { proxyStateMap: proxyStateMap2 } = unstable_getInternalStates();
|
|
468
|
+
function registerSnapshotCopy(copy, target) {
|
|
469
|
+
targetRegistry.set(copy, target);
|
|
470
|
+
}
|
|
471
|
+
function getRegisteredTarget(copy) {
|
|
472
|
+
return targetRegistry.get(copy);
|
|
473
|
+
}
|
|
474
|
+
function peelIdentityLayer(current) {
|
|
475
|
+
const untracked = getUntracked(current);
|
|
476
|
+
if (untracked !== null && untracked !== current) return untracked;
|
|
477
|
+
const wrapperTarget = getRegisteredWrapperTarget(current);
|
|
478
|
+
if (wrapperTarget !== void 0 && wrapperTarget !== current) return wrapperTarget;
|
|
479
|
+
const registeredTarget = targetRegistry.get(current);
|
|
480
|
+
if (registeredTarget !== void 0 && registeredTarget !== current) return registeredTarget;
|
|
481
|
+
return void 0;
|
|
482
|
+
}
|
|
483
|
+
function resolveIdentity(value) {
|
|
484
|
+
let current = value;
|
|
485
|
+
while (isObjectLike(current)) {
|
|
486
|
+
const peeled = peelIdentityLayer(current);
|
|
487
|
+
if (peeled !== void 0) {
|
|
488
|
+
current = peeled;
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
const proxyState = proxyStateMap2.get(current);
|
|
492
|
+
if (proxyState !== void 0 && proxyState[0] !== current) {
|
|
493
|
+
current = proxyState[0];
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
return current;
|
|
499
|
+
}
|
|
500
|
+
function identify(value) {
|
|
501
|
+
const target = resolveIdentity(value);
|
|
502
|
+
if (!isObjectLike(target)) return value;
|
|
503
|
+
const existing = identityTokenRegistry.get(target);
|
|
504
|
+
if (existing !== void 0) return existing;
|
|
505
|
+
const token = Object.freeze({});
|
|
506
|
+
identityTokenRegistry.set(target, token);
|
|
507
|
+
return token;
|
|
508
|
+
}
|
|
509
|
+
function isSameIdentity(first, second) {
|
|
510
|
+
const resolvedFirst = resolveIdentity(first);
|
|
511
|
+
const resolvedSecond = resolveIdentity(second);
|
|
512
|
+
return resolvedFirst === resolvedSecond || resolvedFirst !== resolvedFirst && resolvedSecond !== resolvedSecond;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
515
|
// src/ops/operation.ts
|
|
516
516
|
var operationBrand = /* @__PURE__ */ Symbol.for("opshot.operation");
|
|
517
517
|
var valueOriginals = /* @__PURE__ */ new WeakMap();
|
|
@@ -773,17 +773,17 @@ function diffSnapshots(before, after) {
|
|
|
773
773
|
return ops;
|
|
774
774
|
}
|
|
775
775
|
|
|
776
|
-
// src/
|
|
777
|
-
var
|
|
776
|
+
// src/emit/emitterDeliver.ts
|
|
777
|
+
var deliver = (record, ops, meta) => {
|
|
778
|
+
const groupDelivers = [...record.groupListeners?.values() ?? []].flatMap((byChannel) => [...byChannel.values()]);
|
|
779
|
+
for (const deliverToListener of groupDelivers) deliverToListener(record.target, ops, meta);
|
|
780
|
+
const ownDelivers = [...record.listeners.values()].flatMap((byChannel) => [...byChannel.values()]);
|
|
781
|
+
for (const deliverToListener of ownDelivers) deliverToListener(ops, meta);
|
|
782
|
+
};
|
|
783
|
+
|
|
784
|
+
// src/emit/resolveEmitterTarget.ts
|
|
778
785
|
var { proxyStateMap: proxyStateMap3 } = unstable_getInternalStates();
|
|
779
786
|
var isObjectLike3 = (value) => value !== null && (typeof value === "object" || typeof value === "function");
|
|
780
|
-
var augmentBareCycleError = (error) => {
|
|
781
|
-
const path = getCyclicPath(error);
|
|
782
|
-
if (path === void 0) return void 0;
|
|
783
|
-
return new Error(
|
|
784
|
-
`opshot: a bare write created a cyclic value at ${formatOperationPath(path)}. Cycles cannot be tracked. This surfaced asynchronously because the write was not inside transact. Use transact for catchable cycle errors, ignore() for back-linked structures, or ids.`
|
|
785
|
-
);
|
|
786
|
-
};
|
|
787
787
|
function resolveEmitterTarget(state) {
|
|
788
788
|
let current = state;
|
|
789
789
|
while (isObjectLike3(current)) {
|
|
@@ -795,10 +795,43 @@ function resolveEmitterTarget(state) {
|
|
|
795
795
|
if (!isObjectLike3(current) || !proxyStateMap3.has(current)) throw new Error("opshot: expected a state object");
|
|
796
796
|
return current;
|
|
797
797
|
}
|
|
798
|
+
|
|
799
|
+
// src/emit/emitterRegistry.ts
|
|
800
|
+
var emitters = /* @__PURE__ */ new WeakMap();
|
|
798
801
|
function getEmitter(state) {
|
|
799
802
|
return emitters.get(resolveEmitterTarget(state));
|
|
800
803
|
}
|
|
801
804
|
var hasListeners = (record) => record.listeners.size > 0 || (record.groupListeners?.size ?? 0) > 0;
|
|
805
|
+
function getOrCreateEmitter(target, groupListeners) {
|
|
806
|
+
const resolved = resolveEmitterTarget(target);
|
|
807
|
+
const existing = emitters.get(resolved);
|
|
808
|
+
if (existing !== void 0) return existing;
|
|
809
|
+
const record = {
|
|
810
|
+
listeners: /* @__PURE__ */ new Map(),
|
|
811
|
+
groupListeners,
|
|
812
|
+
lastReported: snapshot(resolved),
|
|
813
|
+
isMutating: false,
|
|
814
|
+
target: resolved
|
|
815
|
+
};
|
|
816
|
+
emitters.set(resolved, record);
|
|
817
|
+
return record;
|
|
818
|
+
}
|
|
819
|
+
function deleteEmitter(target) {
|
|
820
|
+
emitters.delete(target);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// src/emit/emitterBare.ts
|
|
824
|
+
var augmentBareCycleError = (error) => {
|
|
825
|
+
const path = getCyclicPath(error);
|
|
826
|
+
if (path === void 0) return void 0;
|
|
827
|
+
return new Error(
|
|
828
|
+
`opshot: a bare write created a cyclic value at ${formatOperationPath(path)}. Cycles cannot be tracked. This surfaced asynchronously because the write was not inside transact. Use transact for catchable cycle errors, ignore() for back-linked structures, or ids.`
|
|
829
|
+
);
|
|
830
|
+
};
|
|
831
|
+
var requireObjectSnapshot = (value) => {
|
|
832
|
+
if (value !== null && (typeof value === "object" || typeof value === "function")) return value;
|
|
833
|
+
throw new Error("opshot: state snapshots must have an object root");
|
|
834
|
+
};
|
|
802
835
|
var armWatchdog = (record) => {
|
|
803
836
|
if (record.disarm !== void 0) return;
|
|
804
837
|
record.lastReported = snapshot(record.target);
|
|
@@ -810,14 +843,6 @@ var disarmWatchdog = (record) => {
|
|
|
810
843
|
record.disarm?.();
|
|
811
844
|
record.disarm = void 0;
|
|
812
845
|
};
|
|
813
|
-
var deliver = (record, ops, meta) => {
|
|
814
|
-
for (const listener of [...record.groupListeners ?? []]) listener(record.target, ops, meta);
|
|
815
|
-
for (const listener of [...record.listeners]) listener(ops, meta);
|
|
816
|
-
};
|
|
817
|
-
var requireObjectSnapshot = (value) => {
|
|
818
|
-
if (value !== null && (typeof value === "object" || typeof value === "function")) return value;
|
|
819
|
-
throw new Error("opshot: state snapshots must have an object root");
|
|
820
|
-
};
|
|
821
846
|
var reportBareDiff = (record) => {
|
|
822
847
|
const current = snapshot(record.target);
|
|
823
848
|
if (current === record.lastReported) return;
|
|
@@ -835,53 +860,15 @@ var reportBareDiff = (record) => {
|
|
|
835
860
|
var settlePendingBare = (record) => {
|
|
836
861
|
reportBareDiff(record);
|
|
837
862
|
};
|
|
838
|
-
function getOrCreateEmitter(target, groupListeners) {
|
|
839
|
-
const resolved = resolveEmitterTarget(target);
|
|
840
|
-
const existing = emitters.get(resolved);
|
|
841
|
-
if (existing !== void 0) return existing;
|
|
842
|
-
const record = {
|
|
843
|
-
listeners: /* @__PURE__ */ new Set(),
|
|
844
|
-
groupListeners,
|
|
845
|
-
lastReported: snapshot(resolved),
|
|
846
|
-
isMutating: false,
|
|
847
|
-
target: resolved
|
|
848
|
-
};
|
|
849
|
-
emitters.set(resolved, record);
|
|
850
|
-
return record;
|
|
851
|
-
}
|
|
852
|
-
function mintGroupedEmitter(target, groupListeners) {
|
|
853
|
-
const record = getOrCreateEmitter(target, groupListeners);
|
|
854
|
-
armWatchdog(record);
|
|
855
|
-
return record;
|
|
856
|
-
}
|
|
857
863
|
function emitBareFlush(target) {
|
|
858
864
|
const record = getEmitter(target);
|
|
859
865
|
if (record === void 0) return;
|
|
860
866
|
reportBareDiff(record);
|
|
861
867
|
}
|
|
862
|
-
function
|
|
863
|
-
const
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
record = getOrCreateEmitter(target);
|
|
867
|
-
armWatchdog(record);
|
|
868
|
-
} else if (record.disarm === void 0 && record.groupListeners === void 0) {
|
|
869
|
-
armWatchdog(record);
|
|
870
|
-
}
|
|
871
|
-
record.listeners.add(listener);
|
|
872
|
-
return () => {
|
|
873
|
-
if (!record.listeners.delete(listener)) return;
|
|
874
|
-
if (record.groupListeners === void 0 && record.listeners.size === 0) {
|
|
875
|
-
disarmWatchdog(record);
|
|
876
|
-
emitters.delete(target);
|
|
877
|
-
}
|
|
878
|
-
};
|
|
879
|
-
}
|
|
880
|
-
function addGroupListener(groupListeners, listener) {
|
|
881
|
-
groupListeners.add(listener);
|
|
882
|
-
return () => {
|
|
883
|
-
groupListeners.delete(listener);
|
|
884
|
-
};
|
|
868
|
+
function mintGroupedEmitter(target, groupListeners) {
|
|
869
|
+
const record = getOrCreateEmitter(target, groupListeners);
|
|
870
|
+
armWatchdog(record);
|
|
871
|
+
return record;
|
|
885
872
|
}
|
|
886
873
|
|
|
887
874
|
// src/utils/constructorName.ts
|
|
@@ -1231,7 +1218,7 @@ function getGroupListeners(group) {
|
|
|
1231
1218
|
return listeners;
|
|
1232
1219
|
}
|
|
1233
1220
|
function createGroup() {
|
|
1234
|
-
const listeners = /* @__PURE__ */ new
|
|
1221
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
1235
1222
|
const group = {
|
|
1236
1223
|
createMutableState(properties) {
|
|
1237
1224
|
return createMutableState(properties, group);
|
|
@@ -1241,6 +1228,46 @@ function createGroup() {
|
|
|
1241
1228
|
return group;
|
|
1242
1229
|
}
|
|
1243
1230
|
|
|
1231
|
+
// src/emit/emitterListeners.ts
|
|
1232
|
+
function addStateListener(state, listener, channelId, deliver2) {
|
|
1233
|
+
const target = resolveEmitterTarget(state);
|
|
1234
|
+
const record = getOrCreateEmitter(target);
|
|
1235
|
+
if (record.disarm === void 0 && record.groupListeners === void 0) {
|
|
1236
|
+
armWatchdog(record);
|
|
1237
|
+
}
|
|
1238
|
+
let byChannel = record.listeners.get(listener);
|
|
1239
|
+
if (byChannel === void 0) {
|
|
1240
|
+
byChannel = /* @__PURE__ */ new Map();
|
|
1241
|
+
record.listeners.set(listener, byChannel);
|
|
1242
|
+
}
|
|
1243
|
+
byChannel.set(channelId, deliver2);
|
|
1244
|
+
return () => {
|
|
1245
|
+
const channels = record.listeners.get(listener);
|
|
1246
|
+
if (channels?.has(channelId) !== true) return;
|
|
1247
|
+
settlePendingBare(record);
|
|
1248
|
+
channels.delete(channelId);
|
|
1249
|
+
if (channels.size === 0) record.listeners.delete(listener);
|
|
1250
|
+
if (record.groupListeners === void 0 && record.listeners.size === 0) {
|
|
1251
|
+
disarmWatchdog(record);
|
|
1252
|
+
deleteEmitter(target);
|
|
1253
|
+
}
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
function addGroupListener(groupListeners, listener, channelId, deliver2) {
|
|
1257
|
+
let byChannel = groupListeners.get(listener);
|
|
1258
|
+
if (byChannel === void 0) {
|
|
1259
|
+
byChannel = /* @__PURE__ */ new Map();
|
|
1260
|
+
groupListeners.set(listener, byChannel);
|
|
1261
|
+
}
|
|
1262
|
+
byChannel.set(channelId, deliver2);
|
|
1263
|
+
return () => {
|
|
1264
|
+
const channels = groupListeners.get(listener);
|
|
1265
|
+
if (channels?.has(channelId) !== true) return;
|
|
1266
|
+
channels.delete(channelId);
|
|
1267
|
+
if (channels.size === 0) groupListeners.delete(listener);
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1244
1271
|
// src/transact.ts
|
|
1245
1272
|
function transact(state, mutate, meta) {
|
|
1246
1273
|
const record = getEmitter(state);
|
|
@@ -1440,11 +1467,11 @@ function applyOps(state, operations, meta) {
|
|
|
1440
1467
|
// src/subscribe.ts
|
|
1441
1468
|
function subscribe2(target, listener) {
|
|
1442
1469
|
if (isGroup(target)) {
|
|
1443
|
-
return addGroupListener(getGroupListeners(target), (state, ops, meta) => {
|
|
1470
|
+
return addGroupListener(getGroupListeners(target), listener, void 0, (state, ops, meta) => {
|
|
1444
1471
|
listener(state, ops, unwrapTransportMeta(meta));
|
|
1445
1472
|
});
|
|
1446
1473
|
}
|
|
1447
|
-
return addStateListener(target, (ops, meta) => {
|
|
1474
|
+
return addStateListener(target, listener, void 0, (ops, meta) => {
|
|
1448
1475
|
listener(ops, unwrapTransportMeta(meta));
|
|
1449
1476
|
});
|
|
1450
1477
|
}
|
|
@@ -1477,7 +1504,7 @@ function createChannel(defaults) {
|
|
|
1477
1504
|
}
|
|
1478
1505
|
function subscribe3(target, listener) {
|
|
1479
1506
|
if (isGroup(target)) {
|
|
1480
|
-
return addGroupListener(getGroupListeners(target), (state, ops, meta) => {
|
|
1507
|
+
return addGroupListener(getGroupListeners(target), listener, channelId, (state, ops, meta) => {
|
|
1481
1508
|
listener(
|
|
1482
1509
|
state,
|
|
1483
1510
|
ops,
|
|
@@ -1485,7 +1512,7 @@ function createChannel(defaults) {
|
|
|
1485
1512
|
);
|
|
1486
1513
|
});
|
|
1487
1514
|
}
|
|
1488
|
-
return addStateListener(target, (ops, meta) => {
|
|
1515
|
+
return addStateListener(target, listener, channelId, (ops, meta) => {
|
|
1489
1516
|
listener(
|
|
1490
1517
|
ops,
|
|
1491
1518
|
toChannelContext(channelId, defaults, meta)
|
|
@@ -1986,6 +2013,7 @@ var bindMethodToWrapper = (wrapper, method) => {
|
|
|
1986
2013
|
function createBoundary() {
|
|
1987
2014
|
const partitions = /* @__PURE__ */ new Map();
|
|
1988
2015
|
const targets = /* @__PURE__ */ new Map();
|
|
2016
|
+
let afterRender = false;
|
|
1989
2017
|
const getPartition = (sourceProxy) => {
|
|
1990
2018
|
let partition = partitions.get(sourceProxy);
|
|
1991
2019
|
if (partition === void 0) {
|
|
@@ -2000,7 +2028,9 @@ function createBoundary() {
|
|
|
2000
2028
|
}
|
|
2001
2029
|
return partition;
|
|
2002
2030
|
};
|
|
2031
|
+
const trackUsage = (partition, liveProxy) => afterRender ? {} : getUsage(partition.affected, liveProxy);
|
|
2003
2032
|
const ensureBaseline = (partition, liveProxy) => {
|
|
2033
|
+
if (afterRender) return snapshot(liveProxy);
|
|
2004
2034
|
const existing = partition.baselines.get(liveProxy);
|
|
2005
2035
|
if (existing !== void 0) return existing;
|
|
2006
2036
|
const baseline = snapshot(liveProxy);
|
|
@@ -2008,6 +2038,7 @@ function createBoundary() {
|
|
|
2008
2038
|
return baseline;
|
|
2009
2039
|
};
|
|
2010
2040
|
const ensureRootBaseline = (partition) => {
|
|
2041
|
+
if (afterRender) return partition.previousRootSnapshot ?? snapshot(partition.sourceProxy);
|
|
2011
2042
|
if (partition.previousRootSnapshot === void 0) {
|
|
2012
2043
|
partition.previousRootSnapshot = snapshot(partition.sourceProxy);
|
|
2013
2044
|
partition.baselines.set(partition.sourceProxy, partition.previousRootSnapshot);
|
|
@@ -2032,7 +2063,7 @@ function createBoundary() {
|
|
|
2032
2063
|
ensureRootBaseline(partition);
|
|
2033
2064
|
const value = Reflect.get(liveProxy, prop, liveProxy);
|
|
2034
2065
|
const wrapper2 = wrapperBox.current;
|
|
2035
|
-
const used =
|
|
2066
|
+
const used = trackUsage(partition, liveProxy);
|
|
2036
2067
|
recordKey(used, KEYS_PROPERTY2, prop);
|
|
2037
2068
|
ensureBaseline(partition, liveProxy);
|
|
2038
2069
|
if (typeof value === "function") {
|
|
@@ -2048,19 +2079,19 @@ function createBoundary() {
|
|
|
2048
2079
|
return wrapLive(value, partition);
|
|
2049
2080
|
},
|
|
2050
2081
|
has(_target, prop) {
|
|
2051
|
-
const used =
|
|
2082
|
+
const used = trackUsage(partition, liveProxy);
|
|
2052
2083
|
recordKey(used, HAS_KEY_PROPERTY2, prop);
|
|
2053
2084
|
ensureBaseline(partition, liveProxy);
|
|
2054
2085
|
return Reflect.has(liveProxy, prop);
|
|
2055
2086
|
},
|
|
2056
2087
|
getOwnPropertyDescriptor(_target, prop) {
|
|
2057
|
-
const used =
|
|
2088
|
+
const used = trackUsage(partition, liveProxy);
|
|
2058
2089
|
recordKey(used, HAS_OWN_KEY_PROPERTY2, prop);
|
|
2059
2090
|
ensureBaseline(partition, liveProxy);
|
|
2060
2091
|
return Reflect.getOwnPropertyDescriptor(liveProxy, prop);
|
|
2061
2092
|
},
|
|
2062
2093
|
ownKeys() {
|
|
2063
|
-
const used =
|
|
2094
|
+
const used = trackUsage(partition, liveProxy);
|
|
2064
2095
|
used[ALL_OWN_KEYS_PROPERTY2] = true;
|
|
2065
2096
|
ensureBaseline(partition, liveProxy);
|
|
2066
2097
|
return Reflect.ownKeys(liveProxy);
|
|
@@ -2104,6 +2135,9 @@ function createBoundary() {
|
|
|
2104
2135
|
const nextRoot = snapshot(sourceProxy);
|
|
2105
2136
|
return isChanged(partition.previousRootSnapshot, nextRoot, translated, /* @__PURE__ */ new WeakMap());
|
|
2106
2137
|
},
|
|
2138
|
+
captureReads() {
|
|
2139
|
+
afterRender = true;
|
|
2140
|
+
},
|
|
2107
2141
|
evictChangedTargets() {
|
|
2108
2142
|
for (const [liveProxy, entry] of targets) {
|
|
2109
2143
|
const current = snapshot(liveProxy);
|
|
@@ -2116,11 +2150,21 @@ function createBoundary() {
|
|
|
2116
2150
|
}
|
|
2117
2151
|
},
|
|
2118
2152
|
resetReads() {
|
|
2153
|
+
afterRender = false;
|
|
2119
2154
|
for (const partition of partitions.values()) {
|
|
2120
2155
|
partition.previousRootSnapshot = void 0;
|
|
2121
2156
|
partition.affected.clear();
|
|
2122
2157
|
partition.baselines.clear();
|
|
2123
2158
|
}
|
|
2159
|
+
},
|
|
2160
|
+
advanceBaselines() {
|
|
2161
|
+
for (const partition of partitions.values()) {
|
|
2162
|
+
for (const liveProxy of [...partition.baselines.keys()]) {
|
|
2163
|
+
partition.baselines.set(liveProxy, snapshot(liveProxy));
|
|
2164
|
+
}
|
|
2165
|
+
partition.previousRootSnapshot = snapshot(partition.sourceProxy);
|
|
2166
|
+
partition.baselines.set(partition.sourceProxy, partition.previousRootSnapshot);
|
|
2167
|
+
}
|
|
2124
2168
|
}
|
|
2125
2169
|
};
|
|
2126
2170
|
}
|
|
@@ -2207,6 +2251,22 @@ function setAtPath(object, path, value) {
|
|
|
2207
2251
|
return clone;
|
|
2208
2252
|
}
|
|
2209
2253
|
var sourcesKey = (sources) => `${sources.length}:${sources.map((source) => addressOf(source)).join(",")}`;
|
|
2254
|
+
var arePropsEqual = (previous, next) => {
|
|
2255
|
+
const previousRecord = previous;
|
|
2256
|
+
const nextRecord = next;
|
|
2257
|
+
const keys = Object.keys(previousRecord);
|
|
2258
|
+
if (keys.length !== Object.keys(nextRecord).length) return false;
|
|
2259
|
+
for (const key of keys) {
|
|
2260
|
+
const before = previousRecord[key];
|
|
2261
|
+
const after = nextRecord[key];
|
|
2262
|
+
if (Object.is(before, after)) continue;
|
|
2263
|
+
if (typeof before === "object" && before !== null && typeof after === "object" && after !== null && isState(before) && isState(after) && isSameIdentity(before, after)) {
|
|
2264
|
+
continue;
|
|
2265
|
+
}
|
|
2266
|
+
return false;
|
|
2267
|
+
}
|
|
2268
|
+
return true;
|
|
2269
|
+
};
|
|
2210
2270
|
function scope(Component, options) {
|
|
2211
2271
|
const maxDepth = options?.maxDepth ?? 10;
|
|
2212
2272
|
const Scoped = (props) => {
|
|
@@ -2233,6 +2293,9 @@ function scope(Component, options) {
|
|
|
2233
2293
|
}
|
|
2234
2294
|
const renderedProps = changed ? nextProps : props;
|
|
2235
2295
|
const versionsAtRender = sources.map((source) => getVersion(source));
|
|
2296
|
+
useEffect(() => {
|
|
2297
|
+
boundary.captureReads();
|
|
2298
|
+
});
|
|
2236
2299
|
useEffect(() => {
|
|
2237
2300
|
const unsubscribes = sources.map(
|
|
2238
2301
|
(source) => subscribe(
|
|
@@ -2240,6 +2303,7 @@ function scope(Component, options) {
|
|
|
2240
2303
|
() => {
|
|
2241
2304
|
boundary.evictChangedTargets();
|
|
2242
2305
|
if (boundary.readsChanged(source)) bump();
|
|
2306
|
+
else boundary.advanceBaselines();
|
|
2243
2307
|
},
|
|
2244
2308
|
true
|
|
2245
2309
|
)
|
|
@@ -2265,7 +2329,7 @@ function scope(Component, options) {
|
|
|
2265
2329
|
};
|
|
2266
2330
|
const baseName = Component.displayName ?? Component.name;
|
|
2267
2331
|
Scoped.displayName = `scope(${typeof baseName === "string" && baseName !== "" ? baseName : "Component"})`;
|
|
2268
|
-
return memo(Scoped);
|
|
2332
|
+
return memo(Scoped, arePropsEqual);
|
|
2269
2333
|
}
|
|
2270
2334
|
function useGroup() {
|
|
2271
2335
|
return useState(() => createGroup())[0];
|
|
@@ -2279,10 +2343,14 @@ function useMutableState(properties, group) {
|
|
|
2279
2343
|
const versionAtRender = getVersion(proxy2);
|
|
2280
2344
|
boundary.resetReads();
|
|
2281
2345
|
const wrapper = boundary.wrap(proxy2);
|
|
2346
|
+
useEffect(() => {
|
|
2347
|
+
boundary.captureReads();
|
|
2348
|
+
});
|
|
2282
2349
|
useEffect(() => {
|
|
2283
2350
|
const onSignal = () => {
|
|
2284
2351
|
boundary.evictChangedTargets();
|
|
2285
2352
|
if (boundary.readsChanged(proxy2)) bump();
|
|
2353
|
+
else boundary.advanceBaselines();
|
|
2286
2354
|
};
|
|
2287
2355
|
return subscribe(proxy2, onSignal, true);
|
|
2288
2356
|
}, [proxy2, boundary]);
|
package/package.json
CHANGED