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 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-Bt1Mwgrj.cjs");
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-RghG_Qxs.js";
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-Bt1Mwgrj.cjs");
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
- if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== "string") throw new TypeError(`${name} entries must be [string key, value] tuples.`);
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
- const seen = /* @__PURE__ */ new Set();
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 values = Object.create(null);
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
  } })