Created
March 26, 2024 10:40
Revisions
-
rudfoss created this gist
Mar 26, 2024 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,67 @@ 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() } }