jsforce
Version:
Salesforce API Library for JavaScript
181 lines (165 loc) • 4.14 kB
JavaScript
var _ = require('underscore'),
SfDate = require('./date');
/**
* @private
*/
function toCSV(records, headers, options) {
options = options || {};
if (!headers) {
headers = extractHeaders(records, options);
}
var rows = _.map(records, function(record){ return recordToCSV(record, headers, options); });
return arrayToCSV(headers) + "\n" + rows.join("\n");
}
/**
* @private
*/
function extractHeaders(records, options) {
options = options || {};
var headers = {};
_.forEach(records, function(record) {
for (var key in record) {
var value = record[key];
if (record.hasOwnProperty(key) && (value === null || typeof value !== 'object')) {
headers[key] = true;
}
}
});
return _.keys(headers);
}
/**
* @private
*/
function recordToCSV(record, headers, options) {
options = options || {};
var row = [];
_.forEach(headers, function(header) {
var value = record[header];
if (value === null && typeof options.nullValue !== 'undefined') {
value = options.nullValue;
}
if (typeof value === 'undefined') { value = null; }
row.push(value);
});
return arrayToCSV(row);
}
/**
* @private
*/
function arrayToCSV(arr) {
return _.map(arr, escapeCSV).join(',');
}
/**
* @private
*/
function escapeCSV(str) {
if (str === null || typeof str === 'undefined') { str = ''; }
str = String(str);
if (str.indexOf('"') >= 0 || str.indexOf(',') >= 0 || /[\n\r]/.test(str)) {
str = '"' + str.replace(/"/g, '""') + '"';
}
return str;
}
/**
* @private
* @class
* @constructor
* @param {String} text - CSV string
*/
var CSVParser = function(text) {
this.text = text;
this.cursor = 0;
};
CSVParser.prototype = {
nextToken : function() {
var cell;
var dquoted = false;
var firstChar = this.text.charAt(this.cursor);
if (firstChar === '' || firstChar === '\r' || firstChar === '\n') {
return null;
}
if (firstChar === '"') {
dquoted = true;
}
if (dquoted) {
var dq = this.cursor;
while(true) {
dq++;
dq = this.text.indexOf('"', dq);
if (dq<0 || this.text.charAt(dq+1) !== '"') {
break;
} else {
dq++;
}
}
if (dq>=0) {
var delim = this.text.charAt(dq+1);
cell = this.text.substring(this.cursor, dq+1);
this.cursor = dq + (delim === ',' ? 2 : 1);
} else {
cell = this.text.substring(this.cursor);
this.cursor = this.text.length;
}
return cell.replace(/""/g,'"').replace(/^"/,'').replace(/"$/,'');
} else {
var comma = this.text.indexOf(',', this.cursor);
var cr = this.text.indexOf('\r', this.cursor);
var lf = this.text.indexOf('\n', this.cursor);
comma = comma<0 ? this.text.length+1 : comma;
cr = cr<0 ? this.text.length+1 : cr;
lf = lf<0 ? this.text.length+1 : lf;
var pivot = Math.min(comma, cr, lf, this.text.length);
cell = this.text.substring(this.cursor, pivot);
this.cursor = pivot;
if (comma === pivot) {
this.cursor++;
}
return cell;
}
},
nextLine : function() {
for (var c = this.text.charAt(this.cursor);
c === '\r' || c === '\n';
c = this.text.charAt(++this.cursor))
{}
return this.cursor !== this.text.length;
}
};
/**
* @private
*/
function parseCSV(str) {
var parser = new CSVParser(str);
var headers = [];
var token;
if (parser.nextLine()) {
token = parser.nextToken();
while (!_.isUndefined(token) && !_.isNull(token)) {
headers.push(token);
token = parser.nextToken();
}
}
var rows = [];
while (parser.nextLine()) {
var row = {};
token = parser.nextToken();
var i = 0;
while (!_.isUndefined(token) && !_.isNull(token)) {
var header = headers[i++];
row[header] = token;
token = parser.nextToken();
}
rows.push(row);
}
return rows;
}
/**
* @protected
*/
module.exports = {
toCSV : toCSV,
extractHeaders : extractHeaders,
recordToCSV : recordToCSV,
arrayToCSV : arrayToCSV,
parseCSV : parseCSV
};