@platforma-sdk/model 1.59.3 → 1.60.2

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 (140) hide show
  1. package/dist/block_storage.cjs.map +1 -1
  2. package/dist/block_storage.d.ts +1 -11
  3. package/dist/block_storage.js.map +1 -1
  4. package/dist/block_storage_callbacks.cjs.map +1 -1
  5. package/dist/block_storage_callbacks.js.map +1 -1
  6. package/dist/columns/column_collection_builder.cjs +215 -0
  7. package/dist/columns/column_collection_builder.cjs.map +1 -0
  8. package/dist/columns/column_collection_builder.d.ts +112 -0
  9. package/dist/columns/column_collection_builder.js +214 -0
  10. package/dist/columns/column_collection_builder.js.map +1 -0
  11. package/dist/columns/column_selector.cjs +122 -0
  12. package/dist/columns/column_selector.cjs.map +1 -0
  13. package/dist/columns/column_selector.d.ts +41 -0
  14. package/dist/columns/column_selector.js +118 -0
  15. package/dist/columns/column_selector.js.map +1 -0
  16. package/dist/columns/column_snapshot.cjs +20 -0
  17. package/dist/columns/column_snapshot.cjs.map +1 -0
  18. package/dist/columns/column_snapshot.d.ts +39 -0
  19. package/dist/columns/column_snapshot.js +18 -0
  20. package/dist/columns/column_snapshot.js.map +1 -0
  21. package/dist/columns/column_snapshot_provider.cjs +112 -0
  22. package/dist/columns/column_snapshot_provider.cjs.map +1 -0
  23. package/dist/columns/column_snapshot_provider.d.ts +73 -0
  24. package/dist/columns/column_snapshot_provider.js +107 -0
  25. package/dist/columns/column_snapshot_provider.js.map +1 -0
  26. package/dist/columns/ctx_column_sources.cjs +84 -0
  27. package/dist/columns/ctx_column_sources.cjs.map +1 -0
  28. package/dist/columns/ctx_column_sources.d.ts +33 -0
  29. package/dist/columns/ctx_column_sources.js +82 -0
  30. package/dist/columns/ctx_column_sources.js.map +1 -0
  31. package/dist/columns/index.cjs +5 -0
  32. package/dist/columns/index.d.ts +5 -0
  33. package/dist/columns/index.js +5 -0
  34. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.cjs +111 -0
  35. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.cjs.map +1 -0
  36. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.d.ts +25 -0
  37. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js +110 -0
  38. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js.map +1 -0
  39. package/dist/components/PlDataTable/{table.cjs → createPlDataTable/createPlDataTableV3.cjs} +54 -54
  40. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs.map +1 -0
  41. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.d.ts +39 -0
  42. package/dist/components/PlDataTable/{table.js → createPlDataTable/createPlDataTableV3.js} +53 -53
  43. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js.map +1 -0
  44. package/dist/components/PlDataTable/createPlDataTable/index.cjs +12 -0
  45. package/dist/components/PlDataTable/createPlDataTable/index.cjs.map +1 -0
  46. package/dist/components/PlDataTable/createPlDataTable/index.d.ts +15 -0
  47. package/dist/components/PlDataTable/createPlDataTable/index.js +12 -0
  48. package/dist/components/PlDataTable/createPlDataTable/index.js.map +1 -0
  49. package/dist/components/PlDataTable/createPlDataTableSheet.cjs +18 -0
  50. package/dist/components/PlDataTable/createPlDataTableSheet.cjs.map +1 -0
  51. package/dist/components/PlDataTable/createPlDataTableSheet.d.ts +11 -0
  52. package/dist/components/PlDataTable/createPlDataTableSheet.js +17 -0
  53. package/dist/components/PlDataTable/createPlDataTableSheet.js.map +1 -0
  54. package/dist/components/PlDataTable/index.cjs +4 -1
  55. package/dist/components/PlDataTable/index.d.ts +5 -2
  56. package/dist/components/PlDataTable/index.js +4 -1
  57. package/dist/components/PlDataTable/state-migration.cjs.map +1 -1
  58. package/dist/components/PlDataTable/state-migration.d.ts +2 -2
  59. package/dist/components/PlDataTable/state-migration.js.map +1 -1
  60. package/dist/components/PlDataTable/{v4.d.ts → typesV4.d.ts} +2 -2
  61. package/dist/components/PlDataTable/{v5.d.ts → typesV5.d.ts} +2 -2
  62. package/dist/components/index.cjs +4 -1
  63. package/dist/components/index.d.ts +5 -2
  64. package/dist/components/index.js +4 -1
  65. package/dist/index.cjs +44 -16
  66. package/dist/index.d.ts +17 -5
  67. package/dist/index.js +15 -3
  68. package/dist/labels/derive_distinct_labels.cjs +156 -0
  69. package/dist/labels/derive_distinct_labels.cjs.map +1 -0
  70. package/dist/labels/derive_distinct_labels.d.ts +29 -0
  71. package/dist/labels/derive_distinct_labels.js +155 -0
  72. package/dist/labels/derive_distinct_labels.js.map +1 -0
  73. package/dist/labels/index.cjs +2 -0
  74. package/dist/labels/index.d.ts +2 -0
  75. package/dist/labels/index.js +2 -0
  76. package/dist/labels/write_labels_to_specs.cjs +15 -0
  77. package/dist/labels/write_labels_to_specs.cjs.map +1 -0
  78. package/dist/labels/write_labels_to_specs.d.ts +9 -0
  79. package/dist/labels/write_labels_to_specs.js +14 -0
  80. package/dist/labels/write_labels_to_specs.js.map +1 -0
  81. package/dist/package.cjs +1 -1
  82. package/dist/package.js +1 -1
  83. package/dist/render/api.cjs +11 -2
  84. package/dist/render/api.cjs.map +1 -1
  85. package/dist/render/api.d.ts +9 -5
  86. package/dist/render/api.js +12 -3
  87. package/dist/render/api.js.map +1 -1
  88. package/dist/render/index.d.ts +2 -1
  89. package/dist/render/index.js +1 -1
  90. package/dist/render/internal.cjs.map +1 -1
  91. package/dist/render/internal.d.ts +5 -2
  92. package/dist/render/internal.js.map +1 -1
  93. package/dist/render/util/column_collection.cjs +3 -3
  94. package/dist/render/util/column_collection.cjs.map +1 -1
  95. package/dist/render/util/column_collection.d.ts +3 -2
  96. package/dist/render/util/column_collection.js +4 -4
  97. package/dist/render/util/column_collection.js.map +1 -1
  98. package/dist/render/util/index.d.ts +2 -1
  99. package/dist/render/util/index.js +1 -1
  100. package/dist/render/util/label.cjs +7 -134
  101. package/dist/render/util/label.cjs.map +1 -1
  102. package/dist/render/util/label.d.ts +5 -50
  103. package/dist/render/util/label.js +8 -132
  104. package/dist/render/util/label.js.map +1 -1
  105. package/dist/render/util/split_selectors.d.ts +2 -2
  106. package/package.json +9 -7
  107. package/src/block_storage.ts +0 -11
  108. package/src/block_storage_callbacks.ts +1 -1
  109. package/src/columns/column_collection_builder.test.ts +427 -0
  110. package/src/columns/column_collection_builder.ts +455 -0
  111. package/src/columns/column_selector.test.ts +472 -0
  112. package/src/columns/column_selector.ts +212 -0
  113. package/src/columns/column_snapshot.ts +55 -0
  114. package/src/columns/column_snapshot_provider.ts +177 -0
  115. package/src/columns/ctx_column_sources.ts +107 -0
  116. package/src/columns/expand_by_partition.test.ts +289 -0
  117. package/src/columns/expand_by_partition.ts +187 -0
  118. package/src/columns/index.ts +5 -0
  119. package/src/components/PlDataTable/createPlDataTable/createPlDataTableV2.ts +193 -0
  120. package/src/components/PlDataTable/{table.ts → createPlDataTable/createPlDataTableV3.ts} +134 -70
  121. package/src/components/PlDataTable/createPlDataTable/index.ts +27 -0
  122. package/src/components/PlDataTable/createPlDataTableSheet.ts +20 -0
  123. package/src/components/PlDataTable/index.ts +6 -4
  124. package/src/components/PlDataTable/state-migration.ts +2 -2
  125. package/src/index.ts +2 -1
  126. package/src/labels/derive_distinct_labels.test.ts +461 -0
  127. package/src/labels/derive_distinct_labels.ts +289 -0
  128. package/src/labels/index.ts +2 -0
  129. package/src/labels/write_labels_to_specs.ts +12 -0
  130. package/src/render/api.ts +25 -3
  131. package/src/render/internal.ts +20 -1
  132. package/src/render/util/column_collection.ts +9 -6
  133. package/src/render/util/label.test.ts +1 -1
  134. package/src/render/util/label.ts +19 -235
  135. package/src/render/util/split_selectors.ts +3 -3
  136. package/dist/components/PlDataTable/table.cjs.map +0 -1
  137. package/dist/components/PlDataTable/table.d.ts +0 -30
  138. package/dist/components/PlDataTable/table.js.map +0 -1
  139. /package/src/components/PlDataTable/{v4.ts → typesV4.ts} +0 -0
  140. /package/src/components/PlDataTable/{v5.ts → typesV5.ts} +0 -0
@@ -0,0 +1,289 @@
1
+ import {
2
+ Annotation,
3
+ parseJson,
4
+ readAnnotation,
5
+ type CanonicalizedJson,
6
+ type PObjectSpec,
7
+ } from "@milaboratories/pl-model-common";
8
+ import { throwError } from "@milaboratories/helpers";
9
+
10
+ const DISTANCE_PENALTY = 0.001;
11
+ const LABEL_TYPE = "__LABEL__";
12
+ const LABEL_TYPE_FULL = "__LABEL__@1";
13
+
14
+ export type WithLabel<T> = {
15
+ value: T;
16
+ label: string;
17
+ };
18
+
19
+ type TraceEntry = {
20
+ id?: string;
21
+ type: string;
22
+ label: string;
23
+ importance?: number;
24
+ };
25
+
26
+ export type Trace = TraceEntry[];
27
+
28
+ export type Entry =
29
+ | PObjectSpec
30
+ | { spec: PObjectSpec; prefixTrace?: TraceEntry[]; suffixTrace?: TraceEntry[] };
31
+
32
+ export type DeriveLabelsOptions = {
33
+ /** Separator to use between label parts (" / " by default) */
34
+ separator?: string;
35
+ /** If true, label will be added as suffix (at the end of the generated label). By default label added as a prefix. */
36
+ addLabelAsSuffix?: boolean;
37
+ /** Force inclusion of native column label */
38
+ includeNativeLabel?: boolean;
39
+ /** Trace elements list that will be forced to be included in the label. */
40
+ forceTraceElements?: string[];
41
+ };
42
+
43
+ export function deriveDistinctLabels<T extends Entry>(
44
+ values: T[],
45
+ options: DeriveLabelsOptions = {},
46
+ ): WithLabel<T>[] {
47
+ const forceTraceElements =
48
+ options.forceTraceElements !== undefined && options.forceTraceElements.length > 0
49
+ ? new Set(options.forceTraceElements)
50
+ : undefined;
51
+ const separator = options.separator ?? " / ";
52
+
53
+ // Phase 1: enrich each value with parsed trace
54
+ const records = values.map((v) => enrichRecord(v, options));
55
+
56
+ // Phase 2: collect global type statistics
57
+ const stats = collectTypeStats(records);
58
+
59
+ // Phase 3: classify types into main (present everywhere) and secondary
60
+ const { mainTypes, secondaryTypes } = classifyTypes(stats, values.length);
61
+
62
+ const build = (typeSet: Set<string>, force: boolean) =>
63
+ buildLabels(records, typeSet, forceTraceElements, separator, force);
64
+
65
+ if (mainTypes.length === 0) {
66
+ if (secondaryTypes.length !== 0)
67
+ throw new Error("Non-empty secondary types list while main types list is empty.");
68
+ return build(new Set(LABEL_TYPE_FULL), true)!;
69
+ }
70
+
71
+ // Phase 4: search for minimal type set that produces unique labels
72
+ //
73
+ // includedCount = 2
74
+ // * *
75
+ // T0 T1 T2 T3 T4 T5
76
+ // *
77
+ // additionalType = 3
78
+ //
79
+ // Resulting set: T0, T1, T3
80
+ //
81
+ let includedCount = 0;
82
+ let additionalType = -1;
83
+ while (includedCount < mainTypes.length) {
84
+ const currentSet = new Set<string>();
85
+ if (options.includeNativeLabel) currentSet.add(LABEL_TYPE_FULL);
86
+ for (let i = 0; i < includedCount; ++i) currentSet.add(mainTypes[i]);
87
+ if (additionalType >= 0) currentSet.add(mainTypes[additionalType]);
88
+
89
+ const candidateResult = build(currentSet, false);
90
+ if (candidateResult !== undefined && countUniqueLabels(candidateResult) === values.length) {
91
+ const minimized = minimizeTypeSet(
92
+ currentSet,
93
+ records,
94
+ stats,
95
+ forceTraceElements,
96
+ options,
97
+ separator,
98
+ );
99
+ return build(minimized, false) ?? throwError("Failed to derive unique labels");
100
+ }
101
+
102
+ additionalType++;
103
+ if (additionalType >= mainTypes.length) {
104
+ includedCount++;
105
+ additionalType = includedCount;
106
+ }
107
+ }
108
+
109
+ // Fallback: include all types, then minimize
110
+ const fallbackSet = new Set([...mainTypes, ...secondaryTypes]);
111
+ const minimized = minimizeTypeSet(
112
+ fallbackSet,
113
+ records,
114
+ stats,
115
+ forceTraceElements,
116
+ options,
117
+ separator,
118
+ );
119
+ return build(minimized, true) ?? throwError("Failed to derive unique labels");
120
+ }
121
+
122
+ // --- Pure helpers ---
123
+ type FullTraceEntry = TraceEntry & { fullType: string; occurrenceIndex: number };
124
+
125
+ type EnrichedRecord<T> = {
126
+ value: T;
127
+ fullTrace: FullTraceEntry[];
128
+ };
129
+
130
+ function extractSpecAndTrace(entry: Entry): {
131
+ spec: PObjectSpec;
132
+ prefixTrace: TraceEntry[] | undefined;
133
+ suffixTrace: TraceEntry[] | undefined;
134
+ } {
135
+ if ("spec" in entry && typeof entry.spec === "object") {
136
+ return { spec: entry.spec, prefixTrace: entry.prefixTrace, suffixTrace: entry.suffixTrace };
137
+ }
138
+ return { spec: entry as PObjectSpec, prefixTrace: undefined, suffixTrace: undefined };
139
+ }
140
+
141
+ function buildFullTrace(trace: TraceEntry[]): FullTraceEntry[] {
142
+ const result: FullTraceEntry[] = [];
143
+ const occurrences = new Map<string, number>();
144
+
145
+ for (let i = trace.length - 1; i >= 0; --i) {
146
+ const entry = trace[i];
147
+ const occurrenceIndex = (occurrences.get(entry.type) ?? 0) + 1;
148
+ occurrences.set(entry.type, occurrenceIndex);
149
+ result.push({
150
+ ...entry,
151
+ fullType: `${entry.type}@${occurrenceIndex}`,
152
+ occurrenceIndex,
153
+ });
154
+ }
155
+
156
+ result.reverse();
157
+ return result;
158
+ }
159
+
160
+ function enrichRecord<T extends Entry>(value: T, options: DeriveLabelsOptions): EnrichedRecord<T> {
161
+ const { spec, prefixTrace, suffixTrace } = extractSpecAndTrace(value);
162
+
163
+ const label = readAnnotation(spec, Annotation.Label);
164
+ const traceStr = readAnnotation(spec, Annotation.Trace) as
165
+ | CanonicalizedJson<TraceEntry[]>
166
+ | undefined;
167
+ const baseTrace: Trace = traceStr ? (parseJson<Trace>(traceStr) ?? []) : [];
168
+ const trace = [...(prefixTrace ?? []), ...baseTrace, ...(suffixTrace ?? [])];
169
+
170
+ if (label !== undefined) {
171
+ const labelEntry = { label, type: LABEL_TYPE, importance: -2 };
172
+ if (options.addLabelAsSuffix) trace.push(labelEntry);
173
+ else trace.splice(0, 0, labelEntry);
174
+ }
175
+
176
+ return { value, fullTrace: buildFullTrace(trace) };
177
+ }
178
+
179
+ type TypeStats = {
180
+ importances: Map<string, number>;
181
+ countByType: Map<string, number>;
182
+ };
183
+
184
+ function collectTypeStats<T>(records: EnrichedRecord<T>[]): TypeStats {
185
+ const importances = new Map<string, number>();
186
+ const countByType = new Map<string, number>();
187
+
188
+ for (const record of records) {
189
+ for (let i = 0; i < record.fullTrace.length; i++) {
190
+ const { fullType, importance: rawImportance } = record.fullTrace[i];
191
+ const importance = rawImportance ?? 0;
192
+ const distance = (record.fullTrace.length - i) * DISTANCE_PENALTY;
193
+
194
+ countByType.set(fullType, (countByType.get(fullType) ?? 0) + 1);
195
+ importances.set(
196
+ fullType,
197
+ Math.max(importances.get(fullType) ?? Number.NEGATIVE_INFINITY, importance - distance),
198
+ );
199
+ }
200
+ }
201
+
202
+ return { importances, countByType };
203
+ }
204
+
205
+ function classifyTypes(
206
+ stats: TypeStats,
207
+ totalRecords: number,
208
+ ): { mainTypes: string[]; secondaryTypes: string[] } {
209
+ const sorted = [...stats.importances].sort(([, i1], [, i2]) => i2 - i1);
210
+
211
+ const mainTypes: string[] = [];
212
+ const secondaryTypes: string[] = [];
213
+
214
+ for (const [typeName] of sorted) {
215
+ if (typeName.endsWith("@1") || stats.countByType.get(typeName) === totalRecords)
216
+ mainTypes.push(typeName);
217
+ else secondaryTypes.push(typeName);
218
+ }
219
+
220
+ return { mainTypes, secondaryTypes };
221
+ }
222
+
223
+ function buildLabels<T>(
224
+ records: EnrichedRecord<T>[],
225
+ includedTypes: Set<string>,
226
+ forceTraceElements: Set<string> | undefined,
227
+ separator: string,
228
+ force: boolean,
229
+ ): WithLabel<T>[] | undefined {
230
+ const result: WithLabel<T>[] = [];
231
+
232
+ for (const r of records) {
233
+ const parts: string[] = [];
234
+ for (const ft of r.fullTrace) {
235
+ if (includedTypes.has(ft.fullType) || forceTraceElements?.has(ft.type)) {
236
+ parts.push(ft.label);
237
+ }
238
+ }
239
+
240
+ if (parts.length === 0) {
241
+ if (!force) return undefined;
242
+ result.push({ label: "Unlabeled", value: r.value });
243
+ continue;
244
+ }
245
+
246
+ result.push({ label: parts.join(separator), value: r.value });
247
+ }
248
+
249
+ return result;
250
+ }
251
+
252
+ function countUniqueLabels<T>(result: WithLabel<T>[] | undefined): number {
253
+ if (result === undefined) return 0;
254
+ return new Set(result.map((c) => c.label)).size;
255
+ }
256
+
257
+ function minimizeTypeSet<T>(
258
+ typeSet: Set<string>,
259
+ records: EnrichedRecord<T>[],
260
+ stats: TypeStats,
261
+ forceTraceElements: Set<string> | undefined,
262
+ options: DeriveLabelsOptions,
263
+ separator: string,
264
+ ): Set<string> {
265
+ const initialResult = buildLabels(records, typeSet, forceTraceElements, separator, false);
266
+ if (initialResult === undefined) return typeSet;
267
+
268
+ const targetCardinality = countUniqueLabels(initialResult);
269
+ const result = new Set(typeSet);
270
+
271
+ const removable = [...result]
272
+ .filter(
273
+ (t) =>
274
+ !forceTraceElements?.has(t.split("@")[0]) &&
275
+ !(options.includeNativeLabel && t === LABEL_TYPE_FULL),
276
+ )
277
+ .sort((a, b) => (stats.importances.get(a) ?? 0) - (stats.importances.get(b) ?? 0));
278
+
279
+ for (const typeToRemove of removable) {
280
+ const candidate = new Set(result);
281
+ candidate.delete(typeToRemove);
282
+ const candidateResult = buildLabels(records, candidate, forceTraceElements, separator, false);
283
+ if (candidateResult !== undefined && countUniqueLabels(candidateResult) >= targetCardinality) {
284
+ result.delete(typeToRemove);
285
+ }
286
+ }
287
+
288
+ return result;
289
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./derive_distinct_labels";
2
+ export * from "./write_labels_to_specs";
@@ -0,0 +1,12 @@
1
+ import { Annotation } from "@milaboratories/pl-model-common";
2
+ import type { ColumnSnapshot } from "../columns";
3
+ import type { WithLabel } from "./derive_distinct_labels";
4
+
5
+ export function writeLabelsToSpecs(items: WithLabel<ColumnSnapshot>[]): void {
6
+ for (const { value, label } of items) {
7
+ // @ts-expect-error - annotations are mutable at runtime, even if not in the type
8
+ value.spec.annotations = value.spec.annotations ?? {};
9
+ value.spec.annotations[Annotation.Label] = label;
10
+ value.spec.annotations["pl7.app/label/isDerived"] = "true";
11
+ }
12
+ }
package/src/render/api.ts CHANGED
@@ -3,6 +3,8 @@ import type {
3
3
  AnyFunction,
4
4
  AxisId,
5
5
  DataInfo,
6
+ DiscoverColumnsRequest,
7
+ DiscoverColumnsResponse,
6
8
  Option,
7
9
  PColumn,
8
10
  PColumnLazy,
@@ -43,8 +45,8 @@ import {
43
45
  mapValueInVOE,
44
46
  PColumnName,
45
47
  readAnnotation,
46
- selectorsToPredicate,
47
48
  withEnrichments,
49
+ legacyColumnSelectorsToPredicate,
48
50
  } from "@milaboratories/pl-model-common";
49
51
  import canonicalize from "canonicalize";
50
52
  import type { Optional } from "utility-types";
@@ -155,7 +157,7 @@ export class ResultPool implements ColumnProvider, AxisLabelProvider {
155
157
  const predicate =
156
158
  typeof predicateOrSelector === "function"
157
159
  ? predicateOrSelector
158
- : selectorsToPredicate(predicateOrSelector);
160
+ : legacyColumnSelectorsToPredicate(predicateOrSelector);
159
161
  const filtered = this.getSpecs().entries.filter((s) => predicate(s.obj));
160
162
 
161
163
  let labelOps: LabelDerivationOps | ((spec: PObjectSpec, ref: PlRef) => string) = {};
@@ -494,7 +496,8 @@ export class ResultPool implements ColumnProvider, AxisLabelProvider {
494
496
  public selectColumns(
495
497
  selectors: ((spec: PColumnSpec) => boolean) | PColumnSelector | PColumnSelector[],
496
498
  ): PColumn<TreeNodeAccessor | undefined>[] {
497
- const predicate = typeof selectors === "function" ? selectors : selectorsToPredicate(selectors);
499
+ const predicate =
500
+ typeof selectors === "function" ? selectors : legacyColumnSelectorsToPredicate(selectors);
498
501
 
499
502
  const matchedSpecs = this.getSpecs().entries.filter(({ obj: spec }) => {
500
503
  if (!isPColumnSpec(spec)) return false;
@@ -709,6 +712,25 @@ export abstract class RenderCtxBase<Args = unknown, Data = unknown> {
709
712
  return this.ctx.getBlockLabel(blockId);
710
713
  }
711
714
 
715
+ //
716
+ // Spec Frames
717
+ //
718
+
719
+ public createSpecFrame(specs: Record<string, PColumnSpec>): string {
720
+ return this.ctx.createSpecFrame(specs);
721
+ }
722
+
723
+ public specFrameDiscoverColumns(
724
+ handle: string,
725
+ request: DiscoverColumnsRequest,
726
+ ): DiscoverColumnsResponse {
727
+ return this.ctx.specFrameDiscoverColumns(handle, request);
728
+ }
729
+
730
+ public specFrameDispose(handle: string): void {
731
+ this.ctx.specFrameDispose(handle);
732
+ }
733
+
712
734
  public getCurrentUnstableMarker(): string | undefined {
713
735
  return this.ctx.getCurrentUnstableMarker();
714
736
  }
@@ -1,5 +1,10 @@
1
1
  import type { Optional } from "utility-types";
2
- import type { Branded, StringifiedJson } from "@milaboratories/pl-model-common";
2
+ import type {
3
+ Branded,
4
+ DiscoverColumnsRequest,
5
+ DiscoverColumnsResponse,
6
+ StringifiedJson,
7
+ } from "@milaboratories/pl-model-common";
3
8
  import type { CommonFieldTraverseOps, FieldTraversalStep, ResourceType } from "./traversal_ops";
4
9
  import type {
5
10
  ArchiveFormat,
@@ -19,6 +24,7 @@ import type {
19
24
  ValueOrError,
20
25
  DataInfo,
21
26
  RangeBytes,
27
+ PColumnSpec,
22
28
  } from "@milaboratories/pl-model-common";
23
29
  import type { TreeNodeAccessor } from "./accessor";
24
30
 
@@ -157,6 +163,19 @@ export interface GlobalCfgRenderCtxMethods<AHandle = AccessorHandle, FHandle = F
157
163
  def: PTableDefV2<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>,
158
164
  ): PTableHandle;
159
165
 
166
+ //
167
+ // Spec Frames (synchronous WASM-based PFrame for spec-level operations)
168
+ //
169
+
170
+ createSpecFrame(specs: Record<string, PColumnSpec>): string;
171
+
172
+ specFrameDiscoverColumns(
173
+ handle: string,
174
+ request: DiscoverColumnsRequest,
175
+ ): DiscoverColumnsResponse;
176
+
177
+ specFrameDispose(handle: string): void;
178
+
160
179
  //
161
180
  // Computable
162
181
  //
@@ -25,17 +25,17 @@ import {
25
25
  isLinkerColumn,
26
26
  isPartitionedDataInfoEntries,
27
27
  isPColumnSpec,
28
+ legacyColumnSelectorsToPredicate,
28
29
  LinkerMap,
29
30
  matchAxisId,
30
31
  resolveAnchors,
31
- selectorsToPredicate,
32
32
  } from "@milaboratories/pl-model-common";
33
33
  import canonicalize from "canonicalize";
34
34
  import type { Optional } from "utility-types";
35
35
  import type { TreeNodeAccessor } from "../accessor";
36
36
  import type { PColumnDataUniversal } from "../internal";
37
37
  import { filterDataInfoEntries } from "./axis_filtering";
38
- import type { LabelDerivationOps, TraceEntry } from "./label";
38
+ import type { LabelDerivationOps } from "./label";
39
39
  import { deriveLabels } from "./label";
40
40
  import { convertOrParsePColumnData, getUniquePartitionKeys } from "./pcolumn_data";
41
41
  import type { APColumnSelectorWithSplit, PColumnSelectorWithSplit } from "./split_selectors";
@@ -66,7 +66,8 @@ class ArrayColumnProvider implements ColumnProvider {
66
66
  selectColumns(
67
67
  selectors: ((spec: PColumnSpec) => boolean) | PColumnSelector | PColumnSelector[],
68
68
  ): PColumn<PColumnDataUniversal | undefined>[] {
69
- const predicate = typeof selectors === "function" ? selectors : selectorsToPredicate(selectors);
69
+ const predicate =
70
+ typeof selectors === "function" ? selectors : legacyColumnSelectorsToPredicate(selectors);
70
71
  // Filter based on spec, ignoring data type for now
71
72
  return this.columns.filter((column): column is PColumn<PColumnDataUniversal | undefined> =>
72
73
  predicate(column.spec),
@@ -125,7 +126,7 @@ type IntermediateDirectEntry = {
125
126
  // Union type for intermediate processing
126
127
  type IntermediateColumnEntry = IntermediateSplitEntry | IntermediateDirectEntry;
127
128
 
128
- function splitFiltersToTrace(splitFilters?: AxisFilterInfo[]): TraceEntry[] | undefined {
129
+ function splitFiltersToTrace(splitFilters?: AxisFilterInfo[]) {
129
130
  if (!splitFilters) return undefined;
130
131
  return splitFilters.map((filter) => ({
131
132
  type: `split:${canonicalizeAxisId(filter.axisId)}`,
@@ -300,8 +301,10 @@ export class PColumnCollection {
300
301
  throw new Error(
301
302
  "Anchored selectors in exclude require an AnchoredIdDeriver to be provided in options.",
302
303
  );
303
- return selectorsToPredicate(resolveAnchors(anchorCtx.anchors, selector, opts));
304
- } else return selectorsToPredicate(selector);
304
+ return legacyColumnSelectorsToPredicate(
305
+ resolveAnchors(anchorCtx.anchors, selector, opts),
306
+ );
307
+ } else return legacyColumnSelectorsToPredicate(selector);
305
308
  });
306
309
  excludePredicate = (spec) => excludePredicartes.some((predicate) => predicate(spec));
307
310
  }
@@ -1,6 +1,6 @@
1
1
  import { Annotation, PColumnSpec } from "@milaboratories/pl-model-common";
2
2
  import { expect, test } from "vitest";
3
- import { deriveLabels, Trace } from "./label";
3
+ import { deriveLabels, type Trace } from "./label";
4
4
 
5
5
  function tracesToSpecs(traces: Trace[]) {
6
6
  return traces.map(