Repository: zemirco/json2csv (JavaScript)

Issue:
Serializing object containing a ctor function causes crash
I am trying to serialize a list of objects, which contain the constructor to a sub-object for internal reasons in an attribute `_cfgType`.

    class LensValuedSettingArgs {}
    ...
    FocusPos = new LensValuedSetting({ _cfgType:LensValuedSettingArgs, ... })

this causes a runtime error, as this property cannot be serialized.

    TypeError: Cannot read property 'replace' of undefined
      at node_modules/json2csv/lib/json2csv.js:275:50
      at Array.forEach (native)
      at node_modules/json2csv/lib/json2csv.js:215:21
      at Array.forEach (native)
      at createColumnContent (node_modules/json2csv/lib/json2csv.js:209:50)
      at Object.<anonymous>.module.exports (node_modules/json2csv/lib/json2csv.js:60:13)

Since the object hierarchy is deep and complex, I would like to be able to specify `ignoreFields` instead of `fields`, or the parser should gracefully ignore attributes containing a function


Discussion:

Patch:
diff --git a/lib/json2csv.js b/lib/json2csv.js
index 15385199..4d86b14c 100644
--- a/lib/json2csv.js
+++ b/lib/json2csv.js
@@ -248,39 +248,41 @@ function createColumnContent(params, str) {
             stringifiedElement = JSON.stringify(val);
           }
 
-          if (params.preserveNewLinesInValues && typeof val === 'string') {
-            stringifiedElement = stringifiedElement
-              .replace(/\u2028/g, '\n')
-              .replace(/\u2029/g, '\r');
-          }
-
-          if (typeof val === 'object') {
-            // In some cases (e.g. val is a Date), stringifiedElement is already a quoted string.
-            // Strip the leading and trailing quote if so, so we don't end up double-quoting it
-            stringifiedElement = replaceQuotationMarks(stringifiedElement, '');
-
-            // If val is a normal object, we want to escape its JSON so any commas etc
-            // don't get interpreted as field separators
-            stringifiedElement = JSON.stringify(stringifiedElement);
-          }
-
-          if (params.quote !== '"') {
-            stringifiedElement = replaceQuotationMarks(stringifiedElement, params.quote);
+          if (stringifiedElement !== undefined) {
+            if (params.preserveNewLinesInValues && typeof val === 'string') {
+              stringifiedElement = stringifiedElement
+                .replace(/\u2028/g, '\n')
+                .replace(/\u2029/g, '\r');
+            }
+
+            if (typeof val === 'object') {
+              // In some cases (e.g. val is a Date), stringifiedElement is already a quoted string.
+              // Strip the leading and trailing quote if so, so we don't end up double-quoting it
+              stringifiedElement = replaceQuotationMarks(stringifiedElement, '');
+
+              // If val is a normal object, we want to escape its JSON so any commas etc
+              // don't get interpreted as field separators
+              stringifiedElement = JSON.stringify(stringifiedElement);
+            }
+
+            if (params.quote !== '"') {
+              stringifiedElement = replaceQuotationMarks(stringifiedElement, params.quote);
+            }
+
+            //JSON.stringify('\\') results in a string with two backslash
+            //characters in it. I.e. '\\\\'.
+            stringifiedElement = stringifiedElement.replace(/\\\\/g, '\\');
+
+            if (params.excelStrings && typeof val === 'string') {
+              stringifiedElement = '"="' + stringifiedElement + '""';
+            }
+
+            //Replace single quote with double quote.  Single quote are preceeded by
+            //a backslash,  and it's not at the end of the stringifiedElement.
+            stringifiedElement = stringifiedElement.replace(/(\\")(?=.)/g, params.doubleQuote);
+
+            line += stringifiedElement;
           }
-
-          //JSON.stringify('\\') results in a string with two backslash
-          //characters in it. I.e. '\\\\'.
-          stringifiedElement = stringifiedElement.replace(/\\\\/g, '\\');
-
-          if (params.excelStrings && typeof val === 'string') {
-            stringifiedElement = '"="' + stringifiedElement + '""';
-          }
-
-          //Replace single quote with double quote.  Single quote are preceeded by
-          //a backslash,  and it's not at the end of the stringifiedElement.
-          stringifiedElement = stringifiedElement.replace(/(\\")(?=.)/g, params.doubleQuote);
-
-          line += stringifiedElement;
         }
 
         line += params.delimiter;


Test patch:
diff --git a/test/index.js b/test/index.js
index dde40978..1c9167c2 100644
--- a/test/index.js
+++ b/test/index.js
@@ -123,6 +123,19 @@ async.parallel(loadFixtures(csvFixtures), function (err) {
     });
   });
 
+  test('should parse json to csv even if json include functions', function (t) {
+    json2csv({
+      data: {
+        a: 1,
+        funct: function (a) { return a + 1; },
+      }
+    }, function (error, csv) {
+      t.error(error);
+      t.equal(csv, '"a","funct"\n1,');
+      t.end();
+    });
+  });
+
   test('should parse data:{} to csv with only column title', function (t) {
     json2csv({
       data: {},