UNPKG

@ajay7781/csv-to-json-lite

Version:

Zero-dependency CSV to JSON converter (Node + Browser, modern ESM)

53 lines (43 loc) 1.68 kB
// index.js // Modern CSV to JSON converter (Node + Browser, ESM, Zero Dependencies) export async function csvToJson(input, options = {}) { const { headers = true, delimiter = ',', headerCase = 'none', // none | camel | snake trim = true, skipEmpty = true, } = options; const csv = typeof input === 'string' ? input : await input.text(); const lines = csv.split(/\r?\n/).filter(line => (skipEmpty ? line.trim() !== '' : true)); if (lines.length === 0) return []; const parseLine = (line) => { const regex = new RegExp( `(\\\"(?:[^\\\"]|\\\"\\\")*\\\"|[^\"${delimiter}]*)(?:${delimiter}|$)`, 'g' ); return [...line.matchAll(regex)].map((match) => { let value = match[1]; if (value.startsWith('"') && value.endsWith('"')) { value = value.slice(1, -1).replace(/""/g, '"'); } return trim ? value.trim() : value; }).filter((v, i, arr) => i < arr.length - 1 || v !== ''); // remove trailing empty }; const rawHeader = headers ? parseLine(lines.shift()) : null; const normalizeHeader = (h) => { if (headerCase === 'camel') return h.replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : ''); if (headerCase === 'snake') return h.toLowerCase().replace(/\W+/g, '_'); return h; }; const header = rawHeader?.map(normalizeHeader); const result = lines.map((line) => { const values = parseLine(line); if (!headers) return values; return header.reduce((obj, key, i) => { obj[key] = values[i] ?? null; return obj; }, {}); }); return result; }