All files / src/lib csv.ts

100% Statements 20/20
100% Branches 13/13
100% Functions 3/3
100% Lines 18/18

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35              12x   11x 11x 14x   22x 22x 20x   20x 5x   15x         11x 11x 11x 11x 11x 11x 12x 12x    
/**
 * Download data as a CSV file.
 */
export function downloadCsv(
	data: Record<string, unknown>[],
	filename: string,
) {
	if (data.length === 0) return;
 
	const headers = Object.keys(data[0]);
	const rows = data.map((row) =>
		headers
			.map((h) => {
				const val = row[h];
				if (val === null || val === undefined) return "";
				const str = String(val);
				// Escape quotes and wrap in quotes if contains comma, newline, or quote
				if (str.includes(",") || str.includes("\n") || str.includes('"')) {
					return `"${str.replace(/"/g, '""')}"`;
				}
				return str;
			})
			.join(","),
	);
 
	const csv = [headers.join(","), ...rows].join("\n");
	const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
	const url = URL.createObjectURL(blob);
	const a = document.createElement("a");
	a.href = url;
	a.download = filename.endsWith(".csv") ? filename : `${filename}.csv`;
	a.click();
	URL.revokeObjectURL(url);
}