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.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { $ as OptionalNode, B as DocumentAddress, C as Draft, E as snapshot, F as MemberChange, G as DocumentTreeValue, H as DocumentListConfig, I as ValueTransition, J as Infer, K as FieldNode, N as Change, P as ChangeSet, Q as ObjectShape, S as DocumentImpact, T as replace, U as DocumentNode, V as DocumentAnchor, W as DocumentTreeNode, X as MapNode, Y as ListNode, Z as ObjectNode, _ as Unsubscribe, _t as Validator, a as DocumentDisposedError, at as VariantNode, b as MutationIssueCode, c as DocumentReentrancyError, ct as list, d as LocalHistory, dt as optional, et as PathValueOf, f as ObserverError, ft as table, g as TransactionResult, gt as ParseIssue, h as TransactionRejected, ht as ParseError, i as DocumentDiagnostic, it as TreeNode, l as DocumentRuntime, lt as map, mt as variant, n as CommitSource, nt as SchemaPath, o as DocumentProblem, ot as VariantShape, p as OperationResult, pt as tree, r as DocumentCommit, rt as TableNode, s as DocumentReadable, st as field, tt as ReadonlyValue, u as HistoryState, ut as object, v as Readable, vt as parse, w as Read, x as CollectionImpact, y as MutationIssue } from "./contract-XmKnroJq.cjs";
|
|
2
|
-
import {
|
|
2
|
+
import { _ as ExternalValueSource, c as Projection, d as observe, f as CollectionChange, g as ExternalValueEvent, h as ExternalCollectionSource, l as derive, m as ExternalCollectionRead, o as incremental, p as ExternalCollectionEvent, s as Input, u as input, v as ProjectionDisposedError, y as ProjectionError } from "./advanced-GTwIWcn6.cjs";
|
|
3
3
|
|
|
4
4
|
//#region core/src/runtime.d.ts
|
|
5
5
|
declare const createDocument: <S extends ObjectNode>(input: {
|
|
@@ -18,20 +18,40 @@ type DocumentSelector<TSchema extends ObjectNode, TResult> = (read: Read<TSchema
|
|
|
18
18
|
declare const read: <TSchema extends ObjectNode, TResult>(runtime: DocumentReadable<TSchema>, selector: DocumentSelector<TSchema, TResult>) => TResult;
|
|
19
19
|
//#endregion
|
|
20
20
|
//#region core/src/projection/runtime.d.ts
|
|
21
|
+
type KeyedDraft<K extends string, V> = {
|
|
22
|
+
get(key: K): V | undefined;
|
|
23
|
+
has(key: K): boolean;
|
|
24
|
+
set(key: K, value: V): void;
|
|
25
|
+
remove(key: K): void;
|
|
26
|
+
};
|
|
21
27
|
type ProjectionRuntime = {
|
|
22
28
|
get<T>(projection: Projection<T, unknown>): T;
|
|
23
29
|
readable<T>(projection: Projection<T, unknown>): Readable<T>;
|
|
24
30
|
readable<T, R>(projection: Projection<T, unknown>, selector: (value: T) => R, equality?: (previous: R, next: R) => boolean): Readable<R>;
|
|
25
31
|
set<T>(input: Input<T>, value: T): void;
|
|
32
|
+
update<K extends string, V>(input: Input<ReadonlyMap<K, V>, CollectionChange<K, V>>, run: (draft: KeyedDraft<K, V>) => void): void;
|
|
26
33
|
batch<T>(run: () => T): T;
|
|
27
34
|
batch<T>(options: {
|
|
28
35
|
readonly cause?: unknown;
|
|
29
36
|
}, run: () => T): T;
|
|
37
|
+
scope(): ProjectionScope;
|
|
38
|
+
dispose(): void;
|
|
39
|
+
};
|
|
40
|
+
type ProjectionScope = {
|
|
41
|
+
readonly input: typeof input;
|
|
42
|
+
readonly derive: typeof derive;
|
|
43
|
+
readonly incremental: typeof incremental;
|
|
44
|
+
get<T>(projection: Projection<T, unknown>): T;
|
|
45
|
+
readable<T>(projection: Projection<T, unknown>): Readable<T>;
|
|
46
|
+
readable<T, R>(projection: Projection<T, unknown>, selector: (value: T) => R, equality?: (previous: R, next: R) => boolean): Readable<R>;
|
|
47
|
+
set<T>(input: Input<T>, value: T): void;
|
|
48
|
+
update<K extends string, V>(input: Input<ReadonlyMap<K, V>, CollectionChange<K, V>>, run: (draft: KeyedDraft<K, V>) => void): void;
|
|
49
|
+
batch: ProjectionRuntime['batch'];
|
|
30
50
|
dispose(): void;
|
|
31
51
|
};
|
|
32
52
|
declare const createProjectionRuntime: (options?: {
|
|
33
53
|
readonly onError?: (error: ProjectionError) => void;
|
|
34
54
|
}) => ProjectionRuntime;
|
|
35
55
|
//#endregion
|
|
36
|
-
export { type Change, type ChangeSet, type CollectionChange, type CollectionImpact, type CommitSource, type DocumentAddress, type DocumentAnchor, type DocumentCommit, type DocumentDiagnostic, DocumentDisposedError, type DocumentImpact, type DocumentListConfig, type DocumentNode, type DocumentProblem, type DocumentReadable, DocumentReentrancyError, type DocumentRuntime, type DocumentSelector, type DocumentTreeNode, type DocumentTreeValue, type Draft, type ExternalCollectionEvent, type ExternalCollectionRead, type ExternalCollectionSource, type ExternalValueEvent, type ExternalValueSource, type FieldNode, type HistoryState, type Infer, type Input, type ListNode, type LocalHistory, type MapNode, type MemberChange, type MutationIssue, type MutationIssueCode, type ObjectNode, type ObjectShape, type ObserverError, type OperationResult, type OptionalNode, ParseError, type ParseIssue, type PathValueOf, type Projection, ProjectionDisposedError, ProjectionError, type ProjectionRuntime, type Read, type Readable, type ReadonlyValue, type SchemaPath, type TableNode, TransactionRejected, type TransactionResult, type TreeNode, type Unsubscribe, type Validator, type ValueTransition, type VariantNode, type VariantShape, asReadable, createDocument, createProjectionRuntime, derive, field, input, list, map, object, observe, optional, parse, read, replace, snapshot, table, tree, variant };
|
|
56
|
+
export { type Change, type ChangeSet, type CollectionChange, type CollectionImpact, type CommitSource, type DocumentAddress, type DocumentAnchor, type DocumentCommit, type DocumentDiagnostic, DocumentDisposedError, type DocumentImpact, type DocumentListConfig, type DocumentNode, type DocumentProblem, type DocumentReadable, DocumentReentrancyError, type DocumentRuntime, type DocumentSelector, type DocumentTreeNode, type DocumentTreeValue, type Draft, type ExternalCollectionEvent, type ExternalCollectionRead, type ExternalCollectionSource, type ExternalValueEvent, type ExternalValueSource, type FieldNode, type HistoryState, type Infer, type Input, type ListNode, type LocalHistory, type MapNode, type MemberChange, type MutationIssue, type MutationIssueCode, type ObjectNode, type ObjectShape, type ObserverError, type OperationResult, type OptionalNode, ParseError, type ParseIssue, type PathValueOf, type Projection, ProjectionDisposedError, ProjectionError, type ProjectionRuntime, type ProjectionScope, type Read, type Readable, type ReadonlyValue, type SchemaPath, type TableNode, TransactionRejected, type TransactionResult, type TreeNode, type Unsubscribe, type Validator, type ValueTransition, type VariantNode, type VariantShape, asReadable, createDocument, createProjectionRuntime, derive, field, input, list, map, object, observe, optional, parse, read, replace, snapshot, table, tree, variant };
|
|
37
57
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { $ as OptionalNode, B as DocumentAddress, C as Draft, E as snapshot, F as MemberChange, G as DocumentTreeValue, H as DocumentListConfig, I as ValueTransition, J as Infer, K as FieldNode, N as Change, P as ChangeSet, Q as ObjectShape, S as DocumentImpact, T as replace, U as DocumentNode, V as DocumentAnchor, W as DocumentTreeNode, X as MapNode, Y as ListNode, Z as ObjectNode, _ as Unsubscribe, _t as Validator, a as DocumentDisposedError, at as VariantNode, b as MutationIssueCode, c as DocumentReentrancyError, ct as list, d as LocalHistory, dt as optional, et as PathValueOf, f as ObserverError, ft as table, g as TransactionResult, gt as ParseIssue, h as TransactionRejected, ht as ParseError, i as DocumentDiagnostic, it as TreeNode, l as DocumentRuntime, lt as map, mt as variant, n as CommitSource, nt as SchemaPath, o as DocumentProblem, ot as VariantShape, p as OperationResult, pt as tree, r as DocumentCommit, rt as TableNode, s as DocumentReadable, st as field, tt as ReadonlyValue, u as HistoryState, ut as object, v as Readable, vt as parse, w as Read, x as CollectionImpact, y as MutationIssue } from "./contract-CATCCVu5.js";
|
|
2
|
-
import {
|
|
2
|
+
import { _ as ExternalValueSource, c as Projection, d as observe, f as CollectionChange, g as ExternalValueEvent, h as ExternalCollectionSource, l as derive, m as ExternalCollectionRead, o as incremental, p as ExternalCollectionEvent, s as Input, u as input, v as ProjectionDisposedError, y as ProjectionError } from "./advanced-c0F3gpLG.js";
|
|
3
3
|
|
|
4
4
|
//#region core/src/runtime.d.ts
|
|
5
5
|
declare const createDocument: <S extends ObjectNode>(input: {
|
|
@@ -18,20 +18,40 @@ type DocumentSelector<TSchema extends ObjectNode, TResult> = (read: Read<TSchema
|
|
|
18
18
|
declare const read: <TSchema extends ObjectNode, TResult>(runtime: DocumentReadable<TSchema>, selector: DocumentSelector<TSchema, TResult>) => TResult;
|
|
19
19
|
//#endregion
|
|
20
20
|
//#region core/src/projection/runtime.d.ts
|
|
21
|
+
type KeyedDraft<K extends string, V> = {
|
|
22
|
+
get(key: K): V | undefined;
|
|
23
|
+
has(key: K): boolean;
|
|
24
|
+
set(key: K, value: V): void;
|
|
25
|
+
remove(key: K): void;
|
|
26
|
+
};
|
|
21
27
|
type ProjectionRuntime = {
|
|
22
28
|
get<T>(projection: Projection<T, unknown>): T;
|
|
23
29
|
readable<T>(projection: Projection<T, unknown>): Readable<T>;
|
|
24
30
|
readable<T, R>(projection: Projection<T, unknown>, selector: (value: T) => R, equality?: (previous: R, next: R) => boolean): Readable<R>;
|
|
25
31
|
set<T>(input: Input<T>, value: T): void;
|
|
32
|
+
update<K extends string, V>(input: Input<ReadonlyMap<K, V>, CollectionChange<K, V>>, run: (draft: KeyedDraft<K, V>) => void): void;
|
|
26
33
|
batch<T>(run: () => T): T;
|
|
27
34
|
batch<T>(options: {
|
|
28
35
|
readonly cause?: unknown;
|
|
29
36
|
}, run: () => T): T;
|
|
37
|
+
scope(): ProjectionScope;
|
|
38
|
+
dispose(): void;
|
|
39
|
+
};
|
|
40
|
+
type ProjectionScope = {
|
|
41
|
+
readonly input: typeof input;
|
|
42
|
+
readonly derive: typeof derive;
|
|
43
|
+
readonly incremental: typeof incremental;
|
|
44
|
+
get<T>(projection: Projection<T, unknown>): T;
|
|
45
|
+
readable<T>(projection: Projection<T, unknown>): Readable<T>;
|
|
46
|
+
readable<T, R>(projection: Projection<T, unknown>, selector: (value: T) => R, equality?: (previous: R, next: R) => boolean): Readable<R>;
|
|
47
|
+
set<T>(input: Input<T>, value: T): void;
|
|
48
|
+
update<K extends string, V>(input: Input<ReadonlyMap<K, V>, CollectionChange<K, V>>, run: (draft: KeyedDraft<K, V>) => void): void;
|
|
49
|
+
batch: ProjectionRuntime['batch'];
|
|
30
50
|
dispose(): void;
|
|
31
51
|
};
|
|
32
52
|
declare const createProjectionRuntime: (options?: {
|
|
33
53
|
readonly onError?: (error: ProjectionError) => void;
|
|
34
54
|
}) => ProjectionRuntime;
|
|
35
55
|
//#endregion
|
|
36
|
-
export { type Change, type ChangeSet, type CollectionChange, type CollectionImpact, type CommitSource, type DocumentAddress, type DocumentAnchor, type DocumentCommit, type DocumentDiagnostic, DocumentDisposedError, type DocumentImpact, type DocumentListConfig, type DocumentNode, type DocumentProblem, type DocumentReadable, DocumentReentrancyError, type DocumentRuntime, type DocumentSelector, type DocumentTreeNode, type DocumentTreeValue, type Draft, type ExternalCollectionEvent, type ExternalCollectionRead, type ExternalCollectionSource, type ExternalValueEvent, type ExternalValueSource, type FieldNode, type HistoryState, type Infer, type Input, type ListNode, type LocalHistory, type MapNode, type MemberChange, type MutationIssue, type MutationIssueCode, type ObjectNode, type ObjectShape, type ObserverError, type OperationResult, type OptionalNode, ParseError, type ParseIssue, type PathValueOf, type Projection, ProjectionDisposedError, ProjectionError, type ProjectionRuntime, type Read, type Readable, type ReadonlyValue, type SchemaPath, type TableNode, TransactionRejected, type TransactionResult, type TreeNode, type Unsubscribe, type Validator, type ValueTransition, type VariantNode, type VariantShape, asReadable, createDocument, createProjectionRuntime, derive, field, input, list, map, object, observe, optional, parse, read, replace, snapshot, table, tree, variant };
|
|
56
|
+
export { type Change, type ChangeSet, type CollectionChange, type CollectionImpact, type CommitSource, type DocumentAddress, type DocumentAnchor, type DocumentCommit, type DocumentDiagnostic, DocumentDisposedError, type DocumentImpact, type DocumentListConfig, type DocumentNode, type DocumentProblem, type DocumentReadable, DocumentReentrancyError, type DocumentRuntime, type DocumentSelector, type DocumentTreeNode, type DocumentTreeValue, type Draft, type ExternalCollectionEvent, type ExternalCollectionRead, type ExternalCollectionSource, type ExternalValueEvent, type ExternalValueSource, type FieldNode, type HistoryState, type Infer, type Input, type ListNode, type LocalHistory, type MapNode, type MemberChange, type MutationIssue, type MutationIssueCode, type ObjectNode, type ObjectShape, type ObserverError, type OperationResult, type OptionalNode, ParseError, type ParseIssue, type PathValueOf, type Projection, ProjectionDisposedError, ProjectionError, type ProjectionRuntime, type ProjectionScope, type Read, type Readable, type ReadonlyValue, type SchemaPath, type TableNode, TransactionRejected, type TransactionResult, type TreeNode, type Unsubscribe, type Validator, type ValueTransition, type VariantNode, type VariantShape, asReadable, createDocument, createProjectionRuntime, derive, field, input, list, map, object, observe, optional, parse, read, replace, snapshot, table, tree, variant };
|
|
37
57
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { A as insert, D as equal, F as remove, L as profile, M as keys, N as mat
|
|
|
2
2
|
import { a as ParseError, c as copyValue, i as snapshot, l as equalValue, n as createAccess, o as checkKey, r as replace, s as checkValue, t as collectionAccess, u as parse } from "./scope-d-L87NeC.js";
|
|
3
3
|
import { _ as affected, a as documentReadableOwner, d as accessOf, f as bindRuntimeAccess, g as TransactionRejected, h as DocumentReentrancyError, i as disposeNotification, l as subscribeRoot, m as DocumentDisposedError, n as bindDocumentReadable, o as notify, p as readWith, r as createNotification, s as shareNotification, t as attachProjection, u as subscribeTargets, v as belongs, y as same } from "./notification-IQIJyH3Q.js";
|
|
4
4
|
import { n as bindRuntimeDriver, o as decodeChanges, r as disposeRuntimeDriver, s as sealChanges, t as assertRuntimeWritable } from "./driver-CSnhMjbP.js";
|
|
5
|
-
import { a as
|
|
5
|
+
import { a as observe, i as input, n as definitionOf, o as ownDefinition, r as derive, s as ownerOf, t as incremental } from "./advanced-DgRnyRAc.js";
|
|
6
6
|
//#region core/src/schema.ts
|
|
7
7
|
const node = (value) => Object.freeze(value);
|
|
8
8
|
const field = (validator) => node({
|
|
@@ -1195,7 +1195,9 @@ const createScheduler = (onError) => {
|
|
|
1195
1195
|
phase = "compute";
|
|
1196
1196
|
lock(true);
|
|
1197
1197
|
try {
|
|
1198
|
-
pending.forEach((source) =>
|
|
1198
|
+
pending.forEach((source) => {
|
|
1199
|
+
if (source.shouldSettle?.() ?? true) source.consumers.forEach(enqueue);
|
|
1200
|
+
});
|
|
1199
1201
|
while (heap.length) {
|
|
1200
1202
|
const node = pop();
|
|
1201
1203
|
if (node.disposed) continue;
|
|
@@ -1337,12 +1339,29 @@ const createScheduler = (onError) => {
|
|
|
1337
1339
|
unregisterSource(handle) {
|
|
1338
1340
|
const record = records.get(handle);
|
|
1339
1341
|
if (record) {
|
|
1342
|
+
assertIdle();
|
|
1343
|
+
if (record.consumers.size) throw new Error("Projection source is still used by a node.");
|
|
1340
1344
|
record.disposed = true;
|
|
1341
1345
|
pending.delete(record);
|
|
1342
1346
|
record.clear();
|
|
1343
1347
|
records.delete(handle);
|
|
1344
1348
|
}
|
|
1345
1349
|
},
|
|
1350
|
+
releaseNode(handle) {
|
|
1351
|
+
assertIdle();
|
|
1352
|
+
const node = records.get(handle);
|
|
1353
|
+
if (!node || !nodes.has(node)) throw new Error("Unknown projection node.");
|
|
1354
|
+
if (node.consumers.size) throw new Error("Projection node is still used by another node.");
|
|
1355
|
+
node.disposed = true;
|
|
1356
|
+
node.sources.forEach((source) => source.consumers.delete(node));
|
|
1357
|
+
node.release();
|
|
1358
|
+
node.clear();
|
|
1359
|
+
nodes.delete(node);
|
|
1360
|
+
records.delete(handle);
|
|
1361
|
+
pending.delete(node);
|
|
1362
|
+
queued.delete(node);
|
|
1363
|
+
emissions.delete(node);
|
|
1364
|
+
},
|
|
1346
1365
|
source(handle) {
|
|
1347
1366
|
assertActive();
|
|
1348
1367
|
const source = records.get(handle);
|
|
@@ -1684,6 +1703,149 @@ const createSources = (scheduler) => {
|
|
|
1684
1703
|
}
|
|
1685
1704
|
};
|
|
1686
1705
|
};
|
|
1706
|
+
const collectionInput = (initial) => {
|
|
1707
|
+
const values = new Map(initial);
|
|
1708
|
+
const touched = /* @__PURE__ */ new Map();
|
|
1709
|
+
let beforeIds;
|
|
1710
|
+
let revision = 0;
|
|
1711
|
+
let cause;
|
|
1712
|
+
const handle = Object.freeze({ kind: "collection" });
|
|
1713
|
+
const change = () => {
|
|
1714
|
+
const added = [];
|
|
1715
|
+
const updated = [];
|
|
1716
|
+
const removed = [];
|
|
1717
|
+
for (const [key, before] of touched) {
|
|
1718
|
+
const afterPresent = values.has(key);
|
|
1719
|
+
if (!before.present && afterPresent) added.push({
|
|
1720
|
+
key,
|
|
1721
|
+
after: values.get(key)
|
|
1722
|
+
});
|
|
1723
|
+
else if (before.present && !afterPresent) removed.push({
|
|
1724
|
+
key,
|
|
1725
|
+
before: before.value
|
|
1726
|
+
});
|
|
1727
|
+
else if (before.present && afterPresent && !Object.is(before.value, values.get(key))) updated.push({
|
|
1728
|
+
key,
|
|
1729
|
+
before: before.value,
|
|
1730
|
+
after: values.get(key)
|
|
1731
|
+
});
|
|
1732
|
+
}
|
|
1733
|
+
let order;
|
|
1734
|
+
if (beforeIds) {
|
|
1735
|
+
const afterIds = [...values.keys()];
|
|
1736
|
+
const beforeKeys = new Set(beforeIds);
|
|
1737
|
+
const afterKeys = new Set(afterIds);
|
|
1738
|
+
const beforeCommon = beforeIds.filter((key) => afterKeys.has(key));
|
|
1739
|
+
const afterCommon = afterIds.filter((key) => beforeKeys.has(key));
|
|
1740
|
+
if (beforeCommon.some((key, index) => key !== afterCommon[index])) order = Object.freeze({
|
|
1741
|
+
before: beforeIds,
|
|
1742
|
+
after: Object.freeze(afterIds)
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1745
|
+
if (!added.length && !updated.length && !removed.length && !order) return void 0;
|
|
1746
|
+
return Object.freeze({
|
|
1747
|
+
kind: "incremental",
|
|
1748
|
+
added: Object.freeze(added),
|
|
1749
|
+
updated: Object.freeze(updated),
|
|
1750
|
+
removed: Object.freeze(removed),
|
|
1751
|
+
...order ? { order } : {}
|
|
1752
|
+
});
|
|
1753
|
+
};
|
|
1754
|
+
const record = {
|
|
1755
|
+
consumers: /* @__PURE__ */ new Set(),
|
|
1756
|
+
disposed: false,
|
|
1757
|
+
fault: void 0,
|
|
1758
|
+
revision: () => revision,
|
|
1759
|
+
reset: () => false,
|
|
1760
|
+
shouldSettle: () => change() !== void 0,
|
|
1761
|
+
clear: () => {
|
|
1762
|
+
touched.clear();
|
|
1763
|
+
beforeIds = void 0;
|
|
1764
|
+
cause = void 0;
|
|
1765
|
+
},
|
|
1766
|
+
context: (active) => {
|
|
1767
|
+
assertScope(active);
|
|
1768
|
+
const read = Object.freeze({
|
|
1769
|
+
get: (key) => {
|
|
1770
|
+
assertScope(active);
|
|
1771
|
+
return values.get(key);
|
|
1772
|
+
},
|
|
1773
|
+
has: (key) => {
|
|
1774
|
+
assertScope(active);
|
|
1775
|
+
return values.has(key);
|
|
1776
|
+
},
|
|
1777
|
+
ids: () => {
|
|
1778
|
+
assertScope(active);
|
|
1779
|
+
return Object.freeze([...values.keys()]);
|
|
1780
|
+
}
|
|
1781
|
+
});
|
|
1782
|
+
return Object.freeze({
|
|
1783
|
+
kind: "collection",
|
|
1784
|
+
read,
|
|
1785
|
+
change: change(),
|
|
1786
|
+
revision,
|
|
1787
|
+
cause
|
|
1788
|
+
});
|
|
1789
|
+
}
|
|
1790
|
+
};
|
|
1791
|
+
scheduler.register(handle, record);
|
|
1792
|
+
return {
|
|
1793
|
+
source: handle,
|
|
1794
|
+
update(run) {
|
|
1795
|
+
scheduler.assertIdle();
|
|
1796
|
+
const staged = /* @__PURE__ */ new Map();
|
|
1797
|
+
let active = true;
|
|
1798
|
+
const draft = Object.freeze({
|
|
1799
|
+
get: (key) => {
|
|
1800
|
+
assertScope(() => active);
|
|
1801
|
+
const entry = staged.get(key);
|
|
1802
|
+
return entry ? entry.present ? entry.value : void 0 : values.get(key);
|
|
1803
|
+
},
|
|
1804
|
+
has: (key) => {
|
|
1805
|
+
assertScope(() => active);
|
|
1806
|
+
const entry = staged.get(key);
|
|
1807
|
+
return entry ? entry.present : values.has(key);
|
|
1808
|
+
},
|
|
1809
|
+
set: (key, value) => {
|
|
1810
|
+
assertScope(() => active);
|
|
1811
|
+
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
1812
|
+
staged.set(key, {
|
|
1813
|
+
present: true,
|
|
1814
|
+
value
|
|
1815
|
+
});
|
|
1816
|
+
},
|
|
1817
|
+
remove: (key) => {
|
|
1818
|
+
assertScope(() => active);
|
|
1819
|
+
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
1820
|
+
staged.set(key, { present: false });
|
|
1821
|
+
}
|
|
1822
|
+
});
|
|
1823
|
+
try {
|
|
1824
|
+
assertSynchronous(run(draft));
|
|
1825
|
+
} finally {
|
|
1826
|
+
active = false;
|
|
1827
|
+
}
|
|
1828
|
+
let changed = false;
|
|
1829
|
+
for (const [key, entry] of staged) {
|
|
1830
|
+
const present = values.has(key);
|
|
1831
|
+
if (entry.present ? present && Object.is(values.get(key), entry.value) : !present) continue;
|
|
1832
|
+
if (!touched.has(key)) touched.set(key, {
|
|
1833
|
+
present,
|
|
1834
|
+
value: values.get(key)
|
|
1835
|
+
});
|
|
1836
|
+
if (!beforeIds && present !== entry.present) beforeIds = Object.freeze([...values.keys()]);
|
|
1837
|
+
if (entry.present) values.set(key, entry.value);
|
|
1838
|
+
else values.delete(key);
|
|
1839
|
+
changed = true;
|
|
1840
|
+
}
|
|
1841
|
+
if (!changed) return;
|
|
1842
|
+
revision++;
|
|
1843
|
+
cause = scheduler.batchContext()?.cause ?? cause;
|
|
1844
|
+
scheduler.capture(record);
|
|
1845
|
+
scheduler.run();
|
|
1846
|
+
}
|
|
1847
|
+
};
|
|
1848
|
+
};
|
|
1687
1849
|
const externalValueSource = (port, equal) => {
|
|
1688
1850
|
scheduler.assertIdle();
|
|
1689
1851
|
const old = externalSources.get(port);
|
|
@@ -1876,6 +2038,7 @@ const createSources = (scheduler) => {
|
|
|
1876
2038
|
set
|
|
1877
2039
|
});
|
|
1878
2040
|
},
|
|
2041
|
+
collectionInput,
|
|
1879
2042
|
fromReadable: (readable, options) => {
|
|
1880
2043
|
scheduler.assertIdle();
|
|
1881
2044
|
if (projectionHandles.has(readable)) throw new Error("Projection nodes must be declared directly as sources.");
|
|
@@ -2496,11 +2659,15 @@ const createProjectionGraph = (options) => {
|
|
|
2496
2659
|
fromSource: (source, options) => sources.fromSource(source, options),
|
|
2497
2660
|
fromCollectionSource: (source) => sources.fromCollectionSource(source),
|
|
2498
2661
|
input: sources.input,
|
|
2662
|
+
collectionInput: sources.collectionInput,
|
|
2499
2663
|
fromReadable: sources.fromReadable,
|
|
2500
2664
|
value,
|
|
2501
2665
|
collection: (spec) => createCollection(scheduler, spec),
|
|
2502
2666
|
map,
|
|
2503
2667
|
batch: scheduler.batch,
|
|
2668
|
+
assertIdle: scheduler.assertIdle,
|
|
2669
|
+
releaseNode: scheduler.releaseNode,
|
|
2670
|
+
releaseInput: scheduler.unregisterSource,
|
|
2504
2671
|
dispose: () => {
|
|
2505
2672
|
try {
|
|
2506
2673
|
scheduler.dispose();
|
|
@@ -2670,16 +2837,27 @@ const sourceOf = (instance) => instance;
|
|
|
2670
2837
|
const createProjectionRuntime = (options) => {
|
|
2671
2838
|
const runtime = createProjectionGraph({ onError: options?.onError ?? (() => void 0) });
|
|
2672
2839
|
const materialized = /* @__PURE__ */ new WeakMap();
|
|
2673
|
-
|
|
2840
|
+
let disposed = false;
|
|
2841
|
+
const scopes = /* @__PURE__ */ new Set();
|
|
2842
|
+
const materialize = (projection, requester) => {
|
|
2843
|
+
const owner = ownerOf(projection);
|
|
2844
|
+
if (owner) {
|
|
2845
|
+
if (owner !== requester) throw new TypeError("Projection belongs to another scope.");
|
|
2846
|
+
if (!requester.active) throw new ProjectionDisposedError();
|
|
2847
|
+
}
|
|
2674
2848
|
const old = materialized.get(projection);
|
|
2675
2849
|
if (old) return old.node;
|
|
2676
2850
|
const definition = definitionOf(projection);
|
|
2677
2851
|
let instance;
|
|
2678
|
-
let
|
|
2852
|
+
let write;
|
|
2679
2853
|
switch (definition.kind) {
|
|
2680
2854
|
case "input": {
|
|
2681
2855
|
const input = runtime.input(definition.initial, { isEqual: definition.isEqual });
|
|
2682
|
-
|
|
2856
|
+
write = {
|
|
2857
|
+
kind: "value-input",
|
|
2858
|
+
source: input.source,
|
|
2859
|
+
set: input.set
|
|
2860
|
+
};
|
|
2683
2861
|
instance = runtime.value({
|
|
2684
2862
|
sources: { input: input.source },
|
|
2685
2863
|
build: (values) => ({
|
|
@@ -2692,6 +2870,16 @@ const createProjectionRuntime = (options) => {
|
|
|
2692
2870
|
});
|
|
2693
2871
|
break;
|
|
2694
2872
|
}
|
|
2873
|
+
case "collection-input": {
|
|
2874
|
+
const source = runtime.collectionInput(definition.initial);
|
|
2875
|
+
write = {
|
|
2876
|
+
kind: "collection-input",
|
|
2877
|
+
source: source.source,
|
|
2878
|
+
update: source.update
|
|
2879
|
+
};
|
|
2880
|
+
instance = runtime.map(source.source, (_key, value) => value);
|
|
2881
|
+
break;
|
|
2882
|
+
}
|
|
2695
2883
|
case "readable": {
|
|
2696
2884
|
const source = runtime.fromReadable(definition.readable, { isEqual: definition.isEqual });
|
|
2697
2885
|
instance = runtime.value({
|
|
@@ -2763,7 +2951,7 @@ const createProjectionRuntime = (options) => {
|
|
|
2763
2951
|
break;
|
|
2764
2952
|
}
|
|
2765
2953
|
case "derive": {
|
|
2766
|
-
const sources = Object.fromEntries(definition.dependencies.map((dependency, index) => [`d${index}`, sourceOf(materialize(dependency))]));
|
|
2954
|
+
const sources = Object.fromEntries(definition.dependencies.map((dependency, index) => [`d${index}`, sourceOf(materialize(dependency, owner))]));
|
|
2767
2955
|
instance = runtime.value({
|
|
2768
2956
|
sources,
|
|
2769
2957
|
build: (values) => ({
|
|
@@ -2777,7 +2965,7 @@ const createProjectionRuntime = (options) => {
|
|
|
2777
2965
|
break;
|
|
2778
2966
|
}
|
|
2779
2967
|
case "incremental-value": {
|
|
2780
|
-
const sources = Object.fromEntries(Object.entries(definition.dependencies).map(([key, dependency]) => [key, sourceOf(materialize(dependency))]));
|
|
2968
|
+
const sources = Object.fromEntries(Object.entries(definition.dependencies).map(([key, dependency]) => [key, sourceOf(materialize(dependency, owner))]));
|
|
2781
2969
|
instance = runtime.value({
|
|
2782
2970
|
sources,
|
|
2783
2971
|
build: definition.build
|
|
@@ -2785,7 +2973,7 @@ const createProjectionRuntime = (options) => {
|
|
|
2785
2973
|
break;
|
|
2786
2974
|
}
|
|
2787
2975
|
case "incremental-collection": {
|
|
2788
|
-
const sources = Object.fromEntries(Object.entries(definition.dependencies).map(([key, dependency]) => [key, sourceOf(materialize(dependency))]));
|
|
2976
|
+
const sources = Object.fromEntries(Object.entries(definition.dependencies).map(([key, dependency]) => [key, sourceOf(materialize(dependency, owner))]));
|
|
2789
2977
|
instance = runtime.collection({
|
|
2790
2978
|
sources,
|
|
2791
2979
|
build: definition.build,
|
|
@@ -2795,14 +2983,19 @@ const createProjectionRuntime = (options) => {
|
|
|
2795
2983
|
break;
|
|
2796
2984
|
}
|
|
2797
2985
|
}
|
|
2798
|
-
|
|
2986
|
+
const record = write ? {
|
|
2799
2987
|
node: instance,
|
|
2800
|
-
|
|
2801
|
-
}
|
|
2988
|
+
...write
|
|
2989
|
+
} : {
|
|
2990
|
+
kind: "projection",
|
|
2991
|
+
node: instance
|
|
2992
|
+
};
|
|
2993
|
+
materialized.set(projection, record);
|
|
2994
|
+
if (owner) owner.materialized.push(projection);
|
|
2802
2995
|
return instance;
|
|
2803
2996
|
};
|
|
2804
|
-
const get = (projection) => {
|
|
2805
|
-
const instance = materialize(projection);
|
|
2997
|
+
const get = (projection, requester) => {
|
|
2998
|
+
const instance = materialize(projection, requester);
|
|
2806
2999
|
const current = instance.current();
|
|
2807
3000
|
if (instance.kind === "collection") {
|
|
2808
3001
|
const record = materialized.get(projection) ?? materialized.get(instance);
|
|
@@ -2830,11 +3023,11 @@ const createProjectionRuntime = (options) => {
|
|
|
2830
3023
|
}
|
|
2831
3024
|
return current;
|
|
2832
3025
|
};
|
|
2833
|
-
|
|
3026
|
+
const makeReadable = (projection, selector, equality = Object.is, requester) => {
|
|
2834
3027
|
if (!selector) return Object.freeze({
|
|
2835
|
-
current: () => get(projection),
|
|
2836
|
-
revision: () => materialize(projection).revision(),
|
|
2837
|
-
subscribe: (listener) => materialize(projection).subscribe(listener)
|
|
3028
|
+
current: () => get(projection, requester),
|
|
3029
|
+
revision: () => materialize(projection, requester).revision(),
|
|
3030
|
+
subscribe: (listener) => materialize(projection, requester).subscribe(listener)
|
|
2838
3031
|
});
|
|
2839
3032
|
let initialized = false;
|
|
2840
3033
|
let value;
|
|
@@ -2849,7 +3042,7 @@ const createProjectionRuntime = (options) => {
|
|
|
2849
3042
|
let unsubscribeSource;
|
|
2850
3043
|
const listeners = /* @__PURE__ */ new Set();
|
|
2851
3044
|
const updateCollectionSnapshot = () => {
|
|
2852
|
-
const current = get(projection);
|
|
3045
|
+
const current = get(projection, requester);
|
|
2853
3046
|
previousCollection = isMapLike(current) ? current : void 0;
|
|
2854
3047
|
};
|
|
2855
3048
|
const evaluate = () => {
|
|
@@ -2863,7 +3056,7 @@ const createProjectionRuntime = (options) => {
|
|
|
2863
3056
|
let source;
|
|
2864
3057
|
let next;
|
|
2865
3058
|
try {
|
|
2866
|
-
source = get(projection);
|
|
3059
|
+
source = get(projection, requester);
|
|
2867
3060
|
next = selector(source);
|
|
2868
3061
|
} finally {
|
|
2869
3062
|
activeTracker = previousTracker;
|
|
@@ -2880,30 +3073,30 @@ const createProjectionRuntime = (options) => {
|
|
|
2880
3073
|
}
|
|
2881
3074
|
selection = nextSelection;
|
|
2882
3075
|
initialized = true;
|
|
2883
|
-
sourceRevision = materialize(projection).revision();
|
|
3076
|
+
sourceRevision = materialize(projection, requester).revision();
|
|
2884
3077
|
updateCollectionSnapshot();
|
|
2885
3078
|
return changed;
|
|
2886
3079
|
};
|
|
2887
3080
|
const ensureCurrent = () => {
|
|
2888
|
-
const revision = materialize(projection).revision();
|
|
3081
|
+
const revision = materialize(projection, requester).revision();
|
|
2889
3082
|
if (!initialized || !unsubscribeSource && sourceRevision !== revision) evaluate();
|
|
2890
3083
|
return value;
|
|
2891
3084
|
};
|
|
2892
3085
|
const onProjectionChange = (incoming) => {
|
|
2893
3086
|
let change = incoming;
|
|
2894
3087
|
if (!change && previousCollection) {
|
|
2895
|
-
const current = get(projection);
|
|
3088
|
+
const current = get(projection, requester);
|
|
2896
3089
|
if (isMapLike(current)) {
|
|
2897
3090
|
change = mapChange(previousCollection, current);
|
|
2898
3091
|
previousCollection = current;
|
|
2899
3092
|
if (!change) {
|
|
2900
|
-
sourceRevision = materialize(projection).revision();
|
|
3093
|
+
sourceRevision = materialize(projection, requester).revision();
|
|
2901
3094
|
return;
|
|
2902
3095
|
}
|
|
2903
3096
|
} else previousCollection = void 0;
|
|
2904
3097
|
}
|
|
2905
3098
|
if (!selectionAffects(selection, change)) {
|
|
2906
|
-
sourceRevision = materialize(projection).revision();
|
|
3099
|
+
sourceRevision = materialize(projection, requester).revision();
|
|
2907
3100
|
updateCollectionSnapshot();
|
|
2908
3101
|
return;
|
|
2909
3102
|
}
|
|
@@ -2911,12 +3104,12 @@ const createProjectionRuntime = (options) => {
|
|
|
2911
3104
|
const changed = evaluate();
|
|
2912
3105
|
if (unsubscribeSource && !sameSelection(previousSelection, selection)) {
|
|
2913
3106
|
unsubscribeSource();
|
|
2914
|
-
unsubscribeSource = materialize(projection).subscribe(onProjectionChange);
|
|
3107
|
+
unsubscribeSource = materialize(projection, requester).subscribe(onProjectionChange);
|
|
2915
3108
|
}
|
|
2916
3109
|
if (changed) Array.from(listeners).forEach((listener) => listener());
|
|
2917
3110
|
};
|
|
2918
3111
|
const installSource = () => {
|
|
2919
|
-
if (!unsubscribeSource) unsubscribeSource = materialize(projection).subscribe(onProjectionChange);
|
|
3112
|
+
if (!unsubscribeSource) unsubscribeSource = materialize(projection, requester).subscribe(onProjectionChange);
|
|
2920
3113
|
};
|
|
2921
3114
|
return Object.freeze({
|
|
2922
3115
|
current: ensureCurrent,
|
|
@@ -2937,18 +3130,134 @@ const createProjectionRuntime = (options) => {
|
|
|
2937
3130
|
};
|
|
2938
3131
|
}
|
|
2939
3132
|
});
|
|
3133
|
+
};
|
|
3134
|
+
function readable(projection, selector, equality) {
|
|
3135
|
+
return makeReadable(projection, selector, equality);
|
|
2940
3136
|
}
|
|
3137
|
+
const setInput = (target, value, requester) => {
|
|
3138
|
+
materialize(target, requester);
|
|
3139
|
+
const record = materialized.get(target);
|
|
3140
|
+
if (record?.kind !== "value-input") throw new TypeError("Projection is not a value input.");
|
|
3141
|
+
record.set(value);
|
|
3142
|
+
};
|
|
3143
|
+
const updateInput = (target, run, requester) => {
|
|
3144
|
+
materialize(target, requester);
|
|
3145
|
+
const record = materialized.get(target);
|
|
3146
|
+
if (record?.kind !== "collection-input") throw new TypeError("Projection is not a collection input.");
|
|
3147
|
+
record.update(run);
|
|
3148
|
+
};
|
|
3149
|
+
const createScope = () => {
|
|
3150
|
+
runtime.assertIdle();
|
|
3151
|
+
const state = {
|
|
3152
|
+
active: true,
|
|
3153
|
+
materialized: [],
|
|
3154
|
+
subscriptions: /* @__PURE__ */ new Set()
|
|
3155
|
+
};
|
|
3156
|
+
scopes.add(state);
|
|
3157
|
+
const assertActive = () => {
|
|
3158
|
+
if (!state.active) throw new ProjectionDisposedError();
|
|
3159
|
+
};
|
|
3160
|
+
const own = (projection) => {
|
|
3161
|
+
assertActive();
|
|
3162
|
+
const definition = definitionOf(projection);
|
|
3163
|
+
const dependencies = definition.kind === "derive" ? definition.dependencies : definition.kind === "incremental-value" || definition.kind === "incremental-collection" ? Object.values(definition.dependencies) : [];
|
|
3164
|
+
for (const dependency of dependencies) {
|
|
3165
|
+
const dependencyOwner = ownerOf(dependency);
|
|
3166
|
+
if (dependencyOwner && dependencyOwner !== state) throw new TypeError("A scope cannot depend on another scope.");
|
|
3167
|
+
}
|
|
3168
|
+
ownDefinition(projection, state);
|
|
3169
|
+
return projection;
|
|
3170
|
+
};
|
|
3171
|
+
const scopedInput = Object.assign((initial, equality) => own(input(initial, equality)), { collection: (initial) => own(input.collection(initial)) });
|
|
3172
|
+
const scopedDerive = (dependencies, compute, equality) => own(derive(dependencies, compute, equality));
|
|
3173
|
+
const scopedIncremental = Object.assign((dependencies, processor) => own(incremental(dependencies, processor)), { collection: (dependencies, processor) => own(incremental.collection(dependencies, processor)) });
|
|
3174
|
+
function scopeReadable(projection, selector, equality) {
|
|
3175
|
+
assertActive();
|
|
3176
|
+
materialize(projection, state);
|
|
3177
|
+
const source = makeReadable(projection, selector, equality, state);
|
|
3178
|
+
return Object.freeze({
|
|
3179
|
+
current: () => {
|
|
3180
|
+
assertActive();
|
|
3181
|
+
return source.current();
|
|
3182
|
+
},
|
|
3183
|
+
revision: () => {
|
|
3184
|
+
assertActive();
|
|
3185
|
+
return source.revision();
|
|
3186
|
+
},
|
|
3187
|
+
subscribe: (listener) => {
|
|
3188
|
+
assertActive();
|
|
3189
|
+
const stop = source.subscribe(listener);
|
|
3190
|
+
let subscribed = true;
|
|
3191
|
+
const unsubscribe = () => {
|
|
3192
|
+
if (!subscribed) return;
|
|
3193
|
+
subscribed = false;
|
|
3194
|
+
state.subscriptions.delete(unsubscribe);
|
|
3195
|
+
stop();
|
|
3196
|
+
};
|
|
3197
|
+
state.subscriptions.add(unsubscribe);
|
|
3198
|
+
return unsubscribe;
|
|
3199
|
+
}
|
|
3200
|
+
});
|
|
3201
|
+
}
|
|
3202
|
+
function scopeBatch(optionsOrCallback, maybeCallback) {
|
|
3203
|
+
assertActive();
|
|
3204
|
+
return typeof optionsOrCallback === "function" ? runtime.batch(optionsOrCallback) : runtime.batch(optionsOrCallback, maybeCallback);
|
|
3205
|
+
}
|
|
3206
|
+
return Object.freeze({
|
|
3207
|
+
input: scopedInput,
|
|
3208
|
+
derive: scopedDerive,
|
|
3209
|
+
incremental: scopedIncremental,
|
|
3210
|
+
get: (projection) => {
|
|
3211
|
+
assertActive();
|
|
3212
|
+
return get(projection, state);
|
|
3213
|
+
},
|
|
3214
|
+
readable: scopeReadable,
|
|
3215
|
+
set: (target, value) => {
|
|
3216
|
+
assertActive();
|
|
3217
|
+
setInput(target, value, state);
|
|
3218
|
+
},
|
|
3219
|
+
update: (target, run) => {
|
|
3220
|
+
assertActive();
|
|
3221
|
+
updateInput(target, run, state);
|
|
3222
|
+
},
|
|
3223
|
+
batch: scopeBatch,
|
|
3224
|
+
dispose: () => {
|
|
3225
|
+
if (!state.active) return;
|
|
3226
|
+
runtime.assertIdle();
|
|
3227
|
+
state.active = false;
|
|
3228
|
+
state.subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
3229
|
+
for (const definition of state.materialized.reverse()) {
|
|
3230
|
+
const record = materialized.get(definition);
|
|
3231
|
+
if (!record) continue;
|
|
3232
|
+
runtime.releaseNode(record.node);
|
|
3233
|
+
if (record.kind !== "projection") runtime.releaseInput(record.source);
|
|
3234
|
+
materialized.delete(definition);
|
|
3235
|
+
}
|
|
3236
|
+
state.materialized.length = 0;
|
|
3237
|
+
scopes.delete(state);
|
|
3238
|
+
}
|
|
3239
|
+
});
|
|
3240
|
+
};
|
|
2941
3241
|
const store = {
|
|
2942
3242
|
get,
|
|
2943
3243
|
readable,
|
|
2944
|
-
set:
|
|
2945
|
-
|
|
2946
|
-
const target = materialized.get(input);
|
|
2947
|
-
if (!target?.set) throw new TypeError("Projection is not an input.");
|
|
2948
|
-
target.set(value);
|
|
2949
|
-
}),
|
|
3244
|
+
set: setInput,
|
|
3245
|
+
update: updateInput,
|
|
2950
3246
|
batch: runtime.batch,
|
|
2951
|
-
|
|
3247
|
+
scope: createScope,
|
|
3248
|
+
dispose: () => {
|
|
3249
|
+
if (disposed) return;
|
|
3250
|
+
runtime.assertIdle();
|
|
3251
|
+
disposed = true;
|
|
3252
|
+
for (const scope of scopes) {
|
|
3253
|
+
scope.active = false;
|
|
3254
|
+
scope.subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
3255
|
+
scope.subscriptions.clear();
|
|
3256
|
+
scope.materialized.length = 0;
|
|
3257
|
+
}
|
|
3258
|
+
scopes.clear();
|
|
3259
|
+
runtime.dispose();
|
|
3260
|
+
}
|
|
2952
3261
|
};
|
|
2953
3262
|
return Object.freeze(store);
|
|
2954
3263
|
};
|