doxum 0.1.28 → 0.1.30
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 +3 -2
- package/dist/advanced.cjs +1 -1
- package/dist/advanced.js +1 -1
- package/dist/{driver-B5vdPohL.js → driver-B7RR-VfX.js} +31 -12
- package/dist/driver-B7RR-VfX.js.map +1 -0
- package/dist/{driver-BL91gn7_.cjs → driver-CN3dGxQI.cjs} +31 -12
- package/dist/driver-CN3dGxQI.cjs.map +1 -0
- package/dist/index.cjs +206 -133
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +206 -133
- package/dist/index.js.map +1 -1
- package/dist/local-sync.cjs +1 -1
- package/dist/local-sync.js +1 -1
- package/dist/{transform-DUleAsG0.cjs → transform-B6YxfR0R.cjs} +176 -50
- package/dist/transform-B6YxfR0R.cjs.map +1 -0
- package/dist/{transform-B4T3AcJr.js → transform-BQY9I6il.js} +147 -51
- package/dist/transform-BQY9I6il.js.map +1 -0
- package/package.json +3 -2
- package/skills/doxum-runtime/SKILL.md +64 -82
- package/skills/doxum-runtime/agents/openai.yaml +2 -2
- package/skills/doxum-runtime/references/document-runtime.md +370 -0
- package/skills/doxum-runtime/references/integrations.md +215 -0
- package/skills/doxum-runtime/references/{invariants.en.md → invariants.md} +5 -2
- package/skills/doxum-runtime/references/projections.md +467 -0
- package/skills/doxum-runtime/references/public-api.md +623 -0
- package/skills/doxum-runtime/references/recipes.md +493 -0
- package/dist/driver-B5vdPohL.js.map +0 -1
- package/dist/driver-BL91gn7_.cjs.map +0 -1
- package/dist/transform-B4T3AcJr.js.map +0 -1
- package/dist/transform-DUleAsG0.cjs.map +0 -1
- package/skills/doxum-runtime/references/api.en.md +0 -283
- package/skills/doxum-runtime/references/api.zh-CN.md +0 -276
- package/skills/doxum-runtime/references/guide.en.md +0 -138
- package/skills/doxum-runtime/references/guide.zh-CN.md +0 -116
- package/skills/doxum-runtime/references/invariants.zh-CN.md +0 -53
- package/skills/doxum-runtime/references/patterns.en.md +0 -162
- package/skills/doxum-runtime/references/patterns.zh-CN.md +0 -159
- package/skills/doxum-runtime/references/projections.en.md +0 -313
- package/skills/doxum-runtime/references/projections.zh-CN.md +0 -306
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { A as ownProjections, C as snapshotDependencyValue, D as defineProcessor, E as snapshotCollectionView, M as projectionRef, N as profile, O as defineSource, S as compileProjectionDependencies, T as mapRead, _ as createCollectionChange, a as createKeyedDependencyRuntime, b as sameArray, c as assertScope, d as ProjectionDisposedError, f as ProjectionError, g as collectionHasStructuralChange, h as collectionChangeTouchesKey, i as compileKeyedDependencies, j as producerOf, k as isProjection, l as assertSynchronous, m as collectionChangeIntersects, n as keyedAbsent, o as outputKind, r as assertKeyedProjection, s as createKeyRelation, t as createKeyedTransform, u as createScheduler, v as diffCollection, w as collectionView, x as snapshotArray, y as iterableMatchesArray } from "./transform-BQY9I6il.js";
|
|
2
2
|
import { n as isPlainObject, r as isRecord, t as installOwn } from "./record-B2yRhYsc.js";
|
|
3
|
-
import { c as AddressIndex, d as invalidValue, f as children, g as validate, h as parent, i as contextOf, l as MutationRejected, m as is, o as decodeChanges, p as contains$1, r as bindContext, s as sealChanges, t as assertRuntimeWritable, u as fail } from "./driver-
|
|
3
|
+
import { c as AddressIndex, d as invalidValue, f as children, g as validate, h as parent, i as contextOf, l as MutationRejected, m as is, o as decodeChanges, p as contains$1, r as bindContext, s as sealChanges, t as assertRuntimeWritable, u as fail } from "./driver-B7RR-VfX.js";
|
|
4
4
|
//#region core/src/schema/model.ts
|
|
5
5
|
const schemaNodeOf = (schema) => schema;
|
|
6
6
|
const collectionEntryNode = (node) => node.kind === "map" || node.kind === "table" || node.kind === "list" ? node.value : void 0;
|
|
@@ -568,18 +568,44 @@ const moveSelection = (current, selection, position) => {
|
|
|
568
568
|
selected.add(key);
|
|
569
569
|
}
|
|
570
570
|
const moved = [];
|
|
571
|
-
|
|
572
|
-
|
|
571
|
+
let remainingLength = 0;
|
|
572
|
+
let anchorIndex = -1;
|
|
573
|
+
const anchoredKey = position && ("before" in position ? position.before : "after" in position ? position.after : void 0);
|
|
574
|
+
for (const key of current) {
|
|
575
|
+
if (selected.has(key)) {
|
|
576
|
+
moved.push(key);
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
if (key === anchoredKey) anchorIndex = remainingLength;
|
|
580
|
+
remainingLength++;
|
|
581
|
+
}
|
|
573
582
|
if (moved.length !== selected.size) return { kind: "missing" };
|
|
574
|
-
|
|
575
|
-
|
|
583
|
+
let insertion;
|
|
584
|
+
if (!position || "at" in position && position.at === "end") insertion = remainingLength;
|
|
585
|
+
else if ("at" in position) {
|
|
586
|
+
if (position.at !== "start") return { kind: "invalid-anchor" };
|
|
587
|
+
insertion = 0;
|
|
588
|
+
} else {
|
|
589
|
+
if (anchorIndex < 0) return { kind: "invalid-anchor" };
|
|
590
|
+
insertion = "before" in position ? anchorIndex : anchorIndex + 1;
|
|
591
|
+
}
|
|
592
|
+
const order = new Array(current.length);
|
|
593
|
+
let outputIndex = 0;
|
|
594
|
+
let remainingIndex = 0;
|
|
595
|
+
let inserted = false;
|
|
596
|
+
for (const key of current) {
|
|
597
|
+
if (selected.has(key)) continue;
|
|
598
|
+
if (!inserted && remainingIndex === insertion) {
|
|
599
|
+
for (const movedKey of moved) order[outputIndex++] = movedKey;
|
|
600
|
+
inserted = true;
|
|
601
|
+
}
|
|
602
|
+
order[outputIndex++] = key;
|
|
603
|
+
remainingIndex++;
|
|
604
|
+
}
|
|
605
|
+
if (!inserted) for (const movedKey of moved) order[outputIndex++] = movedKey;
|
|
576
606
|
return {
|
|
577
607
|
kind: "ok",
|
|
578
|
-
order
|
|
579
|
-
...remaining.slice(0, insertion),
|
|
580
|
-
...moved,
|
|
581
|
-
...remaining.slice(insertion)
|
|
582
|
-
]
|
|
608
|
+
order
|
|
583
609
|
};
|
|
584
610
|
};
|
|
585
611
|
const index = (keys, anchor) => {
|
|
@@ -1372,6 +1398,17 @@ const contains = (parent, child) => {
|
|
|
1372
1398
|
}
|
|
1373
1399
|
return true;
|
|
1374
1400
|
};
|
|
1401
|
+
/** Compare a virtual `[...base, segment]` address with an existing address without allocating it. */
|
|
1402
|
+
const compareExtended = (base, segment, other) => {
|
|
1403
|
+
profile.address.prefixComparison();
|
|
1404
|
+
const length = base.length + 1;
|
|
1405
|
+
const common = Math.min(length, other.length);
|
|
1406
|
+
for (let index = 0; index < common; index += 1) {
|
|
1407
|
+
profile.address.segmentCompared();
|
|
1408
|
+
if ((index < base.length ? base[index] : segment) !== other[index]) return "disjoint";
|
|
1409
|
+
}
|
|
1410
|
+
return length === other.length ? "equal" : length < other.length ? "ancestor" : "descendant";
|
|
1411
|
+
};
|
|
1375
1412
|
//#endregion
|
|
1376
1413
|
//#region core/src/impact.ts
|
|
1377
1414
|
const createImpact = (schema, changes) => {
|
|
@@ -1798,7 +1835,7 @@ const reconstructBefore = (node, current, records, offset) => {
|
|
|
1798
1835
|
};
|
|
1799
1836
|
const sealMembers = (fact, changes) => {
|
|
1800
1837
|
const members = [];
|
|
1801
|
-
for (const member of fact.members
|
|
1838
|
+
if (fact.members) for (const member of fact.members.values()) {
|
|
1802
1839
|
if (!member) continue;
|
|
1803
1840
|
const key = memberKey(fact, member.key);
|
|
1804
1841
|
const present = Object.hasOwn(fact.parent, key);
|
|
@@ -1882,7 +1919,7 @@ var ChangeRecorder = class {
|
|
|
1882
1919
|
absorb(at, node, value, present) {
|
|
1883
1920
|
const index = this.indexGroups();
|
|
1884
1921
|
const children = [];
|
|
1885
|
-
index.
|
|
1922
|
+
index.forEachOverlap(at, (fact) => {
|
|
1886
1923
|
if (fact.kind === "members") {
|
|
1887
1924
|
if (fact.at.length < at.length) {
|
|
1888
1925
|
if (fact.at.length + 1 === at.length) {
|
|
@@ -1901,18 +1938,19 @@ var ChangeRecorder = class {
|
|
|
1901
1938
|
at: fact.at,
|
|
1902
1939
|
group: fact
|
|
1903
1940
|
});
|
|
1904
|
-
for (const member of fact.members
|
|
1941
|
+
if (fact.members) for (const member of fact.members.values()) {
|
|
1905
1942
|
if (!member) continue;
|
|
1906
|
-
const
|
|
1907
|
-
if (
|
|
1943
|
+
const compared = compareExtended(fact.at, member.key, at);
|
|
1944
|
+
if (compared !== "equal" && compared !== "descendant") continue;
|
|
1945
|
+
children.push({
|
|
1908
1946
|
kind: "member",
|
|
1909
|
-
at:
|
|
1947
|
+
at: fact.at.concat(member.key),
|
|
1910
1948
|
group: fact,
|
|
1911
1949
|
member
|
|
1912
1950
|
});
|
|
1913
1951
|
}
|
|
1914
1952
|
} else if (contains(at, fact.at)) children.push(fact);
|
|
1915
|
-
})
|
|
1953
|
+
});
|
|
1916
1954
|
if (present) value = reconstructBefore(node, value, children, at.length);
|
|
1917
1955
|
this.releaseCovered(children);
|
|
1918
1956
|
return value;
|
|
@@ -1930,7 +1968,9 @@ var ChangeRecorder = class {
|
|
|
1930
1968
|
(changedGroups ??= /* @__PURE__ */ new Set()).add(child.group);
|
|
1931
1969
|
} else this.unregister(child);
|
|
1932
1970
|
}
|
|
1933
|
-
|
|
1971
|
+
if (changedGroups) {
|
|
1972
|
+
for (const group of changedGroups) if (emptyGroup(group)) this.unregister(group);
|
|
1973
|
+
}
|
|
1934
1974
|
}
|
|
1935
1975
|
register(fact) {
|
|
1936
1976
|
this.facts.add(fact);
|
|
@@ -2879,12 +2919,7 @@ const createKeyedGet = (source, key, equality = Object.is) => {
|
|
|
2879
2919
|
} else if (sourceRevision !== collection.revision) {
|
|
2880
2920
|
const change = collection.change;
|
|
2881
2921
|
if (!change || change.kind === "reset") affected = true;
|
|
2882
|
-
else if (selected !== void 0)
|
|
2883
|
-
for (const changedKey of collectionChange.keys(change)) if (changedKey === selected) {
|
|
2884
|
-
affected = true;
|
|
2885
|
-
break;
|
|
2886
|
-
}
|
|
2887
|
-
}
|
|
2922
|
+
else if (selected !== void 0) affected = collectionChangeTouchesKey(change, selected);
|
|
2888
2923
|
}
|
|
2889
2924
|
if (affected) output.output.set(selected === void 0 ? void 0 : collection.read.get(selected));
|
|
2890
2925
|
sourceRevision = collection.revision;
|
|
@@ -3048,9 +3083,7 @@ function createKeyedGroupBy(source, dependenciesOrSelector, maybeSelector) {
|
|
|
3048
3083
|
outputs: [{
|
|
3049
3084
|
kind: "collection",
|
|
3050
3085
|
equality: (previous, next) => {
|
|
3051
|
-
|
|
3052
|
-
const right = next;
|
|
3053
|
-
return left.length === right.length && left.every((key, index) => key === right[index]);
|
|
3086
|
+
return sameArray(previous, next);
|
|
3054
3087
|
}
|
|
3055
3088
|
}],
|
|
3056
3089
|
create: () => {
|
|
@@ -3094,11 +3127,14 @@ function createKeyedGroupBy(source, dependenciesOrSelector, maybeSelector) {
|
|
|
3094
3127
|
output.output.set(group, Object.freeze(members));
|
|
3095
3128
|
};
|
|
3096
3129
|
const publishGroupOrder = (output) => {
|
|
3097
|
-
const order = [...groupRanks.
|
|
3130
|
+
const order = [...groupRanks.keys()];
|
|
3131
|
+
order.sort((leftKey, rightKey) => {
|
|
3132
|
+
const left = groupRanks.get(leftKey);
|
|
3133
|
+
const right = groupRanks.get(rightKey);
|
|
3098
3134
|
if (left.source !== right.source) return left.source - right.source;
|
|
3099
3135
|
if (left.selector !== right.selector) return left.selector - right.selector;
|
|
3100
3136
|
return leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0;
|
|
3101
|
-
})
|
|
3137
|
+
});
|
|
3102
3138
|
output.output.order(order);
|
|
3103
3139
|
};
|
|
3104
3140
|
const rebuild = (driver, sources, output) => {
|
|
@@ -3150,7 +3186,8 @@ function createKeyedGroupBy(source, dependenciesOrSelector, maybeSelector) {
|
|
|
3150
3186
|
return;
|
|
3151
3187
|
} else {
|
|
3152
3188
|
for (const entry of change.removed) {
|
|
3153
|
-
|
|
3189
|
+
const changed = removeSourceKey(entry.key, affected);
|
|
3190
|
+
orderDirty ||= changed;
|
|
3154
3191
|
dependencies.remove(entry.key);
|
|
3155
3192
|
dirty.delete(entry.key);
|
|
3156
3193
|
}
|
|
@@ -3163,7 +3200,10 @@ function createKeyedGroupBy(source, dependenciesOrSelector, maybeSelector) {
|
|
|
3163
3200
|
}
|
|
3164
3201
|
all ||= dependencies.collectInvalidated(evaluation.sources, dirty);
|
|
3165
3202
|
if (all) for (const key of driver.read.ids()) dirty.add(key);
|
|
3166
|
-
for (const key of dirty)
|
|
3203
|
+
for (const key of dirty) {
|
|
3204
|
+
const changed = selectGroups(driver, evaluation.sources, key, affected);
|
|
3205
|
+
orderDirty ||= changed;
|
|
3206
|
+
}
|
|
3167
3207
|
if (structural) markAllGroups(output, affected);
|
|
3168
3208
|
publishAffected(affected, output, orderDirty);
|
|
3169
3209
|
dependencies.remember(evaluation.sources);
|
|
@@ -3367,13 +3407,14 @@ const createPublishedCollection = () => {
|
|
|
3367
3407
|
},
|
|
3368
3408
|
publish: (staged, nextIds, reset) => {
|
|
3369
3409
|
if (reset) {
|
|
3370
|
-
const entries = [];
|
|
3371
|
-
for (const [key, entry] of staged) if (entry.present) entries.push([key, entry.value]);
|
|
3372
|
-
index = PersistentKeyedIndex.from(entries);
|
|
3373
3410
|
values.clear();
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
else
|
|
3411
|
+
for (const [key, entry] of staged) if (entry.present) values.set(key, entry.value);
|
|
3412
|
+
index = PersistentKeyedIndex.from(values);
|
|
3413
|
+
} else for (const [key, entry] of staged) {
|
|
3414
|
+
index = entry.present ? index.set(key, entry.value) : index.remove(key);
|
|
3415
|
+
if (entry.present) values.set(key, entry.value);
|
|
3416
|
+
else values.delete(key);
|
|
3417
|
+
}
|
|
3377
3418
|
ids = nextIds;
|
|
3378
3419
|
},
|
|
3379
3420
|
release: () => {
|
|
@@ -3386,7 +3427,7 @@ const createPublishedCollection = () => {
|
|
|
3386
3427
|
/** Owns staged keyed intent, exact transitions and published collection state. */
|
|
3387
3428
|
const createCollectionOutput = (binding) => {
|
|
3388
3429
|
const published = createPublishedCollection();
|
|
3389
|
-
|
|
3430
|
+
const staged = /* @__PURE__ */ new Map();
|
|
3390
3431
|
let nextIds = published.ids();
|
|
3391
3432
|
let change;
|
|
3392
3433
|
let initialized = false;
|
|
@@ -3402,12 +3443,15 @@ const createCollectionOutput = (binding) => {
|
|
|
3402
3443
|
return entry ? entry.present ? entry.value : void 0 : cleared ? void 0 : published.get(key);
|
|
3403
3444
|
};
|
|
3404
3445
|
const deriveIds = () => {
|
|
3405
|
-
const result =
|
|
3446
|
+
const result = [];
|
|
3447
|
+
if (!cleared) {
|
|
3448
|
+
for (const key of published.ids()) if (hasNext(key)) result.push(key);
|
|
3449
|
+
}
|
|
3406
3450
|
for (const [key, entry] of staged) if (entry.present && (cleared || !published.has(key))) result.push(key);
|
|
3407
3451
|
return result;
|
|
3408
3452
|
};
|
|
3409
3453
|
const begin = (active, initialize) => {
|
|
3410
|
-
staged
|
|
3454
|
+
staged.clear();
|
|
3411
3455
|
nextIds = published.ids();
|
|
3412
3456
|
change = void 0;
|
|
3413
3457
|
explicitOrder = void 0;
|
|
@@ -3424,7 +3468,9 @@ const createCollectionOutput = (binding) => {
|
|
|
3424
3468
|
},
|
|
3425
3469
|
ids: () => {
|
|
3426
3470
|
assertScope(active);
|
|
3427
|
-
|
|
3471
|
+
if (!next) return published.ids();
|
|
3472
|
+
if (explicitOrder) return explicitOrder;
|
|
3473
|
+
return Object.freeze(deriveIds());
|
|
3428
3474
|
}
|
|
3429
3475
|
});
|
|
3430
3476
|
return {
|
|
@@ -3445,7 +3491,7 @@ const createCollectionOutput = (binding) => {
|
|
|
3445
3491
|
},
|
|
3446
3492
|
order: (order) => {
|
|
3447
3493
|
assertScope(active);
|
|
3448
|
-
explicitOrder =
|
|
3494
|
+
explicitOrder = snapshotArray(order);
|
|
3449
3495
|
}
|
|
3450
3496
|
}
|
|
3451
3497
|
};
|
|
@@ -3455,8 +3501,6 @@ const createCollectionOutput = (binding) => {
|
|
|
3455
3501
|
for (const key of published.keys()) if (!staged.has(key)) staged.set(key, { present: false });
|
|
3456
3502
|
}
|
|
3457
3503
|
profile.projection("touchedKeys", staged.size);
|
|
3458
|
-
const added = /* @__PURE__ */ new Set();
|
|
3459
|
-
const removed = /* @__PURE__ */ new Set();
|
|
3460
3504
|
const addedEntries = [];
|
|
3461
3505
|
const updatedEntries = [];
|
|
3462
3506
|
const removedEntries = [];
|
|
@@ -3464,7 +3508,6 @@ const createCollectionOutput = (binding) => {
|
|
|
3464
3508
|
const existed = published.has(key);
|
|
3465
3509
|
if (entry.present) {
|
|
3466
3510
|
if (!existed) {
|
|
3467
|
-
added.add(key);
|
|
3468
3511
|
addedEntries.push({
|
|
3469
3512
|
key,
|
|
3470
3513
|
after: entry.value
|
|
@@ -3480,19 +3523,28 @@ const createCollectionOutput = (binding) => {
|
|
|
3480
3523
|
else if (!nextReset) staged.delete(key);
|
|
3481
3524
|
continue;
|
|
3482
3525
|
}
|
|
3483
|
-
if (existed) {
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
});
|
|
3489
|
-
} else staged.delete(key);
|
|
3526
|
+
if (existed) removedEntries.push({
|
|
3527
|
+
key,
|
|
3528
|
+
before: published.get(key)
|
|
3529
|
+
});
|
|
3530
|
+
else staged.delete(key);
|
|
3490
3531
|
}
|
|
3491
3532
|
const ids = published.ids();
|
|
3492
|
-
if (explicitOrder
|
|
3493
|
-
const
|
|
3494
|
-
|
|
3495
|
-
|
|
3533
|
+
if (explicitOrder) {
|
|
3534
|
+
const expectedLength = published.size() + addedEntries.length - removedEntries.length;
|
|
3535
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3536
|
+
for (const key of explicitOrder) {
|
|
3537
|
+
if (seen.has(key) || !hasNext(key)) throw new TypeError("Projection order must contain every key exactly once.");
|
|
3538
|
+
seen.add(key);
|
|
3539
|
+
}
|
|
3540
|
+
if (seen.size !== expectedLength) throw new TypeError("Projection order must contain every key exactly once.");
|
|
3541
|
+
nextIds = sameArray(ids, explicitOrder) ? ids : explicitOrder;
|
|
3542
|
+
} else if (addedEntries.length || removedEntries.length) {
|
|
3543
|
+
const order = new Array(published.size() + addedEntries.length - removedEntries.length);
|
|
3544
|
+
let index = 0;
|
|
3545
|
+
for (const key of ids) if (hasNext(key)) order[index++] = key;
|
|
3546
|
+
for (const entry of addedEntries) order[index++] = entry.key;
|
|
3547
|
+
nextIds = sameArray(ids, order) ? ids : Object.freeze(order);
|
|
3496
3548
|
} else nextIds = ids;
|
|
3497
3549
|
profile.projection("changedKeys", addedEntries.length + updatedEntries.length + removedEntries.length);
|
|
3498
3550
|
change = nextReset ? Object.freeze({ kind: "reset" }) : createCollectionChange({
|
|
@@ -3809,18 +3861,19 @@ const createProcessor = (scheduler, definition, dependencies) => {
|
|
|
3809
3861
|
};
|
|
3810
3862
|
//#endregion
|
|
3811
3863
|
//#region core/src/projection/readable/listeners.ts
|
|
3812
|
-
/** Exhaustively notifies
|
|
3813
|
-
const
|
|
3814
|
-
|
|
3815
|
-
const
|
|
3816
|
-
for (const listener of snapshot) try {
|
|
3864
|
+
/** Exhaustively notifies an already-stable projection listener snapshot. */
|
|
3865
|
+
const notifyProjectionListenerSnapshot = (listeners, message) => {
|
|
3866
|
+
let failures;
|
|
3867
|
+
for (const listener of listeners) try {
|
|
3817
3868
|
listener();
|
|
3818
3869
|
} catch (error) {
|
|
3819
|
-
failures.push(error);
|
|
3870
|
+
(failures ??= []).push(error);
|
|
3820
3871
|
}
|
|
3821
|
-
if (failures
|
|
3822
|
-
if (failures
|
|
3872
|
+
if (failures?.length === 1) throw failures[0];
|
|
3873
|
+
if (failures?.length) throw new AggregateError(failures, message);
|
|
3823
3874
|
};
|
|
3875
|
+
/** Snapshots a mutable listener collection before exhaustive notification. */
|
|
3876
|
+
const notifyProjectionListeners = (listeners, message) => notifyProjectionListenerSnapshot([...listeners], message);
|
|
3824
3877
|
//#endregion
|
|
3825
3878
|
//#region core/src/projection/readable/selection.ts
|
|
3826
3879
|
let activeTracker;
|
|
@@ -3875,8 +3928,7 @@ const selectionAffects = (selection, change) => {
|
|
|
3875
3928
|
if (!change || change.kind === "reset") return true;
|
|
3876
3929
|
if (selection.all) return true;
|
|
3877
3930
|
if (selection.structure && collectionHasStructuralChange(change)) return true;
|
|
3878
|
-
|
|
3879
|
-
return false;
|
|
3931
|
+
return collectionChangeIntersects(change, selection.keys);
|
|
3880
3932
|
};
|
|
3881
3933
|
const createDirectReadable = (source) => Object.freeze({
|
|
3882
3934
|
current: source.current,
|
|
@@ -3918,7 +3970,7 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
|
|
|
3918
3970
|
activeTracker = previousTracker;
|
|
3919
3971
|
}
|
|
3920
3972
|
const nextSelection = Object.freeze({
|
|
3921
|
-
keys:
|
|
3973
|
+
keys: tracker.keys,
|
|
3922
3974
|
all: tracker.all || isMapLike(current) && tracker.keys.size === 0 && !tracker.structure,
|
|
3923
3975
|
structure: tracker.structure
|
|
3924
3976
|
});
|
|
@@ -4160,10 +4212,11 @@ const clearDocumentDirty = (dirty) => {
|
|
|
4160
4212
|
dirty.treeNodes.clear();
|
|
4161
4213
|
dirty.children.clear();
|
|
4162
4214
|
};
|
|
4163
|
-
const
|
|
4215
|
+
const locateRange = (dirty, path, start, tail) => {
|
|
4164
4216
|
let current = dirty;
|
|
4165
|
-
for (
|
|
4217
|
+
for (let index = start; index < path.length; index++) {
|
|
4166
4218
|
if (current.replace) return void 0;
|
|
4219
|
+
const key = path[index];
|
|
4167
4220
|
let child = current.children.get(key);
|
|
4168
4221
|
if (!child) {
|
|
4169
4222
|
child = createDocumentDirty();
|
|
@@ -4171,10 +4224,17 @@ const locate = (dirty, path) => {
|
|
|
4171
4224
|
}
|
|
4172
4225
|
current = child;
|
|
4173
4226
|
}
|
|
4174
|
-
return current;
|
|
4227
|
+
if (tail === void 0) return current;
|
|
4228
|
+
if (current.replace) return void 0;
|
|
4229
|
+
let child = current.children.get(tail);
|
|
4230
|
+
if (!child) {
|
|
4231
|
+
child = createDocumentDirty();
|
|
4232
|
+
current.children.set(tail, child);
|
|
4233
|
+
}
|
|
4234
|
+
return child;
|
|
4175
4235
|
};
|
|
4176
|
-
const
|
|
4177
|
-
const current =
|
|
4236
|
+
const replaceAt = (dirty, path, start, tail) => {
|
|
4237
|
+
const current = locateRange(dirty, path, start, tail);
|
|
4178
4238
|
if (!current) return;
|
|
4179
4239
|
current.replace = true;
|
|
4180
4240
|
current.order = false;
|
|
@@ -4182,15 +4242,18 @@ const markDocumentReplace = (dirty, path) => {
|
|
|
4182
4242
|
current.treeNodes.clear();
|
|
4183
4243
|
current.children.clear();
|
|
4184
4244
|
};
|
|
4185
|
-
const
|
|
4186
|
-
|
|
4245
|
+
const markDocumentReplace = (dirty, path) => {
|
|
4246
|
+
replaceAt(dirty, path, 0);
|
|
4247
|
+
};
|
|
4248
|
+
const markDocumentOrderRange = (dirty, path, start) => {
|
|
4249
|
+
const current = locateRange(dirty, path, start);
|
|
4187
4250
|
if (current && !current.replace) current.order = true;
|
|
4188
4251
|
};
|
|
4189
|
-
const markDocumentTree = (dirty, path, root, nodes) => {
|
|
4190
|
-
const current =
|
|
4252
|
+
const markDocumentTree = (dirty, path, start, root, nodes) => {
|
|
4253
|
+
const current = locateRange(dirty, path, start);
|
|
4191
4254
|
if (!current || current.replace) return;
|
|
4192
4255
|
current.treeRoot ||= root;
|
|
4193
|
-
for (const
|
|
4256
|
+
for (const node of nodes) current.treeNodes.add(node.id);
|
|
4194
4257
|
};
|
|
4195
4258
|
const createCollectionPending = () => ({
|
|
4196
4259
|
reset: false,
|
|
@@ -4220,19 +4283,19 @@ const mergeValueChanges = (selector, dirty, changes) => {
|
|
|
4220
4283
|
const at = selector.address;
|
|
4221
4284
|
for (const change of changes.changes) {
|
|
4222
4285
|
if (change.kind === "reset") {
|
|
4223
|
-
|
|
4286
|
+
replaceAt(dirty, at, at.length);
|
|
4224
4287
|
return;
|
|
4225
4288
|
}
|
|
4226
4289
|
if (change.kind === "members") {
|
|
4227
4290
|
for (const member of change.members) {
|
|
4228
|
-
const
|
|
4229
|
-
if (
|
|
4230
|
-
else if (
|
|
4291
|
+
const compared = compareExtended(change.at, member.key, at);
|
|
4292
|
+
if (compared === "ancestor" || compared === "equal") replaceAt(dirty, at, at.length);
|
|
4293
|
+
else if (compared === "descendant") replaceAt(dirty, change.at, at.length, member.key);
|
|
4231
4294
|
}
|
|
4232
|
-
if (change.order && contains(at, change.at))
|
|
4295
|
+
if (change.order && contains(at, change.at)) markDocumentOrderRange(dirty, change.at, at.length);
|
|
4233
4296
|
continue;
|
|
4234
4297
|
}
|
|
4235
|
-
if (contains(at, change.at)) markDocumentTree(dirty, change.at
|
|
4298
|
+
if (contains(at, change.at)) markDocumentTree(dirty, change.at, at.length, change.before !== change.after, change.nodes);
|
|
4236
4299
|
}
|
|
4237
4300
|
};
|
|
4238
4301
|
const mergeCollectionChanges = (selector, pending, changes) => {
|
|
@@ -4244,13 +4307,15 @@ const mergeCollectionChanges = (selector, pending, changes) => {
|
|
|
4244
4307
|
return;
|
|
4245
4308
|
}
|
|
4246
4309
|
if (selector.tree?.kind === "nodes") {
|
|
4247
|
-
if (change.kind === "members") {
|
|
4248
|
-
|
|
4310
|
+
if (change.kind === "members") for (const member of change.members) {
|
|
4311
|
+
const compared = compareExtended(change.at, member.key, at);
|
|
4312
|
+
if (compared === "ancestor" || compared === "equal") {
|
|
4249
4313
|
resetCollectionPending(pending);
|
|
4250
4314
|
return;
|
|
4251
4315
|
}
|
|
4252
|
-
}
|
|
4253
|
-
|
|
4316
|
+
}
|
|
4317
|
+
else if (change.at.length === at.length && contains(change.at, at)) for (const node of change.nodes) {
|
|
4318
|
+
replaceAt(dirtyEntry(pending, node.id), at, at.length);
|
|
4254
4319
|
pending.order ||= node.kind !== "updated";
|
|
4255
4320
|
}
|
|
4256
4321
|
else if (contains(change.at, at)) {
|
|
@@ -4261,34 +4326,27 @@ const mergeCollectionChanges = (selector, pending, changes) => {
|
|
|
4261
4326
|
}
|
|
4262
4327
|
if (change.kind === "members") {
|
|
4263
4328
|
for (const member of change.members) {
|
|
4264
|
-
const
|
|
4265
|
-
if (
|
|
4266
|
-
resetCollectionPending(pending);
|
|
4267
|
-
return;
|
|
4268
|
-
}
|
|
4269
|
-
if (!contains(at, changed)) continue;
|
|
4270
|
-
const relative = changed.slice(at.length);
|
|
4271
|
-
if (!relative.length) {
|
|
4329
|
+
const compared = compareExtended(change.at, member.key, at);
|
|
4330
|
+
if (compared === "ancestor" || compared === "equal") {
|
|
4272
4331
|
resetCollectionPending(pending);
|
|
4273
4332
|
return;
|
|
4274
4333
|
}
|
|
4275
|
-
|
|
4276
|
-
if (
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
if (!relative.length) pending.order = true;
|
|
4281
|
-
else markDocumentOrder(dirtyEntry(pending, relative[0]), relative.slice(1));
|
|
4334
|
+
if (compared !== "descendant") continue;
|
|
4335
|
+
if (at.length === change.at.length) {
|
|
4336
|
+
replaceAt(dirtyEntry(pending, member.key), change.at, change.at.length);
|
|
4337
|
+
if (member.kind !== "updated") pending.order = true;
|
|
4338
|
+
} else replaceAt(dirtyEntry(pending, change.at[at.length]), change.at, at.length + 1, member.key);
|
|
4282
4339
|
}
|
|
4340
|
+
if (change.order && contains(at, change.at)) if (change.at.length === at.length) pending.order = true;
|
|
4341
|
+
else markDocumentOrderRange(dirtyEntry(pending, change.at[at.length]), change.at, at.length + 1);
|
|
4283
4342
|
continue;
|
|
4284
4343
|
}
|
|
4285
4344
|
if (!contains(at, change.at)) continue;
|
|
4286
|
-
|
|
4287
|
-
if (!relative.length) {
|
|
4345
|
+
if (change.at.length === at.length) {
|
|
4288
4346
|
resetCollectionPending(pending);
|
|
4289
4347
|
return;
|
|
4290
4348
|
}
|
|
4291
|
-
markDocumentTree(dirtyEntry(pending,
|
|
4349
|
+
markDocumentTree(dirtyEntry(pending, change.at[at.length]), change.at, at.length + 1, change.before !== change.after, change.nodes);
|
|
4292
4350
|
}
|
|
4293
4351
|
};
|
|
4294
4352
|
//#endregion
|
|
@@ -4417,16 +4475,29 @@ const stageCollectionRead = (state, read, active, options) => {
|
|
|
4417
4475
|
evaluation.output.order(ids);
|
|
4418
4476
|
} else {
|
|
4419
4477
|
const previous = state.current();
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
for (const key of
|
|
4478
|
+
let currentIds;
|
|
4479
|
+
const ids = () => currentIds ??= read.ids();
|
|
4480
|
+
if (options.candidates) for (const key of options.candidates) if (read.has(key)) {
|
|
4423
4481
|
profile.collectionView.mapped();
|
|
4424
4482
|
evaluation.output.set(key, read.get(key));
|
|
4425
4483
|
} else evaluation.output.remove(key);
|
|
4484
|
+
else {
|
|
4485
|
+
const previousIds = previous.ids();
|
|
4486
|
+
const nextIds = ids();
|
|
4487
|
+
profile.collectionView.idsScanned(previousIds.length + nextIds.length);
|
|
4488
|
+
for (const key of previousIds) if (read.has(key)) {
|
|
4489
|
+
profile.collectionView.mapped();
|
|
4490
|
+
evaluation.output.set(key, read.get(key));
|
|
4491
|
+
} else evaluation.output.remove(key);
|
|
4492
|
+
for (const key of nextIds) if (!previous.has(key)) {
|
|
4493
|
+
profile.collectionView.mapped();
|
|
4494
|
+
evaluation.output.set(key, read.get(key));
|
|
4495
|
+
}
|
|
4496
|
+
}
|
|
4426
4497
|
if (options.orderMayChange || !options.candidates) {
|
|
4427
|
-
const
|
|
4428
|
-
if (options.candidates) profile.collectionView.idsScanned(
|
|
4429
|
-
evaluation.output.order(
|
|
4498
|
+
const nextIds = ids();
|
|
4499
|
+
if (options.candidates) profile.collectionView.idsScanned(nextIds.length);
|
|
4500
|
+
evaluation.output.order(nextIds);
|
|
4430
4501
|
}
|
|
4431
4502
|
}
|
|
4432
4503
|
return state.seal(options.reset, options.isEqual ?? Object.is);
|
|
@@ -4720,13 +4791,15 @@ const createDocumentSourceRegistry = (scheduler) => {
|
|
|
4720
4791
|
const snapshots = /* @__PURE__ */ new Map();
|
|
4721
4792
|
const replacement = createDocumentDirty();
|
|
4722
4793
|
if (pending.reset) markDocumentReplace(replacement, []);
|
|
4794
|
+
let cachedIds;
|
|
4723
4795
|
const ids = () => {
|
|
4724
4796
|
assertScope(active);
|
|
4725
|
-
if (
|
|
4726
|
-
if (node?.kind === "
|
|
4727
|
-
if (node?.kind === "
|
|
4728
|
-
if (node?.kind === "
|
|
4729
|
-
return Object.freeze(
|
|
4797
|
+
if (cachedIds) return cachedIds;
|
|
4798
|
+
if (treeNodes) return cachedIds = node?.kind === "tree" && isRecord(value) && isRecord(value.nodes) ? Object.freeze(Object.keys(value.nodes)) : Object.freeze([]);
|
|
4799
|
+
if (node?.kind === "map" && isRecord(value)) return cachedIds = Object.freeze(Object.keys(value));
|
|
4800
|
+
if (node?.kind === "table" && isRecord(value) && Array.isArray(value.ids)) return cachedIds = Object.freeze([...value.ids]);
|
|
4801
|
+
if (node?.kind === "list" && Array.isArray(value)) return cachedIds = Object.freeze(toArray(indexedKeys(value, node.keyOf)));
|
|
4802
|
+
return cachedIds = Object.freeze([]);
|
|
4730
4803
|
};
|
|
4731
4804
|
const has = (key) => {
|
|
4732
4805
|
assertScope(active);
|
|
@@ -5214,7 +5287,6 @@ const createSourceRegistry = (scheduler) => {
|
|
|
5214
5287
|
};
|
|
5215
5288
|
//#endregion
|
|
5216
5289
|
//#region core/src/projection/readable/keyed.ts
|
|
5217
|
-
const sameKeys = (previous, next) => previous.length === next.length && previous.every((key, index) => key === next[index]);
|
|
5218
5290
|
/** Runtime-owned keyed consumer family over one materialized collection output. */
|
|
5219
5291
|
const createProjectionItems = (source, checkOwner) => {
|
|
5220
5292
|
if (source.kind !== "collection") throw new TypeError("Projection items require a keyed collection projection.");
|
|
@@ -5234,7 +5306,11 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
5234
5306
|
for (const listener of listeners) notifications.push(listener);
|
|
5235
5307
|
};
|
|
5236
5308
|
const flushNotifications = () => {
|
|
5237
|
-
|
|
5309
|
+
try {
|
|
5310
|
+
notifyProjectionListenerSnapshot(notifications, "Projection item listeners failed.");
|
|
5311
|
+
} finally {
|
|
5312
|
+
notifications.length = 0;
|
|
5313
|
+
}
|
|
5238
5314
|
};
|
|
5239
5315
|
const unregisterWaiting = (state) => {
|
|
5240
5316
|
const states = waiting.get(state.key);
|
|
@@ -5277,16 +5353,11 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
5277
5353
|
publishState(state, void 0);
|
|
5278
5354
|
state.ended = true;
|
|
5279
5355
|
};
|
|
5280
|
-
const
|
|
5281
|
-
const result = [];
|
|
5356
|
+
const terminateKey = (key) => {
|
|
5282
5357
|
const canonical = active.get(key);
|
|
5283
|
-
if (canonical)
|
|
5358
|
+
if (canonical) terminateState(canonical);
|
|
5284
5359
|
const extra = followers.get(key);
|
|
5285
|
-
if (extra)
|
|
5286
|
-
return result;
|
|
5287
|
-
};
|
|
5288
|
-
const terminateKey = (key) => {
|
|
5289
|
-
for (const state of statesFor(key)) terminateState(state);
|
|
5360
|
+
if (extra) for (const state of extra) terminateState(state);
|
|
5290
5361
|
active.delete(key);
|
|
5291
5362
|
followers.delete(key);
|
|
5292
5363
|
};
|
|
@@ -5297,12 +5368,14 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
5297
5368
|
for (const state of states) attachActive(state, value);
|
|
5298
5369
|
};
|
|
5299
5370
|
const updateKey = (key, value) => {
|
|
5300
|
-
|
|
5371
|
+
const canonical = active.get(key);
|
|
5372
|
+
if (canonical) publishState(canonical, value);
|
|
5373
|
+
const extra = followers.get(key);
|
|
5374
|
+
if (extra) for (const state of extra) publishState(state, value);
|
|
5301
5375
|
};
|
|
5302
5376
|
const updateKeys = (current) => {
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
keysValue = next;
|
|
5377
|
+
if (iterableMatchesArray(current.keys(), keysValue)) return;
|
|
5378
|
+
keysValue = Object.freeze([...current.keys()]);
|
|
5306
5379
|
keysRevision++;
|
|
5307
5380
|
notify(keyListeners);
|
|
5308
5381
|
};
|
|
@@ -5345,9 +5418,9 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
5345
5418
|
return state;
|
|
5346
5419
|
};
|
|
5347
5420
|
const reconcile = (current) => {
|
|
5348
|
-
for (const key of
|
|
5421
|
+
for (const key of active.keys()) if (!current.has(key)) terminateKey(key);
|
|
5349
5422
|
else updateKey(key, current.get(key));
|
|
5350
|
-
for (const key of
|
|
5423
|
+
for (const key of waiting.keys()) if (current.has(key)) activateWaiting(key, current.get(key));
|
|
5351
5424
|
updateKeys(current);
|
|
5352
5425
|
};
|
|
5353
5426
|
const onChange = (change) => {
|