Assessor_2.0/src/exports/csv-export.ts

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]))]);
}