const fs = require('fs-extra'); const { toSystemPath } = require('../core/path'); const { keysToLowerCase } = require('../core/util'); // simple inital implementation // better implementation at: // https://github.com/adaltas/node-csv-parse // https://github.com/mafintosh/csv-parser function parseCSV(csv, options) { if (!csv) return []; if (csv.charCodeAt(0) === 0xFEFF) { csv = csv.slice(1); } let delimiter = options.delimiter.replace('\\t', '\t'); let keys = options.fields; let line = 1; let data = []; if (options.header) { keys = getcsv(); options.fields.forEach(field => { if (keys.indexOf(field) == -1) { throw new Error('parseCSV: ' + field + ' is missing in ' + options.path); } }); line++; } let size = keys.length; while (csv.length) { let values = getcsv(); let o = {}; if (values.length != size) { throw new Error('parseCSV: columns do not match. keys: ' + size + ', values: ' + values.length + ' at line ' + line); } for (let i = 0; i < size; i++) { o[keys[i]] = values[i]; } data.push(o); line++; } return data; function getcsv() { let data = [''], l = csv.length, esc = false, escesc = false, n = 0, i = 0; while (i < l) { let s = csv.charAt(i); if (s == '\n') { if (esc) { data[n] += s; } else { i++; break; } } else if (s == '\r') { if (esc) { data[n] += s; } } else if (s == delimiter) { if (esc) { data[n] += s; } else { data[++n] = ''; esc = false; escesc = false; } } else if (s == '"') { if (escesc) { data[n] += s; escesc = false; } if (esc) { esc = false; escesc = true; } else { esc = true; escesc = false; } } else { if (escesc) { data[n] += '"'; escesc = false; } data[n] += s; } i++; } csv = csv.substr(i); return data; } } module.exports = { csv: async function(options) { let path = this.parseRequired(options.path, 'string', 'export.csv: path is required.'); let fields = this.parseOptional(options.fields, 'object', []); let header = this.parseOptional(options.header, 'boolean', false); let delimiter = this.parseOptional(options.delimiter, 'string', ','); let csv = await fs.readFile(toSystemPath(path), 'utf8'); return parseCSV(csv, { fields, header, delimiter }); }, xml: async function(options) { // TODO: import.xml throw new Error('import.xml: not implemented.'); }, };