{"version":3,"file":"csv.cjs","names":["isBoolean","isRecord","isArray","jsonStringifySafe","escapeRegExp"],"sources":["../../src/common/csv.ts"],"sourcesContent":["import { isArray, isBoolean, isRecord } from './data/is'\nimport { jsonStringifySafe } from './data/json'\nimport { escapeRegExp } from './data/regexp'\n\nconst defaultSeparator = ','\n\nexport function csvStringify(data: any[], opt: {\n  // header?: string[]\n  separator?: string\n  addBom?: boolean // option to add byte order mark for improved Excel support\n} = {}): string {\n  const { separator = defaultSeparator } = opt\n  let body = ''\n  if (opt.addBom)\n    body = '\\uFEFF'\n\n  // Append the header row to the response if requested\n  // if (header)\n  //   body = `${header.join(separator)}\\n`\n\n  // Convert the data to a CSV-like structure\n  for (let i = 0; i < data.length; i++) {\n    body += `${data[i].map((field: string) => {\n      if (field == null || field === '')\n        return ''\n      if (isBoolean(field))\n        return field ? 1 : 0\n      let s = String(field)\n      if (isRecord(field) || isArray(field))\n        s = jsonStringifySafe(field)\n      if (s.includes('\"') || s.includes('\\n') || s.includes(separator))\n        return `\"${s.replace(/\"/g, '\"\"')}\"`\n      return s\n    }).join(separator)}\\n`\n  }\n\n  return body\n}\n\nexport function csvParse(raw: string, opt: {\n  separator?: string\n} = {}) {\n  // https://regex101.com/r/BCpKyV/1\n  // eslint-disable-next-line regexp/no-unused-capturing-group, regexp/no-super-linear-backtracking, regexp/no-dupe-disjunctions, regexp/no-useless-non-capturing-group\n  let rxOneValueWithSeparator = /(\"((?:(?:[^\"]*?)(?:\"\")?)*)\"|([^,;\\t\\n]*))([,;\\t\\n]|\\r\\n)/g\n  if (opt.separator)\n    rxOneValueWithSeparator = new RegExp(rxOneValueWithSeparator.source.replace(/',;\\\\t/g, escapeRegExp(opt.separator)), rxOneValueWithSeparator.flags)\n\n  const lines: any[][] = []\n  let row: any[] = []\n  let m: any\n  const text = `${raw.replace(/\\r\\n/g, '\\n').trim()}\\n`\n\n  // eslint-disable-next-line no-cond-assign\n  while (m = rxOneValueWithSeparator.exec(text)) {\n    let value = m[2] ?? m[3] ?? ''\n    value = value.replace(/\"\"/g, '\"')\n    row.push(value)\n    if (m[4] === '\\n') {\n      lines.push(row)\n      row = []\n    }\n  }\n  return lines\n}\n\nexport function csvParseToObjects(raw: string, opt: {\n  separator?: string\n} = {}) {\n  const lines = csvParse(raw, opt)\n  const header = lines[0]\n  return lines.slice(1).map(l =>\n    Object.fromEntries (l.map((v, i) => [header[i], v])),\n  )\n}\n"],"mappings":";;;;;;AAIA,MAAM,mBAAmB;AAEzB,SAAgB,aAAa,MAAa,MAItC,EAAE,EAAU;CACd,MAAM,EAAE,YAAY,qBAAqB;CACzC,IAAI,OAAO;AACX,KAAI,IAAI,OACN,QAAO;AAOT,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,IAC/B,SAAQ,GAAG,KAAK,GAAG,KAAK,UAAkB;AACxC,MAAI,SAAS,QAAQ,UAAU,GAC7B,QAAO;AACT,MAAIA,iCAAU,MAAM,CAClB,QAAO,QAAQ,IAAI;EACrB,IAAI,IAAI,OAAO,MAAM;AACrB,MAAIC,gCAAS,MAAM,IAAIC,+BAAQ,MAAM,CACnC,KAAIC,2CAAkB,MAAM;AAC9B,MAAI,EAAE,SAAS,KAAI,IAAI,EAAE,SAAS,KAAK,IAAI,EAAE,SAAS,UAAU,CAC9D,QAAO,IAAI,EAAE,QAAQ,MAAM,OAAK,CAAC;AACnC,SAAO;GACP,CAAC,KAAK,UAAU,CAAC;AAGrB,QAAO;;AAGT,SAAgB,SAAS,KAAa,MAElC,EAAE,EAAE;CAGN,IAAI,0BAA0B;AAC9B,KAAI,IAAI,UACN,2BAA0B,IAAI,OAAO,wBAAwB,OAAO,QAAQ,WAAWC,wCAAa,IAAI,UAAU,CAAC,EAAE,wBAAwB,MAAM;CAErJ,MAAM,QAAiB,EAAE;CACzB,IAAI,MAAa,EAAE;CACnB,IAAI;CACJ,MAAM,OAAO,GAAG,IAAI,QAAQ,SAAS,KAAK,CAAC,MAAM,CAAC;AAGlD,QAAO,IAAI,wBAAwB,KAAK,KAAK,EAAE;EAC7C,IAAI,QAAQ,EAAE,MAAM,EAAE,MAAM;AAC5B,UAAQ,MAAM,QAAQ,OAAO,KAAI;AACjC,MAAI,KAAK,MAAM;AACf,MAAI,EAAE,OAAO,MAAM;AACjB,SAAM,KAAK,IAAI;AACf,SAAM,EAAE;;;AAGZ,QAAO;;AAGT,SAAgB,kBAAkB,KAAa,MAE3C,EAAE,EAAE;CACN,MAAM,QAAQ,SAAS,KAAK,IAAI;CAChC,MAAM,SAAS,MAAM;AACrB,QAAO,MAAM,MAAM,EAAE,CAAC,KAAI,MACxB,OAAO,YAAa,EAAE,KAAK,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CACrD"}