doxum 0.1.19 → 0.1.21
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 +30 -11
- package/dist/{scope-d-L87NeC.js → access-BeSV5ve-.js} +114 -20
- package/dist/access-BeSV5ve-.js.map +1 -0
- package/dist/{scope-Ezs-Y3TY.cjs → access-Bienf28h.cjs} +149 -19
- package/dist/access-Bienf28h.cjs.map +1 -0
- package/dist/advanced-BRL5pN0y.cjs +1361 -0
- package/dist/advanced-BRL5pN0y.cjs.map +1 -0
- package/dist/advanced-COFJtWMT.js +1188 -0
- package/dist/advanced-COFJtWMT.js.map +1 -0
- package/dist/{advanced-C2fpjbK3.d.ts → advanced-DfKc7TZR.d.cts} +27 -22
- package/dist/{advanced-DlOYk1vi.d.cts → advanced-FgdTwu5b.d.ts} +27 -22
- package/dist/advanced.cjs +1 -1
- package/dist/advanced.d.cts +2 -2
- package/dist/advanced.d.ts +2 -2
- package/dist/advanced.js +1 -1
- package/dist/{contract-XmKnroJq.d.cts → contract-CdmDHRUq.d.cts} +8 -6
- package/dist/{contract-CATCCVu5.d.ts → contract-KG5XnQZt.d.ts} +8 -6
- package/dist/{driver-CSnhMjbP.js → driver-CLYJOGDQ.js} +2 -2
- package/dist/{driver-CSnhMjbP.js.map → driver-CLYJOGDQ.js.map} +1 -1
- package/dist/{driver-BCyfqxsl.cjs → driver-Djr3BVvo.cjs} +2 -2
- package/dist/{driver-BCyfqxsl.cjs.map → driver-Djr3BVvo.cjs.map} +1 -1
- package/dist/index.cjs +1150 -1993
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1105 -1948
- package/dist/index.js.map +1 -1
- package/dist/{integration-CxVhq-KD.js → integration-C4Isp8lJ.js} +3 -2
- package/dist/{integration-CxVhq-KD.js.map → integration-C4Isp8lJ.js.map} +1 -1
- package/dist/{integration-B7VDgAOJ.cjs → integration-Z6MsfFI7.cjs} +4 -3
- package/dist/{integration-B7VDgAOJ.cjs.map → integration-Z6MsfFI7.cjs.map} +1 -1
- package/dist/integration.cjs +3 -3
- package/dist/integration.d.cts +1 -1
- package/dist/integration.d.ts +1 -1
- package/dist/integration.js +3 -3
- package/dist/{issue-DhrNdQNg.cjs → issue-DjK1xp5K.cjs} +106 -22
- package/dist/issue-DjK1xp5K.cjs.map +1 -0
- package/dist/{issue-DVaGQGeP.js → issue-W0hT8u8D.js} +81 -15
- package/dist/issue-W0hT8u8D.js.map +1 -0
- package/dist/local-sync.cjs +2 -2
- package/dist/local-sync.d.cts +1 -1
- package/dist/local-sync.d.ts +1 -1
- package/dist/local-sync.js +2 -2
- package/dist/{notification-IQIJyH3Q.js → notification-Bkjau6B6.js} +3 -56
- package/dist/notification-Bkjau6B6.js.map +1 -0
- package/dist/{notification-CDSUfiip.cjs → notification-DJfouMEb.cjs} +2 -91
- package/dist/notification-DJfouMEb.cjs.map +1 -0
- package/dist/react.cjs +2 -2
- package/dist/react.js +2 -2
- package/package.json +1 -1
- package/skills/doxum-runtime/SKILL.md +4 -1
- package/skills/doxum-runtime/references/guide.en.md +5 -2
- package/skills/doxum-runtime/references/guide.zh-CN.md +5 -2
- package/skills/doxum-runtime/references/projections.en.md +23 -9
- package/skills/doxum-runtime/references/projections.zh-CN.md +18 -6
- package/dist/advanced-BYZCjNWL.js +0 -680
- package/dist/advanced-BYZCjNWL.js.map +0 -1
- package/dist/advanced-CMMNk49G.cjs +0 -763
- package/dist/advanced-CMMNk49G.cjs.map +0 -1
- package/dist/issue-DVaGQGeP.js.map +0 -1
- package/dist/issue-DhrNdQNg.cjs.map +0 -1
- package/dist/notification-CDSUfiip.cjs.map +0 -1
- package/dist/notification-IQIJyH3Q.js.map +0 -1
- package/dist/scope-Ezs-Y3TY.cjs.map +0 -1
- package/dist/scope-d-L87NeC.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,97 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_issue = require("./issue-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
//#region core/src/schema.ts
|
|
8
|
-
const node = (value) => Object.freeze(value);
|
|
9
|
-
const field = (validator) => node({
|
|
10
|
-
kind: "field",
|
|
11
|
-
...validator ? { validator } : {}
|
|
12
|
-
});
|
|
13
|
-
const optional = (value) => {
|
|
14
|
-
if (![
|
|
15
|
-
"field",
|
|
16
|
-
"variant",
|
|
17
|
-
"map",
|
|
18
|
-
"list",
|
|
19
|
-
"tree"
|
|
20
|
-
].includes(value.kind)) throw new TypeError("Only field, variant, map, list and tree nodes support optional presence.");
|
|
21
|
-
return node({
|
|
22
|
-
...value,
|
|
23
|
-
optional: true
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
|
-
const object = (shape) => node({
|
|
27
|
-
kind: "object",
|
|
28
|
-
shape: Object.freeze({ ...shape })
|
|
29
|
-
});
|
|
30
|
-
const variant = (tag, variants) => node({
|
|
31
|
-
kind: "variant",
|
|
32
|
-
tag,
|
|
33
|
-
variants: Object.freeze({ ...variants })
|
|
34
|
-
});
|
|
35
|
-
const table = (value, options) => node({
|
|
36
|
-
kind: "table",
|
|
37
|
-
value,
|
|
38
|
-
...options
|
|
39
|
-
});
|
|
40
|
-
const map = (value, options) => node({
|
|
41
|
-
kind: "map",
|
|
42
|
-
value,
|
|
43
|
-
...options
|
|
44
|
-
});
|
|
45
|
-
const list = (value, config) => node({
|
|
46
|
-
kind: "list",
|
|
47
|
-
keyOf: config.keyOf,
|
|
48
|
-
value
|
|
49
|
-
});
|
|
50
|
-
const tree = (value) => node({
|
|
51
|
-
kind: "tree",
|
|
52
|
-
value
|
|
53
|
-
});
|
|
54
|
-
const paths = /* @__PURE__ */ new WeakMap();
|
|
55
|
-
const pathProxy = (nodes, address, owner) => {
|
|
56
|
-
const proxy = new Proxy({}, { get: (_target, property) => {
|
|
57
|
-
if (typeof property !== "string") return void 0;
|
|
58
|
-
if (nodes.every((node) => node.kind === "table" || node.kind === "map") && property === "item") return (id) => {
|
|
59
|
-
if (typeof id !== "string") throw new TypeError("Collection keys must be strings.");
|
|
60
|
-
for (const node of nodes) if (node.kind === "table" || node.kind === "map") {
|
|
61
|
-
const invalid = require_scope.checkKey(node.key, id, [...address, id]);
|
|
62
|
-
if (invalid) throw new TypeError(invalid.message);
|
|
63
|
-
}
|
|
64
|
-
return pathProxy(nodes.map((node) => node.value), [...address, id], owner);
|
|
65
|
-
};
|
|
66
|
-
const children = nodes.flatMap((node) => {
|
|
67
|
-
if (node.kind === "object") return Object.hasOwn(node.shape, property) ? [node.shape[property]] : [];
|
|
68
|
-
if (node.kind !== "variant") return [];
|
|
69
|
-
if (property === node.tag) return [field()];
|
|
70
|
-
return Object.values(node.variants).flatMap((branch) => Object.hasOwn(branch.shape, property) ? [branch.shape[property]] : []);
|
|
71
|
-
});
|
|
72
|
-
if (!children.length) throw new TypeError(`Invalid schema path segment: ${property}`);
|
|
73
|
-
return pathProxy(children, [...address, property], owner);
|
|
74
|
-
} });
|
|
75
|
-
paths.set(proxy, {
|
|
76
|
-
nodes,
|
|
77
|
-
address,
|
|
78
|
-
owner
|
|
79
|
-
});
|
|
80
|
-
return proxy;
|
|
81
|
-
};
|
|
82
|
-
const compilePath = (owner, kind, pick) => {
|
|
83
|
-
const scope = {};
|
|
84
|
-
const value = pick(pathProxy([owner], [], scope));
|
|
85
|
-
const selected = typeof value === "object" && value !== null ? paths.get(value) : void 0;
|
|
86
|
-
if (!selected || selected.owner !== scope) throw new TypeError("Selector must return a path from its callback.");
|
|
87
|
-
if (kind === "collection" && !selected.nodes.every((node) => node.kind === "table" || node.kind === "map")) throw new TypeError("Collection selectors require a table or map path.");
|
|
88
|
-
return Object.freeze({
|
|
89
|
-
kind,
|
|
90
|
-
schema: owner,
|
|
91
|
-
address: Object.freeze([...selected.address])
|
|
92
|
-
});
|
|
93
|
-
};
|
|
94
|
-
//#endregion
|
|
2
|
+
const require_issue = require("./issue-DjK1xp5K.cjs");
|
|
3
|
+
const require_access = require("./access-Bienf28h.cjs");
|
|
4
|
+
const require_advanced = require("./advanced-BRL5pN0y.cjs");
|
|
5
|
+
const require_notification = require("./notification-DJfouMEb.cjs");
|
|
6
|
+
const require_driver = require("./driver-Djr3BVvo.cjs");
|
|
95
7
|
//#region core/src/impact.ts
|
|
96
8
|
const queries = /* @__PURE__ */ new WeakMap();
|
|
97
9
|
const affectsTarget = (impact, value) => queries.get(impact).affects(value);
|
|
@@ -183,8 +95,8 @@ const createImpact = (schema, changes) => {
|
|
|
183
95
|
};
|
|
184
96
|
const impact = Object.freeze({
|
|
185
97
|
kind: reset ? "reset" : "incremental",
|
|
186
|
-
affects: (pick) => implementation.affects(compilePath(schema, "value", pick)),
|
|
187
|
-
collection: (pick) => implementation.collection(compilePath(schema, "collection", pick))
|
|
98
|
+
affects: (pick) => implementation.affects(require_advanced.compilePath(schema, "value", pick)),
|
|
99
|
+
collection: (pick) => implementation.collection(require_advanced.compilePath(schema, "collection", pick))
|
|
188
100
|
});
|
|
189
101
|
queries.set(impact, implementation);
|
|
190
102
|
return impact;
|
|
@@ -278,7 +190,7 @@ const createHistory = (input) => {
|
|
|
278
190
|
current: () => state,
|
|
279
191
|
revision: () => revision,
|
|
280
192
|
subscribe: (listener) => {
|
|
281
|
-
if (disposed) throw new
|
|
193
|
+
if (disposed) throw new require_access.DocumentDisposedError();
|
|
282
194
|
listeners.add(listener);
|
|
283
195
|
return () => {
|
|
284
196
|
listeners.delete(listener);
|
|
@@ -373,7 +285,7 @@ const installMember = (parent, key, present, value) => {
|
|
|
373
285
|
});
|
|
374
286
|
};
|
|
375
287
|
const orderOf = (node, value) => {
|
|
376
|
-
if (node.kind === "list") return
|
|
288
|
+
if (node.kind === "list") return require_issue.toArray(require_issue.indexedKeys(value, node.keyOf));
|
|
377
289
|
if (node.kind === "table") return [...value.ids];
|
|
378
290
|
throw new Error("Order requires a table or list.");
|
|
379
291
|
};
|
|
@@ -403,8 +315,8 @@ const copyNode = (node) => ({
|
|
|
403
315
|
});
|
|
404
316
|
const transition = (node, key, beforePresent, before, afterPresent, after) => {
|
|
405
317
|
if (beforePresent === afterPresent && (!beforePresent || Object.is(before, after))) return;
|
|
406
|
-
if (node.kind !== "field" && beforePresent === afterPresent &&
|
|
407
|
-
const value = afterPresent ? node.kind === "field" ? after :
|
|
318
|
+
if (node.kind !== "field" && beforePresent === afterPresent && require_access.equalValue(node, before, after)) return;
|
|
319
|
+
const value = afterPresent ? node.kind === "field" ? after : require_access.copyValue(node, after) : void 0;
|
|
408
320
|
require_issue.profile.recorder("transitions");
|
|
409
321
|
return !beforePresent ? {
|
|
410
322
|
key,
|
|
@@ -477,7 +389,7 @@ const restore = (fact, schema, root, skip = 0) => {
|
|
|
477
389
|
const at = skip ? fact.at.slice(skip) : fact.at;
|
|
478
390
|
if (fact.kind === "member") {
|
|
479
391
|
const member = fact.member;
|
|
480
|
-
const value = member.present ?
|
|
392
|
+
const value = member.present ? require_access.copyValue(member.node, member.value) : void 0;
|
|
481
393
|
if (!at.length) return value;
|
|
482
394
|
const location = require_issue.resolveLocated(schema, root, at);
|
|
483
395
|
if (!location) throw new Error("Cannot restore an unresolved member.");
|
|
@@ -496,7 +408,7 @@ const restore = (fact, schema, root, skip = 0) => {
|
|
|
496
408
|
return root;
|
|
497
409
|
};
|
|
498
410
|
const reconstructBefore = (node, current, records, offset) => {
|
|
499
|
-
let before =
|
|
411
|
+
let before = require_access.copyValue(node, current);
|
|
500
412
|
for (let i = records.length - 1; i >= 0; i--) if (records[i].kind !== "order") before = restore(records[i], node, before, offset);
|
|
501
413
|
for (const record of records) if (record.kind === "order") before = restore(record, node, before, offset);
|
|
502
414
|
return before;
|
|
@@ -515,7 +427,7 @@ const sealMembers = (fact, changes) => {
|
|
|
515
427
|
}
|
|
516
428
|
let order;
|
|
517
429
|
if (fact.order) {
|
|
518
|
-
const current = fact.node.kind === "list" ? require_issue.
|
|
430
|
+
const current = fact.node.kind === "list" ? require_issue.indexedKeys(fact.value, fact.node.keyOf) : fact.value.ids;
|
|
519
431
|
if (!require_issue.equal(fact.order, current)) {
|
|
520
432
|
const after = orderOf(fact.node, fact.value);
|
|
521
433
|
require_issue.profile.recorder("publishedOrderItems", after.length);
|
|
@@ -536,7 +448,7 @@ const sealTree = (fact, state, changes) => {
|
|
|
536
448
|
for (const [id, before] of fact.nodes) {
|
|
537
449
|
const after = Object.hasOwn(tree.nodes, id) ? tree.nodes[id] : void 0;
|
|
538
450
|
if (!before && !after) continue;
|
|
539
|
-
if (before && after && before.parentId === after.parentId && require_issue.equal(before.children, after.children) && Object.hasOwn(before, "value") === Object.hasOwn(after, "value") &&
|
|
451
|
+
if (before && after && before.parentId === after.parentId && require_issue.equal(before.children, after.children) && Object.hasOwn(before, "value") === Object.hasOwn(after, "value") && require_access.equalValue(node.value, before.value, after.value)) continue;
|
|
540
452
|
nodes.push(!before ? {
|
|
541
453
|
id,
|
|
542
454
|
kind: "added",
|
|
@@ -744,7 +656,7 @@ var ChangeRecorder = class {
|
|
|
744
656
|
const fact = facts[i];
|
|
745
657
|
if (fact.kind === "members") for (const member of fact.members?.values() ?? []) {
|
|
746
658
|
if (!member) continue;
|
|
747
|
-
installMember(fact.parent, require_issue.memberKey(fact, member.key), member.present, member.present ?
|
|
659
|
+
installMember(fact.parent, require_issue.memberKey(fact, member.key), member.present, member.present ? require_access.copyValue(member.node, member.value) : void 0);
|
|
748
660
|
}
|
|
749
661
|
else if (fact.kind === "tree") restore(fact, this.state.schema, this.state.document);
|
|
750
662
|
}
|
|
@@ -752,12 +664,12 @@ var ChangeRecorder = class {
|
|
|
752
664
|
}
|
|
753
665
|
seal() {
|
|
754
666
|
if (this.resetBefore) {
|
|
755
|
-
if (
|
|
667
|
+
if (require_access.equalValue(this.state.schema, this.resetBefore.value, this.state.document)) return require_driver.sealChanges([]);
|
|
756
668
|
require_issue.profile.recorder("sealed");
|
|
757
669
|
return require_driver.sealChanges([{
|
|
758
670
|
kind: "reset",
|
|
759
671
|
before: this.resetBefore.value,
|
|
760
|
-
after:
|
|
672
|
+
after: require_access.copyValue(this.state.schema, this.state.document)
|
|
761
673
|
}]);
|
|
762
674
|
}
|
|
763
675
|
const changes = [];
|
|
@@ -784,7 +696,7 @@ var MutationSession = class {
|
|
|
784
696
|
this.resolvedRoot = state.document;
|
|
785
697
|
}
|
|
786
698
|
validate(node, value, at) {
|
|
787
|
-
const issue =
|
|
699
|
+
const issue = require_access.checkValue(node, value, at);
|
|
788
700
|
if (issue) require_issue.invalidValue(issue);
|
|
789
701
|
}
|
|
790
702
|
resolveContainer(at) {
|
|
@@ -806,7 +718,7 @@ var MutationSession = class {
|
|
|
806
718
|
this.validate(this.state.schema, value, at);
|
|
807
719
|
if (Object.is(this.state.document, value)) return;
|
|
808
720
|
this.recorder.reset();
|
|
809
|
-
this.state.document =
|
|
721
|
+
this.state.document = require_access.copyValue(this.state.schema, value);
|
|
810
722
|
this.invalidate();
|
|
811
723
|
return;
|
|
812
724
|
}
|
|
@@ -848,12 +760,12 @@ var MutationSession = class {
|
|
|
848
760
|
const previous = container.parent[physicalKey];
|
|
849
761
|
if (existed === present && (!present || Object.is(previous, value))) return false;
|
|
850
762
|
if (parentNode.kind === "map" || parentNode.kind === "table") {
|
|
851
|
-
const issue =
|
|
763
|
+
const issue = require_access.checkKey(parentNode.key, key, []);
|
|
852
764
|
if (issue) return require_issue.fail(container.at.concat(key, ...issue.address), "invalid-key", issue.message);
|
|
853
765
|
}
|
|
854
766
|
if (present) {
|
|
855
767
|
if (node.kind === "field") {
|
|
856
|
-
const issue =
|
|
768
|
+
const issue = require_access.checkValue(node, value, []);
|
|
857
769
|
if (issue) return require_issue.invalidValue(issue, container.at.concat(key, ...issue.address));
|
|
858
770
|
} else this.validate(node, value, container.at.concat(key));
|
|
859
771
|
if (parentNode.kind === "list" && parentNode.keyOf(value) !== key) return require_issue.fail(container.at.concat(key), "invalid-list-key", "Replacing an item must retain its addressed key.");
|
|
@@ -861,7 +773,7 @@ var MutationSession = class {
|
|
|
861
773
|
const membershipChanged = entry && existed !== present;
|
|
862
774
|
if (membershipChanged && (parentNode.kind === "list" || parentNode.kind === "table")) this.recorder.order(container);
|
|
863
775
|
this.recorder.member(container, key, member, physicalKey);
|
|
864
|
-
const next = present ? node.kind === "field" ? value :
|
|
776
|
+
const next = present ? node.kind === "field" ? value : require_access.copyValue(node, value) : void 0;
|
|
865
777
|
installMember(container.parent, physicalKey, present, next);
|
|
866
778
|
if (node.kind !== "field" || membershipChanged) this.invalidate();
|
|
867
779
|
return membershipChanged;
|
|
@@ -931,18 +843,18 @@ function apply(session, changes, direction) {
|
|
|
931
843
|
//#region core/src/runtime.ts
|
|
932
844
|
const createDocument = (input) => {
|
|
933
845
|
if (input.schema.kind !== "object") throw new TypeError("Document schema must be a root object node.");
|
|
934
|
-
const invalid =
|
|
935
|
-
if (invalid) throw new
|
|
846
|
+
const invalid = require_access.checkValue(input.schema, input.initial);
|
|
847
|
+
if (invalid) throw new require_access.ParseError(invalid);
|
|
936
848
|
const state = {
|
|
937
849
|
schema: input.schema,
|
|
938
|
-
document:
|
|
850
|
+
document: require_access.copyValue(input.schema, input.initial),
|
|
939
851
|
disposed: false
|
|
940
852
|
};
|
|
941
853
|
let revision = 0, busy = false;
|
|
942
854
|
let runtime, notification;
|
|
943
855
|
const idle = () => {
|
|
944
|
-
if (state.disposed) throw new
|
|
945
|
-
if (busy ||
|
|
856
|
+
if (state.disposed) throw new require_access.DocumentDisposedError();
|
|
857
|
+
if (busy || require_access.accessOf(runtime).projectionLocks) throw new require_access.DocumentReentrancyError();
|
|
946
858
|
};
|
|
947
859
|
const writable = (intent) => {
|
|
948
860
|
idle();
|
|
@@ -1000,7 +912,7 @@ const createDocument = (input) => {
|
|
|
1000
912
|
issues: [error.issue],
|
|
1001
913
|
revision
|
|
1002
914
|
};
|
|
1003
|
-
if (intent.kind === "update" && error instanceof
|
|
915
|
+
if (intent.kind === "update" && error instanceof require_access.TransactionRejected) return {
|
|
1004
916
|
status: "rejected",
|
|
1005
917
|
issues: error.issues,
|
|
1006
918
|
revision
|
|
@@ -1033,7 +945,7 @@ const createDocument = (input) => {
|
|
|
1033
945
|
kind: "update",
|
|
1034
946
|
source
|
|
1035
947
|
}, options?.history ?? true, (session) => {
|
|
1036
|
-
value = run(
|
|
948
|
+
value = run(require_access.createAccess({
|
|
1037
949
|
state,
|
|
1038
950
|
session
|
|
1039
951
|
}));
|
|
@@ -1059,15 +971,15 @@ const createDocument = (input) => {
|
|
|
1059
971
|
}, source !== "remote", (session) => session.replace([], value));
|
|
1060
972
|
},
|
|
1061
973
|
snapshot: () => {
|
|
1062
|
-
if (state.disposed) throw new
|
|
1063
|
-
return
|
|
974
|
+
if (state.disposed) throw new require_access.DocumentDisposedError();
|
|
975
|
+
return require_access.copyValue(input.schema, state.document);
|
|
1064
976
|
},
|
|
1065
977
|
subscribe: ((pick, listener) => {
|
|
1066
|
-
if (state.disposed) throw new
|
|
978
|
+
if (state.disposed) throw new require_access.DocumentDisposedError();
|
|
1067
979
|
if (!listener) return require_notification.subscribeRoot(notification, pick);
|
|
1068
980
|
const picks = Array.isArray(pick) ? pick : [pick];
|
|
1069
981
|
if (!picks.length) throw new TypeError("Expected at least one subscription path.");
|
|
1070
|
-
return require_notification.subscribeTargets(notification, picks.map((p) => compilePath(input.schema, "value", p)), listener);
|
|
982
|
+
return require_notification.subscribeTargets(notification, picks.map((p) => require_advanced.compilePath(input.schema, "value", p)), listener);
|
|
1071
983
|
}),
|
|
1072
984
|
history: history.api,
|
|
1073
985
|
dispose: () => {
|
|
@@ -1082,7 +994,7 @@ const createDocument = (input) => {
|
|
|
1082
994
|
}
|
|
1083
995
|
}
|
|
1084
996
|
};
|
|
1085
|
-
|
|
997
|
+
require_access.bindRuntimeAccess(runtime, state);
|
|
1086
998
|
require_driver.bindRuntimeDriver(runtime);
|
|
1087
999
|
notification = require_notification.createNotification(runtime);
|
|
1088
1000
|
require_notification.bindDocumentReadable(history.api, runtime);
|
|
@@ -1096,1953 +1008,1227 @@ const asReadable = (runtime) => {
|
|
|
1096
1008
|
revision: runtime.revision,
|
|
1097
1009
|
subscribe: runtime.subscribe
|
|
1098
1010
|
};
|
|
1099
|
-
|
|
1011
|
+
require_access.bindRuntimeAccess(readable, require_access.accessOf(runtime));
|
|
1100
1012
|
require_notification.shareNotification(runtime, readable);
|
|
1101
1013
|
return Object.freeze(readable);
|
|
1102
1014
|
};
|
|
1103
1015
|
//#endregion
|
|
1104
1016
|
//#region core/src/projection/select.ts
|
|
1105
|
-
const read = (runtime, selector) =>
|
|
1017
|
+
const read = (runtime, selector) => require_access.readWith(runtime, selector);
|
|
1106
1018
|
//#endregion
|
|
1107
|
-
//#region core/src/projection/
|
|
1108
|
-
const
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
let reset = false;
|
|
1131
|
-
let orderChanged = false;
|
|
1132
|
-
const keys = /* @__PURE__ */ new Set();
|
|
1133
|
-
let baseline;
|
|
1134
|
-
let baselineIds = Object.freeze([]);
|
|
1135
|
-
let nextBaseline;
|
|
1136
|
-
let nextBaselineIds = Object.freeze([]);
|
|
1137
|
-
const collectionNode = collection ? require_issue.nodeAt(state.schema, collection.address, state.document) : void 0;
|
|
1138
|
-
const entryNode = collectionNode && (collectionNode.kind === "map" || collectionNode.kind === "table") ? collectionNode.value : void 0;
|
|
1139
|
-
const sameEntry = (left, right) => entryNode ? require_scope.equalValue(entryNode, left, right) : Object.is(left, right);
|
|
1140
|
-
const record = {
|
|
1141
|
-
consumers: /* @__PURE__ */ new Set(),
|
|
1142
|
-
disposed: false,
|
|
1143
|
-
fault: void 0,
|
|
1144
|
-
revision: runtime.revision,
|
|
1145
|
-
reset: () => reset,
|
|
1146
|
-
clear: () => {
|
|
1147
|
-
if (collection && nextBaseline) {
|
|
1148
|
-
baseline = nextBaseline;
|
|
1149
|
-
baselineIds = nextBaselineIds;
|
|
1150
|
-
}
|
|
1151
|
-
reset = false;
|
|
1152
|
-
orderChanged = false;
|
|
1153
|
-
batch = void 0;
|
|
1154
|
-
keys.clear();
|
|
1155
|
-
nextBaseline = void 0;
|
|
1156
|
-
nextBaselineIds = Object.freeze([]);
|
|
1157
|
-
},
|
|
1158
|
-
context: (active) => {
|
|
1159
|
-
require_advanced.assertScope(active);
|
|
1160
|
-
if (state.disposed) throw new Error("Document has been disposed.");
|
|
1161
|
-
const context = {
|
|
1162
|
-
state,
|
|
1163
|
-
active
|
|
1164
|
-
};
|
|
1165
|
-
const rawRead = collection ? require_scope.collectionAccess(context, collection.address) : void 0;
|
|
1166
|
-
const snapshots = collection ? /* @__PURE__ */ new Map() : void 0;
|
|
1167
|
-
const read = collection ? Object.freeze({
|
|
1168
|
-
get: (key) => {
|
|
1169
|
-
require_advanced.assertScope(active);
|
|
1170
|
-
if (!snapshots.has(key)) snapshots.set(key, require_scope.snapshot(rawRead.get(key)));
|
|
1171
|
-
return snapshots.get(key);
|
|
1172
|
-
},
|
|
1173
|
-
has: (key) => {
|
|
1174
|
-
require_advanced.assertScope(active);
|
|
1175
|
-
return rawRead.has(key);
|
|
1176
|
-
},
|
|
1177
|
-
ids: () => {
|
|
1178
|
-
require_advanced.assertScope(active);
|
|
1179
|
-
return rawRead.ids();
|
|
1180
|
-
}
|
|
1181
|
-
}) : require_scope.createAccess(context);
|
|
1182
|
-
if (!collection) return Object.freeze({
|
|
1183
|
-
kind: "document",
|
|
1184
|
-
read,
|
|
1185
|
-
revision: runtime.revision(),
|
|
1186
|
-
reset: record.reset(),
|
|
1187
|
-
cause: batch?.cause
|
|
1188
|
-
});
|
|
1189
|
-
if (!baseline) {
|
|
1190
|
-
const collectionRead = read;
|
|
1191
|
-
baseline = /* @__PURE__ */ new Map();
|
|
1192
|
-
baselineIds = Object.freeze(require_scope.collectionAccess(context, collection.address).ids().slice());
|
|
1193
|
-
for (const key of baselineIds) {
|
|
1194
|
-
const value = collectionRead.get(key);
|
|
1195
|
-
baseline.set(key, value);
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
const changed = [...keys];
|
|
1199
|
-
const added = [];
|
|
1200
|
-
const updated = [];
|
|
1201
|
-
const removed = [];
|
|
1202
|
-
const next = new Map(baseline);
|
|
1203
|
-
const collectionRead = read;
|
|
1204
|
-
for (const key of changed) {
|
|
1205
|
-
const beforePresent = baseline.has(key);
|
|
1206
|
-
const afterPresent = collectionRead.has(key);
|
|
1207
|
-
const afterValue = afterPresent ? collectionRead.get(key) : void 0;
|
|
1208
|
-
if (!beforePresent && afterPresent) {
|
|
1209
|
-
added.push({
|
|
1210
|
-
key,
|
|
1211
|
-
after: afterValue
|
|
1212
|
-
});
|
|
1213
|
-
next.set(key, afterValue);
|
|
1214
|
-
} else if (beforePresent && !afterPresent) {
|
|
1215
|
-
removed.push({
|
|
1216
|
-
key,
|
|
1217
|
-
before: baseline.get(key)
|
|
1218
|
-
});
|
|
1219
|
-
next.delete(key);
|
|
1220
|
-
} else if (beforePresent && afterPresent) {
|
|
1221
|
-
const beforeValue = baseline.get(key);
|
|
1222
|
-
if (!sameEntry(beforeValue, afterValue)) updated.push({
|
|
1223
|
-
key,
|
|
1224
|
-
before: beforeValue,
|
|
1225
|
-
after: afterValue
|
|
1226
|
-
});
|
|
1227
|
-
next.set(key, afterValue);
|
|
1228
|
-
}
|
|
1229
|
-
}
|
|
1230
|
-
const ids = record.reset() || orderChanged ? Object.freeze([...collectionRead.ids()]) : baselineIds;
|
|
1231
|
-
if (record.reset()) {
|
|
1232
|
-
next.clear();
|
|
1233
|
-
for (const key of ids) {
|
|
1234
|
-
const value = collectionRead.get(key);
|
|
1235
|
-
next.set(key, value);
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
let order;
|
|
1239
|
-
if (orderChanged) {
|
|
1240
|
-
const beforeKeys = new Set(baselineIds);
|
|
1241
|
-
const afterKeys = new Set(ids);
|
|
1242
|
-
const beforeCommon = baselineIds.filter((key) => afterKeys.has(key));
|
|
1243
|
-
const afterCommon = ids.filter((key) => beforeKeys.has(key));
|
|
1244
|
-
if (beforeCommon.some((key, index) => afterCommon[index] !== key)) order = {
|
|
1245
|
-
before: Object.freeze([...baselineIds]),
|
|
1246
|
-
after: ids
|
|
1247
|
-
};
|
|
1248
|
-
}
|
|
1249
|
-
const change = record.reset() ? Object.freeze({ kind: "reset" }) : added.length || updated.length || removed.length || order ? Object.freeze({
|
|
1250
|
-
kind: "incremental",
|
|
1251
|
-
added: Object.freeze(added),
|
|
1252
|
-
updated: Object.freeze(updated),
|
|
1253
|
-
removed: Object.freeze(removed),
|
|
1254
|
-
...order ? { order: Object.freeze(order) } : {}
|
|
1255
|
-
}) : void 0;
|
|
1256
|
-
nextBaseline = next;
|
|
1257
|
-
nextBaselineIds = ids;
|
|
1258
|
-
return Object.freeze({
|
|
1259
|
-
kind: "collection",
|
|
1260
|
-
read,
|
|
1261
|
-
change,
|
|
1262
|
-
revision: runtime.revision(),
|
|
1263
|
-
cause: batch?.cause
|
|
1264
|
-
});
|
|
1265
|
-
}
|
|
1266
|
-
};
|
|
1267
|
-
const handle = collection ? { kind: "collection" } : {
|
|
1268
|
-
collection: (pick) => {
|
|
1269
|
-
scheduler.assertIdle();
|
|
1270
|
-
return make({ collection: compilePath(state.schema, "collection", pick) });
|
|
1271
|
-
},
|
|
1272
|
-
targets: (...selected) => {
|
|
1273
|
-
scheduler.assertIdle();
|
|
1274
|
-
if (!selected.length) throw new TypeError("Expected at least one target.");
|
|
1275
|
-
return make({ targets: selected.map((pick) => compilePath(state.schema, "value", pick)) });
|
|
1276
|
-
}
|
|
1277
|
-
};
|
|
1278
|
-
Object.freeze(handle);
|
|
1279
|
-
scheduler.register(handle, record);
|
|
1280
|
-
const receive = (commit) => {
|
|
1281
|
-
reset ||= commit.impact.kind === "reset";
|
|
1282
|
-
if (collection) {
|
|
1283
|
-
const change = collectionImpact(commit.impact, collection);
|
|
1284
|
-
if (change.kind === "reset") reset = true;
|
|
1285
|
-
else {
|
|
1286
|
-
change.added.forEach((key) => keys.add(key));
|
|
1287
|
-
change.removed.forEach((key) => keys.add(key));
|
|
1288
|
-
change.updated.forEach((key) => keys.add(key));
|
|
1289
|
-
orderChanged ||= Boolean(change.added.size || change.removed.size || change.orderChanged);
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
};
|
|
1293
|
-
bindings.push({
|
|
1294
|
-
handle,
|
|
1295
|
-
targets,
|
|
1296
|
-
record,
|
|
1297
|
-
receive
|
|
1298
|
-
});
|
|
1299
|
-
return handle;
|
|
1300
|
-
};
|
|
1301
|
-
const handle = make({ targets: [] });
|
|
1302
|
-
const guard = (locked) => {
|
|
1303
|
-
state.projectionLocks = (state.projectionLocks ?? 0) + (locked ? 1 : -1);
|
|
1304
|
-
};
|
|
1305
|
-
scheduler.guards.add(guard);
|
|
1306
|
-
const unsubscribe = require_notification.attachProjection(runtime, {
|
|
1307
|
-
capture: (commit) => {
|
|
1308
|
-
for (const binding of bindings) if (!binding.targets.length || binding.targets.some((value) => affectsTarget(commit.impact, value))) {
|
|
1309
|
-
binding.receive(commit);
|
|
1310
|
-
batch = scheduler.batchContext();
|
|
1311
|
-
scheduler.capture(binding.record);
|
|
1312
|
-
}
|
|
1313
|
-
},
|
|
1314
|
-
settle: scheduler.settle,
|
|
1315
|
-
flush: scheduler.flush,
|
|
1316
|
-
dispose: () => {
|
|
1317
|
-
bindings.forEach(({ record }) => {
|
|
1318
|
-
record.fault = new require_advanced.ProjectionError("source", "document disposed", [runtime.revision()], /* @__PURE__ */ new Error("Document has been disposed."));
|
|
1319
|
-
scheduler.capture(record);
|
|
1320
|
-
});
|
|
1321
|
-
scheduler.run();
|
|
1322
|
-
}
|
|
1323
|
-
});
|
|
1324
|
-
scheduler.cleanups.add(() => {
|
|
1325
|
-
unsubscribe();
|
|
1326
|
-
scheduler.guards.delete(guard);
|
|
1327
|
-
});
|
|
1328
|
-
documents.set(state, handle);
|
|
1329
|
-
return handle;
|
|
1330
|
-
};
|
|
1331
|
-
const valueSource = (initial, equal) => {
|
|
1332
|
-
let value = initial;
|
|
1333
|
-
let revision = 0;
|
|
1334
|
-
let cause;
|
|
1335
|
-
let reset = false;
|
|
1336
|
-
const handle = Object.freeze({});
|
|
1337
|
-
const record = {
|
|
1338
|
-
consumers: /* @__PURE__ */ new Set(),
|
|
1339
|
-
disposed: false,
|
|
1340
|
-
fault: void 0,
|
|
1341
|
-
revision: () => revision,
|
|
1342
|
-
reset: () => reset,
|
|
1343
|
-
clear: () => {
|
|
1344
|
-
cause = void 0;
|
|
1345
|
-
reset = false;
|
|
1019
|
+
//#region core/src/projection/value-output.ts
|
|
1020
|
+
const unset = Symbol("projection-value-unset");
|
|
1021
|
+
/** Owns staged and published state for one scalar Projection output. */
|
|
1022
|
+
const createValueOutput = () => {
|
|
1023
|
+
let value;
|
|
1024
|
+
let staged = unset;
|
|
1025
|
+
let next;
|
|
1026
|
+
let initialized = false;
|
|
1027
|
+
let revision = 0;
|
|
1028
|
+
let changed = false;
|
|
1029
|
+
let reset = false;
|
|
1030
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1031
|
+
const begin = (active, initialize) => {
|
|
1032
|
+
staged = unset;
|
|
1033
|
+
next = value;
|
|
1034
|
+
changed = false;
|
|
1035
|
+
reset = initialize;
|
|
1036
|
+
return {
|
|
1037
|
+
previous: initialized ? value : void 0,
|
|
1038
|
+
next: () => {
|
|
1039
|
+
require_advanced.assertScope(active);
|
|
1040
|
+
if (staged !== unset) return staged;
|
|
1041
|
+
return initialize ? void 0 : initialized ? value : void 0;
|
|
1346
1042
|
},
|
|
1347
|
-
|
|
1043
|
+
output: Object.freeze({ set: (candidate) => {
|
|
1348
1044
|
require_advanced.assertScope(active);
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
value,
|
|
1352
|
-
revision,
|
|
1353
|
-
reset,
|
|
1354
|
-
cause
|
|
1355
|
-
});
|
|
1356
|
-
}
|
|
1357
|
-
};
|
|
1358
|
-
scheduler.register(handle, record);
|
|
1359
|
-
const accept = (next, metadata) => {
|
|
1360
|
-
scheduler.assertIdle();
|
|
1361
|
-
const recovering = record.fault !== void 0;
|
|
1362
|
-
const eventful = metadata !== void 0 && (metadata.reset === true || metadata.revision !== void 0 && metadata.revision !== revision || metadata.cause !== void 0);
|
|
1363
|
-
if (equal(value, next) && !recovering && !eventful) return;
|
|
1364
|
-
record.fault = void 0;
|
|
1365
|
-
value = next;
|
|
1366
|
-
revision = metadata?.revision ?? revision + 1;
|
|
1367
|
-
cause = metadata?.cause ?? scheduler.batchContext()?.cause ?? cause;
|
|
1368
|
-
reset ||= metadata?.reset ?? false;
|
|
1369
|
-
scheduler.capture(record);
|
|
1370
|
-
};
|
|
1371
|
-
return {
|
|
1372
|
-
source: handle,
|
|
1373
|
-
accept,
|
|
1374
|
-
set(next) {
|
|
1375
|
-
accept(next);
|
|
1376
|
-
scheduler.run();
|
|
1377
|
-
}
|
|
1045
|
+
staged = candidate;
|
|
1046
|
+
} })
|
|
1378
1047
|
};
|
|
1379
1048
|
};
|
|
1380
|
-
const
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
before: before.value
|
|
1400
|
-
});
|
|
1401
|
-
else if (before.present && afterPresent && !Object.is(before.value, values.get(key))) updated.push({
|
|
1402
|
-
key,
|
|
1403
|
-
before: before.value,
|
|
1404
|
-
after: values.get(key)
|
|
1405
|
-
});
|
|
1406
|
-
}
|
|
1407
|
-
let order;
|
|
1408
|
-
if (beforeIds) {
|
|
1409
|
-
const afterIds = [...values.keys()];
|
|
1410
|
-
const beforeKeys = new Set(beforeIds);
|
|
1411
|
-
const afterKeys = new Set(afterIds);
|
|
1412
|
-
const beforeCommon = beforeIds.filter((key) => afterKeys.has(key));
|
|
1413
|
-
const afterCommon = afterIds.filter((key) => beforeKeys.has(key));
|
|
1414
|
-
if (beforeCommon.some((key, index) => key !== afterCommon[index])) order = Object.freeze({
|
|
1415
|
-
before: beforeIds,
|
|
1416
|
-
after: Object.freeze(afterIds)
|
|
1417
|
-
});
|
|
1418
|
-
}
|
|
1419
|
-
if (!added.length && !updated.length && !removed.length && !order) return void 0;
|
|
1049
|
+
const seal = (nextReset, isEqual) => {
|
|
1050
|
+
if (reset && staged === unset) throw new TypeError("Value output must be initialized on reset.");
|
|
1051
|
+
if (staged === unset) {
|
|
1052
|
+
reset = nextReset;
|
|
1053
|
+
changed = false;
|
|
1054
|
+
next = value;
|
|
1055
|
+
return false;
|
|
1056
|
+
}
|
|
1057
|
+
const candidate = staged;
|
|
1058
|
+
changed = !initialized || !isEqual(value, candidate);
|
|
1059
|
+
next = changed ? candidate : value;
|
|
1060
|
+
reset = nextReset;
|
|
1061
|
+
return changed;
|
|
1062
|
+
};
|
|
1063
|
+
return {
|
|
1064
|
+
begin,
|
|
1065
|
+
seal,
|
|
1066
|
+
context: (active, cause) => {
|
|
1067
|
+
require_advanced.assertScope(active);
|
|
1420
1068
|
return Object.freeze({
|
|
1421
|
-
kind: "
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1069
|
+
kind: "value",
|
|
1070
|
+
value: next,
|
|
1071
|
+
revision,
|
|
1072
|
+
reset,
|
|
1073
|
+
cause
|
|
1426
1074
|
});
|
|
1427
|
-
}
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
revision,
|
|
1461
|
-
cause
|
|
1462
|
-
});
|
|
1463
|
-
}
|
|
1464
|
-
};
|
|
1465
|
-
scheduler.register(handle, record);
|
|
1466
|
-
return {
|
|
1467
|
-
source: handle,
|
|
1468
|
-
update(run) {
|
|
1469
|
-
scheduler.assertIdle();
|
|
1470
|
-
const staged = /* @__PURE__ */ new Map();
|
|
1471
|
-
let active = true;
|
|
1472
|
-
const draft = Object.freeze({
|
|
1473
|
-
get: (key) => {
|
|
1474
|
-
require_advanced.assertScope(() => active);
|
|
1475
|
-
const entry = staged.get(key);
|
|
1476
|
-
return entry ? entry.present ? entry.value : void 0 : values.get(key);
|
|
1477
|
-
},
|
|
1478
|
-
has: (key) => {
|
|
1479
|
-
require_advanced.assertScope(() => active);
|
|
1480
|
-
const entry = staged.get(key);
|
|
1481
|
-
return entry ? entry.present : values.has(key);
|
|
1482
|
-
},
|
|
1483
|
-
set: (key, value) => {
|
|
1484
|
-
require_advanced.assertScope(() => active);
|
|
1485
|
-
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
1486
|
-
staged.set(key, {
|
|
1487
|
-
present: true,
|
|
1488
|
-
value
|
|
1489
|
-
});
|
|
1490
|
-
},
|
|
1491
|
-
remove: (key) => {
|
|
1492
|
-
require_advanced.assertScope(() => active);
|
|
1493
|
-
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
1494
|
-
staged.set(key, { present: false });
|
|
1495
|
-
}
|
|
1496
|
-
});
|
|
1497
|
-
try {
|
|
1498
|
-
require_advanced.assertSynchronous(run(draft));
|
|
1499
|
-
} finally {
|
|
1500
|
-
active = false;
|
|
1501
|
-
}
|
|
1502
|
-
let changed = false;
|
|
1503
|
-
for (const [key, entry] of staged) {
|
|
1504
|
-
const present = values.has(key);
|
|
1505
|
-
if (entry.present ? present && Object.is(values.get(key), entry.value) : !present) continue;
|
|
1506
|
-
if (!touched.has(key)) touched.set(key, {
|
|
1507
|
-
present,
|
|
1508
|
-
value: values.get(key)
|
|
1509
|
-
});
|
|
1510
|
-
if (!beforeIds && present !== entry.present) beforeIds = Object.freeze([...values.keys()]);
|
|
1511
|
-
if (entry.present) values.set(key, entry.value);
|
|
1512
|
-
else values.delete(key);
|
|
1513
|
-
changed = true;
|
|
1514
|
-
}
|
|
1515
|
-
if (!changed) return;
|
|
1516
|
-
revision++;
|
|
1517
|
-
cause = scheduler.batchContext()?.cause ?? cause;
|
|
1518
|
-
scheduler.capture(record);
|
|
1519
|
-
scheduler.run();
|
|
1520
|
-
}
|
|
1521
|
-
};
|
|
1075
|
+
},
|
|
1076
|
+
current: (check) => {
|
|
1077
|
+
check();
|
|
1078
|
+
return value;
|
|
1079
|
+
},
|
|
1080
|
+
revision: () => revision,
|
|
1081
|
+
reset: () => reset,
|
|
1082
|
+
publish: () => {
|
|
1083
|
+
if (changed && initialized) revision++;
|
|
1084
|
+
if (changed) value = next;
|
|
1085
|
+
initialized = true;
|
|
1086
|
+
},
|
|
1087
|
+
emit: (call) => {
|
|
1088
|
+
require_issue.profile.materialized.notification();
|
|
1089
|
+
Array.from(listeners).forEach((listener) => call(listener));
|
|
1090
|
+
},
|
|
1091
|
+
clear: () => {
|
|
1092
|
+
staged = unset;
|
|
1093
|
+
next = value;
|
|
1094
|
+
changed = false;
|
|
1095
|
+
reset = false;
|
|
1096
|
+
},
|
|
1097
|
+
release: () => {
|
|
1098
|
+
listeners.clear();
|
|
1099
|
+
staged = unset;
|
|
1100
|
+
value = next = void 0;
|
|
1101
|
+
initialized = false;
|
|
1102
|
+
revision = 0;
|
|
1103
|
+
changed = false;
|
|
1104
|
+
reset = false;
|
|
1105
|
+
},
|
|
1106
|
+
subscribe: (listener) => listeners.add(listener),
|
|
1107
|
+
unsubscribe: (listener) => listeners.delete(listener)
|
|
1522
1108
|
};
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
unsubscribe = port.subscribe((event) => {
|
|
1536
|
-
try {
|
|
1537
|
-
input.accept(event.value, {
|
|
1538
|
-
revision: event.revision,
|
|
1539
|
-
reset: event.reset ?? false,
|
|
1540
|
-
cause: event.cause
|
|
1541
|
-
});
|
|
1542
|
-
} catch (cause) {
|
|
1543
|
-
fail(cause);
|
|
1544
|
-
}
|
|
1545
|
-
scheduler.run();
|
|
1546
|
-
});
|
|
1547
|
-
} catch (cause) {
|
|
1548
|
-
unsubscribe?.();
|
|
1549
|
-
scheduler.unregisterSource(input.source);
|
|
1550
|
-
throw cause;
|
|
1551
|
-
}
|
|
1552
|
-
scheduler.cleanups.add(() => unsubscribe?.());
|
|
1553
|
-
externalSources.set(port, input.source);
|
|
1554
|
-
return input.source;
|
|
1109
|
+
};
|
|
1110
|
+
//#endregion
|
|
1111
|
+
//#region core/src/projection/processor.ts
|
|
1112
|
+
/** Materializes every derive/incremental/group definition through one processor lifecycle. */
|
|
1113
|
+
const createProcessor = (scheduler, definition, dependencies) => {
|
|
1114
|
+
scheduler.assertIdle();
|
|
1115
|
+
let processor;
|
|
1116
|
+
let instance;
|
|
1117
|
+
let cause;
|
|
1118
|
+
const check = () => {
|
|
1119
|
+
if (!scheduler.active || processor.disposed) throw new require_advanced.ProjectionDisposedError();
|
|
1120
|
+
if (processor.fault) throw processor.fault;
|
|
1555
1121
|
};
|
|
1556
|
-
const
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
let transitionKeys = /* @__PURE__ */ new Set();
|
|
1568
|
-
let pending = false;
|
|
1569
|
-
const handle = Object.freeze({ kind: "collection" });
|
|
1570
|
-
const record = {
|
|
1571
|
-
consumers: /* @__PURE__ */ new Set(),
|
|
1572
|
-
disposed: false,
|
|
1573
|
-
fault: void 0,
|
|
1574
|
-
revision: () => revision,
|
|
1575
|
-
reset: () => reset,
|
|
1576
|
-
clear: () => {
|
|
1577
|
-
previous = read;
|
|
1578
|
-
pending = false;
|
|
1579
|
-
change = void 0;
|
|
1580
|
-
reset = false;
|
|
1581
|
-
orderChanged = false;
|
|
1582
|
-
cause = void 0;
|
|
1583
|
-
transitionKeys.clear();
|
|
1584
|
-
},
|
|
1585
|
-
context: (active) => {
|
|
1586
|
-
require_advanced.assertScope(active);
|
|
1587
|
-
const currentRead = Object.freeze({
|
|
1588
|
-
get: (key) => {
|
|
1589
|
-
require_advanced.assertScope(active);
|
|
1590
|
-
return read.get(key);
|
|
1122
|
+
const bound = definition.outputs.map((outputDefinition) => {
|
|
1123
|
+
if (outputDefinition.kind === "value") {
|
|
1124
|
+
const state = createValueOutput();
|
|
1125
|
+
return {
|
|
1126
|
+
kind: "value",
|
|
1127
|
+
definition: outputDefinition,
|
|
1128
|
+
state,
|
|
1129
|
+
output: {
|
|
1130
|
+
kind: "value",
|
|
1131
|
+
get owner() {
|
|
1132
|
+
return processor;
|
|
1591
1133
|
},
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1134
|
+
consumers: /* @__PURE__ */ new Set(),
|
|
1135
|
+
context: (active) => state.context(active, cause),
|
|
1136
|
+
current: () => state.current(check),
|
|
1137
|
+
revision: state.revision,
|
|
1138
|
+
reset: state.reset,
|
|
1139
|
+
subscribe: (listener) => {
|
|
1140
|
+
check();
|
|
1141
|
+
const wrapped = () => listener();
|
|
1142
|
+
state.subscribe(wrapped);
|
|
1143
|
+
return () => state.unsubscribe(wrapped);
|
|
1595
1144
|
},
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1145
|
+
emit: state.emit,
|
|
1146
|
+
clear: state.clear,
|
|
1147
|
+
release: state.release
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
const state = require_advanced.createCollectionOutput();
|
|
1152
|
+
return {
|
|
1153
|
+
kind: "collection",
|
|
1154
|
+
definition: outputDefinition,
|
|
1155
|
+
state,
|
|
1156
|
+
output: {
|
|
1157
|
+
kind: "collection",
|
|
1158
|
+
get owner() {
|
|
1159
|
+
return processor;
|
|
1160
|
+
},
|
|
1161
|
+
consumers: /* @__PURE__ */ new Set(),
|
|
1162
|
+
context: (active) => state.context(active, cause),
|
|
1163
|
+
current: () => state.current(check),
|
|
1164
|
+
revision: state.revision,
|
|
1165
|
+
reset: state.reset,
|
|
1166
|
+
subscribe: (listener) => {
|
|
1167
|
+
check();
|
|
1168
|
+
const wrapped = (change) => listener(change);
|
|
1169
|
+
state.subscribe(wrapped);
|
|
1170
|
+
return () => state.unsubscribe(wrapped);
|
|
1171
|
+
},
|
|
1172
|
+
emit: state.emit,
|
|
1173
|
+
clear: state.clear,
|
|
1174
|
+
release: state.release
|
|
1608
1175
|
}
|
|
1609
1176
|
};
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
};
|
|
1615
|
-
const deriveChange = () => {
|
|
1616
|
-
if (reset) return Object.freeze({ kind: "reset" });
|
|
1617
|
-
const added = [];
|
|
1618
|
-
const updated = [];
|
|
1619
|
-
const removed = [];
|
|
1620
|
-
for (const key of transitionKeys) {
|
|
1621
|
-
const beforePresent = previous.has(key);
|
|
1622
|
-
const afterPresent = read.has(key);
|
|
1623
|
-
const before = beforePresent ? previous.get(key) : void 0;
|
|
1624
|
-
const after = afterPresent ? read.get(key) : void 0;
|
|
1625
|
-
if (beforePresent === afterPresent && Object.is(before, after)) continue;
|
|
1626
|
-
if (!beforePresent && afterPresent) added.push({
|
|
1627
|
-
key,
|
|
1628
|
-
after
|
|
1629
|
-
});
|
|
1630
|
-
else if (beforePresent && !afterPresent) removed.push({
|
|
1631
|
-
key,
|
|
1632
|
-
before
|
|
1633
|
-
});
|
|
1634
|
-
else if (beforePresent && afterPresent) updated.push({
|
|
1635
|
-
key,
|
|
1636
|
-
before,
|
|
1637
|
-
after
|
|
1638
|
-
});
|
|
1639
|
-
}
|
|
1640
|
-
let order;
|
|
1641
|
-
if (orderChanged) {
|
|
1642
|
-
const beforeIds = previous.ids();
|
|
1643
|
-
const afterIds = read.ids();
|
|
1644
|
-
const beforeKeys = new Set(beforeIds);
|
|
1645
|
-
const afterKeys = new Set(afterIds);
|
|
1646
|
-
const beforeCommon = beforeIds.filter((key) => afterKeys.has(key));
|
|
1647
|
-
const afterCommon = afterIds.filter((key) => beforeKeys.has(key));
|
|
1648
|
-
if (beforeCommon.some((key, index) => afterCommon[index] !== key)) order = Object.freeze({
|
|
1649
|
-
before: Object.freeze([...beforeIds]),
|
|
1650
|
-
after: Object.freeze([...afterIds])
|
|
1651
|
-
});
|
|
1652
|
-
}
|
|
1653
|
-
if (!added.length && !removed.length && !updated.length && !order) return void 0;
|
|
1177
|
+
});
|
|
1178
|
+
const begin = (active, initialize) => Object.freeze(bound.map((entry) => {
|
|
1179
|
+
if (entry.kind === "value") {
|
|
1180
|
+
const evaluation = entry.state.begin(active, initialize);
|
|
1654
1181
|
return Object.freeze({
|
|
1655
|
-
kind: "
|
|
1656
|
-
|
|
1657
|
-
updated: Object.freeze(updated),
|
|
1658
|
-
removed: Object.freeze(removed),
|
|
1659
|
-
...order ? { order } : {}
|
|
1660
|
-
});
|
|
1661
|
-
};
|
|
1662
|
-
let unsubscribe;
|
|
1663
|
-
try {
|
|
1664
|
-
unsubscribe = port.subscribe((event) => {
|
|
1665
|
-
try {
|
|
1666
|
-
scheduler.assertIdle();
|
|
1667
|
-
if (!pending) previous = event.previous;
|
|
1668
|
-
read = port.current();
|
|
1669
|
-
revision = event.revision;
|
|
1670
|
-
if (event.impact?.kind === "incremental") {
|
|
1671
|
-
event.impact.added.forEach((key) => transitionKeys.add(key));
|
|
1672
|
-
event.impact.removed.forEach((key) => transitionKeys.add(key));
|
|
1673
|
-
event.impact.updated.forEach((key) => transitionKeys.add(key));
|
|
1674
|
-
orderChanged ||= Boolean(event.impact.added.size || event.impact.removed.size || event.impact.orderChanged);
|
|
1675
|
-
} else if (!event.impact) {
|
|
1676
|
-
previous.ids().forEach((key) => transitionKeys.add(key));
|
|
1677
|
-
read.ids().forEach((key) => transitionKeys.add(key));
|
|
1678
|
-
orderChanged = true;
|
|
1679
|
-
}
|
|
1680
|
-
reset ||= event.impact?.kind === "reset";
|
|
1681
|
-
cause = event.cause ?? scheduler.batchContext()?.cause ?? cause;
|
|
1682
|
-
change = deriveChange();
|
|
1683
|
-
record.fault = void 0;
|
|
1684
|
-
scheduler.capture(record);
|
|
1685
|
-
pending = true;
|
|
1686
|
-
} catch (error) {
|
|
1687
|
-
fail(error);
|
|
1688
|
-
}
|
|
1689
|
-
scheduler.run();
|
|
1182
|
+
kind: "value",
|
|
1183
|
+
...evaluation
|
|
1690
1184
|
});
|
|
1691
|
-
} catch (error) {
|
|
1692
|
-
unsubscribe?.();
|
|
1693
|
-
scheduler.unregisterSource(handle);
|
|
1694
|
-
throw error;
|
|
1695
1185
|
}
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1186
|
+
const evaluation = entry.state.begin(active, initialize);
|
|
1187
|
+
return Object.freeze({
|
|
1188
|
+
kind: "collection",
|
|
1189
|
+
...evaluation
|
|
1190
|
+
});
|
|
1191
|
+
}));
|
|
1192
|
+
const seal = (reset) => {
|
|
1193
|
+
const changed = [];
|
|
1194
|
+
for (const entry of bound) if (entry.state.seal(reset, entry.definition.equality)) changed.push(entry.output);
|
|
1195
|
+
return Object.freeze(changed);
|
|
1699
1196
|
};
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1197
|
+
const run = (reset, runCause) => {
|
|
1198
|
+
cause = runCause;
|
|
1199
|
+
let active = true;
|
|
1200
|
+
try {
|
|
1201
|
+
const scopeActive = () => active;
|
|
1202
|
+
const sources = Object.freeze(dependencies.map((output) => output.context(scopeActive)));
|
|
1203
|
+
let outputs = begin(scopeActive, reset);
|
|
1204
|
+
if (!instance) instance = definition.create();
|
|
1205
|
+
require_issue.profile.materialized[reset ? "rebuilt" : "updated"]();
|
|
1206
|
+
let result = instance.evaluate({
|
|
1207
|
+
reset,
|
|
1208
|
+
cause: runCause,
|
|
1209
|
+
sources,
|
|
1210
|
+
outputs
|
|
1713
1211
|
});
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
bindings.set(equal, {
|
|
1726
|
-
source: input.source,
|
|
1727
|
-
accept: (value) => input.accept(value)
|
|
1212
|
+
require_advanced.assertSynchronous(result);
|
|
1213
|
+
if (result?.kind === "rebuild") {
|
|
1214
|
+
if (reset) throw new TypeError("Initial or reset projection processor cannot rebuild.");
|
|
1215
|
+
instance.release?.();
|
|
1216
|
+
instance = definition.create();
|
|
1217
|
+
outputs = begin(scopeActive, true);
|
|
1218
|
+
result = instance.evaluate({
|
|
1219
|
+
reset: true,
|
|
1220
|
+
cause: runCause,
|
|
1221
|
+
sources,
|
|
1222
|
+
outputs
|
|
1728
1223
|
});
|
|
1729
|
-
|
|
1224
|
+
require_advanced.assertSynchronous(result);
|
|
1225
|
+
if (result?.kind === "rebuild") throw new TypeError("Reset projection processor cannot rebuild again.");
|
|
1226
|
+
return seal(true);
|
|
1730
1227
|
}
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
}]]);
|
|
1735
|
-
const members = bindings;
|
|
1736
|
-
const receive = (settle = true) => {
|
|
1737
|
-
if (!scheduler.active) return;
|
|
1738
|
-
let value;
|
|
1739
|
-
try {
|
|
1740
|
-
value = readable.current();
|
|
1741
|
-
} catch (cause) {
|
|
1742
|
-
for (const member of members.values()) {
|
|
1743
|
-
const record = scheduler.source(member.source);
|
|
1744
|
-
record.fault = new require_advanced.ProjectionError("source", "external readable", [record.revision()], cause);
|
|
1745
|
-
scheduler.capture(record);
|
|
1746
|
-
}
|
|
1747
|
-
if (settle) scheduler.run();
|
|
1748
|
-
return;
|
|
1749
|
-
}
|
|
1750
|
-
for (const member of members.values()) try {
|
|
1751
|
-
member.accept(value);
|
|
1752
|
-
} catch (cause) {
|
|
1753
|
-
const record = scheduler.source(member.source);
|
|
1754
|
-
record.fault = new require_advanced.ProjectionError("source", "external readable", [record.revision()], cause);
|
|
1755
|
-
scheduler.capture(record);
|
|
1756
|
-
}
|
|
1757
|
-
if (settle) scheduler.run();
|
|
1758
|
-
};
|
|
1759
|
-
let unsubscribe;
|
|
1760
|
-
let detach;
|
|
1761
|
-
try {
|
|
1762
|
-
const owner = require_notification.documentReadableOwner(readable);
|
|
1763
|
-
if (owner) {
|
|
1764
|
-
document(owner);
|
|
1765
|
-
detach = require_notification.attachProjection(owner, {
|
|
1766
|
-
capture: () => receive(false),
|
|
1767
|
-
settle: scheduler.settle,
|
|
1768
|
-
flush: scheduler.flush,
|
|
1769
|
-
dispose: () => {
|
|
1770
|
-
for (const member of members.values()) {
|
|
1771
|
-
const record = scheduler.source(member.source);
|
|
1772
|
-
record.fault = new require_advanced.ProjectionError("source", "document readable disposed", [record.revision()], /* @__PURE__ */ new Error("Document has been disposed."));
|
|
1773
|
-
scheduler.capture(record);
|
|
1774
|
-
}
|
|
1775
|
-
scheduler.run();
|
|
1776
|
-
}
|
|
1777
|
-
});
|
|
1778
|
-
}
|
|
1779
|
-
unsubscribe = readable.subscribe(() => receive());
|
|
1780
|
-
input.accept(readable.current());
|
|
1781
|
-
} catch (error) {
|
|
1782
|
-
try {
|
|
1783
|
-
unsubscribe?.();
|
|
1784
|
-
detach?.();
|
|
1785
|
-
} finally {
|
|
1786
|
-
scheduler.unregisterSource(input.source);
|
|
1787
|
-
}
|
|
1788
|
-
throw error;
|
|
1789
|
-
}
|
|
1790
|
-
scheduler.cleanups.add(unsubscribe);
|
|
1791
|
-
if (detach) scheduler.cleanups.add(detach);
|
|
1792
|
-
readables.set(readable, bindings);
|
|
1793
|
-
scheduler.run();
|
|
1794
|
-
return input.source;
|
|
1795
|
-
},
|
|
1796
|
-
assertCollection: (handle) => {
|
|
1797
|
-
scheduler.source(handle);
|
|
1798
|
-
if (!isCollectionSource(handle)) throw new Error("map requires a collection source.");
|
|
1228
|
+
return seal(reset);
|
|
1229
|
+
} finally {
|
|
1230
|
+
active = false;
|
|
1799
1231
|
}
|
|
1800
1232
|
};
|
|
1801
|
-
};
|
|
1802
|
-
//#endregion
|
|
1803
|
-
//#region core/src/projection/node.ts
|
|
1804
|
-
const createNode = (scheduler, spec, behavior) => {
|
|
1805
|
-
scheduler.assertIdle();
|
|
1806
|
-
const entries = Object.entries(spec.sources).map(([key, handle]) => [key, scheduler.source(handle)]);
|
|
1807
1233
|
const order = scheduler.order();
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
...behavior,
|
|
1811
|
-
publish: () => {
|
|
1812
|
-
if (node.fault) behavior.clear();
|
|
1813
|
-
else behavior.publish();
|
|
1814
|
-
},
|
|
1234
|
+
processor = {
|
|
1235
|
+
kind: "processor",
|
|
1815
1236
|
order,
|
|
1816
|
-
name:
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
disposed: false,
|
|
1237
|
+
name: definition.name ? `${definition.name} (${order})` : `projection-${order}`,
|
|
1238
|
+
dependencies: Object.freeze([...dependencies]),
|
|
1239
|
+
outputs: Object.freeze(bound.map((entry) => entry.output)),
|
|
1820
1240
|
fault: void 0,
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
node.evaluate(true);
|
|
1837
|
-
node.publish();
|
|
1838
|
-
node.clear();
|
|
1839
|
-
});
|
|
1840
|
-
const check = () => {
|
|
1841
|
-
if (node.disposed || !scheduler.active) throw new require_advanced.ProjectionDisposedError();
|
|
1842
|
-
if (node.fault) throw node.fault;
|
|
1843
|
-
};
|
|
1844
|
-
return {
|
|
1845
|
-
node,
|
|
1846
|
-
check,
|
|
1847
|
-
install(handle) {
|
|
1848
|
-
scheduler.register(handle, node);
|
|
1849
|
-
scheduler.addNode(node);
|
|
1241
|
+
disposed: false,
|
|
1242
|
+
evaluate: run,
|
|
1243
|
+
publish: () => bound.forEach((entry) => entry.state.publish()),
|
|
1244
|
+
clear: () => {
|
|
1245
|
+
bound.forEach((entry) => entry.state.clear());
|
|
1246
|
+
cause = void 0;
|
|
1247
|
+
},
|
|
1248
|
+
release: () => {
|
|
1249
|
+
instance?.release?.();
|
|
1250
|
+
instance = void 0;
|
|
1251
|
+
bound.forEach((entry) => {
|
|
1252
|
+
entry.output.consumers.clear();
|
|
1253
|
+
entry.state.release();
|
|
1254
|
+
});
|
|
1255
|
+
cause = void 0;
|
|
1850
1256
|
}
|
|
1851
1257
|
};
|
|
1258
|
+
try {
|
|
1259
|
+
scheduler.initialize(() => {
|
|
1260
|
+
const invalid = dependencies.find((output) => output.owner.fault || output.owner.disposed);
|
|
1261
|
+
if (invalid) throw invalid.owner.fault ?? new require_advanced.ProjectionDisposedError();
|
|
1262
|
+
if (processor.evaluate(true, void 0).length) processor.publish();
|
|
1263
|
+
processor.clear();
|
|
1264
|
+
});
|
|
1265
|
+
} catch (error) {
|
|
1266
|
+
processor.release();
|
|
1267
|
+
throw error;
|
|
1268
|
+
}
|
|
1269
|
+
scheduler.addProcessor(processor);
|
|
1270
|
+
return processor;
|
|
1852
1271
|
};
|
|
1853
1272
|
//#endregion
|
|
1854
|
-
//#region core/src/projection/
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
instance = void 0;
|
|
1872
|
-
const built = spec.build(sources);
|
|
1873
|
-
require_advanced.assertSynchronous(built);
|
|
1874
|
-
instance = built;
|
|
1875
|
-
candidate = built.value;
|
|
1876
|
-
} else {
|
|
1877
|
-
require_issue.profile.materialized.updated();
|
|
1878
|
-
const result = instance.update(sources);
|
|
1879
|
-
require_advanced.assertSynchronous(result);
|
|
1880
|
-
if (result.kind === "rebuild") {
|
|
1881
|
-
instance = void 0;
|
|
1882
|
-
const built = spec.build(sources);
|
|
1883
|
-
require_advanced.assertSynchronous(built);
|
|
1884
|
-
instance = built;
|
|
1885
|
-
candidate = built.value;
|
|
1886
|
-
build = true;
|
|
1887
|
-
} else candidate = result.kind === "changed" ? result.value : value;
|
|
1888
|
-
}
|
|
1889
|
-
changed = !initialized || !(options?.isEqual ?? Object.is)(value, candidate);
|
|
1890
|
-
next = changed ? candidate : value;
|
|
1891
|
-
reset = build;
|
|
1892
|
-
return changed;
|
|
1273
|
+
//#region core/src/projection/projection-readable.ts
|
|
1274
|
+
let activeTracker;
|
|
1275
|
+
const trackKey = (key) => {
|
|
1276
|
+
activeTracker?.keys.add(key);
|
|
1277
|
+
};
|
|
1278
|
+
const trackStructure = () => {
|
|
1279
|
+
if (activeTracker) activeTracker.structure = true;
|
|
1280
|
+
};
|
|
1281
|
+
const trackAll = () => {
|
|
1282
|
+
if (activeTracker) activeTracker.all = true;
|
|
1283
|
+
};
|
|
1284
|
+
const isMapLike = (value) => value instanceof Map || value !== null && typeof value === "object" && typeof value.get === "function" && typeof value.keys === "function" && typeof value.entries === "function";
|
|
1285
|
+
const trackedMap = (source) => {
|
|
1286
|
+
const view = {
|
|
1287
|
+
get: (key) => {
|
|
1288
|
+
trackKey(key);
|
|
1289
|
+
return source.get(key);
|
|
1893
1290
|
},
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
return
|
|
1897
|
-
kind: "value",
|
|
1898
|
-
value: next,
|
|
1899
|
-
revision: revision + (changed ? 1 : 0),
|
|
1900
|
-
reset,
|
|
1901
|
-
cause
|
|
1902
|
-
});
|
|
1291
|
+
has: (key) => {
|
|
1292
|
+
trackKey(key);
|
|
1293
|
+
return source.has(key);
|
|
1903
1294
|
},
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
if (changed && initialized) revision++;
|
|
1908
|
-
value = next;
|
|
1909
|
-
initialized = true;
|
|
1295
|
+
get size() {
|
|
1296
|
+
trackStructure();
|
|
1297
|
+
return source.size;
|
|
1910
1298
|
},
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1299
|
+
keys: () => {
|
|
1300
|
+
trackStructure();
|
|
1301
|
+
return source.keys();
|
|
1914
1302
|
},
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
reset = false;
|
|
1919
|
-
cause = void 0;
|
|
1303
|
+
values: () => {
|
|
1304
|
+
trackAll();
|
|
1305
|
+
return source.values();
|
|
1920
1306
|
},
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
value = next = void 0;
|
|
1925
|
-
}
|
|
1926
|
-
});
|
|
1927
|
-
const handle = Object.freeze({
|
|
1928
|
-
kind: "value",
|
|
1929
|
-
current: () => {
|
|
1930
|
-
owner.check();
|
|
1931
|
-
return value;
|
|
1307
|
+
entries: () => {
|
|
1308
|
+
trackAll();
|
|
1309
|
+
return source.entries();
|
|
1932
1310
|
},
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1311
|
+
forEach: (callback, thisArg) => {
|
|
1312
|
+
trackAll();
|
|
1313
|
+
source.forEach((value, key) => callback.call(thisArg, value, key, view));
|
|
1936
1314
|
},
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
return () => {
|
|
1941
|
-
listeners.delete(listener);
|
|
1942
|
-
};
|
|
1315
|
+
[Symbol.iterator]: () => {
|
|
1316
|
+
trackAll();
|
|
1317
|
+
return source[Symbol.iterator]();
|
|
1943
1318
|
}
|
|
1944
|
-
}
|
|
1945
|
-
|
|
1946
|
-
return handle;
|
|
1947
|
-
};
|
|
1948
|
-
//#endregion
|
|
1949
|
-
//#region core/src/projection/collection-state.ts
|
|
1950
|
-
const height = (node) => node?.height ?? 0;
|
|
1951
|
-
const makeTreeNode = (key, value, left, right) => Object.freeze({
|
|
1952
|
-
key,
|
|
1953
|
-
value,
|
|
1954
|
-
left,
|
|
1955
|
-
right,
|
|
1956
|
-
height: Math.max(height(left), height(right)) + 1
|
|
1957
|
-
});
|
|
1958
|
-
const rotateLeft = (node) => {
|
|
1959
|
-
const right = node.right;
|
|
1960
|
-
return makeTreeNode(right.key, right.value, makeTreeNode(node.key, node.value, node.left, right.left), right.right);
|
|
1961
|
-
};
|
|
1962
|
-
const rotateRight = (node) => {
|
|
1963
|
-
const left = node.left;
|
|
1964
|
-
return makeTreeNode(left.key, left.value, left.left, makeTreeNode(node.key, node.value, left.right, node.right));
|
|
1965
|
-
};
|
|
1966
|
-
const rebalance = (node) => {
|
|
1967
|
-
const balance = height(node.left) - height(node.right);
|
|
1968
|
-
if (balance > 1) {
|
|
1969
|
-
if (height(node.left.left) < height(node.left.right)) return rotateRight(makeTreeNode(node.key, node.value, rotateLeft(node.left), node.right));
|
|
1970
|
-
return rotateRight(node);
|
|
1971
|
-
}
|
|
1972
|
-
if (balance < -1) {
|
|
1973
|
-
if (height(node.right.right) < height(node.right.left)) return rotateLeft(makeTreeNode(node.key, node.value, node.left, rotateRight(node.right)));
|
|
1974
|
-
return rotateLeft(node);
|
|
1975
|
-
}
|
|
1976
|
-
return node;
|
|
1977
|
-
};
|
|
1978
|
-
const treeSet = (node, key, value) => {
|
|
1979
|
-
if (!node) return makeTreeNode(key, value);
|
|
1980
|
-
if (key === node.key) return makeTreeNode(key, value, node.left, node.right);
|
|
1981
|
-
if (key < node.key) return rebalance(makeTreeNode(node.key, node.value, treeSet(node.left, key, value), node.right));
|
|
1982
|
-
return rebalance(makeTreeNode(node.key, node.value, node.left, treeSet(node.right, key, value)));
|
|
1983
|
-
};
|
|
1984
|
-
const treeMin = (node) => node.left ? treeMin(node.left) : node;
|
|
1985
|
-
const treeRemove = (node, key) => {
|
|
1986
|
-
if (!node) return void 0;
|
|
1987
|
-
if (key < node.key) return rebalance(makeTreeNode(node.key, node.value, treeRemove(node.left, key), node.right));
|
|
1988
|
-
if (key > node.key) return rebalance(makeTreeNode(node.key, node.value, node.left, treeRemove(node.right, key)));
|
|
1989
|
-
if (!node.left) return node.right;
|
|
1990
|
-
if (!node.right) return node.left;
|
|
1991
|
-
const next = treeMin(node.right);
|
|
1992
|
-
return rebalance(makeTreeNode(next.key, next.value, node.left, treeRemove(node.right, next.key)));
|
|
1993
|
-
};
|
|
1994
|
-
const treeGet = (node, key) => {
|
|
1995
|
-
let current = node;
|
|
1996
|
-
while (current) {
|
|
1997
|
-
if (key === current.key) return current.value;
|
|
1998
|
-
current = key < current.key ? current.left : current.right;
|
|
1999
|
-
}
|
|
1319
|
+
};
|
|
1320
|
+
return Object.freeze(view);
|
|
2000
1321
|
};
|
|
2001
|
-
const
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
}
|
|
1322
|
+
const selectionAffects = (selection, change) => {
|
|
1323
|
+
if (!change || change.kind === "reset") return true;
|
|
1324
|
+
if (selection.all && (change.added.length || change.removed.length || change.updated.length || change.order)) return true;
|
|
1325
|
+
if (selection.structure && (change.added.length || change.removed.length || change.order)) return true;
|
|
1326
|
+
for (const key of selection.keys) if (change.added.some((entry) => entry.key === key) || change.removed.some((entry) => entry.key === key) || change.updated.some((entry) => entry.key === key)) return true;
|
|
2007
1327
|
return false;
|
|
2008
1328
|
};
|
|
2009
|
-
const
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
* The one keyed publication kernel used by ordinary collection nodes and
|
|
2017
|
-
* processor-group output leaves. It owns staged intent, exact transitions and
|
|
2018
|
-
* the persistent published snapshot; callers only provide the processor
|
|
2019
|
-
* callback and the equality policy.
|
|
2020
|
-
*/
|
|
2021
|
-
const createCollectionState = () => {
|
|
2022
|
-
const values = /* @__PURE__ */ new Map();
|
|
2023
|
-
let ids = Object.freeze([]);
|
|
2024
|
-
let staged = /* @__PURE__ */ new Map();
|
|
2025
|
-
let nextIds = ids;
|
|
2026
|
-
let change;
|
|
1329
|
+
const createDirectReadable = (source) => Object.freeze({
|
|
1330
|
+
current: source.current,
|
|
1331
|
+
revision: source.revision,
|
|
1332
|
+
subscribe: (listener) => source.subscribe(() => listener())
|
|
1333
|
+
});
|
|
1334
|
+
/** Consumer-side selector tracking; it never mutates processor dependencies. */
|
|
1335
|
+
const createSelectorReadable = (source, selector, equality = Object.is) => {
|
|
2027
1336
|
let initialized = false;
|
|
2028
|
-
let
|
|
2029
|
-
let
|
|
2030
|
-
let
|
|
2031
|
-
let
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
1337
|
+
let value;
|
|
1338
|
+
let selectedRevision = 0;
|
|
1339
|
+
let sourceRevision = -1;
|
|
1340
|
+
let selection = Object.freeze({
|
|
1341
|
+
keys: /* @__PURE__ */ new Set(),
|
|
1342
|
+
all: true,
|
|
1343
|
+
structure: false
|
|
1344
|
+
});
|
|
1345
|
+
let previousCollection;
|
|
1346
|
+
let unsubscribeSource;
|
|
2035
1347
|
const listeners = /* @__PURE__ */ new Set();
|
|
2036
|
-
const
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
return entry ? entry.present ? entry.value : void 0 : cleared ? void 0 : values.get(key);
|
|
2040
|
-
};
|
|
2041
|
-
const deriveIds = () => {
|
|
2042
|
-
const result = cleared ? [] : ids.filter(hasNext);
|
|
2043
|
-
for (const [key, entry] of staged) if (entry.present && (cleared || !values.has(key))) result.push(key);
|
|
2044
|
-
return result;
|
|
1348
|
+
const updateCollectionSnapshot = (current) => {
|
|
1349
|
+
const candidate = current ?? source.current();
|
|
1350
|
+
previousCollection = isMapLike(candidate) ? candidate : void 0;
|
|
2045
1351
|
};
|
|
2046
|
-
const
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
explicitOrder = void 0;
|
|
2052
|
-
orderChanged = false;
|
|
2053
|
-
cleared = nextReset;
|
|
2054
|
-
const read = (next) => ({
|
|
2055
|
-
get: (key) => {
|
|
2056
|
-
require_advanced.assertScope(active);
|
|
2057
|
-
return next ? getNext(key) : values.get(key);
|
|
2058
|
-
},
|
|
2059
|
-
has: (key) => {
|
|
2060
|
-
require_advanced.assertScope(active);
|
|
2061
|
-
return next ? hasNext(key) : values.has(key);
|
|
2062
|
-
},
|
|
2063
|
-
ids: () => {
|
|
2064
|
-
require_advanced.assertScope(active);
|
|
2065
|
-
return next ? Object.freeze(explicitOrder ? [...explicitOrder] : [...deriveIds()]) : ids;
|
|
2066
|
-
}
|
|
2067
|
-
});
|
|
2068
|
-
return {
|
|
2069
|
-
previous: read(false),
|
|
2070
|
-
next: read(true),
|
|
2071
|
-
output: {
|
|
2072
|
-
set: (key, value) => {
|
|
2073
|
-
require_advanced.assertScope(active);
|
|
2074
|
-
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
2075
|
-
staged.set(key, {
|
|
2076
|
-
present: true,
|
|
2077
|
-
value
|
|
2078
|
-
});
|
|
2079
|
-
},
|
|
2080
|
-
remove: (key) => {
|
|
2081
|
-
require_advanced.assertScope(active);
|
|
2082
|
-
staged.set(key, { present: false });
|
|
2083
|
-
},
|
|
2084
|
-
order: (order) => {
|
|
2085
|
-
require_advanced.assertScope(active);
|
|
2086
|
-
explicitOrder = Object.freeze([...order]);
|
|
2087
|
-
}
|
|
2088
|
-
}
|
|
1352
|
+
const evaluate = () => {
|
|
1353
|
+
const tracker = {
|
|
1354
|
+
keys: /* @__PURE__ */ new Set(),
|
|
1355
|
+
all: false,
|
|
1356
|
+
structure: false
|
|
2089
1357
|
};
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
1358
|
+
const previousTracker = activeTracker;
|
|
1359
|
+
activeTracker = tracker;
|
|
1360
|
+
let current;
|
|
1361
|
+
let next;
|
|
1362
|
+
try {
|
|
1363
|
+
current = source.current();
|
|
1364
|
+
next = selector(isMapLike(current) ? trackedMap(current) : current);
|
|
1365
|
+
} finally {
|
|
1366
|
+
activeTracker = previousTracker;
|
|
2094
1367
|
}
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
else if (!nextReset) staged.delete(key);
|
|
2105
|
-
} else if (existed) removed.add(key);
|
|
2106
|
-
else staged.delete(key);
|
|
1368
|
+
const nextSelection = Object.freeze({
|
|
1369
|
+
keys: new Set(tracker.keys),
|
|
1370
|
+
all: tracker.all || isMapLike(current) && tracker.keys.size === 0 && !tracker.structure,
|
|
1371
|
+
structure: tracker.structure
|
|
1372
|
+
});
|
|
1373
|
+
const changed = !initialized || !equality(value, next);
|
|
1374
|
+
if (changed) {
|
|
1375
|
+
if (initialized) selectedRevision++;
|
|
1376
|
+
value = next;
|
|
2107
1377
|
}
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
const
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
}
|
|
2131
|
-
else if (!afterPresent) removedEntries.push({
|
|
2132
|
-
key,
|
|
2133
|
-
before: values.get(key)
|
|
2134
|
-
});
|
|
2135
|
-
else updatedEntries.push({
|
|
2136
|
-
key,
|
|
2137
|
-
before: values.get(key),
|
|
2138
|
-
after: getNext(key)
|
|
2139
|
-
});
|
|
1378
|
+
selection = nextSelection;
|
|
1379
|
+
initialized = true;
|
|
1380
|
+
sourceRevision = source.revision();
|
|
1381
|
+
updateCollectionSnapshot(current);
|
|
1382
|
+
return changed;
|
|
1383
|
+
};
|
|
1384
|
+
const ensureCurrent = () => {
|
|
1385
|
+
const revision = source.revision();
|
|
1386
|
+
if (!initialized || !unsubscribeSource && sourceRevision !== revision) evaluate();
|
|
1387
|
+
return value;
|
|
1388
|
+
};
|
|
1389
|
+
const onProjectionChange = (incoming) => {
|
|
1390
|
+
let change = incoming;
|
|
1391
|
+
if (!change && previousCollection) {
|
|
1392
|
+
const current = source.current();
|
|
1393
|
+
if (isMapLike(current)) {
|
|
1394
|
+
change = require_advanced.collectionChangeBetween(previousCollection, current);
|
|
1395
|
+
previousCollection = current;
|
|
1396
|
+
if (!change) {
|
|
1397
|
+
sourceRevision = source.revision();
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
} else previousCollection = void 0;
|
|
2140
1401
|
}
|
|
2141
|
-
if (
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
const before = ids.filter((key) => !removed.has(key));
|
|
2146
|
-
const after = nextIds.filter((key) => !added.has(key));
|
|
2147
|
-
commonOrderChanged = before.some((key, index) => after[index] !== key);
|
|
2148
|
-
}
|
|
2149
|
-
change = Object.freeze({
|
|
2150
|
-
kind: "incremental",
|
|
2151
|
-
added: Object.freeze(addedEntries),
|
|
2152
|
-
updated: Object.freeze(updatedEntries),
|
|
2153
|
-
removed: Object.freeze(removedEntries),
|
|
2154
|
-
...commonOrderChanged ? { order: Object.freeze({
|
|
2155
|
-
before: Object.freeze([...ids]),
|
|
2156
|
-
after: Object.freeze([...nextIds])
|
|
2157
|
-
}) } : {}
|
|
2158
|
-
});
|
|
1402
|
+
if (!selectionAffects(selection, change)) {
|
|
1403
|
+
sourceRevision = source.revision();
|
|
1404
|
+
updateCollectionSnapshot();
|
|
1405
|
+
return;
|
|
2159
1406
|
}
|
|
2160
|
-
|
|
2161
|
-
return change !== void 0;
|
|
1407
|
+
if (evaluate()) Array.from(listeners).forEach((listener) => listener());
|
|
2162
1408
|
};
|
|
2163
|
-
const
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
require_advanced.assertScope(active);
|
|
2172
|
-
return hasNext(key);
|
|
2173
|
-
},
|
|
2174
|
-
ids: () => {
|
|
2175
|
-
require_advanced.assertScope(active);
|
|
2176
|
-
return nextIds;
|
|
2177
|
-
}
|
|
1409
|
+
const installSource = () => {
|
|
1410
|
+
if (!unsubscribeSource) unsubscribeSource = source.subscribe(onProjectionChange);
|
|
1411
|
+
};
|
|
1412
|
+
return Object.freeze({
|
|
1413
|
+
current: ensureCurrent,
|
|
1414
|
+
revision: () => {
|
|
1415
|
+
ensureCurrent();
|
|
1416
|
+
return selectedRevision;
|
|
2178
1417
|
},
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
1418
|
+
subscribe: (listener) => {
|
|
1419
|
+
ensureCurrent();
|
|
1420
|
+
listeners.add(listener);
|
|
1421
|
+
installSource();
|
|
1422
|
+
return () => {
|
|
1423
|
+
listeners.delete(listener);
|
|
1424
|
+
if (!listeners.size && unsubscribeSource) {
|
|
1425
|
+
unsubscribeSource();
|
|
1426
|
+
unsubscribeSource = void 0;
|
|
1427
|
+
}
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
2182
1430
|
});
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
});
|
|
1431
|
+
};
|
|
1432
|
+
//#endregion
|
|
1433
|
+
//#region core/src/projection/source.ts
|
|
1434
|
+
const sourceError = (source, cause) => new require_advanced.ProjectionError("source", source.name, [source.outputs[0].revision()], cause);
|
|
1435
|
+
const createValueBoundary = (scheduler, name, initial, equality) => {
|
|
1436
|
+
const state = createValueOutput();
|
|
1437
|
+
let boundary;
|
|
1438
|
+
let latest = initial;
|
|
1439
|
+
let pendingReset = false;
|
|
1440
|
+
let pendingCause;
|
|
1441
|
+
let contextCause;
|
|
1442
|
+
let recovering = false;
|
|
1443
|
+
let cleanup;
|
|
1444
|
+
const check = () => {
|
|
1445
|
+
if (!scheduler.active || boundary.disposed) throw new require_advanced.ProjectionDisposedError();
|
|
1446
|
+
if (boundary.fault) throw boundary.fault;
|
|
2200
1447
|
};
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
current,
|
|
2206
|
-
revision: () => revision,
|
|
2207
|
-
reset: () => reset,
|
|
2208
|
-
publish: () => {
|
|
2209
|
-
if (change) if (change.kind === "reset") {
|
|
2210
|
-
const entries = [];
|
|
2211
|
-
for (const [key, entry] of staged) if (entry.present) entries.push([key, entry.value]);
|
|
2212
|
-
entries.sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
|
|
2213
|
-
publishedRoot = treeFromSorted(entries);
|
|
2214
|
-
} else for (const [key, entry] of staged) publishedRoot = entry.present ? treeSet(publishedRoot, key, entry.value) : treeRemove(publishedRoot, key);
|
|
2215
|
-
for (const [key, entry] of staged) if (entry.present) values.set(key, entry.value);
|
|
2216
|
-
else values.delete(key);
|
|
2217
|
-
if (change && initialized) revision++;
|
|
2218
|
-
ids = nextIds;
|
|
2219
|
-
initialized = true;
|
|
1448
|
+
const output = {
|
|
1449
|
+
kind: "value",
|
|
1450
|
+
get owner() {
|
|
1451
|
+
return boundary;
|
|
2220
1452
|
},
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
1453
|
+
consumers: /* @__PURE__ */ new Set(),
|
|
1454
|
+
context: (active) => state.context(active, contextCause),
|
|
1455
|
+
current: () => state.current(check),
|
|
1456
|
+
revision: state.revision,
|
|
1457
|
+
reset: state.reset,
|
|
1458
|
+
subscribe: (listener) => {
|
|
1459
|
+
check();
|
|
1460
|
+
const wrapped = () => listener();
|
|
1461
|
+
state.subscribe(wrapped);
|
|
1462
|
+
return () => state.unsubscribe(wrapped);
|
|
1463
|
+
},
|
|
1464
|
+
emit: state.emit,
|
|
1465
|
+
clear: state.clear,
|
|
1466
|
+
release: state.release
|
|
1467
|
+
};
|
|
1468
|
+
boundary = {
|
|
1469
|
+
kind: "source",
|
|
1470
|
+
name,
|
|
1471
|
+
outputs: Object.freeze([output]),
|
|
1472
|
+
fault: void 0,
|
|
1473
|
+
disposed: false,
|
|
1474
|
+
pendingCause: () => pendingCause,
|
|
1475
|
+
recovering: () => recovering,
|
|
1476
|
+
prepare: (cause) => {
|
|
1477
|
+
contextCause = cause;
|
|
1478
|
+
let active = true;
|
|
1479
|
+
try {
|
|
1480
|
+
state.begin(() => active, pendingReset).output.set(latest);
|
|
1481
|
+
const changed = state.seal(pendingReset, equality);
|
|
1482
|
+
recovering = false;
|
|
1483
|
+
return {
|
|
1484
|
+
changed,
|
|
1485
|
+
force: pendingReset
|
|
1486
|
+
};
|
|
1487
|
+
} finally {
|
|
1488
|
+
active = false;
|
|
1489
|
+
}
|
|
2224
1490
|
},
|
|
1491
|
+
publish: state.publish,
|
|
2225
1492
|
clear: () => {
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
explicitOrder = void 0;
|
|
2232
|
-
orderChanged = false;
|
|
2233
|
-
cleared = false;
|
|
1493
|
+
state.clear();
|
|
1494
|
+
pendingReset = false;
|
|
1495
|
+
pendingCause = void 0;
|
|
1496
|
+
contextCause = void 0;
|
|
1497
|
+
recovering = false;
|
|
2234
1498
|
},
|
|
2235
1499
|
release: () => {
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
1500
|
+
cleanup?.();
|
|
1501
|
+
cleanup = void 0;
|
|
1502
|
+
state.release();
|
|
1503
|
+
output.consumers.clear();
|
|
1504
|
+
}
|
|
1505
|
+
};
|
|
1506
|
+
scheduler.initialize(() => {
|
|
1507
|
+
let active = true;
|
|
1508
|
+
try {
|
|
1509
|
+
state.begin(() => active, true).output.set(initial);
|
|
1510
|
+
state.seal(true, equality);
|
|
1511
|
+
state.publish();
|
|
1512
|
+
state.clear();
|
|
1513
|
+
} finally {
|
|
1514
|
+
active = false;
|
|
1515
|
+
}
|
|
1516
|
+
});
|
|
1517
|
+
scheduler.addSource(boundary);
|
|
1518
|
+
const mark = (metadata = {}) => {
|
|
1519
|
+
scheduler.assertIdle();
|
|
1520
|
+
pendingReset ||= metadata.reset ?? false;
|
|
1521
|
+
if (metadata.cause !== void 0) pendingCause ??= metadata.cause;
|
|
1522
|
+
if (boundary.fault) recovering = true;
|
|
1523
|
+
scheduler.capture(boundary);
|
|
1524
|
+
};
|
|
1525
|
+
const fail = (cause) => {
|
|
1526
|
+
boundary.fault = sourceError(boundary, cause);
|
|
1527
|
+
recovering = false;
|
|
1528
|
+
scheduler.capture(boundary);
|
|
1529
|
+
};
|
|
1530
|
+
return {
|
|
1531
|
+
producer: boundary,
|
|
1532
|
+
output,
|
|
1533
|
+
setLatest: (value) => {
|
|
1534
|
+
latest = value;
|
|
2247
1535
|
},
|
|
2248
|
-
|
|
2249
|
-
|
|
1536
|
+
mark,
|
|
1537
|
+
fail,
|
|
1538
|
+
detach: (next) => {
|
|
1539
|
+
cleanup = next;
|
|
2250
1540
|
}
|
|
2251
1541
|
};
|
|
2252
1542
|
};
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
let
|
|
2258
|
-
let
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
} else {
|
|
2273
|
-
require_issue.profile.materialized.updated();
|
|
2274
|
-
const result = instance.update({
|
|
2275
|
-
sources,
|
|
2276
|
-
...input
|
|
2277
|
-
});
|
|
2278
|
-
require_advanced.assertSynchronous(result);
|
|
2279
|
-
if (result?.kind === "rebuild") {
|
|
2280
|
-
const rebuildInput = state.begin(active, true);
|
|
2281
|
-
instance = void 0;
|
|
2282
|
-
const built = spec.build({
|
|
2283
|
-
sources,
|
|
2284
|
-
...rebuildInput
|
|
2285
|
-
});
|
|
2286
|
-
require_advanced.assertSynchronous(built);
|
|
2287
|
-
instance = built;
|
|
2288
|
-
build = true;
|
|
2289
|
-
}
|
|
2290
|
-
}
|
|
2291
|
-
return state.seal(build, spec.isEqual ?? Object.is);
|
|
1543
|
+
const createCollectionBoundary = (scheduler, name, readLatest, equality) => {
|
|
1544
|
+
const state = require_advanced.createCollectionOutput();
|
|
1545
|
+
let boundary;
|
|
1546
|
+
let pendingReset = false;
|
|
1547
|
+
let pendingCause;
|
|
1548
|
+
let contextCause;
|
|
1549
|
+
let recovering = false;
|
|
1550
|
+
let fullScan = false;
|
|
1551
|
+
let orderMayChange = false;
|
|
1552
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
1553
|
+
let cleanup;
|
|
1554
|
+
const check = () => {
|
|
1555
|
+
if (!scheduler.active || boundary.disposed) throw new require_advanced.ProjectionDisposedError();
|
|
1556
|
+
if (boundary.fault) throw boundary.fault;
|
|
1557
|
+
};
|
|
1558
|
+
const output = {
|
|
1559
|
+
kind: "collection",
|
|
1560
|
+
get owner() {
|
|
1561
|
+
return boundary;
|
|
2292
1562
|
},
|
|
2293
|
-
|
|
1563
|
+
consumers: /* @__PURE__ */ new Set(),
|
|
1564
|
+
context: (active) => state.context(active, contextCause),
|
|
1565
|
+
current: () => state.current(check),
|
|
2294
1566
|
revision: state.revision,
|
|
2295
1567
|
reset: state.reset,
|
|
2296
|
-
|
|
1568
|
+
subscribe: (listener) => {
|
|
1569
|
+
check();
|
|
1570
|
+
const wrapped = (change) => listener(change);
|
|
1571
|
+
state.subscribe(wrapped);
|
|
1572
|
+
return () => state.unsubscribe(wrapped);
|
|
1573
|
+
},
|
|
2297
1574
|
emit: state.emit,
|
|
2298
1575
|
clear: state.clear,
|
|
1576
|
+
release: state.release
|
|
1577
|
+
};
|
|
1578
|
+
boundary = {
|
|
1579
|
+
kind: "source",
|
|
1580
|
+
name,
|
|
1581
|
+
outputs: Object.freeze([output]),
|
|
1582
|
+
fault: void 0,
|
|
1583
|
+
disposed: false,
|
|
1584
|
+
pendingCause: () => pendingCause,
|
|
1585
|
+
recovering: () => recovering,
|
|
1586
|
+
prepare: (cause) => {
|
|
1587
|
+
contextCause = cause;
|
|
1588
|
+
let active = true;
|
|
1589
|
+
try {
|
|
1590
|
+
const changed = require_advanced.stageCollectionRead(state, readLatest(() => active), () => active, {
|
|
1591
|
+
reset: pendingReset,
|
|
1592
|
+
...fullScan ? {} : { candidates },
|
|
1593
|
+
orderMayChange,
|
|
1594
|
+
isEqual: equality
|
|
1595
|
+
});
|
|
1596
|
+
recovering = false;
|
|
1597
|
+
return {
|
|
1598
|
+
changed,
|
|
1599
|
+
force: pendingReset
|
|
1600
|
+
};
|
|
1601
|
+
} finally {
|
|
1602
|
+
active = false;
|
|
1603
|
+
}
|
|
1604
|
+
},
|
|
1605
|
+
publish: state.publish,
|
|
1606
|
+
clear: () => {
|
|
1607
|
+
state.clear();
|
|
1608
|
+
pendingReset = false;
|
|
1609
|
+
pendingCause = void 0;
|
|
1610
|
+
contextCause = void 0;
|
|
1611
|
+
recovering = false;
|
|
1612
|
+
fullScan = false;
|
|
1613
|
+
orderMayChange = false;
|
|
1614
|
+
candidates.clear();
|
|
1615
|
+
},
|
|
2299
1616
|
release: () => {
|
|
1617
|
+
cleanup?.();
|
|
1618
|
+
cleanup = void 0;
|
|
2300
1619
|
state.release();
|
|
2301
|
-
|
|
1620
|
+
output.consumers.clear();
|
|
1621
|
+
}
|
|
1622
|
+
};
|
|
1623
|
+
scheduler.initialize(() => {
|
|
1624
|
+
let active = true;
|
|
1625
|
+
try {
|
|
1626
|
+
require_advanced.stageCollectionRead(state, readLatest(() => active), () => active, {
|
|
1627
|
+
reset: true,
|
|
1628
|
+
isEqual: equality
|
|
1629
|
+
});
|
|
1630
|
+
state.publish();
|
|
1631
|
+
state.clear();
|
|
1632
|
+
} finally {
|
|
1633
|
+
active = false;
|
|
2302
1634
|
}
|
|
2303
1635
|
});
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
1636
|
+
scheduler.addSource(boundary);
|
|
1637
|
+
const mark = (metadata = {}) => {
|
|
1638
|
+
scheduler.assertIdle();
|
|
1639
|
+
pendingReset ||= metadata.reset ?? false;
|
|
1640
|
+
if (metadata.cause !== void 0) pendingCause ??= metadata.cause;
|
|
1641
|
+
fullScan ||= metadata.fullScan ?? false;
|
|
1642
|
+
orderMayChange ||= metadata.orderMayChange ?? false;
|
|
1643
|
+
if (metadata.candidates) for (const key of metadata.candidates) candidates.add(key);
|
|
1644
|
+
if (boundary.fault) recovering = true;
|
|
1645
|
+
scheduler.capture(boundary);
|
|
1646
|
+
};
|
|
1647
|
+
const fail = (cause) => {
|
|
1648
|
+
boundary.fault = sourceError(boundary, cause);
|
|
1649
|
+
recovering = false;
|
|
1650
|
+
scheduler.capture(boundary);
|
|
1651
|
+
};
|
|
1652
|
+
return {
|
|
1653
|
+
producer: boundary,
|
|
1654
|
+
output,
|
|
1655
|
+
mark,
|
|
1656
|
+
fail,
|
|
1657
|
+
detach: (next) => {
|
|
1658
|
+
cleanup = next;
|
|
2318
1659
|
}
|
|
2319
1660
|
};
|
|
2320
|
-
owner.install(handle);
|
|
2321
|
-
return Object.freeze(handle);
|
|
2322
1661
|
};
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
const
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
let changedOutputs = Object.freeze([]);
|
|
2337
|
-
let node;
|
|
2338
|
-
const order = scheduler.order();
|
|
2339
|
-
const outputs = states.map((state, index) => {
|
|
2340
|
-
const output = {
|
|
2341
|
-
owner: void 0,
|
|
2342
|
-
consumers: /* @__PURE__ */ new Set(),
|
|
2343
|
-
context: (active) => state.context(active, cause),
|
|
2344
|
-
revision: state.revision,
|
|
2345
|
-
reset: state.reset,
|
|
2346
|
-
fault: void 0,
|
|
2347
|
-
disposed: false,
|
|
2348
|
-
clear: state.clear,
|
|
2349
|
-
emit: state.emit
|
|
1662
|
+
const createSourceRegistry = (scheduler) => {
|
|
1663
|
+
const documents = /* @__PURE__ */ new Map();
|
|
1664
|
+
const readables = /* @__PURE__ */ new Map();
|
|
1665
|
+
const externalValues = /* @__PURE__ */ new WeakMap();
|
|
1666
|
+
const externalCollections = /* @__PURE__ */ new WeakMap();
|
|
1667
|
+
const documentConnection = (runtime) => {
|
|
1668
|
+
const state = require_access.accessOf(runtime);
|
|
1669
|
+
const cached = documents.get(state);
|
|
1670
|
+
if (cached) return cached;
|
|
1671
|
+
if (state.disposed) throw new Error("Document has been disposed.");
|
|
1672
|
+
const bindings = /* @__PURE__ */ new Set();
|
|
1673
|
+
const guard = (locked) => {
|
|
1674
|
+
state.projectionLocks = (state.projectionLocks ?? 0) + (locked ? 1 : -1);
|
|
2350
1675
|
};
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
1676
|
+
scheduler.guards.add(guard);
|
|
1677
|
+
let closed = false;
|
|
1678
|
+
let detach = () => void 0;
|
|
1679
|
+
const connection = {
|
|
1680
|
+
add(binding) {
|
|
1681
|
+
if (closed) throw new Error("Document projection connection is closed.");
|
|
1682
|
+
bindings.add(binding);
|
|
1683
|
+
let active = true;
|
|
1684
|
+
return () => {
|
|
1685
|
+
if (!active) return;
|
|
1686
|
+
active = false;
|
|
1687
|
+
bindings.delete(binding);
|
|
1688
|
+
if (!bindings.size) connection.close();
|
|
1689
|
+
};
|
|
1690
|
+
},
|
|
1691
|
+
close() {
|
|
1692
|
+
if (closed) return;
|
|
1693
|
+
closed = true;
|
|
1694
|
+
detach();
|
|
1695
|
+
bindings.clear();
|
|
1696
|
+
scheduler.guards.delete(guard);
|
|
1697
|
+
documents.delete(state);
|
|
1698
|
+
}
|
|
1699
|
+
};
|
|
1700
|
+
detach = require_notification.attachProjection(runtime, {
|
|
1701
|
+
capture: (commit) => {
|
|
1702
|
+
for (const binding of bindings) if (binding.matches(commit)) binding.capture(commit);
|
|
1703
|
+
},
|
|
1704
|
+
settle: scheduler.settle,
|
|
1705
|
+
flush: scheduler.flush,
|
|
1706
|
+
dispose: () => {
|
|
1707
|
+
for (const binding of bindings) binding.dispose();
|
|
1708
|
+
scheduler.run();
|
|
2357
1709
|
}
|
|
2358
1710
|
});
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
const check = () => {
|
|
2362
|
-
if (node.disposed || !scheduler.active) throw new require_advanced.ProjectionDisposedError();
|
|
2363
|
-
if (node.fault) throw node.fault;
|
|
1711
|
+
documents.set(state, connection);
|
|
1712
|
+
return connection;
|
|
2364
1713
|
};
|
|
2365
|
-
const
|
|
2366
|
-
|
|
2367
|
-
const
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
1714
|
+
const valueInput = (definition) => {
|
|
1715
|
+
if (definition.source.kind !== "value-input") throw new Error("Invalid value input source.");
|
|
1716
|
+
const source = definition.source;
|
|
1717
|
+
const boundary = createValueBoundary(scheduler, "projection input", source.initial, source.equality);
|
|
1718
|
+
return {
|
|
1719
|
+
...boundary,
|
|
1720
|
+
write: {
|
|
1721
|
+
kind: "value",
|
|
1722
|
+
set(value) {
|
|
1723
|
+
scheduler.assertIdle();
|
|
1724
|
+
boundary.setLatest(value);
|
|
1725
|
+
boundary.mark();
|
|
1726
|
+
scheduler.run();
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
2375
1729
|
};
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
1730
|
+
};
|
|
1731
|
+
const collectionInput = (definition) => {
|
|
1732
|
+
if (definition.source.kind !== "collection-input") throw new Error("Invalid collection input source.");
|
|
1733
|
+
const values = new Map(definition.source.initial);
|
|
1734
|
+
const boundary = createCollectionBoundary(scheduler, "projection collection input", () => require_advanced.mapRead(values), definition.output.equality);
|
|
1735
|
+
return {
|
|
1736
|
+
...boundary,
|
|
1737
|
+
write: {
|
|
1738
|
+
kind: "collection",
|
|
1739
|
+
update(run) {
|
|
1740
|
+
scheduler.assertIdle();
|
|
1741
|
+
const staged = /* @__PURE__ */ new Map();
|
|
1742
|
+
const operations = [];
|
|
1743
|
+
let active = true;
|
|
1744
|
+
const draft = Object.freeze({
|
|
1745
|
+
get: (key) => {
|
|
1746
|
+
require_advanced.assertScope(() => active);
|
|
1747
|
+
const entry = staged.get(key);
|
|
1748
|
+
return entry ? entry.present ? entry.value : void 0 : values.get(key);
|
|
1749
|
+
},
|
|
1750
|
+
has: (key) => {
|
|
1751
|
+
require_advanced.assertScope(() => active);
|
|
1752
|
+
const entry = staged.get(key);
|
|
1753
|
+
return entry ? entry.present : values.has(key);
|
|
1754
|
+
},
|
|
1755
|
+
set: (key, value) => {
|
|
1756
|
+
require_advanced.assertScope(() => active);
|
|
1757
|
+
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
1758
|
+
staged.set(key, {
|
|
1759
|
+
present: true,
|
|
1760
|
+
value
|
|
1761
|
+
});
|
|
1762
|
+
operations.push({
|
|
1763
|
+
kind: "set",
|
|
1764
|
+
key,
|
|
1765
|
+
value
|
|
1766
|
+
});
|
|
1767
|
+
},
|
|
1768
|
+
remove: (key) => {
|
|
1769
|
+
require_advanced.assertScope(() => active);
|
|
1770
|
+
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
1771
|
+
staged.set(key, { present: false });
|
|
1772
|
+
operations.push({
|
|
1773
|
+
kind: "remove",
|
|
1774
|
+
key
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1777
|
+
});
|
|
1778
|
+
try {
|
|
1779
|
+
require_advanced.assertSynchronous(run(draft));
|
|
1780
|
+
} finally {
|
|
1781
|
+
active = false;
|
|
1782
|
+
}
|
|
1783
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
1784
|
+
let structural = false;
|
|
1785
|
+
let changed = false;
|
|
1786
|
+
for (const operation of operations) {
|
|
1787
|
+
const present = values.has(operation.key);
|
|
1788
|
+
if (operation.kind === "set") {
|
|
1789
|
+
if (present && Object.is(values.get(operation.key), operation.value)) continue;
|
|
1790
|
+
structural ||= !present;
|
|
1791
|
+
values.set(operation.key, operation.value);
|
|
1792
|
+
} else {
|
|
1793
|
+
if (!present) continue;
|
|
1794
|
+
structural = true;
|
|
1795
|
+
values.delete(operation.key);
|
|
1796
|
+
}
|
|
1797
|
+
candidates.add(operation.key);
|
|
1798
|
+
changed = true;
|
|
1799
|
+
}
|
|
1800
|
+
if (!changed) return;
|
|
1801
|
+
boundary.mark({
|
|
1802
|
+
candidates,
|
|
1803
|
+
orderMayChange: structural
|
|
1804
|
+
});
|
|
1805
|
+
scheduler.run();
|
|
1806
|
+
}
|
|
2394
1807
|
}
|
|
2395
|
-
}
|
|
2396
|
-
changedOutputs = Object.freeze(states.flatMap((state, index) => state.seal(build, spec.outputs[index].isEqual ?? Object.is) ? [outputs[index]] : []));
|
|
2397
|
-
return changedOutputs.length > 0;
|
|
1808
|
+
};
|
|
2398
1809
|
};
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
1810
|
+
const documentValue = (definition) => {
|
|
1811
|
+
if (definition.source.kind !== "document-value") throw new Error("Invalid document value source.");
|
|
1812
|
+
const { document, selector } = definition.source;
|
|
1813
|
+
const state = require_access.accessOf(document);
|
|
1814
|
+
const address = selector?.address ?? Object.freeze([]);
|
|
1815
|
+
const schemaNode = () => require_issue.nodeAt(state.schema, address, state.document);
|
|
1816
|
+
const read = () => {
|
|
1817
|
+
if (state.disposed) throw new Error("Document has been disposed.");
|
|
1818
|
+
const node = schemaNode();
|
|
1819
|
+
if (!node) return void 0;
|
|
1820
|
+
return require_access.copyValue(node, selector ? require_issue.read(state.document, address, state.schema) : state.document);
|
|
1821
|
+
};
|
|
1822
|
+
const boundary = createValueBoundary(scheduler, "document source", read(), (left, right) => {
|
|
1823
|
+
const node = schemaNode();
|
|
1824
|
+
return node ? require_access.equalValue(node, left, right) : Object.is(left, right);
|
|
1825
|
+
});
|
|
1826
|
+
const remove = documentConnection(document).add({
|
|
1827
|
+
matches: (commit) => !selector || affectsTarget(commit.impact, selector),
|
|
1828
|
+
capture: (commit) => {
|
|
1829
|
+
try {
|
|
1830
|
+
boundary.setLatest(read());
|
|
1831
|
+
boundary.mark({ reset: commit.impact.kind === "reset" });
|
|
1832
|
+
} catch (cause) {
|
|
1833
|
+
boundary.fail(cause);
|
|
1834
|
+
}
|
|
1835
|
+
},
|
|
1836
|
+
dispose: () => boundary.fail(/* @__PURE__ */ new Error("Document has been disposed."))
|
|
1837
|
+
});
|
|
1838
|
+
boundary.detach(remove);
|
|
1839
|
+
return boundary;
|
|
1840
|
+
};
|
|
1841
|
+
const documentCollection = (definition) => {
|
|
1842
|
+
if (definition.source.kind !== "document-collection") throw new Error("Invalid document collection source.");
|
|
1843
|
+
const { document, selector } = definition.source;
|
|
1844
|
+
const state = require_access.accessOf(document);
|
|
1845
|
+
const read = (active) => {
|
|
1846
|
+
if (state.disposed) throw new Error("Document has been disposed.");
|
|
1847
|
+
const raw = require_access.collectionAccess({
|
|
1848
|
+
state,
|
|
1849
|
+
active
|
|
1850
|
+
}, selector.address);
|
|
1851
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
1852
|
+
return Object.freeze({
|
|
1853
|
+
get: (key) => {
|
|
1854
|
+
require_advanced.assertScope(active);
|
|
1855
|
+
if (!snapshots.has(key)) snapshots.set(key, require_access.snapshot(raw.get(key)));
|
|
1856
|
+
return snapshots.get(key);
|
|
1857
|
+
},
|
|
1858
|
+
has: (key) => {
|
|
1859
|
+
require_advanced.assertScope(active);
|
|
1860
|
+
return raw.has(key);
|
|
1861
|
+
},
|
|
1862
|
+
ids: () => {
|
|
1863
|
+
require_advanced.assertScope(active);
|
|
1864
|
+
return raw.ids();
|
|
1865
|
+
}
|
|
1866
|
+
});
|
|
1867
|
+
};
|
|
1868
|
+
const collectionNode = () => require_issue.nodeAt(state.schema, selector.address, state.document);
|
|
1869
|
+
const boundary = createCollectionBoundary(scheduler, "document collection source", read, (left, right) => {
|
|
1870
|
+
const node = collectionNode();
|
|
1871
|
+
const entry = node && require_advanced.collectionEntryNode(node);
|
|
1872
|
+
return entry ? require_access.equalValue(entry, left, right) : Object.is(left, right);
|
|
1873
|
+
});
|
|
1874
|
+
const remove = documentConnection(document).add({
|
|
1875
|
+
matches: (commit) => affectsTarget(commit.impact, selector),
|
|
1876
|
+
capture: (commit) => {
|
|
1877
|
+
const impact = collectionImpact(commit.impact, selector);
|
|
1878
|
+
if (impact.kind === "reset") {
|
|
1879
|
+
boundary.mark({ reset: true });
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
const candidates = new Set([
|
|
1883
|
+
...impact.added,
|
|
1884
|
+
...impact.updated,
|
|
1885
|
+
...impact.removed
|
|
1886
|
+
]);
|
|
1887
|
+
boundary.mark({
|
|
1888
|
+
candidates,
|
|
1889
|
+
orderMayChange: Boolean(impact.added.size || impact.removed.size || impact.orderChanged)
|
|
1890
|
+
});
|
|
1891
|
+
},
|
|
1892
|
+
dispose: () => boundary.fail(/* @__PURE__ */ new Error("Document has been disposed."))
|
|
1893
|
+
});
|
|
1894
|
+
boundary.detach(remove);
|
|
1895
|
+
return boundary;
|
|
1896
|
+
};
|
|
1897
|
+
const readable = (definition) => {
|
|
1898
|
+
if (definition.source.kind !== "readable") throw new Error("Invalid Readable source.");
|
|
1899
|
+
const { readable, equality } = definition.source;
|
|
1900
|
+
let initial = readable.current();
|
|
1901
|
+
const boundary = createValueBoundary(scheduler, "external readable", initial, equality);
|
|
1902
|
+
const member = {
|
|
1903
|
+
boundary,
|
|
1904
|
+
receive(value, metadata) {
|
|
1905
|
+
initial = value;
|
|
1906
|
+
boundary.setLatest(value);
|
|
1907
|
+
boundary.mark(metadata);
|
|
2421
1908
|
}
|
|
2422
|
-
}
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
1909
|
+
};
|
|
1910
|
+
let connection = readables.get(readable);
|
|
1911
|
+
if (!connection) {
|
|
1912
|
+
const members = /* @__PURE__ */ new Set();
|
|
1913
|
+
let closed = false;
|
|
1914
|
+
let unsubscribe;
|
|
1915
|
+
let detachDocument;
|
|
1916
|
+
const receive = (settle) => {
|
|
1917
|
+
if (closed || !scheduler.active) return;
|
|
1918
|
+
try {
|
|
1919
|
+
const value = readable.current();
|
|
1920
|
+
members.forEach((next) => next.receive(value));
|
|
1921
|
+
} catch (cause) {
|
|
1922
|
+
members.forEach((next) => next.boundary.fail(cause));
|
|
1923
|
+
}
|
|
1924
|
+
if (settle) scheduler.run();
|
|
1925
|
+
};
|
|
1926
|
+
const created = {
|
|
1927
|
+
members,
|
|
1928
|
+
close() {
|
|
1929
|
+
if (closed) return;
|
|
1930
|
+
closed = true;
|
|
1931
|
+
unsubscribe?.();
|
|
1932
|
+
detachDocument?.();
|
|
1933
|
+
readables.delete(readable);
|
|
1934
|
+
}
|
|
1935
|
+
};
|
|
1936
|
+
const owner = require_notification.documentReadableOwner(readable);
|
|
1937
|
+
if (owner) detachDocument = documentConnection(owner).add({
|
|
1938
|
+
matches: () => true,
|
|
1939
|
+
capture: () => receive(false),
|
|
1940
|
+
dispose: () => {
|
|
1941
|
+
members.forEach((next) => next.boundary.fail(/* @__PURE__ */ new Error("Document has been disposed.")));
|
|
1942
|
+
}
|
|
2439
1943
|
});
|
|
2440
|
-
|
|
1944
|
+
unsubscribe = readable.subscribe(() => receive(true));
|
|
1945
|
+
connection = created;
|
|
1946
|
+
readables.set(readable, connection);
|
|
2441
1947
|
}
|
|
1948
|
+
connection.members.add(member);
|
|
1949
|
+
boundary.detach(() => {
|
|
1950
|
+
connection.members.delete(member);
|
|
1951
|
+
if (!connection.members.size) connection.close();
|
|
1952
|
+
});
|
|
1953
|
+
return boundary;
|
|
2442
1954
|
};
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
node.clear();
|
|
2453
|
-
});
|
|
2454
|
-
const handles = outputs.map((output, index) => {
|
|
2455
|
-
const handle = {
|
|
2456
|
-
kind: "collection",
|
|
2457
|
-
current: () => {
|
|
2458
|
-
check();
|
|
2459
|
-
return states[index].current(check);
|
|
2460
|
-
},
|
|
2461
|
-
revision: () => {
|
|
2462
|
-
check();
|
|
2463
|
-
return states[index].revision();
|
|
2464
|
-
},
|
|
2465
|
-
subscribe: (listener) => {
|
|
2466
|
-
check();
|
|
2467
|
-
states[index].subscribe(listener);
|
|
2468
|
-
return () => states[index].unsubscribe(listener);
|
|
1955
|
+
const externalValue = (definition) => {
|
|
1956
|
+
if (definition.source.kind !== "external-value") throw new Error("Invalid external value source.");
|
|
1957
|
+
const { source, equality } = definition.source;
|
|
1958
|
+
const boundary = createValueBoundary(scheduler, "external source", source.current(), equality);
|
|
1959
|
+
const member = {
|
|
1960
|
+
boundary,
|
|
1961
|
+
receive(value, metadata) {
|
|
1962
|
+
boundary.setLatest(value);
|
|
1963
|
+
boundary.mark(metadata);
|
|
2469
1964
|
}
|
|
2470
1965
|
};
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
const map = (source, mapper, options) => {
|
|
2484
|
-
sources.assertCollection(source);
|
|
2485
|
-
const calculate = (id, entry) => {
|
|
2486
|
-
const value = mapper(id, entry);
|
|
2487
|
-
require_advanced.assertSynchronous(value);
|
|
2488
|
-
return value;
|
|
2489
|
-
};
|
|
2490
|
-
return createCollection(scheduler, {
|
|
2491
|
-
sources: { source },
|
|
2492
|
-
isEqual: options?.isEqual,
|
|
2493
|
-
build: ({ sources, output }) => {
|
|
2494
|
-
const read = sources.source.read;
|
|
2495
|
-
const ids = read.ids();
|
|
2496
|
-
require_issue.profile.collectionView.idsScanned(ids.length);
|
|
2497
|
-
for (const id of ids) {
|
|
2498
|
-
require_issue.profile.collectionView.mapped();
|
|
2499
|
-
output.set(id, calculate(id, read.get(id)));
|
|
1966
|
+
let connection = externalValues.get(source);
|
|
1967
|
+
if (!connection) {
|
|
1968
|
+
const members = /* @__PURE__ */ new Set();
|
|
1969
|
+
let closed = false;
|
|
1970
|
+
let unsubscribe;
|
|
1971
|
+
const created = {
|
|
1972
|
+
members,
|
|
1973
|
+
close() {
|
|
1974
|
+
if (closed) return;
|
|
1975
|
+
closed = true;
|
|
1976
|
+
unsubscribe?.();
|
|
1977
|
+
externalValues.delete(source);
|
|
2500
1978
|
}
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
}
|
|
2512
|
-
for (const entry of change.updated) {
|
|
2513
|
-
require_issue.profile.collectionView.mapped();
|
|
2514
|
-
output.set(entry.key, calculate(entry.key, entry.after));
|
|
2515
|
-
}
|
|
2516
|
-
for (const entry of change.removed) output.remove(entry.key);
|
|
2517
|
-
if (change.added.length || change.removed.length || change.order) {
|
|
2518
|
-
const ids = read.ids();
|
|
2519
|
-
require_issue.profile.collectionView.idsScanned(ids.length);
|
|
2520
|
-
output.order(ids);
|
|
1979
|
+
};
|
|
1980
|
+
try {
|
|
1981
|
+
unsubscribe = source.subscribe((event) => {
|
|
1982
|
+
try {
|
|
1983
|
+
members.forEach((next) => next.receive(event.value, {
|
|
1984
|
+
reset: event.reset,
|
|
1985
|
+
cause: event.cause
|
|
1986
|
+
}));
|
|
1987
|
+
} catch (cause) {
|
|
1988
|
+
members.forEach((next) => next.boundary.fail(cause));
|
|
2521
1989
|
}
|
|
2522
|
-
|
|
1990
|
+
scheduler.run();
|
|
1991
|
+
});
|
|
1992
|
+
} catch (cause) {
|
|
1993
|
+
created.close();
|
|
1994
|
+
throw cause;
|
|
2523
1995
|
}
|
|
1996
|
+
connection = created;
|
|
1997
|
+
externalValues.set(source, connection);
|
|
1998
|
+
}
|
|
1999
|
+
connection.members.add(member);
|
|
2000
|
+
boundary.detach(() => {
|
|
2001
|
+
connection.members.delete(member);
|
|
2002
|
+
if (!connection.members.size) connection.close();
|
|
2524
2003
|
});
|
|
2004
|
+
return boundary;
|
|
2525
2005
|
};
|
|
2526
|
-
const
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2006
|
+
const externalCollection = (definition) => {
|
|
2007
|
+
if (definition.source.kind !== "external-collection") throw new Error("Invalid external collection source.");
|
|
2008
|
+
const source = definition.source.source;
|
|
2009
|
+
const boundary = createCollectionBoundary(scheduler, "external collection source", () => {
|
|
2010
|
+
const current = source.current();
|
|
2011
|
+
return Object.freeze({
|
|
2012
|
+
get: (key) => current.get(key),
|
|
2013
|
+
has: (key) => current.has(key),
|
|
2014
|
+
ids: () => current.ids()
|
|
2015
|
+
});
|
|
2016
|
+
}, definition.output.equality);
|
|
2017
|
+
let connection = externalCollections.get(source);
|
|
2018
|
+
if (!connection) {
|
|
2019
|
+
const members = /* @__PURE__ */ new Set();
|
|
2020
|
+
let closed = false;
|
|
2021
|
+
let unsubscribe;
|
|
2022
|
+
const created = {
|
|
2023
|
+
members,
|
|
2024
|
+
close() {
|
|
2025
|
+
if (closed) return;
|
|
2026
|
+
closed = true;
|
|
2027
|
+
unsubscribe?.();
|
|
2028
|
+
externalCollections.delete(source);
|
|
2029
|
+
}
|
|
2030
|
+
};
|
|
2542
2031
|
try {
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2032
|
+
unsubscribe = source.subscribe((event) => {
|
|
2033
|
+
try {
|
|
2034
|
+
const impact = event.impact;
|
|
2035
|
+
if (impact?.kind === "reset") members.forEach((next) => next.mark({
|
|
2036
|
+
reset: true,
|
|
2037
|
+
cause: event.cause
|
|
2038
|
+
}));
|
|
2039
|
+
else if (impact?.kind === "incremental") {
|
|
2040
|
+
const candidates = new Set([
|
|
2041
|
+
...impact.added,
|
|
2042
|
+
...impact.updated,
|
|
2043
|
+
...impact.removed
|
|
2044
|
+
]);
|
|
2045
|
+
members.forEach((next) => next.mark({
|
|
2046
|
+
candidates,
|
|
2047
|
+
orderMayChange: Boolean(impact.added.size || impact.removed.size || impact.orderChanged),
|
|
2048
|
+
cause: event.cause
|
|
2049
|
+
}));
|
|
2050
|
+
} else members.forEach((next) => next.mark({
|
|
2051
|
+
fullScan: true,
|
|
2052
|
+
orderMayChange: true,
|
|
2053
|
+
cause: event.cause
|
|
2054
|
+
}));
|
|
2055
|
+
} catch (cause) {
|
|
2056
|
+
members.forEach((next) => next.fail(cause));
|
|
2057
|
+
}
|
|
2058
|
+
scheduler.run();
|
|
2059
|
+
});
|
|
2060
|
+
} catch (cause) {
|
|
2061
|
+
created.close();
|
|
2062
|
+
throw cause;
|
|
2546
2063
|
}
|
|
2064
|
+
connection = created;
|
|
2065
|
+
externalCollections.set(source, connection);
|
|
2547
2066
|
}
|
|
2067
|
+
connection.members.add(boundary);
|
|
2068
|
+
boundary.detach(() => {
|
|
2069
|
+
connection.members.delete(boundary);
|
|
2070
|
+
if (!connection.members.size) connection.close();
|
|
2071
|
+
});
|
|
2072
|
+
return boundary;
|
|
2548
2073
|
};
|
|
2549
|
-
return
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
};
|
|
2561
|
-
const trackAll = () => {
|
|
2562
|
-
if (!activeTracker) return;
|
|
2563
|
-
activeTracker.all = true;
|
|
2564
|
-
};
|
|
2565
|
-
const mapView = (read) => {
|
|
2566
|
-
const keys = read.ids();
|
|
2567
|
-
const source = /* @__PURE__ */ new Map();
|
|
2568
|
-
for (const key of keys) source.set(key, read.get(key));
|
|
2569
|
-
const view = {
|
|
2570
|
-
get: (key) => {
|
|
2571
|
-
trackKey(key);
|
|
2572
|
-
return source.get(key);
|
|
2573
|
-
},
|
|
2574
|
-
has: (key) => {
|
|
2575
|
-
trackKey(key);
|
|
2576
|
-
return source.has(key);
|
|
2577
|
-
},
|
|
2578
|
-
get size() {
|
|
2579
|
-
trackStructure();
|
|
2580
|
-
return source.size;
|
|
2581
|
-
},
|
|
2582
|
-
keys: () => {
|
|
2583
|
-
trackStructure();
|
|
2584
|
-
return source.keys();
|
|
2585
|
-
},
|
|
2586
|
-
values: () => {
|
|
2587
|
-
trackAll();
|
|
2588
|
-
return source.values();
|
|
2589
|
-
},
|
|
2590
|
-
entries: () => {
|
|
2591
|
-
trackAll();
|
|
2592
|
-
return source.entries();
|
|
2593
|
-
},
|
|
2594
|
-
forEach: (callback, thisArg) => {
|
|
2595
|
-
trackAll();
|
|
2596
|
-
source.forEach((value, key) => callback.call(thisArg, value, key, view));
|
|
2597
|
-
},
|
|
2598
|
-
[Symbol.iterator]: () => {
|
|
2599
|
-
trackAll();
|
|
2600
|
-
return source[Symbol.iterator]();
|
|
2601
|
-
}
|
|
2602
|
-
};
|
|
2603
|
-
return Object.freeze(view);
|
|
2604
|
-
};
|
|
2605
|
-
const lazyMapView = (read) => {
|
|
2606
|
-
const ids = read.ids();
|
|
2607
|
-
const entries = function* () {
|
|
2608
|
-
for (const key of ids) yield [key, read.get(key)];
|
|
2609
|
-
};
|
|
2610
|
-
const values = function* () {
|
|
2611
|
-
for (const key of ids) yield read.get(key);
|
|
2612
|
-
};
|
|
2613
|
-
const view = {
|
|
2614
|
-
get: (key) => {
|
|
2615
|
-
trackKey(key);
|
|
2616
|
-
return read.get(key);
|
|
2617
|
-
},
|
|
2618
|
-
has: (key) => {
|
|
2619
|
-
trackKey(key);
|
|
2620
|
-
return read.has(key);
|
|
2621
|
-
},
|
|
2622
|
-
get size() {
|
|
2623
|
-
trackStructure();
|
|
2624
|
-
return ids.length;
|
|
2625
|
-
},
|
|
2626
|
-
keys: () => {
|
|
2627
|
-
trackStructure();
|
|
2628
|
-
return ids[Symbol.iterator]();
|
|
2629
|
-
},
|
|
2630
|
-
values: () => {
|
|
2631
|
-
trackAll();
|
|
2632
|
-
return values();
|
|
2633
|
-
},
|
|
2634
|
-
entries: () => {
|
|
2635
|
-
trackAll();
|
|
2636
|
-
return entries();
|
|
2637
|
-
},
|
|
2638
|
-
forEach: (callback, thisArg) => {
|
|
2639
|
-
trackAll();
|
|
2640
|
-
for (const key of ids) callback.call(thisArg, read.get(key), key, view);
|
|
2074
|
+
return {
|
|
2075
|
+
materialize(definition) {
|
|
2076
|
+
switch (definition.source.kind) {
|
|
2077
|
+
case "value-input": return valueInput(definition);
|
|
2078
|
+
case "collection-input": return collectionInput(definition);
|
|
2079
|
+
case "document-value": return documentValue(definition);
|
|
2080
|
+
case "document-collection": return documentCollection(definition);
|
|
2081
|
+
case "readable": return readable(definition);
|
|
2082
|
+
case "external-value": return externalValue(definition);
|
|
2083
|
+
case "external-collection": return externalCollection(definition);
|
|
2084
|
+
}
|
|
2641
2085
|
},
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2086
|
+
dispose() {
|
|
2087
|
+
documents.forEach((connection) => connection.close());
|
|
2088
|
+
readables.forEach((connection) => connection.close());
|
|
2089
|
+
documents.clear();
|
|
2090
|
+
readables.clear();
|
|
2645
2091
|
}
|
|
2646
2092
|
};
|
|
2647
|
-
return Object.freeze(view);
|
|
2648
|
-
};
|
|
2649
|
-
const isMapLike = (value) => value instanceof Map || value !== null && typeof value === "object" && typeof value.get === "function" && typeof value.keys === "function" && typeof value.entries === "function";
|
|
2650
|
-
const mapRead = (value) => ({
|
|
2651
|
-
get: (key) => value.get(key),
|
|
2652
|
-
has: (key) => value.has(key),
|
|
2653
|
-
ids: () => Object.freeze([...value.keys()])
|
|
2654
|
-
});
|
|
2655
|
-
const mapChange = (previous, current) => {
|
|
2656
|
-
const added = [];
|
|
2657
|
-
const removed = [];
|
|
2658
|
-
const updated = [];
|
|
2659
|
-
for (const key of previous.keys()) if (!current.has(key)) removed.push({
|
|
2660
|
-
key,
|
|
2661
|
-
before: previous.get(key)
|
|
2662
|
-
});
|
|
2663
|
-
else if (!Object.is(previous.get(key), current.get(key))) updated.push({
|
|
2664
|
-
key,
|
|
2665
|
-
before: previous.get(key),
|
|
2666
|
-
after: current.get(key)
|
|
2667
|
-
});
|
|
2668
|
-
for (const key of current.keys()) if (!previous.has(key)) added.push({
|
|
2669
|
-
key,
|
|
2670
|
-
after: current.get(key)
|
|
2671
|
-
});
|
|
2672
|
-
const before = [...previous.keys()].filter((key) => current.has(key));
|
|
2673
|
-
const after = [...current.keys()].filter((key) => previous.has(key));
|
|
2674
|
-
const orderChanged = before.length !== after.length || before.some((key, index) => key !== after[index]);
|
|
2675
|
-
if (!added.length && !removed.length && !updated.length && !orderChanged) return void 0;
|
|
2676
|
-
return {
|
|
2677
|
-
kind: "incremental",
|
|
2678
|
-
added: Object.freeze(added),
|
|
2679
|
-
removed: Object.freeze(removed),
|
|
2680
|
-
updated: Object.freeze(updated),
|
|
2681
|
-
...orderChanged ? { order: Object.freeze({
|
|
2682
|
-
before: Object.freeze([...previous.keys()]),
|
|
2683
|
-
after: Object.freeze([...current.keys()])
|
|
2684
|
-
}) } : {}
|
|
2685
|
-
};
|
|
2686
|
-
};
|
|
2687
|
-
const sameSelection = (left, right) => {
|
|
2688
|
-
if (left.all !== right.all || left.structure !== right.structure || left.keys.size !== right.keys.size) return false;
|
|
2689
|
-
for (const key of left.keys) if (!right.keys.has(key)) return false;
|
|
2690
|
-
return true;
|
|
2691
|
-
};
|
|
2692
|
-
const selectionAffects = (selection, change) => {
|
|
2693
|
-
if (!change || change.kind === "reset") return true;
|
|
2694
|
-
if (selection.all && (change.added.length || change.removed.length || change.updated.length || change.order)) return true;
|
|
2695
|
-
if (selection.structure && (change.added.length || change.removed.length || change.order)) return true;
|
|
2696
|
-
for (const key of selection.keys) if (change.added.some((entry) => entry.key === key) || change.removed.some((entry) => entry.key === key) || change.updated.some((entry) => entry.key === key)) return true;
|
|
2697
|
-
return false;
|
|
2698
2093
|
};
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
if ("kind" in event && event.kind === "value") return event.value;
|
|
2702
|
-
if ("kind" in event && event.kind === "document") return require_scope.snapshot(event.read);
|
|
2703
|
-
if ("kind" in event && event.kind === "collection") return mapView(event.read);
|
|
2704
|
-
return event;
|
|
2705
|
-
};
|
|
2706
|
-
const sourceOf = (instance) => instance;
|
|
2094
|
+
//#endregion
|
|
2095
|
+
//#region core/src/projection/runtime.ts
|
|
2707
2096
|
const createProjectionRuntime = (options) => {
|
|
2708
|
-
const
|
|
2097
|
+
const scheduler = require_advanced.createScheduler(options?.onError ?? (() => void 0));
|
|
2098
|
+
const sources = createSourceRegistry(scheduler);
|
|
2709
2099
|
const materialized = /* @__PURE__ */ new WeakMap();
|
|
2710
|
-
const
|
|
2711
|
-
let disposed = false;
|
|
2100
|
+
const publicViews = /* @__PURE__ */ new WeakMap();
|
|
2712
2101
|
const scopes = /* @__PURE__ */ new Set();
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
const
|
|
2716
|
-
if (
|
|
2717
|
-
if (
|
|
2718
|
-
|
|
2719
|
-
const nodes = runtime.group({
|
|
2720
|
-
sources,
|
|
2721
|
-
outputs: definition.outputs,
|
|
2722
|
-
build: definition.build
|
|
2723
|
-
});
|
|
2724
|
-
const group = Object.freeze({
|
|
2725
|
-
definition,
|
|
2726
|
-
nodes
|
|
2727
|
-
});
|
|
2728
|
-
groups.set(definition, group);
|
|
2729
|
-
for (let index = 0; index < definition.projections.length; index++) materialized.set(definition.projections[index], {
|
|
2730
|
-
kind: "projection",
|
|
2731
|
-
node: nodes[index]
|
|
2732
|
-
});
|
|
2733
|
-
if (requester) requester.materialized.push(definition);
|
|
2734
|
-
return group;
|
|
2102
|
+
const assertAccess = (definition, requester) => {
|
|
2103
|
+
scheduler.assertActive();
|
|
2104
|
+
const owner = definition.owner;
|
|
2105
|
+
if (owner === void 0) return;
|
|
2106
|
+
if (owner !== requester) throw new TypeError("Projection belongs to another scope.");
|
|
2107
|
+
if (!requester?.active) throw new require_advanced.ProjectionDisposedError();
|
|
2735
2108
|
};
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
value: values.input.value,
|
|
2760
|
-
update: (next) => ({
|
|
2761
|
-
kind: "changed",
|
|
2762
|
-
value: next.input.value
|
|
2763
|
-
})
|
|
2764
|
-
})
|
|
2765
|
-
});
|
|
2766
|
-
break;
|
|
2767
|
-
}
|
|
2768
|
-
case "collection-input": {
|
|
2769
|
-
const source = runtime.collectionInput(definition.initial);
|
|
2770
|
-
write = {
|
|
2771
|
-
kind: "collection-input",
|
|
2772
|
-
source: source.source,
|
|
2773
|
-
update: source.update
|
|
2774
|
-
};
|
|
2775
|
-
instance = runtime.map(source.source, (_key, value) => value);
|
|
2776
|
-
break;
|
|
2777
|
-
}
|
|
2778
|
-
case "readable": {
|
|
2779
|
-
const source = runtime.fromReadable(definition.readable, { isEqual: definition.isEqual });
|
|
2780
|
-
instance = runtime.value({
|
|
2781
|
-
sources: { source },
|
|
2782
|
-
build: (values) => ({
|
|
2783
|
-
value: values.source.value,
|
|
2784
|
-
update: (next) => ({
|
|
2785
|
-
kind: "changed",
|
|
2786
|
-
value: next.source.value
|
|
2787
|
-
})
|
|
2788
|
-
})
|
|
2789
|
-
});
|
|
2790
|
-
break;
|
|
2791
|
-
}
|
|
2792
|
-
case "source-value":
|
|
2793
|
-
{
|
|
2794
|
-
const source = runtime.fromSource(definition.source);
|
|
2795
|
-
instance = runtime.value({
|
|
2796
|
-
sources: { source },
|
|
2797
|
-
build: (values) => ({
|
|
2798
|
-
value: values.source.value,
|
|
2799
|
-
update: (next) => ({
|
|
2800
|
-
kind: "changed",
|
|
2801
|
-
value: next.source.value
|
|
2802
|
-
})
|
|
2803
|
-
})
|
|
2804
|
-
});
|
|
2805
|
-
}
|
|
2806
|
-
break;
|
|
2807
|
-
case "source-collection": {
|
|
2808
|
-
const source = runtime.fromCollectionSource(definition.source);
|
|
2809
|
-
instance = runtime.map(source, (_key, value) => value);
|
|
2810
|
-
break;
|
|
2811
|
-
}
|
|
2812
|
-
case "document": {
|
|
2813
|
-
const document = runtime.document(definition.document);
|
|
2814
|
-
if (!definition.selector) {
|
|
2815
|
-
instance = runtime.value({
|
|
2816
|
-
sources: { document },
|
|
2817
|
-
build: (values) => ({
|
|
2818
|
-
value: require_scope.snapshot(values.document.read),
|
|
2819
|
-
update: (next) => ({
|
|
2820
|
-
kind: "changed",
|
|
2821
|
-
value: require_scope.snapshot(next.document.read)
|
|
2822
|
-
})
|
|
2823
|
-
})
|
|
2824
|
-
});
|
|
2825
|
-
break;
|
|
2826
|
-
}
|
|
2827
|
-
const state = require_notification.accessOf(definition.document);
|
|
2828
|
-
try {
|
|
2829
|
-
const collection = document.collection(definition.selector);
|
|
2830
|
-
instance = runtime.map(collection, (_id, entry) => entry);
|
|
2831
|
-
break;
|
|
2832
|
-
} catch {
|
|
2833
|
-
const selected = document.targets(definition.selector);
|
|
2834
|
-
const address = compilePath(state.schema, "value", definition.selector).address;
|
|
2835
|
-
instance = runtime.value({
|
|
2836
|
-
sources: { selected },
|
|
2837
|
-
build: () => ({
|
|
2838
|
-
value: require_issue.read(require_scope.snapshot(state.document), address, state.schema),
|
|
2839
|
-
update: () => ({
|
|
2840
|
-
kind: "changed",
|
|
2841
|
-
value: require_issue.read(require_scope.snapshot(state.document), address, state.schema)
|
|
2842
|
-
})
|
|
2843
|
-
})
|
|
2844
|
-
});
|
|
2845
|
-
}
|
|
2846
|
-
break;
|
|
2847
|
-
}
|
|
2848
|
-
case "derive": {
|
|
2849
|
-
const sources = Object.fromEntries(definition.dependencies.map((dependency, index) => [`d${index}`, sourceOf(materialize(dependency, owner))]));
|
|
2850
|
-
instance = runtime.value({
|
|
2851
|
-
sources,
|
|
2852
|
-
build: (values) => ({
|
|
2853
|
-
value: definition.compute(...Object.values(values).map(currentValue)),
|
|
2854
|
-
update: (next) => ({
|
|
2855
|
-
kind: "changed",
|
|
2856
|
-
value: definition.compute(...Object.values(next).map(currentValue))
|
|
2857
|
-
})
|
|
2858
|
-
})
|
|
2859
|
-
}, { isEqual: definition.isEqual });
|
|
2860
|
-
break;
|
|
2861
|
-
}
|
|
2862
|
-
case "incremental-value": {
|
|
2863
|
-
const sources = Object.fromEntries(Object.entries(definition.dependencies).map(([key, dependency]) => [key, sourceOf(materialize(dependency, owner))]));
|
|
2864
|
-
instance = runtime.value({
|
|
2865
|
-
sources,
|
|
2866
|
-
build: definition.build
|
|
2867
|
-
}, { isEqual: definition.isEqual });
|
|
2868
|
-
break;
|
|
2869
|
-
}
|
|
2870
|
-
case "incremental-collection": {
|
|
2871
|
-
const sources = Object.fromEntries(Object.entries(definition.dependencies).map(([key, dependency]) => [key, sourceOf(materialize(dependency, owner))]));
|
|
2872
|
-
instance = runtime.collection({
|
|
2873
|
-
sources,
|
|
2874
|
-
build: definition.build,
|
|
2875
|
-
isEqual: definition.isEqual,
|
|
2876
|
-
name: definition.name
|
|
2877
|
-
});
|
|
2878
|
-
break;
|
|
2879
|
-
}
|
|
2109
|
+
const rememberScoped = (definition, requester) => {
|
|
2110
|
+
if (requester && definition.owner === requester) requester.materialized.push(definition);
|
|
2111
|
+
};
|
|
2112
|
+
const materializeProducer = (definition, requester) => {
|
|
2113
|
+
assertAccess(definition, requester);
|
|
2114
|
+
const existing = materialized.get(definition);
|
|
2115
|
+
if (existing) return existing;
|
|
2116
|
+
let result;
|
|
2117
|
+
if (definition.kind === "source") {
|
|
2118
|
+
const source = sources.materialize(definition);
|
|
2119
|
+
result = Object.freeze({
|
|
2120
|
+
record: source.producer,
|
|
2121
|
+
outputs: Object.freeze([source.output]),
|
|
2122
|
+
...source.write ? { write: source.write } : {}
|
|
2123
|
+
});
|
|
2124
|
+
} else {
|
|
2125
|
+
if (definition.owner === void 0 && definition.dependencies.some((dependency) => require_advanced.producerOf(dependency).owner !== void 0)) throw new TypeError("A root projection cannot depend on a scoped projection.");
|
|
2126
|
+
const dependencies = definition.dependencies.map((dependency) => resolveOutput(dependency, requester));
|
|
2127
|
+
const processor = createProcessor(scheduler, definition, Object.freeze(dependencies));
|
|
2128
|
+
result = Object.freeze({
|
|
2129
|
+
record: processor,
|
|
2130
|
+
outputs: processor.outputs
|
|
2131
|
+
});
|
|
2880
2132
|
}
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2133
|
+
materialized.set(definition, result);
|
|
2134
|
+
rememberScoped(definition, requester);
|
|
2135
|
+
return result;
|
|
2136
|
+
};
|
|
2137
|
+
const resolveOutput = (projection, requester) => {
|
|
2138
|
+
const ref = require_advanced.projectionRef(projection);
|
|
2139
|
+
const output = materializeProducer(ref.producer, requester).outputs[ref.output];
|
|
2140
|
+
if (!output) throw new TypeError("Projection output does not exist.");
|
|
2141
|
+
return output;
|
|
2142
|
+
};
|
|
2143
|
+
const assertOutput = (output) => {
|
|
2144
|
+
scheduler.assertActive();
|
|
2145
|
+
if (output.owner.disposed) throw new require_advanced.ProjectionDisposedError();
|
|
2146
|
+
if (output.owner.fault) throw output.owner.fault;
|
|
2891
2147
|
};
|
|
2892
|
-
const
|
|
2893
|
-
|
|
2894
|
-
const current =
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
if (record) record.collection = {
|
|
2148
|
+
const publicCurrent = (output) => {
|
|
2149
|
+
assertOutput(output);
|
|
2150
|
+
const current = output.current();
|
|
2151
|
+
const revision = output.revision();
|
|
2152
|
+
const cached = publicViews.get(output);
|
|
2153
|
+
if (cached?.revision === revision) return cached.value;
|
|
2154
|
+
if (output.kind === "collection") {
|
|
2155
|
+
const value = require_advanced.collectionView(current);
|
|
2156
|
+
publicViews.set(output, {
|
|
2902
2157
|
revision,
|
|
2903
2158
|
value
|
|
2904
|
-
};
|
|
2159
|
+
});
|
|
2905
2160
|
return value;
|
|
2906
2161
|
}
|
|
2907
2162
|
if (isMapLike(current)) {
|
|
2908
|
-
const
|
|
2909
|
-
|
|
2910
|
-
const revision = instance.revision();
|
|
2911
|
-
if (existing?.revision === revision) return existing.value;
|
|
2912
|
-
const value = mapView(mapRead(current));
|
|
2913
|
-
if (record) record.collection = {
|
|
2163
|
+
const value = require_advanced.snapshotCollectionView(require_advanced.mapRead(current));
|
|
2164
|
+
publicViews.set(output, {
|
|
2914
2165
|
revision,
|
|
2915
2166
|
value
|
|
2916
|
-
};
|
|
2167
|
+
});
|
|
2917
2168
|
return value;
|
|
2918
2169
|
}
|
|
2170
|
+
publicViews.delete(output);
|
|
2919
2171
|
return current;
|
|
2920
2172
|
};
|
|
2921
|
-
const
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
revision: () => materialize(projection, requester).revision(),
|
|
2925
|
-
subscribe: (listener) => materialize(projection, requester).subscribe(listener)
|
|
2926
|
-
});
|
|
2927
|
-
let initialized = false;
|
|
2928
|
-
let value;
|
|
2929
|
-
let selectedRevision = 0;
|
|
2930
|
-
let sourceRevision = -1;
|
|
2931
|
-
let selection = Object.freeze({
|
|
2932
|
-
keys: /* @__PURE__ */ new Set(),
|
|
2933
|
-
all: true,
|
|
2934
|
-
structure: false
|
|
2935
|
-
});
|
|
2936
|
-
let previousCollection;
|
|
2937
|
-
let unsubscribeSource;
|
|
2938
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
2939
|
-
const updateCollectionSnapshot = () => {
|
|
2940
|
-
const current = get(projection, requester);
|
|
2941
|
-
previousCollection = isMapLike(current) ? current : void 0;
|
|
2942
|
-
};
|
|
2943
|
-
const evaluate = () => {
|
|
2944
|
-
const tracker = {
|
|
2945
|
-
keys: /* @__PURE__ */ new Set(),
|
|
2946
|
-
all: false,
|
|
2947
|
-
structure: false
|
|
2948
|
-
};
|
|
2949
|
-
const previousTracker = activeTracker;
|
|
2950
|
-
activeTracker = tracker;
|
|
2951
|
-
let source;
|
|
2952
|
-
let next;
|
|
2953
|
-
try {
|
|
2954
|
-
source = get(projection, requester);
|
|
2955
|
-
next = selector(source);
|
|
2956
|
-
} finally {
|
|
2957
|
-
activeTracker = previousTracker;
|
|
2958
|
-
}
|
|
2959
|
-
const nextSelection = Object.freeze({
|
|
2960
|
-
keys: new Set(tracker.keys),
|
|
2961
|
-
all: tracker.all || isMapLike(source) && tracker.keys.size === 0,
|
|
2962
|
-
structure: tracker.structure
|
|
2963
|
-
});
|
|
2964
|
-
const changed = !initialized || !equality(value, next);
|
|
2965
|
-
if (changed) {
|
|
2966
|
-
if (initialized) selectedRevision++;
|
|
2967
|
-
value = next;
|
|
2968
|
-
}
|
|
2969
|
-
selection = nextSelection;
|
|
2970
|
-
initialized = true;
|
|
2971
|
-
sourceRevision = materialize(projection, requester).revision();
|
|
2972
|
-
updateCollectionSnapshot();
|
|
2973
|
-
return changed;
|
|
2974
|
-
};
|
|
2975
|
-
const ensureCurrent = () => {
|
|
2976
|
-
const revision = materialize(projection, requester).revision();
|
|
2977
|
-
if (!initialized || !unsubscribeSource && sourceRevision !== revision) evaluate();
|
|
2978
|
-
return value;
|
|
2979
|
-
};
|
|
2980
|
-
const onProjectionChange = (incoming) => {
|
|
2981
|
-
let change = incoming;
|
|
2982
|
-
if (!change && previousCollection) {
|
|
2983
|
-
const current = get(projection, requester);
|
|
2984
|
-
if (isMapLike(current)) {
|
|
2985
|
-
change = mapChange(previousCollection, current);
|
|
2986
|
-
previousCollection = current;
|
|
2987
|
-
if (!change) {
|
|
2988
|
-
sourceRevision = materialize(projection, requester).revision();
|
|
2989
|
-
return;
|
|
2990
|
-
}
|
|
2991
|
-
} else previousCollection = void 0;
|
|
2992
|
-
}
|
|
2993
|
-
if (!selectionAffects(selection, change)) {
|
|
2994
|
-
sourceRevision = materialize(projection, requester).revision();
|
|
2995
|
-
updateCollectionSnapshot();
|
|
2996
|
-
return;
|
|
2997
|
-
}
|
|
2998
|
-
const previousSelection = selection;
|
|
2999
|
-
const changed = evaluate();
|
|
3000
|
-
if (unsubscribeSource && !sameSelection(previousSelection, selection)) {
|
|
3001
|
-
unsubscribeSource();
|
|
3002
|
-
unsubscribeSource = materialize(projection, requester).subscribe(onProjectionChange);
|
|
3003
|
-
}
|
|
3004
|
-
if (changed) Array.from(listeners).forEach((listener) => listener());
|
|
3005
|
-
};
|
|
3006
|
-
const installSource = () => {
|
|
3007
|
-
if (!unsubscribeSource) unsubscribeSource = materialize(projection, requester).subscribe(onProjectionChange);
|
|
3008
|
-
};
|
|
2173
|
+
const get = (projection, requester) => publicCurrent(resolveOutput(projection, requester));
|
|
2174
|
+
const readableSource = (projection, requester) => {
|
|
2175
|
+
const output = resolveOutput(projection, requester);
|
|
3009
2176
|
return Object.freeze({
|
|
3010
|
-
|
|
2177
|
+
kind: output.kind,
|
|
2178
|
+
current: () => get(projection, requester),
|
|
3011
2179
|
revision: () => {
|
|
3012
|
-
|
|
3013
|
-
return
|
|
2180
|
+
assertOutput(output);
|
|
2181
|
+
return output.revision();
|
|
3014
2182
|
},
|
|
3015
|
-
subscribe:
|
|
3016
|
-
ensureCurrent();
|
|
3017
|
-
listeners.add(listener);
|
|
3018
|
-
installSource();
|
|
3019
|
-
return () => {
|
|
3020
|
-
listeners.delete(listener);
|
|
3021
|
-
if (!listeners.size && unsubscribeSource) {
|
|
3022
|
-
unsubscribeSource();
|
|
3023
|
-
unsubscribeSource = void 0;
|
|
3024
|
-
}
|
|
3025
|
-
};
|
|
3026
|
-
}
|
|
2183
|
+
subscribe: output.subscribe
|
|
3027
2184
|
});
|
|
3028
2185
|
};
|
|
2186
|
+
const makeReadable = (projection, selector, equality, requester) => {
|
|
2187
|
+
const source = readableSource(projection, requester);
|
|
2188
|
+
return selector ? createSelectorReadable(source, selector, equality) : createDirectReadable(source);
|
|
2189
|
+
};
|
|
3029
2190
|
function readable(projection, selector, equality) {
|
|
3030
2191
|
return makeReadable(projection, selector, equality);
|
|
3031
2192
|
}
|
|
2193
|
+
const inputWrite = (target, requester) => {
|
|
2194
|
+
const ref = require_advanced.projectionRef(target);
|
|
2195
|
+
if (ref.output !== 0 || ref.producer.kind !== "source") throw new TypeError("Projection is not an input.");
|
|
2196
|
+
if (ref.producer.source.kind !== "value-input" && ref.producer.source.kind !== "collection-input") throw new TypeError("Projection is not an input.");
|
|
2197
|
+
const write = materializeProducer(ref.producer, requester).write;
|
|
2198
|
+
if (!write) throw new TypeError("Projection input is not writable.");
|
|
2199
|
+
return write;
|
|
2200
|
+
};
|
|
3032
2201
|
const setInput = (target, value, requester) => {
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
record.set(value);
|
|
2202
|
+
const write = inputWrite(target, requester);
|
|
2203
|
+
if (write.kind !== "value") throw new TypeError("Projection is not a value input.");
|
|
2204
|
+
write.set(value);
|
|
3037
2205
|
};
|
|
3038
2206
|
const updateInput = (target, run, requester) => {
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
2207
|
+
const write = inputWrite(target, requester);
|
|
2208
|
+
if (write.kind !== "collection") throw new TypeError("Projection is not a collection input.");
|
|
2209
|
+
write.update(run);
|
|
2210
|
+
};
|
|
2211
|
+
function batch(optionsOrCallback, maybeCallback) {
|
|
2212
|
+
return typeof optionsOrCallback === "function" ? scheduler.batch(optionsOrCallback) : scheduler.batch(optionsOrCallback, maybeCallback);
|
|
2213
|
+
}
|
|
2214
|
+
const disposeScope = (state) => {
|
|
2215
|
+
if (!state.active) return;
|
|
2216
|
+
scheduler.assertIdle();
|
|
2217
|
+
state.active = false;
|
|
2218
|
+
state.subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
2219
|
+
state.subscriptions.clear();
|
|
2220
|
+
for (let index = state.materialized.length - 1; index >= 0; index--) {
|
|
2221
|
+
const definition = state.materialized[index];
|
|
2222
|
+
const current = materialized.get(definition);
|
|
2223
|
+
if (!current) continue;
|
|
2224
|
+
scheduler.releaseProducer(current.record);
|
|
2225
|
+
materialized.delete(definition);
|
|
2226
|
+
}
|
|
2227
|
+
state.materialized.length = 0;
|
|
2228
|
+
scopes.delete(state);
|
|
3043
2229
|
};
|
|
3044
2230
|
const createScope = () => {
|
|
3045
|
-
|
|
2231
|
+
scheduler.assertIdle();
|
|
3046
2232
|
const state = {
|
|
3047
2233
|
active: true,
|
|
3048
2234
|
materialized: [],
|
|
@@ -3051,33 +2237,26 @@ const createProjectionRuntime = (options) => {
|
|
|
3051
2237
|
scopes.add(state);
|
|
3052
2238
|
const assertActive = () => {
|
|
3053
2239
|
if (!state.active) throw new require_advanced.ProjectionDisposedError();
|
|
2240
|
+
scheduler.assertActive();
|
|
3054
2241
|
};
|
|
3055
2242
|
const own = (projection) => {
|
|
3056
2243
|
assertActive();
|
|
3057
|
-
|
|
3058
|
-
const dependencies = definition.kind === "derive" ? definition.dependencies : definition.kind === "incremental-value" || definition.kind === "incremental-collection" ? Object.values(definition.dependencies) : definition.kind === "incremental-group-output" ? Object.values(definition.group.dependencies) : [];
|
|
3059
|
-
for (const dependency of dependencies) {
|
|
3060
|
-
const dependencyOwner = require_advanced.ownerOf(dependency);
|
|
3061
|
-
if (dependencyOwner && dependencyOwner !== state) throw new TypeError("A scope cannot depend on another scope.");
|
|
3062
|
-
}
|
|
3063
|
-
require_advanced.ownDefinition(projection, state);
|
|
3064
|
-
return projection;
|
|
2244
|
+
return require_advanced.ownProjection(projection, state);
|
|
3065
2245
|
};
|
|
3066
|
-
const scopedInput = Object.assign((initial, equality) => own(require_advanced.input(initial, equality)), { collection: (initial) => own(require_advanced.input.collection(initial)) });
|
|
3067
|
-
const scopedDerive = (dependencies, compute, equality) => own(require_advanced.derive(dependencies, compute, equality));
|
|
3068
2246
|
const ownOutputTree = (tree) => {
|
|
3069
2247
|
if (require_advanced.isProjection(tree)) return own(tree);
|
|
3070
2248
|
if (!tree || typeof tree !== "object") throw new TypeError("Incremental group output tree must be an object.");
|
|
3071
2249
|
for (const value of Object.values(tree)) ownOutputTree(value);
|
|
3072
2250
|
return tree;
|
|
3073
2251
|
};
|
|
2252
|
+
const scopedInput = Object.assign((initial, equality) => own(require_advanced.input(initial, equality)), { collection: (initial) => own(require_advanced.input.collection(initial)) });
|
|
2253
|
+
const scopedDerive = (dependencies, compute, equality) => own(require_advanced.derive(dependencies, compute, equality));
|
|
3074
2254
|
const scopedIncremental = Object.assign((dependencies, processor) => own(require_advanced.incremental(dependencies, processor)), {
|
|
3075
2255
|
collection: (dependencies, processor) => own(require_advanced.incremental.collection(dependencies, processor)),
|
|
3076
2256
|
group: (dependencies, defineOutputs, processor) => ownOutputTree(require_advanced.incremental.group(dependencies, defineOutputs, processor))
|
|
3077
2257
|
});
|
|
3078
2258
|
function scopeReadable(projection, selector, equality) {
|
|
3079
2259
|
assertActive();
|
|
3080
|
-
materialize(projection, state);
|
|
3081
2260
|
const source = makeReadable(projection, selector, equality, state);
|
|
3082
2261
|
return Object.freeze({
|
|
3083
2262
|
current: () => {
|
|
@@ -3105,7 +2284,7 @@ const createProjectionRuntime = (options) => {
|
|
|
3105
2284
|
}
|
|
3106
2285
|
function scopeBatch(optionsOrCallback, maybeCallback) {
|
|
3107
2286
|
assertActive();
|
|
3108
|
-
return typeof optionsOrCallback === "function" ?
|
|
2287
|
+
return typeof optionsOrCallback === "function" ? batch(optionsOrCallback) : batch(optionsOrCallback, maybeCallback);
|
|
3109
2288
|
}
|
|
3110
2289
|
return Object.freeze({
|
|
3111
2290
|
input: scopedInput,
|
|
@@ -3125,41 +2304,19 @@ const createProjectionRuntime = (options) => {
|
|
|
3125
2304
|
updateInput(target, run, state);
|
|
3126
2305
|
},
|
|
3127
2306
|
batch: scopeBatch,
|
|
3128
|
-
dispose: () =>
|
|
3129
|
-
if (!state.active) return;
|
|
3130
|
-
runtime.assertIdle();
|
|
3131
|
-
state.active = false;
|
|
3132
|
-
state.subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
3133
|
-
for (const definition of state.materialized.reverse()) {
|
|
3134
|
-
const group = groups.get(definition);
|
|
3135
|
-
if (group) {
|
|
3136
|
-
runtime.releaseNode(group.nodes[0]);
|
|
3137
|
-
groups.delete(definition);
|
|
3138
|
-
group.definition.projections.forEach((projection) => materialized.delete(projection));
|
|
3139
|
-
continue;
|
|
3140
|
-
}
|
|
3141
|
-
const record = materialized.get(definition);
|
|
3142
|
-
if (!record) continue;
|
|
3143
|
-
runtime.releaseNode(record.node);
|
|
3144
|
-
if (record.kind !== "projection") runtime.releaseInput(record.source);
|
|
3145
|
-
materialized.delete(definition);
|
|
3146
|
-
}
|
|
3147
|
-
state.materialized.length = 0;
|
|
3148
|
-
scopes.delete(state);
|
|
3149
|
-
}
|
|
2307
|
+
dispose: () => disposeScope(state)
|
|
3150
2308
|
});
|
|
3151
2309
|
};
|
|
3152
|
-
|
|
2310
|
+
return Object.freeze({
|
|
3153
2311
|
get,
|
|
3154
2312
|
readable,
|
|
3155
2313
|
set: setInput,
|
|
3156
2314
|
update: updateInput,
|
|
3157
|
-
batch
|
|
2315
|
+
batch,
|
|
3158
2316
|
scope: createScope,
|
|
3159
2317
|
dispose: () => {
|
|
3160
|
-
if (
|
|
3161
|
-
|
|
3162
|
-
disposed = true;
|
|
2318
|
+
if (!scheduler.active) return;
|
|
2319
|
+
scheduler.assertIdle();
|
|
3163
2320
|
for (const scope of scopes) {
|
|
3164
2321
|
scope.active = false;
|
|
3165
2322
|
scope.subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
@@ -3167,35 +2324,35 @@ const createProjectionRuntime = (options) => {
|
|
|
3167
2324
|
scope.materialized.length = 0;
|
|
3168
2325
|
}
|
|
3169
2326
|
scopes.clear();
|
|
3170
|
-
|
|
2327
|
+
sources.dispose();
|
|
2328
|
+
scheduler.dispose();
|
|
3171
2329
|
}
|
|
3172
|
-
};
|
|
3173
|
-
return Object.freeze(store);
|
|
2330
|
+
});
|
|
3174
2331
|
};
|
|
3175
2332
|
//#endregion
|
|
3176
|
-
exports.DocumentDisposedError =
|
|
3177
|
-
exports.DocumentReentrancyError =
|
|
3178
|
-
exports.ParseError =
|
|
2333
|
+
exports.DocumentDisposedError = require_access.DocumentDisposedError;
|
|
2334
|
+
exports.DocumentReentrancyError = require_access.DocumentReentrancyError;
|
|
2335
|
+
exports.ParseError = require_access.ParseError;
|
|
3179
2336
|
exports.ProjectionDisposedError = require_advanced.ProjectionDisposedError;
|
|
3180
2337
|
exports.ProjectionError = require_advanced.ProjectionError;
|
|
3181
|
-
exports.TransactionRejected =
|
|
2338
|
+
exports.TransactionRejected = require_access.TransactionRejected;
|
|
3182
2339
|
exports.asReadable = asReadable;
|
|
3183
2340
|
exports.createDocument = createDocument;
|
|
3184
2341
|
exports.createProjectionRuntime = createProjectionRuntime;
|
|
3185
2342
|
exports.derive = require_advanced.derive;
|
|
3186
|
-
exports.field = field;
|
|
2343
|
+
exports.field = require_advanced.field;
|
|
3187
2344
|
exports.input = require_advanced.input;
|
|
3188
|
-
exports.list = list;
|
|
3189
|
-
exports.map = map;
|
|
3190
|
-
exports.object = object;
|
|
2345
|
+
exports.list = require_advanced.list;
|
|
2346
|
+
exports.map = require_advanced.map;
|
|
2347
|
+
exports.object = require_advanced.object;
|
|
3191
2348
|
exports.observe = require_advanced.observe;
|
|
3192
|
-
exports.optional = optional;
|
|
3193
|
-
exports.parse =
|
|
2349
|
+
exports.optional = require_advanced.optional;
|
|
2350
|
+
exports.parse = require_access.parse;
|
|
3194
2351
|
exports.read = read;
|
|
3195
|
-
exports.replace =
|
|
3196
|
-
exports.snapshot =
|
|
3197
|
-
exports.table = table;
|
|
3198
|
-
exports.tree = tree;
|
|
3199
|
-
exports.variant = variant;
|
|
2352
|
+
exports.replace = require_access.replace;
|
|
2353
|
+
exports.snapshot = require_access.snapshot;
|
|
2354
|
+
exports.table = require_advanced.table;
|
|
2355
|
+
exports.tree = require_advanced.tree;
|
|
2356
|
+
exports.variant = require_advanced.variant;
|
|
3200
2357
|
|
|
3201
2358
|
//# sourceMappingURL=index.cjs.map
|