abstractor
Version:
Node.js abstraction layer and automation framework.
164 lines (110 loc) • 5.62 kB
JavaScript
/***********************************************************************************
Abstractor | CSV module | MIT License | ©2016 Hexagon <github.com/hexagon>
CSV parser and generator. Parser uses fast-csv.
If input payload is an array width objects, the contained objects are
converted to CSV rows.
If input payload is a string, the string is parsed to an array of objects.
----------------------------------------------------------------------------
Dependencies
fast-csv
----------------------------------------------------------------------------
Options
-----------------+-----------------+----------------------+-----------------
Option | Type | Default | Mandatory
-----------------+-----------------+----------------------+-----------------
headers | boolean | true | no
-----------------+-----------------+----------------------+-----------------
I/O
-------------------------------+----------------------+---------------------
Incoming property | Possible triggers | Sets property
-------------------------------+----------------------+---------------------
| success | payload
payload: <csv string> +----------------------+---------------------
| error | error
-------------------------------+----------------------+---------------------
| success | payload
payload: <object> +----------------------+---------------------
| error | error
-------------------------------+----------------------+---------------------
***********************************************************************************/
;
const
Node = require("../node.js"),
csvHelper = require("fast-csv");
class CSV extends Node {
quote(s) {
// Strings containing double quote, crLf or comma require quoting
var needQuotes = false;
if( s.indexOf && (s.indexOf("\"") !== -1
|| s.indexOf("\r\n") !== -1
|| s.indexOf(",") !== -1 )
) needQuotes = true;
// Return regular string by default, or double quoted string if needed
return needQuotes ? "\"" + s.replace(/\"/g,"\"\"") + "\"" : s;
}
invoke(msg) {
var self = this;
// ToDo, headers should have a default, and be passed to this.getConfig
// Parse if we got a string
if ( typeof msg.payload == "string" ) {
var rows = [],
headers = (this.config.headers === undefined ? true : this.config.headers);
try {
var csvFile = csvHelper.fromString(msg.payload, {headers: headers, trim:true});
csvFile.on("data", function(data){
rows.push(data);
});
csvFile.on("end", function(){
self.success( msg, rows);
});
} catch (e) {
self.error( msg, "Error whild parsing CSV-file: " + e);
}
// Stringify if we got an object
} else if ( typeof msg.payload == "object" ) {
// ToDo: Add headers if it is the first object/row of file, and if it is requested
// Force first level to be array
if( !Array.isArray(msg.payload) ) {
msg.payload = [msg.payload];
}
let rowString = "",
wasFirstLevel = false;
msg.payload.forEach((row) => {
// If second level is an array
if( Array.isArray(row) ) {
row.forEach(function(col) {
rowString += self.quote(col.toString()) + ",";
});
// Finalize this row
if (rowString.length>0) {
rowString = rowString.substring(0, rowString.length - 1) + "\r\n";
}
// If second level is an object
} else if ( typeof row === "object" ) {
Object.keys(row).forEach(function(key) {
let col = row[key];
rowString += self.quote(col.toString()) + ",";
});
// Finalize this row
if (rowString.length>0) {
rowString = rowString.substring(0, rowString.length - 1) + "\r\n";
}
// If second level is something else, we're actually at "first level"
} else {
wasFirstLevel = true;
rowString += self.quote(row) + ",";
}
});
if( wasFirstLevel ) {
// Finalize row
if (rowString.length>0) {
rowString = rowString.substring(0, rowString.length - 1) + "\r\n";
}
}
this.success( msg, rowString );
} else {
return this.error(msg, "CSV node could not determine what to do with payload of type " + typeof msg.payload);
}
}
}
module.exports = CSV;