Repository: mholt/PapaParse
Pull request #322 (2016-07-09 00:25:51)

Support dynamic typing on explicitly defined columns
This PR allows for explicitly defining which columns you'd like to apply dynamic type coercion to. See added tests for all supported use-cases. Here's a basic example:

```js
let csv = `code,price
0001,1.25
0234,5.65`;

Papa.parse(csv, {
  header: true,
  dynamicTypings: {
    price: true
  }
})

// -> [ { code: "0001", price: 1.25 }, { code: "0234", price: 5.65 } ]
```


Patch:
diff --git a/papaparse.js b/papaparse.js
index 0537e0c..4dd12bb 100644
--- a/papaparse.js
+++ b/papaparse.js
@@ -179,6 +179,7 @@
 	function CsvToJson(_input, _config)
 	{
 		_config = _config || {};
+		_config.dynamicTyping = _config.dynamicTyping || false;
 
 		if (_config.worker && Papa.WORKERS_SUPPORTED)
 		{
@@ -845,6 +846,20 @@
 			_results.data.splice(0, 1);
 		}
 
+		function parseDynamic(field, value)
+		{
+			if ((_config.dynamicTyping[field] || _config.dynamicTyping) === true)
+			{
+				if (value === 'true' || value === 'TRUE')
+					return true;
+				else if (value === 'false' || value === 'FALSE')
+					return false;
+				else
+					return tryParseFloat(value);
+			}
+			return value;
+		}
+
 		function applyHeaderAndDynamicTyping()
 		{
 			if (!_results || (!_config.header && !_config.dynamicTyping))
@@ -852,37 +867,31 @@
 
 			for (var i = 0; i < _results.data.length; i++)
 			{
-				var row = {};
+				var row = _config.header ? {} : [];
 
 				for (var j = 0; j < _results.data[i].length; j++)
 				{
-					if (_config.dynamicTyping)
-					{
-						var value = _results.data[i][j];
-						if (value === 'true' || value === 'TRUE')
-							_results.data[i][j] = true;
-						else if (value === 'false' || value === 'FALSE')
-							_results.data[i][j] = false;
-						else
-							_results.data[i][j] = tryParseFloat(value);
-					}
+					var field = j;
+					var value = _results.data[i][j];
 
 					if (_config.header)
+						field = j >= _fields.length ? '__parsed_extra' : _fields[j];
+
+					value = parseDynamic(field, value);
+
+					if (field === '__parsed_extra')
 					{
-						if (j >= _fields.length)
-						{
-							if (!row['__parsed_extra'])
-								row['__parsed_extra'] = [];
-							row['__parsed_extra'].push(_results.data[i][j]);
-						}
-						else
-							row[_fields[j]] = _results.data[i][j];
+						row[field] = row[field] || [];
+						row[field].push(value);
 					}
+					else
+						row[field] = value;
 				}
 
+				_results.data[i] = row;
+
 				if (_config.header)
 				{
-					_results.data[i] = row;
 					if (j > _fields.length)
 						addError('FieldMismatch', 'TooManyFields', 'Too many fields: expected ' + _fields.length + ' fields but parsed ' + j, i);
 					else if (j < _fields.length)


Test patch:
diff --git a/tests/test-cases.js b/tests/test-cases.js
index 4f98590..9dda6ff 100644
--- a/tests/test-cases.js
+++ b/tests/test-cases.js
@@ -652,6 +652,38 @@ var PARSE_TESTS = [
 			errors: []
 		}
 	},
+	{
+		description: "Dynamic typing applies to specific columns",
+		input: 'A,B,C\r\n1,2.2,1e3\r\n-4,-4.5,-4e-5',
+		config: { header: true, dynamicTyping: { A: true, C: true } },
+		expected: {
+			data: [{"A": 1, "B": "2.2", "C": 1000}, {"A": -4, "B": "-4.5", "C": -0.00004}],
+			errors: []
+		}
+	},
+	{
+		description: "Dynamic typing applies to specific columns by index",
+		input: '1,2.2,1e3\r\n-4,-4.5,-4e-5\r\n-,5a,5-2',
+		config: { dynamicTyping: { 1: true } },
+		expected: {
+			data: [["1", 2.2, "1e3"], ["-4", -4.5, "-4e-5"], ["-", "5a", "5-2"]],
+			errors: []
+		}
+	},
+	{
+		description: "Dynamic typing can be applied to `__parsed_extra`",
+		input: 'A,B,C\r\n1,2.2,1e3,5.5\r\n-4,-4.5,-4e-5',
+		config: { header: true, dynamicTyping: { A: true, C: true, __parsed_extra: true } },
+		expected: {
+			data: [{"A": 1, "B": "2.2", "C": 1000, "__parsed_extra": [ 5.5 ]}, {"A": -4, "B": "-4.5", "C": -0.00004}],
+			errors: [{
+				"type": "FieldMismatch",
+				"code": "TooManyFields",
+				"message": "Too many fields: expected 3 fields but parsed 4",
+				"row": 0
+			}]
+		}
+	},
 	{
 		description: "Blank line at beginning",
 		input: '\r\na,b,c\r\nd,e,f',