Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ big number JSON:
JSON.parse(input).value : 9223372036854775807
JSON.stringify(JSON.parse(input)): {"value":9223372036854775807,"v2":123}
```

### Options
The behaviour of the parser is somewhat configurable through 'options'

Expand All @@ -54,6 +55,7 @@ The default follows what is allowed in standard json and resembles the behavior
Setting options.strict = true will fail-fast on such duplicate-key occurances and thus warn you upfront of possible lost information.

example:

```js
var JSONbig = require('json-bigint');
var JSONstrict = require('json-bigint')({"strict": true});
Expand All @@ -73,6 +75,7 @@ try {
```

Output

```
Duplicate Key test with big number JSON
Input: { "dupkey": "value 1", "dupkey": "value 2"}
Expand All @@ -87,6 +90,7 @@ Specifies if BigInts should be stored in the object as a string, rather than the
Note that this is a dangerous behavior as it breaks the default functionality of being able to convert back-and-forth without data type changes (as this will convert all BigInts to be-and-stay strings).

example:

```js
var JSONbig = require('json-bigint');
var JSONbigString = require('json-bigint')({"storeAsString": true});
Expand All @@ -100,13 +104,53 @@ console.log('Default type: %s, With option type: %s', typeof withInt.key, typeof
```

Output

```
Storing the BigInt as a string, instead of a BigNumber
Input: { "key": 1234567890123456789 }
Default type: object, With option type: string

```

#### options.floatHints, boolean, default false

Interpret the presence of a decimal point as a loose hint that this number should be treated as a float.

If there is a mantissa and it is non-zero, then the number is parsed as a float (with precision maintained or not as defined by the in-built javascript float interpreter). e.g. `'123.45'` will parse as `123.45` and `12345678901234567890123.456` will convert to `1.2345678901234568e+22`.

If there is a mantissa and it is only a series of zeros, then it is stripped and only the integer part is used to calculate whether a BigNumber conversion is required. i.e. `'123.000'` will parse as `123` and `12345678901234567890123.000` will convert to `BigNumber('12345678901234567890123')`.



#### options.strictFloatHints, boolean, default false

Always interpret the presence of a decimal point as an instruction to parse the number using the in-built javascript float interpreter.

example:

```js
var JSONbig = require('json-bigint');
var JSONbigFloats = require('json-bigint')({"strictFloatHints": true});
var key = '{ "key": '1234567890123456789012345.000' }';
console.log('\n\nAlways interpreting decimal numbers as floats, instead of a BigNumber');
console.log('Input:', key);
var withStrictFloatHints = JSONbigFloats.parse(key);
var asNormal = JSONbig.parse(key);
console.log('Default type: %s, With option type: %s', typeof asNormal.key, typeof withStrictFloatHints.key);

```

Output

```
Always interpreting decimal numbers as floats, instead of a BigNumber
Input: { "key": "1234567890123456789012345.000" }
Default type: object, With option type: number

```




### Links:
- [RFC4627: The application/json Media Type for JavaScript Object Notation (JSON)](http://www.ietf.org/rfc/rfc4627.txt)
Expand Down
20 changes: 18 additions & 2 deletions lib/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ var json_parse = function (options) {
// Default options one can override by passing options to the parse()
var _options = {
"strict": false, // not being strict means do not generate syntax errors for "duplicate key"
"storeAsString": false // toggles whether the values should be stored as BigNumber (default) or a string
"storeAsString": false, // toggles whether the values should be stored as BigNumber (default) or a string
"floatHints": false, // toggles whether to parse numbers with non-zero mantissas as floats
"strictFloatHints": false // toggles whether to always parse numbers with mantissas as floats
};


Expand All @@ -88,6 +90,12 @@ var json_parse = function (options) {
if (options.storeAsString === true) {
_options.storeAsString = true;
}
if(options.floatHints === true) {
_options.floatHints = true;
}
if(options.strictFloatHints === true) {
_options.strictFloatHints = true;
}
}


Expand Down Expand Up @@ -171,10 +179,18 @@ var json_parse = function (options) {
} else {
if (BigNumber == null)
BigNumber = require('bignumber.js');

if (_options.strictFloatHints && string.indexOf('.') !== -1) {
return parseFloat(number);
}

var testForBigNum = (_options.floatHints) ? !/\..*[^0]/.test(string) : true;

//if (number > 9007199254740992 || number < -9007199254740992)
// Bignumber has stricter check: everything with length > 15 digits disallowed
if (string.length > 15)
if (testForBigNum && string.length > 15 ) {
return (_options.storeAsString === true) ? string : new BigNumber(string);
}
return number;
}
},
Expand Down
167 changes: 167 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions test/bigint-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,21 @@ describe("Testing bigint support", function(){
expect(output).to.equal(input);
done();
});

[
['1.23456789012345678901', '1.23456789012345678901'],
['12345678901234.5678901', '12345678901234.5678901'],
['00000000000000.0000000', '0']
].forEach(function (data) {
var input = data[0];
var expected = data[1];
it('should convert any number longer than 15 chars to bignumber, even floats like' + input, function(done){
var JSONbig = require('../index');
var result = JSONbig.parse(input);
expect(result).to.be.instanceof(BigNumber);
expect(result.toString()).to.equal(expected);
done();
});
})

});
33 changes: 33 additions & 0 deletions test/float-hints-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
var mocha = require('mocha')
, assert = require('chai').assert
, expect = require('chai').expect
, BigNumber = require('bignumber.js')
;

describe("Testing 'strictFloatHints' option", function() {


it('should leave numbers with non-zero mantissa as floats', function(done) {
var JSONbig = require('../index')({floatHints: true});
var obj = JSONbig.parse('12345678912345.123');
expect(typeof obj).to.equal('number');
done();
});

it('should convert numbers with a zero mantissa to ints if the integer part is longer than 15 chars', function(done) {
var inputLong = '9223372036854775807.00000';
var inputShort = '75807.00000';
var JSONbig = require('../index')({floatHints: true});

var objLong = JSONbig.parse(inputLong);
expect(objLong, "instanceof big int").to.be.instanceof(BigNumber);
expect(objLong.toString(), "string from big int").to.equal("9223372036854775807");

var objShort = JSONbig.parse(inputShort);
expect(objShort).to.be.a('number');
expect(objShort).to.equal(75807);

done();
});

});
Loading