@ajay7781/csv-to-json-lite
Version:
Zero-dependency CSV to JSON converter (Node + Browser, modern ESM)
53 lines (43 loc) • 1.68 kB
JavaScript
// 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;
}