to-csv
Version:
Convert objects to CSV
89 lines (67 loc) • 2.18 kB
JavaScript
/**
* Module dependencies
*/
var isArray = Array.isArray
, keys = Object.keys;
CSV.CHAR_RETURN = 0xd;
CSV.CHAR_NEWLINE = 0xa;
CSV.DELIMITER = 0x2c;
CSV.CHAR_ENCAPSULATE = 0x22;
function head (a) {
return a[0];
}
function tail (a) {
return a[a.length -1];
}
function char (c) {
return 'number' === typeof c
? String.fromCharCode.apply(null, arguments)
: c;
}
function needsEncapsulation (string) {
return !!string && (
string.toString().indexOf(char(CSV.DELIMITER)) >= 0 ||
string.toString().indexOf(char(CSV.CHAR_RETURN)) >= 0 ||
string.toString().indexOf(char(CSV.CHAR_NEWLINE)) >= 0 ||
string.toString().indexOf(char(CSV.CHAR_ENCAPSULATE)) >= 0
);
}
function encapsulate (string) {
var wrapperChar = char(CSV.CHAR_ENCAPSULATE)
, replaceWith = "\\" + char(CSV.CHAR_ENCAPSULATE)
, escapedValue = string.toString().replace(new RegExp(wrapperChar, 'g'), replaceWith);
return wrapperChar + escapedValue + wrapperChar;
}
/**
* Parses an array of objects to a CSV output
*/
module.exports = CSV;
function CSV (objects, opts) {
if ('object' !== typeof objects) throw new TypeError("expecting an array");
opts = 'object' === typeof opts
? opts
: {};
objects = isArray(objects)
? objects.slice()
: [objects];
if (!objects.length) throw new Error("expecting at least one object");
var headers = keys(head(objects))
, buf = [];
while (objects.length) {
var lbuf = []
, object = objects.shift();
for (var i = 0 ;i < headers.length; ++i) {
var header = headers[i];
if (lbuf.length) lbuf.push(char(CSV.DELIMITER));
object[header] = needsEncapsulation(object[header])
? encapsulate(object[header])
: object[header];
lbuf.push(object[header]);
}
buf.push(lbuf.join(''));
buf.push(char(CSV.CHAR_RETURN, CSV.CHAR_NEWLINE));
}
return false !== opts.headers
? [].concat(headers.join(char(CSV.DELIMITER)), char(CSV.CHAR_NEWLINE)).concat(buf).filter(Boolean).join('')
: buf.filter(Boolean).join('');
}