function _check_private_redeclaration(obj, privateCollection) {
    if (privateCollection.has(obj)) {
        throw new TypeError("Cannot initialize the same private elements twice on an object");
    }
}
function _class_private_method_get(receiver, privateSet, fn) {
    if (!privateSet.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return fn;
}
function _class_private_method_init(obj, privateSet) {
    _check_private_redeclaration(obj, privateSet);
    privateSet.add(obj);
}
import { stringify } from '../../../helpers/mixed.mjs';
import { extend } from '../../../helpers/object.mjs';
import BaseType from './_base.mjs';
const CHAR_CARRIAGE_RETURN = String.fromCharCode(13);
const CHAR_DOUBLE_QUOTES = String.fromCharCode(34);
const CHAR_LINE_FEED = String.fromCharCode(10);
const CHAR_EQUAL = String.fromCharCode(61);
const CHAR_PLUS = String.fromCharCode(43);
const CHAR_MINUS = String.fromCharCode(45);
const CHAR_AT = String.fromCharCode(64);
const CHAR_TAB = String.fromCharCode(9);
var /**
   * Sanitize value that may be interpreted as a formula in spreadsheet software.
   * Following the OWASP recommendations: https://owasp.org/www-community/attacks/CSV_Injection.
   *
   * @param {string} value Cell value.
   * @returns {string}
   */ _sanitizeValueWithOWASP = /*#__PURE__*/ new WeakSet(), /**
   * Sanitize value using regular expression.
   *
   * @param {string} value Cell value.
   * @param {RegExp} regexp Regular expression to test against.
   * @returns {string}
   */ _sanitizeValueWithRegExp = /*#__PURE__*/ new WeakSet();
/**
 * @private
 */ class Csv extends BaseType {
    /**
   * Default options for exporting CSV format.
   *
   * @returns {object}
   */ static get DEFAULT_OPTIONS() {
        return {
            mimeType: 'text/csv',
            fileExtension: 'csv',
            bom: true,
            columnDelimiter: ',',
            rowDelimiter: '\r\n',
            sanitizeValues: false
        };
    }
    /**
   * Merge options, normalizing XLSX-only values that are not applicable to CSV.
   *
   * The `'hide'` value for `exportHiddenRows` and `exportHiddenColumns` is only
   * meaningful for Excel exports (it marks rows/columns as hidden in the workbook).
   * For CSV the only sensible fallback is `false` — omit those rows/columns entirely.
   *
   * @param {object} options User-supplied options.
   * @returns {object}
   */ _mergeOptions(options) {
        const merged = super._mergeOptions(options);
        const overrides = {};
        if (merged.exportHiddenRows === 'hide') {
            overrides.exportHiddenRows = false;
        }
        if (merged.exportHiddenColumns === 'hide') {
            overrides.exportHiddenColumns = false;
        }
        return Object.keys(overrides).length > 0 ? extend(merged, overrides) : merged;
    }
    /**
   * Create string body in desired format.
   *
   * @returns {string}
   */ export() {
        const options = this.options;
        const data = this.dataProvider.getData();
        let columnHeaders = this.dataProvider.getColumnHeaders();
        const hasColumnHeaders = columnHeaders.length > 0;
        const rowHeaders = this.dataProvider.getRowHeaders();
        const hasRowHeaders = rowHeaders.length > 0;
        let result = options.bom ? String.fromCharCode(0xFEFF) : '';
        if (hasColumnHeaders) {
            columnHeaders = columnHeaders.map((value)=>this._escapeCell(value, {
                    force: true,
                    sanitizeValue: options.sanitizeValues
                }));
            if (hasRowHeaders) {
                result += options.columnDelimiter;
            }
            result += columnHeaders.join(options.columnDelimiter);
            result += options.rowDelimiter;
        }
        data.forEach((value, index)=>{
            if (index > 0) {
                result += options.rowDelimiter;
            }
            if (hasRowHeaders) {
                result += this._escapeCell(rowHeaders[index], {
                    sanitizeValue: options.sanitizeValues
                });
                result += options.columnDelimiter;
            }
            const escapedValue = value.map((cellValue)=>this._escapeCell(cellValue, {
                    sanitizeValue: options.sanitizeValues
                })).join(options.columnDelimiter);
            result += escapedValue;
        });
        return result;
    }
    /**
   * Escape cell value.
   *
   * @param {*} value Cell value.
   * @param {object} options Options.
   * @param {boolean} [options.force=false] Indicates if cell value will be escaped forcefully.
   * @param {boolean|RegExp|Function} [options.sanitizeValue=false] Controls the sanitization of cell value.
   * @returns {string}
   */ _escapeCell(value, { force = false, sanitizeValue = false } = {}) {
        let returnValue = stringify(value);
        if (returnValue === '') {
            return returnValue;
        }
        if (sanitizeValue) {
            force = true;
        }
        if (sanitizeValue instanceof RegExp) {
            returnValue = _class_private_method_get(this, _sanitizeValueWithRegExp, sanitizeValueWithRegExp).call(this, returnValue, sanitizeValue);
        } else if (typeof sanitizeValue === 'function') {
            returnValue = sanitizeValue(returnValue);
        } else if (sanitizeValue) {
            returnValue = _class_private_method_get(this, _sanitizeValueWithOWASP, sanitizeValueWithOWASP).call(this, returnValue);
        }
        if (force || returnValue.indexOf(CHAR_CARRIAGE_RETURN) >= 0 || returnValue.indexOf(CHAR_DOUBLE_QUOTES) >= 0 || returnValue.indexOf(CHAR_LINE_FEED) >= 0 || returnValue.indexOf(this.options.columnDelimiter) >= 0) {
            returnValue = returnValue.replace(new RegExp('"', 'g'), '""');
            returnValue = `"${returnValue}"`;
        }
        return returnValue;
    }
    constructor(...args){
        super(...args), _class_private_method_init(this, _sanitizeValueWithOWASP), _class_private_method_init(this, _sanitizeValueWithRegExp);
    }
}
function sanitizeValueWithOWASP(value) {
    if (value.startsWith(CHAR_EQUAL) || value.startsWith(CHAR_PLUS) || value.startsWith(CHAR_MINUS) || value.startsWith(CHAR_AT) || value.startsWith(CHAR_TAB) || value.startsWith(CHAR_CARRIAGE_RETURN)) {
        return `'${value}`;
    }
    return value;
}
function sanitizeValueWithRegExp(value, regexp) {
    return regexp.test(value) ? `'${value}` : value;
}
export default Csv;
