doxum 0.1.17 → 0.1.18
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 -3
- package/dist/advanced-DgRnyRAc.js +233 -0
- package/dist/advanced-DgRnyRAc.js.map +1 -0
- package/dist/advanced-Dgu8-bPS.cjs +274 -0
- package/dist/advanced-Dgu8-bPS.cjs.map +1 -0
- package/dist/{definition-Bf8Z7xtX.d.cts → advanced-GTwIWcn6.d.cts} +44 -7
- package/dist/{definition-BdLGD8Rq.d.ts → advanced-c0F3gpLG.d.ts} +44 -7
- package/dist/advanced.cjs +2 -149
- package/dist/advanced.d.cts +2 -39
- package/dist/advanced.d.ts +2 -39
- package/dist/advanced.js +1 -148
- package/dist/index.cjs +346 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -2
- package/dist/index.d.ts +22 -2
- package/dist/index.js +342 -33
- package/dist/index.js.map +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
- package/skills/doxum-runtime/references/projections.en.md +13 -1
- package/skills/doxum-runtime/references/projections.zh-CN.md +9 -1
- package/dist/advanced.cjs.map +0 -1
- package/dist/advanced.js.map +0 -1
- package/dist/definition-DUo1lfQ8.js +0 -71
- package/dist/definition-DUo1lfQ8.js.map +0 -1
- package/dist/definition-De6rhTlZ.cjs +0 -106
- package/dist/definition-De6rhTlZ.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -3,7 +3,7 @@ const require_issue = require("./issue-DhrNdQNg.cjs");
|
|
|
3
3
|
const require_scope = require("./scope-Ezs-Y3TY.cjs");
|
|
4
4
|
const require_notification = require("./notification-CDSUfiip.cjs");
|
|
5
5
|
const require_driver = require("./driver-BCyfqxsl.cjs");
|
|
6
|
-
const
|
|
6
|
+
const require_advanced = require("./advanced-Dgu8-bPS.cjs");
|
|
7
7
|
//#region core/src/schema.ts
|
|
8
8
|
const node = (value) => Object.freeze(value);
|
|
9
9
|
const field = (validator) => node({
|
|
@@ -1196,7 +1196,9 @@ const createScheduler = (onError) => {
|
|
|
1196
1196
|
phase = "compute";
|
|
1197
1197
|
lock(true);
|
|
1198
1198
|
try {
|
|
1199
|
-
pending.forEach((source) =>
|
|
1199
|
+
pending.forEach((source) => {
|
|
1200
|
+
if (source.shouldSettle?.() ?? true) source.consumers.forEach(enqueue);
|
|
1201
|
+
});
|
|
1200
1202
|
while (heap.length) {
|
|
1201
1203
|
const node = pop();
|
|
1202
1204
|
if (node.disposed) continue;
|
|
@@ -1338,12 +1340,29 @@ const createScheduler = (onError) => {
|
|
|
1338
1340
|
unregisterSource(handle) {
|
|
1339
1341
|
const record = records.get(handle);
|
|
1340
1342
|
if (record) {
|
|
1343
|
+
assertIdle();
|
|
1344
|
+
if (record.consumers.size) throw new Error("Projection source is still used by a node.");
|
|
1341
1345
|
record.disposed = true;
|
|
1342
1346
|
pending.delete(record);
|
|
1343
1347
|
record.clear();
|
|
1344
1348
|
records.delete(handle);
|
|
1345
1349
|
}
|
|
1346
1350
|
},
|
|
1351
|
+
releaseNode(handle) {
|
|
1352
|
+
assertIdle();
|
|
1353
|
+
const node = records.get(handle);
|
|
1354
|
+
if (!node || !nodes.has(node)) throw new Error("Unknown projection node.");
|
|
1355
|
+
if (node.consumers.size) throw new Error("Projection node is still used by another node.");
|
|
1356
|
+
node.disposed = true;
|
|
1357
|
+
node.sources.forEach((source) => source.consumers.delete(node));
|
|
1358
|
+
node.release();
|
|
1359
|
+
node.clear();
|
|
1360
|
+
nodes.delete(node);
|
|
1361
|
+
records.delete(handle);
|
|
1362
|
+
pending.delete(node);
|
|
1363
|
+
queued.delete(node);
|
|
1364
|
+
emissions.delete(node);
|
|
1365
|
+
},
|
|
1347
1366
|
source(handle) {
|
|
1348
1367
|
assertActive();
|
|
1349
1368
|
const source = records.get(handle);
|
|
@@ -1685,6 +1704,149 @@ const createSources = (scheduler) => {
|
|
|
1685
1704
|
}
|
|
1686
1705
|
};
|
|
1687
1706
|
};
|
|
1707
|
+
const collectionInput = (initial) => {
|
|
1708
|
+
const values = new Map(initial);
|
|
1709
|
+
const touched = /* @__PURE__ */ new Map();
|
|
1710
|
+
let beforeIds;
|
|
1711
|
+
let revision = 0;
|
|
1712
|
+
let cause;
|
|
1713
|
+
const handle = Object.freeze({ kind: "collection" });
|
|
1714
|
+
const change = () => {
|
|
1715
|
+
const added = [];
|
|
1716
|
+
const updated = [];
|
|
1717
|
+
const removed = [];
|
|
1718
|
+
for (const [key, before] of touched) {
|
|
1719
|
+
const afterPresent = values.has(key);
|
|
1720
|
+
if (!before.present && afterPresent) added.push({
|
|
1721
|
+
key,
|
|
1722
|
+
after: values.get(key)
|
|
1723
|
+
});
|
|
1724
|
+
else if (before.present && !afterPresent) removed.push({
|
|
1725
|
+
key,
|
|
1726
|
+
before: before.value
|
|
1727
|
+
});
|
|
1728
|
+
else if (before.present && afterPresent && !Object.is(before.value, values.get(key))) updated.push({
|
|
1729
|
+
key,
|
|
1730
|
+
before: before.value,
|
|
1731
|
+
after: values.get(key)
|
|
1732
|
+
});
|
|
1733
|
+
}
|
|
1734
|
+
let order;
|
|
1735
|
+
if (beforeIds) {
|
|
1736
|
+
const afterIds = [...values.keys()];
|
|
1737
|
+
const beforeKeys = new Set(beforeIds);
|
|
1738
|
+
const afterKeys = new Set(afterIds);
|
|
1739
|
+
const beforeCommon = beforeIds.filter((key) => afterKeys.has(key));
|
|
1740
|
+
const afterCommon = afterIds.filter((key) => beforeKeys.has(key));
|
|
1741
|
+
if (beforeCommon.some((key, index) => key !== afterCommon[index])) order = Object.freeze({
|
|
1742
|
+
before: beforeIds,
|
|
1743
|
+
after: Object.freeze(afterIds)
|
|
1744
|
+
});
|
|
1745
|
+
}
|
|
1746
|
+
if (!added.length && !updated.length && !removed.length && !order) return void 0;
|
|
1747
|
+
return Object.freeze({
|
|
1748
|
+
kind: "incremental",
|
|
1749
|
+
added: Object.freeze(added),
|
|
1750
|
+
updated: Object.freeze(updated),
|
|
1751
|
+
removed: Object.freeze(removed),
|
|
1752
|
+
...order ? { order } : {}
|
|
1753
|
+
});
|
|
1754
|
+
};
|
|
1755
|
+
const record = {
|
|
1756
|
+
consumers: /* @__PURE__ */ new Set(),
|
|
1757
|
+
disposed: false,
|
|
1758
|
+
fault: void 0,
|
|
1759
|
+
revision: () => revision,
|
|
1760
|
+
reset: () => false,
|
|
1761
|
+
shouldSettle: () => change() !== void 0,
|
|
1762
|
+
clear: () => {
|
|
1763
|
+
touched.clear();
|
|
1764
|
+
beforeIds = void 0;
|
|
1765
|
+
cause = void 0;
|
|
1766
|
+
},
|
|
1767
|
+
context: (active) => {
|
|
1768
|
+
assertScope(active);
|
|
1769
|
+
const read = Object.freeze({
|
|
1770
|
+
get: (key) => {
|
|
1771
|
+
assertScope(active);
|
|
1772
|
+
return values.get(key);
|
|
1773
|
+
},
|
|
1774
|
+
has: (key) => {
|
|
1775
|
+
assertScope(active);
|
|
1776
|
+
return values.has(key);
|
|
1777
|
+
},
|
|
1778
|
+
ids: () => {
|
|
1779
|
+
assertScope(active);
|
|
1780
|
+
return Object.freeze([...values.keys()]);
|
|
1781
|
+
}
|
|
1782
|
+
});
|
|
1783
|
+
return Object.freeze({
|
|
1784
|
+
kind: "collection",
|
|
1785
|
+
read,
|
|
1786
|
+
change: change(),
|
|
1787
|
+
revision,
|
|
1788
|
+
cause
|
|
1789
|
+
});
|
|
1790
|
+
}
|
|
1791
|
+
};
|
|
1792
|
+
scheduler.register(handle, record);
|
|
1793
|
+
return {
|
|
1794
|
+
source: handle,
|
|
1795
|
+
update(run) {
|
|
1796
|
+
scheduler.assertIdle();
|
|
1797
|
+
const staged = /* @__PURE__ */ new Map();
|
|
1798
|
+
let active = true;
|
|
1799
|
+
const draft = Object.freeze({
|
|
1800
|
+
get: (key) => {
|
|
1801
|
+
assertScope(() => active);
|
|
1802
|
+
const entry = staged.get(key);
|
|
1803
|
+
return entry ? entry.present ? entry.value : void 0 : values.get(key);
|
|
1804
|
+
},
|
|
1805
|
+
has: (key) => {
|
|
1806
|
+
assertScope(() => active);
|
|
1807
|
+
const entry = staged.get(key);
|
|
1808
|
+
return entry ? entry.present : values.has(key);
|
|
1809
|
+
},
|
|
1810
|
+
set: (key, value) => {
|
|
1811
|
+
assertScope(() => active);
|
|
1812
|
+
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
1813
|
+
staged.set(key, {
|
|
1814
|
+
present: true,
|
|
1815
|
+
value
|
|
1816
|
+
});
|
|
1817
|
+
},
|
|
1818
|
+
remove: (key) => {
|
|
1819
|
+
assertScope(() => active);
|
|
1820
|
+
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
1821
|
+
staged.set(key, { present: false });
|
|
1822
|
+
}
|
|
1823
|
+
});
|
|
1824
|
+
try {
|
|
1825
|
+
assertSynchronous(run(draft));
|
|
1826
|
+
} finally {
|
|
1827
|
+
active = false;
|
|
1828
|
+
}
|
|
1829
|
+
let changed = false;
|
|
1830
|
+
for (const [key, entry] of staged) {
|
|
1831
|
+
const present = values.has(key);
|
|
1832
|
+
if (entry.present ? present && Object.is(values.get(key), entry.value) : !present) continue;
|
|
1833
|
+
if (!touched.has(key)) touched.set(key, {
|
|
1834
|
+
present,
|
|
1835
|
+
value: values.get(key)
|
|
1836
|
+
});
|
|
1837
|
+
if (!beforeIds && present !== entry.present) beforeIds = Object.freeze([...values.keys()]);
|
|
1838
|
+
if (entry.present) values.set(key, entry.value);
|
|
1839
|
+
else values.delete(key);
|
|
1840
|
+
changed = true;
|
|
1841
|
+
}
|
|
1842
|
+
if (!changed) return;
|
|
1843
|
+
revision++;
|
|
1844
|
+
cause = scheduler.batchContext()?.cause ?? cause;
|
|
1845
|
+
scheduler.capture(record);
|
|
1846
|
+
scheduler.run();
|
|
1847
|
+
}
|
|
1848
|
+
};
|
|
1849
|
+
};
|
|
1688
1850
|
const externalValueSource = (port, equal) => {
|
|
1689
1851
|
scheduler.assertIdle();
|
|
1690
1852
|
const old = externalSources.get(port);
|
|
@@ -1877,6 +2039,7 @@ const createSources = (scheduler) => {
|
|
|
1877
2039
|
set
|
|
1878
2040
|
});
|
|
1879
2041
|
},
|
|
2042
|
+
collectionInput,
|
|
1880
2043
|
fromReadable: (readable, options) => {
|
|
1881
2044
|
scheduler.assertIdle();
|
|
1882
2045
|
if (projectionHandles.has(readable)) throw new Error("Projection nodes must be declared directly as sources.");
|
|
@@ -2497,11 +2660,15 @@ const createProjectionGraph = (options) => {
|
|
|
2497
2660
|
fromSource: (source, options) => sources.fromSource(source, options),
|
|
2498
2661
|
fromCollectionSource: (source) => sources.fromCollectionSource(source),
|
|
2499
2662
|
input: sources.input,
|
|
2663
|
+
collectionInput: sources.collectionInput,
|
|
2500
2664
|
fromReadable: sources.fromReadable,
|
|
2501
2665
|
value,
|
|
2502
2666
|
collection: (spec) => createCollection(scheduler, spec),
|
|
2503
2667
|
map,
|
|
2504
2668
|
batch: scheduler.batch,
|
|
2669
|
+
assertIdle: scheduler.assertIdle,
|
|
2670
|
+
releaseNode: scheduler.releaseNode,
|
|
2671
|
+
releaseInput: scheduler.unregisterSource,
|
|
2505
2672
|
dispose: () => {
|
|
2506
2673
|
try {
|
|
2507
2674
|
scheduler.dispose();
|
|
@@ -2671,16 +2838,27 @@ const sourceOf = (instance) => instance;
|
|
|
2671
2838
|
const createProjectionRuntime = (options) => {
|
|
2672
2839
|
const runtime = createProjectionGraph({ onError: options?.onError ?? (() => void 0) });
|
|
2673
2840
|
const materialized = /* @__PURE__ */ new WeakMap();
|
|
2674
|
-
|
|
2841
|
+
let disposed = false;
|
|
2842
|
+
const scopes = /* @__PURE__ */ new Set();
|
|
2843
|
+
const materialize = (projection, requester) => {
|
|
2844
|
+
const owner = require_advanced.ownerOf(projection);
|
|
2845
|
+
if (owner) {
|
|
2846
|
+
if (owner !== requester) throw new TypeError("Projection belongs to another scope.");
|
|
2847
|
+
if (!requester.active) throw new ProjectionDisposedError();
|
|
2848
|
+
}
|
|
2675
2849
|
const old = materialized.get(projection);
|
|
2676
2850
|
if (old) return old.node;
|
|
2677
|
-
const definition =
|
|
2851
|
+
const definition = require_advanced.definitionOf(projection);
|
|
2678
2852
|
let instance;
|
|
2679
|
-
let
|
|
2853
|
+
let write;
|
|
2680
2854
|
switch (definition.kind) {
|
|
2681
2855
|
case "input": {
|
|
2682
2856
|
const input = runtime.input(definition.initial, { isEqual: definition.isEqual });
|
|
2683
|
-
|
|
2857
|
+
write = {
|
|
2858
|
+
kind: "value-input",
|
|
2859
|
+
source: input.source,
|
|
2860
|
+
set: input.set
|
|
2861
|
+
};
|
|
2684
2862
|
instance = runtime.value({
|
|
2685
2863
|
sources: { input: input.source },
|
|
2686
2864
|
build: (values) => ({
|
|
@@ -2693,6 +2871,16 @@ const createProjectionRuntime = (options) => {
|
|
|
2693
2871
|
});
|
|
2694
2872
|
break;
|
|
2695
2873
|
}
|
|
2874
|
+
case "collection-input": {
|
|
2875
|
+
const source = runtime.collectionInput(definition.initial);
|
|
2876
|
+
write = {
|
|
2877
|
+
kind: "collection-input",
|
|
2878
|
+
source: source.source,
|
|
2879
|
+
update: source.update
|
|
2880
|
+
};
|
|
2881
|
+
instance = runtime.map(source.source, (_key, value) => value);
|
|
2882
|
+
break;
|
|
2883
|
+
}
|
|
2696
2884
|
case "readable": {
|
|
2697
2885
|
const source = runtime.fromReadable(definition.readable, { isEqual: definition.isEqual });
|
|
2698
2886
|
instance = runtime.value({
|
|
@@ -2764,7 +2952,7 @@ const createProjectionRuntime = (options) => {
|
|
|
2764
2952
|
break;
|
|
2765
2953
|
}
|
|
2766
2954
|
case "derive": {
|
|
2767
|
-
const sources = Object.fromEntries(definition.dependencies.map((dependency, index) => [`d${index}`, sourceOf(materialize(dependency))]));
|
|
2955
|
+
const sources = Object.fromEntries(definition.dependencies.map((dependency, index) => [`d${index}`, sourceOf(materialize(dependency, owner))]));
|
|
2768
2956
|
instance = runtime.value({
|
|
2769
2957
|
sources,
|
|
2770
2958
|
build: (values) => ({
|
|
@@ -2778,7 +2966,7 @@ const createProjectionRuntime = (options) => {
|
|
|
2778
2966
|
break;
|
|
2779
2967
|
}
|
|
2780
2968
|
case "incremental-value": {
|
|
2781
|
-
const sources = Object.fromEntries(Object.entries(definition.dependencies).map(([key, dependency]) => [key, sourceOf(materialize(dependency))]));
|
|
2969
|
+
const sources = Object.fromEntries(Object.entries(definition.dependencies).map(([key, dependency]) => [key, sourceOf(materialize(dependency, owner))]));
|
|
2782
2970
|
instance = runtime.value({
|
|
2783
2971
|
sources,
|
|
2784
2972
|
build: definition.build
|
|
@@ -2786,7 +2974,7 @@ const createProjectionRuntime = (options) => {
|
|
|
2786
2974
|
break;
|
|
2787
2975
|
}
|
|
2788
2976
|
case "incremental-collection": {
|
|
2789
|
-
const sources = Object.fromEntries(Object.entries(definition.dependencies).map(([key, dependency]) => [key, sourceOf(materialize(dependency))]));
|
|
2977
|
+
const sources = Object.fromEntries(Object.entries(definition.dependencies).map(([key, dependency]) => [key, sourceOf(materialize(dependency, owner))]));
|
|
2790
2978
|
instance = runtime.collection({
|
|
2791
2979
|
sources,
|
|
2792
2980
|
build: definition.build,
|
|
@@ -2796,14 +2984,19 @@ const createProjectionRuntime = (options) => {
|
|
|
2796
2984
|
break;
|
|
2797
2985
|
}
|
|
2798
2986
|
}
|
|
2799
|
-
|
|
2987
|
+
const record = write ? {
|
|
2800
2988
|
node: instance,
|
|
2801
|
-
|
|
2802
|
-
}
|
|
2989
|
+
...write
|
|
2990
|
+
} : {
|
|
2991
|
+
kind: "projection",
|
|
2992
|
+
node: instance
|
|
2993
|
+
};
|
|
2994
|
+
materialized.set(projection, record);
|
|
2995
|
+
if (owner) owner.materialized.push(projection);
|
|
2803
2996
|
return instance;
|
|
2804
2997
|
};
|
|
2805
|
-
const get = (projection) => {
|
|
2806
|
-
const instance = materialize(projection);
|
|
2998
|
+
const get = (projection, requester) => {
|
|
2999
|
+
const instance = materialize(projection, requester);
|
|
2807
3000
|
const current = instance.current();
|
|
2808
3001
|
if (instance.kind === "collection") {
|
|
2809
3002
|
const record = materialized.get(projection) ?? materialized.get(instance);
|
|
@@ -2831,11 +3024,11 @@ const createProjectionRuntime = (options) => {
|
|
|
2831
3024
|
}
|
|
2832
3025
|
return current;
|
|
2833
3026
|
};
|
|
2834
|
-
|
|
3027
|
+
const makeReadable = (projection, selector, equality = Object.is, requester) => {
|
|
2835
3028
|
if (!selector) return Object.freeze({
|
|
2836
|
-
current: () => get(projection),
|
|
2837
|
-
revision: () => materialize(projection).revision(),
|
|
2838
|
-
subscribe: (listener) => materialize(projection).subscribe(listener)
|
|
3029
|
+
current: () => get(projection, requester),
|
|
3030
|
+
revision: () => materialize(projection, requester).revision(),
|
|
3031
|
+
subscribe: (listener) => materialize(projection, requester).subscribe(listener)
|
|
2839
3032
|
});
|
|
2840
3033
|
let initialized = false;
|
|
2841
3034
|
let value;
|
|
@@ -2850,7 +3043,7 @@ const createProjectionRuntime = (options) => {
|
|
|
2850
3043
|
let unsubscribeSource;
|
|
2851
3044
|
const listeners = /* @__PURE__ */ new Set();
|
|
2852
3045
|
const updateCollectionSnapshot = () => {
|
|
2853
|
-
const current = get(projection);
|
|
3046
|
+
const current = get(projection, requester);
|
|
2854
3047
|
previousCollection = isMapLike(current) ? current : void 0;
|
|
2855
3048
|
};
|
|
2856
3049
|
const evaluate = () => {
|
|
@@ -2864,7 +3057,7 @@ const createProjectionRuntime = (options) => {
|
|
|
2864
3057
|
let source;
|
|
2865
3058
|
let next;
|
|
2866
3059
|
try {
|
|
2867
|
-
source = get(projection);
|
|
3060
|
+
source = get(projection, requester);
|
|
2868
3061
|
next = selector(source);
|
|
2869
3062
|
} finally {
|
|
2870
3063
|
activeTracker = previousTracker;
|
|
@@ -2881,30 +3074,30 @@ const createProjectionRuntime = (options) => {
|
|
|
2881
3074
|
}
|
|
2882
3075
|
selection = nextSelection;
|
|
2883
3076
|
initialized = true;
|
|
2884
|
-
sourceRevision = materialize(projection).revision();
|
|
3077
|
+
sourceRevision = materialize(projection, requester).revision();
|
|
2885
3078
|
updateCollectionSnapshot();
|
|
2886
3079
|
return changed;
|
|
2887
3080
|
};
|
|
2888
3081
|
const ensureCurrent = () => {
|
|
2889
|
-
const revision = materialize(projection).revision();
|
|
3082
|
+
const revision = materialize(projection, requester).revision();
|
|
2890
3083
|
if (!initialized || !unsubscribeSource && sourceRevision !== revision) evaluate();
|
|
2891
3084
|
return value;
|
|
2892
3085
|
};
|
|
2893
3086
|
const onProjectionChange = (incoming) => {
|
|
2894
3087
|
let change = incoming;
|
|
2895
3088
|
if (!change && previousCollection) {
|
|
2896
|
-
const current = get(projection);
|
|
3089
|
+
const current = get(projection, requester);
|
|
2897
3090
|
if (isMapLike(current)) {
|
|
2898
3091
|
change = mapChange(previousCollection, current);
|
|
2899
3092
|
previousCollection = current;
|
|
2900
3093
|
if (!change) {
|
|
2901
|
-
sourceRevision = materialize(projection).revision();
|
|
3094
|
+
sourceRevision = materialize(projection, requester).revision();
|
|
2902
3095
|
return;
|
|
2903
3096
|
}
|
|
2904
3097
|
} else previousCollection = void 0;
|
|
2905
3098
|
}
|
|
2906
3099
|
if (!selectionAffects(selection, change)) {
|
|
2907
|
-
sourceRevision = materialize(projection).revision();
|
|
3100
|
+
sourceRevision = materialize(projection, requester).revision();
|
|
2908
3101
|
updateCollectionSnapshot();
|
|
2909
3102
|
return;
|
|
2910
3103
|
}
|
|
@@ -2912,12 +3105,12 @@ const createProjectionRuntime = (options) => {
|
|
|
2912
3105
|
const changed = evaluate();
|
|
2913
3106
|
if (unsubscribeSource && !sameSelection(previousSelection, selection)) {
|
|
2914
3107
|
unsubscribeSource();
|
|
2915
|
-
unsubscribeSource = materialize(projection).subscribe(onProjectionChange);
|
|
3108
|
+
unsubscribeSource = materialize(projection, requester).subscribe(onProjectionChange);
|
|
2916
3109
|
}
|
|
2917
3110
|
if (changed) Array.from(listeners).forEach((listener) => listener());
|
|
2918
3111
|
};
|
|
2919
3112
|
const installSource = () => {
|
|
2920
|
-
if (!unsubscribeSource) unsubscribeSource = materialize(projection).subscribe(onProjectionChange);
|
|
3113
|
+
if (!unsubscribeSource) unsubscribeSource = materialize(projection, requester).subscribe(onProjectionChange);
|
|
2921
3114
|
};
|
|
2922
3115
|
return Object.freeze({
|
|
2923
3116
|
current: ensureCurrent,
|
|
@@ -2938,18 +3131,134 @@ const createProjectionRuntime = (options) => {
|
|
|
2938
3131
|
};
|
|
2939
3132
|
}
|
|
2940
3133
|
});
|
|
3134
|
+
};
|
|
3135
|
+
function readable(projection, selector, equality) {
|
|
3136
|
+
return makeReadable(projection, selector, equality);
|
|
2941
3137
|
}
|
|
3138
|
+
const setInput = (target, value, requester) => {
|
|
3139
|
+
materialize(target, requester);
|
|
3140
|
+
const record = materialized.get(target);
|
|
3141
|
+
if (record?.kind !== "value-input") throw new TypeError("Projection is not a value input.");
|
|
3142
|
+
record.set(value);
|
|
3143
|
+
};
|
|
3144
|
+
const updateInput = (target, run, requester) => {
|
|
3145
|
+
materialize(target, requester);
|
|
3146
|
+
const record = materialized.get(target);
|
|
3147
|
+
if (record?.kind !== "collection-input") throw new TypeError("Projection is not a collection input.");
|
|
3148
|
+
record.update(run);
|
|
3149
|
+
};
|
|
3150
|
+
const createScope = () => {
|
|
3151
|
+
runtime.assertIdle();
|
|
3152
|
+
const state = {
|
|
3153
|
+
active: true,
|
|
3154
|
+
materialized: [],
|
|
3155
|
+
subscriptions: /* @__PURE__ */ new Set()
|
|
3156
|
+
};
|
|
3157
|
+
scopes.add(state);
|
|
3158
|
+
const assertActive = () => {
|
|
3159
|
+
if (!state.active) throw new ProjectionDisposedError();
|
|
3160
|
+
};
|
|
3161
|
+
const own = (projection) => {
|
|
3162
|
+
assertActive();
|
|
3163
|
+
const definition = require_advanced.definitionOf(projection);
|
|
3164
|
+
const dependencies = definition.kind === "derive" ? definition.dependencies : definition.kind === "incremental-value" || definition.kind === "incremental-collection" ? Object.values(definition.dependencies) : [];
|
|
3165
|
+
for (const dependency of dependencies) {
|
|
3166
|
+
const dependencyOwner = require_advanced.ownerOf(dependency);
|
|
3167
|
+
if (dependencyOwner && dependencyOwner !== state) throw new TypeError("A scope cannot depend on another scope.");
|
|
3168
|
+
}
|
|
3169
|
+
require_advanced.ownDefinition(projection, state);
|
|
3170
|
+
return projection;
|
|
3171
|
+
};
|
|
3172
|
+
const scopedInput = Object.assign((initial, equality) => own(require_advanced.input(initial, equality)), { collection: (initial) => own(require_advanced.input.collection(initial)) });
|
|
3173
|
+
const scopedDerive = (dependencies, compute, equality) => own(require_advanced.derive(dependencies, compute, equality));
|
|
3174
|
+
const scopedIncremental = Object.assign((dependencies, processor) => own(require_advanced.incremental(dependencies, processor)), { collection: (dependencies, processor) => own(require_advanced.incremental.collection(dependencies, processor)) });
|
|
3175
|
+
function scopeReadable(projection, selector, equality) {
|
|
3176
|
+
assertActive();
|
|
3177
|
+
materialize(projection, state);
|
|
3178
|
+
const source = makeReadable(projection, selector, equality, state);
|
|
3179
|
+
return Object.freeze({
|
|
3180
|
+
current: () => {
|
|
3181
|
+
assertActive();
|
|
3182
|
+
return source.current();
|
|
3183
|
+
},
|
|
3184
|
+
revision: () => {
|
|
3185
|
+
assertActive();
|
|
3186
|
+
return source.revision();
|
|
3187
|
+
},
|
|
3188
|
+
subscribe: (listener) => {
|
|
3189
|
+
assertActive();
|
|
3190
|
+
const stop = source.subscribe(listener);
|
|
3191
|
+
let subscribed = true;
|
|
3192
|
+
const unsubscribe = () => {
|
|
3193
|
+
if (!subscribed) return;
|
|
3194
|
+
subscribed = false;
|
|
3195
|
+
state.subscriptions.delete(unsubscribe);
|
|
3196
|
+
stop();
|
|
3197
|
+
};
|
|
3198
|
+
state.subscriptions.add(unsubscribe);
|
|
3199
|
+
return unsubscribe;
|
|
3200
|
+
}
|
|
3201
|
+
});
|
|
3202
|
+
}
|
|
3203
|
+
function scopeBatch(optionsOrCallback, maybeCallback) {
|
|
3204
|
+
assertActive();
|
|
3205
|
+
return typeof optionsOrCallback === "function" ? runtime.batch(optionsOrCallback) : runtime.batch(optionsOrCallback, maybeCallback);
|
|
3206
|
+
}
|
|
3207
|
+
return Object.freeze({
|
|
3208
|
+
input: scopedInput,
|
|
3209
|
+
derive: scopedDerive,
|
|
3210
|
+
incremental: scopedIncremental,
|
|
3211
|
+
get: (projection) => {
|
|
3212
|
+
assertActive();
|
|
3213
|
+
return get(projection, state);
|
|
3214
|
+
},
|
|
3215
|
+
readable: scopeReadable,
|
|
3216
|
+
set: (target, value) => {
|
|
3217
|
+
assertActive();
|
|
3218
|
+
setInput(target, value, state);
|
|
3219
|
+
},
|
|
3220
|
+
update: (target, run) => {
|
|
3221
|
+
assertActive();
|
|
3222
|
+
updateInput(target, run, state);
|
|
3223
|
+
},
|
|
3224
|
+
batch: scopeBatch,
|
|
3225
|
+
dispose: () => {
|
|
3226
|
+
if (!state.active) return;
|
|
3227
|
+
runtime.assertIdle();
|
|
3228
|
+
state.active = false;
|
|
3229
|
+
state.subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
3230
|
+
for (const definition of state.materialized.reverse()) {
|
|
3231
|
+
const record = materialized.get(definition);
|
|
3232
|
+
if (!record) continue;
|
|
3233
|
+
runtime.releaseNode(record.node);
|
|
3234
|
+
if (record.kind !== "projection") runtime.releaseInput(record.source);
|
|
3235
|
+
materialized.delete(definition);
|
|
3236
|
+
}
|
|
3237
|
+
state.materialized.length = 0;
|
|
3238
|
+
scopes.delete(state);
|
|
3239
|
+
}
|
|
3240
|
+
});
|
|
3241
|
+
};
|
|
2942
3242
|
const store = {
|
|
2943
3243
|
get,
|
|
2944
3244
|
readable,
|
|
2945
|
-
set:
|
|
2946
|
-
|
|
2947
|
-
const target = materialized.get(input);
|
|
2948
|
-
if (!target?.set) throw new TypeError("Projection is not an input.");
|
|
2949
|
-
target.set(value);
|
|
2950
|
-
}),
|
|
3245
|
+
set: setInput,
|
|
3246
|
+
update: updateInput,
|
|
2951
3247
|
batch: runtime.batch,
|
|
2952
|
-
|
|
3248
|
+
scope: createScope,
|
|
3249
|
+
dispose: () => {
|
|
3250
|
+
if (disposed) return;
|
|
3251
|
+
runtime.assertIdle();
|
|
3252
|
+
disposed = true;
|
|
3253
|
+
for (const scope of scopes) {
|
|
3254
|
+
scope.active = false;
|
|
3255
|
+
scope.subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
3256
|
+
scope.subscriptions.clear();
|
|
3257
|
+
scope.materialized.length = 0;
|
|
3258
|
+
}
|
|
3259
|
+
scopes.clear();
|
|
3260
|
+
runtime.dispose();
|
|
3261
|
+
}
|
|
2953
3262
|
};
|
|
2954
3263
|
return Object.freeze(store);
|
|
2955
3264
|
};
|
|
@@ -2963,13 +3272,13 @@ exports.TransactionRejected = require_notification.TransactionRejected;
|
|
|
2963
3272
|
exports.asReadable = asReadable;
|
|
2964
3273
|
exports.createDocument = createDocument;
|
|
2965
3274
|
exports.createProjectionRuntime = createProjectionRuntime;
|
|
2966
|
-
exports.derive =
|
|
3275
|
+
exports.derive = require_advanced.derive;
|
|
2967
3276
|
exports.field = field;
|
|
2968
|
-
exports.input =
|
|
3277
|
+
exports.input = require_advanced.input;
|
|
2969
3278
|
exports.list = list;
|
|
2970
3279
|
exports.map = map;
|
|
2971
3280
|
exports.object = object;
|
|
2972
|
-
exports.observe =
|
|
3281
|
+
exports.observe = require_advanced.observe;
|
|
2973
3282
|
exports.optional = optional;
|
|
2974
3283
|
exports.parse = require_scope.parse;
|
|
2975
3284
|
exports.read = read;
|