import type { LcmsPlateCell, LcmsPlateType } from './utils/rack' /** @deprecated Scheduled for removal in MINT 1.4; no SDK replacement. */ export type LcmsPolarity = 'POS' | 'NEG' | 'BOTH' /** @deprecated Scheduled for removal in MINT 1.4; no SDK replacement. */ export type LcmsContainerType = 'VIAL' | 'PLATE' /** @deprecated Scheduled for removal in MINT 1.4; no SDK replacement. */ export interface LcmsSequenceItem { sample_type: string file_name: string sample_id: string path: string instrument_method: string position: string injection_volume: number } /** @deprecated Scheduled for removal in MINT 1.4; no SDK replacement. */ export interface LcmsSequenceTableColumn { key: keyof LcmsSequenceItem | 'index' | 'actions' label: string align?: 'left' | 'right' } /** @deprecated Scheduled for removal in MINT 1.4; no SDK replacement. */ export const DEFAULT_LCMS_SEQUENCE_COLUMNS: LcmsSequenceTableColumn[] = [ { key: 'index', label: '#' }, { key: 'sample_type', label: 'Type' }, { key: 'file_name', label: 'File Name' }, { key: 'position', label: 'Position' }, { key: 'instrument_method', label: 'Method' }, { key: 'injection_volume', label: 'Inj Vol', align: 'right' }, ] /** @deprecated Scheduled for removal in MINT 1.4; no SDK replacement. */ export function extractLcmsCommonPrefix(fileNames: readonly string[]): string { if (fileNames.length === 0) return '' const stripped = fileNames.map(fileName => fileName.replace(/_\d{3}$/, '')) const prefixes = stripped.map((fileName) => { const match = fileName.match(/^(.+?)_(POS|NEG)_/i) return match ? match[1] : fileName.replace(/_[^_]+$/, '') }) let common = prefixes[0] ?? '' for (const prefix of prefixes.slice(1)) { while (common && !prefix.startsWith(common)) { const index = common.lastIndexOf('_') common = index > 0 ? common.substring(0, index) : common.substring(0, common.length - 1) } } return common } /** @deprecated Scheduled for removal in MINT 1.4; no SDK replacement. */ export function extractLcmsSampleName(fileName: string, prefix = ''): string { let name = fileName.replace(/_\d{3}$/, '') if (prefix && name.startsWith(prefix)) { name = name.substring(prefix.length).replace(/^_+/, '') } name = name.replace(/^(POS|NEG)_/i, '') return name || fileName } /** @deprecated Scheduled for removal in MINT 1.4; no SDK replacement. */ export function lcmsWellIdFromPosition(position: string): string { return position.includes(':') ? position.split(':').pop() ?? position : position } /** @deprecated Scheduled for removal in MINT 1.4; no SDK replacement. */ export function inferLcmsPlateTypeFromWellIds(wellIds: readonly string[]): LcmsPlateType | null { let maxCol = 0 let maxRow = 0 for (const wellId of wellIds) { const match = wellId.match(/^([A-Z])(\d+)$/i) if (!match) continue maxRow = Math.max(maxRow, match[1].toUpperCase().charCodeAt(0) - 64) maxCol = Math.max(maxCol, Number(match[2])) } if (maxCol === 0 && maxRow === 0) return null return maxCol <= 9 && maxRow <= 6 ? '54vial' : '96well' } /** @deprecated Scheduled for removal in MINT 1.4; no SDK replacement. */ export function reconstructLcmsPlateCellsFromSequenceItems( items: readonly LcmsSequenceItem[], ): { cells: LcmsPlateCell[]; plateType: LcmsPlateType } | null { const unknownItems = items.filter(item => item.sample_type === 'Unknown') if (unknownItems.length === 0) return null const prefix = extractLcmsCommonPrefix(unknownItems.map(item => item.file_name)) const seen = new Set() const cells: LcmsPlateCell[] = [] for (const item of unknownItems) { const wellId = lcmsWellIdFromPosition(item.position) if (seen.has(wellId)) continue seen.add(wellId) const match = wellId.match(/^([A-Z])(\d+)$/i) if (!match) continue cells.push({ row: match[1].toUpperCase(), column: Number(match[2]), sample_name: extractLcmsSampleName(item.file_name, prefix), }) } if (cells.length === 0) return null const plateType = inferLcmsPlateTypeFromWellIds(cells.map(cell => `${cell.row}${cell.column}`)) if (!plateType) return null return { cells, plateType } } /** @deprecated Scheduled for removal in MINT 1.4; no SDK replacement. */ export function basenameFromWindowsPath(path: string | null | undefined): string { if (!path) return '' return path.split(/[\\/]/).pop() ?? path }