129 lines
3.3 KiB
JavaScript
129 lines
3.3 KiB
JavaScript
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.');
|
|
},
|
|
|
|
}; |