doxum 0.1.32 → 0.1.34
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 +33 -1
- package/dist/advanced.cjs +1 -1
- package/dist/advanced.d.cts +1 -1
- package/dist/advanced.d.ts +1 -1
- package/dist/advanced.js +1 -1
- package/dist/{dependency-B1qIJJBL.d.cts → dependency-Cbf3C8eJ.d.cts} +2 -2
- package/dist/{dependency-BRgPvyN6.d.ts → dependency-DzxXGYe1.d.ts} +2 -2
- package/dist/index.cjs +580 -212
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -12
- package/dist/index.d.ts +19 -12
- package/dist/index.js +580 -212
- package/dist/index.js.map +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js.map +1 -1
- package/dist/{transform-CENhTaVN.cjs → transform-Bt1Mwgrj.cjs} +310 -280
- package/dist/transform-Bt1Mwgrj.cjs.map +1 -0
- package/dist/{transform-gOtqcdHe.js → transform-RghG_Qxs.js} +305 -275
- package/dist/transform-RghG_Qxs.js.map +1 -0
- package/package.json +1 -1
- package/skills/doxum-runtime/SKILL.md +4 -2
- package/skills/doxum-runtime/references/integrations.md +2 -2
- package/skills/doxum-runtime/references/invariants.md +6 -3
- package/skills/doxum-runtime/references/projections.md +62 -3
- package/skills/doxum-runtime/references/public-api.md +14 -4
- package/skills/doxum-runtime/references/recipes.md +32 -0
- package/dist/transform-CENhTaVN.cjs.map +0 -1
- package/dist/transform-gOtqcdHe.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_transform = require("./transform-
|
|
2
|
+
const require_transform = require("./transform-Bt1Mwgrj.cjs");
|
|
3
3
|
const require_record = require("./record-ChYUi8PP.cjs");
|
|
4
4
|
const require_driver = require("./driver-CN3dGxQI.cjs");
|
|
5
5
|
//#region core/src/schema/model.ts
|
|
@@ -2775,6 +2775,108 @@ const isExternalSource = (source) => {
|
|
|
2775
2775
|
return (candidate.kind === "value" || candidate.kind === "collection") && typeof candidate.current === "function" && typeof candidate.revision === "function" && typeof candidate.subscribe === "function";
|
|
2776
2776
|
};
|
|
2777
2777
|
//#endregion
|
|
2778
|
+
//#region core/src/projection/keyed/flat-map.ts
|
|
2779
|
+
function createKeyedFlatMap(source, dependenciesOrSelect, selectOrEquality, maybeEquality) {
|
|
2780
|
+
const name = "derive.keyed.flatMap";
|
|
2781
|
+
require_transform.assertKeyedProjection(source, `${name} source`);
|
|
2782
|
+
const specs = typeof dependenciesOrSelect === "function" ? void 0 : dependenciesOrSelect;
|
|
2783
|
+
const select = specs === void 0 ? dependenciesOrSelect : selectOrEquality;
|
|
2784
|
+
const equality = specs === void 0 ? selectOrEquality : maybeEquality;
|
|
2785
|
+
if (typeof select !== "function") throw new TypeError(`${name} requires a selector.`);
|
|
2786
|
+
if (equality !== void 0 && typeof equality !== "function") throw new TypeError(`${name} equality must be a function.`);
|
|
2787
|
+
const compiled = require_transform.compileKeyedDependencies(source, specs, name);
|
|
2788
|
+
const [projection] = require_transform.defineProcessor({
|
|
2789
|
+
dependencies: compiled.projections,
|
|
2790
|
+
outputs: [{
|
|
2791
|
+
kind: "collection",
|
|
2792
|
+
equality: equality ?? Object.is
|
|
2793
|
+
}],
|
|
2794
|
+
name,
|
|
2795
|
+
create: () => {
|
|
2796
|
+
const dependencies = require_transform.createKeyedDependencyRuntime(compiled);
|
|
2797
|
+
const childrenByParent = /* @__PURE__ */ new Map();
|
|
2798
|
+
const ownerByOutput = /* @__PURE__ */ new Map();
|
|
2799
|
+
return {
|
|
2800
|
+
evaluate: (evaluation) => {
|
|
2801
|
+
const driver = evaluation.sources[0];
|
|
2802
|
+
const output = evaluation.outputs[0];
|
|
2803
|
+
if (driver.kind !== "collection" || output.kind !== "collection") throw new Error(`${name} requires collection input and output.`);
|
|
2804
|
+
const plan = require_transform.collectKeyedInvalidation(driver, evaluation.sources, dependencies, evaluation.reset);
|
|
2805
|
+
dependencies.prepare(evaluation.sources, plan.rebuild);
|
|
2806
|
+
if (plan.rebuild) {
|
|
2807
|
+
dependencies.clearBindings();
|
|
2808
|
+
childrenByParent.clear();
|
|
2809
|
+
ownerByOutput.clear();
|
|
2810
|
+
}
|
|
2811
|
+
const replaced = new Set(plan.keys);
|
|
2812
|
+
for (const entry of plan.removed) replaced.add(entry.key);
|
|
2813
|
+
const proposals = /* @__PURE__ */ new Map();
|
|
2814
|
+
const segments = /* @__PURE__ */ new Map();
|
|
2815
|
+
let orderDirty = plan.structural;
|
|
2816
|
+
for (const parent of replaced) {
|
|
2817
|
+
if (!driver.read.has(parent)) continue;
|
|
2818
|
+
const value = driver.read.get(parent);
|
|
2819
|
+
const entries = select(value, parent, dependencies.resolve(value, parent, evaluation.sources));
|
|
2820
|
+
require_transform.assertSynchronous(entries);
|
|
2821
|
+
if (!Array.isArray(entries)) throw new TypeError(`${name} selector must return an array of entries.`);
|
|
2822
|
+
const keys = [];
|
|
2823
|
+
for (const entry of entries) {
|
|
2824
|
+
if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== "string") throw new TypeError(`${name} entries must be [string key, value] tuples.`);
|
|
2825
|
+
const [key, child] = entry;
|
|
2826
|
+
const owner = ownerByOutput.get(key);
|
|
2827
|
+
if (proposals.has(key) || owner !== void 0 && !replaced.has(owner)) throw new TypeError(`${name} duplicate key ${JSON.stringify(key)}.`);
|
|
2828
|
+
proposals.set(key, {
|
|
2829
|
+
parent,
|
|
2830
|
+
value: child
|
|
2831
|
+
});
|
|
2832
|
+
keys.push(key);
|
|
2833
|
+
}
|
|
2834
|
+
const previous = childrenByParent.get(parent);
|
|
2835
|
+
const unchanged = previous ? require_transform.sameArray(previous, keys) : keys.length === 0;
|
|
2836
|
+
if (!unchanged) orderDirty = true;
|
|
2837
|
+
if (keys.length) segments.set(parent, unchanged && previous ? previous : Object.freeze(keys));
|
|
2838
|
+
}
|
|
2839
|
+
if (plan.rebuild) {
|
|
2840
|
+
if (!evaluation.reset) {
|
|
2841
|
+
for (const key of output.previous.ids()) if (!proposals.has(key)) output.output.remove(key);
|
|
2842
|
+
}
|
|
2843
|
+
} else for (const parent of replaced) {
|
|
2844
|
+
const previous = childrenByParent.get(parent);
|
|
2845
|
+
if (previous) for (const key of previous) {
|
|
2846
|
+
if (!proposals.has(key)) output.output.remove(key);
|
|
2847
|
+
ownerByOutput.delete(key);
|
|
2848
|
+
}
|
|
2849
|
+
childrenByParent.delete(parent);
|
|
2850
|
+
}
|
|
2851
|
+
for (const entry of plan.removed) dependencies.remove(entry.key);
|
|
2852
|
+
for (const [parent, keys] of segments) childrenByParent.set(parent, keys);
|
|
2853
|
+
for (const [key, entry] of proposals) {
|
|
2854
|
+
ownerByOutput.set(key, entry.parent);
|
|
2855
|
+
output.output.set(key, entry.value);
|
|
2856
|
+
}
|
|
2857
|
+
if (orderDirty) {
|
|
2858
|
+
const order = [];
|
|
2859
|
+
const parents = driver.read.ids();
|
|
2860
|
+
for (const parent of parents) {
|
|
2861
|
+
const keys = childrenByParent.get(parent);
|
|
2862
|
+
if (keys) for (const key of keys) order.push(key);
|
|
2863
|
+
}
|
|
2864
|
+
require_transform.profile.collectionView.idsScanned(parents.length + order.length);
|
|
2865
|
+
output.output.order(order);
|
|
2866
|
+
}
|
|
2867
|
+
dependencies.remember(evaluation.sources);
|
|
2868
|
+
},
|
|
2869
|
+
release: () => {
|
|
2870
|
+
childrenByParent.clear();
|
|
2871
|
+
ownerByOutput.clear();
|
|
2872
|
+
dependencies.release();
|
|
2873
|
+
}
|
|
2874
|
+
};
|
|
2875
|
+
}
|
|
2876
|
+
});
|
|
2877
|
+
return projection;
|
|
2878
|
+
}
|
|
2879
|
+
//#endregion
|
|
2778
2880
|
//#region core/src/projection/keyed/composition.ts
|
|
2779
2881
|
const assertEquality = (equality, role) => {
|
|
2780
2882
|
if (equality !== void 0 && typeof equality !== "function") throw new TypeError(`${role} equality must be a function.`);
|
|
@@ -3441,44 +3543,26 @@ function createKeyedGroupBy(source, dependenciesOrSelector, maybeSelector) {
|
|
|
3441
3543
|
const driver = evaluation.sources[0];
|
|
3442
3544
|
const output = evaluation.outputs[0];
|
|
3443
3545
|
if (driver.kind !== "collection" || output.kind !== "collection") throw new Error("derive.keyed.groupBy requires collection input and output.");
|
|
3444
|
-
|
|
3445
|
-
|
|
3546
|
+
const invalidation = require_transform.collectKeyedInvalidation(driver, evaluation.sources, dependencies, evaluation.reset);
|
|
3547
|
+
dependencies.prepare(evaluation.sources, invalidation.rebuild);
|
|
3548
|
+
if (invalidation.rebuild) {
|
|
3446
3549
|
rebuild(driver, evaluation.sources, output);
|
|
3447
3550
|
dependencies.remember(evaluation.sources);
|
|
3448
3551
|
return;
|
|
3449
3552
|
}
|
|
3450
|
-
const dirty = /* @__PURE__ */ new Set();
|
|
3451
3553
|
const affected = /* @__PURE__ */ new Set();
|
|
3452
|
-
let
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
if (!change || change.kind === "reset") {
|
|
3458
|
-
rebuild(driver, evaluation.sources, output);
|
|
3459
|
-
dependencies.remember(evaluation.sources);
|
|
3460
|
-
return;
|
|
3461
|
-
} else {
|
|
3462
|
-
for (const entry of change.removed) {
|
|
3463
|
-
const changed = removeSourceKey(entry.key, affected);
|
|
3464
|
-
orderDirty ||= changed;
|
|
3465
|
-
dependencies.remove(entry.key);
|
|
3466
|
-
dirty.delete(entry.key);
|
|
3467
|
-
}
|
|
3468
|
-
for (const entry of change.added) dirty.add(entry.key);
|
|
3469
|
-
for (const entry of change.updated) dirty.add(entry.key);
|
|
3470
|
-
structural = Boolean(change.added.length || change.removed.length || change.order);
|
|
3471
|
-
orderDirty ||= structural;
|
|
3472
|
-
if (structural) refreshOrderIndex(driver);
|
|
3473
|
-
}
|
|
3554
|
+
let orderDirty = invalidation.structural;
|
|
3555
|
+
for (const entry of invalidation.removed) {
|
|
3556
|
+
const changed = removeSourceKey(entry.key, affected);
|
|
3557
|
+
orderDirty ||= changed;
|
|
3558
|
+
dependencies.remove(entry.key);
|
|
3474
3559
|
}
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
for (const key of dirty) {
|
|
3560
|
+
if (invalidation.structural) refreshOrderIndex(driver);
|
|
3561
|
+
for (const key of invalidation.keys) {
|
|
3478
3562
|
const changed = selectGroups(driver, evaluation.sources, key, affected);
|
|
3479
3563
|
orderDirty ||= changed;
|
|
3480
3564
|
}
|
|
3481
|
-
if (structural) markAllGroups(output, affected);
|
|
3565
|
+
if (invalidation.structural) markAllGroups(output, affected);
|
|
3482
3566
|
publishAffected(affected, output, orderDirty);
|
|
3483
3567
|
dependencies.remember(evaluation.sources);
|
|
3484
3568
|
},
|
|
@@ -3502,6 +3586,7 @@ const keyedDerive = Object.assign(createKeyedDerive, {
|
|
|
3502
3586
|
from: createKeyedFrom,
|
|
3503
3587
|
merge: createKeyedMerge,
|
|
3504
3588
|
groupBy: createKeyedGroupBy,
|
|
3589
|
+
flatMap: createKeyedFlatMap,
|
|
3505
3590
|
singleton: createKeyedSingleton,
|
|
3506
3591
|
subset: createKeyedSubset,
|
|
3507
3592
|
filter: createKeyedFilter,
|
|
@@ -3533,6 +3618,104 @@ function createValueDerive(dependencies, compute, equality = Object.is) {
|
|
|
3533
3618
|
}
|
|
3534
3619
|
const derive = Object.assign(createValueDerive, { keyed: keyedDerive });
|
|
3535
3620
|
//#endregion
|
|
3621
|
+
//#region core/src/projection/collection/changes.ts
|
|
3622
|
+
/** Net transitions for one consumer's unconsumed interval; bounded by touched keys. */
|
|
3623
|
+
const createCollectionChanges = () => {
|
|
3624
|
+
let first;
|
|
3625
|
+
let beforeOrder = [];
|
|
3626
|
+
let afterOrder = [];
|
|
3627
|
+
let cached;
|
|
3628
|
+
let valid = false;
|
|
3629
|
+
let transitions;
|
|
3630
|
+
const merge = (change) => {
|
|
3631
|
+
const write = (key, before, after) => {
|
|
3632
|
+
const previous = transitions.get(key);
|
|
3633
|
+
const initial = previous?.before ?? before;
|
|
3634
|
+
if (initial.present === after.present && (!initial.present || after.present && Object.is(initial.value, after.value))) transitions.delete(key);
|
|
3635
|
+
else if (previous) previous.after = after;
|
|
3636
|
+
else transitions.set(key, {
|
|
3637
|
+
before,
|
|
3638
|
+
after
|
|
3639
|
+
});
|
|
3640
|
+
};
|
|
3641
|
+
for (const entry of change.added) write(entry.key, { present: false }, {
|
|
3642
|
+
present: true,
|
|
3643
|
+
value: entry.after
|
|
3644
|
+
});
|
|
3645
|
+
for (const entry of change.updated) write(entry.key, {
|
|
3646
|
+
present: true,
|
|
3647
|
+
value: entry.before
|
|
3648
|
+
}, {
|
|
3649
|
+
present: true,
|
|
3650
|
+
value: entry.after
|
|
3651
|
+
});
|
|
3652
|
+
for (const entry of change.removed) write(entry.key, {
|
|
3653
|
+
present: true,
|
|
3654
|
+
value: entry.before
|
|
3655
|
+
}, { present: false });
|
|
3656
|
+
};
|
|
3657
|
+
return {
|
|
3658
|
+
add(change, before, after) {
|
|
3659
|
+
valid = false;
|
|
3660
|
+
afterOrder = after;
|
|
3661
|
+
if (!first) {
|
|
3662
|
+
first = change;
|
|
3663
|
+
beforeOrder = before;
|
|
3664
|
+
return;
|
|
3665
|
+
}
|
|
3666
|
+
if (first.kind === "reset") return;
|
|
3667
|
+
if (change.kind === "reset") {
|
|
3668
|
+
first = change;
|
|
3669
|
+
transitions = void 0;
|
|
3670
|
+
return;
|
|
3671
|
+
}
|
|
3672
|
+
if (!transitions) {
|
|
3673
|
+
transitions = /* @__PURE__ */ new Map();
|
|
3674
|
+
merge(first);
|
|
3675
|
+
}
|
|
3676
|
+
merge(change);
|
|
3677
|
+
},
|
|
3678
|
+
current() {
|
|
3679
|
+
if (!transitions) return first;
|
|
3680
|
+
if (valid) return cached;
|
|
3681
|
+
const added = [];
|
|
3682
|
+
const updated = [];
|
|
3683
|
+
const removed = [];
|
|
3684
|
+
for (const [key, { before, after }] of transitions) if (!before.present) {
|
|
3685
|
+
if (after.present) added.push({
|
|
3686
|
+
key,
|
|
3687
|
+
after: after.value
|
|
3688
|
+
});
|
|
3689
|
+
} else if (!after.present) removed.push({
|
|
3690
|
+
key,
|
|
3691
|
+
before: before.value
|
|
3692
|
+
});
|
|
3693
|
+
else if (!Object.is(before.value, after.value)) updated.push({
|
|
3694
|
+
key,
|
|
3695
|
+
before: before.value,
|
|
3696
|
+
after: after.value
|
|
3697
|
+
});
|
|
3698
|
+
cached = require_transform.createCollectionChange({
|
|
3699
|
+
added,
|
|
3700
|
+
updated,
|
|
3701
|
+
removed,
|
|
3702
|
+
beforeOrder,
|
|
3703
|
+
afterOrder
|
|
3704
|
+
});
|
|
3705
|
+
valid = true;
|
|
3706
|
+
return cached;
|
|
3707
|
+
},
|
|
3708
|
+
reset: () => first?.kind === "reset",
|
|
3709
|
+
clear() {
|
|
3710
|
+
first = void 0;
|
|
3711
|
+
cached = void 0;
|
|
3712
|
+
valid = false;
|
|
3713
|
+
transitions = void 0;
|
|
3714
|
+
beforeOrder = afterOrder = [];
|
|
3715
|
+
}
|
|
3716
|
+
};
|
|
3717
|
+
};
|
|
3718
|
+
//#endregion
|
|
3536
3719
|
//#region core/src/projection/collection/index.ts
|
|
3537
3720
|
const height = (node) => node?.height ?? 0;
|
|
3538
3721
|
const node = (key, value, left, right) => {
|
|
@@ -3623,11 +3806,11 @@ var PersistentKeyedIndex = class PersistentKeyedIndex {
|
|
|
3623
3806
|
}
|
|
3624
3807
|
};
|
|
3625
3808
|
//#endregion
|
|
3626
|
-
//#region core/src/projection/
|
|
3627
|
-
const
|
|
3628
|
-
const values =
|
|
3629
|
-
let ids = Object.freeze([]);
|
|
3630
|
-
let index
|
|
3809
|
+
//#region core/src/projection/collection/state.ts
|
|
3810
|
+
const createCollectionState = (initial) => {
|
|
3811
|
+
const values = new Map(initial);
|
|
3812
|
+
let ids = Object.freeze([...values.keys()]);
|
|
3813
|
+
let index;
|
|
3631
3814
|
return {
|
|
3632
3815
|
get: (key) => values.get(key),
|
|
3633
3816
|
has: (key) => values.has(key),
|
|
@@ -3635,7 +3818,7 @@ const createPublishedCollection = () => {
|
|
|
3635
3818
|
size: () => values.size,
|
|
3636
3819
|
ids: () => ids,
|
|
3637
3820
|
read: (check) => {
|
|
3638
|
-
const snapshotIndex = index;
|
|
3821
|
+
const snapshotIndex = index ??= PersistentKeyedIndex.from(values);
|
|
3639
3822
|
const snapshotIds = ids;
|
|
3640
3823
|
return Object.freeze({
|
|
3641
3824
|
get: (key) => {
|
|
@@ -3652,13 +3835,13 @@ const createPublishedCollection = () => {
|
|
|
3652
3835
|
}
|
|
3653
3836
|
});
|
|
3654
3837
|
},
|
|
3655
|
-
|
|
3838
|
+
install: (staged, nextIds, reset) => {
|
|
3656
3839
|
if (reset) {
|
|
3657
3840
|
values.clear();
|
|
3658
3841
|
for (const [key, entry] of staged) if (entry.present) values.set(key, entry.value);
|
|
3659
|
-
index = PersistentKeyedIndex.from(values);
|
|
3842
|
+
if (index) index = PersistentKeyedIndex.from(values);
|
|
3660
3843
|
} else for (const [key, entry] of staged) {
|
|
3661
|
-
index = entry.present ? index.set(key, entry.value) : index.remove(key);
|
|
3844
|
+
if (index) index = entry.present ? index.set(key, entry.value) : index.remove(key);
|
|
3662
3845
|
if (entry.present) values.set(key, entry.value);
|
|
3663
3846
|
else values.delete(key);
|
|
3664
3847
|
}
|
|
@@ -3667,15 +3850,17 @@ const createPublishedCollection = () => {
|
|
|
3667
3850
|
release: () => {
|
|
3668
3851
|
values.clear();
|
|
3669
3852
|
ids = Object.freeze([]);
|
|
3670
|
-
index =
|
|
3853
|
+
index = void 0;
|
|
3671
3854
|
}
|
|
3672
3855
|
};
|
|
3673
3856
|
};
|
|
3674
|
-
|
|
3857
|
+
//#endregion
|
|
3858
|
+
//#region core/src/projection/output/collection.ts
|
|
3859
|
+
/** Owns staged keyed intent, exact transitions and current collection state. */
|
|
3675
3860
|
const createCollectionOutput = (binding) => {
|
|
3676
|
-
const
|
|
3861
|
+
const currentState = createCollectionState();
|
|
3677
3862
|
const staged = /* @__PURE__ */ new Map();
|
|
3678
|
-
let nextIds =
|
|
3863
|
+
let nextIds = currentState.ids();
|
|
3679
3864
|
let change;
|
|
3680
3865
|
let initialized = false;
|
|
3681
3866
|
let reset = false;
|
|
@@ -3683,23 +3868,26 @@ const createCollectionOutput = (binding) => {
|
|
|
3683
3868
|
let explicitOrder;
|
|
3684
3869
|
let cleared = false;
|
|
3685
3870
|
const listeners = /* @__PURE__ */ new Set();
|
|
3686
|
-
const consumers = /* @__PURE__ */ new
|
|
3687
|
-
const
|
|
3871
|
+
const consumers = /* @__PURE__ */ new Map();
|
|
3872
|
+
const notifications = createCollectionChanges();
|
|
3873
|
+
const observers = /* @__PURE__ */ new Set();
|
|
3874
|
+
let baseline;
|
|
3875
|
+
const hasNext = (key) => staged.has(key) ? staged.get(key).present : !cleared && currentState.has(key);
|
|
3688
3876
|
const getNext = (key) => {
|
|
3689
3877
|
const entry = staged.get(key);
|
|
3690
|
-
return entry ? entry.present ? entry.value : void 0 : cleared ? void 0 :
|
|
3878
|
+
return entry ? entry.present ? entry.value : void 0 : cleared ? void 0 : currentState.get(key);
|
|
3691
3879
|
};
|
|
3692
3880
|
const deriveIds = () => {
|
|
3693
3881
|
const result = [];
|
|
3694
3882
|
if (!cleared) {
|
|
3695
|
-
for (const key of
|
|
3883
|
+
for (const key of currentState.ids()) if (hasNext(key)) result.push(key);
|
|
3696
3884
|
}
|
|
3697
|
-
for (const [key, entry] of staged) if (entry.present && (cleared || !
|
|
3885
|
+
for (const [key, entry] of staged) if (entry.present && (cleared || !currentState.has(key))) result.push(key);
|
|
3698
3886
|
return result;
|
|
3699
3887
|
};
|
|
3700
3888
|
const begin = (active, initialize) => {
|
|
3701
3889
|
staged.clear();
|
|
3702
|
-
nextIds =
|
|
3890
|
+
nextIds = currentState.ids();
|
|
3703
3891
|
change = void 0;
|
|
3704
3892
|
explicitOrder = void 0;
|
|
3705
3893
|
cleared = initialize;
|
|
@@ -3707,15 +3895,15 @@ const createCollectionOutput = (binding) => {
|
|
|
3707
3895
|
const read = (next) => ({
|
|
3708
3896
|
get: (key) => {
|
|
3709
3897
|
require_transform.assertScope(active);
|
|
3710
|
-
return next ? getNext(key) :
|
|
3898
|
+
return next ? getNext(key) : currentState.get(key);
|
|
3711
3899
|
},
|
|
3712
3900
|
has: (key) => {
|
|
3713
3901
|
require_transform.assertScope(active);
|
|
3714
|
-
return next ? hasNext(key) :
|
|
3902
|
+
return next ? hasNext(key) : currentState.has(key);
|
|
3715
3903
|
},
|
|
3716
3904
|
ids: () => {
|
|
3717
3905
|
require_transform.assertScope(active);
|
|
3718
|
-
if (!next) return
|
|
3906
|
+
if (!next) return currentState.ids();
|
|
3719
3907
|
if (explicitOrder) return explicitOrder;
|
|
3720
3908
|
return Object.freeze(deriveIds());
|
|
3721
3909
|
}
|
|
@@ -3745,15 +3933,28 @@ const createCollectionOutput = (binding) => {
|
|
|
3745
3933
|
};
|
|
3746
3934
|
const seal = (nextReset, isEqual) => {
|
|
3747
3935
|
if (cleared) {
|
|
3748
|
-
for (const key of
|
|
3936
|
+
for (const key of currentState.keys()) if (!staged.has(key)) staged.set(key, { present: false });
|
|
3749
3937
|
}
|
|
3750
3938
|
require_transform.profile.projection("touchedKeys", staged.size);
|
|
3751
3939
|
const addedEntries = [];
|
|
3752
3940
|
const updatedEntries = [];
|
|
3753
3941
|
const removedEntries = [];
|
|
3754
|
-
for (const [key,
|
|
3755
|
-
|
|
3942
|
+
for (const [key, original] of staged) {
|
|
3943
|
+
let entry = original;
|
|
3944
|
+
const existed = currentState.has(key);
|
|
3756
3945
|
if (entry.present) {
|
|
3946
|
+
if (baseline?.has(key) && (!existed || !Object.is(currentState.get(key), baseline.get(key)))) {
|
|
3947
|
+
const before = baseline.get(key);
|
|
3948
|
+
const equivalent = isEqual(before, entry.value);
|
|
3949
|
+
require_transform.assertSynchronous(equivalent);
|
|
3950
|
+
if (equivalent) {
|
|
3951
|
+
entry = {
|
|
3952
|
+
present: true,
|
|
3953
|
+
value: before
|
|
3954
|
+
};
|
|
3955
|
+
staged.set(key, entry);
|
|
3956
|
+
}
|
|
3957
|
+
}
|
|
3757
3958
|
if (!existed) {
|
|
3758
3959
|
addedEntries.push({
|
|
3759
3960
|
key,
|
|
@@ -3761,24 +3962,30 @@ const createCollectionOutput = (binding) => {
|
|
|
3761
3962
|
});
|
|
3762
3963
|
continue;
|
|
3763
3964
|
}
|
|
3764
|
-
const before =
|
|
3765
|
-
|
|
3965
|
+
const before = currentState.get(key);
|
|
3966
|
+
const equal = isEqual(before, entry.value);
|
|
3967
|
+
require_transform.assertSynchronous(equal);
|
|
3968
|
+
if (!equal) updatedEntries.push({
|
|
3766
3969
|
key,
|
|
3767
3970
|
before,
|
|
3768
3971
|
after: entry.value
|
|
3769
3972
|
});
|
|
3770
|
-
else if (
|
|
3973
|
+
else if (nextReset) staged.set(key, {
|
|
3974
|
+
present: true,
|
|
3975
|
+
value: before
|
|
3976
|
+
});
|
|
3977
|
+
else staged.delete(key);
|
|
3771
3978
|
continue;
|
|
3772
3979
|
}
|
|
3773
3980
|
if (existed) removedEntries.push({
|
|
3774
3981
|
key,
|
|
3775
|
-
before:
|
|
3982
|
+
before: currentState.get(key)
|
|
3776
3983
|
});
|
|
3777
3984
|
else staged.delete(key);
|
|
3778
3985
|
}
|
|
3779
|
-
const ids =
|
|
3986
|
+
const ids = currentState.ids();
|
|
3780
3987
|
if (explicitOrder) {
|
|
3781
|
-
const expectedLength =
|
|
3988
|
+
const expectedLength = currentState.size() + addedEntries.length - removedEntries.length;
|
|
3782
3989
|
const seen = /* @__PURE__ */ new Set();
|
|
3783
3990
|
for (const key of explicitOrder) {
|
|
3784
3991
|
if (seen.has(key) || !hasNext(key)) throw new TypeError("Projection order must contain every key exactly once.");
|
|
@@ -3787,7 +3994,7 @@ const createCollectionOutput = (binding) => {
|
|
|
3787
3994
|
if (seen.size !== expectedLength) throw new TypeError("Projection order must contain every key exactly once.");
|
|
3788
3995
|
nextIds = require_transform.sameArray(ids, explicitOrder) ? ids : explicitOrder;
|
|
3789
3996
|
} else if (addedEntries.length || removedEntries.length) {
|
|
3790
|
-
const order = new Array(
|
|
3997
|
+
const order = new Array(currentState.size() + addedEntries.length - removedEntries.length);
|
|
3791
3998
|
let index = 0;
|
|
3792
3999
|
for (const key of ids) if (hasNext(key)) order[index++] = key;
|
|
3793
4000
|
for (const entry of addedEntries) order[index++] = entry.key;
|
|
@@ -3804,7 +4011,7 @@ const createCollectionOutput = (binding) => {
|
|
|
3804
4011
|
reset = nextReset;
|
|
3805
4012
|
return change !== void 0;
|
|
3806
4013
|
};
|
|
3807
|
-
const context = (active, cause) => Object.freeze({
|
|
4014
|
+
const context = (active, cause, consumer) => Object.freeze({
|
|
3808
4015
|
kind: "collection",
|
|
3809
4016
|
read: {
|
|
3810
4017
|
get: (key) => {
|
|
@@ -3820,9 +4027,9 @@ const createCollectionOutput = (binding) => {
|
|
|
3820
4027
|
return nextIds;
|
|
3821
4028
|
}
|
|
3822
4029
|
},
|
|
3823
|
-
change,
|
|
4030
|
+
change: consumer ? consumers.get(consumer)?.current() : change,
|
|
3824
4031
|
revision,
|
|
3825
|
-
reset,
|
|
4032
|
+
reset: consumer ? consumers.get(consumer)?.reset() ?? false : reset,
|
|
3826
4033
|
cause
|
|
3827
4034
|
});
|
|
3828
4035
|
return {
|
|
@@ -3832,35 +4039,59 @@ const createCollectionOutput = (binding) => {
|
|
|
3832
4039
|
},
|
|
3833
4040
|
begin,
|
|
3834
4041
|
seal,
|
|
3835
|
-
context: (active) => context(active, binding.cause()),
|
|
3836
|
-
|
|
4042
|
+
context: (active, consumer) => context(active, binding.cause(), consumer),
|
|
4043
|
+
acknowledge: (consumer) => consumers.get(consumer)?.clear(),
|
|
4044
|
+
pending: (consumer) => consumers.get(consumer)?.current() !== void 0,
|
|
4045
|
+
baseline: () => baseline ?? currentState.read(binding.check),
|
|
4046
|
+
current: () => currentState.read(binding.check),
|
|
3837
4047
|
revision: () => revision,
|
|
3838
|
-
reset: () => reset,
|
|
4048
|
+
reset: (consumer) => consumer ? consumers.get(consumer)?.reset() ?? false : reset,
|
|
3839
4049
|
publish: () => {
|
|
3840
|
-
if (change)
|
|
3841
|
-
|
|
4050
|
+
if (change) {
|
|
4051
|
+
if (initialized) {
|
|
4052
|
+
baseline ??= currentState.read(() => void 0);
|
|
4053
|
+
notifications.add(change, currentState.ids(), nextIds);
|
|
4054
|
+
for (const pending of consumers.values()) pending.add(change, currentState.ids(), nextIds);
|
|
4055
|
+
revision++;
|
|
4056
|
+
}
|
|
4057
|
+
currentState.install(staged, nextIds, change.kind === "reset");
|
|
4058
|
+
}
|
|
3842
4059
|
initialized = true;
|
|
3843
4060
|
},
|
|
3844
|
-
emit: (call) => {
|
|
3845
|
-
|
|
4061
|
+
emit: (call, force) => {
|
|
4062
|
+
const net = notifications.current();
|
|
4063
|
+
for (const listener of [...observers]) call(listener, net);
|
|
4064
|
+
if (net || force) for (const listener of [...listeners]) call(listener, net);
|
|
4065
|
+
},
|
|
4066
|
+
finish: () => {
|
|
4067
|
+
baseline = void 0;
|
|
4068
|
+
notifications.clear();
|
|
4069
|
+
},
|
|
4070
|
+
observe: (listener) => {
|
|
4071
|
+
binding.check();
|
|
4072
|
+
observers.add(listener);
|
|
4073
|
+
return () => observers.delete(listener);
|
|
3846
4074
|
},
|
|
3847
4075
|
hasConsumers: () => consumers.size > 0,
|
|
3848
|
-
forEachConsumer: (run) => consumers.forEach(run),
|
|
3849
|
-
attachConsumer: (consumer) => consumers.
|
|
4076
|
+
forEachConsumer: (run) => consumers.forEach((_pending, consumer) => run(consumer)),
|
|
4077
|
+
attachConsumer: (consumer) => consumers.set(consumer, createCollectionChanges()),
|
|
3850
4078
|
detachConsumer: (consumer) => consumers.delete(consumer),
|
|
3851
4079
|
clear: () => {
|
|
3852
4080
|
staged.clear();
|
|
3853
|
-
nextIds =
|
|
4081
|
+
nextIds = currentState.ids();
|
|
3854
4082
|
change = void 0;
|
|
3855
4083
|
reset = false;
|
|
3856
4084
|
explicitOrder = void 0;
|
|
3857
4085
|
cleared = false;
|
|
3858
4086
|
},
|
|
3859
4087
|
release: () => {
|
|
3860
|
-
|
|
4088
|
+
currentState.release();
|
|
3861
4089
|
staged.clear();
|
|
3862
4090
|
listeners.clear();
|
|
3863
4091
|
consumers.clear();
|
|
4092
|
+
observers.clear();
|
|
4093
|
+
baseline = void 0;
|
|
4094
|
+
notifications.clear();
|
|
3864
4095
|
nextIds = Object.freeze([]);
|
|
3865
4096
|
change = void 0;
|
|
3866
4097
|
initialized = false;
|
|
@@ -3879,7 +4110,7 @@ const createCollectionOutput = (binding) => {
|
|
|
3879
4110
|
//#endregion
|
|
3880
4111
|
//#region core/src/projection/output/value.ts
|
|
3881
4112
|
const unset = Symbol("projection-value-unset");
|
|
3882
|
-
/** Owns staged and
|
|
4113
|
+
/** Owns staged and current state for one scalar Projection output. */
|
|
3883
4114
|
const createValueOutput = (binding) => {
|
|
3884
4115
|
let value;
|
|
3885
4116
|
let staged = unset;
|
|
@@ -3889,7 +4120,10 @@ const createValueOutput = (binding) => {
|
|
|
3889
4120
|
let changed = false;
|
|
3890
4121
|
let reset = false;
|
|
3891
4122
|
const listeners = /* @__PURE__ */ new Set();
|
|
3892
|
-
const consumers = /* @__PURE__ */ new
|
|
4123
|
+
const consumers = /* @__PURE__ */ new Map();
|
|
4124
|
+
const observers = /* @__PURE__ */ new Set();
|
|
4125
|
+
let baseline = unset;
|
|
4126
|
+
let resetRevision = -1;
|
|
3893
4127
|
const begin = (active, initialize) => {
|
|
3894
4128
|
staged = unset;
|
|
3895
4129
|
next = value;
|
|
@@ -3916,8 +4150,15 @@ const createValueOutput = (binding) => {
|
|
|
3916
4150
|
next = value;
|
|
3917
4151
|
return false;
|
|
3918
4152
|
}
|
|
3919
|
-
|
|
3920
|
-
|
|
4153
|
+
let candidate = staged;
|
|
4154
|
+
if (baseline !== unset && !Object.is(value, baseline)) {
|
|
4155
|
+
const equivalent = isEqual(baseline, candidate);
|
|
4156
|
+
require_transform.assertSynchronous(equivalent);
|
|
4157
|
+
if (equivalent) candidate = baseline;
|
|
4158
|
+
}
|
|
4159
|
+
const equal = initialized ? isEqual(value, candidate) : false;
|
|
4160
|
+
require_transform.assertSynchronous(equal);
|
|
4161
|
+
changed = !equal;
|
|
3921
4162
|
next = changed ? candidate : value;
|
|
3922
4163
|
reset = nextReset;
|
|
3923
4164
|
return changed;
|
|
@@ -3929,13 +4170,13 @@ const createValueOutput = (binding) => {
|
|
|
3929
4170
|
},
|
|
3930
4171
|
begin,
|
|
3931
4172
|
seal,
|
|
3932
|
-
context: (active) => {
|
|
4173
|
+
context: (active, consumer) => {
|
|
3933
4174
|
require_transform.assertScope(active);
|
|
3934
4175
|
return Object.freeze({
|
|
3935
4176
|
kind: "value",
|
|
3936
4177
|
value: next,
|
|
3937
4178
|
revision,
|
|
3938
|
-
reset,
|
|
4179
|
+
reset: consumer ? (consumers.get(consumer)?.revision ?? -1) < resetRevision : reset,
|
|
3939
4180
|
cause: binding.cause()
|
|
3940
4181
|
});
|
|
3941
4182
|
},
|
|
@@ -3944,19 +4185,48 @@ const createValueOutput = (binding) => {
|
|
|
3944
4185
|
return value;
|
|
3945
4186
|
},
|
|
3946
4187
|
revision: () => revision,
|
|
3947
|
-
reset: () => reset,
|
|
3948
|
-
|
|
3949
|
-
if (
|
|
4188
|
+
reset: (consumer) => consumer ? (consumers.get(consumer)?.revision ?? -1) < resetRevision : reset,
|
|
4189
|
+
acknowledge: (consumer) => {
|
|
4190
|
+
if (consumers.has(consumer)) consumers.set(consumer, {
|
|
4191
|
+
revision,
|
|
4192
|
+
value
|
|
4193
|
+
});
|
|
4194
|
+
},
|
|
4195
|
+
pending: (consumer) => {
|
|
4196
|
+
const previous = consumers.get(consumer);
|
|
4197
|
+
return !previous || previous.revision < resetRevision || !Object.is(previous.value, value);
|
|
4198
|
+
},
|
|
4199
|
+
baseline: () => baseline === unset ? value : baseline,
|
|
4200
|
+
publish: (forceReset) => {
|
|
4201
|
+
if (initialized && (changed || forceReset)) {
|
|
4202
|
+
if (baseline === unset) baseline = value;
|
|
4203
|
+
revision++;
|
|
4204
|
+
if (reset) resetRevision = revision;
|
|
4205
|
+
}
|
|
3950
4206
|
if (changed) value = next;
|
|
3951
4207
|
initialized = true;
|
|
3952
4208
|
},
|
|
3953
|
-
emit: (call) => {
|
|
3954
|
-
|
|
3955
|
-
|
|
4209
|
+
emit: (call, force) => {
|
|
4210
|
+
for (const listener of [...observers]) call(listener, void 0);
|
|
4211
|
+
if (force || baseline !== unset && !Object.is(baseline, value)) {
|
|
4212
|
+
require_transform.profile.materialized.notification();
|
|
4213
|
+
for (const listener of [...listeners]) call(listener, void 0);
|
|
4214
|
+
}
|
|
4215
|
+
},
|
|
4216
|
+
finish: () => {
|
|
4217
|
+
baseline = unset;
|
|
4218
|
+
},
|
|
4219
|
+
observe: (listener) => {
|
|
4220
|
+
binding.check();
|
|
4221
|
+
observers.add(listener);
|
|
4222
|
+
return () => observers.delete(listener);
|
|
3956
4223
|
},
|
|
3957
4224
|
hasConsumers: () => consumers.size > 0,
|
|
3958
|
-
forEachConsumer: (run) => consumers.forEach(run),
|
|
3959
|
-
attachConsumer: (consumer) => consumers.
|
|
4225
|
+
forEachConsumer: (run) => consumers.forEach((_revision, consumer) => run(consumer)),
|
|
4226
|
+
attachConsumer: (consumer) => consumers.set(consumer, {
|
|
4227
|
+
revision,
|
|
4228
|
+
value
|
|
4229
|
+
}),
|
|
3960
4230
|
detachConsumer: (consumer) => consumers.delete(consumer),
|
|
3961
4231
|
clear: () => {
|
|
3962
4232
|
staged = unset;
|
|
@@ -3967,6 +4237,8 @@ const createValueOutput = (binding) => {
|
|
|
3967
4237
|
release: () => {
|
|
3968
4238
|
listeners.clear();
|
|
3969
4239
|
consumers.clear();
|
|
4240
|
+
observers.clear();
|
|
4241
|
+
baseline = unset;
|
|
3970
4242
|
staged = unset;
|
|
3971
4243
|
value = next = void 0;
|
|
3972
4244
|
initialized = false;
|
|
@@ -4037,7 +4309,7 @@ const createProcessor = (scheduler, definition, dependencies) => {
|
|
|
4037
4309
|
let active = true;
|
|
4038
4310
|
try {
|
|
4039
4311
|
const scopeActive = () => active;
|
|
4040
|
-
const sources = Object.freeze(dependencies.map((output) => output.context(scopeActive)));
|
|
4312
|
+
const sources = Object.freeze(dependencies.map((output) => output.context(scopeActive, processor)));
|
|
4041
4313
|
const outputs = begin(scopeActive, reset);
|
|
4042
4314
|
if (recreate && instance) {
|
|
4043
4315
|
instance.release?.();
|
|
@@ -4051,16 +4323,17 @@ const createProcessor = (scheduler, definition, dependencies) => {
|
|
|
4051
4323
|
sources,
|
|
4052
4324
|
outputs
|
|
4053
4325
|
}));
|
|
4054
|
-
|
|
4326
|
+
const changed = seal(reset);
|
|
4327
|
+
dependencies.forEach((output) => output.acknowledge(processor));
|
|
4328
|
+
return changed;
|
|
4055
4329
|
} finally {
|
|
4056
4330
|
active = false;
|
|
4057
4331
|
}
|
|
4058
4332
|
};
|
|
4059
|
-
const
|
|
4333
|
+
const id = scheduler.nextId();
|
|
4060
4334
|
processor = {
|
|
4061
4335
|
kind: "processor",
|
|
4062
|
-
|
|
4063
|
-
name: definition.name ? `${definition.name} (${order})` : `projection-${order}`,
|
|
4336
|
+
name: definition.name ? `${definition.name} (${id})` : `projection-${id}`,
|
|
4064
4337
|
dependencies: Object.freeze([...dependencies]),
|
|
4065
4338
|
outputs: Object.freeze(bound.map((entry) => entry.state)),
|
|
4066
4339
|
fault: void 0,
|
|
@@ -4187,7 +4460,9 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
|
|
|
4187
4460
|
let initialized = false;
|
|
4188
4461
|
let value;
|
|
4189
4462
|
let selectedRevision = 0;
|
|
4463
|
+
let notified;
|
|
4190
4464
|
let sourceRevision = -1;
|
|
4465
|
+
let notificationRevision = -1;
|
|
4191
4466
|
let selection = Object.freeze({
|
|
4192
4467
|
keys: /* @__PURE__ */ new Set(),
|
|
4193
4468
|
all: true,
|
|
@@ -4223,8 +4498,9 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
|
|
|
4223
4498
|
});
|
|
4224
4499
|
const changed = !initialized || !equality(value, next);
|
|
4225
4500
|
if (changed) {
|
|
4501
|
+
const candidate = unsubscribeSource && equality(notified, next) ? notified : next;
|
|
4226
4502
|
if (initialized) selectedRevision++;
|
|
4227
|
-
value =
|
|
4503
|
+
value = candidate;
|
|
4228
4504
|
}
|
|
4229
4505
|
selection = nextSelection;
|
|
4230
4506
|
initialized = true;
|
|
@@ -4234,31 +4510,44 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
|
|
|
4234
4510
|
};
|
|
4235
4511
|
const ensureCurrent = () => {
|
|
4236
4512
|
const revision = source.revision();
|
|
4237
|
-
if (!initialized
|
|
4238
|
-
|
|
4239
|
-
};
|
|
4240
|
-
const onProjectionChange = (incoming) => {
|
|
4241
|
-
let change = incoming;
|
|
4242
|
-
if (!change && previousCollection) {
|
|
4513
|
+
if (!initialized) evaluate();
|
|
4514
|
+
else if (sourceRevision !== revision) {
|
|
4243
4515
|
const current = source.current();
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
if (!
|
|
4248
|
-
|
|
4249
|
-
|
|
4516
|
+
let affected = true;
|
|
4517
|
+
if (previousCollection && isMapLike(current) && !selection.all) {
|
|
4518
|
+
affected = selection.structure && !require_transform.iterableMatchesArray(current.keys(), [...previousCollection.keys()]);
|
|
4519
|
+
if (!affected) {
|
|
4520
|
+
for (const key of selection.keys) if (previousCollection.has(key) !== current.has(key) || !Object.is(previousCollection.get(key), current.get(key))) {
|
|
4521
|
+
affected = true;
|
|
4522
|
+
break;
|
|
4523
|
+
}
|
|
4250
4524
|
}
|
|
4251
|
-
}
|
|
4525
|
+
}
|
|
4526
|
+
if (affected) evaluate();
|
|
4527
|
+
else {
|
|
4528
|
+
sourceRevision = revision;
|
|
4529
|
+
updateCollectionSnapshot(current);
|
|
4530
|
+
}
|
|
4252
4531
|
}
|
|
4253
|
-
|
|
4532
|
+
return value;
|
|
4533
|
+
};
|
|
4534
|
+
const onProjectionChange = (incoming) => {
|
|
4535
|
+
if (sourceRevision === notificationRevision && sourceRevision !== source.revision() && incoming && !selectionAffects(selection, incoming)) {
|
|
4254
4536
|
sourceRevision = source.revision();
|
|
4255
4537
|
updateCollectionSnapshot();
|
|
4256
|
-
|
|
4538
|
+
} else ensureCurrent();
|
|
4539
|
+
notificationRevision = sourceRevision;
|
|
4540
|
+
if (!equality(notified, value)) {
|
|
4541
|
+
notified = value;
|
|
4542
|
+
notifyProjectionListeners(listeners, "Projection selector listeners failed.");
|
|
4257
4543
|
}
|
|
4258
|
-
if (evaluate()) notifyProjectionListeners(listeners, "Projection selector listeners failed.");
|
|
4259
4544
|
};
|
|
4260
4545
|
const installSource = () => {
|
|
4261
|
-
if (!unsubscribeSource)
|
|
4546
|
+
if (!unsubscribeSource) {
|
|
4547
|
+
notified = value;
|
|
4548
|
+
notificationRevision = sourceRevision;
|
|
4549
|
+
unsubscribeSource = source.observe(onProjectionChange);
|
|
4550
|
+
}
|
|
4262
4551
|
};
|
|
4263
4552
|
return Object.freeze({
|
|
4264
4553
|
current: ensureCurrent,
|
|
@@ -4640,13 +4929,12 @@ const createValueBoundary = (scheduler, name, initial, equality, prepare, clearS
|
|
|
4640
4929
|
active = false;
|
|
4641
4930
|
}
|
|
4642
4931
|
},
|
|
4643
|
-
publish: state.publish,
|
|
4932
|
+
publish: () => state.publish(pendingReset),
|
|
4644
4933
|
clear: () => {
|
|
4645
4934
|
const failed = boundary.fault !== void 0;
|
|
4646
4935
|
state.clear();
|
|
4647
4936
|
pendingReset = false;
|
|
4648
4937
|
pendingCause = void 0;
|
|
4649
|
-
contextCause = void 0;
|
|
4650
4938
|
recovering = false;
|
|
4651
4939
|
clearSource(failed);
|
|
4652
4940
|
},
|
|
@@ -4702,6 +4990,7 @@ const createValueBoundary = (scheduler, name, initial, equality, prepare, clearS
|
|
|
4702
4990
|
return {
|
|
4703
4991
|
producer: boundary,
|
|
4704
4992
|
output,
|
|
4993
|
+
baseline: state.baseline,
|
|
4705
4994
|
mark,
|
|
4706
4995
|
fail,
|
|
4707
4996
|
detach: (next) => {
|
|
@@ -4721,7 +5010,7 @@ const stageCollectionRead = (state, read, active, options) => {
|
|
|
4721
5010
|
}
|
|
4722
5011
|
evaluation.output.order(ids);
|
|
4723
5012
|
} else {
|
|
4724
|
-
const previous =
|
|
5013
|
+
const previous = evaluation.previous;
|
|
4725
5014
|
let currentIds;
|
|
4726
5015
|
const ids = () => currentIds ??= read.ids();
|
|
4727
5016
|
if (options.candidates) for (const key of options.candidates) if (read.has(key)) {
|
|
@@ -4802,7 +5091,6 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSo
|
|
|
4802
5091
|
state.clear();
|
|
4803
5092
|
pendingReset = false;
|
|
4804
5093
|
pendingCause = void 0;
|
|
4805
|
-
contextCause = void 0;
|
|
4806
5094
|
recovering = false;
|
|
4807
5095
|
fullScan = false;
|
|
4808
5096
|
orderMayChange = false;
|
|
@@ -4855,7 +5143,11 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSo
|
|
|
4855
5143
|
fullScan ||= metadata.fullScan ?? false;
|
|
4856
5144
|
orderMayChange ||= metadata.orderMayChange ?? false;
|
|
4857
5145
|
if (metadata.candidates) for (const key of metadata.candidates) candidates.add(key);
|
|
4858
|
-
if (boundary.fault)
|
|
5146
|
+
if (boundary.fault) {
|
|
5147
|
+
recovering = true;
|
|
5148
|
+
fullScan = true;
|
|
5149
|
+
orderMayChange = true;
|
|
5150
|
+
}
|
|
4859
5151
|
scheduler.capture(boundary);
|
|
4860
5152
|
};
|
|
4861
5153
|
const fail = (cause) => {
|
|
@@ -4866,6 +5158,7 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSo
|
|
|
4866
5158
|
return {
|
|
4867
5159
|
producer: boundary,
|
|
4868
5160
|
output,
|
|
5161
|
+
baseline: state.baseline,
|
|
4869
5162
|
mark,
|
|
4870
5163
|
fail,
|
|
4871
5164
|
detach: (next) => {
|
|
@@ -5399,101 +5692,136 @@ const createExternalSourceRegistry = (scheduler, documents) => {
|
|
|
5399
5692
|
//#region core/src/projection/source/input.ts
|
|
5400
5693
|
const materializeInputSource = (scheduler, definition) => {
|
|
5401
5694
|
const source = definition.source;
|
|
5695
|
+
if (source.kind !== "value-input" && source.kind !== "collection-input") throw new Error("Invalid projection input source.");
|
|
5696
|
+
const equal = (previous, next) => {
|
|
5697
|
+
const result = source.equality(previous, next);
|
|
5698
|
+
require_transform.assertSynchronous(result);
|
|
5699
|
+
return result;
|
|
5700
|
+
};
|
|
5402
5701
|
if (source.kind === "value-input") {
|
|
5403
5702
|
let latest = source.initial;
|
|
5404
|
-
const boundary = createValueBoundary(scheduler, "projection input", source.initial,
|
|
5703
|
+
const boundary = createValueBoundary(scheduler, "projection input", source.initial, Object.is, () => latest, () => void 0);
|
|
5704
|
+
boundary.detach(() => {
|
|
5705
|
+
latest = void 0;
|
|
5706
|
+
});
|
|
5405
5707
|
return {
|
|
5406
5708
|
...boundary,
|
|
5407
|
-
|
|
5709
|
+
input: {
|
|
5408
5710
|
kind: "value",
|
|
5409
5711
|
set(value) {
|
|
5410
|
-
scheduler.
|
|
5411
|
-
|
|
5712
|
+
const next = scheduler.acceptInput(() => {
|
|
5713
|
+
if (equal(latest, value)) return latest;
|
|
5714
|
+
if (source.equality === Object.is) return value;
|
|
5715
|
+
const baseline = boundary.baseline();
|
|
5716
|
+
return !Object.is(latest, baseline) && equal(baseline, value) ? baseline : value;
|
|
5717
|
+
});
|
|
5718
|
+
if (Object.is(latest, next)) return;
|
|
5719
|
+
latest = next;
|
|
5412
5720
|
boundary.mark();
|
|
5413
5721
|
scheduler.run();
|
|
5414
5722
|
}
|
|
5415
5723
|
}
|
|
5416
5724
|
};
|
|
5417
5725
|
}
|
|
5418
|
-
|
|
5419
|
-
const
|
|
5420
|
-
|
|
5726
|
+
const values = createCollectionState(source.initial);
|
|
5727
|
+
const latest = {
|
|
5728
|
+
get: values.get,
|
|
5729
|
+
has: values.has,
|
|
5730
|
+
ids: values.ids
|
|
5731
|
+
};
|
|
5732
|
+
const boundary = createCollectionBoundary(scheduler, "projection collection input", () => latest, Object.is, () => void 0);
|
|
5733
|
+
boundary.detach(() => {
|
|
5734
|
+
values.release();
|
|
5735
|
+
});
|
|
5421
5736
|
return {
|
|
5422
5737
|
...boundary,
|
|
5423
|
-
|
|
5738
|
+
input: {
|
|
5424
5739
|
kind: "collection",
|
|
5425
5740
|
update(run) {
|
|
5426
|
-
scheduler.
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
get: (key) => {
|
|
5433
|
-
require_transform.assertScope(() => active);
|
|
5434
|
-
const entry = staged.get(key);
|
|
5435
|
-
return entry ? entry.present ? entry.value : void 0 : values.get(key);
|
|
5436
|
-
},
|
|
5437
|
-
has: (key) => {
|
|
5438
|
-
require_transform.assertScope(() => active);
|
|
5741
|
+
const accepted = scheduler.acceptInput(() => {
|
|
5742
|
+
const staged = /* @__PURE__ */ new Map();
|
|
5743
|
+
const appended = /* @__PURE__ */ new Set();
|
|
5744
|
+
let structural = false;
|
|
5745
|
+
let active = true;
|
|
5746
|
+
const has = (key) => {
|
|
5439
5747
|
const entry = staged.get(key);
|
|
5440
5748
|
return entry ? entry.present : values.has(key);
|
|
5441
|
-
}
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
key
|
|
5467
|
-
|
|
5749
|
+
};
|
|
5750
|
+
const draft = Object.freeze({
|
|
5751
|
+
get: (key) => {
|
|
5752
|
+
require_transform.assertScope(() => active);
|
|
5753
|
+
const entry = staged.get(key);
|
|
5754
|
+
return entry ? entry.present ? entry.value : void 0 : values.get(key);
|
|
5755
|
+
},
|
|
5756
|
+
has: (key) => {
|
|
5757
|
+
require_transform.assertScope(() => active);
|
|
5758
|
+
return has(key);
|
|
5759
|
+
},
|
|
5760
|
+
set: (key, value) => {
|
|
5761
|
+
require_transform.assertScope(() => active);
|
|
5762
|
+
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
5763
|
+
if (!has(key)) {
|
|
5764
|
+
appended.add(key);
|
|
5765
|
+
structural = true;
|
|
5766
|
+
}
|
|
5767
|
+
staged.set(key, {
|
|
5768
|
+
present: true,
|
|
5769
|
+
value
|
|
5770
|
+
});
|
|
5771
|
+
},
|
|
5772
|
+
remove: (key) => {
|
|
5773
|
+
require_transform.assertScope(() => active);
|
|
5774
|
+
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
5775
|
+
if (!has(key)) return;
|
|
5776
|
+
appended.delete(key);
|
|
5777
|
+
structural = true;
|
|
5778
|
+
staged.set(key, { present: false });
|
|
5779
|
+
}
|
|
5780
|
+
});
|
|
5781
|
+
try {
|
|
5782
|
+
require_transform.assertSynchronous(run(draft));
|
|
5783
|
+
} finally {
|
|
5784
|
+
active = false;
|
|
5468
5785
|
}
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
}
|
|
5475
|
-
if (!operations.length) return;
|
|
5476
|
-
const candidates = /* @__PURE__ */ new Set();
|
|
5477
|
-
const retained = /* @__PURE__ */ new Map();
|
|
5478
|
-
for (const [key, entry] of staged) {
|
|
5479
|
-
const existed = values.has(key);
|
|
5480
|
-
if (entry.present) {
|
|
5481
|
-
if (!existed) {
|
|
5482
|
-
candidates.add(key);
|
|
5786
|
+
const baseline = source.equality === Object.is ? void 0 : boundary.baseline();
|
|
5787
|
+
for (const [key, entry] of staged) {
|
|
5788
|
+
const existed = values.has(key);
|
|
5789
|
+
if (!entry.present) {
|
|
5790
|
+
if (!existed) staged.delete(key);
|
|
5483
5791
|
continue;
|
|
5484
5792
|
}
|
|
5485
5793
|
const previous = values.get(key);
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5794
|
+
let next = entry.value;
|
|
5795
|
+
if (existed && equal(previous, next)) next = previous;
|
|
5796
|
+
else if (baseline?.has(key)) {
|
|
5797
|
+
const before = baseline.get(key);
|
|
5798
|
+
if ((!existed || !Object.is(previous, before)) && equal(before, next)) next = before;
|
|
5799
|
+
}
|
|
5800
|
+
if (existed && Object.is(previous, next)) staged.delete(key);
|
|
5801
|
+
else if (!Object.is(entry.value, next)) staged.set(key, {
|
|
5802
|
+
present: true,
|
|
5803
|
+
value: next
|
|
5804
|
+
});
|
|
5805
|
+
}
|
|
5806
|
+
const beforeOrder = values.ids();
|
|
5807
|
+
let order = beforeOrder;
|
|
5808
|
+
if (structural) {
|
|
5809
|
+
const next = [];
|
|
5810
|
+
for (const key of beforeOrder) if (has(key) && !appended.has(key)) next.push(key);
|
|
5811
|
+
for (const key of appended) next.push(key);
|
|
5812
|
+
if (!require_transform.sameArray(beforeOrder, next)) order = Object.freeze(next);
|
|
5813
|
+
}
|
|
5814
|
+
return {
|
|
5815
|
+
staged,
|
|
5816
|
+
order,
|
|
5817
|
+
structural: order !== beforeOrder
|
|
5818
|
+
};
|
|
5819
|
+
});
|
|
5820
|
+
if (!accepted.staged.size && !accepted.structural) return;
|
|
5821
|
+
values.install(accepted.staged, accepted.order, false);
|
|
5494
5822
|
boundary.mark({
|
|
5495
|
-
candidates,
|
|
5496
|
-
orderMayChange: structural
|
|
5823
|
+
candidates: accepted.staged.keys(),
|
|
5824
|
+
orderMayChange: accepted.structural
|
|
5497
5825
|
});
|
|
5498
5826
|
scheduler.run();
|
|
5499
5827
|
}
|
|
@@ -5543,6 +5871,11 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
5543
5871
|
const waiting = /* @__PURE__ */ new Map();
|
|
5544
5872
|
let keysValue = Object.freeze([...source.current().keys()]);
|
|
5545
5873
|
let keysRevision = 0;
|
|
5874
|
+
let notifiedKeys = keysValue;
|
|
5875
|
+
let settledRevision = source.revision();
|
|
5876
|
+
let keysSourceRevision = settledRevision;
|
|
5877
|
+
const pendingKeys = /* @__PURE__ */ new Set();
|
|
5878
|
+
const changedStates = /* @__PURE__ */ new Set();
|
|
5546
5879
|
const keyListeners = /* @__PURE__ */ new Set();
|
|
5547
5880
|
const check = () => {
|
|
5548
5881
|
if (disposed) throw new require_transform.ProjectionDisposedError();
|
|
@@ -5578,7 +5911,7 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
5578
5911
|
}
|
|
5579
5912
|
state.value = value;
|
|
5580
5913
|
state.revision++;
|
|
5581
|
-
|
|
5914
|
+
changedStates.add(state);
|
|
5582
5915
|
};
|
|
5583
5916
|
const attachActive = (state, value) => {
|
|
5584
5917
|
if (state.ended) return;
|
|
@@ -5621,10 +5954,12 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
5621
5954
|
if (extra) for (const state of extra) publishState(state, value);
|
|
5622
5955
|
};
|
|
5623
5956
|
const updateKeys = (current) => {
|
|
5957
|
+
const revision = source.revision();
|
|
5958
|
+
if (keysSourceRevision === revision) return;
|
|
5959
|
+
keysSourceRevision = revision;
|
|
5624
5960
|
if (require_transform.iterableMatchesArray(current.keys(), keysValue)) return;
|
|
5625
|
-
keysValue = Object.freeze([...current.keys()]);
|
|
5961
|
+
keysValue = require_transform.iterableMatchesArray(current.keys(), notifiedKeys) ? notifiedKeys : Object.freeze([...current.keys()]);
|
|
5626
5962
|
keysRevision++;
|
|
5627
|
-
notify(keyListeners);
|
|
5628
5963
|
};
|
|
5629
5964
|
const createItem = (key, initial) => {
|
|
5630
5965
|
const state = {
|
|
@@ -5633,12 +5968,15 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
5633
5968
|
tracked: initial !== void 0,
|
|
5634
5969
|
ended: false,
|
|
5635
5970
|
value: initial?.value,
|
|
5971
|
+
notified: initial?.value,
|
|
5636
5972
|
revision: 0
|
|
5637
5973
|
};
|
|
5638
5974
|
const ensureObserved = () => {
|
|
5639
|
-
if (state.ended
|
|
5975
|
+
if (state.ended) return;
|
|
5640
5976
|
const current = source.current();
|
|
5641
|
-
if (
|
|
5977
|
+
if (source.revision() !== settledRevision) pendingKeys.add(key);
|
|
5978
|
+
if (!state.tracked && current.has(key)) attachActive(state, current.get(key));
|
|
5979
|
+
else if (state.tracked) publishState(state, current.get(key));
|
|
5642
5980
|
};
|
|
5643
5981
|
state.readable = Object.freeze({
|
|
5644
5982
|
current: () => {
|
|
@@ -5673,25 +6011,45 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
5673
6011
|
const onChange = (change) => {
|
|
5674
6012
|
check();
|
|
5675
6013
|
const current = source.current();
|
|
5676
|
-
if (
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
6014
|
+
if (change?.kind === "reset") reconcile(current);
|
|
6015
|
+
else {
|
|
6016
|
+
if (change) {
|
|
6017
|
+
for (const entry of change.removed) terminateKey(entry.key);
|
|
6018
|
+
for (const entry of change.added) activateWaiting(entry.key, entry.after);
|
|
6019
|
+
for (const entry of change.updated) updateKey(entry.key, entry.after);
|
|
6020
|
+
if (change.added.length || change.removed.length || change.order) updateKeys(current);
|
|
6021
|
+
}
|
|
6022
|
+
for (const key of pendingKeys) if (!current.has(key)) terminateKey(key);
|
|
6023
|
+
else {
|
|
6024
|
+
updateKey(key, current.get(key));
|
|
6025
|
+
activateWaiting(key, current.get(key));
|
|
6026
|
+
}
|
|
6027
|
+
}
|
|
6028
|
+
pendingKeys.clear();
|
|
6029
|
+
settledRevision = source.revision();
|
|
6030
|
+
for (const state of changedStates) if (!Object.is(state.notified, state.value)) {
|
|
6031
|
+
state.notified = state.value;
|
|
6032
|
+
notify(state.listeners);
|
|
6033
|
+
}
|
|
6034
|
+
changedStates.clear();
|
|
6035
|
+
if (keysValue !== notifiedKeys) updateKeys(current);
|
|
6036
|
+
else keysSourceRevision = settledRevision;
|
|
6037
|
+
if (keysValue !== notifiedKeys) {
|
|
6038
|
+
notifiedKeys = keysValue;
|
|
6039
|
+
notify(keyListeners);
|
|
5680
6040
|
}
|
|
5681
|
-
for (const entry of change.removed) terminateKey(entry.key);
|
|
5682
|
-
for (const entry of change.added) activateWaiting(entry.key, entry.after);
|
|
5683
|
-
for (const entry of change.updated) updateKey(entry.key, entry.after);
|
|
5684
|
-
if (change.added.length || change.removed.length || change.order) updateKeys(current);
|
|
5685
6041
|
flushNotifications();
|
|
5686
6042
|
};
|
|
5687
|
-
const stop = source.
|
|
6043
|
+
const stop = source.observe(onChange);
|
|
5688
6044
|
const keys = Object.freeze({
|
|
5689
6045
|
current: () => {
|
|
5690
6046
|
check();
|
|
6047
|
+
updateKeys(source.current());
|
|
5691
6048
|
return keysValue;
|
|
5692
6049
|
},
|
|
5693
6050
|
revision: () => {
|
|
5694
6051
|
check();
|
|
6052
|
+
updateKeys(source.current());
|
|
5695
6053
|
return keysRevision;
|
|
5696
6054
|
},
|
|
5697
6055
|
subscribe: (listener) => {
|
|
@@ -5705,11 +6063,12 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
5705
6063
|
keys,
|
|
5706
6064
|
get: (key) => {
|
|
5707
6065
|
check();
|
|
6066
|
+
const current = source.current();
|
|
6067
|
+
if (source.revision() !== settledRevision) pendingKeys.add(key);
|
|
5708
6068
|
const canonical = active.get(key);
|
|
5709
6069
|
if (canonical) return canonical.readable;
|
|
5710
6070
|
const pending = waiting.get(key)?.values().next().value;
|
|
5711
6071
|
if (pending) return pending.readable;
|
|
5712
|
-
const current = source.current();
|
|
5713
6072
|
if (current.has(key)) {
|
|
5714
6073
|
const state = createItem(key, {
|
|
5715
6074
|
present: true,
|
|
@@ -5735,6 +6094,8 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
5735
6094
|
followers.clear();
|
|
5736
6095
|
waiting.clear();
|
|
5737
6096
|
notifications.length = 0;
|
|
6097
|
+
pendingKeys.clear();
|
|
6098
|
+
changedStates.clear();
|
|
5738
6099
|
}
|
|
5739
6100
|
};
|
|
5740
6101
|
};
|
|
@@ -5790,11 +6151,12 @@ const createProjectionRuntime = (options) => {
|
|
|
5790
6151
|
result = Object.freeze({
|
|
5791
6152
|
record: source.producer,
|
|
5792
6153
|
outputs: Object.freeze([source.output]),
|
|
5793
|
-
...source.
|
|
6154
|
+
...source.input ? { input: source.input } : {}
|
|
5794
6155
|
});
|
|
5795
6156
|
} else {
|
|
5796
6157
|
if (definition.owner === void 0 && definition.dependencies.some((dependency) => require_transform.producerOf(dependency).owner !== void 0)) throw new TypeError("A root projection cannot depend on a scoped projection.");
|
|
5797
6158
|
const dependencies = definition.dependencies.map((dependency) => resolveOutput(dependency, requester));
|
|
6159
|
+
dependencies.forEach((output) => scheduler.ensureCurrent(output));
|
|
5798
6160
|
const processor = createProcessor(scheduler, definition, Object.freeze(dependencies));
|
|
5799
6161
|
result = Object.freeze({
|
|
5800
6162
|
record: processor,
|
|
@@ -5818,6 +6180,7 @@ const createProjectionRuntime = (options) => {
|
|
|
5818
6180
|
if (output.owner.fault) throw output.owner.fault;
|
|
5819
6181
|
};
|
|
5820
6182
|
const publicCurrent = (output) => {
|
|
6183
|
+
scheduler.ensureCurrent(output);
|
|
5821
6184
|
assertOutput(output);
|
|
5822
6185
|
const current = output.current();
|
|
5823
6186
|
const revision = output.revision();
|
|
@@ -5849,10 +6212,12 @@ const createProjectionRuntime = (options) => {
|
|
|
5849
6212
|
kind: output.kind,
|
|
5850
6213
|
current: () => readProjection(projection, requester),
|
|
5851
6214
|
revision: () => {
|
|
6215
|
+
scheduler.ensureCurrent(output);
|
|
5852
6216
|
assertOutput(output);
|
|
5853
6217
|
return output.revision();
|
|
5854
6218
|
},
|
|
5855
|
-
subscribe: output.subscribe
|
|
6219
|
+
subscribe: output.subscribe,
|
|
6220
|
+
observe: output.observe
|
|
5856
6221
|
});
|
|
5857
6222
|
};
|
|
5858
6223
|
const projectionItems = (projection, requester) => {
|
|
@@ -5863,6 +6228,7 @@ const createProjectionRuntime = (options) => {
|
|
|
5863
6228
|
if (existing) return existing.items;
|
|
5864
6229
|
const controller = createProjectionItems(readableSource(projection, requester), () => {
|
|
5865
6230
|
if (requester && !requester.active) throw new require_transform.ProjectionDisposedError();
|
|
6231
|
+
scheduler.ensureCurrent(output);
|
|
5866
6232
|
assertOutput(output);
|
|
5867
6233
|
});
|
|
5868
6234
|
registry.set(output, controller);
|
|
@@ -5875,16 +6241,18 @@ const createProjectionRuntime = (options) => {
|
|
|
5875
6241
|
function selectProjection(projection, selector, equality) {
|
|
5876
6242
|
return makeReadable(projection, selector, equality);
|
|
5877
6243
|
}
|
|
5878
|
-
const
|
|
6244
|
+
const inputAccess = (target, requester) => {
|
|
6245
|
+
scheduler.assertIdle();
|
|
6246
|
+
if (requester && !requester.active) throw new require_transform.ProjectionDisposedError();
|
|
5879
6247
|
const ref = require_transform.projectionRef(target);
|
|
5880
6248
|
if (ref.output !== 0 || ref.producer.kind !== "source") throw new TypeError("Projection is not an input.");
|
|
5881
6249
|
if (ref.producer.source.kind !== "value-input" && ref.producer.source.kind !== "collection-input") throw new TypeError("Projection is not an input.");
|
|
5882
|
-
const
|
|
5883
|
-
if (!
|
|
5884
|
-
return
|
|
6250
|
+
const access = materializeProducer(ref.producer, requester).input;
|
|
6251
|
+
if (!access) throw new TypeError("Projection input is not writable.");
|
|
6252
|
+
return access;
|
|
5885
6253
|
};
|
|
5886
6254
|
const updateInput = (target, valueOrRun, requester) => {
|
|
5887
|
-
const write =
|
|
6255
|
+
const write = inputAccess(target, requester);
|
|
5888
6256
|
if (write.kind === "value") {
|
|
5889
6257
|
write.set(valueOrRun);
|
|
5890
6258
|
return;
|