@platforma-sdk/model 1.68.5 → 1.68.6

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 (52) hide show
  1. package/dist/columns/column_collection_builder.cjs +8 -2
  2. package/dist/columns/column_collection_builder.cjs.map +1 -1
  3. package/dist/columns/column_collection_builder.d.ts +14 -3
  4. package/dist/columns/column_collection_builder.d.ts.map +1 -1
  5. package/dist/columns/column_collection_builder.js +8 -2
  6. package/dist/columns/column_collection_builder.js.map +1 -1
  7. package/dist/columns/ctx_column_sources.d.ts +1 -1
  8. package/dist/columns/index.d.ts +1 -1
  9. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs +48 -49
  10. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs.map +1 -1
  11. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.d.ts +5 -10
  12. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.d.ts.map +1 -1
  13. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js +48 -49
  14. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js.map +1 -1
  15. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.cjs +16 -17
  16. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.cjs.map +1 -1
  17. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.d.ts +4 -4
  18. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.d.ts.map +1 -1
  19. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.js +16 -17
  20. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.js.map +1 -1
  21. package/dist/components/PlDataTable/createPlDataTable/utils.cjs +8 -2
  22. package/dist/components/PlDataTable/createPlDataTable/utils.cjs.map +1 -1
  23. package/dist/components/PlDataTable/createPlDataTable/utils.js +8 -2
  24. package/dist/components/PlDataTable/createPlDataTable/utils.js.map +1 -1
  25. package/dist/components/PlDatasetSelector/filter_discovery.d.ts +1 -1
  26. package/dist/index.d.ts +6 -6
  27. package/dist/labels/derive_distinct_labels.cjs +121 -50
  28. package/dist/labels/derive_distinct_labels.cjs.map +1 -1
  29. package/dist/labels/derive_distinct_labels.d.ts +30 -14
  30. package/dist/labels/derive_distinct_labels.d.ts.map +1 -1
  31. package/dist/labels/derive_distinct_labels.js +121 -50
  32. package/dist/labels/derive_distinct_labels.js.map +1 -1
  33. package/dist/labels/derive_distinct_tooltips.cjs +0 -10
  34. package/dist/labels/derive_distinct_tooltips.cjs.map +1 -1
  35. package/dist/labels/derive_distinct_tooltips.d.ts +2 -3
  36. package/dist/labels/derive_distinct_tooltips.d.ts.map +1 -1
  37. package/dist/labels/derive_distinct_tooltips.js +0 -10
  38. package/dist/labels/derive_distinct_tooltips.js.map +1 -1
  39. package/dist/labels/index.d.ts +1 -1
  40. package/dist/package.cjs +1 -1
  41. package/dist/package.js +1 -1
  42. package/package.json +5 -5
  43. package/src/columns/column_collection_builder.test.ts +0 -2
  44. package/src/columns/column_collection_builder.ts +26 -3
  45. package/src/components/PlDataTable/createPlDataTable/createPlDataTableV3.ts +85 -75
  46. package/src/components/PlDataTable/createPlDataTable/discoverColumns.ts +31 -34
  47. package/src/components/PlDataTable/createPlDataTable/utils.test.ts +1 -1
  48. package/src/components/PlDataTable/createPlDataTable/utils.ts +11 -4
  49. package/src/labels/derive_distinct_labels.test.ts +396 -52
  50. package/src/labels/derive_distinct_labels.ts +205 -103
  51. package/src/labels/derive_distinct_tooltips.test.ts +1 -22
  52. package/src/labels/derive_distinct_tooltips.ts +1 -18
@@ -117,8 +117,7 @@ var AnchoredColumnCollectionImpl = class {
117
117
  });
118
118
  const variants = hit.mappingVariants.map((v) => ({
119
119
  path,
120
- qualifications: remapFromIdxToId(v.qualifications, anchors),
121
- distinctiveQualifications: remapFromIdxToId(v.distinctiveQualifications, anchors)
120
+ qualifications: remapFromIdxToId(v.qualifications, anchors)
122
121
  }));
123
122
  const existing = acc.get(origId);
124
123
  return acc.set(origId, existing === void 0 ? {
@@ -131,6 +130,13 @@ var AnchoredColumnCollectionImpl = class {
131
130
  }, /* @__PURE__ */ new Map());
132
131
  return Array.from(byColumn.values());
133
132
  }
133
+ findColumnVariants(options) {
134
+ return this.findColumns(options).flatMap((match) => match.variants.map((variant) => ({
135
+ column: match.column,
136
+ path: variant.path,
137
+ qualifications: variant.qualifications
138
+ })));
139
+ }
134
140
  };
135
141
  /**
136
142
  * Collect all columns from all providers, dedup by NativePObjectId.
@@ -1 +1 @@
1
- {"version":3,"file":"column_collection_builder.cjs","names":["getService","TreeNodeAccessor","ArrayColumnProvider","toColumnSnapshotProvider","convertColumnSelectorToMultiColumnSelector"],"sources":["../../src/columns/column_collection_builder.ts"],"sourcesContent":["import type {\n AxisQualification,\n DiscoverColumnsConstraints,\n DiscoverColumnsRequest,\n DiscoverColumnsResponse,\n MultiColumnSelector,\n NativePObjectId,\n PColumnSpec,\n PObjectId,\n} from \"@milaboratories/pl-model-common\";\nimport { deriveNativeId, isPColumnSpec } from \"@milaboratories/pl-model-common\";\nimport type { ColumnSelector, RelaxedColumnSelector } from \"./column_selector\";\nimport { convertColumnSelectorToMultiColumnSelector } from \"./column_selector\";\nimport { TreeNodeAccessor } from \"../render/accessor\";\nimport type { ColumnSnapshot } from \"./column_snapshot\";\nimport type { ColumnSnapshotProvider, ColumnSource } from \"./column_snapshot_provider\";\nimport { ArrayColumnProvider, toColumnSnapshotProvider } from \"./column_snapshot_provider\";\n\nimport type { PFrameSpecDriver, PoolEntry, SpecFrameHandle } from \"@milaboratories/pl-model-common\";\nimport { throwError } from \"@milaboratories/helpers\";\nimport { getService } from \"../services\";\n\n// --- FindColumnsOptions ---\n\n/** Options for plain collection findColumns. */\nexport interface FindColumnsOptions {\n /** Include columns matching these selectors. If omitted, includes all columns. */\n include?: ColumnSelector;\n /** Exclude columns matching these selectors. */\n exclude?: ColumnSelector;\n}\n\n// --- ColumnCollection ---\n\n/** Plain collection — no axis context, selector-based filtering only. */\nexport interface ColumnCollection extends Disposable {\n /** Release the underlying spec frame WASM resource. */\n dispose(): void;\n\n /** Find columns matching selectors. Returns flat list of snapshots.\n * No axis compatibility matching, no linker traversal.\n * Never returns undefined — the \"not ready\" state was absorbed by the builder. */\n findColumns(options?: FindColumnsOptions): ColumnSnapshot<PObjectId>[];\n}\n\n// --- AnchoredColumnCollection ---\n\n/** Axis-aware column collection with anchored identity derivation. */\nexport interface AnchoredColumnCollection extends Disposable {\n /** Release the underlying spec frame WASM resource. */\n dispose(): void;\n\n /** List of anchors used for discovery, with their resolved specs. */\n getAnchors(): Map<string, ColumnSnapshot<PObjectId>>;\n\n /** Axis-aware column discovery. */\n findColumns(options?: AnchoredFindColumnsOptions): ColumnMatch[];\n}\n\n/** Controls axis matching behavior for anchored discovery. */\nexport type MatchingMode = \"enrichment\" | \"related\" | \"exact\";\n\n/** Options for anchored collection findColumns. */\nexport interface AnchoredFindColumnsOptions extends FindColumnsOptions {\n /** Controls axis matching behavior. Default: 'enrichment'. */\n mode?: MatchingMode;\n /** Maximum linker hops for cross-domain discovery (0 = direct only, default: 4). */\n maxHops?: number;\n}\n\n/** Result of anchored discovery — column snapshot + routing info. */\nexport interface ColumnMatch {\n /** Column snapshot with anchored SUniversalPColumnId. */\n readonly column: ColumnSnapshot<PObjectId>;\n /** Match variants — different ways (paths/qualifications) to reach this column. */\n readonly variants: MatchVariant[];\n}\n\n/** A single mapping variant describing how a hit column can be integrated. */\nexport interface MatchVariant {\n /** Full qualifications needed for integration. */\n readonly qualifications: MatchQualifications;\n /** Distinctive (minimal) qualifications needed for integration. */\n readonly distinctiveQualifications: MatchQualifications;\n /** Linker steps traversed to reach this hit; empty for direct matches. */\n readonly path: {\n linker: ColumnSnapshot<PObjectId>;\n qualifications: AxisQualification[];\n }[];\n}\n\n/** Qualifications needed for both already-integrated anchor columns and the hit column. */\nexport interface MatchQualifications {\n /** Qualifications for already-integrated anchor columns */\n readonly forQueries: Record<PObjectId, AxisQualification[]>;\n /** Qualifications for the hit column. */\n readonly forHit: AxisQualification[];\n}\n\n// --- Build options ---\n\nexport interface BuildOptions {\n allowPartialColumnList?: true;\n}\n\nexport type AnchorEntry = PObjectId | PColumnSpec | RelaxedColumnSelector;\n\nexport interface AnchoredBuildOptions extends BuildOptions {\n anchors: Record<string, AnchorEntry>;\n}\n\n// --- ColumnCollectionBuilder ---\n\n/**\n * Mutable builder that accumulates column sources, then produces\n * a ColumnCollection (plain) or AnchoredColumnCollection (with anchors).\n *\n * Each output lambda creates its own builder — a constraint of the\n * computable framework where each output tracks its own dependencies.\n */\nexport class ColumnCollectionBuilder {\n private readonly providers: ColumnSnapshotProvider[] = [];\n\n constructor(private readonly specDriver: PFrameSpecDriver = getService(\"pframeSpec\")) {}\n\n /**\n * Register a column source. Sources added first take precedence for dedup.\n * Does NOT accept undefined — if a source isn't available yet,\n * the caller should return undefined from the output lambda.\n */\n addSource(source: ColumnSource | TreeNodeAccessor): this {\n if (source instanceof TreeNodeAccessor) {\n const columns = source.getPColumns();\n if (columns) this.providers.push(new ArrayColumnProvider(columns));\n } else {\n this.providers.push(toColumnSnapshotProvider(source));\n }\n return this;\n }\n\n addSources(sources: (ColumnSource | TreeNodeAccessor)[]): this {\n for (const source of sources) {\n this.addSource(source);\n }\n return this;\n }\n\n /** Plain collection — selector-based filtering, PObjectId namespace. */\n build(): undefined | ColumnCollection;\n build(options: {\n allowPartialColumnList: true;\n }): ColumnCollection & { readonly columnListComplete: boolean };\n /** Anchored collection — axis-aware discovery, SUniversalPColumnId namespace. */\n build(\n options: AnchoredBuildOptions & { allowPartialColumnList: true },\n ): AnchoredColumnCollection & { readonly columnListComplete: boolean };\n build(options: AnchoredBuildOptions): undefined | AnchoredColumnCollection;\n build(\n options?: BuildOptions | AnchoredBuildOptions,\n ):\n | undefined\n | ColumnCollection\n | AnchoredColumnCollection\n | (ColumnCollection & { readonly columnListComplete: boolean })\n | (AnchoredColumnCollection & { readonly columnListComplete: boolean }) {\n const allowPartial = options?.allowPartialColumnList === true;\n\n // Check column list completeness\n const allComplete = this.providers.every((p) => p.isColumnListComplete());\n if (!allComplete && !allowPartial) return undefined;\n\n // Collect all columns, dedup by native ID (first source wins)\n const columns = collectColumns(this.providers);\n const hasAnchors = options !== undefined && \"anchors\" in options;\n\n if (hasAnchors) {\n return new AnchoredColumnCollectionImpl(this.specDriver, {\n anchors: options.anchors,\n columns,\n });\n } else {\n return new ColumnCollectionImpl(this.specDriver, {\n columns,\n });\n }\n }\n}\n\n// --- ColumnCollectionImpl ---\n\ninterface ColumnCollectionImplOptions {\n readonly columns: ColumnSnapshot<PObjectId>[];\n}\n\nclass ColumnCollectionImpl implements ColumnCollection, Disposable {\n private readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly specFrameEntry: PoolEntry<SpecFrameHandle>;\n\n constructor(\n private readonly specDriver: PFrameSpecDriver,\n options: ColumnCollectionImplOptions,\n ) {\n this.columns = new Map(options.columns.map((col) => [col.id, col]));\n this.specFrameEntry = this.specDriver.createSpecFrame(\n Object.fromEntries(options.columns.map((col) => [col.id, col.spec])),\n );\n }\n\n dispose(): void {\n this.specFrameEntry.unref();\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n findColumns(options?: FindColumnsOptions): ColumnSnapshot<PObjectId>[] {\n const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : undefined;\n const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : undefined;\n\n const response = this.specDriver.discoverColumns(this.specFrameEntry.key, {\n includeColumns,\n excludeColumns,\n axes: [],\n maxHops: 0,\n constraints: matchingModeToConstraints(\"enrichment\"),\n });\n\n // Map hits back to snapshots\n const results = response.hits\n .map((hit) => this.columns.get(hit.hit.columnId as PObjectId))\n .filter((col): col is ColumnSnapshot<PObjectId> => col !== undefined);\n\n return results;\n }\n}\n\n// --- AnchoredColumnCollectionImpl ---\n\ninterface AnchoredColumnCollectionImplOptions extends ColumnCollectionImplOptions {\n readonly anchors: Record<string, AnchorEntry>;\n}\n\nclass AnchoredColumnCollectionImpl implements AnchoredColumnCollection, Disposable {\n private readonly anchorsMap: Map<string, ColumnSnapshot<PObjectId>>;\n private readonly columnsMap: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly specFrameEntry: PoolEntry<SpecFrameHandle>;\n\n constructor(\n private readonly specDriver: PFrameSpecDriver,\n options: AnchoredColumnCollectionImplOptions,\n ) {\n // Create spec frame from all collected columns\n this.specFrameEntry = this.specDriver.createSpecFrame(\n Object.fromEntries(options.columns.map((col) => [col.id, col.spec])),\n );\n this.columnsMap = new Map(options.columns.map((col) => [col.id, col]));\n this.anchorsMap = resolveAnchorMap(\n options.anchors,\n options.columns,\n this.specDriver.discoverColumns.bind(this.specDriver, this.specFrameEntry.key),\n );\n }\n\n dispose(): void {\n this.specFrameEntry.unref();\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n getAnchors(): Map<string, ColumnSnapshot<PObjectId>> {\n return this.anchorsMap;\n }\n\n findColumns(options?: AnchoredFindColumnsOptions): ColumnMatch[] {\n const mode = options?.mode ?? \"enrichment\";\n const constraints = matchingModeToConstraints(mode);\n const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : undefined;\n const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : undefined;\n const anchors = Array.from(this.anchorsMap.values());\n const response = this.specDriver.discoverColumns(this.specFrameEntry.key, {\n includeColumns,\n excludeColumns,\n constraints,\n maxHops: options?.maxHops ?? 4,\n axes: anchors.map((anchor) => ({\n axesSpec: anchor.spec.axesSpec,\n qualifications: [],\n })),\n });\n\n const byColumn = response.hits.reduce<Map<PObjectId, ColumnMatch>>((acc, hit) => {\n const origId = hit.hit.columnId as PObjectId;\n const col =\n this.columnsMap.get(origId) ??\n throwError(`Column with id ${origId} not found in collection`);\n\n const path = hit.path.map((step) => {\n if (step.type !== \"linker\") {\n throw new Error(`Unexpected discover-columns step type: ${step.type}`);\n }\n\n return {\n linker:\n this.columnsMap.get(step.linker.columnId) ??\n throwError(`Linker column with id ${step.linker.columnId} not found in collection`),\n qualifications: step.qualifications,\n };\n });\n const variants: MatchVariant[] = hit.mappingVariants.map((v) => ({\n path,\n qualifications: remapFromIdxToId(v.qualifications, anchors),\n distinctiveQualifications: remapFromIdxToId(v.distinctiveQualifications, anchors),\n }));\n const existing = acc.get(origId);\n return acc.set(\n origId,\n existing === undefined\n ? { column: col, variants }\n : { ...existing, variants: [...existing.variants, ...variants] },\n );\n }, new Map());\n\n return Array.from(byColumn.values());\n }\n}\n\n/**\n * Collect all columns from all providers, dedup by NativePObjectId.\n * First source wins.\n */\nfunction collectColumns(providers: ColumnSnapshotProvider[]): ColumnSnapshot<PObjectId>[] {\n const seen = new Set<NativePObjectId>();\n const result: ColumnSnapshot<PObjectId>[] = [];\n\n for (const provider of providers) {\n const columns = provider.getAllColumns();\n for (const col of columns) {\n const nativeId = deriveNativeId(col.spec);\n if (seen.has(nativeId)) continue;\n seen.add(nativeId);\n result.push(col);\n }\n }\n\n return result;\n}\n\n// --- Shared snapshot helpers ---\n\n/** Normalize ColumnSelector (relaxed, single or array) to MultiColumnSelector[]. */\nfunction toMultiColumnSelectors(input: ColumnSelector): MultiColumnSelector[] {\n return convertColumnSelectorToMultiColumnSelector(input);\n}\n\n// --- Anchor resolution ---\n\n/**\n * Resolve each anchor entry to a ColumnSnapshot from the collected columns.\n * - PObjectId (string): looked up by id in the collected columns\n * - PColumnSpec: matched by deriveNativeId against collected columns\n * - RelaxedColumnSelector: resolved via discoverColumns in \"exact\" mode;\n * must match exactly one column\n * Throws on unresolved, ambiguous, or duplicated matches. Requires at least one\n * anchor to resolve.\n */\nfunction resolveAnchorMap(\n anchors: Record<string, AnchorEntry>,\n columns: ColumnSnapshot<PObjectId>[],\n discoverColumns: (request: DiscoverColumnsRequest) => DiscoverColumnsResponse,\n): Map<string, ColumnSnapshot<PObjectId>> {\n const result = new Map<string, ColumnSnapshot<PObjectId>>();\n const resovedIds = new Set<PObjectId>();\n const getDuplicateError = (key: string) =>\n `Anchor \"${key}\": selector matched a column that was already matched by another anchor; please refine the selector to match a different column`;\n\n for (const [name, anchor] of Object.entries(anchors)) {\n if (typeof anchor === \"string\") {\n const found =\n columns.find((col) => col.id === anchor) ??\n throwError(`Anchor \"${name}\": column with id \"${anchor}\" not found in sources`);\n if (resovedIds.has(found.id)) {\n throwError(getDuplicateError(name));\n }\n result.set(name, found);\n resovedIds.add(found.id);\n } else if (\"kind\" in anchor) {\n if (!isPColumnSpec(anchor)) throwError(`Anchor \"${name}\": invalid PColumnSpec`);\n const nativeId = deriveNativeId(anchor);\n const found =\n columns.find((col) => deriveNativeId(col.spec) === nativeId) ??\n throwError(`Anchor \"${name}\": no column matching spec found in sources`);\n if (resovedIds.has(found.id)) {\n throwError(getDuplicateError(name));\n }\n result.set(name, found);\n resovedIds.add(found.id);\n } else {\n const matched = discoverColumns({\n includeColumns: toMultiColumnSelectors(anchor),\n excludeColumns: undefined,\n axes: [],\n maxHops: 0,\n constraints: matchingModeToConstraints(\"exact\"),\n });\n\n if (matched.hits.length === 0) {\n throwError(`Anchor \"${name}\": no columns matched selector`);\n }\n if (matched.hits.length > 1) {\n throwError(\n `Anchor \"${name}\": selector is ambiguous and matched multiple columns; please refine the selector to match exactly one column`,\n );\n }\n if (resovedIds.has(matched.hits[0].hit.columnId as PObjectId)) {\n throwError(getDuplicateError(name));\n }\n\n const id = matched.hits[0].hit.columnId as PObjectId;\n const snap =\n columns.find((col) => col.id === id) ??\n throwError(`Anchor \"${name}\": matched column with id \"${id}\" not found in sources`);\n result.set(name, snap);\n resovedIds.add(snap.id);\n }\n }\n\n if (resovedIds.size === 0) {\n throwError(\"At least one anchor must be resolved to a valid column\");\n }\n\n return result;\n}\n\nfunction remapFromIdxToId(\n qualifications: {\n forQueries: AxisQualification[][];\n forHit: AxisQualification[];\n },\n anchors: ColumnSnapshot<PObjectId>[],\n): MatchQualifications {\n const forQueries = qualifications.forQueries.reduce<Record<PObjectId, AxisQualification[]>>(\n (acc, qs, i) => (anchors[i] ? ((acc[anchors[i].id] = qs), acc) : acc),\n {},\n );\n return { forQueries, forHit: qualifications.forHit };\n}\n\n// --- MatchingMode → DiscoverColumnsConstraints ---\n\nfunction matchingModeToConstraints(mode: MatchingMode): DiscoverColumnsConstraints {\n switch (mode) {\n case \"enrichment\":\n return {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: false,\n allowSourceQualifications: true,\n allowHitQualifications: true,\n };\n case \"related\":\n return {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: true,\n allowSourceQualifications: true,\n allowHitQualifications: true,\n };\n case \"exact\":\n return {\n allowFloatingSourceAxes: false,\n allowFloatingHitAxes: false,\n allowSourceQualifications: false,\n allowHitQualifications: false,\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"column_collection_builder.cjs","names":["getService","TreeNodeAccessor","ArrayColumnProvider","toColumnSnapshotProvider","convertColumnSelectorToMultiColumnSelector"],"sources":["../../src/columns/column_collection_builder.ts"],"sourcesContent":["import type {\n AxisQualification,\n DiscoverColumnsConstraints,\n DiscoverColumnsRequest,\n DiscoverColumnsResponse,\n MultiColumnSelector,\n NativePObjectId,\n PColumnSpec,\n PObjectId,\n} from \"@milaboratories/pl-model-common\";\nimport { deriveNativeId, isPColumnSpec } from \"@milaboratories/pl-model-common\";\nimport type { ColumnSelector, RelaxedColumnSelector } from \"./column_selector\";\nimport { convertColumnSelectorToMultiColumnSelector } from \"./column_selector\";\nimport { TreeNodeAccessor } from \"../render/accessor\";\nimport type { ColumnSnapshot } from \"./column_snapshot\";\nimport type { ColumnSnapshotProvider, ColumnSource } from \"./column_snapshot_provider\";\nimport { ArrayColumnProvider, toColumnSnapshotProvider } from \"./column_snapshot_provider\";\n\nimport type { PFrameSpecDriver, PoolEntry, SpecFrameHandle } from \"@milaboratories/pl-model-common\";\nimport { throwError } from \"@milaboratories/helpers\";\nimport { getService } from \"../services\";\n\n// --- FindColumnsOptions ---\n\n/** Options for plain collection findColumns. */\nexport interface FindColumnsOptions {\n /** Include columns matching these selectors. If omitted, includes all columns. */\n include?: ColumnSelector;\n /** Exclude columns matching these selectors. */\n exclude?: ColumnSelector;\n}\n\n// --- ColumnCollection ---\n\n/** Plain collection — no axis context, selector-based filtering only. */\nexport interface ColumnCollection extends Disposable {\n /** Release the underlying spec frame WASM resource. */\n dispose(): void;\n\n /** Find columns matching selectors. Returns flat list of snapshots.\n * No axis compatibility matching, no linker traversal.\n * Never returns undefined — the \"not ready\" state was absorbed by the builder. */\n findColumns(options?: FindColumnsOptions): ColumnSnapshot<PObjectId>[];\n}\n\n// --- AnchoredColumnCollection ---\n\n/** Axis-aware column collection with anchored identity derivation. */\nexport interface AnchoredColumnCollection extends Disposable {\n /** Release the underlying spec frame WASM resource. */\n dispose(): void;\n\n /** List of anchors used for discovery, with their resolved specs. */\n getAnchors(): Map<string, ColumnSnapshot<PObjectId>>;\n\n /** Axis-aware column discovery. */\n findColumns(options?: AnchoredFindColumnsOptions): ColumnMatch[];\n\n /** Variant discovery with detailed mapping info for each hit. */\n findColumnVariants(options?: AnchoredFindColumnsOptions): ColumnVariant[];\n}\n\n/** Controls axis matching behavior for anchored discovery. */\nexport type MatchingMode = \"enrichment\" | \"related\" | \"exact\";\n\n/** Options for anchored collection findColumns. */\nexport interface AnchoredFindColumnsOptions extends FindColumnsOptions {\n /** Controls axis matching behavior. Default: 'enrichment'. */\n mode?: MatchingMode;\n /** Maximum linker hops for cross-domain discovery (0 = direct only, default: 4). */\n maxHops?: number;\n}\n\n/** Result of anchored discovery — column snapshot + routing info. */\nexport interface ColumnMatch {\n /** Column snapshot with anchored SUniversalPColumnId. */\n readonly column: ColumnSnapshot<PObjectId>;\n /** Match variants — different ways (paths/qualifications) to reach this column. */\n readonly variants: MatchVariant[];\n}\n\nexport interface ColumnVariant<Id extends PObjectId = PObjectId> {\n /** Column snapshot with anchored SUniversalPColumnId. */\n readonly column: ColumnSnapshot<Id>;\n /** Full qualifications needed for integration. */\n readonly qualifications: MatchQualifications;\n /** Linker steps traversed to reach this hit; empty for direct matches. */\n readonly path: {\n linker: ColumnSnapshot<PObjectId>;\n qualifications: AxisQualification[];\n }[];\n}\n\n/** A single mapping variant describing how a hit column can be integrated. */\nexport interface MatchVariant {\n /** Full qualifications needed for integration. */\n readonly qualifications: MatchQualifications;\n /** Linker steps traversed to reach this hit; empty for direct matches. */\n readonly path: {\n linker: ColumnSnapshot<PObjectId>;\n qualifications: AxisQualification[];\n }[];\n}\n\n/** Qualifications needed for both already-integrated anchor columns and the hit column. */\nexport interface MatchQualifications {\n /** Qualifications for already-integrated anchor columns */\n readonly forQueries: Record<PObjectId, AxisQualification[]>;\n /** Qualifications for the hit column. */\n readonly forHit: AxisQualification[];\n}\n\n// --- Build options ---\n\nexport interface BuildOptions {\n allowPartialColumnList?: true;\n}\n\nexport type AnchorEntry = PObjectId | PColumnSpec | RelaxedColumnSelector;\n\nexport interface AnchoredBuildOptions extends BuildOptions {\n anchors: Record<string, AnchorEntry>;\n}\n\n// --- ColumnCollectionBuilder ---\n\n/**\n * Mutable builder that accumulates column sources, then produces\n * a ColumnCollection (plain) or AnchoredColumnCollection (with anchors).\n *\n * Each output lambda creates its own builder — a constraint of the\n * computable framework where each output tracks its own dependencies.\n */\nexport class ColumnCollectionBuilder {\n private readonly providers: ColumnSnapshotProvider[] = [];\n\n constructor(private readonly specDriver: PFrameSpecDriver = getService(\"pframeSpec\")) {}\n\n /**\n * Register a column source. Sources added first take precedence for dedup.\n * Does NOT accept undefined — if a source isn't available yet,\n * the caller should return undefined from the output lambda.\n */\n addSource(source: ColumnSource | TreeNodeAccessor): this {\n if (source instanceof TreeNodeAccessor) {\n const columns = source.getPColumns();\n if (columns) this.providers.push(new ArrayColumnProvider(columns));\n } else {\n this.providers.push(toColumnSnapshotProvider(source));\n }\n return this;\n }\n\n addSources(sources: (ColumnSource | TreeNodeAccessor)[]): this {\n for (const source of sources) {\n this.addSource(source);\n }\n return this;\n }\n\n /** Plain collection — selector-based filtering, PObjectId namespace. */\n build(): undefined | ColumnCollection;\n build(options: {\n allowPartialColumnList: true;\n }): ColumnCollection & { readonly columnListComplete: boolean };\n /** Anchored collection — axis-aware discovery, SUniversalPColumnId namespace. */\n build(\n options: AnchoredBuildOptions & { allowPartialColumnList: true },\n ): AnchoredColumnCollection & { readonly columnListComplete: boolean };\n build(options: AnchoredBuildOptions): undefined | AnchoredColumnCollection;\n build(\n options?: BuildOptions | AnchoredBuildOptions,\n ):\n | undefined\n | ColumnCollection\n | AnchoredColumnCollection\n | (ColumnCollection & { readonly columnListComplete: boolean })\n | (AnchoredColumnCollection & { readonly columnListComplete: boolean }) {\n const allowPartial = options?.allowPartialColumnList === true;\n\n // Check column list completeness\n const allComplete = this.providers.every((p) => p.isColumnListComplete());\n if (!allComplete && !allowPartial) return undefined;\n\n // Collect all columns, dedup by native ID (first source wins)\n const columns = collectColumns(this.providers);\n const hasAnchors = options !== undefined && \"anchors\" in options;\n\n if (hasAnchors) {\n return new AnchoredColumnCollectionImpl(this.specDriver, {\n anchors: options.anchors,\n columns,\n });\n } else {\n return new ColumnCollectionImpl(this.specDriver, {\n columns,\n });\n }\n }\n}\n\n// --- ColumnCollectionImpl ---\n\ninterface ColumnCollectionImplOptions {\n readonly columns: ColumnSnapshot<PObjectId>[];\n}\n\nclass ColumnCollectionImpl implements ColumnCollection, Disposable {\n private readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly specFrameEntry: PoolEntry<SpecFrameHandle>;\n\n constructor(\n private readonly specDriver: PFrameSpecDriver,\n options: ColumnCollectionImplOptions,\n ) {\n this.columns = new Map(options.columns.map((col) => [col.id, col]));\n this.specFrameEntry = this.specDriver.createSpecFrame(\n Object.fromEntries(options.columns.map((col) => [col.id, col.spec])),\n );\n }\n\n dispose(): void {\n this.specFrameEntry.unref();\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n findColumns(options?: FindColumnsOptions): ColumnSnapshot<PObjectId>[] {\n const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : undefined;\n const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : undefined;\n\n const response = this.specDriver.discoverColumns(this.specFrameEntry.key, {\n includeColumns,\n excludeColumns,\n axes: [],\n maxHops: 0,\n constraints: matchingModeToConstraints(\"enrichment\"),\n });\n\n // Map hits back to snapshots\n const results = response.hits\n .map((hit) => this.columns.get(hit.hit.columnId as PObjectId))\n .filter((col): col is ColumnSnapshot<PObjectId> => col !== undefined);\n\n return results;\n }\n}\n\n// --- AnchoredColumnCollectionImpl ---\n\ninterface AnchoredColumnCollectionImplOptions extends ColumnCollectionImplOptions {\n readonly anchors: Record<string, AnchorEntry>;\n}\n\nclass AnchoredColumnCollectionImpl implements AnchoredColumnCollection, Disposable {\n private readonly anchorsMap: Map<string, ColumnSnapshot<PObjectId>>;\n private readonly columnsMap: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly specFrameEntry: PoolEntry<SpecFrameHandle>;\n\n constructor(\n private readonly specDriver: PFrameSpecDriver,\n options: AnchoredColumnCollectionImplOptions,\n ) {\n // Create spec frame from all collected columns\n this.specFrameEntry = this.specDriver.createSpecFrame(\n Object.fromEntries(options.columns.map((col) => [col.id, col.spec])),\n );\n this.columnsMap = new Map(options.columns.map((col) => [col.id, col]));\n this.anchorsMap = resolveAnchorMap(\n options.anchors,\n options.columns,\n this.specDriver.discoverColumns.bind(this.specDriver, this.specFrameEntry.key),\n );\n }\n\n dispose(): void {\n this.specFrameEntry.unref();\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n getAnchors(): Map<string, ColumnSnapshot<PObjectId>> {\n return this.anchorsMap;\n }\n\n findColumns(options?: AnchoredFindColumnsOptions): ColumnMatch[] {\n const mode = options?.mode ?? \"enrichment\";\n const constraints = matchingModeToConstraints(mode);\n const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : undefined;\n const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : undefined;\n const anchors = Array.from(this.anchorsMap.values());\n const response = this.specDriver.discoverColumns(this.specFrameEntry.key, {\n includeColumns,\n excludeColumns,\n constraints,\n maxHops: options?.maxHops ?? 4,\n axes: anchors.map((anchor) => ({\n axesSpec: anchor.spec.axesSpec,\n qualifications: [],\n })),\n });\n\n const byColumn = response.hits.reduce<Map<PObjectId, ColumnMatch>>((acc, hit) => {\n const origId = hit.hit.columnId as PObjectId;\n const col =\n this.columnsMap.get(origId) ??\n throwError(`Column with id ${origId} not found in collection`);\n\n const path = hit.path.map((step) => {\n if (step.type !== \"linker\") {\n throw new Error(`Unexpected discover-columns step type: ${step.type}`);\n }\n\n return {\n linker:\n this.columnsMap.get(step.linker.columnId) ??\n throwError(`Linker column with id ${step.linker.columnId} not found in collection`),\n qualifications: step.qualifications,\n };\n });\n const variants: MatchVariant[] = hit.mappingVariants.map((v) => ({\n path,\n qualifications: remapFromIdxToId(v.qualifications, anchors),\n }));\n const existing = acc.get(origId);\n return acc.set(\n origId,\n existing === undefined\n ? { column: col, variants }\n : { ...existing, variants: [...existing.variants, ...variants] },\n );\n }, new Map());\n\n return Array.from(byColumn.values());\n }\n\n findColumnVariants(options?: AnchoredFindColumnsOptions): ColumnVariant[] {\n const matches = this.findColumns(options);\n return matches.flatMap((match) =>\n match.variants.map((variant) => ({\n column: match.column,\n path: variant.path,\n qualifications: variant.qualifications,\n })),\n );\n }\n}\n\n/**\n * Collect all columns from all providers, dedup by NativePObjectId.\n * First source wins.\n */\nfunction collectColumns(providers: ColumnSnapshotProvider[]): ColumnSnapshot<PObjectId>[] {\n const seen = new Set<NativePObjectId>();\n const result: ColumnSnapshot<PObjectId>[] = [];\n\n for (const provider of providers) {\n const columns = provider.getAllColumns();\n for (const col of columns) {\n const nativeId = deriveNativeId(col.spec);\n if (seen.has(nativeId)) continue;\n seen.add(nativeId);\n result.push(col);\n }\n }\n\n return result;\n}\n\n// --- Shared snapshot helpers ---\n\n/** Normalize ColumnSelector (relaxed, single or array) to MultiColumnSelector[]. */\nfunction toMultiColumnSelectors(input: ColumnSelector): MultiColumnSelector[] {\n return convertColumnSelectorToMultiColumnSelector(input);\n}\n\n// --- Anchor resolution ---\n\n/**\n * Resolve each anchor entry to a ColumnSnapshot from the collected columns.\n * - PObjectId (string): looked up by id in the collected columns\n * - PColumnSpec: matched by deriveNativeId against collected columns\n * - RelaxedColumnSelector: resolved via discoverColumns in \"exact\" mode;\n * must match exactly one column\n * Throws on unresolved, ambiguous, or duplicated matches. Requires at least one\n * anchor to resolve.\n */\nfunction resolveAnchorMap(\n anchors: Record<string, AnchorEntry>,\n columns: ColumnSnapshot<PObjectId>[],\n discoverColumns: (request: DiscoverColumnsRequest) => DiscoverColumnsResponse,\n): Map<string, ColumnSnapshot<PObjectId>> {\n const result = new Map<string, ColumnSnapshot<PObjectId>>();\n const resovedIds = new Set<PObjectId>();\n const getDuplicateError = (key: string) =>\n `Anchor \"${key}\": selector matched a column that was already matched by another anchor; please refine the selector to match a different column`;\n\n for (const [name, anchor] of Object.entries(anchors)) {\n if (typeof anchor === \"string\") {\n const found =\n columns.find((col) => col.id === anchor) ??\n throwError(`Anchor \"${name}\": column with id \"${anchor}\" not found in sources`);\n if (resovedIds.has(found.id)) {\n throwError(getDuplicateError(name));\n }\n result.set(name, found);\n resovedIds.add(found.id);\n } else if (\"kind\" in anchor) {\n if (!isPColumnSpec(anchor)) throwError(`Anchor \"${name}\": invalid PColumnSpec`);\n const nativeId = deriveNativeId(anchor);\n const found =\n columns.find((col) => deriveNativeId(col.spec) === nativeId) ??\n throwError(`Anchor \"${name}\": no column matching spec found in sources`);\n if (resovedIds.has(found.id)) {\n throwError(getDuplicateError(name));\n }\n result.set(name, found);\n resovedIds.add(found.id);\n } else {\n const matched = discoverColumns({\n includeColumns: toMultiColumnSelectors(anchor),\n excludeColumns: undefined,\n axes: [],\n maxHops: 0,\n constraints: matchingModeToConstraints(\"exact\"),\n });\n\n if (matched.hits.length === 0) {\n throwError(`Anchor \"${name}\": no columns matched selector`);\n }\n if (matched.hits.length > 1) {\n throwError(\n `Anchor \"${name}\": selector is ambiguous and matched multiple columns; please refine the selector to match exactly one column`,\n );\n }\n if (resovedIds.has(matched.hits[0].hit.columnId as PObjectId)) {\n throwError(getDuplicateError(name));\n }\n\n const id = matched.hits[0].hit.columnId as PObjectId;\n const snap =\n columns.find((col) => col.id === id) ??\n throwError(`Anchor \"${name}\": matched column with id \"${id}\" not found in sources`);\n result.set(name, snap);\n resovedIds.add(snap.id);\n }\n }\n\n if (resovedIds.size === 0) {\n throwError(\"At least one anchor must be resolved to a valid column\");\n }\n\n return result;\n}\n\nfunction remapFromIdxToId(\n qualifications: {\n forQueries: AxisQualification[][];\n forHit: AxisQualification[];\n },\n anchors: ColumnSnapshot<PObjectId>[],\n): MatchQualifications {\n const forQueries = qualifications.forQueries.reduce<Record<PObjectId, AxisQualification[]>>(\n (acc, qs, i) => (anchors[i] ? ((acc[anchors[i].id] = qs), acc) : acc),\n {},\n );\n return { forQueries, forHit: qualifications.forHit };\n}\n\n// --- MatchingMode → DiscoverColumnsConstraints ---\n\nfunction matchingModeToConstraints(mode: MatchingMode): DiscoverColumnsConstraints {\n switch (mode) {\n case \"enrichment\":\n return {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: false,\n allowSourceQualifications: true,\n allowHitQualifications: true,\n };\n case \"related\":\n return {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: true,\n allowSourceQualifications: true,\n allowHitQualifications: true,\n };\n case \"exact\":\n return {\n allowFloatingSourceAxes: false,\n allowFloatingHitAxes: false,\n allowSourceQualifications: false,\n allowHitQualifications: false,\n };\n }\n}\n"],"mappings":"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"}
@@ -29,6 +29,8 @@ interface AnchoredColumnCollection extends Disposable {
29
29
  getAnchors(): Map<string, ColumnSnapshot<PObjectId>>;
30
30
  /** Axis-aware column discovery. */
31
31
  findColumns(options?: AnchoredFindColumnsOptions): ColumnMatch[];
32
+ /** Variant discovery with detailed mapping info for each hit. */
33
+ findColumnVariants(options?: AnchoredFindColumnsOptions): ColumnVariant[];
32
34
  }
33
35
  /** Controls axis matching behavior for anchored discovery. */
34
36
  type MatchingMode = "enrichment" | "related" | "exact";
@@ -46,12 +48,21 @@ interface ColumnMatch {
46
48
  /** Match variants — different ways (paths/qualifications) to reach this column. */
47
49
  readonly variants: MatchVariant[];
48
50
  }
51
+ interface ColumnVariant<Id extends PObjectId = PObjectId> {
52
+ /** Column snapshot with anchored SUniversalPColumnId. */
53
+ readonly column: ColumnSnapshot<Id>;
54
+ /** Full qualifications needed for integration. */
55
+ readonly qualifications: MatchQualifications;
56
+ /** Linker steps traversed to reach this hit; empty for direct matches. */
57
+ readonly path: {
58
+ linker: ColumnSnapshot<PObjectId>;
59
+ qualifications: AxisQualification[];
60
+ }[];
61
+ }
49
62
  /** A single mapping variant describing how a hit column can be integrated. */
50
63
  interface MatchVariant {
51
64
  /** Full qualifications needed for integration. */
52
65
  readonly qualifications: MatchQualifications;
53
- /** Distinctive (minimal) qualifications needed for integration. */
54
- readonly distinctiveQualifications: MatchQualifications;
55
66
  /** Linker steps traversed to reach this hit; empty for direct matches. */
56
67
  readonly path: {
57
68
  linker: ColumnSnapshot<PObjectId>;
@@ -106,5 +117,5 @@ declare class ColumnCollectionBuilder {
106
117
  build(options: AnchoredBuildOptions): undefined | AnchoredColumnCollection;
107
118
  }
108
119
  //#endregion
109
- export { AnchorEntry, AnchoredBuildOptions, AnchoredColumnCollection, AnchoredFindColumnsOptions, BuildOptions, ColumnCollection, ColumnCollectionBuilder, ColumnMatch, FindColumnsOptions, MatchQualifications, MatchVariant, MatchingMode };
120
+ export { AnchorEntry, AnchoredBuildOptions, AnchoredColumnCollection, AnchoredFindColumnsOptions, BuildOptions, ColumnCollection, ColumnCollectionBuilder, ColumnMatch, ColumnVariant, FindColumnsOptions, MatchQualifications, MatchVariant, MatchingMode };
110
121
  //# sourceMappingURL=column_collection_builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"column_collection_builder.d.ts","names":[],"sources":["../../src/columns/column_collection_builder.ts"],"mappings":";;;;;;;;UAyBiB,kBAAA;EAAkB;EAEjC,OAAA,GAAU,cAAA;EAEc;EAAxB,OAAA,GAAU,cAAA;AAAA;;UAMK,gBAAA,SAAyB,UAAA;EANhB;EAQxB,OAAA;EAFe;;;EAOf,WAAA,CAAY,OAAA,GAAU,kBAAA,GAAqB,cAAA,CAAe,SAAA;AAAA;;UAM3C,wBAAA,SAAiC,UAAA;EAbE;EAelD,OAAA;EAfwC;EAkBxC,UAAA,IAAc,GAAA,SAAY,cAAA,CAAe,SAAA;EAXzC;EAcA,WAAA,CAAY,OAAA,GAAU,0BAAA,GAA6B,WAAA;AAAA;;KAIzC,YAAA;;UAGK,0BAAA,SAAmC,kBAAA;EAfnC;EAiBf,IAAA,GAAO,YAAA;;EAEP,OAAA;AAAA;;UAIe,WAAA;EAfoC;EAAA,SAiB1C,MAAA,EAAQ,cAAA,CAAe,SAAA;EAzB0B;EAAA,SA2BjD,QAAA,EAAU,YAAA;AAAA;;UAIJ,YAAA;EA1BD;EAAA,SA4BL,cAAA,EAAgB,mBAAA;EA5BgB;EAAA,SA8BhC,yBAAA,EAA2B,mBAAA;EA3Bd;EAAA,SA6Bb,IAAA;IACP,MAAA,EAAQ,cAAA,CAAe,SAAA;IACvB,cAAA,EAAgB,iBAAA;EAAA;AAAA;;UAKH,mBAAA;EAhCO;EAAA,SAkCb,UAAA,EAAY,MAAA,CAAO,SAAA,EAAW,iBAAA;EA/BxB;EAAA,SAiCN,MAAA,EAAQ,iBAAA;AAAA;AAAA,UAKF,YAAA;EACf,sBAAA;AAAA;AAAA,KAGU,WAAA,GAAc,SAAA,GAAY,WAAA,GAAc,qBAAA;AAAA,UAEnC,oBAAA,SAA6B,YAAA;EAC5C,OAAA,EAAS,MAAA,SAAe,WAAA;AAAA;AArC1B;;;;;;;AAAA,cAiDa,uBAAA;EAAA,iBAGkB,UAAA;EAAA,iBAFZ,SAAA;cAEY,UAAA,GAAY,gBAAA;EAhDhC;;;;AAIX;EAmDE,SAAA,CAAU,MAAA,EAAQ,YAAA,GAAe,gBAAA;EAUjC,UAAA,CAAW,OAAA,GAAU,YAAA,GAAe,gBAAA;EA3DX;EAmEzB,KAAA,CAAA,eAAqB,gBAAA;EACrB,KAAA,CAAM,OAAA;IACJ,sBAAA;EAAA,IACE,gBAAA;IAAA,SAA8B,kBAAA;EAAA;EAtEzB;EAwET,KAAA,CACE,OAAA,EAAS,oBAAA;IAAyB,sBAAA;EAAA,IACjC,wBAAA;IAAA,SAAsC,kBAAA;EAAA;EACzC,KAAA,CAAM,OAAA,EAAS,oBAAA,eAAmC,wBAAA;AAAA"}
1
+ {"version":3,"file":"column_collection_builder.d.ts","names":[],"sources":["../../src/columns/column_collection_builder.ts"],"mappings":";;;;;;;;UAyBiB,kBAAA;EAAkB;EAEjC,OAAA,GAAU,cAAA;EAEc;EAAxB,OAAA,GAAU,cAAA;AAAA;;UAMK,gBAAA,SAAyB,UAAA;EANhB;EAQxB,OAAA;EAFe;;;EAOf,WAAA,CAAY,OAAA,GAAU,kBAAA,GAAqB,cAAA,CAAe,SAAA;AAAA;;UAM3C,wBAAA,SAAiC,UAAA;EAbE;EAelD,OAAA;EAfwC;EAkBxC,UAAA,IAAc,GAAA,SAAY,cAAA,CAAe,SAAA;EAXzC;EAcA,WAAA,CAAY,OAAA,GAAU,0BAAA,GAA6B,WAAA;EAdvC;EAiBZ,kBAAA,CAAmB,OAAA,GAAU,0BAAA,GAA6B,aAAA;AAAA;;KAIhD,YAAA;AAfZ;AAAA,UAkBiB,0BAAA,SAAmC,kBAAA;;EAElD,IAAA,GAAO,YAAA;EAfmB;EAiB1B,OAAA;AAAA;;UAIe,WAAA;EAf2C;EAAA,SAiBjD,MAAA,EAAQ,cAAA,CAAe,SAAA;EA5B0B;EAAA,SA8BjD,QAAA,EAAU,YAAA;AAAA;AAAA,UAGJ,aAAA,YAAyB,SAAA,GAAY,SAAA;EA5BpD;EAAA,SA8BS,MAAA,EAAQ,cAAA,CAAe,EAAA;EA9BN;EAAA,SAgCjB,cAAA,EAAgB,mBAAA;EA7BzB;EAAA,SA+BS,IAAA;IACP,MAAA,EAAQ,cAAA,CAAe,SAAA;IACvB,cAAA,EAAgB,iBAAA;EAAA;AAAA;;UAKH,YAAA;EAnCwD;EAAA,SAqC9D,cAAA,EAAgB,mBAAA;EAjCf;EAAA,SAmCD,IAAA;IACP,MAAA,EAAQ,cAAA,CAAe,SAAA;IACvB,cAAA,EAAgB,iBAAA;EAAA;AAAA;;UAKH,mBAAA;EAvCqD;EAAA,SAyC3D,UAAA,EAAY,MAAA,CAAO,SAAA,EAAW,iBAAA;EAvCvC;EAAA,SAyCS,MAAA,EAAQ,iBAAA;AAAA;AAAA,UAKF,YAAA;EACf,sBAAA;AAAA;AAAA,KAGU,WAAA,GAAc,SAAA,GAAY,WAAA,GAAc,qBAAA;AAAA,UAEnC,oBAAA,SAA6B,YAAA;EAC5C,OAAA,EAAS,MAAA,SAAe,WAAA;AAAA;;;;;;;;cAYb,uBAAA;EAAA,iBAGkB,UAAA;EAAA,iBAFZ,SAAA;cAEY,UAAA,GAAY,gBAAA;EAvDb;;;;;EA8D5B,SAAA,CAAU,MAAA,EAAQ,YAAA,GAAe,gBAAA;EAUjC,UAAA,CAAW,OAAA,GAAU,YAAA,GAAe,gBAAA;EAjEX;EAyEzB,KAAA,CAAA,eAAqB,gBAAA;EACrB,KAAA,CAAM,OAAA;IACJ,sBAAA;EAAA,IACE,gBAAA;IAAA,SAA8B,kBAAA;EAAA;EAnFkB;EAqFpD,KAAA,CACE,OAAA,EAAS,oBAAA;IAAyB,sBAAA;EAAA,IACjC,wBAAA;IAAA,SAAsC,kBAAA;EAAA;EACzC,KAAA,CAAM,OAAA,EAAS,oBAAA,eAAmC,wBAAA;AAAA"}
@@ -116,8 +116,7 @@ var AnchoredColumnCollectionImpl = class {
116
116
  });
117
117
  const variants = hit.mappingVariants.map((v) => ({
118
118
  path,
119
- qualifications: remapFromIdxToId(v.qualifications, anchors),
120
- distinctiveQualifications: remapFromIdxToId(v.distinctiveQualifications, anchors)
119
+ qualifications: remapFromIdxToId(v.qualifications, anchors)
121
120
  }));
122
121
  const existing = acc.get(origId);
123
122
  return acc.set(origId, existing === void 0 ? {
@@ -130,6 +129,13 @@ var AnchoredColumnCollectionImpl = class {
130
129
  }, /* @__PURE__ */ new Map());
131
130
  return Array.from(byColumn.values());
132
131
  }
132
+ findColumnVariants(options) {
133
+ return this.findColumns(options).flatMap((match) => match.variants.map((variant) => ({
134
+ column: match.column,
135
+ path: variant.path,
136
+ qualifications: variant.qualifications
137
+ })));
138
+ }
133
139
  };
134
140
  /**
135
141
  * Collect all columns from all providers, dedup by NativePObjectId.
@@ -1 +1 @@
1
- {"version":3,"file":"column_collection_builder.js","names":[],"sources":["../../src/columns/column_collection_builder.ts"],"sourcesContent":["import type {\n AxisQualification,\n DiscoverColumnsConstraints,\n DiscoverColumnsRequest,\n DiscoverColumnsResponse,\n MultiColumnSelector,\n NativePObjectId,\n PColumnSpec,\n PObjectId,\n} from \"@milaboratories/pl-model-common\";\nimport { deriveNativeId, isPColumnSpec } from \"@milaboratories/pl-model-common\";\nimport type { ColumnSelector, RelaxedColumnSelector } from \"./column_selector\";\nimport { convertColumnSelectorToMultiColumnSelector } from \"./column_selector\";\nimport { TreeNodeAccessor } from \"../render/accessor\";\nimport type { ColumnSnapshot } from \"./column_snapshot\";\nimport type { ColumnSnapshotProvider, ColumnSource } from \"./column_snapshot_provider\";\nimport { ArrayColumnProvider, toColumnSnapshotProvider } from \"./column_snapshot_provider\";\n\nimport type { PFrameSpecDriver, PoolEntry, SpecFrameHandle } from \"@milaboratories/pl-model-common\";\nimport { throwError } from \"@milaboratories/helpers\";\nimport { getService } from \"../services\";\n\n// --- FindColumnsOptions ---\n\n/** Options for plain collection findColumns. */\nexport interface FindColumnsOptions {\n /** Include columns matching these selectors. If omitted, includes all columns. */\n include?: ColumnSelector;\n /** Exclude columns matching these selectors. */\n exclude?: ColumnSelector;\n}\n\n// --- ColumnCollection ---\n\n/** Plain collection — no axis context, selector-based filtering only. */\nexport interface ColumnCollection extends Disposable {\n /** Release the underlying spec frame WASM resource. */\n dispose(): void;\n\n /** Find columns matching selectors. Returns flat list of snapshots.\n * No axis compatibility matching, no linker traversal.\n * Never returns undefined — the \"not ready\" state was absorbed by the builder. */\n findColumns(options?: FindColumnsOptions): ColumnSnapshot<PObjectId>[];\n}\n\n// --- AnchoredColumnCollection ---\n\n/** Axis-aware column collection with anchored identity derivation. */\nexport interface AnchoredColumnCollection extends Disposable {\n /** Release the underlying spec frame WASM resource. */\n dispose(): void;\n\n /** List of anchors used for discovery, with their resolved specs. */\n getAnchors(): Map<string, ColumnSnapshot<PObjectId>>;\n\n /** Axis-aware column discovery. */\n findColumns(options?: AnchoredFindColumnsOptions): ColumnMatch[];\n}\n\n/** Controls axis matching behavior for anchored discovery. */\nexport type MatchingMode = \"enrichment\" | \"related\" | \"exact\";\n\n/** Options for anchored collection findColumns. */\nexport interface AnchoredFindColumnsOptions extends FindColumnsOptions {\n /** Controls axis matching behavior. Default: 'enrichment'. */\n mode?: MatchingMode;\n /** Maximum linker hops for cross-domain discovery (0 = direct only, default: 4). */\n maxHops?: number;\n}\n\n/** Result of anchored discovery — column snapshot + routing info. */\nexport interface ColumnMatch {\n /** Column snapshot with anchored SUniversalPColumnId. */\n readonly column: ColumnSnapshot<PObjectId>;\n /** Match variants — different ways (paths/qualifications) to reach this column. */\n readonly variants: MatchVariant[];\n}\n\n/** A single mapping variant describing how a hit column can be integrated. */\nexport interface MatchVariant {\n /** Full qualifications needed for integration. */\n readonly qualifications: MatchQualifications;\n /** Distinctive (minimal) qualifications needed for integration. */\n readonly distinctiveQualifications: MatchQualifications;\n /** Linker steps traversed to reach this hit; empty for direct matches. */\n readonly path: {\n linker: ColumnSnapshot<PObjectId>;\n qualifications: AxisQualification[];\n }[];\n}\n\n/** Qualifications needed for both already-integrated anchor columns and the hit column. */\nexport interface MatchQualifications {\n /** Qualifications for already-integrated anchor columns */\n readonly forQueries: Record<PObjectId, AxisQualification[]>;\n /** Qualifications for the hit column. */\n readonly forHit: AxisQualification[];\n}\n\n// --- Build options ---\n\nexport interface BuildOptions {\n allowPartialColumnList?: true;\n}\n\nexport type AnchorEntry = PObjectId | PColumnSpec | RelaxedColumnSelector;\n\nexport interface AnchoredBuildOptions extends BuildOptions {\n anchors: Record<string, AnchorEntry>;\n}\n\n// --- ColumnCollectionBuilder ---\n\n/**\n * Mutable builder that accumulates column sources, then produces\n * a ColumnCollection (plain) or AnchoredColumnCollection (with anchors).\n *\n * Each output lambda creates its own builder — a constraint of the\n * computable framework where each output tracks its own dependencies.\n */\nexport class ColumnCollectionBuilder {\n private readonly providers: ColumnSnapshotProvider[] = [];\n\n constructor(private readonly specDriver: PFrameSpecDriver = getService(\"pframeSpec\")) {}\n\n /**\n * Register a column source. Sources added first take precedence for dedup.\n * Does NOT accept undefined — if a source isn't available yet,\n * the caller should return undefined from the output lambda.\n */\n addSource(source: ColumnSource | TreeNodeAccessor): this {\n if (source instanceof TreeNodeAccessor) {\n const columns = source.getPColumns();\n if (columns) this.providers.push(new ArrayColumnProvider(columns));\n } else {\n this.providers.push(toColumnSnapshotProvider(source));\n }\n return this;\n }\n\n addSources(sources: (ColumnSource | TreeNodeAccessor)[]): this {\n for (const source of sources) {\n this.addSource(source);\n }\n return this;\n }\n\n /** Plain collection — selector-based filtering, PObjectId namespace. */\n build(): undefined | ColumnCollection;\n build(options: {\n allowPartialColumnList: true;\n }): ColumnCollection & { readonly columnListComplete: boolean };\n /** Anchored collection — axis-aware discovery, SUniversalPColumnId namespace. */\n build(\n options: AnchoredBuildOptions & { allowPartialColumnList: true },\n ): AnchoredColumnCollection & { readonly columnListComplete: boolean };\n build(options: AnchoredBuildOptions): undefined | AnchoredColumnCollection;\n build(\n options?: BuildOptions | AnchoredBuildOptions,\n ):\n | undefined\n | ColumnCollection\n | AnchoredColumnCollection\n | (ColumnCollection & { readonly columnListComplete: boolean })\n | (AnchoredColumnCollection & { readonly columnListComplete: boolean }) {\n const allowPartial = options?.allowPartialColumnList === true;\n\n // Check column list completeness\n const allComplete = this.providers.every((p) => p.isColumnListComplete());\n if (!allComplete && !allowPartial) return undefined;\n\n // Collect all columns, dedup by native ID (first source wins)\n const columns = collectColumns(this.providers);\n const hasAnchors = options !== undefined && \"anchors\" in options;\n\n if (hasAnchors) {\n return new AnchoredColumnCollectionImpl(this.specDriver, {\n anchors: options.anchors,\n columns,\n });\n } else {\n return new ColumnCollectionImpl(this.specDriver, {\n columns,\n });\n }\n }\n}\n\n// --- ColumnCollectionImpl ---\n\ninterface ColumnCollectionImplOptions {\n readonly columns: ColumnSnapshot<PObjectId>[];\n}\n\nclass ColumnCollectionImpl implements ColumnCollection, Disposable {\n private readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly specFrameEntry: PoolEntry<SpecFrameHandle>;\n\n constructor(\n private readonly specDriver: PFrameSpecDriver,\n options: ColumnCollectionImplOptions,\n ) {\n this.columns = new Map(options.columns.map((col) => [col.id, col]));\n this.specFrameEntry = this.specDriver.createSpecFrame(\n Object.fromEntries(options.columns.map((col) => [col.id, col.spec])),\n );\n }\n\n dispose(): void {\n this.specFrameEntry.unref();\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n findColumns(options?: FindColumnsOptions): ColumnSnapshot<PObjectId>[] {\n const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : undefined;\n const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : undefined;\n\n const response = this.specDriver.discoverColumns(this.specFrameEntry.key, {\n includeColumns,\n excludeColumns,\n axes: [],\n maxHops: 0,\n constraints: matchingModeToConstraints(\"enrichment\"),\n });\n\n // Map hits back to snapshots\n const results = response.hits\n .map((hit) => this.columns.get(hit.hit.columnId as PObjectId))\n .filter((col): col is ColumnSnapshot<PObjectId> => col !== undefined);\n\n return results;\n }\n}\n\n// --- AnchoredColumnCollectionImpl ---\n\ninterface AnchoredColumnCollectionImplOptions extends ColumnCollectionImplOptions {\n readonly anchors: Record<string, AnchorEntry>;\n}\n\nclass AnchoredColumnCollectionImpl implements AnchoredColumnCollection, Disposable {\n private readonly anchorsMap: Map<string, ColumnSnapshot<PObjectId>>;\n private readonly columnsMap: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly specFrameEntry: PoolEntry<SpecFrameHandle>;\n\n constructor(\n private readonly specDriver: PFrameSpecDriver,\n options: AnchoredColumnCollectionImplOptions,\n ) {\n // Create spec frame from all collected columns\n this.specFrameEntry = this.specDriver.createSpecFrame(\n Object.fromEntries(options.columns.map((col) => [col.id, col.spec])),\n );\n this.columnsMap = new Map(options.columns.map((col) => [col.id, col]));\n this.anchorsMap = resolveAnchorMap(\n options.anchors,\n options.columns,\n this.specDriver.discoverColumns.bind(this.specDriver, this.specFrameEntry.key),\n );\n }\n\n dispose(): void {\n this.specFrameEntry.unref();\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n getAnchors(): Map<string, ColumnSnapshot<PObjectId>> {\n return this.anchorsMap;\n }\n\n findColumns(options?: AnchoredFindColumnsOptions): ColumnMatch[] {\n const mode = options?.mode ?? \"enrichment\";\n const constraints = matchingModeToConstraints(mode);\n const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : undefined;\n const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : undefined;\n const anchors = Array.from(this.anchorsMap.values());\n const response = this.specDriver.discoverColumns(this.specFrameEntry.key, {\n includeColumns,\n excludeColumns,\n constraints,\n maxHops: options?.maxHops ?? 4,\n axes: anchors.map((anchor) => ({\n axesSpec: anchor.spec.axesSpec,\n qualifications: [],\n })),\n });\n\n const byColumn = response.hits.reduce<Map<PObjectId, ColumnMatch>>((acc, hit) => {\n const origId = hit.hit.columnId as PObjectId;\n const col =\n this.columnsMap.get(origId) ??\n throwError(`Column with id ${origId} not found in collection`);\n\n const path = hit.path.map((step) => {\n if (step.type !== \"linker\") {\n throw new Error(`Unexpected discover-columns step type: ${step.type}`);\n }\n\n return {\n linker:\n this.columnsMap.get(step.linker.columnId) ??\n throwError(`Linker column with id ${step.linker.columnId} not found in collection`),\n qualifications: step.qualifications,\n };\n });\n const variants: MatchVariant[] = hit.mappingVariants.map((v) => ({\n path,\n qualifications: remapFromIdxToId(v.qualifications, anchors),\n distinctiveQualifications: remapFromIdxToId(v.distinctiveQualifications, anchors),\n }));\n const existing = acc.get(origId);\n return acc.set(\n origId,\n existing === undefined\n ? { column: col, variants }\n : { ...existing, variants: [...existing.variants, ...variants] },\n );\n }, new Map());\n\n return Array.from(byColumn.values());\n }\n}\n\n/**\n * Collect all columns from all providers, dedup by NativePObjectId.\n * First source wins.\n */\nfunction collectColumns(providers: ColumnSnapshotProvider[]): ColumnSnapshot<PObjectId>[] {\n const seen = new Set<NativePObjectId>();\n const result: ColumnSnapshot<PObjectId>[] = [];\n\n for (const provider of providers) {\n const columns = provider.getAllColumns();\n for (const col of columns) {\n const nativeId = deriveNativeId(col.spec);\n if (seen.has(nativeId)) continue;\n seen.add(nativeId);\n result.push(col);\n }\n }\n\n return result;\n}\n\n// --- Shared snapshot helpers ---\n\n/** Normalize ColumnSelector (relaxed, single or array) to MultiColumnSelector[]. */\nfunction toMultiColumnSelectors(input: ColumnSelector): MultiColumnSelector[] {\n return convertColumnSelectorToMultiColumnSelector(input);\n}\n\n// --- Anchor resolution ---\n\n/**\n * Resolve each anchor entry to a ColumnSnapshot from the collected columns.\n * - PObjectId (string): looked up by id in the collected columns\n * - PColumnSpec: matched by deriveNativeId against collected columns\n * - RelaxedColumnSelector: resolved via discoverColumns in \"exact\" mode;\n * must match exactly one column\n * Throws on unresolved, ambiguous, or duplicated matches. Requires at least one\n * anchor to resolve.\n */\nfunction resolveAnchorMap(\n anchors: Record<string, AnchorEntry>,\n columns: ColumnSnapshot<PObjectId>[],\n discoverColumns: (request: DiscoverColumnsRequest) => DiscoverColumnsResponse,\n): Map<string, ColumnSnapshot<PObjectId>> {\n const result = new Map<string, ColumnSnapshot<PObjectId>>();\n const resovedIds = new Set<PObjectId>();\n const getDuplicateError = (key: string) =>\n `Anchor \"${key}\": selector matched a column that was already matched by another anchor; please refine the selector to match a different column`;\n\n for (const [name, anchor] of Object.entries(anchors)) {\n if (typeof anchor === \"string\") {\n const found =\n columns.find((col) => col.id === anchor) ??\n throwError(`Anchor \"${name}\": column with id \"${anchor}\" not found in sources`);\n if (resovedIds.has(found.id)) {\n throwError(getDuplicateError(name));\n }\n result.set(name, found);\n resovedIds.add(found.id);\n } else if (\"kind\" in anchor) {\n if (!isPColumnSpec(anchor)) throwError(`Anchor \"${name}\": invalid PColumnSpec`);\n const nativeId = deriveNativeId(anchor);\n const found =\n columns.find((col) => deriveNativeId(col.spec) === nativeId) ??\n throwError(`Anchor \"${name}\": no column matching spec found in sources`);\n if (resovedIds.has(found.id)) {\n throwError(getDuplicateError(name));\n }\n result.set(name, found);\n resovedIds.add(found.id);\n } else {\n const matched = discoverColumns({\n includeColumns: toMultiColumnSelectors(anchor),\n excludeColumns: undefined,\n axes: [],\n maxHops: 0,\n constraints: matchingModeToConstraints(\"exact\"),\n });\n\n if (matched.hits.length === 0) {\n throwError(`Anchor \"${name}\": no columns matched selector`);\n }\n if (matched.hits.length > 1) {\n throwError(\n `Anchor \"${name}\": selector is ambiguous and matched multiple columns; please refine the selector to match exactly one column`,\n );\n }\n if (resovedIds.has(matched.hits[0].hit.columnId as PObjectId)) {\n throwError(getDuplicateError(name));\n }\n\n const id = matched.hits[0].hit.columnId as PObjectId;\n const snap =\n columns.find((col) => col.id === id) ??\n throwError(`Anchor \"${name}\": matched column with id \"${id}\" not found in sources`);\n result.set(name, snap);\n resovedIds.add(snap.id);\n }\n }\n\n if (resovedIds.size === 0) {\n throwError(\"At least one anchor must be resolved to a valid column\");\n }\n\n return result;\n}\n\nfunction remapFromIdxToId(\n qualifications: {\n forQueries: AxisQualification[][];\n forHit: AxisQualification[];\n },\n anchors: ColumnSnapshot<PObjectId>[],\n): MatchQualifications {\n const forQueries = qualifications.forQueries.reduce<Record<PObjectId, AxisQualification[]>>(\n (acc, qs, i) => (anchors[i] ? ((acc[anchors[i].id] = qs), acc) : acc),\n {},\n );\n return { forQueries, forHit: qualifications.forHit };\n}\n\n// --- MatchingMode → DiscoverColumnsConstraints ---\n\nfunction matchingModeToConstraints(mode: MatchingMode): DiscoverColumnsConstraints {\n switch (mode) {\n case \"enrichment\":\n return {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: false,\n allowSourceQualifications: true,\n allowHitQualifications: true,\n };\n case \"related\":\n return {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: true,\n allowSourceQualifications: true,\n allowHitQualifications: true,\n };\n case \"exact\":\n return {\n allowFloatingSourceAxes: false,\n allowFloatingHitAxes: false,\n allowSourceQualifications: false,\n allowHitQualifications: false,\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"column_collection_builder.js","names":[],"sources":["../../src/columns/column_collection_builder.ts"],"sourcesContent":["import type {\n AxisQualification,\n DiscoverColumnsConstraints,\n DiscoverColumnsRequest,\n DiscoverColumnsResponse,\n MultiColumnSelector,\n NativePObjectId,\n PColumnSpec,\n PObjectId,\n} from \"@milaboratories/pl-model-common\";\nimport { deriveNativeId, isPColumnSpec } from \"@milaboratories/pl-model-common\";\nimport type { ColumnSelector, RelaxedColumnSelector } from \"./column_selector\";\nimport { convertColumnSelectorToMultiColumnSelector } from \"./column_selector\";\nimport { TreeNodeAccessor } from \"../render/accessor\";\nimport type { ColumnSnapshot } from \"./column_snapshot\";\nimport type { ColumnSnapshotProvider, ColumnSource } from \"./column_snapshot_provider\";\nimport { ArrayColumnProvider, toColumnSnapshotProvider } from \"./column_snapshot_provider\";\n\nimport type { PFrameSpecDriver, PoolEntry, SpecFrameHandle } from \"@milaboratories/pl-model-common\";\nimport { throwError } from \"@milaboratories/helpers\";\nimport { getService } from \"../services\";\n\n// --- FindColumnsOptions ---\n\n/** Options for plain collection findColumns. */\nexport interface FindColumnsOptions {\n /** Include columns matching these selectors. If omitted, includes all columns. */\n include?: ColumnSelector;\n /** Exclude columns matching these selectors. */\n exclude?: ColumnSelector;\n}\n\n// --- ColumnCollection ---\n\n/** Plain collection — no axis context, selector-based filtering only. */\nexport interface ColumnCollection extends Disposable {\n /** Release the underlying spec frame WASM resource. */\n dispose(): void;\n\n /** Find columns matching selectors. Returns flat list of snapshots.\n * No axis compatibility matching, no linker traversal.\n * Never returns undefined — the \"not ready\" state was absorbed by the builder. */\n findColumns(options?: FindColumnsOptions): ColumnSnapshot<PObjectId>[];\n}\n\n// --- AnchoredColumnCollection ---\n\n/** Axis-aware column collection with anchored identity derivation. */\nexport interface AnchoredColumnCollection extends Disposable {\n /** Release the underlying spec frame WASM resource. */\n dispose(): void;\n\n /** List of anchors used for discovery, with their resolved specs. */\n getAnchors(): Map<string, ColumnSnapshot<PObjectId>>;\n\n /** Axis-aware column discovery. */\n findColumns(options?: AnchoredFindColumnsOptions): ColumnMatch[];\n\n /** Variant discovery with detailed mapping info for each hit. */\n findColumnVariants(options?: AnchoredFindColumnsOptions): ColumnVariant[];\n}\n\n/** Controls axis matching behavior for anchored discovery. */\nexport type MatchingMode = \"enrichment\" | \"related\" | \"exact\";\n\n/** Options for anchored collection findColumns. */\nexport interface AnchoredFindColumnsOptions extends FindColumnsOptions {\n /** Controls axis matching behavior. Default: 'enrichment'. */\n mode?: MatchingMode;\n /** Maximum linker hops for cross-domain discovery (0 = direct only, default: 4). */\n maxHops?: number;\n}\n\n/** Result of anchored discovery — column snapshot + routing info. */\nexport interface ColumnMatch {\n /** Column snapshot with anchored SUniversalPColumnId. */\n readonly column: ColumnSnapshot<PObjectId>;\n /** Match variants — different ways (paths/qualifications) to reach this column. */\n readonly variants: MatchVariant[];\n}\n\nexport interface ColumnVariant<Id extends PObjectId = PObjectId> {\n /** Column snapshot with anchored SUniversalPColumnId. */\n readonly column: ColumnSnapshot<Id>;\n /** Full qualifications needed for integration. */\n readonly qualifications: MatchQualifications;\n /** Linker steps traversed to reach this hit; empty for direct matches. */\n readonly path: {\n linker: ColumnSnapshot<PObjectId>;\n qualifications: AxisQualification[];\n }[];\n}\n\n/** A single mapping variant describing how a hit column can be integrated. */\nexport interface MatchVariant {\n /** Full qualifications needed for integration. */\n readonly qualifications: MatchQualifications;\n /** Linker steps traversed to reach this hit; empty for direct matches. */\n readonly path: {\n linker: ColumnSnapshot<PObjectId>;\n qualifications: AxisQualification[];\n }[];\n}\n\n/** Qualifications needed for both already-integrated anchor columns and the hit column. */\nexport interface MatchQualifications {\n /** Qualifications for already-integrated anchor columns */\n readonly forQueries: Record<PObjectId, AxisQualification[]>;\n /** Qualifications for the hit column. */\n readonly forHit: AxisQualification[];\n}\n\n// --- Build options ---\n\nexport interface BuildOptions {\n allowPartialColumnList?: true;\n}\n\nexport type AnchorEntry = PObjectId | PColumnSpec | RelaxedColumnSelector;\n\nexport interface AnchoredBuildOptions extends BuildOptions {\n anchors: Record<string, AnchorEntry>;\n}\n\n// --- ColumnCollectionBuilder ---\n\n/**\n * Mutable builder that accumulates column sources, then produces\n * a ColumnCollection (plain) or AnchoredColumnCollection (with anchors).\n *\n * Each output lambda creates its own builder — a constraint of the\n * computable framework where each output tracks its own dependencies.\n */\nexport class ColumnCollectionBuilder {\n private readonly providers: ColumnSnapshotProvider[] = [];\n\n constructor(private readonly specDriver: PFrameSpecDriver = getService(\"pframeSpec\")) {}\n\n /**\n * Register a column source. Sources added first take precedence for dedup.\n * Does NOT accept undefined — if a source isn't available yet,\n * the caller should return undefined from the output lambda.\n */\n addSource(source: ColumnSource | TreeNodeAccessor): this {\n if (source instanceof TreeNodeAccessor) {\n const columns = source.getPColumns();\n if (columns) this.providers.push(new ArrayColumnProvider(columns));\n } else {\n this.providers.push(toColumnSnapshotProvider(source));\n }\n return this;\n }\n\n addSources(sources: (ColumnSource | TreeNodeAccessor)[]): this {\n for (const source of sources) {\n this.addSource(source);\n }\n return this;\n }\n\n /** Plain collection — selector-based filtering, PObjectId namespace. */\n build(): undefined | ColumnCollection;\n build(options: {\n allowPartialColumnList: true;\n }): ColumnCollection & { readonly columnListComplete: boolean };\n /** Anchored collection — axis-aware discovery, SUniversalPColumnId namespace. */\n build(\n options: AnchoredBuildOptions & { allowPartialColumnList: true },\n ): AnchoredColumnCollection & { readonly columnListComplete: boolean };\n build(options: AnchoredBuildOptions): undefined | AnchoredColumnCollection;\n build(\n options?: BuildOptions | AnchoredBuildOptions,\n ):\n | undefined\n | ColumnCollection\n | AnchoredColumnCollection\n | (ColumnCollection & { readonly columnListComplete: boolean })\n | (AnchoredColumnCollection & { readonly columnListComplete: boolean }) {\n const allowPartial = options?.allowPartialColumnList === true;\n\n // Check column list completeness\n const allComplete = this.providers.every((p) => p.isColumnListComplete());\n if (!allComplete && !allowPartial) return undefined;\n\n // Collect all columns, dedup by native ID (first source wins)\n const columns = collectColumns(this.providers);\n const hasAnchors = options !== undefined && \"anchors\" in options;\n\n if (hasAnchors) {\n return new AnchoredColumnCollectionImpl(this.specDriver, {\n anchors: options.anchors,\n columns,\n });\n } else {\n return new ColumnCollectionImpl(this.specDriver, {\n columns,\n });\n }\n }\n}\n\n// --- ColumnCollectionImpl ---\n\ninterface ColumnCollectionImplOptions {\n readonly columns: ColumnSnapshot<PObjectId>[];\n}\n\nclass ColumnCollectionImpl implements ColumnCollection, Disposable {\n private readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly specFrameEntry: PoolEntry<SpecFrameHandle>;\n\n constructor(\n private readonly specDriver: PFrameSpecDriver,\n options: ColumnCollectionImplOptions,\n ) {\n this.columns = new Map(options.columns.map((col) => [col.id, col]));\n this.specFrameEntry = this.specDriver.createSpecFrame(\n Object.fromEntries(options.columns.map((col) => [col.id, col.spec])),\n );\n }\n\n dispose(): void {\n this.specFrameEntry.unref();\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n findColumns(options?: FindColumnsOptions): ColumnSnapshot<PObjectId>[] {\n const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : undefined;\n const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : undefined;\n\n const response = this.specDriver.discoverColumns(this.specFrameEntry.key, {\n includeColumns,\n excludeColumns,\n axes: [],\n maxHops: 0,\n constraints: matchingModeToConstraints(\"enrichment\"),\n });\n\n // Map hits back to snapshots\n const results = response.hits\n .map((hit) => this.columns.get(hit.hit.columnId as PObjectId))\n .filter((col): col is ColumnSnapshot<PObjectId> => col !== undefined);\n\n return results;\n }\n}\n\n// --- AnchoredColumnCollectionImpl ---\n\ninterface AnchoredColumnCollectionImplOptions extends ColumnCollectionImplOptions {\n readonly anchors: Record<string, AnchorEntry>;\n}\n\nclass AnchoredColumnCollectionImpl implements AnchoredColumnCollection, Disposable {\n private readonly anchorsMap: Map<string, ColumnSnapshot<PObjectId>>;\n private readonly columnsMap: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly specFrameEntry: PoolEntry<SpecFrameHandle>;\n\n constructor(\n private readonly specDriver: PFrameSpecDriver,\n options: AnchoredColumnCollectionImplOptions,\n ) {\n // Create spec frame from all collected columns\n this.specFrameEntry = this.specDriver.createSpecFrame(\n Object.fromEntries(options.columns.map((col) => [col.id, col.spec])),\n );\n this.columnsMap = new Map(options.columns.map((col) => [col.id, col]));\n this.anchorsMap = resolveAnchorMap(\n options.anchors,\n options.columns,\n this.specDriver.discoverColumns.bind(this.specDriver, this.specFrameEntry.key),\n );\n }\n\n dispose(): void {\n this.specFrameEntry.unref();\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n getAnchors(): Map<string, ColumnSnapshot<PObjectId>> {\n return this.anchorsMap;\n }\n\n findColumns(options?: AnchoredFindColumnsOptions): ColumnMatch[] {\n const mode = options?.mode ?? \"enrichment\";\n const constraints = matchingModeToConstraints(mode);\n const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : undefined;\n const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : undefined;\n const anchors = Array.from(this.anchorsMap.values());\n const response = this.specDriver.discoverColumns(this.specFrameEntry.key, {\n includeColumns,\n excludeColumns,\n constraints,\n maxHops: options?.maxHops ?? 4,\n axes: anchors.map((anchor) => ({\n axesSpec: anchor.spec.axesSpec,\n qualifications: [],\n })),\n });\n\n const byColumn = response.hits.reduce<Map<PObjectId, ColumnMatch>>((acc, hit) => {\n const origId = hit.hit.columnId as PObjectId;\n const col =\n this.columnsMap.get(origId) ??\n throwError(`Column with id ${origId} not found in collection`);\n\n const path = hit.path.map((step) => {\n if (step.type !== \"linker\") {\n throw new Error(`Unexpected discover-columns step type: ${step.type}`);\n }\n\n return {\n linker:\n this.columnsMap.get(step.linker.columnId) ??\n throwError(`Linker column with id ${step.linker.columnId} not found in collection`),\n qualifications: step.qualifications,\n };\n });\n const variants: MatchVariant[] = hit.mappingVariants.map((v) => ({\n path,\n qualifications: remapFromIdxToId(v.qualifications, anchors),\n }));\n const existing = acc.get(origId);\n return acc.set(\n origId,\n existing === undefined\n ? { column: col, variants }\n : { ...existing, variants: [...existing.variants, ...variants] },\n );\n }, new Map());\n\n return Array.from(byColumn.values());\n }\n\n findColumnVariants(options?: AnchoredFindColumnsOptions): ColumnVariant[] {\n const matches = this.findColumns(options);\n return matches.flatMap((match) =>\n match.variants.map((variant) => ({\n column: match.column,\n path: variant.path,\n qualifications: variant.qualifications,\n })),\n );\n }\n}\n\n/**\n * Collect all columns from all providers, dedup by NativePObjectId.\n * First source wins.\n */\nfunction collectColumns(providers: ColumnSnapshotProvider[]): ColumnSnapshot<PObjectId>[] {\n const seen = new Set<NativePObjectId>();\n const result: ColumnSnapshot<PObjectId>[] = [];\n\n for (const provider of providers) {\n const columns = provider.getAllColumns();\n for (const col of columns) {\n const nativeId = deriveNativeId(col.spec);\n if (seen.has(nativeId)) continue;\n seen.add(nativeId);\n result.push(col);\n }\n }\n\n return result;\n}\n\n// --- Shared snapshot helpers ---\n\n/** Normalize ColumnSelector (relaxed, single or array) to MultiColumnSelector[]. */\nfunction toMultiColumnSelectors(input: ColumnSelector): MultiColumnSelector[] {\n return convertColumnSelectorToMultiColumnSelector(input);\n}\n\n// --- Anchor resolution ---\n\n/**\n * Resolve each anchor entry to a ColumnSnapshot from the collected columns.\n * - PObjectId (string): looked up by id in the collected columns\n * - PColumnSpec: matched by deriveNativeId against collected columns\n * - RelaxedColumnSelector: resolved via discoverColumns in \"exact\" mode;\n * must match exactly one column\n * Throws on unresolved, ambiguous, or duplicated matches. Requires at least one\n * anchor to resolve.\n */\nfunction resolveAnchorMap(\n anchors: Record<string, AnchorEntry>,\n columns: ColumnSnapshot<PObjectId>[],\n discoverColumns: (request: DiscoverColumnsRequest) => DiscoverColumnsResponse,\n): Map<string, ColumnSnapshot<PObjectId>> {\n const result = new Map<string, ColumnSnapshot<PObjectId>>();\n const resovedIds = new Set<PObjectId>();\n const getDuplicateError = (key: string) =>\n `Anchor \"${key}\": selector matched a column that was already matched by another anchor; please refine the selector to match a different column`;\n\n for (const [name, anchor] of Object.entries(anchors)) {\n if (typeof anchor === \"string\") {\n const found =\n columns.find((col) => col.id === anchor) ??\n throwError(`Anchor \"${name}\": column with id \"${anchor}\" not found in sources`);\n if (resovedIds.has(found.id)) {\n throwError(getDuplicateError(name));\n }\n result.set(name, found);\n resovedIds.add(found.id);\n } else if (\"kind\" in anchor) {\n if (!isPColumnSpec(anchor)) throwError(`Anchor \"${name}\": invalid PColumnSpec`);\n const nativeId = deriveNativeId(anchor);\n const found =\n columns.find((col) => deriveNativeId(col.spec) === nativeId) ??\n throwError(`Anchor \"${name}\": no column matching spec found in sources`);\n if (resovedIds.has(found.id)) {\n throwError(getDuplicateError(name));\n }\n result.set(name, found);\n resovedIds.add(found.id);\n } else {\n const matched = discoverColumns({\n includeColumns: toMultiColumnSelectors(anchor),\n excludeColumns: undefined,\n axes: [],\n maxHops: 0,\n constraints: matchingModeToConstraints(\"exact\"),\n });\n\n if (matched.hits.length === 0) {\n throwError(`Anchor \"${name}\": no columns matched selector`);\n }\n if (matched.hits.length > 1) {\n throwError(\n `Anchor \"${name}\": selector is ambiguous and matched multiple columns; please refine the selector to match exactly one column`,\n );\n }\n if (resovedIds.has(matched.hits[0].hit.columnId as PObjectId)) {\n throwError(getDuplicateError(name));\n }\n\n const id = matched.hits[0].hit.columnId as PObjectId;\n const snap =\n columns.find((col) => col.id === id) ??\n throwError(`Anchor \"${name}\": matched column with id \"${id}\" not found in sources`);\n result.set(name, snap);\n resovedIds.add(snap.id);\n }\n }\n\n if (resovedIds.size === 0) {\n throwError(\"At least one anchor must be resolved to a valid column\");\n }\n\n return result;\n}\n\nfunction remapFromIdxToId(\n qualifications: {\n forQueries: AxisQualification[][];\n forHit: AxisQualification[];\n },\n anchors: ColumnSnapshot<PObjectId>[],\n): MatchQualifications {\n const forQueries = qualifications.forQueries.reduce<Record<PObjectId, AxisQualification[]>>(\n (acc, qs, i) => (anchors[i] ? ((acc[anchors[i].id] = qs), acc) : acc),\n {},\n );\n return { forQueries, forHit: qualifications.forHit };\n}\n\n// --- MatchingMode → DiscoverColumnsConstraints ---\n\nfunction matchingModeToConstraints(mode: MatchingMode): DiscoverColumnsConstraints {\n switch (mode) {\n case \"enrichment\":\n return {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: false,\n allowSourceQualifications: true,\n allowHitQualifications: true,\n };\n case \"related\":\n return {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: true,\n allowSourceQualifications: true,\n allowHitQualifications: true,\n };\n case \"exact\":\n return {\n allowFloatingSourceAxes: false,\n allowFloatingHitAxes: false,\n allowSourceQualifications: false,\n allowHitQualifications: false,\n };\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { RenderCtxBase, ResultPool } from "../render/api.js";
2
1
  import { ColumnSnapshot } from "./column_snapshot.js";
3
2
  import { ColumnSnapshotProvider } from "./column_snapshot_provider.js";
3
+ import { RenderCtxBase, ResultPool } from "../render/api.js";
4
4
  import { PObjectId } from "@milaboratories/pl-model-common";
5
5
 
6
6
  //#region src/columns/ctx_column_sources.d.ts
@@ -1,6 +1,6 @@
1
1
  import { ColumnSelector, RelaxedAxisSelector, RelaxedColumnSelector, RelaxedRecord, RelaxedStringMatchers, StringMatcher, convertColumnSelectorToMultiColumnSelector, convertRelaxedAxisSelectorToMultiAxisSelector, convertRelaxedColumnSelectorToMultiColumnSelector } from "./column_selector.js";
2
2
  import { ColumnData, ColumnDataStatus, ColumnSnapshot, createColumnSnapshot, createReadyColumnData } from "./column_snapshot.js";
3
3
  import { ArrayColumnProvider, ColumnSnapshotProvider, ColumnSource, OutputColumnProvider, OutputColumnProviderOpts, SnapshotColumnProvider, isColumnSnapshotProvider, toColumnSnapshotProvider } from "./column_snapshot_provider.js";
4
- import { AnchorEntry, AnchoredBuildOptions, AnchoredColumnCollection, AnchoredFindColumnsOptions, BuildOptions, ColumnCollection, ColumnCollectionBuilder, ColumnMatch, FindColumnsOptions, MatchQualifications, MatchVariant, MatchingMode } from "./column_collection_builder.js";
4
+ import { AnchorEntry, AnchoredBuildOptions, AnchoredColumnCollection, AnchoredFindColumnsOptions, BuildOptions, ColumnCollection, ColumnCollectionBuilder, ColumnMatch, ColumnVariant, FindColumnsOptions, MatchQualifications, MatchVariant, MatchingMode } from "./column_collection_builder.js";
5
5
  import { ResultPoolColumnSnapshotProvider, collectCtxColumnSnapshotProviders } from "./ctx_column_sources.js";
6
6
  import { ExpandByPartitionOpts, ExpandByPartitionResult, SplitAxis, expandByPartition } from "./expand_by_partition.js";
@@ -16,12 +16,13 @@ function createPlDataTableV3(ctx, options) {
16
16
  const discovered = (0, _milaboratories_helpers.isPlainObject)(options.columns) ? require_discoverColumns.discoverTableColumnSnaphots(ctx, options.columns) : options.columns;
17
17
  if ((0, _milaboratories_helpers.isNil)(discovered) || discovered.length === 0) return void 0;
18
18
  const splited = splitDiscoveredColumns(discovered);
19
- const labelColumns = require_labels.getMatchingLabelColumns([...splited.direct, ...splited.linked], require_labels.getAllLabelColumns(ctx));
19
+ const labelColumns = require_labels.getMatchingLabelColumns([...splited.direct, ...splited.linked].map((v) => v.column), require_labels.getAllLabelColumns(ctx));
20
20
  const derivedLabels = require_utils.deriveAllLabels({
21
21
  columns: discovered.map((dc) => ({
22
- id: dc.id,
23
- spec: dc.spec,
24
- linkerPath: dc.linkerPath?.map((lp) => ({ spec: lp.linker.spec }))
22
+ id: dc.column.id,
23
+ spec: dc.column.spec,
24
+ linkerPath: dc.path,
25
+ qualifications: dc.qualifications
25
26
  })),
26
27
  labelColumns,
27
28
  deriveLabelsOptions: {
@@ -30,12 +31,11 @@ function createPlDataTableV3(ctx, options) {
30
31
  }
31
32
  });
32
33
  const derivedTooltips = require_utils.deriveAllTooltips({ columns: discovered.map((dc) => ({
33
- id: dc.id,
34
+ id: dc.column.id,
34
35
  originalId: dc.originalId,
35
- spec: dc.spec,
36
- linkerPath: dc.linkerPath,
37
- qualifications: dc.qualifications,
38
- distinctiveQualifications: dc.distinctiveQualifications
36
+ spec: dc.column.spec,
37
+ linkerPath: dc.path,
38
+ qualifications: dc.qualifications
39
39
  })) });
40
40
  const annotated = annotateColumnGroups({
41
41
  pframeSpec,
@@ -49,8 +49,8 @@ function createPlDataTableV3(ctx, options) {
49
49
  const secondarySnapshots = annotated.direct.filter((c) => !c.isPrimary);
50
50
  if (primarySnapshots.length === 0) return void 0;
51
51
  const columnIsAvailable = createColumnValidationById([
52
- ...annotated.direct,
53
- ...annotated.linked.flatMap((lc) => [...(lc.linkerPath ?? []).map((s) => s.linker), lc]),
52
+ ...annotated.direct.map((v) => v.column),
53
+ ...annotated.linked.flatMap((lc) => [...lc.path.map((s) => s.linker), lc.column]),
54
54
  ...annotated.labels
55
55
  ]);
56
56
  const remapedDefaultFilters = remapFilterColumnIds(options.filters, discovered);
@@ -58,7 +58,7 @@ function createPlDataTableV3(ctx, options) {
58
58
  validateFilters(filters, columnIsAvailable);
59
59
  const sorting = resolveSorting(state.pTableParams.sorting, remapSortingColumnIds(options.sorting, discovered));
60
60
  validateSorting(sorting, columnIsAvailable);
61
- const primaryEntries = primarySnapshots.map((snap) => ({ column: resolveSnapshot(snap) }));
61
+ const primaryEntries = primarySnapshots.map((v) => ({ column: resolveSnapshot(v.column) }));
62
62
  const fullDef = require_createPTableDefV3.createPTableDefV3({
63
63
  primaryJoinType,
64
64
  primary: primaryEntries,
@@ -68,13 +68,13 @@ function createPlDataTableV3(ctx, options) {
68
68
  });
69
69
  const fullHandle = ctx.createPTableV2(fullDef);
70
70
  const pframeHandle = ctx.createPFrame([
71
- ...annotated.direct.map(resolveSnapshot),
72
- ...annotated.linked.map(resolveSnapshot),
71
+ ...annotated.direct.map((v) => resolveSnapshot(v.column)),
72
+ ...annotated.linked.map((v) => resolveSnapshot(v.column)),
73
73
  ...annotated.labels,
74
74
  ...collectLinkerSnapshots(annotated.linked).map(resolveSnapshot)
75
75
  ]);
76
76
  const hiddenSpecs = state.pTableParams.hiddenColIds;
77
- const visible = buildVisibleColumns(annotated, computeHiddenColumns([...annotated.direct, ...annotated.linked], sorting, filters, hiddenSpecs), labelColumns);
77
+ const visible = buildVisibleColumns(annotated, computeHiddenColumns([...annotated.direct, ...annotated.linked].map((v) => v.column), sorting, filters, hiddenSpecs), labelColumns);
78
78
  const visibleDef = require_createPTableDefV3.createPTableDefV3({
79
79
  primaryJoinType,
80
80
  primary: primaryEntries,
@@ -94,13 +94,13 @@ function createPlDataTableV3(ctx, options) {
94
94
  /** Split discovered columns into direct (no linker path) and linked (with linker path). */
95
95
  function splitDiscoveredColumns(columns) {
96
96
  return {
97
- direct: columns.filter((dc) => (0, _milaboratories_helpers.isNil)(dc.linkerPath) || dc.linkerPath.length === 0),
98
- linked: columns.filter((dc) => !(0, _milaboratories_helpers.isNil)(dc.linkerPath) && dc.linkerPath.length > 0)
97
+ direct: columns.filter((dc) => dc.path.length === 0),
98
+ linked: columns.filter((dc) => dc.path.length > 0)
99
99
  };
100
100
  }
101
101
  /** All linker snapshots across the given linked columns, deduped by id. */
102
102
  function collectLinkerSnapshots(linked) {
103
- return (0, _milaboratories_pl_model_common.uniqueBy)(linked.flatMap((lc) => (lc.linkerPath ?? []).map((s) => s.linker)), (c) => c.id);
103
+ return (0, _milaboratories_pl_model_common.uniqueBy)(linked.flatMap((lc) => lc.path.map((s) => s.linker)), (c) => c.id);
104
104
  }
105
105
  /**
106
106
  * Annotate all column groups with derived labels and display-rule annotations.
@@ -111,34 +111,33 @@ function collectLinkerSnapshots(linked) {
111
111
  function annotateColumnGroups(params) {
112
112
  const { direct, linked, labelColumns, derivedLabels, derivedTooltips, displayOptions, pframeSpec } = params;
113
113
  const allColumnsForRules = [
114
- ...direct,
115
- ...linked,
114
+ ...direct.map((v) => v.column),
115
+ ...linked.map((v) => v.column),
116
116
  ...labelColumns,
117
117
  ...collectLinkerSnapshots(linked)
118
118
  ];
119
119
  const visibilityByColId = require_utils.evaluateRules(displayOptions?.visibility ?? [], allColumnsForRules, pframeSpec);
120
120
  const orderByColId = require_utils.evaluateRules(displayOptions?.ordering ?? [], allColumnsForRules, pframeSpec);
121
121
  return {
122
- direct: [
123
- require_utils.withLabelAnnotations.bind(null, derivedLabels),
124
- require_utils.withInfoAnnotations.bind(null, derivedTooltips),
125
- require_utils.withTableVisualAnnotations.bind(null, visibilityByColId, orderByColId)
126
- ].reduce((cols, fn) => fn(cols), direct),
127
- linked: [
128
- require_utils.withLabelAnnotations.bind(null, derivedLabels),
129
- require_utils.withInfoAnnotations.bind(null, derivedTooltips),
130
- require_utils.withHidenAxesAnnotations.bind(null),
131
- require_utils.withTableVisualAnnotations.bind(null, visibilityByColId, orderByColId),
132
- (cols) => cols.map((lc) => ({
133
- ...lc,
134
- linkerPath: annotateLinkerPath(derivedLabels, lc.linkerPath)
135
- }))
136
- ].reduce((cols, fn) => fn(cols), linked),
122
+ direct: withVariantColumns(direct, (cols) => require_utils.withTableVisualAnnotations(visibilityByColId, orderByColId, require_utils.withInfoAnnotations(derivedTooltips, require_utils.withLabelAnnotations(derivedLabels, cols)))),
123
+ linked: withVariantColumns(linked, (cols) => require_utils.withTableVisualAnnotations(visibilityByColId, orderByColId, require_utils.withHidenAxesAnnotations(require_utils.withInfoAnnotations(derivedTooltips, require_utils.withLabelAnnotations(derivedLabels, cols))))).map((lc) => ({
124
+ ...lc,
125
+ path: annotateLinkerPath(derivedLabels, lc.path)
126
+ })),
137
127
  labels: require_utils.withLabelAnnotations(derivedLabels, labelColumns)
138
128
  };
139
129
  }
130
+ /** Apply a snapshot-array transformation to the inner `column` of each variant. */
131
+ function withVariantColumns(variants, fn) {
132
+ const cols = fn(variants.map((v) => v.column));
133
+ if (cols.length !== variants.length) throw new Error(`withVariantColumns: fn must preserve array length (got ${cols.length}, expected ${variants.length})`);
134
+ return variants.map((v, i) => ({
135
+ ...v,
136
+ column: cols[i]
137
+ }));
138
+ }
140
139
  function annotateLinkerPath(derivedLabels, path) {
141
- if ((0, _milaboratories_helpers.isNil)(path) || path.length === 0) return path;
140
+ if (path.length === 0) return path;
142
141
  const annotatedLinkers = require_utils.withHidenAxesAnnotations(require_utils.withLabelAnnotations(derivedLabels, path.map((s) => s.linker)));
143
142
  return path.map((s, i) => ({
144
143
  ...s,
@@ -187,20 +186,20 @@ function buildSecondaryGroups(direct, linked, labels) {
187
186
  return [
188
187
  ...direct.map((c) => ({
189
188
  entries: [{
190
- column: resolveSnapshot(c),
191
- qualifications: c.qualifications?.forHit
189
+ column: resolveSnapshot(c.column),
190
+ qualifications: c.qualifications.forHit
192
191
  }],
193
- primaryQualifications: c.qualifications?.forQueries
192
+ primaryQualifications: c.qualifications.forQueries
194
193
  })),
195
194
  ...linked.map((lc) => ({
196
- entries: [...(lc.linkerPath ?? []).map((s) => ({
195
+ entries: [...lc.path.map((s) => ({
197
196
  column: resolveSnapshot(s.linker),
198
197
  qualifications: s.qualifications
199
198
  })), {
200
- column: resolveSnapshot(lc),
201
- qualifications: lc.qualifications?.forHit
199
+ column: resolveSnapshot(lc.column),
200
+ qualifications: lc.qualifications.forHit
202
201
  }],
203
- primaryQualifications: lc.qualifications?.forQueries
202
+ primaryQualifications: lc.qualifications.forQueries
204
203
  })),
205
204
  ...labels.map((c) => ({ entries: [{ column: c }] }))
206
205
  ];
@@ -224,12 +223,12 @@ function collectPreservedColumnIds(sorting, filters) {
224
223
  }
225
224
  /** Filter annotated columns to only visible ones, re-matching label columns for the visible subset. */
226
225
  function buildVisibleColumns(annotated, hiddenColumns, originalLabelColumns) {
227
- const direct = annotated.direct.filter((c) => !hiddenColumns.has(c.id));
228
- const linked = annotated.linked.filter((c) => !hiddenColumns.has(c.id));
226
+ const direct = annotated.direct.filter((c) => !hiddenColumns.has(c.column.id));
227
+ const linked = annotated.linked.filter((c) => !hiddenColumns.has(c.column.id));
229
228
  return {
230
229
  direct,
231
230
  linked,
232
- labels: require_labels.getMatchingLabelColumns([...direct, ...linked], originalLabelColumns)
231
+ labels: require_labels.getMatchingLabelColumns([...direct, ...linked].map((v) => v.column), originalLabelColumns)
233
232
  };
234
233
  }
235
234
  /** Resolve a ColumnSnapshot to a PColumn with lazily-evaluated data. */
@@ -245,12 +244,12 @@ function remapSortingColumnIds(sorting, columns) {
245
244
  return sorting?.map((s) => {
246
245
  if (s.column.type === "axis") return s;
247
246
  const id = s.column.id;
248
- const column = columns.find((c) => (c.originalId ?? c.id) === id) ?? (0, _milaboratories_helpers.throwError)(`Column ID "${id}" in sorting does not match any discovered column`);
247
+ const column = columns.find((c) => (c.originalId ?? c.column.id) === id) ?? (0, _milaboratories_helpers.throwError)(`Column ID "${id}" in sorting does not match any discovered column`);
249
248
  return {
250
249
  ...s,
251
250
  column: {
252
251
  type: "column",
253
- id: column.id
252
+ id: column.column.id
254
253
  }
255
254
  };
256
255
  });
@@ -264,7 +263,7 @@ function remapFilterColumnIds(filters, columns) {
264
263
  const originalId = parsed.id;
265
264
  return (0, _milaboratories_pl_model_common.canonicalizeJson)({
266
265
  type: "column",
267
- id: (columns.find((c) => (c.originalId ?? c.id) === originalId) ?? (0, _milaboratories_helpers.throwError)(`Column ID "${parsed.id}" in filters does not match any discovered column`)).id
266
+ id: (columns.find((c) => (c.originalId ?? c.column.id) === originalId) ?? (0, _milaboratories_helpers.throwError)(`Column ID "${parsed.id}" in filters does not match any discovered column`)).column.id
268
267
  });
269
268
  };
270
269
  return require_traverse.traverseFilterSpec(filters, {