| // Lightweight CSV parsing helpers used by the app. | |
| // Exports: | |
| // - parseCSVLine(line): parse a single CSV line into array of values (handles quoted fields) | |
| // - parseCsvContent(text): parse CSV text into { headers: string[], rows: Array<object> } | |
| export function parseCSVLine(line) { | |
| const res = [] | |
| let cur = '' | |
| let inQuotes = false | |
| for (let i = 0; i < line.length; i++) { | |
| const ch = line[i] | |
| if (inQuotes) { | |
| if (ch === '"') { | |
| if (i + 1 < line.length && line[i + 1] === '"') { cur += '"'; i++ } else { inQuotes = false } | |
| } else { cur += ch } | |
| } else { | |
| if (ch === ',') { res.push(cur); cur = '' } | |
| else if (ch === '"') { inQuotes = true } | |
| else { cur += ch } | |
| } | |
| } | |
| res.push(cur) | |
| return res | |
| } | |
| export function parseCsvContent(txt) { | |
| const lines = txt.split(/\r?\n/) | |
| let headerIdx = null | |
| for (let i = 0; i < lines.length; i++) if (lines[i].trim().length > 0) { headerIdx = i; break } | |
| if (headerIdx === null) return { headers: [], rows: [] } | |
| const headers = parseCSVLine(lines[headerIdx]) | |
| const rows = [] | |
| for (let i = headerIdx + 1; i < lines.length; i++) { | |
| const l = lines[i] | |
| if (!l || l.trim() === '') continue | |
| const vals = parseCSVLine(l) | |
| const obj = {} | |
| for (let j = 0; j < headers.length; j++) obj[headers[j]] = vals[j] ?? '' | |
| rows.push(obj) | |
| } | |
| return { headers, rows } | |
| } | |