Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 1x 1x 22x 12x 10x 5x 5x 1x 4x 22x 22x 2x 22x 16x 22x 16x | const NEEDS_QUOTES = /[\n\r"]|^\s|\s$/v;
const FORMULA_START = /^[\t\r+\-=@]/v;
function toText(value: unknown): string {
if (typeof value === 'string') {
return value;
}
if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
return String(value);
}
if (value instanceof Date) {
return value.toISOString();
}
return typeof value === 'object' && value !== null ? JSON.stringify(value) : '';
}
function formatField(value: unknown, separator: string, shouldEscapeFormulas: boolean): string {
let text = toText(value);
if (shouldEscapeFormulas && typeof value === 'string' && FORMULA_START.test(text)) {
text = `'${text}`;
}
return text.includes(separator) || NEEDS_QUOTES.test(text) ? `"${text.replaceAll('"', '""')}"` : text;
}
/**
* Builds CSV text (RFC 4180): fields are quoted when needed, lines end with CRLF. Prepend `'\uFEFF'` so that
* Excel reads UTF-8.
*
* @param rows - The rows, header first; `null` and `undefined` give empty fields, dates their ISO text,
* objects their JSON.
* @param separator - The field separator, such as `';'` for a locale with a decimal comma. Defaults to `','`.
* @param shouldEscapeFormulas - Whether to prefix a text starting with `=`, `+`, `-` or `@` with `'`, so that a
* spreadsheet does not run it. Defaults to `true`.
* @returns The CSV text, without a final line break.
* @example
* toCsv([['time', 'speed'], [new Date(0), 12.5]]); // 'time,speed\r\n1970-01-01T00:00:00.000Z,12.5'
*/
export function toCsv(rows: Iterable<readonly unknown[]>, separator = ',', shouldEscapeFormulas = true): string {
const lines: string[] = Array.from(rows, (row) =>
row.map((value) => formatField(value, separator, shouldEscapeFormulas)).join(separator),
);
return lines.join('\r\n');
}
|