@platforma-sdk/model 1.60.0 → 1.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -95,14 +95,15 @@ var ColumnCollectionImpl = class {
95
95
  return this.toSnapshot(col);
96
96
  }
97
97
  findColumns(options) {
98
- const columnFilter = options?.include ? toMultiColumnSelectors(options.include) : [];
99
- let results = this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {
100
- columnFilter,
98
+ const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : void 0;
99
+ const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : void 0;
100
+ return this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {
101
+ includeColumns,
102
+ excludeColumns,
101
103
  axes: [],
104
+ maxHops: 0,
102
105
  constraints: PLAIN_CONSTRAINTS
103
106
  }).hits.map((hit) => this.columns.get(hit.hit.columnId)).filter((col) => col !== void 0).map((col) => this.toSnapshot(col));
104
- if (options?.exclude) throw new Error("Exclude filter is not yet implemented for plain ColumnCollection");
105
- return results;
106
107
  }
107
108
  toSnapshot(col) {
108
109
  return remapSnapshot(col.id, col);
@@ -137,11 +138,14 @@ var AnchoredColumnCollectionImpl = class {
137
138
  }
138
139
  findColumns(options) {
139
140
  const constraints = matchingModeToConstraints(options?.mode ?? "enrichment");
140
- const columnFilter = options?.include ? toMultiColumnSelectors(options.include) : [];
141
- let results = this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {
142
- columnFilter,
141
+ const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : void 0;
142
+ const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : void 0;
143
+ return this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {
144
+ includeColumns,
145
+ excludeColumns,
143
146
  constraints,
144
- axes: this.anchorAxes
147
+ axes: this.anchorAxes,
148
+ maxHops: options?.maxHops ?? 4
145
149
  }).hits.map((hit) => {
146
150
  const origId = hit.hit.columnId;
147
151
  const col = this.columns.get(origId);
@@ -153,11 +157,10 @@ var AnchoredColumnCollectionImpl = class {
153
157
  variants: hit.mappingVariants.map((v) => ({
154
158
  qualifications: v.qualifications,
155
159
  distinctiveQualifications: v.distinctiveQualifications
156
- }))
160
+ })),
161
+ path: hit.path
157
162
  };
158
163
  }).filter((m) => m !== void 0);
159
- if (options?.exclude) throw new Error("Exclude filter is not yet implemented for AnchoredColumnCollection");
160
- return results;
161
164
  }
162
165
  toSnapshot(universalId, col) {
163
166
  return remapSnapshot(universalId, col);
@@ -1 +1 @@
1
- {"version":3,"file":"column_collection_builder.cjs","names":["TreeNodeAccessor","ArrayColumnProvider","toColumnSnapshotProvider","AnchoredIdDeriver","createColumnSnapshot","normalizeSelectors"],"sources":["../../src/columns/column_collection_builder.ts"],"sourcesContent":["import type {\n AxisQualification,\n ColumnAxesWithQualifications,\n DiscoverColumnsConstraints,\n MultiColumnSelector,\n NativePObjectId,\n PColumnSpec,\n PlRef,\n PObjectId,\n SUniversalPColumnId,\n} from \"@milaboratories/pl-model-common\";\nimport { AnchoredIdDeriver, deriveNativeId, isPlRef } from \"@milaboratories/pl-model-common\";\nimport type { ColumnSelectorInput } from \"./column_selector\";\nimport { normalizeSelectors } from \"./column_selector\";\nimport { TreeNodeAccessor } from \"../render/accessor\";\nimport type { ColumnSnapshot } from \"./column_snapshot\";\nimport { createColumnSnapshot } from \"./column_snapshot\";\nimport type { ColumnSnapshotProvider, ColumnSource } from \"./column_snapshot_provider\";\nimport { ArrayColumnProvider, toColumnSnapshotProvider } from \"./column_snapshot_provider\";\n\nimport type { GlobalCfgRenderCtxMethods } from \"../render/internal\";\n\n/** Subset of render context methods needed for spec frame operations. */\ntype SpecFrameCtx = Pick<\n GlobalCfgRenderCtxMethods,\n \"createSpecFrame\" | \"specFrameDiscoverColumns\" | \"specFrameDispose\"\n>;\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?: ColumnSelectorInput;\n /** Exclude columns matching these selectors. */\n exclude?: ColumnSelectorInput;\n}\n\n// --- ColumnCollection ---\n\n/** Plain collection — no axis context, selector-based filtering only. */\nexport interface ColumnCollection {\n /** Point lookup by provider-native ID. */\n getColumn(id: PObjectId): undefined | ColumnSnapshot<PObjectId>;\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 {\n /** Point lookup by anchored ID. */\n getColumn(id: SUniversalPColumnId): undefined | ColumnSnapshot<SUniversalPColumnId>;\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<SUniversalPColumnId>;\n /** Provider-native ID — for lookups back to the source provider. */\n readonly originalId: PObjectId;\n /** Match variants — different paths/qualifications that reach this column. */\n readonly variants: MatchVariant[];\n}\n\n/** Qualifications needed for both query (already-integrated) columns and the hit column. */\nexport interface MatchQualifications {\n /** Qualifications for each query (already-integrated) column set. */\n readonly forQueries: AxisQualification[][];\n /** Qualifications for the hit column. */\n readonly forHit: AxisQualification[];\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}\n\n// --- Build options ---\n\nexport interface BuildOptions {\n allowPartialColumnList?: true;\n}\n\nexport interface AnchoredBuildOptions extends BuildOptions {\n anchors: Record<string, PlRef | PObjectId | PColumnSpec>;\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 specFrameCtx: SpecFrameCtx) {}\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 const hasAnchors = options !== undefined && \"anchors\" in options;\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 columnMap = this.collectColumns();\n\n if (hasAnchors) {\n const anchorSpecs = resolveAnchorSpecs(options.anchors, columnMap);\n const idDeriver = new AnchoredIdDeriver(anchorSpecs);\n\n return new AnchoredColumnCollectionImpl(this.specFrameCtx, {\n columns: columnMap,\n idDeriver,\n anchorSpecs,\n columnListComplete: allowPartial ? allComplete : false,\n });\n } else {\n return new ColumnCollectionImpl(this.specFrameCtx, {\n columns: columnMap,\n columnListComplete: allowPartial ? allComplete : false,\n });\n }\n }\n\n /**\n * Collect all columns from all providers, dedup by NativePObjectId.\n * First source wins.\n */\n private collectColumns(): Map<PObjectId, ColumnSnapshot<PObjectId>> {\n const seen = new Set<NativePObjectId>();\n const result = new Map<PObjectId, ColumnSnapshot<PObjectId>>();\n\n for (const provider of this.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.set(col.id, col);\n }\n }\n\n return result;\n }\n}\n\n// --- Permissive constraints for plain (non-anchored) filtering ---\n\nconst PLAIN_CONSTRAINTS: DiscoverColumnsConstraints = {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: true,\n allowSourceQualifications: false,\n allowHitQualifications: false,\n};\n\n// --- ColumnCollectionImpl ---\n\ninterface ColumnCollectionImplOptions {\n readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n readonly columnListComplete?: boolean;\n}\n\nclass ColumnCollectionImpl implements ColumnCollection {\n private readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly specFrameHandle: string;\n public readonly columnListComplete: boolean;\n\n constructor(\n private readonly ctx: SpecFrameCtx,\n options: ColumnCollectionImplOptions,\n ) {\n this.columns = options.columns;\n this.columnListComplete = options.columnListComplete ?? false;\n this.specFrameHandle = this.ctx.createSpecFrame(\n Array.from(this.columns.entries()).reduce(\n (acc, [id, col]) => ((acc[id] = col.spec), acc),\n {} as Record<string, PColumnSpec>,\n ),\n );\n }\n\n getColumn(id: PObjectId): undefined | ColumnSnapshot<PObjectId> {\n const col = this.columns.get(id);\n if (col === undefined) return undefined;\n return this.toSnapshot(col);\n }\n\n findColumns(options?: FindColumnsOptions): ColumnSnapshot<PObjectId>[] {\n const columnFilter = options?.include ? toMultiColumnSelectors(options.include) : [];\n\n const response = this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {\n columnFilter,\n axes: [],\n constraints: PLAIN_CONSTRAINTS,\n });\n\n // Map hits back to snapshots\n let results = response.hits\n .map((hit) => this.columns.get(hit.hit.columnId as PObjectId))\n .filter((col): col is ColumnSnapshot<PObjectId> => col !== undefined)\n .map((col) => this.toSnapshot(col));\n\n if (options?.exclude) {\n throw new Error(\"Exclude filter is not yet implemented for plain ColumnCollection\");\n }\n\n return results;\n }\n\n private toSnapshot(col: ColumnSnapshot<PObjectId>): ColumnSnapshot<PObjectId> {\n return remapSnapshot(col.id, col);\n }\n}\n\n// --- AnchoredColumnCollectionImpl ---\n\ninterface AnchoredColumnCollectionImplOptions extends ColumnCollectionImplOptions {\n readonly idDeriver: AnchoredIdDeriver;\n readonly anchorSpecs: Record<string, PColumnSpec>;\n}\n\nclass AnchoredColumnCollectionImpl implements AnchoredColumnCollection {\n private readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly idDeriver: AnchoredIdDeriver;\n private readonly specFrameHandle: string;\n private readonly anchorAxes: ColumnAxesWithQualifications[];\n /** Reverse lookup: SUniversalPColumnId → PObjectId */\n private readonly idToOriginal: Map<SUniversalPColumnId, PObjectId>;\n public readonly columnListComplete: boolean;\n\n constructor(\n private readonly ctx: SpecFrameCtx,\n options: AnchoredColumnCollectionImplOptions,\n ) {\n this.columns = options.columns;\n this.idDeriver = options.idDeriver;\n this.columnListComplete = options.columnListComplete ?? false;\n\n // Create spec frame from all collected columns\n this.specFrameHandle = this.ctx.createSpecFrame(\n Array.from(this.columns.entries()).reduce(\n (acc, [id, col]) => ((acc[id] = col.spec), acc),\n {} as Record<string, PColumnSpec>,\n ),\n );\n\n // Build anchor axes for discovery requests\n this.anchorAxes = Object.values(options.anchorSpecs).map((spec) => ({\n axesSpec: spec.axesSpec,\n qualifications: [],\n }));\n\n // Build reverse lookup map\n this.idToOriginal = new Map(\n Array.from(this.columns.entries()).map(\n ([id, col]) => [this.idDeriver.deriveS(col.spec), id] as const,\n ),\n );\n }\n\n getColumn(id: SUniversalPColumnId): undefined | ColumnSnapshot<SUniversalPColumnId> {\n const origId = this.idToOriginal.get(id);\n if (origId === undefined) return undefined;\n const col = this.columns.get(origId);\n if (col === undefined) return undefined;\n return this.toSnapshot(id, col);\n }\n\n findColumns(options?: AnchoredFindColumnsOptions): ColumnMatch[] {\n const mode = options?.mode ?? \"enrichment\";\n const constraints = matchingModeToConstraints(mode);\n const columnFilter = options?.include ? toMultiColumnSelectors(options.include) : [];\n\n const response = this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {\n columnFilter,\n constraints,\n axes: this.anchorAxes,\n });\n\n // Map hits back to ColumnMatch entries\n let results = response.hits\n .map((hit) => {\n const origId = hit.hit.columnId as PObjectId;\n const col = this.columns.get(origId);\n if (!col) return undefined;\n const universalId = this.idDeriver.deriveS(col.spec);\n return {\n column: this.toSnapshot(universalId, col),\n originalId: origId,\n variants: hit.mappingVariants.map(\n (v): MatchVariant => ({\n qualifications: v.qualifications,\n distinctiveQualifications: v.distinctiveQualifications,\n }),\n ),\n } satisfies ColumnMatch;\n })\n .filter((m): m is ColumnMatch => m !== undefined);\n\n if (options?.exclude) {\n throw new Error(\"Exclude filter is not yet implemented for AnchoredColumnCollection\");\n }\n\n return results;\n }\n\n private toSnapshot(\n universalId: SUniversalPColumnId,\n col: ColumnSnapshot<PObjectId>,\n ): ColumnSnapshot<SUniversalPColumnId> {\n return remapSnapshot(universalId, col);\n }\n}\n\n// --- Shared snapshot helpers ---\n\n/** Create a new snapshot with a different ID, preserving data accessors. */\nfunction remapSnapshot<Id extends PObjectId>(\n id: Id,\n col: ColumnSnapshot<PObjectId>,\n): ColumnSnapshot<Id> {\n return createColumnSnapshot(id, col.spec, col.dataStatus, col.data);\n}\n\n/** Normalize SDK ColumnSelectorInput to MultiColumnSelector[]. */\nfunction toMultiColumnSelectors(input: ColumnSelectorInput): MultiColumnSelector[] {\n return normalizeSelectors(input);\n}\n\n// --- Anchor resolution ---\n\n/**\n * Resolve each anchor value to a PColumnSpec.\n * - PColumnSpec: used directly\n * - PObjectId (string): looked up in the collected column map\n * - PlRef: not supported at this level — caller must resolve before building\n */\nfunction resolveAnchorSpecs(\n anchors: Record<string, PlRef | PObjectId | PColumnSpec>,\n columnMap: Map<PObjectId, ColumnSnapshot<PObjectId>>,\n): Record<string, PColumnSpec> {\n const result: Record<string, PColumnSpec> = {};\n for (const [key, anchor] of Object.entries(anchors)) {\n if (typeof anchor === \"string\") {\n // PObjectId — look up in collected columns\n const col = columnMap.get(anchor as PObjectId);\n if (!col) throw new Error(`Anchor \"${key}\": column with id \"${anchor}\" not found in sources`);\n result[key] = col.spec;\n } else if (isPlRef(anchor)) {\n throw new Error(\n `Anchor \"${key}\": PlRef anchors must be resolved to PColumnSpec before building. ` +\n `Use the column's spec directly or pass its PObjectId.`,\n );\n } else {\n // PColumnSpec\n result[key] = anchor;\n }\n }\n return result;\n}\n\n// --- MatchingMode → DiscoverColumnsConstraints ---\n\nfunction matchingModeToConstraints(mode: MatchingMode): DiscoverColumnsConstraints {\n switch (mode) {\n case \"enrichment\":\n return {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: true,\n allowSourceQualifications: false,\n allowHitQualifications: false,\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":";;;;;;;;;;;;;;;AAsHA,IAAa,0BAAb,MAAqC;CACnC,AAAiB,YAAsC,EAAE;CAEzD,YAAY,AAAiB,cAA4B;EAA5B;;;;;;;CAO7B,UAAU,QAA+C;AACvD,MAAI,kBAAkBA,mCAAkB;GACtC,MAAM,UAAU,OAAO,aAAa;AACpC,OAAI,QAAS,MAAK,UAAU,KAAK,IAAIC,qDAAoB,QAAQ,CAAC;QAElE,MAAK,UAAU,KAAKC,0DAAyB,OAAO,CAAC;AAEvD,SAAO;;CAGT,WAAW,SAAoD;AAC7D,OAAK,MAAM,UAAU,QACnB,MAAK,UAAU,OAAO;AAExB,SAAO;;CAaT,MACE,SAMwE;EACxE,MAAM,eAAe,SAAS,2BAA2B;EACzD,MAAM,aAAa,YAAY,UAAa,aAAa;EAGzD,MAAM,cAAc,KAAK,UAAU,OAAO,MAAM,EAAE,sBAAsB,CAAC;AACzE,MAAI,CAAC,eAAe,CAAC,aAAc,QAAO;EAG1C,MAAM,YAAY,KAAK,gBAAgB;AAEvC,MAAI,YAAY;GACd,MAAM,cAAc,mBAAmB,QAAQ,SAAS,UAAU;GAClE,MAAM,YAAY,IAAIC,kDAAkB,YAAY;AAEpD,UAAO,IAAI,6BAA6B,KAAK,cAAc;IACzD,SAAS;IACT;IACA;IACA,oBAAoB,eAAe,cAAc;IAClD,CAAC;QAEF,QAAO,IAAI,qBAAqB,KAAK,cAAc;GACjD,SAAS;GACT,oBAAoB,eAAe,cAAc;GAClD,CAAC;;;;;;CAQN,AAAQ,iBAA4D;EAClE,MAAM,uBAAO,IAAI,KAAsB;EACvC,MAAM,yBAAS,IAAI,KAA2C;AAE9D,OAAK,MAAM,YAAY,KAAK,WAAW;GACrC,MAAM,UAAU,SAAS,eAAe;AACxC,QAAK,MAAM,OAAO,SAAS;IACzB,MAAM,+DAA0B,IAAI,KAAK;AACzC,QAAI,KAAK,IAAI,SAAS,CAAE;AACxB,SAAK,IAAI,SAAS;AAClB,WAAO,IAAI,IAAI,IAAI,IAAI;;;AAI3B,SAAO;;;AAMX,MAAM,oBAAgD;CACpD,yBAAyB;CACzB,sBAAsB;CACtB,2BAA2B;CAC3B,wBAAwB;CACzB;AASD,IAAM,uBAAN,MAAuD;CACrD,AAAiB;CACjB,AAAiB;CACjB,AAAgB;CAEhB,YACE,AAAiB,KACjB,SACA;EAFiB;AAGjB,OAAK,UAAU,QAAQ;AACvB,OAAK,qBAAqB,QAAQ,sBAAsB;AACxD,OAAK,kBAAkB,KAAK,IAAI,gBAC9B,MAAM,KAAK,KAAK,QAAQ,SAAS,CAAC,CAAC,QAChC,KAAK,CAAC,IAAI,UAAW,IAAI,MAAM,IAAI,MAAO,MAC3C,EAAE,CACH,CACF;;CAGH,UAAU,IAAsD;EAC9D,MAAM,MAAM,KAAK,QAAQ,IAAI,GAAG;AAChC,MAAI,QAAQ,OAAW,QAAO;AAC9B,SAAO,KAAK,WAAW,IAAI;;CAG7B,YAAY,SAA2D;EACrE,MAAM,eAAe,SAAS,UAAU,uBAAuB,QAAQ,QAAQ,GAAG,EAAE;EASpF,IAAI,UAPa,KAAK,IAAI,yBAAyB,KAAK,iBAAiB;GACvE;GACA,MAAM,EAAE;GACR,aAAa;GACd,CAAC,CAGqB,KACpB,KAAK,QAAQ,KAAK,QAAQ,IAAI,IAAI,IAAI,SAAsB,CAAC,CAC7D,QAAQ,QAA0C,QAAQ,OAAU,CACpE,KAAK,QAAQ,KAAK,WAAW,IAAI,CAAC;AAErC,MAAI,SAAS,QACX,OAAM,IAAI,MAAM,mEAAmE;AAGrF,SAAO;;CAGT,AAAQ,WAAW,KAA2D;AAC5E,SAAO,cAAc,IAAI,IAAI,IAAI;;;AAWrC,IAAM,+BAAN,MAAuE;CACrE,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;;CAEjB,AAAiB;CACjB,AAAgB;CAEhB,YACE,AAAiB,KACjB,SACA;EAFiB;AAGjB,OAAK,UAAU,QAAQ;AACvB,OAAK,YAAY,QAAQ;AACzB,OAAK,qBAAqB,QAAQ,sBAAsB;AAGxD,OAAK,kBAAkB,KAAK,IAAI,gBAC9B,MAAM,KAAK,KAAK,QAAQ,SAAS,CAAC,CAAC,QAChC,KAAK,CAAC,IAAI,UAAW,IAAI,MAAM,IAAI,MAAO,MAC3C,EAAE,CACH,CACF;AAGD,OAAK,aAAa,OAAO,OAAO,QAAQ,YAAY,CAAC,KAAK,UAAU;GAClE,UAAU,KAAK;GACf,gBAAgB,EAAE;GACnB,EAAE;AAGH,OAAK,eAAe,IAAI,IACtB,MAAM,KAAK,KAAK,QAAQ,SAAS,CAAC,CAAC,KAChC,CAAC,IAAI,SAAS,CAAC,KAAK,UAAU,QAAQ,IAAI,KAAK,EAAE,GAAG,CACtD,CACF;;CAGH,UAAU,IAA0E;EAClF,MAAM,SAAS,KAAK,aAAa,IAAI,GAAG;AACxC,MAAI,WAAW,OAAW,QAAO;EACjC,MAAM,MAAM,KAAK,QAAQ,IAAI,OAAO;AACpC,MAAI,QAAQ,OAAW,QAAO;AAC9B,SAAO,KAAK,WAAW,IAAI,IAAI;;CAGjC,YAAY,SAAqD;EAE/D,MAAM,cAAc,0BADP,SAAS,QAAQ,aACqB;EACnD,MAAM,eAAe,SAAS,UAAU,uBAAuB,QAAQ,QAAQ,GAAG,EAAE;EASpF,IAAI,UAPa,KAAK,IAAI,yBAAyB,KAAK,iBAAiB;GACvE;GACA;GACA,MAAM,KAAK;GACZ,CAAC,CAGqB,KACpB,KAAK,QAAQ;GACZ,MAAM,SAAS,IAAI,IAAI;GACvB,MAAM,MAAM,KAAK,QAAQ,IAAI,OAAO;AACpC,OAAI,CAAC,IAAK,QAAO;GACjB,MAAM,cAAc,KAAK,UAAU,QAAQ,IAAI,KAAK;AACpD,UAAO;IACL,QAAQ,KAAK,WAAW,aAAa,IAAI;IACzC,YAAY;IACZ,UAAU,IAAI,gBAAgB,KAC3B,OAAqB;KACpB,gBAAgB,EAAE;KAClB,2BAA2B,EAAE;KAC9B,EACF;IACF;IACD,CACD,QAAQ,MAAwB,MAAM,OAAU;AAEnD,MAAI,SAAS,QACX,OAAM,IAAI,MAAM,qEAAqE;AAGvF,SAAO;;CAGT,AAAQ,WACN,aACA,KACqC;AACrC,SAAO,cAAc,aAAa,IAAI;;;;AAO1C,SAAS,cACP,IACA,KACoB;AACpB,QAAOC,6CAAqB,IAAI,IAAI,MAAM,IAAI,YAAY,IAAI,KAAK;;;AAIrE,SAAS,uBAAuB,OAAmD;AACjF,QAAOC,2CAAmB,MAAM;;;;;;;;AAWlC,SAAS,mBACP,SACA,WAC6B;CAC7B,MAAM,SAAsC,EAAE;AAC9C,MAAK,MAAM,CAAC,KAAK,WAAW,OAAO,QAAQ,QAAQ,CACjD,KAAI,OAAO,WAAW,UAAU;EAE9B,MAAM,MAAM,UAAU,IAAI,OAAoB;AAC9C,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,WAAW,IAAI,qBAAqB,OAAO,wBAAwB;AAC7F,SAAO,OAAO,IAAI;yDACD,OAAO,CACxB,OAAM,IAAI,MACR,WAAW,IAAI,yHAEhB;KAGD,QAAO,OAAO;AAGlB,QAAO;;AAKT,SAAS,0BAA0B,MAAgD;AACjF,SAAQ,MAAR;EACE,KAAK,aACH,QAAO;GACL,yBAAyB;GACzB,sBAAsB;GACtB,2BAA2B;GAC3B,wBAAwB;GACzB;EACH,KAAK,UACH,QAAO;GACL,yBAAyB;GACzB,sBAAsB;GACtB,2BAA2B;GAC3B,wBAAwB;GACzB;EACH,KAAK,QACH,QAAO;GACL,yBAAyB;GACzB,sBAAsB;GACtB,2BAA2B;GAC3B,wBAAwB;GACzB"}
1
+ {"version":3,"file":"column_collection_builder.cjs","names":["TreeNodeAccessor","ArrayColumnProvider","toColumnSnapshotProvider","AnchoredIdDeriver","createColumnSnapshot","normalizeSelectors"],"sources":["../../src/columns/column_collection_builder.ts"],"sourcesContent":["import type {\n AxisQualification,\n ColumnAxesWithQualifications,\n DiscoverColumnsConstraints,\n DiscoverColumnsStepInfo,\n MultiColumnSelector,\n NativePObjectId,\n PColumnSpec,\n PlRef,\n PObjectId,\n SUniversalPColumnId,\n} from \"@milaboratories/pl-model-common\";\nimport { AnchoredIdDeriver, deriveNativeId, isPlRef } from \"@milaboratories/pl-model-common\";\nimport type { ColumnSelectorInput } from \"./column_selector\";\nimport { normalizeSelectors } from \"./column_selector\";\nimport { TreeNodeAccessor } from \"../render/accessor\";\nimport type { ColumnSnapshot } from \"./column_snapshot\";\nimport { createColumnSnapshot } from \"./column_snapshot\";\nimport type { ColumnSnapshotProvider, ColumnSource } from \"./column_snapshot_provider\";\nimport { ArrayColumnProvider, toColumnSnapshotProvider } from \"./column_snapshot_provider\";\n\nimport type { GlobalCfgRenderCtxMethods } from \"../render/internal\";\n\n/** Subset of render context methods needed for spec frame operations. */\ntype SpecFrameCtx = Pick<\n GlobalCfgRenderCtxMethods,\n \"createSpecFrame\" | \"specFrameDiscoverColumns\" | \"disposeSpecFrame\"\n>;\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?: ColumnSelectorInput;\n /** Exclude columns matching these selectors. */\n exclude?: ColumnSelectorInput;\n}\n\n// --- ColumnCollection ---\n\n/** Plain collection — no axis context, selector-based filtering only. */\nexport interface ColumnCollection {\n /** Point lookup by provider-native ID. */\n getColumn(id: PObjectId): undefined | ColumnSnapshot<PObjectId>;\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 {\n /** Point lookup by anchored ID. */\n getColumn(id: SUniversalPColumnId): undefined | ColumnSnapshot<SUniversalPColumnId>;\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<SUniversalPColumnId>;\n /** Provider-native ID — for lookups back to the source provider. */\n readonly originalId: PObjectId;\n /** Match variants — different paths/qualifications that reach this column. */\n readonly variants: MatchVariant[];\n /** Linker steps traversed to reach this hit; empty for direct matches. */\n readonly path: DiscoverColumnsStepInfo[];\n}\n\n/** Qualifications needed for both query (already-integrated) columns and the hit column. */\nexport interface MatchQualifications {\n /** Qualifications for each query (already-integrated) column set. */\n readonly forQueries: AxisQualification[][];\n /** Qualifications for the hit column. */\n readonly forHit: AxisQualification[];\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}\n\n// --- Build options ---\n\nexport interface BuildOptions {\n allowPartialColumnList?: true;\n}\n\nexport interface AnchoredBuildOptions extends BuildOptions {\n anchors: Record<string, PlRef | PObjectId | PColumnSpec>;\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 specFrameCtx: SpecFrameCtx) {}\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 const hasAnchors = options !== undefined && \"anchors\" in options;\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 columnMap = this.collectColumns();\n\n if (hasAnchors) {\n const anchorSpecs = resolveAnchorSpecs(options.anchors, columnMap);\n const idDeriver = new AnchoredIdDeriver(anchorSpecs);\n\n return new AnchoredColumnCollectionImpl(this.specFrameCtx, {\n columns: columnMap,\n idDeriver,\n anchorSpecs,\n columnListComplete: allowPartial ? allComplete : false,\n });\n } else {\n return new ColumnCollectionImpl(this.specFrameCtx, {\n columns: columnMap,\n columnListComplete: allowPartial ? allComplete : false,\n });\n }\n }\n\n /**\n * Collect all columns from all providers, dedup by NativePObjectId.\n * First source wins.\n */\n private collectColumns(): Map<PObjectId, ColumnSnapshot<PObjectId>> {\n const seen = new Set<NativePObjectId>();\n const result = new Map<PObjectId, ColumnSnapshot<PObjectId>>();\n\n for (const provider of this.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.set(col.id, col);\n }\n }\n\n return result;\n }\n}\n\n// --- Permissive constraints for plain (non-anchored) filtering ---\n\nconst PLAIN_CONSTRAINTS: DiscoverColumnsConstraints = {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: true,\n allowSourceQualifications: false,\n allowHitQualifications: false,\n};\n\n// --- ColumnCollectionImpl ---\n\ninterface ColumnCollectionImplOptions {\n readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n readonly columnListComplete?: boolean;\n}\n\nclass ColumnCollectionImpl implements ColumnCollection {\n private readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly specFrameHandle: string;\n public readonly columnListComplete: boolean;\n\n constructor(\n private readonly ctx: SpecFrameCtx,\n options: ColumnCollectionImplOptions,\n ) {\n this.columns = options.columns;\n this.columnListComplete = options.columnListComplete ?? false;\n this.specFrameHandle = this.ctx.createSpecFrame(\n Array.from(this.columns.entries()).reduce(\n (acc, [id, col]) => ((acc[id] = col.spec), acc),\n {} as Record<string, PColumnSpec>,\n ),\n );\n }\n\n getColumn(id: PObjectId): undefined | ColumnSnapshot<PObjectId> {\n const col = this.columns.get(id);\n if (col === undefined) return undefined;\n return this.toSnapshot(col);\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.ctx.specFrameDiscoverColumns(this.specFrameHandle, {\n includeColumns,\n excludeColumns,\n axes: [],\n maxHops: 0,\n constraints: PLAIN_CONSTRAINTS,\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 .map((col) => this.toSnapshot(col));\n\n return results;\n }\n\n private toSnapshot(col: ColumnSnapshot<PObjectId>): ColumnSnapshot<PObjectId> {\n return remapSnapshot(col.id, col);\n }\n}\n\n// --- AnchoredColumnCollectionImpl ---\n\ninterface AnchoredColumnCollectionImplOptions extends ColumnCollectionImplOptions {\n readonly idDeriver: AnchoredIdDeriver;\n readonly anchorSpecs: Record<string, PColumnSpec>;\n}\n\nclass AnchoredColumnCollectionImpl implements AnchoredColumnCollection {\n private readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly idDeriver: AnchoredIdDeriver;\n private readonly specFrameHandle: string;\n private readonly anchorAxes: ColumnAxesWithQualifications[];\n /** Reverse lookup: SUniversalPColumnId → PObjectId */\n private readonly idToOriginal: Map<SUniversalPColumnId, PObjectId>;\n public readonly columnListComplete: boolean;\n\n constructor(\n private readonly ctx: SpecFrameCtx,\n options: AnchoredColumnCollectionImplOptions,\n ) {\n this.columns = options.columns;\n this.idDeriver = options.idDeriver;\n this.columnListComplete = options.columnListComplete ?? false;\n\n // Create spec frame from all collected columns\n this.specFrameHandle = this.ctx.createSpecFrame(\n Array.from(this.columns.entries()).reduce(\n (acc, [id, col]) => ((acc[id] = col.spec), acc),\n {} as Record<string, PColumnSpec>,\n ),\n );\n\n // Build anchor axes for discovery requests\n this.anchorAxes = Object.values(options.anchorSpecs).map((spec) => ({\n axesSpec: spec.axesSpec,\n qualifications: [],\n }));\n\n // Build reverse lookup map\n this.idToOriginal = new Map(\n Array.from(this.columns.entries()).map(\n ([id, col]) => [this.idDeriver.deriveS(col.spec), id] as const,\n ),\n );\n }\n\n getColumn(id: SUniversalPColumnId): undefined | ColumnSnapshot<SUniversalPColumnId> {\n const origId = this.idToOriginal.get(id);\n if (origId === undefined) return undefined;\n const col = this.columns.get(origId);\n if (col === undefined) return undefined;\n return this.toSnapshot(id, col);\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\n const response = this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {\n includeColumns,\n excludeColumns,\n constraints,\n axes: this.anchorAxes,\n maxHops: options?.maxHops ?? 4,\n });\n\n // Map hits back to ColumnMatch entries\n const results = response.hits\n .map((hit) => {\n const origId = hit.hit.columnId as PObjectId;\n const col = this.columns.get(origId);\n if (!col) return undefined;\n const universalId = this.idDeriver.deriveS(col.spec);\n return {\n column: this.toSnapshot(universalId, col),\n originalId: origId,\n variants: hit.mappingVariants.map(\n (v): MatchVariant => ({\n qualifications: v.qualifications,\n distinctiveQualifications: v.distinctiveQualifications,\n }),\n ),\n path: hit.path,\n } satisfies ColumnMatch;\n })\n .filter((m): m is ColumnMatch => m !== undefined);\n\n return results;\n }\n\n private toSnapshot(\n universalId: SUniversalPColumnId,\n col: ColumnSnapshot<PObjectId>,\n ): ColumnSnapshot<SUniversalPColumnId> {\n return remapSnapshot(universalId, col);\n }\n}\n\n// --- Shared snapshot helpers ---\n\n/** Create a new snapshot with a different ID, preserving data accessors. */\nfunction remapSnapshot<Id extends PObjectId>(\n id: Id,\n col: ColumnSnapshot<PObjectId>,\n): ColumnSnapshot<Id> {\n return createColumnSnapshot(id, col.spec, col.dataStatus, col.data);\n}\n\n/** Normalize SDK ColumnSelectorInput to MultiColumnSelector[]. */\nfunction toMultiColumnSelectors(input: ColumnSelectorInput): MultiColumnSelector[] {\n return normalizeSelectors(input);\n}\n\n// --- Anchor resolution ---\n\n/**\n * Resolve each anchor value to a PColumnSpec.\n * - PColumnSpec: used directly\n * - PObjectId (string): looked up in the collected column map\n * - PlRef: not supported at this level — caller must resolve before building\n */\nfunction resolveAnchorSpecs(\n anchors: Record<string, PlRef | PObjectId | PColumnSpec>,\n columnMap: Map<PObjectId, ColumnSnapshot<PObjectId>>,\n): Record<string, PColumnSpec> {\n const result: Record<string, PColumnSpec> = {};\n for (const [key, anchor] of Object.entries(anchors)) {\n if (typeof anchor === \"string\") {\n // PObjectId — look up in collected columns\n const col = columnMap.get(anchor as PObjectId);\n if (!col) throw new Error(`Anchor \"${key}\": column with id \"${anchor}\" not found in sources`);\n result[key] = col.spec;\n } else if (isPlRef(anchor)) {\n throw new Error(\n `Anchor \"${key}\": PlRef anchors must be resolved to PColumnSpec before building. ` +\n `Use the column's spec directly or pass its PObjectId.`,\n );\n } else {\n // PColumnSpec\n result[key] = anchor;\n }\n }\n return result;\n}\n\n// --- MatchingMode → DiscoverColumnsConstraints ---\n\nfunction matchingModeToConstraints(mode: MatchingMode): DiscoverColumnsConstraints {\n switch (mode) {\n case \"enrichment\":\n return {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: true,\n allowSourceQualifications: false,\n allowHitQualifications: false,\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":";;;;;;;;;;;;;;;AAyHA,IAAa,0BAAb,MAAqC;CACnC,AAAiB,YAAsC,EAAE;CAEzD,YAAY,AAAiB,cAA4B;EAA5B;;;;;;;CAO7B,UAAU,QAA+C;AACvD,MAAI,kBAAkBA,mCAAkB;GACtC,MAAM,UAAU,OAAO,aAAa;AACpC,OAAI,QAAS,MAAK,UAAU,KAAK,IAAIC,qDAAoB,QAAQ,CAAC;QAElE,MAAK,UAAU,KAAKC,0DAAyB,OAAO,CAAC;AAEvD,SAAO;;CAGT,WAAW,SAAoD;AAC7D,OAAK,MAAM,UAAU,QACnB,MAAK,UAAU,OAAO;AAExB,SAAO;;CAaT,MACE,SAMwE;EACxE,MAAM,eAAe,SAAS,2BAA2B;EACzD,MAAM,aAAa,YAAY,UAAa,aAAa;EAGzD,MAAM,cAAc,KAAK,UAAU,OAAO,MAAM,EAAE,sBAAsB,CAAC;AACzE,MAAI,CAAC,eAAe,CAAC,aAAc,QAAO;EAG1C,MAAM,YAAY,KAAK,gBAAgB;AAEvC,MAAI,YAAY;GACd,MAAM,cAAc,mBAAmB,QAAQ,SAAS,UAAU;GAClE,MAAM,YAAY,IAAIC,kDAAkB,YAAY;AAEpD,UAAO,IAAI,6BAA6B,KAAK,cAAc;IACzD,SAAS;IACT;IACA;IACA,oBAAoB,eAAe,cAAc;IAClD,CAAC;QAEF,QAAO,IAAI,qBAAqB,KAAK,cAAc;GACjD,SAAS;GACT,oBAAoB,eAAe,cAAc;GAClD,CAAC;;;;;;CAQN,AAAQ,iBAA4D;EAClE,MAAM,uBAAO,IAAI,KAAsB;EACvC,MAAM,yBAAS,IAAI,KAA2C;AAE9D,OAAK,MAAM,YAAY,KAAK,WAAW;GACrC,MAAM,UAAU,SAAS,eAAe;AACxC,QAAK,MAAM,OAAO,SAAS;IACzB,MAAM,+DAA0B,IAAI,KAAK;AACzC,QAAI,KAAK,IAAI,SAAS,CAAE;AACxB,SAAK,IAAI,SAAS;AAClB,WAAO,IAAI,IAAI,IAAI,IAAI;;;AAI3B,SAAO;;;AAMX,MAAM,oBAAgD;CACpD,yBAAyB;CACzB,sBAAsB;CACtB,2BAA2B;CAC3B,wBAAwB;CACzB;AASD,IAAM,uBAAN,MAAuD;CACrD,AAAiB;CACjB,AAAiB;CACjB,AAAgB;CAEhB,YACE,AAAiB,KACjB,SACA;EAFiB;AAGjB,OAAK,UAAU,QAAQ;AACvB,OAAK,qBAAqB,QAAQ,sBAAsB;AACxD,OAAK,kBAAkB,KAAK,IAAI,gBAC9B,MAAM,KAAK,KAAK,QAAQ,SAAS,CAAC,CAAC,QAChC,KAAK,CAAC,IAAI,UAAW,IAAI,MAAM,IAAI,MAAO,MAC3C,EAAE,CACH,CACF;;CAGH,UAAU,IAAsD;EAC9D,MAAM,MAAM,KAAK,QAAQ,IAAI,GAAG;AAChC,MAAI,QAAQ,OAAW,QAAO;AAC9B,SAAO,KAAK,WAAW,IAAI;;CAG7B,YAAY,SAA2D;EACrE,MAAM,iBAAiB,SAAS,UAAU,uBAAuB,QAAQ,QAAQ,GAAG;EACpF,MAAM,iBAAiB,SAAS,UAAU,uBAAuB,QAAQ,QAAQ,GAAG;AAgBpF,SAdiB,KAAK,IAAI,yBAAyB,KAAK,iBAAiB;GACvE;GACA;GACA,MAAM,EAAE;GACR,SAAS;GACT,aAAa;GACd,CAAC,CAGuB,KACtB,KAAK,QAAQ,KAAK,QAAQ,IAAI,IAAI,IAAI,SAAsB,CAAC,CAC7D,QAAQ,QAA0C,QAAQ,OAAU,CACpE,KAAK,QAAQ,KAAK,WAAW,IAAI,CAAC;;CAKvC,AAAQ,WAAW,KAA2D;AAC5E,SAAO,cAAc,IAAI,IAAI,IAAI;;;AAWrC,IAAM,+BAAN,MAAuE;CACrE,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;;CAEjB,AAAiB;CACjB,AAAgB;CAEhB,YACE,AAAiB,KACjB,SACA;EAFiB;AAGjB,OAAK,UAAU,QAAQ;AACvB,OAAK,YAAY,QAAQ;AACzB,OAAK,qBAAqB,QAAQ,sBAAsB;AAGxD,OAAK,kBAAkB,KAAK,IAAI,gBAC9B,MAAM,KAAK,KAAK,QAAQ,SAAS,CAAC,CAAC,QAChC,KAAK,CAAC,IAAI,UAAW,IAAI,MAAM,IAAI,MAAO,MAC3C,EAAE,CACH,CACF;AAGD,OAAK,aAAa,OAAO,OAAO,QAAQ,YAAY,CAAC,KAAK,UAAU;GAClE,UAAU,KAAK;GACf,gBAAgB,EAAE;GACnB,EAAE;AAGH,OAAK,eAAe,IAAI,IACtB,MAAM,KAAK,KAAK,QAAQ,SAAS,CAAC,CAAC,KAChC,CAAC,IAAI,SAAS,CAAC,KAAK,UAAU,QAAQ,IAAI,KAAK,EAAE,GAAG,CACtD,CACF;;CAGH,UAAU,IAA0E;EAClF,MAAM,SAAS,KAAK,aAAa,IAAI,GAAG;AACxC,MAAI,WAAW,OAAW,QAAO;EACjC,MAAM,MAAM,KAAK,QAAQ,IAAI,OAAO;AACpC,MAAI,QAAQ,OAAW,QAAO;AAC9B,SAAO,KAAK,WAAW,IAAI,IAAI;;CAGjC,YAAY,SAAqD;EAE/D,MAAM,cAAc,0BADP,SAAS,QAAQ,aACqB;EACnD,MAAM,iBAAiB,SAAS,UAAU,uBAAuB,QAAQ,QAAQ,GAAG;EACpF,MAAM,iBAAiB,SAAS,UAAU,uBAAuB,QAAQ,QAAQ,GAAG;AA+BpF,SA7BiB,KAAK,IAAI,yBAAyB,KAAK,iBAAiB;GACvE;GACA;GACA;GACA,MAAM,KAAK;GACX,SAAS,SAAS,WAAW;GAC9B,CAAC,CAGuB,KACtB,KAAK,QAAQ;GACZ,MAAM,SAAS,IAAI,IAAI;GACvB,MAAM,MAAM,KAAK,QAAQ,IAAI,OAAO;AACpC,OAAI,CAAC,IAAK,QAAO;GACjB,MAAM,cAAc,KAAK,UAAU,QAAQ,IAAI,KAAK;AACpD,UAAO;IACL,QAAQ,KAAK,WAAW,aAAa,IAAI;IACzC,YAAY;IACZ,UAAU,IAAI,gBAAgB,KAC3B,OAAqB;KACpB,gBAAgB,EAAE;KAClB,2BAA2B,EAAE;KAC9B,EACF;IACD,MAAM,IAAI;IACX;IACD,CACD,QAAQ,MAAwB,MAAM,OAAU;;CAKrD,AAAQ,WACN,aACA,KACqC;AACrC,SAAO,cAAc,aAAa,IAAI;;;;AAO1C,SAAS,cACP,IACA,KACoB;AACpB,QAAOC,6CAAqB,IAAI,IAAI,MAAM,IAAI,YAAY,IAAI,KAAK;;;AAIrE,SAAS,uBAAuB,OAAmD;AACjF,QAAOC,2CAAmB,MAAM;;;;;;;;AAWlC,SAAS,mBACP,SACA,WAC6B;CAC7B,MAAM,SAAsC,EAAE;AAC9C,MAAK,MAAM,CAAC,KAAK,WAAW,OAAO,QAAQ,QAAQ,CACjD,KAAI,OAAO,WAAW,UAAU;EAE9B,MAAM,MAAM,UAAU,IAAI,OAAoB;AAC9C,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,WAAW,IAAI,qBAAqB,OAAO,wBAAwB;AAC7F,SAAO,OAAO,IAAI;yDACD,OAAO,CACxB,OAAM,IAAI,MACR,WAAW,IAAI,yHAEhB;KAGD,QAAO,OAAO;AAGlB,QAAO;;AAKT,SAAS,0BAA0B,MAAgD;AACjF,SAAQ,MAAR;EACE,KAAK,aACH,QAAO;GACL,yBAAyB;GACzB,sBAAsB;GACtB,2BAA2B;GAC3B,wBAAwB;GACzB;EACH,KAAK,UACH,QAAO;GACL,yBAAyB;GACzB,sBAAsB;GACtB,2BAA2B;GAC3B,wBAAwB;GACzB;EACH,KAAK,QACH,QAAO;GACL,yBAAyB;GACzB,sBAAsB;GACtB,2BAA2B;GAC3B,wBAAwB;GACzB"}
@@ -3,11 +3,11 @@ import { TreeNodeAccessor } from "../render/accessor.js";
3
3
  import { ColumnSnapshot } from "./column_snapshot.js";
4
4
  import { ColumnSource } from "./column_snapshot_provider.js";
5
5
  import { ColumnSelectorInput } from "./column_selector.js";
6
- import { AxisQualification, PColumnSpec, PObjectId, PlRef, SUniversalPColumnId } from "@milaboratories/pl-model-common";
6
+ import { AxisQualification, DiscoverColumnsStepInfo, PColumnSpec, PObjectId, PlRef, SUniversalPColumnId } from "@milaboratories/pl-model-common";
7
7
 
8
8
  //#region src/columns/column_collection_builder.d.ts
9
9
  /** Subset of render context methods needed for spec frame operations. */
10
- type SpecFrameCtx = Pick<GlobalCfgRenderCtxMethods, "createSpecFrame" | "specFrameDiscoverColumns" | "specFrameDispose">;
10
+ type SpecFrameCtx = Pick<GlobalCfgRenderCtxMethods, "createSpecFrame" | "specFrameDiscoverColumns" | "disposeSpecFrame">;
11
11
  /** Options for plain collection findColumns. */
12
12
  interface FindColumnsOptions {
13
13
  /** Include columns matching these selectors. If omitted, includes all columns. */
@@ -48,6 +48,8 @@ interface ColumnMatch {
48
48
  readonly originalId: PObjectId;
49
49
  /** Match variants — different paths/qualifications that reach this column. */
50
50
  readonly variants: MatchVariant[];
51
+ /** Linker steps traversed to reach this hit; empty for direct matches. */
52
+ readonly path: DiscoverColumnsStepInfo[];
51
53
  }
52
54
  /** Qualifications needed for both query (already-integrated) columns and the hit column. */
53
55
  interface MatchQualifications {
@@ -94,14 +94,15 @@ var ColumnCollectionImpl = class {
94
94
  return this.toSnapshot(col);
95
95
  }
96
96
  findColumns(options) {
97
- const columnFilter = options?.include ? toMultiColumnSelectors(options.include) : [];
98
- let results = this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {
99
- columnFilter,
97
+ const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : void 0;
98
+ const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : void 0;
99
+ return this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {
100
+ includeColumns,
101
+ excludeColumns,
100
102
  axes: [],
103
+ maxHops: 0,
101
104
  constraints: PLAIN_CONSTRAINTS
102
105
  }).hits.map((hit) => this.columns.get(hit.hit.columnId)).filter((col) => col !== void 0).map((col) => this.toSnapshot(col));
103
- if (options?.exclude) throw new Error("Exclude filter is not yet implemented for plain ColumnCollection");
104
- return results;
105
106
  }
106
107
  toSnapshot(col) {
107
108
  return remapSnapshot(col.id, col);
@@ -136,11 +137,14 @@ var AnchoredColumnCollectionImpl = class {
136
137
  }
137
138
  findColumns(options) {
138
139
  const constraints = matchingModeToConstraints(options?.mode ?? "enrichment");
139
- const columnFilter = options?.include ? toMultiColumnSelectors(options.include) : [];
140
- let results = this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {
141
- columnFilter,
140
+ const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : void 0;
141
+ const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : void 0;
142
+ return this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {
143
+ includeColumns,
144
+ excludeColumns,
142
145
  constraints,
143
- axes: this.anchorAxes
146
+ axes: this.anchorAxes,
147
+ maxHops: options?.maxHops ?? 4
144
148
  }).hits.map((hit) => {
145
149
  const origId = hit.hit.columnId;
146
150
  const col = this.columns.get(origId);
@@ -152,11 +156,10 @@ var AnchoredColumnCollectionImpl = class {
152
156
  variants: hit.mappingVariants.map((v) => ({
153
157
  qualifications: v.qualifications,
154
158
  distinctiveQualifications: v.distinctiveQualifications
155
- }))
159
+ })),
160
+ path: hit.path
156
161
  };
157
162
  }).filter((m) => m !== void 0);
158
- if (options?.exclude) throw new Error("Exclude filter is not yet implemented for AnchoredColumnCollection");
159
- return results;
160
163
  }
161
164
  toSnapshot(universalId, col) {
162
165
  return remapSnapshot(universalId, col);
@@ -1 +1 @@
1
- {"version":3,"file":"column_collection_builder.js","names":[],"sources":["../../src/columns/column_collection_builder.ts"],"sourcesContent":["import type {\n AxisQualification,\n ColumnAxesWithQualifications,\n DiscoverColumnsConstraints,\n MultiColumnSelector,\n NativePObjectId,\n PColumnSpec,\n PlRef,\n PObjectId,\n SUniversalPColumnId,\n} from \"@milaboratories/pl-model-common\";\nimport { AnchoredIdDeriver, deriveNativeId, isPlRef } from \"@milaboratories/pl-model-common\";\nimport type { ColumnSelectorInput } from \"./column_selector\";\nimport { normalizeSelectors } from \"./column_selector\";\nimport { TreeNodeAccessor } from \"../render/accessor\";\nimport type { ColumnSnapshot } from \"./column_snapshot\";\nimport { createColumnSnapshot } from \"./column_snapshot\";\nimport type { ColumnSnapshotProvider, ColumnSource } from \"./column_snapshot_provider\";\nimport { ArrayColumnProvider, toColumnSnapshotProvider } from \"./column_snapshot_provider\";\n\nimport type { GlobalCfgRenderCtxMethods } from \"../render/internal\";\n\n/** Subset of render context methods needed for spec frame operations. */\ntype SpecFrameCtx = Pick<\n GlobalCfgRenderCtxMethods,\n \"createSpecFrame\" | \"specFrameDiscoverColumns\" | \"specFrameDispose\"\n>;\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?: ColumnSelectorInput;\n /** Exclude columns matching these selectors. */\n exclude?: ColumnSelectorInput;\n}\n\n// --- ColumnCollection ---\n\n/** Plain collection — no axis context, selector-based filtering only. */\nexport interface ColumnCollection {\n /** Point lookup by provider-native ID. */\n getColumn(id: PObjectId): undefined | ColumnSnapshot<PObjectId>;\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 {\n /** Point lookup by anchored ID. */\n getColumn(id: SUniversalPColumnId): undefined | ColumnSnapshot<SUniversalPColumnId>;\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<SUniversalPColumnId>;\n /** Provider-native ID — for lookups back to the source provider. */\n readonly originalId: PObjectId;\n /** Match variants — different paths/qualifications that reach this column. */\n readonly variants: MatchVariant[];\n}\n\n/** Qualifications needed for both query (already-integrated) columns and the hit column. */\nexport interface MatchQualifications {\n /** Qualifications for each query (already-integrated) column set. */\n readonly forQueries: AxisQualification[][];\n /** Qualifications for the hit column. */\n readonly forHit: AxisQualification[];\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}\n\n// --- Build options ---\n\nexport interface BuildOptions {\n allowPartialColumnList?: true;\n}\n\nexport interface AnchoredBuildOptions extends BuildOptions {\n anchors: Record<string, PlRef | PObjectId | PColumnSpec>;\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 specFrameCtx: SpecFrameCtx) {}\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 const hasAnchors = options !== undefined && \"anchors\" in options;\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 columnMap = this.collectColumns();\n\n if (hasAnchors) {\n const anchorSpecs = resolveAnchorSpecs(options.anchors, columnMap);\n const idDeriver = new AnchoredIdDeriver(anchorSpecs);\n\n return new AnchoredColumnCollectionImpl(this.specFrameCtx, {\n columns: columnMap,\n idDeriver,\n anchorSpecs,\n columnListComplete: allowPartial ? allComplete : false,\n });\n } else {\n return new ColumnCollectionImpl(this.specFrameCtx, {\n columns: columnMap,\n columnListComplete: allowPartial ? allComplete : false,\n });\n }\n }\n\n /**\n * Collect all columns from all providers, dedup by NativePObjectId.\n * First source wins.\n */\n private collectColumns(): Map<PObjectId, ColumnSnapshot<PObjectId>> {\n const seen = new Set<NativePObjectId>();\n const result = new Map<PObjectId, ColumnSnapshot<PObjectId>>();\n\n for (const provider of this.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.set(col.id, col);\n }\n }\n\n return result;\n }\n}\n\n// --- Permissive constraints for plain (non-anchored) filtering ---\n\nconst PLAIN_CONSTRAINTS: DiscoverColumnsConstraints = {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: true,\n allowSourceQualifications: false,\n allowHitQualifications: false,\n};\n\n// --- ColumnCollectionImpl ---\n\ninterface ColumnCollectionImplOptions {\n readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n readonly columnListComplete?: boolean;\n}\n\nclass ColumnCollectionImpl implements ColumnCollection {\n private readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly specFrameHandle: string;\n public readonly columnListComplete: boolean;\n\n constructor(\n private readonly ctx: SpecFrameCtx,\n options: ColumnCollectionImplOptions,\n ) {\n this.columns = options.columns;\n this.columnListComplete = options.columnListComplete ?? false;\n this.specFrameHandle = this.ctx.createSpecFrame(\n Array.from(this.columns.entries()).reduce(\n (acc, [id, col]) => ((acc[id] = col.spec), acc),\n {} as Record<string, PColumnSpec>,\n ),\n );\n }\n\n getColumn(id: PObjectId): undefined | ColumnSnapshot<PObjectId> {\n const col = this.columns.get(id);\n if (col === undefined) return undefined;\n return this.toSnapshot(col);\n }\n\n findColumns(options?: FindColumnsOptions): ColumnSnapshot<PObjectId>[] {\n const columnFilter = options?.include ? toMultiColumnSelectors(options.include) : [];\n\n const response = this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {\n columnFilter,\n axes: [],\n constraints: PLAIN_CONSTRAINTS,\n });\n\n // Map hits back to snapshots\n let results = response.hits\n .map((hit) => this.columns.get(hit.hit.columnId as PObjectId))\n .filter((col): col is ColumnSnapshot<PObjectId> => col !== undefined)\n .map((col) => this.toSnapshot(col));\n\n if (options?.exclude) {\n throw new Error(\"Exclude filter is not yet implemented for plain ColumnCollection\");\n }\n\n return results;\n }\n\n private toSnapshot(col: ColumnSnapshot<PObjectId>): ColumnSnapshot<PObjectId> {\n return remapSnapshot(col.id, col);\n }\n}\n\n// --- AnchoredColumnCollectionImpl ---\n\ninterface AnchoredColumnCollectionImplOptions extends ColumnCollectionImplOptions {\n readonly idDeriver: AnchoredIdDeriver;\n readonly anchorSpecs: Record<string, PColumnSpec>;\n}\n\nclass AnchoredColumnCollectionImpl implements AnchoredColumnCollection {\n private readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly idDeriver: AnchoredIdDeriver;\n private readonly specFrameHandle: string;\n private readonly anchorAxes: ColumnAxesWithQualifications[];\n /** Reverse lookup: SUniversalPColumnId → PObjectId */\n private readonly idToOriginal: Map<SUniversalPColumnId, PObjectId>;\n public readonly columnListComplete: boolean;\n\n constructor(\n private readonly ctx: SpecFrameCtx,\n options: AnchoredColumnCollectionImplOptions,\n ) {\n this.columns = options.columns;\n this.idDeriver = options.idDeriver;\n this.columnListComplete = options.columnListComplete ?? false;\n\n // Create spec frame from all collected columns\n this.specFrameHandle = this.ctx.createSpecFrame(\n Array.from(this.columns.entries()).reduce(\n (acc, [id, col]) => ((acc[id] = col.spec), acc),\n {} as Record<string, PColumnSpec>,\n ),\n );\n\n // Build anchor axes for discovery requests\n this.anchorAxes = Object.values(options.anchorSpecs).map((spec) => ({\n axesSpec: spec.axesSpec,\n qualifications: [],\n }));\n\n // Build reverse lookup map\n this.idToOriginal = new Map(\n Array.from(this.columns.entries()).map(\n ([id, col]) => [this.idDeriver.deriveS(col.spec), id] as const,\n ),\n );\n }\n\n getColumn(id: SUniversalPColumnId): undefined | ColumnSnapshot<SUniversalPColumnId> {\n const origId = this.idToOriginal.get(id);\n if (origId === undefined) return undefined;\n const col = this.columns.get(origId);\n if (col === undefined) return undefined;\n return this.toSnapshot(id, col);\n }\n\n findColumns(options?: AnchoredFindColumnsOptions): ColumnMatch[] {\n const mode = options?.mode ?? \"enrichment\";\n const constraints = matchingModeToConstraints(mode);\n const columnFilter = options?.include ? toMultiColumnSelectors(options.include) : [];\n\n const response = this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {\n columnFilter,\n constraints,\n axes: this.anchorAxes,\n });\n\n // Map hits back to ColumnMatch entries\n let results = response.hits\n .map((hit) => {\n const origId = hit.hit.columnId as PObjectId;\n const col = this.columns.get(origId);\n if (!col) return undefined;\n const universalId = this.idDeriver.deriveS(col.spec);\n return {\n column: this.toSnapshot(universalId, col),\n originalId: origId,\n variants: hit.mappingVariants.map(\n (v): MatchVariant => ({\n qualifications: v.qualifications,\n distinctiveQualifications: v.distinctiveQualifications,\n }),\n ),\n } satisfies ColumnMatch;\n })\n .filter((m): m is ColumnMatch => m !== undefined);\n\n if (options?.exclude) {\n throw new Error(\"Exclude filter is not yet implemented for AnchoredColumnCollection\");\n }\n\n return results;\n }\n\n private toSnapshot(\n universalId: SUniversalPColumnId,\n col: ColumnSnapshot<PObjectId>,\n ): ColumnSnapshot<SUniversalPColumnId> {\n return remapSnapshot(universalId, col);\n }\n}\n\n// --- Shared snapshot helpers ---\n\n/** Create a new snapshot with a different ID, preserving data accessors. */\nfunction remapSnapshot<Id extends PObjectId>(\n id: Id,\n col: ColumnSnapshot<PObjectId>,\n): ColumnSnapshot<Id> {\n return createColumnSnapshot(id, col.spec, col.dataStatus, col.data);\n}\n\n/** Normalize SDK ColumnSelectorInput to MultiColumnSelector[]. */\nfunction toMultiColumnSelectors(input: ColumnSelectorInput): MultiColumnSelector[] {\n return normalizeSelectors(input);\n}\n\n// --- Anchor resolution ---\n\n/**\n * Resolve each anchor value to a PColumnSpec.\n * - PColumnSpec: used directly\n * - PObjectId (string): looked up in the collected column map\n * - PlRef: not supported at this level — caller must resolve before building\n */\nfunction resolveAnchorSpecs(\n anchors: Record<string, PlRef | PObjectId | PColumnSpec>,\n columnMap: Map<PObjectId, ColumnSnapshot<PObjectId>>,\n): Record<string, PColumnSpec> {\n const result: Record<string, PColumnSpec> = {};\n for (const [key, anchor] of Object.entries(anchors)) {\n if (typeof anchor === \"string\") {\n // PObjectId — look up in collected columns\n const col = columnMap.get(anchor as PObjectId);\n if (!col) throw new Error(`Anchor \"${key}\": column with id \"${anchor}\" not found in sources`);\n result[key] = col.spec;\n } else if (isPlRef(anchor)) {\n throw new Error(\n `Anchor \"${key}\": PlRef anchors must be resolved to PColumnSpec before building. ` +\n `Use the column's spec directly or pass its PObjectId.`,\n );\n } else {\n // PColumnSpec\n result[key] = anchor;\n }\n }\n return result;\n}\n\n// --- MatchingMode → DiscoverColumnsConstraints ---\n\nfunction matchingModeToConstraints(mode: MatchingMode): DiscoverColumnsConstraints {\n switch (mode) {\n case \"enrichment\":\n return {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: true,\n allowSourceQualifications: false,\n allowHitQualifications: false,\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 ColumnAxesWithQualifications,\n DiscoverColumnsConstraints,\n DiscoverColumnsStepInfo,\n MultiColumnSelector,\n NativePObjectId,\n PColumnSpec,\n PlRef,\n PObjectId,\n SUniversalPColumnId,\n} from \"@milaboratories/pl-model-common\";\nimport { AnchoredIdDeriver, deriveNativeId, isPlRef } from \"@milaboratories/pl-model-common\";\nimport type { ColumnSelectorInput } from \"./column_selector\";\nimport { normalizeSelectors } from \"./column_selector\";\nimport { TreeNodeAccessor } from \"../render/accessor\";\nimport type { ColumnSnapshot } from \"./column_snapshot\";\nimport { createColumnSnapshot } from \"./column_snapshot\";\nimport type { ColumnSnapshotProvider, ColumnSource } from \"./column_snapshot_provider\";\nimport { ArrayColumnProvider, toColumnSnapshotProvider } from \"./column_snapshot_provider\";\n\nimport type { GlobalCfgRenderCtxMethods } from \"../render/internal\";\n\n/** Subset of render context methods needed for spec frame operations. */\ntype SpecFrameCtx = Pick<\n GlobalCfgRenderCtxMethods,\n \"createSpecFrame\" | \"specFrameDiscoverColumns\" | \"disposeSpecFrame\"\n>;\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?: ColumnSelectorInput;\n /** Exclude columns matching these selectors. */\n exclude?: ColumnSelectorInput;\n}\n\n// --- ColumnCollection ---\n\n/** Plain collection — no axis context, selector-based filtering only. */\nexport interface ColumnCollection {\n /** Point lookup by provider-native ID. */\n getColumn(id: PObjectId): undefined | ColumnSnapshot<PObjectId>;\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 {\n /** Point lookup by anchored ID. */\n getColumn(id: SUniversalPColumnId): undefined | ColumnSnapshot<SUniversalPColumnId>;\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<SUniversalPColumnId>;\n /** Provider-native ID — for lookups back to the source provider. */\n readonly originalId: PObjectId;\n /** Match variants — different paths/qualifications that reach this column. */\n readonly variants: MatchVariant[];\n /** Linker steps traversed to reach this hit; empty for direct matches. */\n readonly path: DiscoverColumnsStepInfo[];\n}\n\n/** Qualifications needed for both query (already-integrated) columns and the hit column. */\nexport interface MatchQualifications {\n /** Qualifications for each query (already-integrated) column set. */\n readonly forQueries: AxisQualification[][];\n /** Qualifications for the hit column. */\n readonly forHit: AxisQualification[];\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}\n\n// --- Build options ---\n\nexport interface BuildOptions {\n allowPartialColumnList?: true;\n}\n\nexport interface AnchoredBuildOptions extends BuildOptions {\n anchors: Record<string, PlRef | PObjectId | PColumnSpec>;\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 specFrameCtx: SpecFrameCtx) {}\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 const hasAnchors = options !== undefined && \"anchors\" in options;\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 columnMap = this.collectColumns();\n\n if (hasAnchors) {\n const anchorSpecs = resolveAnchorSpecs(options.anchors, columnMap);\n const idDeriver = new AnchoredIdDeriver(anchorSpecs);\n\n return new AnchoredColumnCollectionImpl(this.specFrameCtx, {\n columns: columnMap,\n idDeriver,\n anchorSpecs,\n columnListComplete: allowPartial ? allComplete : false,\n });\n } else {\n return new ColumnCollectionImpl(this.specFrameCtx, {\n columns: columnMap,\n columnListComplete: allowPartial ? allComplete : false,\n });\n }\n }\n\n /**\n * Collect all columns from all providers, dedup by NativePObjectId.\n * First source wins.\n */\n private collectColumns(): Map<PObjectId, ColumnSnapshot<PObjectId>> {\n const seen = new Set<NativePObjectId>();\n const result = new Map<PObjectId, ColumnSnapshot<PObjectId>>();\n\n for (const provider of this.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.set(col.id, col);\n }\n }\n\n return result;\n }\n}\n\n// --- Permissive constraints for plain (non-anchored) filtering ---\n\nconst PLAIN_CONSTRAINTS: DiscoverColumnsConstraints = {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: true,\n allowSourceQualifications: false,\n allowHitQualifications: false,\n};\n\n// --- ColumnCollectionImpl ---\n\ninterface ColumnCollectionImplOptions {\n readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n readonly columnListComplete?: boolean;\n}\n\nclass ColumnCollectionImpl implements ColumnCollection {\n private readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly specFrameHandle: string;\n public readonly columnListComplete: boolean;\n\n constructor(\n private readonly ctx: SpecFrameCtx,\n options: ColumnCollectionImplOptions,\n ) {\n this.columns = options.columns;\n this.columnListComplete = options.columnListComplete ?? false;\n this.specFrameHandle = this.ctx.createSpecFrame(\n Array.from(this.columns.entries()).reduce(\n (acc, [id, col]) => ((acc[id] = col.spec), acc),\n {} as Record<string, PColumnSpec>,\n ),\n );\n }\n\n getColumn(id: PObjectId): undefined | ColumnSnapshot<PObjectId> {\n const col = this.columns.get(id);\n if (col === undefined) return undefined;\n return this.toSnapshot(col);\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.ctx.specFrameDiscoverColumns(this.specFrameHandle, {\n includeColumns,\n excludeColumns,\n axes: [],\n maxHops: 0,\n constraints: PLAIN_CONSTRAINTS,\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 .map((col) => this.toSnapshot(col));\n\n return results;\n }\n\n private toSnapshot(col: ColumnSnapshot<PObjectId>): ColumnSnapshot<PObjectId> {\n return remapSnapshot(col.id, col);\n }\n}\n\n// --- AnchoredColumnCollectionImpl ---\n\ninterface AnchoredColumnCollectionImplOptions extends ColumnCollectionImplOptions {\n readonly idDeriver: AnchoredIdDeriver;\n readonly anchorSpecs: Record<string, PColumnSpec>;\n}\n\nclass AnchoredColumnCollectionImpl implements AnchoredColumnCollection {\n private readonly columns: Map<PObjectId, ColumnSnapshot<PObjectId>>;\n private readonly idDeriver: AnchoredIdDeriver;\n private readonly specFrameHandle: string;\n private readonly anchorAxes: ColumnAxesWithQualifications[];\n /** Reverse lookup: SUniversalPColumnId → PObjectId */\n private readonly idToOriginal: Map<SUniversalPColumnId, PObjectId>;\n public readonly columnListComplete: boolean;\n\n constructor(\n private readonly ctx: SpecFrameCtx,\n options: AnchoredColumnCollectionImplOptions,\n ) {\n this.columns = options.columns;\n this.idDeriver = options.idDeriver;\n this.columnListComplete = options.columnListComplete ?? false;\n\n // Create spec frame from all collected columns\n this.specFrameHandle = this.ctx.createSpecFrame(\n Array.from(this.columns.entries()).reduce(\n (acc, [id, col]) => ((acc[id] = col.spec), acc),\n {} as Record<string, PColumnSpec>,\n ),\n );\n\n // Build anchor axes for discovery requests\n this.anchorAxes = Object.values(options.anchorSpecs).map((spec) => ({\n axesSpec: spec.axesSpec,\n qualifications: [],\n }));\n\n // Build reverse lookup map\n this.idToOriginal = new Map(\n Array.from(this.columns.entries()).map(\n ([id, col]) => [this.idDeriver.deriveS(col.spec), id] as const,\n ),\n );\n }\n\n getColumn(id: SUniversalPColumnId): undefined | ColumnSnapshot<SUniversalPColumnId> {\n const origId = this.idToOriginal.get(id);\n if (origId === undefined) return undefined;\n const col = this.columns.get(origId);\n if (col === undefined) return undefined;\n return this.toSnapshot(id, col);\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\n const response = this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {\n includeColumns,\n excludeColumns,\n constraints,\n axes: this.anchorAxes,\n maxHops: options?.maxHops ?? 4,\n });\n\n // Map hits back to ColumnMatch entries\n const results = response.hits\n .map((hit) => {\n const origId = hit.hit.columnId as PObjectId;\n const col = this.columns.get(origId);\n if (!col) return undefined;\n const universalId = this.idDeriver.deriveS(col.spec);\n return {\n column: this.toSnapshot(universalId, col),\n originalId: origId,\n variants: hit.mappingVariants.map(\n (v): MatchVariant => ({\n qualifications: v.qualifications,\n distinctiveQualifications: v.distinctiveQualifications,\n }),\n ),\n path: hit.path,\n } satisfies ColumnMatch;\n })\n .filter((m): m is ColumnMatch => m !== undefined);\n\n return results;\n }\n\n private toSnapshot(\n universalId: SUniversalPColumnId,\n col: ColumnSnapshot<PObjectId>,\n ): ColumnSnapshot<SUniversalPColumnId> {\n return remapSnapshot(universalId, col);\n }\n}\n\n// --- Shared snapshot helpers ---\n\n/** Create a new snapshot with a different ID, preserving data accessors. */\nfunction remapSnapshot<Id extends PObjectId>(\n id: Id,\n col: ColumnSnapshot<PObjectId>,\n): ColumnSnapshot<Id> {\n return createColumnSnapshot(id, col.spec, col.dataStatus, col.data);\n}\n\n/** Normalize SDK ColumnSelectorInput to MultiColumnSelector[]. */\nfunction toMultiColumnSelectors(input: ColumnSelectorInput): MultiColumnSelector[] {\n return normalizeSelectors(input);\n}\n\n// --- Anchor resolution ---\n\n/**\n * Resolve each anchor value to a PColumnSpec.\n * - PColumnSpec: used directly\n * - PObjectId (string): looked up in the collected column map\n * - PlRef: not supported at this level — caller must resolve before building\n */\nfunction resolveAnchorSpecs(\n anchors: Record<string, PlRef | PObjectId | PColumnSpec>,\n columnMap: Map<PObjectId, ColumnSnapshot<PObjectId>>,\n): Record<string, PColumnSpec> {\n const result: Record<string, PColumnSpec> = {};\n for (const [key, anchor] of Object.entries(anchors)) {\n if (typeof anchor === \"string\") {\n // PObjectId — look up in collected columns\n const col = columnMap.get(anchor as PObjectId);\n if (!col) throw new Error(`Anchor \"${key}\": column with id \"${anchor}\" not found in sources`);\n result[key] = col.spec;\n } else if (isPlRef(anchor)) {\n throw new Error(\n `Anchor \"${key}\": PlRef anchors must be resolved to PColumnSpec before building. ` +\n `Use the column's spec directly or pass its PObjectId.`,\n );\n } else {\n // PColumnSpec\n result[key] = anchor;\n }\n }\n return result;\n}\n\n// --- MatchingMode → DiscoverColumnsConstraints ---\n\nfunction matchingModeToConstraints(mode: MatchingMode): DiscoverColumnsConstraints {\n switch (mode) {\n case \"enrichment\":\n return {\n allowFloatingSourceAxes: true,\n allowFloatingHitAxes: true,\n allowSourceQualifications: false,\n allowHitQualifications: false,\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 +1 @@
1
- {"version":3,"file":"column_selector.cjs","names":[],"sources":["../../src/columns/column_selector.ts"],"sourcesContent":["import type {\n MultiAxisSelector,\n MultiColumnSelector,\n PColumnSpec,\n StringMatcher,\n ValueType,\n} from \"@milaboratories/pl-model-common\";\n\nexport type { StringMatcher } from \"@milaboratories/pl-model-common\";\n\n// --- Relaxed types ---\n\n/** Relaxed string matcher input: plain string, single matcher, or array of mixed. */\nexport type RelaxedStringMatchers = string | StringMatcher | (string | StringMatcher)[];\n\n/** Relaxed record matcher: values can be plain strings or relaxed matchers. */\nexport type RelaxedRecord = Record<string, RelaxedStringMatchers>;\n\n/** Relaxed axis selector — accepts plain strings where strict requires StringMatcher[]. */\nexport interface RelaxedAxisSelector {\n name?: RelaxedStringMatchers;\n type?: ValueType | ValueType[];\n domain?: RelaxedRecord;\n contextDomain?: RelaxedRecord;\n annotations?: RelaxedRecord;\n}\n\n/** Relaxed column selector — convenient hand-written form. */\nexport interface RelaxedColumnSelector {\n name?: RelaxedStringMatchers;\n type?: ValueType | ValueType[];\n domain?: RelaxedRecord;\n contextDomain?: RelaxedRecord;\n annotations?: RelaxedRecord;\n axes?: RelaxedAxisSelector[];\n partialAxesMatch?: boolean;\n}\n\n/** Input that normalizes to ColumnSelector[]. */\nexport type ColumnSelectorInput = RelaxedColumnSelector | RelaxedColumnSelector[];\n\n// --- Normalization ---\n\nfunction normalizeStringMatchers(input: RelaxedStringMatchers): StringMatcher[] {\n if (typeof input === \"string\") return [{ type: \"regex\", value: input }];\n if (!Array.isArray(input)) return [input];\n return input.map((v) =>\n typeof v === \"string\" ? ({ type: \"regex\", value: v } satisfies StringMatcher) : v,\n );\n}\n\nfunction normalizeRecord(input: RelaxedRecord): Record<string, StringMatcher[]> {\n const result: Record<string, StringMatcher[]> = {};\n for (const [key, value] of Object.entries(input)) {\n result[key] = normalizeStringMatchers(value);\n }\n return result;\n}\n\nfunction normalizeTypes(input: ValueType | ValueType[]): ValueType[] {\n return Array.isArray(input) ? input : [input];\n}\n\ntype Mutable<T> = { -readonly [K in keyof T]: T[K] };\n\nfunction normalizeAxisSelector(input: RelaxedAxisSelector): MultiAxisSelector {\n const result: Mutable<MultiAxisSelector> = {};\n if (input.name !== undefined) result.name = normalizeStringMatchers(input.name);\n if (input.type !== undefined) result.type = normalizeTypes(input.type);\n if (input.domain !== undefined) result.domain = normalizeRecord(input.domain);\n if (input.contextDomain !== undefined)\n result.contextDomain = normalizeRecord(input.contextDomain);\n if (input.annotations !== undefined) result.annotations = normalizeRecord(input.annotations);\n return result;\n}\n\n/** Normalize relaxed input to strict ColumnSelector[]. */\nexport function normalizeSelectors(input: ColumnSelectorInput): MultiColumnSelector[] {\n const arr = Array.isArray(input) ? input : [input];\n return arr.map(normalizeSingleSelector);\n}\n\nfunction normalizeSingleSelector(input: RelaxedColumnSelector): MultiColumnSelector {\n const result: Mutable<MultiColumnSelector> = {};\n if (input.name !== undefined) result.name = normalizeStringMatchers(input.name);\n if (input.type !== undefined) result.type = normalizeTypes(input.type);\n if (input.domain !== undefined) result.domain = normalizeRecord(input.domain);\n if (input.contextDomain !== undefined)\n result.contextDomain = normalizeRecord(input.contextDomain);\n if (input.annotations !== undefined) result.annotations = normalizeRecord(input.annotations);\n if (input.axes !== undefined) result.axes = input.axes.map(normalizeAxisSelector);\n if (input.partialAxesMatch !== undefined) result.partialAxesMatch = input.partialAxesMatch;\n return result;\n}\n\n// --- Matching ---\n\nfunction matchStringValue(value: string, matchers: StringMatcher[]): boolean {\n return matchers.some((m) => {\n if (m.type === \"exact\") return value === m.value;\n return new RegExp(`^(?:${m.value})$`).test(value);\n });\n}\n\nfunction matchRecordField(\n actual: Record<string, string> | undefined,\n required: Record<string, StringMatcher[]>,\n): boolean {\n const record = actual ?? {};\n for (const [key, matchers] of Object.entries(required)) {\n const value = record[key];\n if (value === undefined) return false;\n if (!matchStringValue(value, matchers)) return false;\n }\n return true;\n}\n\n/** Get combined domain: column's own domain merged with all axis domains. */\nfunction getCombinedDomain(spec: PColumnSpec): Record<string, string> {\n const result: Record<string, string> = {};\n if (spec.domain) Object.assign(result, spec.domain);\n for (const axis of spec.axesSpec) {\n if (axis.domain) Object.assign(result, axis.domain);\n }\n return result;\n}\n\n/** Get combined context domain: column's own contextDomain merged with all axis contextDomains. */\nfunction getCombinedContextDomain(spec: PColumnSpec): Record<string, string> {\n const result: Record<string, string> = {};\n if (spec.contextDomain) Object.assign(result, spec.contextDomain);\n for (const axis of spec.axesSpec) {\n if (\"contextDomain\" in axis && axis.contextDomain) Object.assign(result, axis.contextDomain);\n }\n return result;\n}\n\nfunction matchAxisSelector(\n axis: PColumnSpec[\"axesSpec\"][number],\n selector: MultiAxisSelector,\n): boolean {\n if (selector.name !== undefined && !matchStringValue(axis.name, selector.name)) return false;\n if (selector.type !== undefined && !selector.type.includes(axis.type as ValueType)) return false;\n if (selector.domain !== undefined && !matchRecordField(axis.domain, selector.domain))\n return false;\n if (\n selector.contextDomain !== undefined &&\n !matchRecordField(\n \"contextDomain\" in axis ? (axis.contextDomain as Record<string, string>) : undefined,\n selector.contextDomain,\n )\n )\n return false;\n if (\n selector.annotations !== undefined &&\n !matchRecordField(axis.annotations, selector.annotations)\n )\n return false;\n return true;\n}\n\n/** Check if a PColumnSpec matches a single strict ColumnSelector. */\nexport function matchColumn(spec: PColumnSpec, selector: MultiColumnSelector): boolean {\n if (selector.name !== undefined && !matchStringValue(spec.name, selector.name)) return false;\n if (selector.type !== undefined && !selector.type.includes(spec.valueType)) return false;\n\n if (selector.domain !== undefined) {\n const combined = getCombinedDomain(spec);\n if (!matchRecordField(combined, selector.domain)) return false;\n }\n\n if (selector.contextDomain !== undefined) {\n const combined = getCombinedContextDomain(spec);\n if (!matchRecordField(combined, selector.contextDomain)) return false;\n }\n\n if (selector.annotations !== undefined) {\n if (!matchRecordField(spec.annotations, selector.annotations)) return false;\n }\n\n if (selector.axes !== undefined) {\n const partialMatch = selector.partialAxesMatch ?? true;\n if (partialMatch) {\n for (const axisSel of selector.axes) {\n if (!spec.axesSpec.some((axis) => matchAxisSelector(axis, axisSel))) return false;\n }\n } else {\n if (spec.axesSpec.length !== selector.axes.length) return false;\n for (let i = 0; i < selector.axes.length; i++) {\n if (!matchAxisSelector(spec.axesSpec[i], selector.axes[i])) return false;\n }\n }\n }\n\n return true;\n}\n\n/** Check if a PColumnSpec matches any of the selectors (OR across array). */\nexport function matchColumnSelectors(selectors: MultiColumnSelector[], spec: PColumnSpec): boolean {\n return selectors.some((sel) => matchColumn(spec, sel));\n}\n\n/**\n * Convert selector input to a predicate function.\n * Normalizes relaxed form, then returns a function that OR-matches.\n */\nexport function columnSelectorsToPredicate(\n input: ColumnSelectorInput,\n): (spec: PColumnSpec) => boolean {\n const selectors = normalizeSelectors(input);\n return (spec) => matchColumnSelectors(selectors, spec);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"column_selector.cjs","names":[],"sources":["../../src/columns/column_selector.ts"],"sourcesContent":["import type {\n AxisValueType,\n ColumnValueType,\n MultiAxisSelector,\n MultiColumnSelector,\n PColumnSpec,\n StringMatcher,\n} from \"@milaboratories/pl-model-common\";\n\nexport type { StringMatcher } from \"@milaboratories/pl-model-common\";\n\n// --- Relaxed types ---\n\n/** Relaxed string matcher input: plain string, single matcher, or array of mixed. */\nexport type RelaxedStringMatchers = string | StringMatcher | (string | StringMatcher)[];\n\n/** Relaxed record matcher: values can be plain strings or relaxed matchers. */\nexport type RelaxedRecord = Record<string, RelaxedStringMatchers>;\n\n/** Relaxed axis selector — accepts plain strings where strict requires StringMatcher[]. */\nexport interface RelaxedAxisSelector {\n name?: RelaxedStringMatchers;\n type?: AxisValueType | AxisValueType[];\n domain?: RelaxedRecord;\n contextDomain?: RelaxedRecord;\n annotations?: RelaxedRecord;\n}\n\n/** Relaxed column selector — convenient hand-written form. */\nexport interface RelaxedColumnSelector {\n name?: RelaxedStringMatchers;\n type?: ColumnValueType | ColumnValueType[];\n domain?: RelaxedRecord;\n contextDomain?: RelaxedRecord;\n annotations?: RelaxedRecord;\n axes?: RelaxedAxisSelector[];\n partialAxesMatch?: boolean;\n}\n\n/** Input that normalizes to ColumnSelector[]. */\nexport type ColumnSelectorInput = RelaxedColumnSelector | RelaxedColumnSelector[];\n\n// --- Normalization ---\n\nfunction normalizeStringMatchers(input: RelaxedStringMatchers): StringMatcher[] {\n if (typeof input === \"string\") return [{ type: \"regex\", value: input }];\n if (!Array.isArray(input)) return [input];\n return input.map((v) =>\n typeof v === \"string\" ? ({ type: \"regex\", value: v } satisfies StringMatcher) : v,\n );\n}\n\nfunction normalizeRecord(input: RelaxedRecord): Record<string, StringMatcher[]> {\n const result: Record<string, StringMatcher[]> = {};\n for (const [key, value] of Object.entries(input)) {\n result[key] = normalizeStringMatchers(value);\n }\n return result;\n}\n\nfunction normalizeTypes<T>(input: T | T[]): T[] {\n return Array.isArray(input) ? input : [input];\n}\n\ntype Mutable<T> = { -readonly [K in keyof T]: T[K] };\n\nfunction normalizeAxisSelector(input: RelaxedAxisSelector): MultiAxisSelector {\n const result: Mutable<MultiAxisSelector> = {};\n if (input.name !== undefined) result.name = normalizeStringMatchers(input.name);\n if (input.type !== undefined) result.type = normalizeTypes(input.type);\n if (input.domain !== undefined) result.domain = normalizeRecord(input.domain);\n if (input.contextDomain !== undefined)\n result.contextDomain = normalizeRecord(input.contextDomain);\n if (input.annotations !== undefined) result.annotations = normalizeRecord(input.annotations);\n return result;\n}\n\n/** Normalize relaxed input to strict ColumnSelector[]. */\nexport function normalizeSelectors(input: ColumnSelectorInput): MultiColumnSelector[] {\n const arr = Array.isArray(input) ? input : [input];\n return arr.map(normalizeSingleSelector);\n}\n\nfunction normalizeSingleSelector(input: RelaxedColumnSelector): MultiColumnSelector {\n const result: Mutable<MultiColumnSelector> = {};\n if (input.name !== undefined) result.name = normalizeStringMatchers(input.name);\n if (input.type !== undefined) result.type = normalizeTypes(input.type);\n if (input.domain !== undefined) result.domain = normalizeRecord(input.domain);\n if (input.contextDomain !== undefined)\n result.contextDomain = normalizeRecord(input.contextDomain);\n if (input.annotations !== undefined) result.annotations = normalizeRecord(input.annotations);\n if (input.axes !== undefined) result.axes = input.axes.map(normalizeAxisSelector);\n if (input.partialAxesMatch !== undefined) result.partialAxesMatch = input.partialAxesMatch;\n return result;\n}\n\n// --- Matching ---\n\nfunction matchStringValue(value: string, matchers: StringMatcher[]): boolean {\n return matchers.some((m) => {\n if (m.type === \"exact\") return value === m.value;\n return new RegExp(`^(?:${m.value})$`).test(value);\n });\n}\n\nfunction matchRecordField(\n actual: Record<string, string> | undefined,\n required: Record<string, StringMatcher[]>,\n): boolean {\n const record = actual ?? {};\n for (const [key, matchers] of Object.entries(required)) {\n const value = record[key];\n if (value === undefined) return false;\n if (!matchStringValue(value, matchers)) return false;\n }\n return true;\n}\n\n/** Get combined domain: column's own domain merged with all axis domains. */\nfunction getCombinedDomain(spec: PColumnSpec): Record<string, string> {\n const result: Record<string, string> = {};\n if (spec.domain) Object.assign(result, spec.domain);\n for (const axis of spec.axesSpec) {\n if (axis.domain) Object.assign(result, axis.domain);\n }\n return result;\n}\n\n/** Get combined context domain: column's own contextDomain merged with all axis contextDomains. */\nfunction getCombinedContextDomain(spec: PColumnSpec): Record<string, string> {\n const result: Record<string, string> = {};\n if (spec.contextDomain) Object.assign(result, spec.contextDomain);\n for (const axis of spec.axesSpec) {\n if (\"contextDomain\" in axis && axis.contextDomain) Object.assign(result, axis.contextDomain);\n }\n return result;\n}\n\nfunction matchAxisSelector(\n axis: PColumnSpec[\"axesSpec\"][number],\n selector: MultiAxisSelector,\n): boolean {\n if (selector.name !== undefined && !matchStringValue(axis.name, selector.name)) return false;\n if (selector.type !== undefined && !selector.type.includes(axis.type)) return false;\n if (selector.domain !== undefined && !matchRecordField(axis.domain, selector.domain))\n return false;\n if (\n selector.contextDomain !== undefined &&\n !matchRecordField(\n \"contextDomain\" in axis ? (axis.contextDomain as Record<string, string>) : undefined,\n selector.contextDomain,\n )\n )\n return false;\n if (\n selector.annotations !== undefined &&\n !matchRecordField(axis.annotations, selector.annotations)\n )\n return false;\n return true;\n}\n\n/** Check if a PColumnSpec matches a single strict ColumnSelector. */\nexport function matchColumn(spec: PColumnSpec, selector: MultiColumnSelector): boolean {\n if (selector.name !== undefined && !matchStringValue(spec.name, selector.name)) return false;\n if (selector.type !== undefined && !selector.type.includes(spec.valueType)) return false;\n\n if (selector.domain !== undefined) {\n const combined = getCombinedDomain(spec);\n if (!matchRecordField(combined, selector.domain)) return false;\n }\n\n if (selector.contextDomain !== undefined) {\n const combined = getCombinedContextDomain(spec);\n if (!matchRecordField(combined, selector.contextDomain)) return false;\n }\n\n if (selector.annotations !== undefined) {\n if (!matchRecordField(spec.annotations, selector.annotations)) return false;\n }\n\n if (selector.axes !== undefined) {\n const partialMatch = selector.partialAxesMatch ?? true;\n if (partialMatch) {\n for (const axisSel of selector.axes) {\n if (!spec.axesSpec.some((axis) => matchAxisSelector(axis, axisSel))) return false;\n }\n } else {\n if (spec.axesSpec.length !== selector.axes.length) return false;\n for (let i = 0; i < selector.axes.length; i++) {\n if (!matchAxisSelector(spec.axesSpec[i], selector.axes[i])) return false;\n }\n }\n }\n\n return true;\n}\n\n/** Check if a PColumnSpec matches any of the selectors (OR across array). */\nexport function matchColumnSelectors(selectors: MultiColumnSelector[], spec: PColumnSpec): boolean {\n return selectors.some((sel) => matchColumn(spec, sel));\n}\n\n/**\n * Convert selector input to a predicate function.\n * Normalizes relaxed form, then returns a function that OR-matches.\n */\nexport function columnSelectorsToPredicate(\n input: ColumnSelectorInput,\n): (spec: PColumnSpec) => boolean {\n const selectors = normalizeSelectors(input);\n return (spec) => matchColumnSelectors(selectors, spec);\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { MultiColumnSelector, PColumnSpec, StringMatcher, StringMatcher as StringMatcher$1, ValueType } from "@milaboratories/pl-model-common";
1
+ import { AxisValueType, ColumnValueType, MultiColumnSelector, PColumnSpec, StringMatcher, StringMatcher as StringMatcher$1 } from "@milaboratories/pl-model-common";
2
2
 
3
3
  //#region src/columns/column_selector.d.ts
4
4
  /** Relaxed string matcher input: plain string, single matcher, or array of mixed. */
@@ -8,7 +8,7 @@ type RelaxedRecord = Record<string, RelaxedStringMatchers>;
8
8
  /** Relaxed axis selector — accepts plain strings where strict requires StringMatcher[]. */
9
9
  interface RelaxedAxisSelector {
10
10
  name?: RelaxedStringMatchers;
11
- type?: ValueType | ValueType[];
11
+ type?: AxisValueType | AxisValueType[];
12
12
  domain?: RelaxedRecord;
13
13
  contextDomain?: RelaxedRecord;
14
14
  annotations?: RelaxedRecord;
@@ -16,7 +16,7 @@ interface RelaxedAxisSelector {
16
16
  /** Relaxed column selector — convenient hand-written form. */
17
17
  interface RelaxedColumnSelector {
18
18
  name?: RelaxedStringMatchers;
19
- type?: ValueType | ValueType[];
19
+ type?: ColumnValueType | ColumnValueType[];
20
20
  domain?: RelaxedRecord;
21
21
  contextDomain?: RelaxedRecord;
22
22
  annotations?: RelaxedRecord;
@@ -1 +1 @@
1
- {"version":3,"file":"column_selector.js","names":[],"sources":["../../src/columns/column_selector.ts"],"sourcesContent":["import type {\n MultiAxisSelector,\n MultiColumnSelector,\n PColumnSpec,\n StringMatcher,\n ValueType,\n} from \"@milaboratories/pl-model-common\";\n\nexport type { StringMatcher } from \"@milaboratories/pl-model-common\";\n\n// --- Relaxed types ---\n\n/** Relaxed string matcher input: plain string, single matcher, or array of mixed. */\nexport type RelaxedStringMatchers = string | StringMatcher | (string | StringMatcher)[];\n\n/** Relaxed record matcher: values can be plain strings or relaxed matchers. */\nexport type RelaxedRecord = Record<string, RelaxedStringMatchers>;\n\n/** Relaxed axis selector — accepts plain strings where strict requires StringMatcher[]. */\nexport interface RelaxedAxisSelector {\n name?: RelaxedStringMatchers;\n type?: ValueType | ValueType[];\n domain?: RelaxedRecord;\n contextDomain?: RelaxedRecord;\n annotations?: RelaxedRecord;\n}\n\n/** Relaxed column selector — convenient hand-written form. */\nexport interface RelaxedColumnSelector {\n name?: RelaxedStringMatchers;\n type?: ValueType | ValueType[];\n domain?: RelaxedRecord;\n contextDomain?: RelaxedRecord;\n annotations?: RelaxedRecord;\n axes?: RelaxedAxisSelector[];\n partialAxesMatch?: boolean;\n}\n\n/** Input that normalizes to ColumnSelector[]. */\nexport type ColumnSelectorInput = RelaxedColumnSelector | RelaxedColumnSelector[];\n\n// --- Normalization ---\n\nfunction normalizeStringMatchers(input: RelaxedStringMatchers): StringMatcher[] {\n if (typeof input === \"string\") return [{ type: \"regex\", value: input }];\n if (!Array.isArray(input)) return [input];\n return input.map((v) =>\n typeof v === \"string\" ? ({ type: \"regex\", value: v } satisfies StringMatcher) : v,\n );\n}\n\nfunction normalizeRecord(input: RelaxedRecord): Record<string, StringMatcher[]> {\n const result: Record<string, StringMatcher[]> = {};\n for (const [key, value] of Object.entries(input)) {\n result[key] = normalizeStringMatchers(value);\n }\n return result;\n}\n\nfunction normalizeTypes(input: ValueType | ValueType[]): ValueType[] {\n return Array.isArray(input) ? input : [input];\n}\n\ntype Mutable<T> = { -readonly [K in keyof T]: T[K] };\n\nfunction normalizeAxisSelector(input: RelaxedAxisSelector): MultiAxisSelector {\n const result: Mutable<MultiAxisSelector> = {};\n if (input.name !== undefined) result.name = normalizeStringMatchers(input.name);\n if (input.type !== undefined) result.type = normalizeTypes(input.type);\n if (input.domain !== undefined) result.domain = normalizeRecord(input.domain);\n if (input.contextDomain !== undefined)\n result.contextDomain = normalizeRecord(input.contextDomain);\n if (input.annotations !== undefined) result.annotations = normalizeRecord(input.annotations);\n return result;\n}\n\n/** Normalize relaxed input to strict ColumnSelector[]. */\nexport function normalizeSelectors(input: ColumnSelectorInput): MultiColumnSelector[] {\n const arr = Array.isArray(input) ? input : [input];\n return arr.map(normalizeSingleSelector);\n}\n\nfunction normalizeSingleSelector(input: RelaxedColumnSelector): MultiColumnSelector {\n const result: Mutable<MultiColumnSelector> = {};\n if (input.name !== undefined) result.name = normalizeStringMatchers(input.name);\n if (input.type !== undefined) result.type = normalizeTypes(input.type);\n if (input.domain !== undefined) result.domain = normalizeRecord(input.domain);\n if (input.contextDomain !== undefined)\n result.contextDomain = normalizeRecord(input.contextDomain);\n if (input.annotations !== undefined) result.annotations = normalizeRecord(input.annotations);\n if (input.axes !== undefined) result.axes = input.axes.map(normalizeAxisSelector);\n if (input.partialAxesMatch !== undefined) result.partialAxesMatch = input.partialAxesMatch;\n return result;\n}\n\n// --- Matching ---\n\nfunction matchStringValue(value: string, matchers: StringMatcher[]): boolean {\n return matchers.some((m) => {\n if (m.type === \"exact\") return value === m.value;\n return new RegExp(`^(?:${m.value})$`).test(value);\n });\n}\n\nfunction matchRecordField(\n actual: Record<string, string> | undefined,\n required: Record<string, StringMatcher[]>,\n): boolean {\n const record = actual ?? {};\n for (const [key, matchers] of Object.entries(required)) {\n const value = record[key];\n if (value === undefined) return false;\n if (!matchStringValue(value, matchers)) return false;\n }\n return true;\n}\n\n/** Get combined domain: column's own domain merged with all axis domains. */\nfunction getCombinedDomain(spec: PColumnSpec): Record<string, string> {\n const result: Record<string, string> = {};\n if (spec.domain) Object.assign(result, spec.domain);\n for (const axis of spec.axesSpec) {\n if (axis.domain) Object.assign(result, axis.domain);\n }\n return result;\n}\n\n/** Get combined context domain: column's own contextDomain merged with all axis contextDomains. */\nfunction getCombinedContextDomain(spec: PColumnSpec): Record<string, string> {\n const result: Record<string, string> = {};\n if (spec.contextDomain) Object.assign(result, spec.contextDomain);\n for (const axis of spec.axesSpec) {\n if (\"contextDomain\" in axis && axis.contextDomain) Object.assign(result, axis.contextDomain);\n }\n return result;\n}\n\nfunction matchAxisSelector(\n axis: PColumnSpec[\"axesSpec\"][number],\n selector: MultiAxisSelector,\n): boolean {\n if (selector.name !== undefined && !matchStringValue(axis.name, selector.name)) return false;\n if (selector.type !== undefined && !selector.type.includes(axis.type as ValueType)) return false;\n if (selector.domain !== undefined && !matchRecordField(axis.domain, selector.domain))\n return false;\n if (\n selector.contextDomain !== undefined &&\n !matchRecordField(\n \"contextDomain\" in axis ? (axis.contextDomain as Record<string, string>) : undefined,\n selector.contextDomain,\n )\n )\n return false;\n if (\n selector.annotations !== undefined &&\n !matchRecordField(axis.annotations, selector.annotations)\n )\n return false;\n return true;\n}\n\n/** Check if a PColumnSpec matches a single strict ColumnSelector. */\nexport function matchColumn(spec: PColumnSpec, selector: MultiColumnSelector): boolean {\n if (selector.name !== undefined && !matchStringValue(spec.name, selector.name)) return false;\n if (selector.type !== undefined && !selector.type.includes(spec.valueType)) return false;\n\n if (selector.domain !== undefined) {\n const combined = getCombinedDomain(spec);\n if (!matchRecordField(combined, selector.domain)) return false;\n }\n\n if (selector.contextDomain !== undefined) {\n const combined = getCombinedContextDomain(spec);\n if (!matchRecordField(combined, selector.contextDomain)) return false;\n }\n\n if (selector.annotations !== undefined) {\n if (!matchRecordField(spec.annotations, selector.annotations)) return false;\n }\n\n if (selector.axes !== undefined) {\n const partialMatch = selector.partialAxesMatch ?? true;\n if (partialMatch) {\n for (const axisSel of selector.axes) {\n if (!spec.axesSpec.some((axis) => matchAxisSelector(axis, axisSel))) return false;\n }\n } else {\n if (spec.axesSpec.length !== selector.axes.length) return false;\n for (let i = 0; i < selector.axes.length; i++) {\n if (!matchAxisSelector(spec.axesSpec[i], selector.axes[i])) return false;\n }\n }\n }\n\n return true;\n}\n\n/** Check if a PColumnSpec matches any of the selectors (OR across array). */\nexport function matchColumnSelectors(selectors: MultiColumnSelector[], spec: PColumnSpec): boolean {\n return selectors.some((sel) => matchColumn(spec, sel));\n}\n\n/**\n * Convert selector input to a predicate function.\n * Normalizes relaxed form, then returns a function that OR-matches.\n */\nexport function columnSelectorsToPredicate(\n input: ColumnSelectorInput,\n): (spec: PColumnSpec) => boolean {\n const selectors = normalizeSelectors(input);\n return (spec) => matchColumnSelectors(selectors, spec);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"column_selector.js","names":[],"sources":["../../src/columns/column_selector.ts"],"sourcesContent":["import type {\n AxisValueType,\n ColumnValueType,\n MultiAxisSelector,\n MultiColumnSelector,\n PColumnSpec,\n StringMatcher,\n} from \"@milaboratories/pl-model-common\";\n\nexport type { StringMatcher } from \"@milaboratories/pl-model-common\";\n\n// --- Relaxed types ---\n\n/** Relaxed string matcher input: plain string, single matcher, or array of mixed. */\nexport type RelaxedStringMatchers = string | StringMatcher | (string | StringMatcher)[];\n\n/** Relaxed record matcher: values can be plain strings or relaxed matchers. */\nexport type RelaxedRecord = Record<string, RelaxedStringMatchers>;\n\n/** Relaxed axis selector — accepts plain strings where strict requires StringMatcher[]. */\nexport interface RelaxedAxisSelector {\n name?: RelaxedStringMatchers;\n type?: AxisValueType | AxisValueType[];\n domain?: RelaxedRecord;\n contextDomain?: RelaxedRecord;\n annotations?: RelaxedRecord;\n}\n\n/** Relaxed column selector — convenient hand-written form. */\nexport interface RelaxedColumnSelector {\n name?: RelaxedStringMatchers;\n type?: ColumnValueType | ColumnValueType[];\n domain?: RelaxedRecord;\n contextDomain?: RelaxedRecord;\n annotations?: RelaxedRecord;\n axes?: RelaxedAxisSelector[];\n partialAxesMatch?: boolean;\n}\n\n/** Input that normalizes to ColumnSelector[]. */\nexport type ColumnSelectorInput = RelaxedColumnSelector | RelaxedColumnSelector[];\n\n// --- Normalization ---\n\nfunction normalizeStringMatchers(input: RelaxedStringMatchers): StringMatcher[] {\n if (typeof input === \"string\") return [{ type: \"regex\", value: input }];\n if (!Array.isArray(input)) return [input];\n return input.map((v) =>\n typeof v === \"string\" ? ({ type: \"regex\", value: v } satisfies StringMatcher) : v,\n );\n}\n\nfunction normalizeRecord(input: RelaxedRecord): Record<string, StringMatcher[]> {\n const result: Record<string, StringMatcher[]> = {};\n for (const [key, value] of Object.entries(input)) {\n result[key] = normalizeStringMatchers(value);\n }\n return result;\n}\n\nfunction normalizeTypes<T>(input: T | T[]): T[] {\n return Array.isArray(input) ? input : [input];\n}\n\ntype Mutable<T> = { -readonly [K in keyof T]: T[K] };\n\nfunction normalizeAxisSelector(input: RelaxedAxisSelector): MultiAxisSelector {\n const result: Mutable<MultiAxisSelector> = {};\n if (input.name !== undefined) result.name = normalizeStringMatchers(input.name);\n if (input.type !== undefined) result.type = normalizeTypes(input.type);\n if (input.domain !== undefined) result.domain = normalizeRecord(input.domain);\n if (input.contextDomain !== undefined)\n result.contextDomain = normalizeRecord(input.contextDomain);\n if (input.annotations !== undefined) result.annotations = normalizeRecord(input.annotations);\n return result;\n}\n\n/** Normalize relaxed input to strict ColumnSelector[]. */\nexport function normalizeSelectors(input: ColumnSelectorInput): MultiColumnSelector[] {\n const arr = Array.isArray(input) ? input : [input];\n return arr.map(normalizeSingleSelector);\n}\n\nfunction normalizeSingleSelector(input: RelaxedColumnSelector): MultiColumnSelector {\n const result: Mutable<MultiColumnSelector> = {};\n if (input.name !== undefined) result.name = normalizeStringMatchers(input.name);\n if (input.type !== undefined) result.type = normalizeTypes(input.type);\n if (input.domain !== undefined) result.domain = normalizeRecord(input.domain);\n if (input.contextDomain !== undefined)\n result.contextDomain = normalizeRecord(input.contextDomain);\n if (input.annotations !== undefined) result.annotations = normalizeRecord(input.annotations);\n if (input.axes !== undefined) result.axes = input.axes.map(normalizeAxisSelector);\n if (input.partialAxesMatch !== undefined) result.partialAxesMatch = input.partialAxesMatch;\n return result;\n}\n\n// --- Matching ---\n\nfunction matchStringValue(value: string, matchers: StringMatcher[]): boolean {\n return matchers.some((m) => {\n if (m.type === \"exact\") return value === m.value;\n return new RegExp(`^(?:${m.value})$`).test(value);\n });\n}\n\nfunction matchRecordField(\n actual: Record<string, string> | undefined,\n required: Record<string, StringMatcher[]>,\n): boolean {\n const record = actual ?? {};\n for (const [key, matchers] of Object.entries(required)) {\n const value = record[key];\n if (value === undefined) return false;\n if (!matchStringValue(value, matchers)) return false;\n }\n return true;\n}\n\n/** Get combined domain: column's own domain merged with all axis domains. */\nfunction getCombinedDomain(spec: PColumnSpec): Record<string, string> {\n const result: Record<string, string> = {};\n if (spec.domain) Object.assign(result, spec.domain);\n for (const axis of spec.axesSpec) {\n if (axis.domain) Object.assign(result, axis.domain);\n }\n return result;\n}\n\n/** Get combined context domain: column's own contextDomain merged with all axis contextDomains. */\nfunction getCombinedContextDomain(spec: PColumnSpec): Record<string, string> {\n const result: Record<string, string> = {};\n if (spec.contextDomain) Object.assign(result, spec.contextDomain);\n for (const axis of spec.axesSpec) {\n if (\"contextDomain\" in axis && axis.contextDomain) Object.assign(result, axis.contextDomain);\n }\n return result;\n}\n\nfunction matchAxisSelector(\n axis: PColumnSpec[\"axesSpec\"][number],\n selector: MultiAxisSelector,\n): boolean {\n if (selector.name !== undefined && !matchStringValue(axis.name, selector.name)) return false;\n if (selector.type !== undefined && !selector.type.includes(axis.type)) return false;\n if (selector.domain !== undefined && !matchRecordField(axis.domain, selector.domain))\n return false;\n if (\n selector.contextDomain !== undefined &&\n !matchRecordField(\n \"contextDomain\" in axis ? (axis.contextDomain as Record<string, string>) : undefined,\n selector.contextDomain,\n )\n )\n return false;\n if (\n selector.annotations !== undefined &&\n !matchRecordField(axis.annotations, selector.annotations)\n )\n return false;\n return true;\n}\n\n/** Check if a PColumnSpec matches a single strict ColumnSelector. */\nexport function matchColumn(spec: PColumnSpec, selector: MultiColumnSelector): boolean {\n if (selector.name !== undefined && !matchStringValue(spec.name, selector.name)) return false;\n if (selector.type !== undefined && !selector.type.includes(spec.valueType)) return false;\n\n if (selector.domain !== undefined) {\n const combined = getCombinedDomain(spec);\n if (!matchRecordField(combined, selector.domain)) return false;\n }\n\n if (selector.contextDomain !== undefined) {\n const combined = getCombinedContextDomain(spec);\n if (!matchRecordField(combined, selector.contextDomain)) return false;\n }\n\n if (selector.annotations !== undefined) {\n if (!matchRecordField(spec.annotations, selector.annotations)) return false;\n }\n\n if (selector.axes !== undefined) {\n const partialMatch = selector.partialAxesMatch ?? true;\n if (partialMatch) {\n for (const axisSel of selector.axes) {\n if (!spec.axesSpec.some((axis) => matchAxisSelector(axis, axisSel))) return false;\n }\n } else {\n if (spec.axesSpec.length !== selector.axes.length) return false;\n for (let i = 0; i < selector.axes.length; i++) {\n if (!matchAxisSelector(spec.axesSpec[i], selector.axes[i])) return false;\n }\n }\n }\n\n return true;\n}\n\n/** Check if a PColumnSpec matches any of the selectors (OR across array). */\nexport function matchColumnSelectors(selectors: MultiColumnSelector[], spec: PColumnSpec): boolean {\n return selectors.some((sel) => matchColumn(spec, sel));\n}\n\n/**\n * Convert selector input to a predicate function.\n * Normalizes relaxed form, then returns a function that OR-matches.\n */\nexport function columnSelectorsToPredicate(\n input: ColumnSelectorInput,\n): (spec: PColumnSpec) => boolean {\n const selectors = normalizeSelectors(input);\n return (spec) => matchColumnSelectors(selectors, spec);\n}\n"],"mappings":"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"}
package/dist/package.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  //#region package.json
3
- var version = "1.60.0";
3
+ var version = "1.61.0";
4
4
 
5
5
  //#endregion
6
6
  Object.defineProperty(exports, 'version', {
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "1.60.0";
2
+ var version = "1.61.0";
3
3
 
4
4
  //#endregion
5
5
  export { version };
@@ -410,8 +410,20 @@ var RenderCtxBase = class {
410
410
  specFrameDiscoverColumns(handle, request) {
411
411
  return this.ctx.specFrameDiscoverColumns(handle, request);
412
412
  }
413
- specFrameDispose(handle) {
414
- this.ctx.specFrameDispose(handle);
413
+ disposeSpecFrame(handle) {
414
+ this.ctx.disposeSpecFrame(handle);
415
+ }
416
+ expandAxes(spec) {
417
+ return this.ctx.expandAxes(spec);
418
+ }
419
+ collapseAxes(ids) {
420
+ return this.ctx.collapseAxes(ids);
421
+ }
422
+ findAxis(spec, selector) {
423
+ return this.ctx.findAxis(spec, selector);
424
+ }
425
+ findTableColumn(tableSpec, selector) {
426
+ return this.ctx.findTableColumn(tableSpec, selector);
415
427
  }
416
428
  getCurrentUnstableMarker() {
417
429
  return this.ctx.getCurrentUnstableMarker();