fix: add comments
This commit is contained in:
+64
-55
@@ -7,66 +7,75 @@
|
||||
* @param delimiter - csv delimiter (default is comma)
|
||||
* @param addBOM - add UTF-8 BOM to the file to make Excel detect UTF-8 correctly
|
||||
*/
|
||||
/*
|
||||
Usage examples:
|
||||
// 1) With headers and array of objects
|
||||
// downloadCsv(['name', 'age'], [{name: 'Alice', age: 25}, {name: 'Bob', age: 30}], 'people.csv');
|
||||
// 2) Without headers (automatically uses object keys)
|
||||
// downloadCsv(null, [{name: 'Alice', age: 25}, {name: 'Bob', age: 30}], 'people.csv');
|
||||
// 3) With array-of-arrays
|
||||
// downloadCsv(['col1', 'col2'], [['a', 'b'], ['c', 'd']], 'matrix.csv');
|
||||
*/
|
||||
export function downloadCsv(
|
||||
headers: string[] | null,
|
||||
data: Array<Record<string, any> | any[]>,
|
||||
filename = 'data.csv',
|
||||
delimiter = ',',
|
||||
addBOM = true,
|
||||
headers: string[] | null,
|
||||
data: Array<Record<string, any> | any[]>,
|
||||
filename = 'data.csv',
|
||||
delimiter = ',',
|
||||
addBOM = true,
|
||||
) {
|
||||
if (!Array.isArray(data) || data.length === 0) {
|
||||
// still create an empty CSV containing only headers
|
||||
const csvHeader = headers ? headers.join(delimiter) : '';
|
||||
const csvString = addBOM ? '\uFEFF' + csvHeader : csvHeader;
|
||||
const blob = new Blob([csvString], { type: 'text/csv;charset=utf-8;' });
|
||||
const link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.setAttribute('download', filename);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(data) || data.length === 0) {
|
||||
// still create an empty CSV containing only headers
|
||||
const csvHeader = headers ? headers.join(delimiter) : ''
|
||||
const csvString = addBOM ? '\uFEFF' + csvHeader : csvHeader
|
||||
const blob = new Blob([csvString], { type: 'text/csv;charset=utf-8;' })
|
||||
const link = document.createElement('a')
|
||||
link.href = URL.createObjectURL(blob)
|
||||
link.setAttribute('download', filename)
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
return
|
||||
}
|
||||
|
||||
// if headers not provided and rows are objects, take keys from first object
|
||||
let _headers: string[] | null = headers;
|
||||
if (!_headers) {
|
||||
const firstRow = data[0];
|
||||
if (typeof firstRow === 'object' && !Array.isArray(firstRow)) {
|
||||
_headers = Object.keys(firstRow);
|
||||
} else if (Array.isArray(firstRow)) {
|
||||
// if rows are arrays and no headers provided, we won't add header row
|
||||
_headers = null;
|
||||
}
|
||||
}
|
||||
// if headers not provided and rows are objects, take keys from first object
|
||||
let _headers: string[] | null = headers
|
||||
if (!_headers) {
|
||||
const firstRow = data[0]
|
||||
if (typeof firstRow === 'object' && !Array.isArray(firstRow)) {
|
||||
_headers = Object.keys(firstRow)
|
||||
} else if (Array.isArray(firstRow)) {
|
||||
// if rows are arrays and no headers provided, we won't add header row
|
||||
_headers = null
|
||||
}
|
||||
}
|
||||
|
||||
const escape = (val: unknown) => {
|
||||
if (val === null || typeof val === 'undefined') return '';
|
||||
const str = String(val);
|
||||
const needsQuoting = str.includes(delimiter) || str.includes('\n') || str.includes('\r') || str.includes('"');
|
||||
if (!needsQuoting) return str;
|
||||
return '"' + str.replace(/"/g, '""') + '"';
|
||||
};
|
||||
const escape = (val: unknown) => {
|
||||
if (val === null || typeof val === 'undefined') return ''
|
||||
const str = String(val)
|
||||
const needsQuoting = str.includes(delimiter) || str.includes('\n') || str.includes('\r') || str.includes('"')
|
||||
if (!needsQuoting) return str
|
||||
return '"' + str.replace(/"/g, '""') + '"'
|
||||
}
|
||||
|
||||
const rows: string[] = data.map((row) => {
|
||||
if (Array.isArray(row)) {
|
||||
return row.map(escape).join(delimiter);
|
||||
}
|
||||
// object row - map using headers if available, otherwise use object values
|
||||
if (_headers && Array.isArray(_headers)) {
|
||||
return _headers.map(h => escape((row as Record<string, any>)[h])).join(delimiter);
|
||||
}
|
||||
return Object.values(row).map(escape).join(delimiter);
|
||||
});
|
||||
const rows: string[] = data.map((row) => {
|
||||
if (Array.isArray(row)) {
|
||||
return row.map(escape).join(delimiter)
|
||||
}
|
||||
// object row - map using headers if available, otherwise use object values
|
||||
if (_headers && Array.isArray(_headers)) {
|
||||
return _headers.map((h) => escape((row as Record<string, any>)[h])).join(delimiter)
|
||||
}
|
||||
return Object.values(row).map(escape).join(delimiter)
|
||||
})
|
||||
|
||||
const headerRow = _headers ? _headers.join(delimiter) : null;
|
||||
const csvString = (addBOM ? '\uFEFF' : '') + [headerRow, ...rows].filter(Boolean).join('\r\n');
|
||||
const headerRow = _headers ? _headers.join(delimiter) : null
|
||||
const csvString = (addBOM ? '\uFEFF' : '') + [headerRow, ...rows].filter(Boolean).join('\r\n')
|
||||
|
||||
const blob = new Blob([csvString], { type: 'text/csv;charset=utf-8;' });
|
||||
const link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.setAttribute('download', filename);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
const blob = new Blob([csvString], { type: 'text/csv;charset=utf-8;' })
|
||||
const link = document.createElement('a')
|
||||
link.href = URL.createObjectURL(blob)
|
||||
link.setAttribute('download', filename)
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user