blob: 14329b3c0b6e53fa65c0bfe1fab1354f27af7e5b [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/** @const {string} CSV download link's data href prefix, RFC 4810 Section 3 */
export const CSV_DATA_HREF_PREFIX = 'data:text/csv;charset=utf-8,';
/**
* Format array into plaintext csv
* @param {Array<Array>} data
* @return {string}
*/
export const convertListContentToCsv = (data) => {
const result = data.reduce((acc, row) => {
return `${acc}\r\n${row.map(preventCSVInjectionAndStringify).join(',')}`;
}, '');
// Remove leading /r and /n
return result.slice(2);
};
/**
* Prevent CSV injection, escape double quotes, and wrap with double quotes
* See owasp.org/index.php/CSV_Injection
* @param {string} cell
* @return {string}
*/
export const preventCSVInjectionAndStringify = (cell) => {
// Prepend all double quotes with another double quote, RFC 4810 Section 2.7
let escaped = cell.replace(/"/g, '""');
// prevent CSV injection: owasp.org/index.php/CSV_Injection
if (cell[0] === '=' ||
cell[0] === '+' ||
cell[0] === '-' ||
cell[0] === '@') {
escaped = `'${escaped}`;
}
// Wrap cell with double quotes, RFC 4810 Section 2.7
return `"${escaped}"`;
};
/**
* Prepare data for csv download by converting array of array into csv string
* @param {Array<Array<string>>} data
* @param {Array<string>=} headers Column headers
* @return {string} CSV formatted string
*/
export const prepareDataForDownload = (data, headers = []) => {
const mainContent = [headers, ...data];
return `${convertListContentToCsv(mainContent)}`;
};
/**
* Constructs download link url from csv string data.
* @param {string} data CSV data
* @return {string}
*/
export const constructHref = (data = '') => {
return `${CSV_DATA_HREF_PREFIX}${encodeURIComponent(data)}`;
};