// One parser used across all tool pages. Handles: // - FASTA (headers starting with '>') // - plain newline-separated sequences // - comma-separated sequence lists // Returns a normalized list of { id, seq }. export interface ParsedSequence { id: string seq: string } const AA_RE = /[^A-Za-z]/g function cleanSeq(raw: string): string { return raw.replace(AA_RE, '').toUpperCase() } export function parseSequences(input: string): ParsedSequence[] { const text = input.trim() if (!text) return [] // FASTA path: contains at least one '>' header. if (text.includes('>')) { const out: ParsedSequence[] = [] let current: ParsedSequence | null = null for (const line of text.split(/\r?\n/)) { const trimmed = line.trim() if (!trimmed) continue if (trimmed.startsWith('>')) { if (current) out.push(current) const id = trimmed.slice(1).trim().split(/\s+/)[0] || `seq_${out.length + 1}` current = { id, seq: '' } } else if (current) { current.seq += cleanSeq(trimmed) } else { // sequence data before any header current = { id: `seq_1`, seq: cleanSeq(trimmed) } } } if (current) out.push(current) return out.filter((s) => s.seq.length > 0) } // Non-FASTA: split on commas and/or newlines. const tokens = text .split(/[,\n\r]+/) .map((t) => t.trim()) .filter(Boolean) return tokens .map((tok, i) => ({ id: `seq_${i + 1}`, seq: cleanSeq(tok) })) .filter((s) => s.seq.length > 0) }