export interface ParsedCsv { headers: string[]; rows: string[][]; } export function parseCsv(input: string): ParsedCsv { const text = input.replace(/^\uFEFF/, ""); if (text.trim() === "") throw new Error("CSV input is empty"); const rows: string[][] = []; let field = ""; let row: string[] = []; let inQuotes = false; for (let i = 0; i < text.length; i++) { const ch = text[i]; if (inQuotes) { if (ch === '"') { if (text[i + 1] === '"') { field += '"'; i++; } else inQuotes = false; } else field += ch; } else if (ch === '"') { inQuotes = true; } else if (ch === ',') { row.push(field); field = ""; } else if (ch === '\n' || ch === '\r') { if (ch === '\r' && text[i + 1] === '\n') i++; row.push(field); field = ""; rows.push(row); row = []; } else field += ch; } if (field !== "" || row.length > 0) { row.push(field); rows.push(row); } if (rows.length === 0) throw new Error("CSV input is empty"); const [headers, ...data] = rows; const width = headers.length; const padded = data.map((r) => { const out = r.slice(0, width); while (out.length < width) out.push(""); return out; }); return { headers, rows: padded }; }