@@ -11,22 +11,22 @@ var retrieveSubHeading = function (heading, data) {
1111 newKey ; // temporary variable to aid in determining the heading - used to generate the 'nested' headings
1212 _ . each ( subKeys , function ( subKey , indx ) {
1313 // If the given heading is empty, then we set the heading to be the subKey, otherwise set it as a nested heading w/ a dot
14- newKey = heading === '' ? subKey : heading + '.' + subKey ;
15- if ( typeof data [ subKey ] === 'object' && data [ subKey ] !== null ) { // If we have another nested document
14+ newKey = heading === '' ? subKey : heading + '.' + subKey ;
15+ if ( typeof data [ subKey ] === 'object' && data [ subKey ] !== null && typeof data [ subKey ] . length === 'undefined' ) { // If we have another nested document
1616 subKeys [ indx ] = retrieveSubHeading ( newKey , data [ subKey ] ) ; // Recur on the subdocument to retrieve the full key name
1717 } else {
1818 subKeys [ indx ] = newKey ; // Set the key name since we don't have a sub document
1919 }
2020 } ) ;
21- return subKeys . join ( options . DELIMITER ) ; // Return the headings joined by our delimiter
21+ return subKeys . join ( options . DELIMITER . FIELD ) ; // Return the headings joined by our field delimiter
2222} ;
2323
2424// Retrieve the headings for all documents and return it. This checks that all documents have the same schema.
2525var retrieveHeading = function ( data ) {
2626 return function ( cb ) { // Returns a function that takes a callback - the function is passed to async.parallel
2727 var keys = _ . keys ( data ) ; // Retrieve the current data keys
2828 _ . each ( keys , function ( key , indx ) { // for each key
29- if ( typeof data [ key ] === 'object' ) {
29+ if ( typeof data [ key ] === 'object' ) {
3030 // if the data at the key is a document, then we retrieve the subHeading starting with an empty string heading and the doc
3131 keys [ indx ] = retrieveSubHeading ( '' , data [ key ] ) ;
3232 }
@@ -35,7 +35,7 @@ var retrieveHeading = function (data) {
3535 keys = _ . uniq ( keys ) ;
3636 // If we have more than 1 unique list, then not all docs have the same schema - report an error
3737 if ( keys . length > 1 ) { throw new Error ( 'Not all documents have the same schema.' , keys ) ; }
38- cb ( null , _ . flatten ( keys ) . join ( options . DELIMITER ) ) ; // Return headings back
38+ return cb ( null , _ . flatten ( keys ) . join ( options . DELIMITER . FIELD ) ) ; // Return headings back
3939 } ;
4040} ;
4141
@@ -46,14 +46,16 @@ var convertData = function (data, keys) {
4646 _ . each ( keys , function ( key , indx ) { // For each key
4747 value = data [ key ] ; // Set the current data that we are looking at
4848 if ( keys . indexOf ( key ) > - 1 ) { // If the keys contain the current key, then process the data
49- if ( typeof value === 'object' ) { // If we have an object
49+ if ( typeof value === 'object' && value !== null && typeof value . length === 'undefined' ) { // If we have an object
5050 output . push ( convertData ( value , _ . keys ( value ) ) ) ; // Push the recursively generated CSV
51+ } else if ( typeof value === 'object' && value !== null && typeof value . length === 'number' ) { // We have an array of values
52+ output . push ( '[' + value . join ( options . DELIMITER . ARRAY ) + ']' ) ;
5153 } else {
5254 output . push ( value ) ; // Otherwise push the current value
5355 }
5456 }
5557 } ) ;
56- return output . join ( options . DELIMITER ) ; // Return the data joined by our field delimiter
58+ return output . join ( options . DELIMITER . FIELD ) ; // Return the data joined by our field delimiter
5759} ;
5860
5961// Generate the CSV representing the given data.
@@ -74,17 +76,17 @@ module.exports = {
7476 else { options = opts ; } // Options were passed, set the global options value
7577 if ( ! data ) { callback ( new Error ( 'Cannot call json2csv on ' + data + '.' ) ) ; return null ; } // If we don't receive data, report an error
7678 if ( typeof data !== 'object' ) { // If the data was not a single document or an array of documents
77- cb ( new Error ( 'Data provided was not an array of documents.' ) ) ; // Report the error back to the caller
79+ return cb ( new Error ( 'Data provided was not an array of documents.' ) ) ; // Report the error back to the caller
7880 } else if ( typeof data === 'object' && ! data . length ) { // Single document, not an array
7981 data = [ data ] ; // Convert to an array of the given document
8082 }
8183 // Retrieve the heading and the CSV asynchronously in parallel
8284 async . parallel ( [ retrieveHeading ( data ) , generateCsv ( data ) ] , function ( err , res ) {
8385 if ( ! err ) {
8486 // Data received with no errors, join the two responses with an end of line delimiter to setup heading and CSV body
85- callback ( null , res . join ( options . EOL ) ) ;
87+ return callback ( null , res . join ( options . EOL ) ) ;
8688 } else {
87- callback ( err , null ) ; // Report received error back to caller
89+ return callback ( err , null ) ; // Report received error back to caller
8890 }
8991 } ) ;
9092 }
0 commit comments