From dfcf4e6bd71c151df7f7be49b391e18dd74deec5 Mon Sep 17 00:00:00 2001
From: Dan Vanderkam <danvk@sidewalklabs.com>
Date: Wed, 28 Dec 2016 12:47:02 -0500
Subject: [PATCH] Check for strings in native format

---
 auto_tests/tests/formats.js | 10 ++++++++++
 src/dygraph.js              | 20 +++++++++++++++++++-
 tests/native-format.html    |  8 ++++----
 3 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/auto_tests/tests/formats.js b/auto_tests/tests/formats.js
index f16cc6d..2548d99 100644
--- a/auto_tests/tests/formats.js
+++ b/auto_tests/tests/formats.js
@@ -77,6 +77,16 @@ it('testXValueParser', function() {
   assert.equal(6, g.getValue(3, 0));
 });
 
+it('should throw on strings in native format', () => {
+  assert.throws(() => {
+    new Dygraph('graph', [['1', '10'], ['2', '20']])
+  }, /expected number or date/i);
+
+  assert.throws(() => {
+    new Dygraph('graph', [[new Date(), '10'], [new Date(), '20']])
+  }, /expected number or array/i);
+});
+
 var assertData = function(g) {
   var expected = dataArray;
 
diff --git a/src/dygraph.js b/src/dygraph.js
index c12bbec..7cb9bff 100644
--- a/src/dygraph.js
+++ b/src/dygraph.js
@@ -40,7 +40,6 @@
  And error bars will be calculated automatically using a binomial distribution.
 
  For further documentation and examples, see http://dygraphs.com/
-
  */
 
 import DygraphLayout from './dygraph-layout';
@@ -2776,6 +2775,23 @@ Dygraph.prototype.parseCSV_ = function(data) {
   return ret;
 };
 
+// In native format, all values must be dates or numbers.
+// This check isn't perfect but will catch most mistaken uses of strings.
+function validateNativeFormat(data) {
+  const firstRow = data[0];
+  const firstX = firstRow[0];
+  if (typeof firstX !== 'number' && !utils.isDateLike(firstX)) {
+    throw new Error(`Expected number or date but got ${typeof firstX}: ${firstX}.`);
+  }
+  for (let i = 1; i < firstRow.length; i++) {
+    const val = firstRow[i];
+    if (val === null || val === undefined) continue;
+    if (typeof val === 'number') continue;
+    if (utils.isArrayLike(val)) continue;  // e.g. error bars or custom bars.
+    throw new Error(`Expected number or array but got ${typeof val}: ${val}.`);
+  }
+}
+
 /**
  * The user has provided their data as a pre-packaged JS array. If the x values
  * are numeric, this is the same as dygraphs' internal format. If the x values
@@ -2795,6 +2811,8 @@ Dygraph.prototype.parseArray_ = function(data) {
     return null;
   }
 
+  validateNativeFormat(data);
+
   var i;
   if (this.attr_("labels") === null) {
     console.warn("Using default labels. Set labels explicitly via 'labels' " +
diff --git a/tests/native-format.html b/tests/native-format.html
index 8b3bca8..a9f24b5 100644
--- a/tests/native-format.html
+++ b/tests/native-format.html
@@ -24,10 +24,10 @@
     <script type="text/javascript">
       g2 = new Dygraph(document.getElementById("graphdiv2"),
                        [
-                         [1,10,100],
-                         [2,20,80],
-                         [3,50,60],
-                         [4,70,80]
+                         ['1', '10', '100'],
+                         ['2', '20', '80'],
+                         ['3', '50', '60'],
+                         ['4', '70', '80']
                        ],
                        {
                          labels: [ "x", "A", "B" ]
-- 
2.7.4