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