@@ -13,33 +13,36 @@ var options = {}; // Initialize the options - this will be populated when the js
1313 * @returns {Promise }
1414 */
1515var generateHeading = function ( data ) {
16- return new Promise ( function ( resolve , reject ) {
17- if ( options . KEYS ) { return resolve ( options . KEYS ) ; }
18-
19- var keys = _ . map ( _ . keys ( data ) , function ( key , indx ) { // for each key
20- if ( _ . isObject ( data [ key ] ) ) {
21- // if the data at the key is a document, then we retrieve the subHeading starting with an empty string heading and the doc
22- return generateSubHeading ( '' , data [ key ] ) ;
23- }
24- return key ;
25- } ) ;
26-
27- // Check for a consistent schema that does not require the same order:
28- // if we only have one document - then there is no possiblility of multiple schemas
29- if ( keys && keys . length <= 1 ) {
30- return resolve ( _ . flatten ( keys ) || [ ] ) ;
16+ if ( options . KEYS ) { return Promise . resolve ( options . KEYS ) ; }
17+
18+ var keys = _ . map ( data , function ( document , indx ) { // for each key
19+ if ( _ . isObject ( document ) ) {
20+ // if the data at the key is a document, then we retrieve the subHeading starting with an empty string heading and the doc
21+ return generateDocumentHeading ( '' , document ) ;
22+ }
23+ } ) ;
24+
25+ // Check for a consistent schema that does not require the same order:
26+ // if we only have one document - then there is no possibility of multiple schemas
27+ if ( keys && keys . length <= 1 ) {
28+ return Promise . resolve ( _ . flatten ( keys ) || [ ] ) ;
29+ }
30+ // else - multiple documents - ensure only one schema (regardless of field ordering)
31+ var firstDocSchema = _ . flatten ( keys [ 0 ] ) ,
32+ schemaDifferences = 0 ;
33+
34+ _ . each ( keys , function ( keyList ) {
35+ // If there is a difference between the schemas, increment the counter of schema inconsistencies
36+ var diff = _ . difference ( firstDocSchema , _ . flatten ( keyList ) ) ;
37+ if ( ! _ . isEqual ( diff , [ ] ) ) {
38+ schemaDifferences ++ ;
3139 }
32- // else - multiple documents - ensure only one schema (regardless of field ordering)
33- var firstDocSchema = _ . flatten ( keys [ 0 ] ) ;
34- _ . each ( keys , function ( keyList ) {
35- // If there is a difference between the schemas, throw the inconsistent schema error
36- var diff = _ . difference ( firstDocSchema , _ . flatten ( keyList ) ) ;
37- if ( ! _ . isEqual ( diff , [ ] ) ) {
38- return reject ( new Error ( constants . Errors . json2csv . notSameSchema ) ) ;
39- }
40- } ) ;
41- return resolve ( _ . flatten ( keys [ 0 ] ) ) ;
4240 } ) ;
41+
42+ // If there are schema inconsistencies, throw a schema not the same error
43+ if ( schemaDifferences ) { return Promise . reject ( new Error ( constants . Errors . json2csv . notSameSchema ) ) ; }
44+
45+ return Promise . resolve ( _ . flatten ( keys [ 0 ] ) ) ;
4346} ;
4447
4548/**
@@ -48,21 +51,22 @@ var generateHeading = function(data) {
4851 * @param data
4952 * @returns {Array }
5053 */
51- var generateSubHeading = function ( heading , data ) {
52- var subKeys , // retrieve the keys from the current document
53- newKey = '' ; // temporary variable to aid in determining the heading - used to generate the 'nested' headings
54+ var generateDocumentHeading = function ( heading , data ) {
55+ var keyName = '' ; // temporary variable to aid in determining the heading - used to generate the 'nested' headings
5456
55- subKeys = _ . map ( _ . keys ( data ) , function ( subKey ) {
57+ var documentKeys = _ . map ( _ . keys ( data ) , function ( currentKey ) {
5658 // 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
57- newKey = heading === '' ? subKey : heading + '.' + subKey ;
58- if ( _ . isObject ( data [ subKey ] ) && ! _ . isNull ( data [ subKey ] ) && _ . isUndefined ( data [ subKey ] . length ) && _ . keys ( data [ subKey ] ) . length > 0 ) { // If we have another nested document
59- return generateSubHeading ( newKey , data [ subKey ] ) ; // Recur on the sub-document to retrieve the full key name
60- } else {
61- return newKey ; // Set the key name since we don't have a sub document
59+ keyName = heading ? heading + '.' + currentKey : currentKey ;
60+
61+ // If we have another nested document, recur on the sub-document to retrieve the full key name
62+ if ( _ . isObject ( data [ currentKey ] ) && ! _ . isNull ( data [ currentKey ] ) && _ . isUndefined ( data [ currentKey ] . length ) && _ . keys ( data [ currentKey ] ) . length ) {
63+ return generateDocumentHeading ( keyName , data [ currentKey ] ) ;
6264 }
65+ // Otherwise return this key name since we don't have a sub document
66+ return keyName ;
6367 } ) ;
6468
65- return subKeys ; // Return the headings joined by our field delimiter
69+ return documentKeys ; // Return the headings joined by our field delimiter
6670} ;
6771
6872/**
@@ -83,7 +87,7 @@ var convertData = function (data, keys) {
8387 output . push ( convertData ( data [ pathPrefix ] , [ pathRemainder ] ) ) ;
8488 } else if ( keys . indexOf ( key ) > - 1 ) { // If the keys contain the current key, then process the data
8589 value = data [ key ] ; // Set the current data that we are looking at
86- convertField ( value , output ) ;
90+ output . push ( convertField ( value , output ) ) ;
8791 }
8892 } ) ;
8993 return output ; // Return the data joined by our field delimiter
@@ -94,17 +98,15 @@ var convertData = function (data, keys) {
9498 * @param value
9599 * @param output
96100 */
97- var convertField = function ( value , output ) {
101+ var convertField = function ( value ) {
98102 if ( _ . isArray ( value ) ) { // We have an array of values
99- output . push ( options . DELIMITER . WRAP + '[' + value . join ( options . DELIMITER . ARRAY ) + ']' + options . DELIMITER . WRAP ) ;
103+ return options . DELIMITER . WRAP + '[' + value . join ( options . DELIMITER . ARRAY ) + ']' + options . DELIMITER . WRAP ;
100104 } else if ( _ . isDate ( value ) ) { // If we have a date
101- output . push ( value . toString ( ) ) ;
105+ return options . DELIMITER . WRAP + value . toString ( ) + options . DELIMITER . WRAP ;
102106 } else if ( _ . isObject ( value ) ) { // If we have an object
103- output . push ( convertData ( value , _ . keys ( value ) ) ) ; // Push the recursively generated CSV
104- } else {
105- value = value ? value . toString ( ) : '' ;
106- output . push ( options . DELIMITER . WRAP + value + options . DELIMITER . WRAP ) ; // Otherwise push the current value
107+ return options . DELIMITER . WRAP + convertData ( value , _ . keys ( value ) ) + options . DELIMITER . WRAP ; // Push the recursively generated CSV
107108 }
109+ return options . DELIMITER . WRAP + ( value ? value . toString ( ) : '' ) + options . DELIMITER . WRAP ; // Otherwise push the current value
108110} ;
109111
110112/**
0 commit comments