{"version":3,"file":"lil-csv.module.mjs","sources":["../src/lil-csv.js"],"sourcesContent":["let isArray = Array.isArray;\nlet isString = (v) => typeof v === \"string\";\nlet isNumber = (v) => typeof v === \"number\";\nlet isBoolean = (v) => typeof v === \"boolean\";\nlet isDate = (v) => v instanceof Date && !isNaN(v.valueOf());\nlet isObject = (v) => v && typeof v === \"object\" && !isArray(v);\nconst isPlainObject = (value) => value && typeof value == \"object\" && value.__proto__ == Object.prototype;\nlet isFunction = (v) => typeof v === \"function\";\n\nfunction getDeep(obj, path) {\n    return path.split(\".\").reduce((result, curr) => (result == null ? result : result[curr]), obj);\n}\n\nfunction setDeep(obj, path, value) {\n    path.split(\".\").reduce((result, curr, index, paths) => {\n        let newVal = index + 1 === paths.length ? value : {};\n        return isPlainObject(result[curr]) ? result[curr] : (result[curr] = newVal);\n    }, obj);\n}\n\nfunction keysDeep(obj, prefix) {\n    return Object.entries(obj).reduce((keys, [k, v]) => {\n        let newKey = prefix ? prefix + \".\" + k : k;\n        return keys.concat(isPlainObject(v) ? keysDeep(v, newKey) : newKey);\n    }, []);\n}\n\n/**\n * @param str {String} The CSV file contents.\n * @param [header=true] {Boolean | String[] | Object.<string,String> | Object.<string,Function> | Object.<string,{[parse]:Function,[newName]:String}>}\n * @param [delimiter=\",\"] {String} specifies the character sequence which should separate fields (aka columns). Default = `\",\"`. Examples: `\"\\t\"` or `\"|\"`.\n * @param [quoteChar='\"'] {String} specifies a one-character string to use as the quoting character. Default = `\\\"`\n * @param [escapeChar=\"\\\\\"] {String} specifies a one-character string to use for escaping, mutually exclusive with `quoteChar`. Default: `\"\\\\\"`\n * @return {Object[] | String[] | *[]} The parsed strings, objects, values of all kind(s).\n */\nexport function parse(str, { header = true, delimiter = \",\", quoteChar = '\"', escapeChar = \"\\\\\" } = {}) {\n    let entries = [];\n    let quote = false; // 'true' means we're inside a quoted field\n\n    // Iterate over each character, keep track of current row and column (of the returned array)\n    for (let row = 0, col = 0, c = 0; c < str.length; c++) {\n        let cc = str[c]; // Current character\n        let nc = str[c + 1]; // Next character\n        entries[row] = entries[row] || []; // Create a new row if necessary\n        entries[row][col] = entries[row][col] || \"\"; // Create a new column (start with empty string) if necessary\n\n        // If it's an escaping, then just use the following character as data\n        if (cc === escapeChar) {\n            entries[row][col] += nc;\n            ++c;\n            continue;\n        }\n\n        // If it's just one quotation mark, begin/end quoted field\n        if (cc === quoteChar) {\n            quote = !quote;\n            continue;\n        }\n\n        if (!quote) {\n            // If it's a comma, move on to the next column\n            if (cc === delimiter) {\n                ++col;\n                entries[row][col] = \"\"; // If line ends with comma we need to add an empty column to the row.\n                continue;\n            }\n\n            // If it's a lineTerminator (LF or CR),\n            // move on to the next row and move to column 0 of that new row\n            if (cc === \"\\n\" || cc === \"\\r\") {\n                ++row;\n                col = 0;\n\n                // If it's a lineTerminator (CRLF), skip the next character\n                // and move on to the next row and move to column 0 of that new row\n                if (cc === \"\\r\" && nc === \"\\n\") {\n                    ++c;\n                }\n\n                continue;\n            }\n        }\n\n        // Otherwise, append the current character to the current column\n        entries[row][col] += cc;\n    }\n\n    if (!header) return entries; // no data processing needed.\n\n    let headerEntry = entries.shift();\n    if (new Set(headerEntry).size !== headerEntry.length) {\n        throw Error(\"Can't parse CSV as data. Some headers have same name.\");\n    }\n\n    // Auto-construct the headers (JSON objects keys) from the top most line of the file.\n    if (isBoolean(header)) header = headerEntry.reduce((o, h) => ((o[h] = true), o), {});\n    let defaultDataHeader = header[\"*\"];\n\n    return entries.map((entry) => {\n        let processedEntry = {};\n        for (let col = 0; col < entry.length; col++) {\n            let dataHeaderName = headerEntry[col];\n            let dataHeader = isArray(header) ? header[col] : header[dataHeaderName] || defaultDataHeader;\n            if (!dataHeader) continue; // We don't want this column\n            let value = entry[col];\n\n            let parse = dataHeader.parse || dataHeader;\n            if (isFunction(parse)) value = parse(value, entry);\n\n            if (value !== undefined) {\n                let propName = dataHeader.newName || (isString(dataHeader) ? dataHeader : dataHeaderName);\n                setDeep(processedEntry, propName, value);\n            }\n        }\n        return processedEntry;\n    });\n}\n\nlet valueToString = (v) => {\n    if (v == null || v === \"\" || !((isNumber(v) && !isNaN(v)) || isString(v) || isDate(v) || isBoolean(v))) return \"\"; // ignore bad data\n\n    v = isDate(v) ? v.toISOString() : String(v); // convert any kind of value to string\n    return v;\n};\n\n/**\n * Generate CSV from your data (arrays or objects) to a string.\n * The options are named using this standard: https://specs.frictionlessdata.io//csv-dialect/#specification\n * @param rows {Object[] | String[]}\n * @param [header=true] {Boolean | String[] | Object.<string,Boolean> | Object.<string,String> | Object.<string,Function> | Object.<string,{[stringify]:Function,[newName]:String}>}\n * @param [delimiter=\",\"] {String} specifies the character sequence which should separate fields (aka columns). Default = `\",\"`. Examples: `\"\\t\"` or `\"|\"`.\n * @param [quoteChar='\"'] {String} specifies a one-character string to use as the quoting character. Default = `\\\"`\n * @param [escapeChar=\"\\\\\"] {String} specifies a one-character string to use for escaping, mutually exclusive with `quoteChar`. Default: `\"\\\\\"`\n * @param [wrapStrings=false] {Boolean} specifies if all string cells must be wrapped with the `quoteChar`\n * @param [lineTerminator=\"\\n\"] {String} specifies the character sequence which should terminate rows. Default = `\"\\n\"`\n * @return {String} The CSV file contents.\n */\nexport function generate(\n    rows,\n    {\n        header = true,\n        delimiter = \",\",\n        lineTerminator = \"\\n\",\n        quoteChar = '\"',\n        escapeChar = \"\\\\\",\n        wrapStrings = false,\n    } = {}\n) {\n    let serialiseString = (v) => {\n        v = v.replace(new RegExp(quoteChar, \"g\"), escapeChar + quoteChar); // Escape quote character\n        return wrapStrings || v.includes(delimiter) ? quoteChar + v + quoteChar : v; // Add quotes if value has commas\n    };\n\n    /**\n     * @type {String[]|null}\n     */\n    let detectedHeaders = null;\n    if (header) {\n        if (isArray(header)) {\n            if (!header.length || !header.every(isString))\n                throw new Error(\"If header is array all items must be strings\");\n            detectedHeaders = header;\n        } else {\n            // Here we know that `header` is either `true` or an object.\n            if (isObject(rows[0])) {\n                detectedHeaders = keysDeep(rows[0]);\n                if (detectedHeaders.length === 0) throw new Error(\"Bad header and rows\");\n            } else {\n                if (!isArray(rows[0])) throw new Error(\"Can't auto detect header from rows\");\n            }\n\n            if (isPlainObject(header)) {\n                // If there is \"star\" header then the column order would be taken from the data rows;\n                // but if no \"*\" was given then let's user the `header` object order.\n                let detectedHeadersSet = new Set(header[\"*\"] ? detectedHeaders : Object.keys(header));\n                for (let [key, value] of Object.entries(header)) {\n                    if (!value) {\n                        detectedHeadersSet.delete(key);\n                    } else {\n                        detectedHeadersSet.add(key);\n                    }\n                }\n                detectedHeadersSet.delete(\"*\");\n                detectedHeaders = Array.from(detectedHeadersSet);\n            } else {\n                if (!isBoolean(header)) throw new Error(\"Header must be either boolean, or array, or object\");\n            }\n        }\n    }\n\n    let textHeader = detectedHeaders\n        ? detectedHeaders\n              .map((h) => {\n                  let dataHeader = header[h] || header[\"*\"] || h;\n                  let newHeader = dataHeader.newName || (isString(dataHeader) ? dataHeader : h);\n                  return serialiseString(newHeader);\n              })\n              .join(delimiter) + lineTerminator\n        : \"\";\n    return (\n        textHeader +\n        rows\n            .map((row, i) => {\n                if (isArray(row)) {\n                    if (detectedHeaders && row.length !== detectedHeaders.length)\n                        throw new Error(`Each row array must have exactly ${detectedHeaders.length} items`);\n                    return row.map((v) => serialiseString(valueToString(v))).join(delimiter);\n                }\n                if (isObject(row)) {\n                    if (!detectedHeaders) throw new Error(\"Unexpected row object\");\n\n                    return detectedHeaders\n                        .map((h) => {\n                            let dataHeader = header[h] || header[\"*\"] || h;\n                            let stringify = dataHeader.stringify || dataHeader;\n                            if (!isFunction(stringify)) stringify = valueToString;\n                            return serialiseString(valueToString(stringify(getDeep(row, h), row)));\n                        })\n                        .join(delimiter);\n                }\n                throw new Error(`Row ${i} must be either array or object`);\n            })\n            .join(lineTerminator)\n    );\n}\n"],"names":["isArray","Array","isString","v","isBoolean","isDate","Date","isNaN","valueOf","isObject","isPlainObject","value","__proto__","Object","prototype","isFunction","setDeep","obj","path","split","reduce","result","curr","index","paths","newVal","length","keysDeep","prefix","entries","keys","k","newKey","concat","parse","str","header","delimiter","quoteChar","escapeChar","quote","row","col","c","cc","nc","headerEntry","shift","Set","size","Error","o","h","defaultDataHeader","map","entry","processedEntry","dataHeaderName","dataHeader","undefined","newName","valueToString","isNumber","toISOString","String","generate","rows","lineTerminator","wrapStrings","serialiseString","replace","RegExp","includes","detectedHeaders","every","detectedHeadersSet","key","add","from","newHeader","join","i","stringify"],"mappings":"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"}