@platforma-sdk/model 1.80.13 → 1.81.0

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.
Files changed (118) hide show
  1. package/dist/columns/column.cjs +9 -6
  2. package/dist/columns/column.cjs.map +1 -1
  3. package/dist/columns/column.d.ts +5 -5
  4. package/dist/columns/column.d.ts.map +1 -1
  5. package/dist/columns/column.js +10 -7
  6. package/dist/columns/column.js.map +1 -1
  7. package/dist/columns/column_providers/index.cjs.map +1 -1
  8. package/dist/columns/column_providers/index.d.ts.map +1 -1
  9. package/dist/columns/column_providers/index.js.map +1 -1
  10. package/dist/columns/column_providers/providers.cjs +5 -5
  11. package/dist/columns/column_providers/providers.cjs.map +1 -1
  12. package/dist/columns/column_providers/providers.d.ts +8 -8
  13. package/dist/columns/column_providers/providers.d.ts.map +1 -1
  14. package/dist/columns/column_providers/providers.js +5 -5
  15. package/dist/columns/column_providers/providers.js.map +1 -1
  16. package/dist/columns/column_providers/types.d.ts +3 -3
  17. package/dist/columns/column_providers/types.d.ts.map +1 -1
  18. package/dist/columns/column_recipes/column_discovered_recipe.cjs +1 -1
  19. package/dist/columns/column_recipes/column_discovered_recipe.cjs.map +1 -1
  20. package/dist/columns/column_recipes/column_discovered_recipe.d.ts +1 -1
  21. package/dist/columns/column_recipes/column_discovered_recipe.js +1 -1
  22. package/dist/columns/column_recipes/column_discovered_recipe.js.map +1 -1
  23. package/dist/columns/column_recipes/column_overrided_recipe.cjs +47 -2
  24. package/dist/columns/column_recipes/column_overrided_recipe.cjs.map +1 -1
  25. package/dist/columns/column_recipes/column_overrided_recipe.d.ts +30 -3
  26. package/dist/columns/column_recipes/column_overrided_recipe.d.ts.map +1 -1
  27. package/dist/columns/column_recipes/column_overrided_recipe.js +47 -3
  28. package/dist/columns/column_recipes/column_overrided_recipe.js.map +1 -1
  29. package/dist/columns/column_recipes/index.cjs +4 -14
  30. package/dist/columns/column_recipes/index.cjs.map +1 -1
  31. package/dist/columns/column_recipes/index.d.ts +3 -10
  32. package/dist/columns/column_recipes/index.d.ts.map +1 -1
  33. package/dist/columns/column_recipes/index.js +5 -14
  34. package/dist/columns/column_recipes/index.js.map +1 -1
  35. package/dist/columns/{column_lazy.cjs → data_column.cjs} +57 -54
  36. package/dist/columns/data_column.cjs.map +1 -0
  37. package/dist/columns/data_column.d.ts +152 -0
  38. package/dist/columns/data_column.d.ts.map +1 -0
  39. package/dist/columns/{column_lazy.js → data_column.js} +55 -52
  40. package/dist/columns/data_column.js.map +1 -0
  41. package/dist/columns/derive_axis_values_labels.cjs +4 -4
  42. package/dist/columns/derive_axis_values_labels.cjs.map +1 -1
  43. package/dist/columns/derive_axis_values_labels.d.ts +2 -2
  44. package/dist/columns/derive_axis_values_labels.js +4 -4
  45. package/dist/columns/derive_axis_values_labels.js.map +1 -1
  46. package/dist/columns/index.cjs +9 -9
  47. package/dist/columns/index.d.ts +5 -5
  48. package/dist/columns/index.js +5 -5
  49. package/dist/columns/{expand_by_partition.cjs → split_by_axes.cjs} +13 -8
  50. package/dist/columns/split_by_axes.cjs.map +1 -0
  51. package/dist/columns/{expand_by_partition.d.ts → split_by_axes.d.ts} +18 -8
  52. package/dist/columns/split_by_axes.d.ts.map +1 -0
  53. package/dist/columns/{expand_by_partition.js → split_by_axes.js} +14 -9
  54. package/dist/columns/split_by_axes.js.map +1 -0
  55. package/dist/columns/utils.cjs +50 -43
  56. package/dist/columns/utils.cjs.map +1 -1
  57. package/dist/columns/utils.d.ts +44 -19
  58. package/dist/columns/utils.d.ts.map +1 -1
  59. package/dist/columns/utils.js +50 -44
  60. package/dist/columns/utils.js.map +1 -1
  61. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.cjs +3 -3
  62. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.cjs.map +1 -1
  63. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.js +3 -3
  64. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.js.map +1 -1
  65. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.cjs +2 -2
  66. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.cjs.map +1 -1
  67. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js +2 -2
  68. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js.map +1 -1
  69. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs +1 -1
  70. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs.map +1 -1
  71. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js +2 -2
  72. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js.map +1 -1
  73. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.cjs +1 -1
  74. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.cjs.map +1 -1
  75. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.js +2 -2
  76. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.js.map +1 -1
  77. package/dist/components/PlDatasetSelector/enrichment_discovery.cjs +1 -1
  78. package/dist/components/PlDatasetSelector/enrichment_discovery.cjs.map +1 -1
  79. package/dist/components/PlDatasetSelector/enrichment_discovery.js +2 -2
  80. package/dist/components/PlDatasetSelector/enrichment_discovery.js.map +1 -1
  81. package/dist/index.cjs +9 -9
  82. package/dist/index.d.ts +5 -5
  83. package/dist/index.js +5 -5
  84. package/dist/package.cjs +1 -1
  85. package/dist/package.js +1 -1
  86. package/package.json +9 -9
  87. package/src/columns/__test_helpers__/collection_driver.ts +6 -6
  88. package/src/columns/__test_helpers__/stub_registry.ts +4 -6
  89. package/src/columns/column.ts +20 -9
  90. package/src/columns/column_providers/index.ts +9 -3
  91. package/src/columns/column_providers/providers.ts +16 -15
  92. package/src/columns/column_providers/types.ts +3 -3
  93. package/src/columns/column_recipes/column_discovered_recipe.ts +1 -1
  94. package/src/columns/column_recipes/column_overrided_recipe.ts +58 -4
  95. package/src/columns/column_recipes/column_recipes.test.ts +2 -2
  96. package/src/columns/column_recipes/index.ts +5 -20
  97. package/src/columns/{column_lazy.test.ts → data_column.test.ts} +19 -19
  98. package/src/columns/{column_lazy.ts → data_column.ts} +105 -67
  99. package/src/columns/derive_axis_values_labels.ts +4 -4
  100. package/src/columns/index.ts +2 -2
  101. package/src/columns/predicates.test.ts +124 -0
  102. package/src/columns/{expand_by_partition.test.ts → split_by_axes.test.ts} +29 -21
  103. package/src/columns/{expand_by_partition.ts → split_by_axes.ts} +22 -9
  104. package/src/columns/utils.ts +53 -48
  105. package/src/components/PlDataTable/columnResolver.test.ts +3 -3
  106. package/src/components/PlDataTable/createPlDataTable/createPTableDefV2.ts +3 -3
  107. package/src/components/PlDataTable/createPlDataTable/createPlDataTableV2.ts +2 -2
  108. package/src/components/PlDataTable/createPlDataTable/createPlDataTableV3.ts +2 -2
  109. package/src/components/PlDataTable/createPlDataTable/discoverColumns.ts +2 -2
  110. package/src/components/PlDataTable/createPlDataTable/utils.test.ts +3 -3
  111. package/src/components/PlDatasetSelector/enrichment_discovery.ts +2 -2
  112. package/dist/columns/column_lazy.cjs.map +0 -1
  113. package/dist/columns/column_lazy.d.ts +0 -137
  114. package/dist/columns/column_lazy.d.ts.map +0 -1
  115. package/dist/columns/column_lazy.js.map +0 -1
  116. package/dist/columns/expand_by_partition.cjs.map +0 -1
  117. package/dist/columns/expand_by_partition.d.ts.map +0 -1
  118. package/dist/columns/expand_by_partition.js.map +0 -1
@@ -3,7 +3,7 @@ const require_index = require("./column_providers/index.cjs");
3
3
  let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
4
4
  let es_toolkit = require("es-toolkit");
5
5
  let lru_cache = require("lru-cache");
6
- //#region src/columns/column_lazy.ts
6
+ //#region src/columns/data_column.ts
7
7
  /**
8
8
  * Thrown by leaf-recipe factories when the requested column is provably
9
9
  * absent in the active render ctx — i.e. every relevant accessor reports
@@ -24,13 +24,15 @@ var ColumnAbsentError = class extends Error {
24
24
  }
25
25
  };
26
26
  /**
27
- * ColumnLazy is the leaf-recipe building block: a {@link ColumnRecipe} whose
28
- * `id` is a bare {@link PObjectId} and whose readers are bound to a single
29
- * tree-accessor leaf. Layered encodings (Overridden / Discovered / Filtered)
30
- * are reified through their dedicated recipe classes and reference leaf
31
- * columns by id.
27
+ * The leaf-recipe building block: a {@link DataColumnRecipe} whose `id` is a bare
28
+ * {@link PObjectId} and whose readers are bound to a single tree-accessor
29
+ * leaf. Layered encodings (Overridden / Discovered / Filtered) are reified
30
+ * through their dedicated recipe classes and reference leaf columns by id.
31
+ *
32
+ * Internal — consumers hold the {@link DataColumnRecipe} interface and construct
33
+ * through the {@link DataColumnRecipe} dispatcher.
32
34
  */
33
- var ColumnLazyImpl = class ColumnLazyImpl {
35
+ var DataColumnImpl = class DataColumnImpl {
34
36
  id;
35
37
  options;
36
38
  specCache;
@@ -55,7 +57,6 @@ var ColumnLazyImpl = class ColumnLazyImpl {
55
57
  column: this.id
56
58
  };
57
59
  }
58
- /** Leaf-only: not on the recipe interface — only the leaf can read data directly. */
59
60
  getData() {
60
61
  if (this.dataCache === void 0) this.dataCache = { value: this.options.getData() };
61
62
  return this.dataCache.value;
@@ -66,7 +67,7 @@ var ColumnLazyImpl = class ColumnLazyImpl {
66
67
  }
67
68
  /**
68
69
  * Overlay overrides → produces a {@link ColumnOverriddenRecipe} wrapping
69
- * this leaf. ColumnLazy itself stays bare (id remains a plain PObjectId);
70
+ * this leaf. The leaf itself stays bare (id remains a plain PObjectId);
70
71
  * layering lives entirely in the recipe wrappers.
71
72
  */
72
73
  withSpecs(overrides) {
@@ -92,7 +93,7 @@ var ColumnLazyImpl = class ColumnLazyImpl {
92
93
  return;
93
94
  }
94
95
  if (!spec.hasData()) return void 0;
95
- return new ColumnLazyImpl(id, {
96
+ return new DataColumnImpl(id, {
96
97
  getSpec: () => spec.getDataAsJson(),
97
98
  getData: () => readDataAccessor(leaf),
98
99
  getDataStatus: () => readDataStatus(leaf)
@@ -100,7 +101,7 @@ var ColumnLazyImpl = class ColumnLazyImpl {
100
101
  }
101
102
  /** {@link PlRef} wrapper over {@link fromId}. */
102
103
  static fromPlRef(ref) {
103
- return ColumnLazyImpl.fromId((0, _milaboratories_pl_model_common.createGlobalPObjectId)(ref.blockId, ref.name));
104
+ return DataColumnImpl.fromId((0, _milaboratories_pl_model_common.createGlobalPObjectId)(ref.blockId, ref.name));
104
105
  }
105
106
  /**
106
107
  * Bind directly to an accessor-backed {@link LeafEntry} — no registry.
@@ -114,7 +115,7 @@ var ColumnLazyImpl = class ColumnLazyImpl {
114
115
  return;
115
116
  }
116
117
  if (!spec.hasData()) return void 0;
117
- return new ColumnLazyImpl(entry.id, {
118
+ return new DataColumnImpl(entry.id, {
118
119
  getSpec: () => spec.getDataAsJson(),
119
120
  getData: () => readDataAccessor(entry),
120
121
  getDataStatus: () => readDataStatus(entry)
@@ -122,13 +123,14 @@ var ColumnLazyImpl = class ColumnLazyImpl {
122
123
  }
123
124
  /**
124
125
  * Wrap a materialised {@link PColumn}. If the input is already a
125
- * {@link ColumnLazy} it is returned as-is.
126
+ * {@link DataColumnRecipe} leaf it is returned as-is.
126
127
  */
127
128
  static fromColumn(column) {
128
- if (column instanceof ColumnLazyImpl) return column;
129
- return new ColumnLazyImpl(column.id, {
130
- getSpec: () => column.spec,
131
- getData: () => column.data,
129
+ if (column instanceof DataColumnImpl) return column;
130
+ const pColumn = column;
131
+ return new DataColumnImpl(pColumn.id, {
132
+ getSpec: () => pColumn.spec,
133
+ getData: () => pColumn.data,
132
134
  getDataStatus: () => "present"
133
135
  });
134
136
  }
@@ -146,7 +148,7 @@ var ColumnLazyImpl = class ColumnLazyImpl {
146
148
  }
147
149
  /** {@link PlRef} wrapper over {@link getStatusById}. */
148
150
  static getStatusByPlRef(ref, opts = {}) {
149
- return ColumnLazyImpl.getStatusById((0, _milaboratories_pl_model_common.createGlobalPObjectId)(ref.blockId, ref.name), opts);
151
+ return DataColumnImpl.getStatusById((0, _milaboratories_pl_model_common.createGlobalPObjectId)(ref.blockId, ref.name), opts);
150
152
  }
151
153
  /** No registry — reads straight off the entry's accessor. */
152
154
  static getStatusByAccessor(entry) {
@@ -154,50 +156,51 @@ var ColumnLazyImpl = class ColumnLazyImpl {
154
156
  }
155
157
  };
156
158
  /**
157
- * Unified dispatcher — picks the right `ColumnLazyImpl.fromX` by source
159
+ * Unified dispatcher — picks the right `DataColumnImpl.fromX` by source
158
160
  * shape. For ambiguous inputs callers can still use the explicit factories
159
- * (also attached as properties: `ColumnLazy.fromId`, `.fromPlRef`,
161
+ * (also attached as properties: `DataColumn.fromId`, `.fromPlRef`,
160
162
  * `.fromAccessor`, `.fromColumn`).
161
163
  */
162
- function ColumnLazyDispatch(source, opts = {}) {
163
- if (typeof source === "string") return ColumnLazyImpl.fromId(source, opts);
164
- if (source instanceof ColumnLazyImpl) return source;
165
- if ("accessor" in source) return ColumnLazyImpl.fromAccessor(source);
166
- if ((0, _milaboratories_pl_model_common.isPlRef)(source)) return ColumnLazyImpl.fromPlRef(source);
167
- if ((0, _milaboratories_pl_model_common.isPColumn)(source)) return ColumnLazyImpl.fromColumn(source);
168
- throw new Error("ColumnLazy: unknown source shape");
164
+ function DataColumnDispatch(source, opts = {}) {
165
+ if (typeof source === "string") return DataColumnImpl.fromId(source, opts);
166
+ if (source instanceof DataColumnImpl) return source;
167
+ const rest = source;
168
+ if ("accessor" in rest) return DataColumnImpl.fromAccessor(rest);
169
+ if ((0, _milaboratories_pl_model_common.isPlRef)(rest)) return DataColumnImpl.fromPlRef(rest);
170
+ if ((0, _milaboratories_pl_model_common.isPColumn)(rest)) return DataColumnImpl.fromColumn(rest);
171
+ throw new Error("DataColumn: unknown source shape");
169
172
  }
170
173
  /**
171
- * Polymorphic counterpart to {@link ColumnLazyDispatch}: returns the
174
+ * Polymorphic counterpart to {@link DataColumnDispatch}: returns the
172
175
  * {@link ColumnResolutionStatus} for any factory input without constructing
173
176
  * the recipe. For already-materialised sources ({@link PColumn} value,
174
- * existing {@link ColumnLazy}) status is `present` by construction.
177
+ * existing {@link DataColumnRecipe}) status is `present` by construction.
175
178
  */
176
- function ColumnLazyGetStatus(source, opts = {}) {
177
- if (typeof source === "string") return ColumnLazyImpl.getStatusById(source, opts);
178
- if (source instanceof ColumnLazyImpl) return "present";
179
- if ("accessor" in source) return ColumnLazyImpl.getStatusByAccessor(source);
180
- if ((0, _milaboratories_pl_model_common.isPlRef)(source)) return ColumnLazyImpl.getStatusByPlRef(source, opts);
181
- if ((0, _milaboratories_pl_model_common.isPColumn)(source)) return "present";
182
- throw new Error("ColumnLazy.getStatus: unknown source shape");
179
+ function DataColumnGetStatus(source, opts = {}) {
180
+ if (typeof source === "string") return DataColumnImpl.getStatusById(source, opts);
181
+ if (source instanceof DataColumnImpl) return "present";
182
+ const rest = source;
183
+ if ("accessor" in rest) return DataColumnImpl.getStatusByAccessor(rest);
184
+ if ((0, _milaboratories_pl_model_common.isPlRef)(rest)) return DataColumnImpl.getStatusByPlRef(rest, opts);
185
+ if ((0, _milaboratories_pl_model_common.isPColumn)(rest)) return "present";
186
+ throw new Error("DataColumn.getStatus: unknown source shape");
183
187
  }
184
- const ColumnLazy = Object.assign(ColumnLazyDispatch, {
185
- fromId: ColumnLazyImpl.fromId,
186
- fromPlRef: ColumnLazyImpl.fromPlRef,
187
- fromAccessor: ColumnLazyImpl.fromAccessor,
188
- fromColumn: ColumnLazyImpl.fromColumn,
189
- getStatus: ColumnLazyGetStatus,
190
- getStatusById: ColumnLazyImpl.getStatusById,
191
- getStatusByPlRef: ColumnLazyImpl.getStatusByPlRef,
192
- getStatusByAccessor: ColumnLazyImpl.getStatusByAccessor
188
+ const DataColumn = Object.assign(DataColumnDispatch, {
189
+ fromId: DataColumnImpl.fromId,
190
+ fromPlRef: DataColumnImpl.fromPlRef,
191
+ fromAccessor: DataColumnImpl.fromAccessor,
192
+ fromColumn: DataColumnImpl.fromColumn,
193
+ getStatus: DataColumnGetStatus,
194
+ getStatusById: DataColumnImpl.getStatusById,
195
+ getStatusByPlRef: DataColumnImpl.getStatusByPlRef,
196
+ getStatusByAccessor: DataColumnImpl.getStatusByAccessor
193
197
  });
194
198
  /**
195
- * Type-guard narrowing to the leaf recipe. Prefer this over
196
- * `instanceof ColumnLazyImpl` — `ColumnLazy` (the value) is the dispatcher
197
- * with statics, not the class, so `instanceof` requires the impl symbol.
199
+ * Type-guard narrowing to a bare leaf — a {@link DataColumnRecipe} whose `id` is a
200
+ * plain {@link PObjectId}.
198
201
  */
199
- function isColumnLazy(value) {
200
- return value instanceof ColumnLazyImpl;
202
+ function isDataColumn(value) {
203
+ return value instanceof DataColumnImpl;
201
204
  }
202
205
  const readSpecAccessor = memoizeByEntry(({ accessor, name }) => accessor.traverse({
203
206
  field: `${name}.spec`,
@@ -241,8 +244,8 @@ function memoizeByEntry(fn) {
241
244
  }
242
245
  //#endregion
243
246
  exports.ColumnAbsentError = ColumnAbsentError;
244
- exports.ColumnLazy = ColumnLazy;
245
- exports.ColumnLazyImpl = ColumnLazyImpl;
246
- exports.isColumnLazy = isColumnLazy;
247
+ exports.DataColumn = DataColumn;
248
+ exports.DataColumnImpl = DataColumnImpl;
249
+ exports.isDataColumn = isDataColumn;
247
250
 
248
- //# sourceMappingURL=column_lazy.cjs.map
251
+ //# sourceMappingURL=data_column.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data_column.cjs","names":["ColumnOverriddenRecipe","ColumnRegistry","getCtxProviders","LRUCache"],"sources":["../../src/columns/data_column.ts"],"sourcesContent":["import {\n ColumnRegistry,\n createGlobalPObjectId,\n isPColumn,\n isPlRef,\n PlRef,\n PObjectId,\n type ColumnUniversalId,\n type LeafEntry,\n type PColumn,\n type PColumnSpec,\n type SpecOverrides,\n type SpecQuery,\n} from \"@milaboratories/pl-model-common\";\nimport type { GlobalCfgRenderCtx, PColumnDataUniversal } from \"../render/internal\";\nimport { getCtxProviders } from \"./column_providers\";\nimport { isNil } from \"es-toolkit\";\nimport { LRUCache } from \"lru-cache\";\nimport { TreeNodeAccessor } from \"../render\";\nimport type {\n ColumnFieldStatus,\n ColumnRecipe,\n ColumnRecipeId,\n ColumnResolutionStatus,\n} from \"./column_recipes/types\";\nimport { ColumnOverriddenRecipe } from \"./column_recipes/column_overrided_recipe\";\n\nexport type DataColumnId = PObjectId;\nexport type ColumnData = undefined | PColumnDataUniversal;\nexport type { ColumnFieldStatus, ColumnResolutionStatus } from \"./column_recipes/types\";\n\n/**\n * A {@link ColumnRecipe} that can be read directly in the sandbox: its\n * {@link getData} is guaranteed to be consistent with {@link getSpec}.\n *\n * This is a *capability*, not a class. Only two recipe shapes carry it — a\n * bare leaf and a spec-override over a bare leaf — because those are the only\n * ones whose data still matches their spec. An axis-filtered recipe drops axes\n * from its spec while the underlying data keeps them, and a discovered recipe\n * only materialises after a join; neither can be read here, so neither\n * implements this interface.\n *\n * Narrow to it with `hasReachableData(recipe)` rather than testing for a concrete\n * class — which recipe classes exist is an implementation detail behind\n * `recipe.id`.\n */\nexport interface DataColumnRecipe<\n ID extends ColumnRecipeId = ColumnRecipeId,\n> extends ColumnRecipe<ID> {\n /** Column data, consistent with {@link ColumnRecipe.getSpec}. */\n getData(): ColumnData;\n}\n\n/**\n * Thrown by leaf-recipe factories when the requested column is provably\n * absent in the active render ctx — i.e. every relevant accessor reports\n * `inputsLocked` and the column did not appear. Distinct from the\n * `undefined` return that the factories still use for the \"resolving\" case\n * (the column may still appear later).\n *\n * Catch at the boundary (resolver / filter+sort wiring / data-table assembly)\n * when partial absence should be surfaced to the user rather than silently\n * producing an empty result.\n */\nexport class ColumnAbsentError extends Error {\n constructor(public readonly id: ColumnUniversalId) {\n super(`Column is absent in the active render ctx and will not appear: ${id}`);\n this.name = \"ColumnAbsentError\";\n }\n}\n\n/**\n * The leaf-recipe building block: a {@link DataColumnRecipe} whose `id` is a bare\n * {@link PObjectId} and whose readers are bound to a single tree-accessor\n * leaf. Layered encodings (Overridden / Discovered / Filtered) are reified\n * through their dedicated recipe classes and reference leaf columns by id.\n *\n * Internal — consumers hold the {@link DataColumnRecipe} interface and construct\n * through the {@link DataColumnRecipe} dispatcher.\n */\nexport class DataColumnImpl implements DataColumnRecipe<PObjectId> {\n private specCache?: { readonly value: PColumnSpec };\n private dataCache?: { readonly value: ColumnData };\n private dataStatusCache?: { readonly value: ColumnFieldStatus };\n\n private constructor(\n public readonly id: PObjectId,\n private readonly options: {\n getSpec: () => PColumnSpec;\n getData: () => ColumnData;\n getDataStatus: () => ColumnFieldStatus;\n },\n ) {}\n\n /** A leaf-recipe references exactly one column — its own id. */\n getReferencedIds(): PObjectId[] {\n return [this.id];\n }\n\n getSpec(): PColumnSpec {\n if (this.specCache === undefined) {\n this.specCache = { value: this.options.getSpec() };\n }\n return this.specCache.value;\n }\n\n /** Leaf-shaped — points straight at `this.id`. */\n getQuery(): SpecQuery {\n return { type: \"column\", column: this.id } as SpecQuery;\n }\n\n getData(): ColumnData {\n if (this.dataCache === undefined) this.dataCache = { value: this.options.getData() };\n return this.dataCache.value;\n }\n\n getDataStatus(): ColumnFieldStatus {\n if (this.dataStatusCache === undefined) {\n this.dataStatusCache = { value: this.options.getDataStatus() };\n }\n return this.dataStatusCache.value;\n }\n\n /**\n * Overlay overrides → produces a {@link ColumnOverriddenRecipe} wrapping\n * this leaf. The leaf itself stays bare (id remains a plain PObjectId);\n * layering lives entirely in the recipe wrappers.\n */\n withSpecs(overrides: SpecOverrides): ColumnRecipe {\n return ColumnOverriddenRecipe.wrap(this, overrides);\n }\n\n /**\n * Resolve via the ambient {@link ColumnRegistry}. Spec is resolved eagerly:\n * returns `undefined` if the leaf isn't reachable yet (resolving). Throws\n * {@link ColumnAbsentError} when every relevant accessor is `inputsLocked`\n * and the column did not appear — the column will not exist in this ctx.\n * Data and dataStatus stay lazy.\n */\n static fromId(\n id: PObjectId,\n { ctx }: { ctx?: GlobalCfgRenderCtx } = {},\n ): undefined | DataColumnRecipe<PObjectId> {\n const registry = new ColumnRegistry(getCtxProviders({ ctx }));\n const leaf = registry.resolve(id);\n if (isNil(leaf)) {\n if (registry.isFinal()) throw new ColumnAbsentError(id);\n return undefined;\n }\n const spec = readSpecAccessor(leaf);\n if (isNil(spec)) {\n if (leaf.accessor.getInputsLocked()) throw new ColumnAbsentError(id);\n return undefined;\n }\n if (!spec.hasData()) return undefined;\n return new DataColumnImpl(id, {\n getSpec: () => spec.getDataAsJson<PColumnSpec>(),\n getData: () => readDataAccessor(leaf),\n getDataStatus: () => readDataStatus(leaf),\n });\n }\n\n /** {@link PlRef} wrapper over {@link fromId}. */\n static fromPlRef(ref: PlRef): undefined | DataColumnRecipe<PObjectId> {\n return DataColumnImpl.fromId(createGlobalPObjectId(ref.blockId, ref.name));\n }\n\n /**\n * Bind directly to an accessor-backed {@link LeafEntry} — no registry.\n * Throws {@link ColumnAbsentError} if the leaf has no spec field and its\n * accessor is `inputsLocked`. Returns `undefined` while still resolving.\n */\n static fromAccessor(entry: LeafEntry<TreeNodeAccessor>): undefined | DataColumnRecipe<PObjectId> {\n const spec = readSpecAccessor(entry);\n if (isNil(spec)) {\n if (entry.accessor.getInputsLocked()) throw new ColumnAbsentError(entry.id);\n return undefined;\n }\n if (!spec.hasData()) return undefined;\n return new DataColumnImpl(entry.id, {\n getSpec: () => spec.getDataAsJson<PColumnSpec>(),\n getData: () => readDataAccessor(entry),\n getDataStatus: () => readDataStatus(entry),\n });\n }\n\n /**\n * Wrap a materialised {@link PColumn}. If the input is already a\n * {@link DataColumnRecipe} leaf it is returned as-is.\n */\n static fromColumn(\n column: PColumn<ColumnData> | DataColumnRecipe<PObjectId>,\n ): DataColumnRecipe<PObjectId> {\n if (column instanceof DataColumnImpl) return column;\n // `DataColumnRecipe` is an interface, so `instanceof` above does not remove it\n // from the union. The only implementation carrying a bare `PObjectId` is\n // `DataColumnImpl` (wrappers expose `ColumnUniversalId`), so anything\n // reaching here is a materialised `PColumn`.\n const pColumn = column as PColumn<ColumnData>;\n return new DataColumnImpl(pColumn.id, {\n getSpec: () => pColumn.spec,\n getData: () => pColumn.data,\n getDataStatus: () => \"present\",\n });\n }\n\n /**\n * Distinguishes `present` / `resolving` / `absent` for a {@link PObjectId}\n * in the active render ctx. Falls back to the registry's `isFinal()`\n * when the id has no entry — only then we can say `absent` instead of\n * `resolving`.\n */\n static getStatusById(\n id: PObjectId,\n { ctx }: { ctx?: GlobalCfgRenderCtx } = {},\n ): ColumnResolutionStatus {\n const registry = new ColumnRegistry(getCtxProviders({ ctx }));\n const leaf = registry.resolve(id);\n if (isNil(leaf)) return registry.isFinal() ? \"absent\" : \"resolving\";\n return getLeafEntryStatus(leaf);\n }\n\n /** {@link PlRef} wrapper over {@link getStatusById}. */\n static getStatusByPlRef(\n ref: PlRef,\n opts: { ctx?: GlobalCfgRenderCtx } = {},\n ): ColumnResolutionStatus {\n return DataColumnImpl.getStatusById(createGlobalPObjectId(ref.blockId, ref.name), opts);\n }\n\n /** No registry — reads straight off the entry's accessor. */\n static getStatusByAccessor(entry: LeafEntry<TreeNodeAccessor>): ColumnResolutionStatus {\n return getLeafEntryStatus(entry);\n }\n}\n\n/** Anything the {@link DataColumnRecipe} dispatcher can build a leaf from. */\nexport type DataColumnSource =\n | PObjectId\n | PlRef\n | LeafEntry<TreeNodeAccessor>\n | PColumn<ColumnData>\n | DataColumnRecipe<PObjectId>;\n\n/**\n * Unified dispatcher — picks the right `DataColumnImpl.fromX` by source\n * shape. For ambiguous inputs callers can still use the explicit factories\n * (also attached as properties: `DataColumn.fromId`, `.fromPlRef`,\n * `.fromAccessor`, `.fromColumn`).\n */\nfunction DataColumnDispatch(\n source: DataColumnSource,\n opts: { ctx?: GlobalCfgRenderCtx } = {},\n): undefined | DataColumnRecipe<PObjectId> {\n if (typeof source === \"string\") return DataColumnImpl.fromId(source, opts);\n if (source instanceof DataColumnImpl) return source;\n // `DataColumnRecipe` is an interface — `instanceof` above cannot remove it from\n // the union, and only `DataColumnImpl` implements it with a bare id.\n const rest = source as LeafEntry<TreeNodeAccessor> | PlRef | PColumn<ColumnData>;\n if (\"accessor\" in rest) return DataColumnImpl.fromAccessor(rest);\n if (isPlRef(rest)) return DataColumnImpl.fromPlRef(rest);\n if (isPColumn(rest)) return DataColumnImpl.fromColumn(rest);\n throw new Error(\"DataColumn: unknown source shape\");\n}\n\n/**\n * Polymorphic counterpart to {@link DataColumnDispatch}: returns the\n * {@link ColumnResolutionStatus} for any factory input without constructing\n * the recipe. For already-materialised sources ({@link PColumn} value,\n * existing {@link DataColumnRecipe}) status is `present` by construction.\n */\nfunction DataColumnGetStatus(\n source: DataColumnSource,\n opts: { ctx?: GlobalCfgRenderCtx } = {},\n): ColumnResolutionStatus {\n if (typeof source === \"string\") return DataColumnImpl.getStatusById(source, opts);\n if (source instanceof DataColumnImpl) return \"present\";\n const rest = source as LeafEntry<TreeNodeAccessor> | PlRef | PColumn<ColumnData>;\n if (\"accessor\" in rest) return DataColumnImpl.getStatusByAccessor(rest);\n if (isPlRef(rest)) return DataColumnImpl.getStatusByPlRef(rest, opts);\n if (isPColumn(rest)) return \"present\";\n throw new Error(\"DataColumn.getStatus: unknown source shape\");\n}\n\nexport const DataColumn = Object.assign(DataColumnDispatch, {\n fromId: DataColumnImpl.fromId,\n fromPlRef: DataColumnImpl.fromPlRef,\n fromAccessor: DataColumnImpl.fromAccessor,\n fromColumn: DataColumnImpl.fromColumn,\n getStatus: DataColumnGetStatus,\n getStatusById: DataColumnImpl.getStatusById,\n getStatusByPlRef: DataColumnImpl.getStatusByPlRef,\n getStatusByAccessor: DataColumnImpl.getStatusByAccessor,\n});\n\n/**\n * Type-guard narrowing to a bare leaf — a {@link DataColumnRecipe} whose `id` is a\n * plain {@link PObjectId}.\n */\nexport function isDataColumn(value: unknown): value is DataColumnRecipe<PObjectId> {\n return value instanceof DataColumnImpl;\n}\n\nconst readSpecAccessor = memoizeByEntry(\n ({ accessor, name }: LeafEntry<TreeNodeAccessor>): undefined | TreeNodeAccessor =>\n accessor.traverse({ field: `${name}.spec`, assertFieldType: \"Input\", ignoreError: true }),\n);\n\n/**\n * Per-entry counterpart to {@link readDataStatus}: tells whether the leaf's\n * **spec** can be read in this ctx, and — for the negative cases —\n * distinguishes `resolving` from `absent` via `getInputsLocked()`.\n *\n * - spec field not yet on the entry's accessor + inputs locked → `absent`\n * - spec field not yet on the entry's accessor + still resolving → `resolving`\n * - spec resource present but bytes not yet written → `resolving`\n * (transient — the spec resource is connected, just unfilled)\n * - spec resource present and `hasData()` → `present`\n */\nfunction getLeafEntryStatus(entry: LeafEntry<TreeNodeAccessor>): ColumnResolutionStatus {\n const spec = readSpecAccessor(entry);\n if (isNil(spec)) return entry.accessor.getInputsLocked() ? \"absent\" : \"resolving\";\n if (!spec.hasData()) return \"resolving\";\n return \"present\";\n}\n\nconst readDataAccessor = memoizeByEntry(\n ({ accessor, name }: LeafEntry<TreeNodeAccessor>): undefined | TreeNodeAccessor =>\n accessor.traverse({ field: `${name}.data`, assertFieldType: \"Input\", ignoreError: true }),\n);\n\nconst readDataStatus = memoizeByEntry(\n ({ accessor, name }: LeafEntry<TreeNodeAccessor>): ColumnFieldStatus => {\n if (accessor.listInputFields().includes(`${name}.data`)) return \"present\";\n return accessor.getInputsLocked() ? \"absent\" : \"resolving\";\n },\n);\n\nfunction memoizeByEntry<R>(\n fn: (entry: LeafEntry<TreeNodeAccessor>) => R,\n): (entry: LeafEntry<TreeNodeAccessor>) => R {\n const cache = new LRUCache<string, { value: R }>({ max: 1000 });\n return (entry) => {\n const key = `${entry.accessor.handle}:${entry.name}`;\n let hit = cache.get(key);\n if (!hit) cache.set(key, (hit = { value: fn(entry) }));\n return hit.value;\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,152 @@
1
+ import { GlobalCfgRenderCtx, PColumnDataUniversal } from "../render/internal.js";
2
+ import { TreeNodeAccessor } from "../render/accessor.js";
3
+ import { ColumnFieldStatus, ColumnRecipe, ColumnRecipeId, ColumnResolutionStatus } from "./column_recipes/types.js";
4
+ import { ColumnUniversalId, LeafEntry, PColumn, PColumnSpec, PObjectId, PlRef, SpecOverrides, SpecQuery } from "@milaboratories/pl-model-common";
5
+
6
+ //#region src/columns/data_column.d.ts
7
+ type DataColumnId = PObjectId;
8
+ type ColumnData = undefined | PColumnDataUniversal;
9
+ /**
10
+ * A {@link ColumnRecipe} that can be read directly in the sandbox: its
11
+ * {@link getData} is guaranteed to be consistent with {@link getSpec}.
12
+ *
13
+ * This is a *capability*, not a class. Only two recipe shapes carry it — a
14
+ * bare leaf and a spec-override over a bare leaf — because those are the only
15
+ * ones whose data still matches their spec. An axis-filtered recipe drops axes
16
+ * from its spec while the underlying data keeps them, and a discovered recipe
17
+ * only materialises after a join; neither can be read here, so neither
18
+ * implements this interface.
19
+ *
20
+ * Narrow to it with `hasReachableData(recipe)` rather than testing for a concrete
21
+ * class — which recipe classes exist is an implementation detail behind
22
+ * `recipe.id`.
23
+ */
24
+ interface DataColumnRecipe<ID extends ColumnRecipeId = ColumnRecipeId> extends ColumnRecipe<ID> {
25
+ /** Column data, consistent with {@link ColumnRecipe.getSpec}. */
26
+ getData(): ColumnData;
27
+ }
28
+ /**
29
+ * Thrown by leaf-recipe factories when the requested column is provably
30
+ * absent in the active render ctx — i.e. every relevant accessor reports
31
+ * `inputsLocked` and the column did not appear. Distinct from the
32
+ * `undefined` return that the factories still use for the "resolving" case
33
+ * (the column may still appear later).
34
+ *
35
+ * Catch at the boundary (resolver / filter+sort wiring / data-table assembly)
36
+ * when partial absence should be surfaced to the user rather than silently
37
+ * producing an empty result.
38
+ */
39
+ declare class ColumnAbsentError extends Error {
40
+ readonly id: ColumnUniversalId;
41
+ constructor(id: ColumnUniversalId);
42
+ }
43
+ /**
44
+ * The leaf-recipe building block: a {@link DataColumnRecipe} whose `id` is a bare
45
+ * {@link PObjectId} and whose readers are bound to a single tree-accessor
46
+ * leaf. Layered encodings (Overridden / Discovered / Filtered) are reified
47
+ * through their dedicated recipe classes and reference leaf columns by id.
48
+ *
49
+ * Internal — consumers hold the {@link DataColumnRecipe} interface and construct
50
+ * through the {@link DataColumnRecipe} dispatcher.
51
+ */
52
+ declare class DataColumnImpl implements DataColumnRecipe<PObjectId> {
53
+ readonly id: PObjectId;
54
+ private readonly options;
55
+ private specCache?;
56
+ private dataCache?;
57
+ private dataStatusCache?;
58
+ private constructor();
59
+ /** A leaf-recipe references exactly one column — its own id. */
60
+ getReferencedIds(): PObjectId[];
61
+ getSpec(): PColumnSpec;
62
+ /** Leaf-shaped — points straight at `this.id`. */
63
+ getQuery(): SpecQuery;
64
+ getData(): ColumnData;
65
+ getDataStatus(): ColumnFieldStatus;
66
+ /**
67
+ * Overlay overrides → produces a {@link ColumnOverriddenRecipe} wrapping
68
+ * this leaf. The leaf itself stays bare (id remains a plain PObjectId);
69
+ * layering lives entirely in the recipe wrappers.
70
+ */
71
+ withSpecs(overrides: SpecOverrides): ColumnRecipe;
72
+ /**
73
+ * Resolve via the ambient {@link ColumnRegistry}. Spec is resolved eagerly:
74
+ * returns `undefined` if the leaf isn't reachable yet (resolving). Throws
75
+ * {@link ColumnAbsentError} when every relevant accessor is `inputsLocked`
76
+ * and the column did not appear — the column will not exist in this ctx.
77
+ * Data and dataStatus stay lazy.
78
+ */
79
+ static fromId(id: PObjectId, {
80
+ ctx
81
+ }?: {
82
+ ctx?: GlobalCfgRenderCtx;
83
+ }): undefined | DataColumnRecipe<PObjectId>;
84
+ /** {@link PlRef} wrapper over {@link fromId}. */
85
+ static fromPlRef(ref: PlRef): undefined | DataColumnRecipe<PObjectId>;
86
+ /**
87
+ * Bind directly to an accessor-backed {@link LeafEntry} — no registry.
88
+ * Throws {@link ColumnAbsentError} if the leaf has no spec field and its
89
+ * accessor is `inputsLocked`. Returns `undefined` while still resolving.
90
+ */
91
+ static fromAccessor(entry: LeafEntry<TreeNodeAccessor>): undefined | DataColumnRecipe<PObjectId>;
92
+ /**
93
+ * Wrap a materialised {@link PColumn}. If the input is already a
94
+ * {@link DataColumnRecipe} leaf it is returned as-is.
95
+ */
96
+ static fromColumn(column: PColumn<ColumnData> | DataColumnRecipe<PObjectId>): DataColumnRecipe<PObjectId>;
97
+ /**
98
+ * Distinguishes `present` / `resolving` / `absent` for a {@link PObjectId}
99
+ * in the active render ctx. Falls back to the registry's `isFinal()`
100
+ * when the id has no entry — only then we can say `absent` instead of
101
+ * `resolving`.
102
+ */
103
+ static getStatusById(id: PObjectId, {
104
+ ctx
105
+ }?: {
106
+ ctx?: GlobalCfgRenderCtx;
107
+ }): ColumnResolutionStatus;
108
+ /** {@link PlRef} wrapper over {@link getStatusById}. */
109
+ static getStatusByPlRef(ref: PlRef, opts?: {
110
+ ctx?: GlobalCfgRenderCtx;
111
+ }): ColumnResolutionStatus;
112
+ /** No registry — reads straight off the entry's accessor. */
113
+ static getStatusByAccessor(entry: LeafEntry<TreeNodeAccessor>): ColumnResolutionStatus;
114
+ }
115
+ /** Anything the {@link DataColumnRecipe} dispatcher can build a leaf from. */
116
+ type DataColumnSource = PObjectId | PlRef | LeafEntry<TreeNodeAccessor> | PColumn<ColumnData> | DataColumnRecipe<PObjectId>;
117
+ /**
118
+ * Unified dispatcher — picks the right `DataColumnImpl.fromX` by source
119
+ * shape. For ambiguous inputs callers can still use the explicit factories
120
+ * (also attached as properties: `DataColumn.fromId`, `.fromPlRef`,
121
+ * `.fromAccessor`, `.fromColumn`).
122
+ */
123
+ declare function DataColumnDispatch(source: DataColumnSource, opts?: {
124
+ ctx?: GlobalCfgRenderCtx;
125
+ }): undefined | DataColumnRecipe<PObjectId>;
126
+ /**
127
+ * Polymorphic counterpart to {@link DataColumnDispatch}: returns the
128
+ * {@link ColumnResolutionStatus} for any factory input without constructing
129
+ * the recipe. For already-materialised sources ({@link PColumn} value,
130
+ * existing {@link DataColumnRecipe}) status is `present` by construction.
131
+ */
132
+ declare function DataColumnGetStatus(source: DataColumnSource, opts?: {
133
+ ctx?: GlobalCfgRenderCtx;
134
+ }): ColumnResolutionStatus;
135
+ declare const DataColumn: typeof DataColumnDispatch & {
136
+ fromId: typeof DataColumnImpl.fromId;
137
+ fromPlRef: typeof DataColumnImpl.fromPlRef;
138
+ fromAccessor: typeof DataColumnImpl.fromAccessor;
139
+ fromColumn: typeof DataColumnImpl.fromColumn;
140
+ getStatus: typeof DataColumnGetStatus;
141
+ getStatusById: typeof DataColumnImpl.getStatusById;
142
+ getStatusByPlRef: typeof DataColumnImpl.getStatusByPlRef;
143
+ getStatusByAccessor: typeof DataColumnImpl.getStatusByAccessor;
144
+ };
145
+ /**
146
+ * Type-guard narrowing to a bare leaf — a {@link DataColumnRecipe} whose `id` is a
147
+ * plain {@link PObjectId}.
148
+ */
149
+ declare function isDataColumn(value: unknown): value is DataColumnRecipe<PObjectId>;
150
+ //#endregion
151
+ export { ColumnAbsentError, ColumnData, type ColumnFieldStatus, type ColumnResolutionStatus, DataColumn, DataColumnId, DataColumnImpl, DataColumnRecipe, DataColumnSource, isDataColumn };
152
+ //# sourceMappingURL=data_column.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data_column.d.ts","names":[],"sources":["../../src/columns/data_column.ts"],"mappings":";;;;;;KA2BY,YAAA,GAAe,SAAS;AAAA,KACxB,UAAA,eAAyB,oBAAoB;AADzD;;;;AAAoC;AACpC;;;;AAAyD;AAkBzD;;;;;AAnBA,UAmBiB,gBAAA,YACJ,cAAA,GAAiB,cAAA,UACpB,YAAA,CAAa,EAAA;EAEV;EAAX,OAAA,IAAW,UAAA;AAAA;;;;;;;;;;AAAU;AAcvB;cAAa,iBAAA,SAA0B,KAAA;EAAA,SACT,EAAA,EAAI,iBAAA;cAAJ,EAAA,EAAI,iBAAA;AAAA;;;;;;;;;;cAerB,cAAA,YAA0B,gBAAA,CAAiB,SAAA;EAAA,SAMpC,EAAA,EAAI,SAAA;EAAA,iBACH,OAAA;EAAA,QANX,SAAA;EAAA,QACA,SAAA;EAAA,QACA,eAAA;EAAA,QAED,WAAA;EAUa;EAApB,gBAAA,IAAoB,SAAA;EAIpB,OAAA,IAAW,WAAA;EAYA;EAJX,QAAA,IAAY,SAAA;EAIZ,OAAA,IAAW,UAAA;EAKX,aAAA,IAAiB,iBAAA;EAwBX;;;;;EAZN,SAAA,CAAU,SAAA,EAAW,aAAA,GAAgB,YAAA;EAmCsB;;;;;;;EAAA,OAxBpD,MAAA,CACL,EAAA,EAAI,SAAA;IACF;EAAA;IAAS,GAAA,GAAM,kBAAA;EAAA,gBACJ,gBAAA,CAAiB,SAAA;EAkDZ;EAAA,OA7Bb,SAAA,CAAU,GAAA,EAAK,KAAA,eAAoB,gBAAA,CAAiB,SAAA;EAkDrD;;;;;EAAA,OAzCC,YAAA,CAAa,KAAA,EAAO,SAAA,CAAU,gBAAA,gBAAgC,gBAAA,CAAiB,SAAA;EAsDnF;;;;EAAA,OApCI,UAAA,CACL,MAAA,EAAQ,OAAA,CAAQ,UAAA,IAAc,gBAAA,CAAiB,SAAA,IAC9C,gBAAA,CAAiB,SAAA;EAhHiC;;;;;;EAAA,OAoI9C,aAAA,CACL,EAAA,EAAI,SAAA;IACF;EAAA;IAAS,GAAA,GAAM,kBAAA;EAAA,IAChB,sBAAA;EApIK;EAAA,OA4ID,gBAAA,CACL,GAAA,EAAK,KAAA,EACL,IAAA;IAAQ,GAAA,GAAM,kBAAA;EAAA,IACb,sBAAA;EA/HH;EAAA,OAoIO,mBAAA,CAAoB,KAAA,EAAO,SAAA,CAAU,gBAAA,IAAoB,sBAAA;AAAA;;KAMtD,gBAAA,GACR,SAAA,GACA,KAAA,GACA,SAAA,CAAU,gBAAA,IACV,OAAA,CAAQ,UAAA,IACR,gBAAA,CAAiB,SAAA;;;;;;;iBAQZ,kBAAA,CACP,MAAA,EAAQ,gBAAA,EACR,IAAA;EAAQ,GAAA,GAAM,kBAAA;AAAA,gBACD,gBAAA,CAAiB,SAAA;;;;;;;iBAkBvB,mBAAA,CACP,MAAA,EAAQ,gBAAA,EACR,IAAA;EAAQ,GAAA,GAAM,kBAAA;AAAA,IACb,sBAAA;AAAA,cAUU,UAAA,SAAU,kBAAA;;;;;;;;;;;;;;iBAeP,YAAA,CAAa,KAAA,YAAiB,KAAA,IAAS,gBAAgB,CAAC,SAAA"}
@@ -3,7 +3,7 @@ import { getCtxProviders } from "./column_providers/index.js";
3
3
  import { ColumnRegistry, createGlobalPObjectId, isPColumn, isPlRef } from "@milaboratories/pl-model-common";
4
4
  import { isNil } from "es-toolkit";
5
5
  import { LRUCache } from "lru-cache";
6
- //#region src/columns/column_lazy.ts
6
+ //#region src/columns/data_column.ts
7
7
  /**
8
8
  * Thrown by leaf-recipe factories when the requested column is provably
9
9
  * absent in the active render ctx — i.e. every relevant accessor reports
@@ -24,13 +24,15 @@ var ColumnAbsentError = class extends Error {
24
24
  }
25
25
  };
26
26
  /**
27
- * ColumnLazy is the leaf-recipe building block: a {@link ColumnRecipe} whose
28
- * `id` is a bare {@link PObjectId} and whose readers are bound to a single
29
- * tree-accessor leaf. Layered encodings (Overridden / Discovered / Filtered)
30
- * are reified through their dedicated recipe classes and reference leaf
31
- * columns by id.
27
+ * The leaf-recipe building block: a {@link DataColumnRecipe} whose `id` is a bare
28
+ * {@link PObjectId} and whose readers are bound to a single tree-accessor
29
+ * leaf. Layered encodings (Overridden / Discovered / Filtered) are reified
30
+ * through their dedicated recipe classes and reference leaf columns by id.
31
+ *
32
+ * Internal — consumers hold the {@link DataColumnRecipe} interface and construct
33
+ * through the {@link DataColumnRecipe} dispatcher.
32
34
  */
33
- var ColumnLazyImpl = class ColumnLazyImpl {
35
+ var DataColumnImpl = class DataColumnImpl {
34
36
  id;
35
37
  options;
36
38
  specCache;
@@ -55,7 +57,6 @@ var ColumnLazyImpl = class ColumnLazyImpl {
55
57
  column: this.id
56
58
  };
57
59
  }
58
- /** Leaf-only: not on the recipe interface — only the leaf can read data directly. */
59
60
  getData() {
60
61
  if (this.dataCache === void 0) this.dataCache = { value: this.options.getData() };
61
62
  return this.dataCache.value;
@@ -66,7 +67,7 @@ var ColumnLazyImpl = class ColumnLazyImpl {
66
67
  }
67
68
  /**
68
69
  * Overlay overrides → produces a {@link ColumnOverriddenRecipe} wrapping
69
- * this leaf. ColumnLazy itself stays bare (id remains a plain PObjectId);
70
+ * this leaf. The leaf itself stays bare (id remains a plain PObjectId);
70
71
  * layering lives entirely in the recipe wrappers.
71
72
  */
72
73
  withSpecs(overrides) {
@@ -92,7 +93,7 @@ var ColumnLazyImpl = class ColumnLazyImpl {
92
93
  return;
93
94
  }
94
95
  if (!spec.hasData()) return void 0;
95
- return new ColumnLazyImpl(id, {
96
+ return new DataColumnImpl(id, {
96
97
  getSpec: () => spec.getDataAsJson(),
97
98
  getData: () => readDataAccessor(leaf),
98
99
  getDataStatus: () => readDataStatus(leaf)
@@ -100,7 +101,7 @@ var ColumnLazyImpl = class ColumnLazyImpl {
100
101
  }
101
102
  /** {@link PlRef} wrapper over {@link fromId}. */
102
103
  static fromPlRef(ref) {
103
- return ColumnLazyImpl.fromId(createGlobalPObjectId(ref.blockId, ref.name));
104
+ return DataColumnImpl.fromId(createGlobalPObjectId(ref.blockId, ref.name));
104
105
  }
105
106
  /**
106
107
  * Bind directly to an accessor-backed {@link LeafEntry} — no registry.
@@ -114,7 +115,7 @@ var ColumnLazyImpl = class ColumnLazyImpl {
114
115
  return;
115
116
  }
116
117
  if (!spec.hasData()) return void 0;
117
- return new ColumnLazyImpl(entry.id, {
118
+ return new DataColumnImpl(entry.id, {
118
119
  getSpec: () => spec.getDataAsJson(),
119
120
  getData: () => readDataAccessor(entry),
120
121
  getDataStatus: () => readDataStatus(entry)
@@ -122,13 +123,14 @@ var ColumnLazyImpl = class ColumnLazyImpl {
122
123
  }
123
124
  /**
124
125
  * Wrap a materialised {@link PColumn}. If the input is already a
125
- * {@link ColumnLazy} it is returned as-is.
126
+ * {@link DataColumnRecipe} leaf it is returned as-is.
126
127
  */
127
128
  static fromColumn(column) {
128
- if (column instanceof ColumnLazyImpl) return column;
129
- return new ColumnLazyImpl(column.id, {
130
- getSpec: () => column.spec,
131
- getData: () => column.data,
129
+ if (column instanceof DataColumnImpl) return column;
130
+ const pColumn = column;
131
+ return new DataColumnImpl(pColumn.id, {
132
+ getSpec: () => pColumn.spec,
133
+ getData: () => pColumn.data,
132
134
  getDataStatus: () => "present"
133
135
  });
134
136
  }
@@ -146,7 +148,7 @@ var ColumnLazyImpl = class ColumnLazyImpl {
146
148
  }
147
149
  /** {@link PlRef} wrapper over {@link getStatusById}. */
148
150
  static getStatusByPlRef(ref, opts = {}) {
149
- return ColumnLazyImpl.getStatusById(createGlobalPObjectId(ref.blockId, ref.name), opts);
151
+ return DataColumnImpl.getStatusById(createGlobalPObjectId(ref.blockId, ref.name), opts);
150
152
  }
151
153
  /** No registry — reads straight off the entry's accessor. */
152
154
  static getStatusByAccessor(entry) {
@@ -154,50 +156,51 @@ var ColumnLazyImpl = class ColumnLazyImpl {
154
156
  }
155
157
  };
156
158
  /**
157
- * Unified dispatcher — picks the right `ColumnLazyImpl.fromX` by source
159
+ * Unified dispatcher — picks the right `DataColumnImpl.fromX` by source
158
160
  * shape. For ambiguous inputs callers can still use the explicit factories
159
- * (also attached as properties: `ColumnLazy.fromId`, `.fromPlRef`,
161
+ * (also attached as properties: `DataColumn.fromId`, `.fromPlRef`,
160
162
  * `.fromAccessor`, `.fromColumn`).
161
163
  */
162
- function ColumnLazyDispatch(source, opts = {}) {
163
- if (typeof source === "string") return ColumnLazyImpl.fromId(source, opts);
164
- if (source instanceof ColumnLazyImpl) return source;
165
- if ("accessor" in source) return ColumnLazyImpl.fromAccessor(source);
166
- if (isPlRef(source)) return ColumnLazyImpl.fromPlRef(source);
167
- if (isPColumn(source)) return ColumnLazyImpl.fromColumn(source);
168
- throw new Error("ColumnLazy: unknown source shape");
164
+ function DataColumnDispatch(source, opts = {}) {
165
+ if (typeof source === "string") return DataColumnImpl.fromId(source, opts);
166
+ if (source instanceof DataColumnImpl) return source;
167
+ const rest = source;
168
+ if ("accessor" in rest) return DataColumnImpl.fromAccessor(rest);
169
+ if (isPlRef(rest)) return DataColumnImpl.fromPlRef(rest);
170
+ if (isPColumn(rest)) return DataColumnImpl.fromColumn(rest);
171
+ throw new Error("DataColumn: unknown source shape");
169
172
  }
170
173
  /**
171
- * Polymorphic counterpart to {@link ColumnLazyDispatch}: returns the
174
+ * Polymorphic counterpart to {@link DataColumnDispatch}: returns the
172
175
  * {@link ColumnResolutionStatus} for any factory input without constructing
173
176
  * the recipe. For already-materialised sources ({@link PColumn} value,
174
- * existing {@link ColumnLazy}) status is `present` by construction.
177
+ * existing {@link DataColumnRecipe}) status is `present` by construction.
175
178
  */
176
- function ColumnLazyGetStatus(source, opts = {}) {
177
- if (typeof source === "string") return ColumnLazyImpl.getStatusById(source, opts);
178
- if (source instanceof ColumnLazyImpl) return "present";
179
- if ("accessor" in source) return ColumnLazyImpl.getStatusByAccessor(source);
180
- if (isPlRef(source)) return ColumnLazyImpl.getStatusByPlRef(source, opts);
181
- if (isPColumn(source)) return "present";
182
- throw new Error("ColumnLazy.getStatus: unknown source shape");
179
+ function DataColumnGetStatus(source, opts = {}) {
180
+ if (typeof source === "string") return DataColumnImpl.getStatusById(source, opts);
181
+ if (source instanceof DataColumnImpl) return "present";
182
+ const rest = source;
183
+ if ("accessor" in rest) return DataColumnImpl.getStatusByAccessor(rest);
184
+ if (isPlRef(rest)) return DataColumnImpl.getStatusByPlRef(rest, opts);
185
+ if (isPColumn(rest)) return "present";
186
+ throw new Error("DataColumn.getStatus: unknown source shape");
183
187
  }
184
- const ColumnLazy = Object.assign(ColumnLazyDispatch, {
185
- fromId: ColumnLazyImpl.fromId,
186
- fromPlRef: ColumnLazyImpl.fromPlRef,
187
- fromAccessor: ColumnLazyImpl.fromAccessor,
188
- fromColumn: ColumnLazyImpl.fromColumn,
189
- getStatus: ColumnLazyGetStatus,
190
- getStatusById: ColumnLazyImpl.getStatusById,
191
- getStatusByPlRef: ColumnLazyImpl.getStatusByPlRef,
192
- getStatusByAccessor: ColumnLazyImpl.getStatusByAccessor
188
+ const DataColumn = Object.assign(DataColumnDispatch, {
189
+ fromId: DataColumnImpl.fromId,
190
+ fromPlRef: DataColumnImpl.fromPlRef,
191
+ fromAccessor: DataColumnImpl.fromAccessor,
192
+ fromColumn: DataColumnImpl.fromColumn,
193
+ getStatus: DataColumnGetStatus,
194
+ getStatusById: DataColumnImpl.getStatusById,
195
+ getStatusByPlRef: DataColumnImpl.getStatusByPlRef,
196
+ getStatusByAccessor: DataColumnImpl.getStatusByAccessor
193
197
  });
194
198
  /**
195
- * Type-guard narrowing to the leaf recipe. Prefer this over
196
- * `instanceof ColumnLazyImpl` — `ColumnLazy` (the value) is the dispatcher
197
- * with statics, not the class, so `instanceof` requires the impl symbol.
199
+ * Type-guard narrowing to a bare leaf — a {@link DataColumnRecipe} whose `id` is a
200
+ * plain {@link PObjectId}.
198
201
  */
199
- function isColumnLazy(value) {
200
- return value instanceof ColumnLazyImpl;
202
+ function isDataColumn(value) {
203
+ return value instanceof DataColumnImpl;
201
204
  }
202
205
  const readSpecAccessor = memoizeByEntry(({ accessor, name }) => accessor.traverse({
203
206
  field: `${name}.spec`,
@@ -240,6 +243,6 @@ function memoizeByEntry(fn) {
240
243
  };
241
244
  }
242
245
  //#endregion
243
- export { ColumnAbsentError, ColumnLazy, ColumnLazyImpl, isColumnLazy };
246
+ export { ColumnAbsentError, DataColumn, DataColumnImpl, isDataColumn };
244
247
 
245
- //# sourceMappingURL=column_lazy.js.map
248
+ //# sourceMappingURL=data_column.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data_column.js","names":[],"sources":["../../src/columns/data_column.ts"],"sourcesContent":["import {\n ColumnRegistry,\n createGlobalPObjectId,\n isPColumn,\n isPlRef,\n PlRef,\n PObjectId,\n type ColumnUniversalId,\n type LeafEntry,\n type PColumn,\n type PColumnSpec,\n type SpecOverrides,\n type SpecQuery,\n} from \"@milaboratories/pl-model-common\";\nimport type { GlobalCfgRenderCtx, PColumnDataUniversal } from \"../render/internal\";\nimport { getCtxProviders } from \"./column_providers\";\nimport { isNil } from \"es-toolkit\";\nimport { LRUCache } from \"lru-cache\";\nimport { TreeNodeAccessor } from \"../render\";\nimport type {\n ColumnFieldStatus,\n ColumnRecipe,\n ColumnRecipeId,\n ColumnResolutionStatus,\n} from \"./column_recipes/types\";\nimport { ColumnOverriddenRecipe } from \"./column_recipes/column_overrided_recipe\";\n\nexport type DataColumnId = PObjectId;\nexport type ColumnData = undefined | PColumnDataUniversal;\nexport type { ColumnFieldStatus, ColumnResolutionStatus } from \"./column_recipes/types\";\n\n/**\n * A {@link ColumnRecipe} that can be read directly in the sandbox: its\n * {@link getData} is guaranteed to be consistent with {@link getSpec}.\n *\n * This is a *capability*, not a class. Only two recipe shapes carry it — a\n * bare leaf and a spec-override over a bare leaf — because those are the only\n * ones whose data still matches their spec. An axis-filtered recipe drops axes\n * from its spec while the underlying data keeps them, and a discovered recipe\n * only materialises after a join; neither can be read here, so neither\n * implements this interface.\n *\n * Narrow to it with `hasReachableData(recipe)` rather than testing for a concrete\n * class — which recipe classes exist is an implementation detail behind\n * `recipe.id`.\n */\nexport interface DataColumnRecipe<\n ID extends ColumnRecipeId = ColumnRecipeId,\n> extends ColumnRecipe<ID> {\n /** Column data, consistent with {@link ColumnRecipe.getSpec}. */\n getData(): ColumnData;\n}\n\n/**\n * Thrown by leaf-recipe factories when the requested column is provably\n * absent in the active render ctx — i.e. every relevant accessor reports\n * `inputsLocked` and the column did not appear. Distinct from the\n * `undefined` return that the factories still use for the \"resolving\" case\n * (the column may still appear later).\n *\n * Catch at the boundary (resolver / filter+sort wiring / data-table assembly)\n * when partial absence should be surfaced to the user rather than silently\n * producing an empty result.\n */\nexport class ColumnAbsentError extends Error {\n constructor(public readonly id: ColumnUniversalId) {\n super(`Column is absent in the active render ctx and will not appear: ${id}`);\n this.name = \"ColumnAbsentError\";\n }\n}\n\n/**\n * The leaf-recipe building block: a {@link DataColumnRecipe} whose `id` is a bare\n * {@link PObjectId} and whose readers are bound to a single tree-accessor\n * leaf. Layered encodings (Overridden / Discovered / Filtered) are reified\n * through their dedicated recipe classes and reference leaf columns by id.\n *\n * Internal — consumers hold the {@link DataColumnRecipe} interface and construct\n * through the {@link DataColumnRecipe} dispatcher.\n */\nexport class DataColumnImpl implements DataColumnRecipe<PObjectId> {\n private specCache?: { readonly value: PColumnSpec };\n private dataCache?: { readonly value: ColumnData };\n private dataStatusCache?: { readonly value: ColumnFieldStatus };\n\n private constructor(\n public readonly id: PObjectId,\n private readonly options: {\n getSpec: () => PColumnSpec;\n getData: () => ColumnData;\n getDataStatus: () => ColumnFieldStatus;\n },\n ) {}\n\n /** A leaf-recipe references exactly one column — its own id. */\n getReferencedIds(): PObjectId[] {\n return [this.id];\n }\n\n getSpec(): PColumnSpec {\n if (this.specCache === undefined) {\n this.specCache = { value: this.options.getSpec() };\n }\n return this.specCache.value;\n }\n\n /** Leaf-shaped — points straight at `this.id`. */\n getQuery(): SpecQuery {\n return { type: \"column\", column: this.id } as SpecQuery;\n }\n\n getData(): ColumnData {\n if (this.dataCache === undefined) this.dataCache = { value: this.options.getData() };\n return this.dataCache.value;\n }\n\n getDataStatus(): ColumnFieldStatus {\n if (this.dataStatusCache === undefined) {\n this.dataStatusCache = { value: this.options.getDataStatus() };\n }\n return this.dataStatusCache.value;\n }\n\n /**\n * Overlay overrides → produces a {@link ColumnOverriddenRecipe} wrapping\n * this leaf. The leaf itself stays bare (id remains a plain PObjectId);\n * layering lives entirely in the recipe wrappers.\n */\n withSpecs(overrides: SpecOverrides): ColumnRecipe {\n return ColumnOverriddenRecipe.wrap(this, overrides);\n }\n\n /**\n * Resolve via the ambient {@link ColumnRegistry}. Spec is resolved eagerly:\n * returns `undefined` if the leaf isn't reachable yet (resolving). Throws\n * {@link ColumnAbsentError} when every relevant accessor is `inputsLocked`\n * and the column did not appear — the column will not exist in this ctx.\n * Data and dataStatus stay lazy.\n */\n static fromId(\n id: PObjectId,\n { ctx }: { ctx?: GlobalCfgRenderCtx } = {},\n ): undefined | DataColumnRecipe<PObjectId> {\n const registry = new ColumnRegistry(getCtxProviders({ ctx }));\n const leaf = registry.resolve(id);\n if (isNil(leaf)) {\n if (registry.isFinal()) throw new ColumnAbsentError(id);\n return undefined;\n }\n const spec = readSpecAccessor(leaf);\n if (isNil(spec)) {\n if (leaf.accessor.getInputsLocked()) throw new ColumnAbsentError(id);\n return undefined;\n }\n if (!spec.hasData()) return undefined;\n return new DataColumnImpl(id, {\n getSpec: () => spec.getDataAsJson<PColumnSpec>(),\n getData: () => readDataAccessor(leaf),\n getDataStatus: () => readDataStatus(leaf),\n });\n }\n\n /** {@link PlRef} wrapper over {@link fromId}. */\n static fromPlRef(ref: PlRef): undefined | DataColumnRecipe<PObjectId> {\n return DataColumnImpl.fromId(createGlobalPObjectId(ref.blockId, ref.name));\n }\n\n /**\n * Bind directly to an accessor-backed {@link LeafEntry} — no registry.\n * Throws {@link ColumnAbsentError} if the leaf has no spec field and its\n * accessor is `inputsLocked`. Returns `undefined` while still resolving.\n */\n static fromAccessor(entry: LeafEntry<TreeNodeAccessor>): undefined | DataColumnRecipe<PObjectId> {\n const spec = readSpecAccessor(entry);\n if (isNil(spec)) {\n if (entry.accessor.getInputsLocked()) throw new ColumnAbsentError(entry.id);\n return undefined;\n }\n if (!spec.hasData()) return undefined;\n return new DataColumnImpl(entry.id, {\n getSpec: () => spec.getDataAsJson<PColumnSpec>(),\n getData: () => readDataAccessor(entry),\n getDataStatus: () => readDataStatus(entry),\n });\n }\n\n /**\n * Wrap a materialised {@link PColumn}. If the input is already a\n * {@link DataColumnRecipe} leaf it is returned as-is.\n */\n static fromColumn(\n column: PColumn<ColumnData> | DataColumnRecipe<PObjectId>,\n ): DataColumnRecipe<PObjectId> {\n if (column instanceof DataColumnImpl) return column;\n // `DataColumnRecipe` is an interface, so `instanceof` above does not remove it\n // from the union. The only implementation carrying a bare `PObjectId` is\n // `DataColumnImpl` (wrappers expose `ColumnUniversalId`), so anything\n // reaching here is a materialised `PColumn`.\n const pColumn = column as PColumn<ColumnData>;\n return new DataColumnImpl(pColumn.id, {\n getSpec: () => pColumn.spec,\n getData: () => pColumn.data,\n getDataStatus: () => \"present\",\n });\n }\n\n /**\n * Distinguishes `present` / `resolving` / `absent` for a {@link PObjectId}\n * in the active render ctx. Falls back to the registry's `isFinal()`\n * when the id has no entry — only then we can say `absent` instead of\n * `resolving`.\n */\n static getStatusById(\n id: PObjectId,\n { ctx }: { ctx?: GlobalCfgRenderCtx } = {},\n ): ColumnResolutionStatus {\n const registry = new ColumnRegistry(getCtxProviders({ ctx }));\n const leaf = registry.resolve(id);\n if (isNil(leaf)) return registry.isFinal() ? \"absent\" : \"resolving\";\n return getLeafEntryStatus(leaf);\n }\n\n /** {@link PlRef} wrapper over {@link getStatusById}. */\n static getStatusByPlRef(\n ref: PlRef,\n opts: { ctx?: GlobalCfgRenderCtx } = {},\n ): ColumnResolutionStatus {\n return DataColumnImpl.getStatusById(createGlobalPObjectId(ref.blockId, ref.name), opts);\n }\n\n /** No registry — reads straight off the entry's accessor. */\n static getStatusByAccessor(entry: LeafEntry<TreeNodeAccessor>): ColumnResolutionStatus {\n return getLeafEntryStatus(entry);\n }\n}\n\n/** Anything the {@link DataColumnRecipe} dispatcher can build a leaf from. */\nexport type DataColumnSource =\n | PObjectId\n | PlRef\n | LeafEntry<TreeNodeAccessor>\n | PColumn<ColumnData>\n | DataColumnRecipe<PObjectId>;\n\n/**\n * Unified dispatcher — picks the right `DataColumnImpl.fromX` by source\n * shape. For ambiguous inputs callers can still use the explicit factories\n * (also attached as properties: `DataColumn.fromId`, `.fromPlRef`,\n * `.fromAccessor`, `.fromColumn`).\n */\nfunction DataColumnDispatch(\n source: DataColumnSource,\n opts: { ctx?: GlobalCfgRenderCtx } = {},\n): undefined | DataColumnRecipe<PObjectId> {\n if (typeof source === \"string\") return DataColumnImpl.fromId(source, opts);\n if (source instanceof DataColumnImpl) return source;\n // `DataColumnRecipe` is an interface — `instanceof` above cannot remove it from\n // the union, and only `DataColumnImpl` implements it with a bare id.\n const rest = source as LeafEntry<TreeNodeAccessor> | PlRef | PColumn<ColumnData>;\n if (\"accessor\" in rest) return DataColumnImpl.fromAccessor(rest);\n if (isPlRef(rest)) return DataColumnImpl.fromPlRef(rest);\n if (isPColumn(rest)) return DataColumnImpl.fromColumn(rest);\n throw new Error(\"DataColumn: unknown source shape\");\n}\n\n/**\n * Polymorphic counterpart to {@link DataColumnDispatch}: returns the\n * {@link ColumnResolutionStatus} for any factory input without constructing\n * the recipe. For already-materialised sources ({@link PColumn} value,\n * existing {@link DataColumnRecipe}) status is `present` by construction.\n */\nfunction DataColumnGetStatus(\n source: DataColumnSource,\n opts: { ctx?: GlobalCfgRenderCtx } = {},\n): ColumnResolutionStatus {\n if (typeof source === \"string\") return DataColumnImpl.getStatusById(source, opts);\n if (source instanceof DataColumnImpl) return \"present\";\n const rest = source as LeafEntry<TreeNodeAccessor> | PlRef | PColumn<ColumnData>;\n if (\"accessor\" in rest) return DataColumnImpl.getStatusByAccessor(rest);\n if (isPlRef(rest)) return DataColumnImpl.getStatusByPlRef(rest, opts);\n if (isPColumn(rest)) return \"present\";\n throw new Error(\"DataColumn.getStatus: unknown source shape\");\n}\n\nexport const DataColumn = Object.assign(DataColumnDispatch, {\n fromId: DataColumnImpl.fromId,\n fromPlRef: DataColumnImpl.fromPlRef,\n fromAccessor: DataColumnImpl.fromAccessor,\n fromColumn: DataColumnImpl.fromColumn,\n getStatus: DataColumnGetStatus,\n getStatusById: DataColumnImpl.getStatusById,\n getStatusByPlRef: DataColumnImpl.getStatusByPlRef,\n getStatusByAccessor: DataColumnImpl.getStatusByAccessor,\n});\n\n/**\n * Type-guard narrowing to a bare leaf — a {@link DataColumnRecipe} whose `id` is a\n * plain {@link PObjectId}.\n */\nexport function isDataColumn(value: unknown): value is DataColumnRecipe<PObjectId> {\n return value instanceof DataColumnImpl;\n}\n\nconst readSpecAccessor = memoizeByEntry(\n ({ accessor, name }: LeafEntry<TreeNodeAccessor>): undefined | TreeNodeAccessor =>\n accessor.traverse({ field: `${name}.spec`, assertFieldType: \"Input\", ignoreError: true }),\n);\n\n/**\n * Per-entry counterpart to {@link readDataStatus}: tells whether the leaf's\n * **spec** can be read in this ctx, and — for the negative cases —\n * distinguishes `resolving` from `absent` via `getInputsLocked()`.\n *\n * - spec field not yet on the entry's accessor + inputs locked → `absent`\n * - spec field not yet on the entry's accessor + still resolving → `resolving`\n * - spec resource present but bytes not yet written → `resolving`\n * (transient — the spec resource is connected, just unfilled)\n * - spec resource present and `hasData()` → `present`\n */\nfunction getLeafEntryStatus(entry: LeafEntry<TreeNodeAccessor>): ColumnResolutionStatus {\n const spec = readSpecAccessor(entry);\n if (isNil(spec)) return entry.accessor.getInputsLocked() ? \"absent\" : \"resolving\";\n if (!spec.hasData()) return \"resolving\";\n return \"present\";\n}\n\nconst readDataAccessor = memoizeByEntry(\n ({ accessor, name }: LeafEntry<TreeNodeAccessor>): undefined | TreeNodeAccessor =>\n accessor.traverse({ field: `${name}.data`, assertFieldType: \"Input\", ignoreError: true }),\n);\n\nconst readDataStatus = memoizeByEntry(\n ({ accessor, name }: LeafEntry<TreeNodeAccessor>): ColumnFieldStatus => {\n if (accessor.listInputFields().includes(`${name}.data`)) return \"present\";\n return accessor.getInputsLocked() ? \"absent\" : \"resolving\";\n },\n);\n\nfunction memoizeByEntry<R>(\n fn: (entry: LeafEntry<TreeNodeAccessor>) => R,\n): (entry: LeafEntry<TreeNodeAccessor>) => R {\n const cache = new LRUCache<string, { value: R }>({ max: 1000 });\n return (entry) => {\n const key = `${entry.accessor.handle}:${entry.name}`;\n let hit = cache.get(key);\n if (!hit) cache.set(key, (hit = { value: fn(entry) }));\n return hit.value;\n };\n}\n"],"mappings":"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"}