Created
March 26, 2024 10:40
-
-
Save rudfoss/543c9b3ea2e048576c43c3eacc3ba5bc to your computer and use it in GitHub Desktop.
A small set of helper functions that convert raw data to CSV which in turn can be downloaded. Uses no libraries and escapes necessary characters.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const sanitizeCellValue = (value: unknown, cellSeparator: string): string => { | |
let valueString = String(value ?? "") | |
if ( | |
valueString.includes(cellSeparator) || | |
valueString.includes(" ") || | |
valueString.includes('"') || | |
valueString.includes("\n") | |
) { | |
valueString = valueString.replaceAll('"', '""') | |
valueString = `"${valueString}"` | |
} | |
return valueString | |
} | |
/** | |
* Given a data set will convert it to a csv string with a header and newline-separated rows. | |
* @param data The data to convert | |
* @param columns The name of each property to include. If not specified will infer properties based on the first row. | |
* @param cellSeparator The separator character to use between cells. Defaults to comma. | |
* @returns | |
*/ | |
export const convertDataToCsvRows = <TRow extends object>( | |
data: TRow[], | |
columns?: Array<keyof TRow>, | |
cellSeparator: "," | ";" | "\t" | " " = "," | |
) => { | |
const columnsInOrder = columns ?? (Object.keys(data[0] ?? {}) as Array<keyof TRow>) | |
const columnNames = columnsInOrder | |
.map((columnName) => sanitizeCellValue(columnName, cellSeparator)) | |
.join(cellSeparator) | |
if (data.length === 0) { | |
return [columnNames].join("\n") | |
} | |
const rows = data.map((row) => | |
columnsInOrder | |
.map((columnName) => sanitizeCellValue(row[columnName], cellSeparator)) | |
.join(cellSeparator) | |
) | |
return [columnNames, ...rows].join("\n") | |
} | |
/** | |
* Creates a url for downloading the CSV data provided as a file. | |
* @param csvData | |
* @returns A function that will trigger the download when called. | |
*/ | |
export const makeDownloadableCsv = ( | |
csvData: string, | |
filename: string, | |
type = "text/csv;charset=utf-8" | |
) => { | |
const blob = new Blob([csvData], { type }) | |
const url = URL.createObjectURL(blob) | |
const downloadLink = document.createElement("a") | |
downloadLink.href = url | |
downloadLink.download = filename | |
downloadLink.style.visibility = "hidden" | |
return () => { | |
document.body.append(downloadLink) | |
downloadLink.click() | |
downloadLink.remove() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment