32 lines
1.2 KiB
TypeScript
32 lines
1.2 KiB
TypeScript
import { stringifyCell } from '../shared/text';
|
|
|
|
function escapeCsvCell(value: unknown, delimiter: string, neutralizeFormulas: boolean): string {
|
|
const originalCell = stringifyCell(value);
|
|
const isSpreadsheetFormula = /^[\u0000-\u0020]*[=+\-@]/.test(originalCell);
|
|
const cell = neutralizeFormulas && isSpreadsheetFormula ? `'${originalCell}` : originalCell;
|
|
const mustQuote = neutralizeFormulas && isSpreadsheetFormula
|
|
|| cell.includes('"')
|
|
|| cell.includes('\n')
|
|
|| cell.includes('\r')
|
|
|| cell.includes(delimiter);
|
|
|
|
return mustQuote ? `"${cell.replaceAll('"', '""')}"` : cell;
|
|
}
|
|
|
|
export function rowsToCsv(rows: unknown[][], delimiter = ';'): string {
|
|
return rows
|
|
.map(row => row.map(value => escapeCsvCell(value, delimiter, false)).join(delimiter))
|
|
.join('\n');
|
|
}
|
|
|
|
export function rowsToSpreadsheetSafeCsv(rows: unknown[][], delimiter = ';'): string {
|
|
return rows
|
|
.map(row => row.map(value => escapeCsvCell(value, delimiter, true)).join(delimiter))
|
|
.join('\n');
|
|
}
|
|
|
|
export function objectsToCsv(rows: Array<Record<string, unknown>>): string {
|
|
const headers = Object.keys(rows[0] ?? {});
|
|
return rowsToSpreadsheetSafeCsv([headers, ...rows.map(row => headers.map(header => row[header]))]);
|
|
}
|