doxum 0.1.32 → 0.1.33
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 -0
- 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 +273 -121
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -12
- package/dist/index.d.ts +23 -12
- package/dist/index.js +273 -121
- 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-gOtqcdHe.js → transform-A9Lx5R2l.js} +215 -174
- package/dist/transform-A9Lx5R2l.js.map +1 -0
- package/dist/{transform-CENhTaVN.cjs → transform-CSPGdBe5.cjs} +220 -173
- package/dist/transform-CSPGdBe5.cjs.map +1 -0
- package/package.json +1 -1
- package/skills/doxum-runtime/SKILL.md +4 -2
- package/skills/doxum-runtime/references/integrations.md +1 -1
- package/skills/doxum-runtime/references/projections.md +59 -1
- package/skills/doxum-runtime/references/public-api.md +18 -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
|
|
1
|
+
import { A as isProjection, C as compileProjectionDependencies, D as snapshotCollectionView, E as mapRead, M as producerOf, N as projectionRef, O as defineProcessor, P as profile, S as collectKeyedInvalidation, T as collectionView, _ as assertScope, a as collectionChangeTouchesKey, b as ProjectionDisposedError, c as diffCollection, d as createKeyedDependencyRuntime, f as outputKind, g as snapshotArray, h as sameArray, i as collectionChangeIntersects, j as ownProjections, k as defineSource, l as assertKeyedProjection, m as iterableMatchesArray, n as keyedAbsent, o as collectionHasStructuralChange, p as createKeyRelation, s as createCollectionChange, t as createKeyedTransform, u as compileKeyedDependencies, v as assertSynchronous, w as snapshotDependencyValue, x as ProjectionError, y as createScheduler } from "./transform-A9Lx5R2l.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,
|
|
@@ -3622,11 +3707,11 @@ var PersistentKeyedIndex = class PersistentKeyedIndex {
|
|
|
3622
3707
|
}
|
|
3623
3708
|
};
|
|
3624
3709
|
//#endregion
|
|
3625
|
-
//#region core/src/projection/
|
|
3626
|
-
const
|
|
3627
|
-
const values =
|
|
3628
|
-
let ids = Object.freeze([]);
|
|
3629
|
-
let index = PersistentKeyedIndex.empty();
|
|
3710
|
+
//#region core/src/projection/collection/state.ts
|
|
3711
|
+
const createCollectionState = (initial) => {
|
|
3712
|
+
const values = new Map(initial);
|
|
3713
|
+
let ids = Object.freeze([...values.keys()]);
|
|
3714
|
+
let index = values.size ? PersistentKeyedIndex.from(values) : PersistentKeyedIndex.empty();
|
|
3630
3715
|
return {
|
|
3631
3716
|
get: (key) => values.get(key),
|
|
3632
3717
|
has: (key) => values.has(key),
|
|
@@ -3651,7 +3736,7 @@ const createPublishedCollection = () => {
|
|
|
3651
3736
|
}
|
|
3652
3737
|
});
|
|
3653
3738
|
},
|
|
3654
|
-
|
|
3739
|
+
install: (staged, nextIds, reset) => {
|
|
3655
3740
|
if (reset) {
|
|
3656
3741
|
values.clear();
|
|
3657
3742
|
for (const [key, entry] of staged) if (entry.present) values.set(key, entry.value);
|
|
@@ -3670,9 +3755,11 @@ const createPublishedCollection = () => {
|
|
|
3670
3755
|
}
|
|
3671
3756
|
};
|
|
3672
3757
|
};
|
|
3758
|
+
//#endregion
|
|
3759
|
+
//#region core/src/projection/output/collection.ts
|
|
3673
3760
|
/** Owns staged keyed intent, exact transitions and published collection state. */
|
|
3674
3761
|
const createCollectionOutput = (binding) => {
|
|
3675
|
-
const published =
|
|
3762
|
+
const published = createCollectionState();
|
|
3676
3763
|
const staged = /* @__PURE__ */ new Map();
|
|
3677
3764
|
let nextIds = published.ids();
|
|
3678
3765
|
let change;
|
|
@@ -3761,12 +3848,18 @@ const createCollectionOutput = (binding) => {
|
|
|
3761
3848
|
continue;
|
|
3762
3849
|
}
|
|
3763
3850
|
const before = published.get(key);
|
|
3764
|
-
|
|
3851
|
+
const equal = isEqual(before, entry.value);
|
|
3852
|
+
assertSynchronous(equal);
|
|
3853
|
+
if (!equal) updatedEntries.push({
|
|
3765
3854
|
key,
|
|
3766
3855
|
before,
|
|
3767
3856
|
after: entry.value
|
|
3768
3857
|
});
|
|
3769
|
-
else if (
|
|
3858
|
+
else if (nextReset) staged.set(key, {
|
|
3859
|
+
present: true,
|
|
3860
|
+
value: before
|
|
3861
|
+
});
|
|
3862
|
+
else staged.delete(key);
|
|
3770
3863
|
continue;
|
|
3771
3864
|
}
|
|
3772
3865
|
if (existed) removedEntries.push({
|
|
@@ -3836,7 +3929,7 @@ const createCollectionOutput = (binding) => {
|
|
|
3836
3929
|
revision: () => revision,
|
|
3837
3930
|
reset: () => reset,
|
|
3838
3931
|
publish: () => {
|
|
3839
|
-
if (change) published.
|
|
3932
|
+
if (change) published.install(staged, nextIds, change.kind === "reset");
|
|
3840
3933
|
if (change && initialized) revision++;
|
|
3841
3934
|
initialized = true;
|
|
3842
3935
|
},
|
|
@@ -3916,7 +4009,9 @@ const createValueOutput = (binding) => {
|
|
|
3916
4009
|
return false;
|
|
3917
4010
|
}
|
|
3918
4011
|
const candidate = staged;
|
|
3919
|
-
|
|
4012
|
+
const equal = initialized ? isEqual(value, candidate) : false;
|
|
4013
|
+
assertSynchronous(equal);
|
|
4014
|
+
changed = !equal;
|
|
3920
4015
|
next = changed ? candidate : value;
|
|
3921
4016
|
reset = nextReset;
|
|
3922
4017
|
return changed;
|
|
@@ -5398,101 +5493,145 @@ const createExternalSourceRegistry = (scheduler, documents) => {
|
|
|
5398
5493
|
//#region core/src/projection/source/input.ts
|
|
5399
5494
|
const materializeInputSource = (scheduler, definition) => {
|
|
5400
5495
|
const source = definition.source;
|
|
5496
|
+
if (source.kind !== "value-input" && source.kind !== "collection-input") throw new Error("Invalid projection input source.");
|
|
5497
|
+
const equal = (previous, next) => {
|
|
5498
|
+
const result = source.equality(previous, next);
|
|
5499
|
+
assertSynchronous(result);
|
|
5500
|
+
return result;
|
|
5501
|
+
};
|
|
5401
5502
|
if (source.kind === "value-input") {
|
|
5402
5503
|
let latest = source.initial;
|
|
5403
|
-
const boundary = createValueBoundary(scheduler, "projection input", source.initial,
|
|
5504
|
+
const boundary = createValueBoundary(scheduler, "projection input", source.initial, Object.is, () => latest, () => void 0);
|
|
5505
|
+
boundary.detach(() => {
|
|
5506
|
+
latest = void 0;
|
|
5507
|
+
});
|
|
5404
5508
|
return {
|
|
5405
5509
|
...boundary,
|
|
5406
|
-
|
|
5510
|
+
input: {
|
|
5407
5511
|
kind: "value",
|
|
5512
|
+
read: () => latest,
|
|
5408
5513
|
set(value) {
|
|
5409
|
-
scheduler.
|
|
5410
|
-
|
|
5514
|
+
const next = scheduler.acceptInput(() => {
|
|
5515
|
+
if (equal(latest, value)) return latest;
|
|
5516
|
+
if (source.equality === Object.is) return value;
|
|
5517
|
+
const published = boundary.output.current();
|
|
5518
|
+
return !Object.is(latest, published) && equal(published, value) ? published : value;
|
|
5519
|
+
});
|
|
5520
|
+
if (Object.is(latest, next)) return;
|
|
5521
|
+
latest = next;
|
|
5411
5522
|
boundary.mark();
|
|
5412
5523
|
scheduler.run();
|
|
5413
5524
|
}
|
|
5414
5525
|
}
|
|
5415
5526
|
};
|
|
5416
5527
|
}
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
const
|
|
5528
|
+
const values = createCollectionState(source.initial);
|
|
5529
|
+
let view;
|
|
5530
|
+
const latest = {
|
|
5531
|
+
get: values.get,
|
|
5532
|
+
has: values.has,
|
|
5533
|
+
ids: values.ids
|
|
5534
|
+
};
|
|
5535
|
+
const boundary = createCollectionBoundary(scheduler, "projection collection input", () => latest, Object.is, () => void 0);
|
|
5536
|
+
boundary.detach(() => {
|
|
5537
|
+
values.release();
|
|
5538
|
+
view = void 0;
|
|
5539
|
+
});
|
|
5540
|
+
const check = () => {
|
|
5541
|
+
scheduler.assertActive();
|
|
5542
|
+
if (boundary.producer.disposed) throw new ProjectionDisposedError();
|
|
5543
|
+
};
|
|
5420
5544
|
return {
|
|
5421
5545
|
...boundary,
|
|
5422
|
-
|
|
5546
|
+
input: {
|
|
5423
5547
|
kind: "collection",
|
|
5548
|
+
read: () => view ??= collectionView(values.read(check)),
|
|
5424
5549
|
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);
|
|
5550
|
+
const accepted = scheduler.acceptInput(() => {
|
|
5551
|
+
const staged = /* @__PURE__ */ new Map();
|
|
5552
|
+
const appended = /* @__PURE__ */ new Set();
|
|
5553
|
+
let structural = false;
|
|
5554
|
+
let active = true;
|
|
5555
|
+
const has = (key) => {
|
|
5438
5556
|
const entry = staged.get(key);
|
|
5439
5557
|
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
|
-
|
|
5558
|
+
};
|
|
5559
|
+
const draft = Object.freeze({
|
|
5560
|
+
get: (key) => {
|
|
5561
|
+
assertScope(() => active);
|
|
5562
|
+
const entry = staged.get(key);
|
|
5563
|
+
return entry ? entry.present ? entry.value : void 0 : values.get(key);
|
|
5564
|
+
},
|
|
5565
|
+
has: (key) => {
|
|
5566
|
+
assertScope(() => active);
|
|
5567
|
+
return has(key);
|
|
5568
|
+
},
|
|
5569
|
+
set: (key, value) => {
|
|
5570
|
+
assertScope(() => active);
|
|
5571
|
+
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
5572
|
+
if (!has(key)) {
|
|
5573
|
+
appended.add(key);
|
|
5574
|
+
structural = true;
|
|
5575
|
+
}
|
|
5576
|
+
staged.set(key, {
|
|
5577
|
+
present: true,
|
|
5578
|
+
value
|
|
5579
|
+
});
|
|
5580
|
+
},
|
|
5581
|
+
remove: (key) => {
|
|
5582
|
+
assertScope(() => active);
|
|
5583
|
+
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
5584
|
+
if (!has(key)) return;
|
|
5585
|
+
appended.delete(key);
|
|
5586
|
+
structural = true;
|
|
5587
|
+
staged.set(key, { present: false });
|
|
5588
|
+
}
|
|
5589
|
+
});
|
|
5590
|
+
try {
|
|
5591
|
+
assertSynchronous(run(draft));
|
|
5592
|
+
} finally {
|
|
5593
|
+
active = false;
|
|
5467
5594
|
}
|
|
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);
|
|
5595
|
+
const published = source.equality === Object.is ? void 0 : boundary.output.current();
|
|
5596
|
+
for (const [key, entry] of staged) {
|
|
5597
|
+
const existed = values.has(key);
|
|
5598
|
+
if (!entry.present) {
|
|
5599
|
+
if (!existed) staged.delete(key);
|
|
5482
5600
|
continue;
|
|
5483
5601
|
}
|
|
5484
5602
|
const previous = values.get(key);
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5603
|
+
let next = entry.value;
|
|
5604
|
+
if (existed && equal(previous, next)) next = previous;
|
|
5605
|
+
else if (published?.has(key)) {
|
|
5606
|
+
const before = published.get(key);
|
|
5607
|
+
if ((!existed || !Object.is(previous, before)) && equal(before, next)) next = before;
|
|
5608
|
+
}
|
|
5609
|
+
if (existed && Object.is(previous, next)) staged.delete(key);
|
|
5610
|
+
else if (!Object.is(entry.value, next)) staged.set(key, {
|
|
5611
|
+
present: true,
|
|
5612
|
+
value: next
|
|
5613
|
+
});
|
|
5614
|
+
}
|
|
5615
|
+
const beforeOrder = values.ids();
|
|
5616
|
+
let order = beforeOrder;
|
|
5617
|
+
if (structural) {
|
|
5618
|
+
const next = [];
|
|
5619
|
+
for (const key of beforeOrder) if (has(key) && !appended.has(key)) next.push(key);
|
|
5620
|
+
for (const key of appended) next.push(key);
|
|
5621
|
+
if (!sameArray(beforeOrder, next)) order = Object.freeze(next);
|
|
5622
|
+
}
|
|
5623
|
+
return {
|
|
5624
|
+
staged,
|
|
5625
|
+
order,
|
|
5626
|
+
structural: order !== beforeOrder
|
|
5627
|
+
};
|
|
5628
|
+
});
|
|
5629
|
+
if (!accepted.staged.size && !accepted.structural) return;
|
|
5630
|
+
values.install(accepted.staged, accepted.order, false);
|
|
5631
|
+
view = void 0;
|
|
5493
5632
|
boundary.mark({
|
|
5494
|
-
candidates,
|
|
5495
|
-
orderMayChange: structural
|
|
5633
|
+
candidates: accepted.staged.keys(),
|
|
5634
|
+
orderMayChange: accepted.structural
|
|
5496
5635
|
});
|
|
5497
5636
|
scheduler.run();
|
|
5498
5637
|
}
|
|
@@ -5789,7 +5928,7 @@ const createProjectionRuntime = (options) => {
|
|
|
5789
5928
|
result = Object.freeze({
|
|
5790
5929
|
record: source.producer,
|
|
5791
5930
|
outputs: Object.freeze([source.output]),
|
|
5792
|
-
...source.
|
|
5931
|
+
...source.input ? { input: source.input } : {}
|
|
5793
5932
|
});
|
|
5794
5933
|
} else {
|
|
5795
5934
|
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.");
|
|
@@ -5874,16 +6013,18 @@ const createProjectionRuntime = (options) => {
|
|
|
5874
6013
|
function selectProjection(projection, selector, equality) {
|
|
5875
6014
|
return makeReadable(projection, selector, equality);
|
|
5876
6015
|
}
|
|
5877
|
-
const
|
|
6016
|
+
const inputAccess = (target, requester) => {
|
|
6017
|
+
scheduler.assertIdle();
|
|
6018
|
+
if (requester && !requester.active) throw new ProjectionDisposedError();
|
|
5878
6019
|
const ref = projectionRef(target);
|
|
5879
6020
|
if (ref.output !== 0 || ref.producer.kind !== "source") throw new TypeError("Projection is not an input.");
|
|
5880
6021
|
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
|
|
6022
|
+
const access = materializeProducer(ref.producer, requester).input;
|
|
6023
|
+
if (!access) throw new TypeError("Projection input is not writable.");
|
|
6024
|
+
return access;
|
|
5884
6025
|
};
|
|
5885
6026
|
const updateInput = (target, valueOrRun, requester) => {
|
|
5886
|
-
const write =
|
|
6027
|
+
const write = inputAccess(target, requester);
|
|
5887
6028
|
if (write.kind === "value") {
|
|
5888
6029
|
write.set(valueOrRun);
|
|
5889
6030
|
return;
|
|
@@ -5894,7 +6035,18 @@ const createProjectionRuntime = (options) => {
|
|
|
5894
6035
|
function update(target, valueOrRun) {
|
|
5895
6036
|
updateInput(target, valueOrRun);
|
|
5896
6037
|
}
|
|
5897
|
-
const batch = (run, options) => scheduler.batch(
|
|
6038
|
+
const batch = (run, options, requester) => scheduler.batch(() => {
|
|
6039
|
+
let active = true;
|
|
6040
|
+
const read = (target) => {
|
|
6041
|
+
assertScope(() => active);
|
|
6042
|
+
return inputAccess(target, requester).read();
|
|
6043
|
+
};
|
|
6044
|
+
try {
|
|
6045
|
+
return run(read);
|
|
6046
|
+
} finally {
|
|
6047
|
+
active = false;
|
|
6048
|
+
}
|
|
6049
|
+
}, options);
|
|
5898
6050
|
const disposeScope = (state) => {
|
|
5899
6051
|
if (!state.active) return;
|
|
5900
6052
|
scheduler.assertIdle();
|
|
@@ -5986,7 +6138,7 @@ const createProjectionRuntime = (options) => {
|
|
|
5986
6138
|
}
|
|
5987
6139
|
function scopeBatch(run, options) {
|
|
5988
6140
|
assertActive();
|
|
5989
|
-
return batch(run, options);
|
|
6141
|
+
return batch(run, options, state);
|
|
5990
6142
|
}
|
|
5991
6143
|
return Object.freeze({
|
|
5992
6144
|
own,
|