doxum 0.1.26 → 0.1.27
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 +21 -1
- package/dist/advanced.cjs +5 -21
- package/dist/advanced.cjs.map +1 -1
- package/dist/advanced.d.cts +8 -1
- package/dist/advanced.d.ts +8 -1
- package/dist/advanced.js +5 -22
- package/dist/advanced.js.map +1 -1
- package/dist/index.cjs +364 -192
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -16
- package/dist/index.d.ts +40 -16
- package/dist/index.js +361 -189
- package/dist/index.js.map +1 -1
- package/dist/{scheduler-D4VthaaK.cjs → scheduler-k1ZGR1PG.cjs} +136 -1
- package/dist/scheduler-k1ZGR1PG.cjs.map +1 -0
- package/dist/{scheduler--137L3j-.js → scheduler-vzf3OcjT.js} +95 -2
- package/dist/scheduler-vzf3OcjT.js.map +1 -0
- package/package.json +1 -1
- package/skills/doxum-runtime/SKILL.md +8 -4
- package/skills/doxum-runtime/references/api.en.md +28 -13
- package/skills/doxum-runtime/references/api.zh-CN.md +27 -12
- package/skills/doxum-runtime/references/projections.en.md +31 -2
- package/skills/doxum-runtime/references/projections.zh-CN.md +30 -1
- package/dist/scheduler--137L3j-.js.map +0 -1
- package/dist/scheduler-D4VthaaK.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_scheduler = require("./scheduler-
|
|
2
|
+
const require_scheduler = require("./scheduler-k1ZGR1PG.cjs");
|
|
3
3
|
const require_record = require("./record-ChYUi8PP.cjs");
|
|
4
4
|
const require_driver = require("./driver-BL91gn7_.cjs");
|
|
5
5
|
//#region core/src/schema/model.ts
|
|
@@ -2735,14 +2735,9 @@ const isExternalSource = (source) => {
|
|
|
2735
2735
|
return (candidate.kind === "value" || candidate.kind === "collection") && typeof candidate.current === "function" && typeof candidate.revision === "function" && typeof candidate.subscribe === "function";
|
|
2736
2736
|
};
|
|
2737
2737
|
//#endregion
|
|
2738
|
-
//#region core/src/projection/derive.ts
|
|
2739
|
-
const sourceValue = (source) => source.kind === "value" ? source.value : require_scheduler.snapshotCollectionView(source.read);
|
|
2738
|
+
//#region core/src/projection/derive/keyed.ts
|
|
2740
2739
|
const outputKind = (projection) => {
|
|
2741
|
-
|
|
2742
|
-
const definition = ref.producer;
|
|
2743
|
-
const output = definition.kind === "source" ? definition.output : definition.outputs[ref.output];
|
|
2744
|
-
if (!output) throw new TypeError("Projection output does not exist.");
|
|
2745
|
-
return output.kind;
|
|
2740
|
+
return require_scheduler.outputDefinitionOf(projection).kind;
|
|
2746
2741
|
};
|
|
2747
2742
|
const assertKeyedProjection = (projection, role) => {
|
|
2748
2743
|
if (outputKind(projection) !== "collection") throw new TypeError(`${role} must be a keyed collection projection.`);
|
|
@@ -2768,41 +2763,29 @@ const bindKey = (index, outputKey, sourceKey) => {
|
|
|
2768
2763
|
else index.reverse.set(sourceKey, new Set([outputKey]));
|
|
2769
2764
|
};
|
|
2770
2765
|
const unbindKey = (indexes, outputKey) => {
|
|
2771
|
-
for (const index of indexes) bindKey(index, outputKey, void 0);
|
|
2766
|
+
for (const index of indexes) if (index) bindKey(index, outputKey, void 0);
|
|
2772
2767
|
};
|
|
2773
2768
|
const createBindingIndex = () => ({
|
|
2774
2769
|
forward: /* @__PURE__ */ new Map(),
|
|
2775
2770
|
reverse: /* @__PURE__ */ new Map()
|
|
2776
2771
|
});
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
const
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
const next = compute(Object.freeze(values));
|
|
2794
|
-
require_scheduler.assertSynchronous(next);
|
|
2795
|
-
output.output.set(next);
|
|
2796
|
-
} })
|
|
2797
|
-
});
|
|
2798
|
-
return projection;
|
|
2799
|
-
}
|
|
2800
|
-
function createKeyedDerive(source, dependenciesOrSelect, selectOrEquality, maybeEquality) {
|
|
2772
|
+
const emptyKeyedDependencies = Object.freeze(Object.create(null));
|
|
2773
|
+
const absent = Symbol("keyed-transform-absent");
|
|
2774
|
+
const compileOrderedKeys = (value, role) => {
|
|
2775
|
+
if (!Array.isArray(value)) throw new TypeError(`${role} must be an array of string keys.`);
|
|
2776
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2777
|
+
for (const key of value) {
|
|
2778
|
+
if (typeof key !== "string") throw new TypeError(`${role} must contain only string keys.`);
|
|
2779
|
+
if (seen.has(key)) throw new TypeError(`${role} must not contain duplicate keys.`);
|
|
2780
|
+
seen.add(key);
|
|
2781
|
+
}
|
|
2782
|
+
return {
|
|
2783
|
+
keys: value,
|
|
2784
|
+
requested: seen
|
|
2785
|
+
};
|
|
2786
|
+
};
|
|
2787
|
+
const createKeyedTransform = (source, dependencySpecs, select, equality, name) => {
|
|
2801
2788
|
assertKeyedProjection(source, "Keyed derive source");
|
|
2802
|
-
const dependencySpecs = typeof dependenciesOrSelect === "function" ? void 0 : dependenciesOrSelect;
|
|
2803
|
-
const select = dependencySpecs === void 0 ? dependenciesOrSelect : selectOrEquality;
|
|
2804
|
-
const equality = dependencySpecs === void 0 ? selectOrEquality : maybeEquality;
|
|
2805
|
-
if (typeof select !== "function") throw new TypeError("Keyed derive requires a selector.");
|
|
2806
2789
|
const dependencies = [source];
|
|
2807
2790
|
const dependencyNames = [];
|
|
2808
2791
|
const keyed = [];
|
|
@@ -2833,81 +2816,91 @@ function createKeyedDerive(source, dependenciesOrSelect, selectOrEquality, maybe
|
|
|
2833
2816
|
}],
|
|
2834
2817
|
create: () => {
|
|
2835
2818
|
const bindings = keyed.map((dependency) => dependency ? createBindingIndex() : void 0);
|
|
2836
|
-
const bindingIndexes = bindings.filter((index) => index !== void 0);
|
|
2837
2819
|
const globalValues = keyed.map(() => void 0);
|
|
2838
|
-
|
|
2820
|
+
const revisions = [];
|
|
2839
2821
|
const clearBindings = () => {
|
|
2840
2822
|
for (const index of bindings) {
|
|
2841
2823
|
index?.forward.clear();
|
|
2842
2824
|
index?.reverse.clear();
|
|
2843
2825
|
}
|
|
2844
2826
|
};
|
|
2827
|
+
const rememberRevisions = (sources) => {
|
|
2828
|
+
revisions.length = sources.length;
|
|
2829
|
+
for (let index = 0; index < sources.length; index++) revisions[index] = sources[index].revision;
|
|
2830
|
+
};
|
|
2845
2831
|
return {
|
|
2846
2832
|
evaluate: (evaluation) => {
|
|
2847
2833
|
const driver = evaluation.sources[0];
|
|
2848
2834
|
const output = evaluation.outputs[0];
|
|
2849
2835
|
if (driver.kind !== "collection" || output.kind !== "collection") throw new Error("Keyed derive requires collection input and output.");
|
|
2850
|
-
const currentRevisions = evaluation.sources.map((current) => current.revision);
|
|
2851
2836
|
for (let index = 0; index < keyed.length; index++) {
|
|
2852
2837
|
if (keyed[index]) continue;
|
|
2853
|
-
|
|
2838
|
+
const dependencySource = evaluation.sources[index + 1];
|
|
2839
|
+
if (evaluation.reset || revisions[index + 1] !== dependencySource.revision) globalValues[index] = require_scheduler.snapshotDependencyValue(dependencySource);
|
|
2854
2840
|
}
|
|
2855
2841
|
const project = (key) => {
|
|
2856
2842
|
if (!driver.read.has(key)) return;
|
|
2857
2843
|
const value = driver.read.get(key);
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
const
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2844
|
+
let dependencyValues = emptyKeyedDependencies;
|
|
2845
|
+
if (keyed.length) {
|
|
2846
|
+
const values = Object.create(null);
|
|
2847
|
+
for (let index = 0; index < keyed.length; index++) {
|
|
2848
|
+
const dependency = keyed[index];
|
|
2849
|
+
if (!dependency) {
|
|
2850
|
+
values[dependencyNames[index]] = globalValues[index];
|
|
2851
|
+
continue;
|
|
2852
|
+
}
|
|
2853
|
+
const sourceContext = evaluation.sources[index + 1];
|
|
2854
|
+
if (sourceContext.kind !== "collection") throw new TypeError("Dynamic keyed dependency resolved to a non-collection source.");
|
|
2855
|
+
const selectedKey = dependency.key(value, key);
|
|
2856
|
+
require_scheduler.assertSynchronous(selectedKey);
|
|
2857
|
+
if (selectedKey !== void 0 && typeof selectedKey !== "string") throw new TypeError("Dynamic keyed dependency keys must be strings or undefined.");
|
|
2858
|
+
bindKey(bindings[index], key, selectedKey);
|
|
2859
|
+
values[dependencyNames[index]] = selectedKey === void 0 ? void 0 : sourceContext.read.get(selectedKey);
|
|
2864
2860
|
}
|
|
2865
|
-
|
|
2866
|
-
if (sourceContext.kind !== "collection") throw new TypeError("Dynamic keyed dependency resolved to a non-collection source.");
|
|
2867
|
-
const selectedKey = dependency.key(value, key);
|
|
2868
|
-
require_scheduler.assertSynchronous(selectedKey);
|
|
2869
|
-
if (selectedKey !== void 0 && typeof selectedKey !== "string") throw new TypeError("Dynamic keyed dependency keys must be strings or undefined.");
|
|
2870
|
-
bindKey(bindings[index], key, selectedKey);
|
|
2871
|
-
dependencyValues[dependencyNames[index]] = selectedKey === void 0 ? void 0 : sourceContext.read.get(selectedKey);
|
|
2861
|
+
dependencyValues = Object.freeze(values);
|
|
2872
2862
|
}
|
|
2873
|
-
const next =
|
|
2863
|
+
const next = select(value, key, dependencyValues);
|
|
2874
2864
|
require_scheduler.assertSynchronous(next);
|
|
2875
|
-
output.output.
|
|
2865
|
+
if (next === absent) output.output.remove(key);
|
|
2866
|
+
else output.output.set(key, next);
|
|
2876
2867
|
};
|
|
2877
2868
|
if (evaluation.reset) {
|
|
2878
2869
|
clearBindings();
|
|
2879
2870
|
const ids = driver.read.ids();
|
|
2880
2871
|
for (const key of ids) project(key);
|
|
2881
|
-
output.output.order(ids);
|
|
2882
|
-
|
|
2872
|
+
output.output.order(ids.filter((key) => output.next.has(key)));
|
|
2873
|
+
rememberRevisions(evaluation.sources);
|
|
2883
2874
|
return;
|
|
2884
2875
|
}
|
|
2885
2876
|
const dirty = /* @__PURE__ */ new Set();
|
|
2886
2877
|
let all = false;
|
|
2887
2878
|
let updateOrder = false;
|
|
2888
|
-
|
|
2879
|
+
let membershipChanged = false;
|
|
2880
|
+
if (revisions[0] !== driver.revision) {
|
|
2889
2881
|
const change = driver.change;
|
|
2890
2882
|
if (!change || change.kind === "reset") {
|
|
2891
2883
|
all = true;
|
|
2892
2884
|
updateOrder = true;
|
|
2893
2885
|
} else {
|
|
2894
2886
|
for (const entry of change.removed) {
|
|
2887
|
+
membershipChanged ||= output.previous.has(entry.key);
|
|
2895
2888
|
output.output.remove(entry.key);
|
|
2896
|
-
unbindKey(
|
|
2889
|
+
unbindKey(bindings, entry.key);
|
|
2897
2890
|
dirty.delete(entry.key);
|
|
2898
2891
|
}
|
|
2899
2892
|
for (const entry of change.added) dirty.add(entry.key);
|
|
2900
2893
|
for (const entry of change.updated) dirty.add(entry.key);
|
|
2901
|
-
updateOrder = Boolean(change.
|
|
2894
|
+
updateOrder = Boolean(change.order);
|
|
2902
2895
|
}
|
|
2903
2896
|
}
|
|
2904
2897
|
for (let index = 0; index < keyed.length; index++) {
|
|
2905
|
-
|
|
2898
|
+
const sourceContext = evaluation.sources[index + 1];
|
|
2899
|
+
if (revisions[index + 1] === sourceContext.revision) continue;
|
|
2906
2900
|
if (!keyed[index]) {
|
|
2907
2901
|
all = true;
|
|
2908
2902
|
continue;
|
|
2909
2903
|
}
|
|
2910
|
-
const sourceContext = evaluation.sources[index + 1];
|
|
2911
2904
|
if (sourceContext.kind !== "collection" || !sourceContext.change) {
|
|
2912
2905
|
all = true;
|
|
2913
2906
|
continue;
|
|
@@ -2917,86 +2910,274 @@ function createKeyedDerive(source, dependenciesOrSelect, selectOrEquality, maybe
|
|
|
2917
2910
|
continue;
|
|
2918
2911
|
}
|
|
2919
2912
|
const reverse = bindings[index].reverse;
|
|
2920
|
-
for (const
|
|
2921
|
-
for (const transition of sourceContext.change.updated) for (const outputKey of reverse.get(transition.key) ?? []) dirty.add(outputKey);
|
|
2922
|
-
for (const transition of sourceContext.change.removed) for (const outputKey of reverse.get(transition.key) ?? []) dirty.add(outputKey);
|
|
2913
|
+
for (const sourceKey of require_scheduler.collectionChange.keys(sourceContext.change)) for (const outputKey of reverse.get(sourceKey) ?? []) dirty.add(outputKey);
|
|
2923
2914
|
}
|
|
2924
2915
|
if (all) for (const key of driver.read.ids()) dirty.add(key);
|
|
2925
|
-
for (const key of dirty)
|
|
2926
|
-
|
|
2927
|
-
|
|
2916
|
+
for (const key of dirty) {
|
|
2917
|
+
if (!driver.read.has(key)) continue;
|
|
2918
|
+
const beforePresent = output.previous.has(key);
|
|
2919
|
+
project(key);
|
|
2920
|
+
membershipChanged ||= beforePresent !== output.next.has(key);
|
|
2921
|
+
}
|
|
2922
|
+
if (updateOrder || membershipChanged) output.output.order(driver.read.ids().filter((key) => output.next.has(key)));
|
|
2923
|
+
rememberRevisions(evaluation.sources);
|
|
2928
2924
|
},
|
|
2929
2925
|
release: () => {
|
|
2930
2926
|
clearBindings();
|
|
2931
|
-
revisions =
|
|
2927
|
+
revisions.length = 0;
|
|
2932
2928
|
}
|
|
2933
2929
|
};
|
|
2934
2930
|
},
|
|
2935
|
-
name
|
|
2931
|
+
name
|
|
2936
2932
|
});
|
|
2937
2933
|
return projection;
|
|
2934
|
+
};
|
|
2935
|
+
function createKeyedDerive(source, dependenciesOrSelect, selectOrEquality, maybeEquality) {
|
|
2936
|
+
const dependencySpecs = typeof dependenciesOrSelect === "function" ? void 0 : dependenciesOrSelect;
|
|
2937
|
+
const select = dependencySpecs === void 0 ? dependenciesOrSelect : selectOrEquality;
|
|
2938
|
+
const equality = dependencySpecs === void 0 ? selectOrEquality : maybeEquality;
|
|
2939
|
+
if (typeof select !== "function") throw new TypeError("Keyed derive requires a selector.");
|
|
2940
|
+
return createKeyedTransform(source, dependencySpecs, (value, key, dependencies) => dependencySpecs === void 0 ? select(value, key) : select(value, key, dependencies), equality, "derive.keyed");
|
|
2938
2941
|
}
|
|
2939
|
-
const
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
}
|
|
2947
|
-
|
|
2948
|
-
const
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
kind: "incremental",
|
|
2955
|
-
added: Object.freeze([...input.added]),
|
|
2956
|
-
updated: Object.freeze([...input.updated]),
|
|
2957
|
-
removed: Object.freeze([...input.removed]),
|
|
2958
|
-
...orderChanged ? { order: Object.freeze({
|
|
2959
|
-
before: Object.freeze([...input.beforeOrder]),
|
|
2960
|
-
after: Object.freeze([...input.afterOrder])
|
|
2961
|
-
}) } : {}
|
|
2942
|
+
const createKeyedKeys = (source) => {
|
|
2943
|
+
assertKeyedProjection(source, "Keyed keys source");
|
|
2944
|
+
const [projection] = require_scheduler.defineProcessor({
|
|
2945
|
+
dependencies: [source],
|
|
2946
|
+
outputs: [{
|
|
2947
|
+
kind: "value",
|
|
2948
|
+
equality: Object.is
|
|
2949
|
+
}],
|
|
2950
|
+
create: () => ({ evaluate: (evaluation) => {
|
|
2951
|
+
const driver = evaluation.sources[0];
|
|
2952
|
+
const output = evaluation.outputs[0];
|
|
2953
|
+
if (driver.kind !== "collection" || output.kind !== "value") throw new Error("derive.keyed.keys requires collection input and value output.");
|
|
2954
|
+
if (evaluation.reset || !driver.change || require_scheduler.collectionHasStructuralChange(driver.change)) output.output.set(driver.read.ids());
|
|
2955
|
+
} }),
|
|
2956
|
+
name: "derive.keyed.keys"
|
|
2962
2957
|
});
|
|
2958
|
+
return projection;
|
|
2963
2959
|
};
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
const
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2960
|
+
const createKeyedValues = (source) => {
|
|
2961
|
+
assertKeyedProjection(source, "Keyed values source");
|
|
2962
|
+
const [projection] = require_scheduler.defineProcessor({
|
|
2963
|
+
dependencies: [source],
|
|
2964
|
+
outputs: [{
|
|
2965
|
+
kind: "value",
|
|
2966
|
+
equality: Object.is
|
|
2967
|
+
}],
|
|
2968
|
+
create: () => {
|
|
2969
|
+
let indexes = /* @__PURE__ */ new Map();
|
|
2970
|
+
const rebuild = (driver) => {
|
|
2971
|
+
const nextIndexes = /* @__PURE__ */ new Map();
|
|
2972
|
+
const ids = driver.read.ids();
|
|
2973
|
+
const values = Object.freeze(ids.map((key, index) => {
|
|
2974
|
+
nextIndexes.set(key, index);
|
|
2975
|
+
return driver.read.get(key);
|
|
2976
|
+
}));
|
|
2977
|
+
indexes = nextIndexes;
|
|
2978
|
+
return values;
|
|
2979
|
+
};
|
|
2980
|
+
const rebuildIncremental = (driver, change, previous) => {
|
|
2981
|
+
const changedValues = /* @__PURE__ */ new Map();
|
|
2982
|
+
for (const entry of change.added) changedValues.set(entry.key, entry.after);
|
|
2983
|
+
for (const entry of change.updated) changedValues.set(entry.key, entry.after);
|
|
2984
|
+
const nextIndexes = /* @__PURE__ */ new Map();
|
|
2985
|
+
const values = Object.freeze(driver.read.ids().map((key, index) => {
|
|
2986
|
+
nextIndexes.set(key, index);
|
|
2987
|
+
if (changedValues.has(key)) return changedValues.get(key);
|
|
2988
|
+
const previousIndex = indexes.get(key);
|
|
2989
|
+
return previousIndex === void 0 ? driver.read.get(key) : previous[previousIndex];
|
|
2990
|
+
}));
|
|
2991
|
+
indexes = nextIndexes;
|
|
2992
|
+
return values;
|
|
2993
|
+
};
|
|
2994
|
+
return {
|
|
2995
|
+
evaluate: (evaluation) => {
|
|
2996
|
+
const driver = evaluation.sources[0];
|
|
2997
|
+
const output = evaluation.outputs[0];
|
|
2998
|
+
if (driver.kind !== "collection" || output.kind !== "value") throw new Error("derive.keyed.values requires collection input and value output.");
|
|
2999
|
+
const change = driver.change;
|
|
3000
|
+
if (evaluation.reset || !change || change.kind === "reset") {
|
|
3001
|
+
output.output.set(rebuild(driver));
|
|
3002
|
+
return;
|
|
3003
|
+
}
|
|
3004
|
+
const previous = output.previous;
|
|
3005
|
+
if (!previous) {
|
|
3006
|
+
output.output.set(rebuild(driver));
|
|
3007
|
+
return;
|
|
3008
|
+
}
|
|
3009
|
+
if (require_scheduler.collectionHasStructuralChange(change)) {
|
|
3010
|
+
output.output.set(rebuildIncremental(driver, change, previous));
|
|
3011
|
+
return;
|
|
3012
|
+
}
|
|
3013
|
+
if (!change.updated.length) return;
|
|
3014
|
+
const next = [...previous];
|
|
3015
|
+
for (const entry of change.updated) {
|
|
3016
|
+
const index = indexes.get(entry.key);
|
|
3017
|
+
if (index === void 0) {
|
|
3018
|
+
output.output.set(rebuild(driver));
|
|
3019
|
+
return;
|
|
3020
|
+
}
|
|
3021
|
+
next[index] = entry.after;
|
|
3022
|
+
}
|
|
3023
|
+
output.output.set(Object.freeze(next));
|
|
3024
|
+
},
|
|
3025
|
+
release: () => indexes.clear()
|
|
3026
|
+
};
|
|
3027
|
+
},
|
|
3028
|
+
name: "derive.keyed.values"
|
|
2984
3029
|
});
|
|
2985
|
-
return
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
3030
|
+
return projection;
|
|
3031
|
+
};
|
|
3032
|
+
function createKeyedFilter(source, dependenciesOrPredicate, maybePredicate) {
|
|
3033
|
+
const dependencySpecs = typeof dependenciesOrPredicate === "function" ? void 0 : dependenciesOrPredicate;
|
|
3034
|
+
const predicate = dependencySpecs === void 0 ? dependenciesOrPredicate : maybePredicate;
|
|
3035
|
+
if (typeof predicate !== "function") throw new TypeError("Keyed filter requires a predicate.");
|
|
3036
|
+
return createKeyedTransform(source, dependencySpecs, (value, key, dependencies) => {
|
|
3037
|
+
const included = dependencySpecs === void 0 ? predicate(value, key) : predicate(value, key, dependencies);
|
|
3038
|
+
require_scheduler.assertSynchronous(included);
|
|
3039
|
+
if (typeof included !== "boolean") throw new TypeError("Keyed filter predicate must return boolean.");
|
|
3040
|
+
return included ? value : absent;
|
|
3041
|
+
}, Object.is, "derive.keyed.filter");
|
|
3042
|
+
}
|
|
3043
|
+
function createKeyedCompact(source, dependenciesOrSelect, selectOrEquality, maybeEquality) {
|
|
3044
|
+
const dependencySpecs = typeof dependenciesOrSelect === "function" ? void 0 : dependenciesOrSelect;
|
|
3045
|
+
const select = dependencySpecs === void 0 ? dependenciesOrSelect : selectOrEquality;
|
|
3046
|
+
const equality = dependencySpecs === void 0 ? selectOrEquality : maybeEquality;
|
|
3047
|
+
if (typeof select !== "function") throw new TypeError("Keyed compact requires a selector.");
|
|
3048
|
+
return createKeyedTransform(source, dependencySpecs, (value, key, dependencies) => {
|
|
3049
|
+
const next = dependencySpecs === void 0 ? select(value, key) : select(value, key, dependencies);
|
|
3050
|
+
require_scheduler.assertSynchronous(next);
|
|
3051
|
+
return next === void 0 ? absent : next;
|
|
3052
|
+
}, equality, "derive.keyed.compact");
|
|
3053
|
+
}
|
|
3054
|
+
const createKeyedSubset = (source, orderedKeys) => {
|
|
3055
|
+
assertKeyedProjection(source, "Keyed subset source");
|
|
3056
|
+
const keyProjection = require_scheduler.isProjection(orderedKeys) ? orderedKeys : void 0;
|
|
3057
|
+
if (keyProjection && outputKind(keyProjection) !== "value") throw new TypeError("Keyed subset ordered keys must be a value projection.");
|
|
3058
|
+
const staticSelection = keyProjection ? void 0 : (() => {
|
|
3059
|
+
const compiled = compileOrderedKeys(orderedKeys, "Keyed subset ordered keys");
|
|
3060
|
+
return {
|
|
3061
|
+
keys: Object.freeze([...compiled.keys]),
|
|
3062
|
+
requested: compiled.requested
|
|
3063
|
+
};
|
|
3064
|
+
})();
|
|
3065
|
+
const [projection] = require_scheduler.defineProcessor({
|
|
3066
|
+
dependencies: keyProjection ? [source, keyProjection] : [source],
|
|
3067
|
+
outputs: [{
|
|
3068
|
+
kind: "collection",
|
|
3069
|
+
equality: Object.is
|
|
3070
|
+
}],
|
|
3071
|
+
create: () => {
|
|
3072
|
+
let keys = staticSelection?.keys;
|
|
3073
|
+
let requested = staticSelection?.requested;
|
|
3074
|
+
let keyRevision = -1;
|
|
3075
|
+
return {
|
|
3076
|
+
evaluate: (evaluation) => {
|
|
3077
|
+
const driver = evaluation.sources[0];
|
|
3078
|
+
const output = evaluation.outputs[0];
|
|
3079
|
+
if (driver.kind !== "collection" || output.kind !== "collection") throw new Error("derive.keyed.subset requires collection input and output.");
|
|
3080
|
+
let keysChanged = false;
|
|
3081
|
+
if (keyProjection) {
|
|
3082
|
+
const sourceContext = evaluation.sources[1];
|
|
3083
|
+
if (sourceContext?.kind !== "value") throw new TypeError("Keyed subset ordered keys resolved to a collection.");
|
|
3084
|
+
if (keys === void 0 || sourceContext.reset || keyRevision !== sourceContext.revision) {
|
|
3085
|
+
const compiled = compileOrderedKeys(sourceContext.value, "Keyed subset ordered keys");
|
|
3086
|
+
keys = compiled.keys;
|
|
3087
|
+
requested = compiled.requested;
|
|
3088
|
+
keyRevision = sourceContext.revision;
|
|
3089
|
+
keysChanged = true;
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
if (!keys || !requested) throw new Error("Keyed subset keys were not initialized.");
|
|
3093
|
+
const activeKeys = keys;
|
|
3094
|
+
const activeRequested = requested;
|
|
3095
|
+
const orderedPresentKeys = () => activeKeys.filter((key) => driver.read.has(key));
|
|
3096
|
+
const rebuild = () => {
|
|
3097
|
+
const nextKeys = orderedPresentKeys();
|
|
3098
|
+
for (const key of nextKeys) output.output.set(key, driver.read.get(key));
|
|
3099
|
+
output.output.order(nextKeys);
|
|
3100
|
+
};
|
|
3101
|
+
const reconcileKeys = () => {
|
|
3102
|
+
const nextKeys = orderedPresentKeys();
|
|
3103
|
+
for (const key of output.previous.ids()) if (!activeRequested.has(key) || !driver.read.has(key)) output.output.remove(key);
|
|
3104
|
+
for (const key of nextKeys) if (!output.previous.has(key)) output.output.set(key, driver.read.get(key));
|
|
3105
|
+
output.output.order(nextKeys);
|
|
3106
|
+
};
|
|
3107
|
+
const change = driver.change;
|
|
3108
|
+
if (evaluation.reset || change?.kind === "reset") rebuild();
|
|
3109
|
+
else if (keysChanged) {
|
|
3110
|
+
reconcileKeys();
|
|
3111
|
+
if (change) for (const entry of change.updated) {
|
|
3112
|
+
const key = entry.key;
|
|
3113
|
+
if (activeRequested.has(key) && output.previous.has(key)) output.output.set(key, entry.after);
|
|
3114
|
+
}
|
|
3115
|
+
} else if (change) {
|
|
3116
|
+
let updateOrder = false;
|
|
3117
|
+
for (const entry of change.removed) {
|
|
3118
|
+
const key = entry.key;
|
|
3119
|
+
if (!activeRequested.has(key)) continue;
|
|
3120
|
+
output.output.remove(key);
|
|
3121
|
+
updateOrder = true;
|
|
3122
|
+
}
|
|
3123
|
+
for (const entry of change.added) {
|
|
3124
|
+
const key = entry.key;
|
|
3125
|
+
if (!activeRequested.has(key)) continue;
|
|
3126
|
+
output.output.set(key, entry.after);
|
|
3127
|
+
updateOrder = true;
|
|
3128
|
+
}
|
|
3129
|
+
for (const entry of change.updated) {
|
|
3130
|
+
const key = entry.key;
|
|
3131
|
+
if (activeRequested.has(key)) output.output.set(key, entry.after);
|
|
3132
|
+
}
|
|
3133
|
+
if (updateOrder) output.output.order(orderedPresentKeys());
|
|
3134
|
+
}
|
|
3135
|
+
},
|
|
3136
|
+
release: () => {
|
|
3137
|
+
if (keyProjection) {
|
|
3138
|
+
keys = void 0;
|
|
3139
|
+
requested = void 0;
|
|
3140
|
+
keyRevision = -1;
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
};
|
|
3144
|
+
},
|
|
3145
|
+
name: "derive.keyed.subset"
|
|
2991
3146
|
});
|
|
3147
|
+
return projection;
|
|
2992
3148
|
};
|
|
2993
|
-
const
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3149
|
+
const keyedDerive = Object.assign(createKeyedDerive, {
|
|
3150
|
+
keys: createKeyedKeys,
|
|
3151
|
+
values: createKeyedValues,
|
|
3152
|
+
subset: createKeyedSubset,
|
|
3153
|
+
filter: createKeyedFilter,
|
|
3154
|
+
compact: createKeyedCompact
|
|
3155
|
+
});
|
|
3156
|
+
//#endregion
|
|
3157
|
+
//#region core/src/projection/derive.ts
|
|
3158
|
+
function createValueDerive(dependencies, compute, equality = Object.is) {
|
|
3159
|
+
const compiled = require_scheduler.compileProjectionDependencies(dependencies, "Derive");
|
|
3160
|
+
const names = compiled.names;
|
|
3161
|
+
const ordered = compiled.projections;
|
|
3162
|
+
const [projection] = require_scheduler.defineProcessor({
|
|
3163
|
+
dependencies: ordered,
|
|
3164
|
+
outputs: [{
|
|
3165
|
+
kind: "value",
|
|
3166
|
+
equality
|
|
3167
|
+
}],
|
|
3168
|
+
create: () => ({ evaluate: (evaluation) => {
|
|
3169
|
+
const output = evaluation.outputs[0];
|
|
3170
|
+
if (output.kind !== "value") throw new Error("derive requires a value output.");
|
|
3171
|
+
const values = Object.create(null);
|
|
3172
|
+
for (let index = 0; index < names.length; index++) values[names[index]] = require_scheduler.snapshotDependencyValue(evaluation.sources[index]);
|
|
3173
|
+
const next = compute(Object.freeze(values));
|
|
3174
|
+
require_scheduler.assertSynchronous(next);
|
|
3175
|
+
output.output.set(next);
|
|
3176
|
+
} })
|
|
3177
|
+
});
|
|
3178
|
+
return projection;
|
|
3179
|
+
}
|
|
3180
|
+
const derive = Object.assign(createValueDerive, { keyed: keyedDerive });
|
|
3000
3181
|
//#endregion
|
|
3001
3182
|
//#region core/src/projection/collection/index.ts
|
|
3002
3183
|
const height = (node) => node?.height ?? 0;
|
|
@@ -3209,15 +3390,36 @@ const createCollectionOutput = (binding) => {
|
|
|
3209
3390
|
require_scheduler.profile.projection("touchedKeys", staged.size);
|
|
3210
3391
|
const added = /* @__PURE__ */ new Set();
|
|
3211
3392
|
const removed = /* @__PURE__ */ new Set();
|
|
3212
|
-
const
|
|
3393
|
+
const addedEntries = [];
|
|
3394
|
+
const updatedEntries = [];
|
|
3395
|
+
const removedEntries = [];
|
|
3213
3396
|
for (const [key, entry] of staged) {
|
|
3214
3397
|
const existed = published.has(key);
|
|
3215
3398
|
if (entry.present) {
|
|
3216
|
-
if (!existed)
|
|
3217
|
-
|
|
3399
|
+
if (!existed) {
|
|
3400
|
+
added.add(key);
|
|
3401
|
+
addedEntries.push({
|
|
3402
|
+
key,
|
|
3403
|
+
after: entry.value
|
|
3404
|
+
});
|
|
3405
|
+
continue;
|
|
3406
|
+
}
|
|
3407
|
+
const before = published.get(key);
|
|
3408
|
+
if (!isEqual(before, entry.value)) updatedEntries.push({
|
|
3409
|
+
key,
|
|
3410
|
+
before,
|
|
3411
|
+
after: entry.value
|
|
3412
|
+
});
|
|
3218
3413
|
else if (!nextReset) staged.delete(key);
|
|
3219
|
-
|
|
3220
|
-
|
|
3414
|
+
continue;
|
|
3415
|
+
}
|
|
3416
|
+
if (existed) {
|
|
3417
|
+
removed.add(key);
|
|
3418
|
+
removedEntries.push({
|
|
3419
|
+
key,
|
|
3420
|
+
before: published.get(key)
|
|
3421
|
+
});
|
|
3422
|
+
} else staged.delete(key);
|
|
3221
3423
|
}
|
|
3222
3424
|
const ids = published.ids();
|
|
3223
3425
|
if (explicitOrder || added.size || removed.size) {
|
|
@@ -3225,36 +3427,8 @@ const createCollectionOutput = (binding) => {
|
|
|
3225
3427
|
if (new Set(order).size !== order.length || order.length !== published.size() + added.size - removed.size || order.some((key) => !hasNext(key))) throw new TypeError("Projection order must contain every key exactly once.");
|
|
3226
3428
|
nextIds = ids.length === order.length && ids.every((key, index) => key === order[index]) ? ids : Object.freeze([...order]);
|
|
3227
3429
|
} else nextIds = ids;
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
removed.forEach((key) => changedKeys.add(key));
|
|
3231
|
-
updated.forEach((key) => changedKeys.add(key));
|
|
3232
|
-
require_scheduler.profile.projection("changedKeys", changedKeys.size);
|
|
3233
|
-
const addedEntries = [];
|
|
3234
|
-
const updatedEntries = [];
|
|
3235
|
-
const removedEntries = [];
|
|
3236
|
-
for (const key of changedKeys) {
|
|
3237
|
-
const beforePresent = published.has(key);
|
|
3238
|
-
const afterPresent = hasNext(key);
|
|
3239
|
-
if (beforePresent === afterPresent) {
|
|
3240
|
-
if (!beforePresent) continue;
|
|
3241
|
-
if (isEqual !== Object.is && isEqual(published.get(key), getNext(key))) continue;
|
|
3242
|
-
}
|
|
3243
|
-
if (!beforePresent) addedEntries.push({
|
|
3244
|
-
key,
|
|
3245
|
-
after: getNext(key)
|
|
3246
|
-
});
|
|
3247
|
-
else if (!afterPresent) removedEntries.push({
|
|
3248
|
-
key,
|
|
3249
|
-
before: published.get(key)
|
|
3250
|
-
});
|
|
3251
|
-
else updatedEntries.push({
|
|
3252
|
-
key,
|
|
3253
|
-
before: published.get(key),
|
|
3254
|
-
after: getNext(key)
|
|
3255
|
-
});
|
|
3256
|
-
}
|
|
3257
|
-
change = nextReset ? Object.freeze({ kind: "reset" }) : createCollectionChange({
|
|
3430
|
+
require_scheduler.profile.projection("changedKeys", addedEntries.length + updatedEntries.length + removedEntries.length);
|
|
3431
|
+
change = nextReset ? Object.freeze({ kind: "reset" }) : require_scheduler.createCollectionChange({
|
|
3258
3432
|
added: addedEntries,
|
|
3259
3433
|
updated: updatedEntries,
|
|
3260
3434
|
removed: removedEntries,
|
|
@@ -3618,10 +3792,9 @@ const trackedMap = (source) => {
|
|
|
3618
3792
|
};
|
|
3619
3793
|
const selectionAffects = (selection, change) => {
|
|
3620
3794
|
if (!change || change.kind === "reset") return true;
|
|
3621
|
-
if (selection.all
|
|
3622
|
-
if (selection.structure && collectionHasStructuralChange(change)) return true;
|
|
3623
|
-
const
|
|
3624
|
-
for (const key of selection.keys) if (changedKeys.has(key)) return true;
|
|
3795
|
+
if (selection.all) return true;
|
|
3796
|
+
if (selection.structure && require_scheduler.collectionHasStructuralChange(change)) return true;
|
|
3797
|
+
for (const key of require_scheduler.collectionChange.keys(change)) if (selection.keys.has(key)) return true;
|
|
3625
3798
|
return false;
|
|
3626
3799
|
};
|
|
3627
3800
|
const createDirectReadable = (source) => Object.freeze({
|
|
@@ -3689,7 +3862,7 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
|
|
|
3689
3862
|
if (!change && previousCollection) {
|
|
3690
3863
|
const current = source.current();
|
|
3691
3864
|
if (isMapLike(current)) {
|
|
3692
|
-
change = diffCollection(previousCollection, current);
|
|
3865
|
+
change = require_scheduler.diffCollection(previousCollection, current);
|
|
3693
3866
|
previousCollection = current;
|
|
3694
3867
|
if (!change) {
|
|
3695
3868
|
sourceRevision = source.revision();
|
|
@@ -4163,7 +4336,7 @@ const stageCollectionRead = (state, read, active, options) => {
|
|
|
4163
4336
|
evaluation.output.order(ids);
|
|
4164
4337
|
} else {
|
|
4165
4338
|
const previous = state.current();
|
|
4166
|
-
const keys = options.candidates ? [...
|
|
4339
|
+
const keys = options.candidates ? [...options.candidates] : [...new Set([...previous.ids(), ...read.ids()])];
|
|
4167
4340
|
if (!options.candidates) require_scheduler.profile.collectionView.idsScanned(keys.length);
|
|
4168
4341
|
for (const key of keys) if (read.has(key)) {
|
|
4169
4342
|
require_scheduler.profile.collectionView.mapped();
|
|
@@ -4852,6 +5025,7 @@ const materializeInputSource = (scheduler, definition) => {
|
|
|
4852
5025
|
scheduler.assertIdle();
|
|
4853
5026
|
const staged = /* @__PURE__ */ new Map();
|
|
4854
5027
|
const operations = [];
|
|
5028
|
+
let structural = false;
|
|
4855
5029
|
let active = true;
|
|
4856
5030
|
const draft = Object.freeze({
|
|
4857
5031
|
get: (key) => {
|
|
@@ -4867,6 +5041,8 @@ const materializeInputSource = (scheduler, definition) => {
|
|
|
4867
5041
|
set: (key, value) => {
|
|
4868
5042
|
require_scheduler.assertScope(() => active);
|
|
4869
5043
|
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
5044
|
+
const previous = staged.get(key);
|
|
5045
|
+
structural ||= previous ? !previous.present : !values.has(key);
|
|
4870
5046
|
staged.set(key, {
|
|
4871
5047
|
present: true,
|
|
4872
5048
|
value
|
|
@@ -4880,8 +5056,11 @@ const materializeInputSource = (scheduler, definition) => {
|
|
|
4880
5056
|
remove: (key) => {
|
|
4881
5057
|
require_scheduler.assertScope(() => active);
|
|
4882
5058
|
if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
|
|
5059
|
+
const previous = staged.get(key);
|
|
5060
|
+
const present = previous ? previous.present : values.has(key);
|
|
5061
|
+
structural ||= present;
|
|
4883
5062
|
staged.set(key, { present: false });
|
|
4884
|
-
operations.push({
|
|
5063
|
+
if (present) operations.push({
|
|
4885
5064
|
kind: "remove",
|
|
4886
5065
|
key
|
|
4887
5066
|
});
|
|
@@ -4892,32 +5071,25 @@ const materializeInputSource = (scheduler, definition) => {
|
|
|
4892
5071
|
} finally {
|
|
4893
5072
|
active = false;
|
|
4894
5073
|
}
|
|
5074
|
+
if (!operations.length) return;
|
|
4895
5075
|
const candidates = /* @__PURE__ */ new Set();
|
|
4896
|
-
|
|
4897
|
-
const
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
value: operation.value
|
|
4909
|
-
});
|
|
4910
|
-
} else {
|
|
4911
|
-
if (!present) continue;
|
|
4912
|
-
structural = true;
|
|
4913
|
-
overlay.set(operation.key, { present: false });
|
|
4914
|
-
}
|
|
4915
|
-
accepted.push(operation);
|
|
4916
|
-
candidates.add(operation.key);
|
|
5076
|
+
const retained = /* @__PURE__ */ new Map();
|
|
5077
|
+
for (const [key, entry] of staged) {
|
|
5078
|
+
const existed = values.has(key);
|
|
5079
|
+
if (entry.present) {
|
|
5080
|
+
if (!existed) {
|
|
5081
|
+
candidates.add(key);
|
|
5082
|
+
continue;
|
|
5083
|
+
}
|
|
5084
|
+
const previous = values.get(key);
|
|
5085
|
+
if (source.equality(previous, entry.value)) retained.set(key, previous);
|
|
5086
|
+
else candidates.add(key);
|
|
5087
|
+
} else if (existed) candidates.add(key);
|
|
4917
5088
|
}
|
|
4918
|
-
if (!
|
|
4919
|
-
for (const operation of
|
|
5089
|
+
if (!candidates.size && !structural) return;
|
|
5090
|
+
for (const operation of operations) if (operation.kind === "set") values.set(operation.key, operation.value);
|
|
4920
5091
|
else values.delete(operation.key);
|
|
5092
|
+
for (const [key, value] of retained) if (values.has(key)) values.set(key, value);
|
|
4921
5093
|
boundary.mark({
|
|
4922
5094
|
candidates,
|
|
4923
5095
|
orderMayChange: structural
|