doxum 0.1.34 → 0.1.35
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 +12 -0
- package/dist/advanced.cjs +1 -1
- package/dist/advanced.js +1 -1
- package/dist/index.cjs +56 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -5
- package/dist/index.d.ts +11 -5
- package/dist/index.js +56 -19
- package/dist/index.js.map +1 -1
- package/dist/{transform-RghG_Qxs.js → transform-3mj0eStL.js} +8 -2
- package/dist/transform-3mj0eStL.js.map +1 -0
- package/dist/{transform-Bt1Mwgrj.cjs → transform-D45KWMzj.cjs} +9 -3
- package/dist/transform-D45KWMzj.cjs.map +1 -0
- package/package.json +1 -1
- package/skills/doxum-runtime/SKILL.md +2 -2
- package/skills/doxum-runtime/references/projections.md +27 -0
- package/skills/doxum-runtime/references/public-api.md +19 -14
- package/skills/doxum-runtime/references/recipes.md +23 -0
- package/dist/transform-Bt1Mwgrj.cjs.map +0 -1
- package/dist/transform-RghG_Qxs.js.map +0 -1
package/README.md
CHANGED
|
@@ -432,6 +432,18 @@ const lines = derive.keyed.flatMap(orders, order =>
|
|
|
432
432
|
|
|
433
433
|
Each parent returns ordered `[globalKey, value]` tuples, including zero entries. `flatMap` reuses named/dynamic keyed dependencies and only recomputes invalidated parents. Formal output order follows parent order then child order; parent-only reordering runs no selectors. Duplicate final output keys are errors, and present `undefined` is valid. Same-batch transfers preserve a global key's membership identity. Structural changes can rebuild full order; this is not a claim that every operation costs only the changed entries.
|
|
434
434
|
|
|
435
|
+
### Compute a keyed result from named inputs
|
|
436
|
+
|
|
437
|
+
```ts
|
|
438
|
+
const errors = derive.keyed.fromEntries(
|
|
439
|
+
{ form: formState, rules: validationRules },
|
|
440
|
+
({ form, rules }) => validateForm(form, rules).map(error => [error.id, error]),
|
|
441
|
+
(before, after) => before.message === after.message && before.field === after.field
|
|
442
|
+
);
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
`fromEntries` uses the same named dependencies as `derive`, including the single-source form `{ form }`. The synchronous callback returns the complete ordered `[key, value]` array: `[]` is empty, missing keys are removed, and `[key, undefined]` is present. Duplicate keys are errors. Per-entry equality preserves equivalent value references while membership/order changes remain observable. It computes and scans the full result, then publishes exact changes; use `flatMap` for per-parent incremental computation or `derive.keyed.get` as an input for precise active-entry dependencies. See [Projection API](docs/projections.md#keyed-results-from-named-dependencies).
|
|
446
|
+
|
|
435
447
|
### Runtime-local keyed state
|
|
436
448
|
|
|
437
449
|
Use `input.collection` for selection, expanded state, local overrides and other
|
package/dist/advanced.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_transform = require("./transform-
|
|
2
|
+
const require_transform = require("./transform-D45KWMzj.cjs");
|
|
3
3
|
const require_record = require("./record-ChYUi8PP.cjs");
|
|
4
4
|
//#region core/src/projection/advanced.ts
|
|
5
5
|
const resetCollectionChange = Object.freeze({ kind: "reset" });
|
package/dist/advanced.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as defineProcessor, S as compileProjectionDependencies, _ as assertSynchronous, r as collectionChange, t as createKeyedTransform, w as collectionView } from "./transform-
|
|
1
|
+
import { D as defineProcessor, S as compileProjectionDependencies, _ as assertSynchronous, r as collectionChange, t as createKeyedTransform, w as collectionView } from "./transform-3mj0eStL.js";
|
|
2
2
|
import { n as isPlainObject } from "./record-B2yRhYsc.js";
|
|
3
3
|
//#region core/src/projection/advanced.ts
|
|
4
4
|
const resetCollectionChange = Object.freeze({ kind: "reset" });
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_transform = require("./transform-
|
|
2
|
+
const require_transform = require("./transform-D45KWMzj.cjs");
|
|
3
3
|
const require_record = require("./record-ChYUi8PP.cjs");
|
|
4
4
|
const require_driver = require("./driver-CN3dGxQI.cjs");
|
|
5
5
|
//#region core/src/schema/model.ts
|
|
@@ -2775,6 +2775,12 @@ const isExternalSource = (source) => {
|
|
|
2775
2775
|
return (candidate.kind === "value" || candidate.kind === "collection") && typeof candidate.current === "function" && typeof candidate.revision === "function" && typeof candidate.subscribe === "function";
|
|
2776
2776
|
};
|
|
2777
2777
|
//#endregion
|
|
2778
|
+
//#region core/src/projection/keyed/entries.ts
|
|
2779
|
+
/** Shared entry boundary; membership and duplicate policy belong to each operation. */
|
|
2780
|
+
function assertKeyedEntry(entry, name) {
|
|
2781
|
+
if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== "string") throw new TypeError(`${name} entries must be [string key, value] tuples.`);
|
|
2782
|
+
}
|
|
2783
|
+
//#endregion
|
|
2778
2784
|
//#region core/src/projection/keyed/flat-map.ts
|
|
2779
2785
|
function createKeyedFlatMap(source, dependenciesOrSelect, selectOrEquality, maybeEquality) {
|
|
2780
2786
|
const name = "derive.keyed.flatMap";
|
|
@@ -2821,7 +2827,7 @@ function createKeyedFlatMap(source, dependenciesOrSelect, selectOrEquality, mayb
|
|
|
2821
2827
|
if (!Array.isArray(entries)) throw new TypeError(`${name} selector must return an array of entries.`);
|
|
2822
2828
|
const keys = [];
|
|
2823
2829
|
for (const entry of entries) {
|
|
2824
|
-
|
|
2830
|
+
assertKeyedEntry(entry, name);
|
|
2825
2831
|
const [key, child] = entry;
|
|
2826
2832
|
const owner = ownerByOutput.get(key);
|
|
2827
2833
|
if (proposals.has(key) || owner !== void 0 && !replaced.has(owner)) throw new TypeError(`${name} duplicate key ${JSON.stringify(key)}.`);
|
|
@@ -2908,6 +2914,25 @@ const assertCollectionSources = (sources, expected) => {
|
|
|
2908
2914
|
if (sources.length !== expected) throw new Error("derive.keyed.merge resolved an invalid dependency count.");
|
|
2909
2915
|
for (const source of sources) if (source.kind !== "collection") throw new Error("derive.keyed.merge requires collection inputs.");
|
|
2910
2916
|
};
|
|
2917
|
+
/** Complete ordered result reconciliation, without retaining a second member/value cache. */
|
|
2918
|
+
const stageKeyedSnapshot = (values, output, keyOf, valueOf, name) => {
|
|
2919
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2920
|
+
const order = new Array(values.length);
|
|
2921
|
+
const previous = output.previous.ids();
|
|
2922
|
+
require_transform.profile.collectionView.idsScanned(values.length + previous.length);
|
|
2923
|
+
for (let index = 0; index < values.length; index++) {
|
|
2924
|
+
const value = values[index];
|
|
2925
|
+
const key = keyOf(value);
|
|
2926
|
+
require_transform.assertSynchronous(key);
|
|
2927
|
+
if (typeof key !== "string") throw new TypeError(`${name} key selector must return a string.`);
|
|
2928
|
+
if (seen.has(key)) throw new TypeError(`${name} duplicate key ${JSON.stringify(key)}.`);
|
|
2929
|
+
seen.add(key);
|
|
2930
|
+
order[index] = key;
|
|
2931
|
+
output.output.set(key, valueOf(value));
|
|
2932
|
+
}
|
|
2933
|
+
for (const key of previous) if (!seen.has(key)) output.output.remove(key);
|
|
2934
|
+
output.output.order(order);
|
|
2935
|
+
};
|
|
2911
2936
|
function createKeyedFrom(source, keyOf, equality) {
|
|
2912
2937
|
if (typeof keyOf !== "function") throw new TypeError("derive.keyed.from requires a key selector.");
|
|
2913
2938
|
const outputEquality = assertEquality(equality, "derive.keyed.from");
|
|
@@ -2937,25 +2962,38 @@ function createKeyedFrom(source, keyOf, equality) {
|
|
|
2937
2962
|
values = scalar.value;
|
|
2938
2963
|
}
|
|
2939
2964
|
if (!values) throw new Error("derive.keyed.from has no source values.");
|
|
2940
|
-
|
|
2941
|
-
const order = new Array(values.length);
|
|
2942
|
-
for (let index = 0; index < values.length; index++) {
|
|
2943
|
-
const value = values[index];
|
|
2944
|
-
const key = keyOf(value);
|
|
2945
|
-
require_transform.assertSynchronous(key);
|
|
2946
|
-
if (typeof key !== "string") throw new TypeError("derive.keyed.from key selector must return a string.");
|
|
2947
|
-
if (seen.has(key)) throw new TypeError(`derive.keyed.from duplicate key ${JSON.stringify(key)}.`);
|
|
2948
|
-
seen.add(key);
|
|
2949
|
-
order[index] = key;
|
|
2950
|
-
output.output.set(key, value);
|
|
2951
|
-
}
|
|
2952
|
-
for (const previousKey of output.previous.ids()) if (!seen.has(previousKey)) output.output.remove(previousKey);
|
|
2953
|
-
output.output.order(order);
|
|
2965
|
+
stageKeyedSnapshot(values, output, keyOf, (value) => value, "derive.keyed.from");
|
|
2954
2966
|
} }),
|
|
2955
2967
|
name: "derive.keyed.from"
|
|
2956
2968
|
});
|
|
2957
2969
|
return projection;
|
|
2958
2970
|
}
|
|
2971
|
+
function createKeyedFromEntries(dependencies, compute, equality) {
|
|
2972
|
+
const name = "derive.keyed.fromEntries";
|
|
2973
|
+
const compiled = require_transform.compileProjectionDependencies(dependencies, name);
|
|
2974
|
+
if (typeof compute !== "function") throw new TypeError(`${name} requires a compute callback.`);
|
|
2975
|
+
const outputEquality = assertEquality(equality, name);
|
|
2976
|
+
const [projection] = require_transform.defineProcessor({
|
|
2977
|
+
dependencies: compiled.projections,
|
|
2978
|
+
outputs: [{
|
|
2979
|
+
kind: "collection",
|
|
2980
|
+
equality: outputEquality
|
|
2981
|
+
}],
|
|
2982
|
+
name,
|
|
2983
|
+
create: () => ({ evaluate: (evaluation) => {
|
|
2984
|
+
const output = evaluation.outputs[0];
|
|
2985
|
+
if (output.kind !== "collection") throw new Error(`${name} requires a collection output.`);
|
|
2986
|
+
const entries = compute(require_transform.snapshotProjectionValues(compiled.names, evaluation.sources));
|
|
2987
|
+
require_transform.assertSynchronous(entries);
|
|
2988
|
+
if (!Array.isArray(entries)) throw new TypeError(`${name} compute must return an array of entries.`);
|
|
2989
|
+
stageKeyedSnapshot(entries, output, (entry) => {
|
|
2990
|
+
assertKeyedEntry(entry, name);
|
|
2991
|
+
return entry[0];
|
|
2992
|
+
}, (entry) => entry[1], name);
|
|
2993
|
+
} })
|
|
2994
|
+
});
|
|
2995
|
+
return projection;
|
|
2996
|
+
}
|
|
2959
2997
|
function createKeyedMerge(sources, options) {
|
|
2960
2998
|
if (!Array.isArray(sources)) throw new TypeError("derive.keyed.merge sources must be an array of keyed projections.");
|
|
2961
2999
|
const capturedSources = require_transform.snapshotArray(sources);
|
|
@@ -3584,6 +3622,7 @@ const keyedDerive = Object.assign(createKeyedDerive, {
|
|
|
3584
3622
|
entries: createKeyedEntries,
|
|
3585
3623
|
get: createKeyedGet,
|
|
3586
3624
|
from: createKeyedFrom,
|
|
3625
|
+
fromEntries: createKeyedFromEntries,
|
|
3587
3626
|
merge: createKeyedMerge,
|
|
3588
3627
|
groupBy: createKeyedGroupBy,
|
|
3589
3628
|
flatMap: createKeyedFlatMap,
|
|
@@ -3607,9 +3646,7 @@ function createValueDerive(dependencies, compute, equality = Object.is) {
|
|
|
3607
3646
|
create: () => ({ evaluate: (evaluation) => {
|
|
3608
3647
|
const output = evaluation.outputs[0];
|
|
3609
3648
|
if (output.kind !== "value") throw new Error("derive requires a value output.");
|
|
3610
|
-
const
|
|
3611
|
-
for (let index = 0; index < names.length; index++) values[names[index]] = require_transform.snapshotDependencyValue(evaluation.sources[index]);
|
|
3612
|
-
const next = compute(Object.freeze(values));
|
|
3649
|
+
const next = compute(require_transform.snapshotProjectionValues(names, evaluation.sources));
|
|
3613
3650
|
require_transform.assertSynchronous(next);
|
|
3614
3651
|
output.output.set(next);
|
|
3615
3652
|
} })
|