// Parser CSV minimo (RFC4180: campos entre comillas, comillas escapadas // como "", comas y saltos de linea dentro de campos citados) -- se evita // sumar una dependencia nueva (papaparse/csv-parse) para un formato que // nosotros mismos controlamos via la plantilla descargable. export function parseCsv(text: string): string[][] { const rows: string[][] = []; let row: string[] = []; let field = ""; let inQuotes = false; let i = 0; const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); while (i < normalized.length) { const char = normalized[i]; if (inQuotes) { if (char === '"') { if (normalized[i + 1] === '"') { field += '"'; i += 2; continue; } inQuotes = false; i += 1; continue; } field += char; i += 1; continue; } if (char === '"') { inQuotes = true; i += 1; continue; } if (char === ",") { row.push(field); field = ""; i += 1; continue; } if (char === "\n") { row.push(field); rows.push(row); row = []; field = ""; i += 1; continue; } field += char; i += 1; } if (field.length > 0 || row.length > 0) { row.push(field); rows.push(row); } return rows.filter((r) => r.some((cell) => cell.trim().length > 0)); } export function csvRowsToObjects(rows: string[][]): Record[] { const [header, ...body] = rows; if (!header) return []; const keys = header.map((h) => h.trim().toLowerCase()); return body.map((cols) => { const obj: Record = {}; keys.forEach((key, index) => { obj[key] = (cols[index] ?? "").trim(); }); return obj; }); }