Skip to content

Commit 6c659f5

Browse files
authored
Merge pull request #36 from babyadoresorange/master
use native BigInt as option, add always option
2 parents a544c58 + 1556563 commit 6c659f5

8 files changed

Lines changed: 355 additions & 9 deletions

File tree

README.md

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ json-bigint
44
[![Build Status](https://secure.travis-ci.org/sidorares/json-bigint.png)](http://travis-ci.org/sidorares/json-bigint)
55
[![NPM](https://nodei.co/npm/json-bigint.png?downloads=true&stars=true)](https://nodei.co/npm/json-bigint/)
66

7-
JSON.parse/stringify with bigints support. Based on Douglas Crockford [JSON.js](https://github.com/douglascrockford/JSON-js) package and [bignumber.js](https://github.com/MikeMcl/bignumber.js) library.
7+
JSON.parse/stringify with bigints support. Based on Douglas Crockford [JSON.js](https://github.com/douglascrockford/JSON-js) package and [bignumber.js](https://github.com/MikeMcl/bignumber.js) library.
8+
9+
Native `Bigint` was added to JS recently, so we added an option to leverage it instead of `bignumber.js`. However, the parsing with native `BigInt` is kept an option for backward compability.
810

911
While most JSON parsers assume numeric values have same precision restrictions as IEEE 754 double, JSON specification _does not_ say anything about number precision. Any floating point number in decimal (optionally scientific) notation is valid JSON value. It's a good idea to serialize values which might fall out of IEEE 754 integer precision as strings in your JSON api, but `{ "value" : 9223372036854775807}`, for example, is still a valid RFC4627 JSON string, and in most JS runtimes the result of `JSON.parse` is this object: `{ value: 9223372036854776000 }`
1012

@@ -107,6 +109,61 @@ Default type: object, With option type: string
107109
108110
```
109111

112+
#### options.useNativeBigInt, boolean, default false
113+
Specifies if parser uses native BigInt instead of bignumber.js
114+
115+
example:
116+
```js
117+
var JSONbig = require('json-bigint');
118+
var JSONbigNative = require('json-bigint')({"useNativeBigInt": true});
119+
var key = '{ "key": 993143214321423154315154321 }';
120+
console.log(`\n\nStoring the Number as native BigInt, instead of a BigNumber`);
121+
console.log('Input:', key);
122+
var normal = JSONbig.parse(key);
123+
var nativeBigInt = JSONbigNative.parse(key);
124+
console.log('Default type: %s, With option type: %s', typeof normal.key, typeof nativeBigInt.key);
125+
126+
```
127+
128+
Output
129+
```
130+
Storing the Number as native BigInt, instead of a BigNumber
131+
Input: { "key": 993143214321423154315154321 }
132+
Default type: object, With option type: bigint
133+
134+
```
135+
136+
#### options.alwaysParseAsBig, boolean, default false
137+
Specifies if all numbers should be stored as BigNumber.
138+
139+
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 Number to be-and-stay BigNumber)
140+
141+
example:
142+
```js
143+
var JSONbig = require('json-bigint');
144+
var JSONbigAlways = require('json-bigint')({"alwaysParseAsBig": true});
145+
var key = '{ "key": 123 }'; // there is no need for BigNumber by default, but we're forcing it
146+
console.log(`\n\nStoring the Number as a BigNumber, instead of a Number`);
147+
console.log('Input:', key);
148+
var normal = JSONbig.parse(key);
149+
var always = JSONbigAlways.parse(key);
150+
console.log('Default type: %s, With option type: %s', typeof normal.key, typeof always.key);
151+
152+
```
153+
154+
Output
155+
```
156+
Storing the Number as a BigNumber, instead of a Number
157+
Input: { "key": 123 }
158+
Default type: number, With option type: object
159+
160+
```
161+
162+
If you want to force all numbers to be parsed as native `BigInt`
163+
(you probably do! Otherwise any calulations become a real headache):
164+
```js
165+
var JSONbig = require('json-bigint')({"alwaysParseAsBig": true, "useNativeBigInt": true});
166+
```
110167

111168
### Links:
112169
- [RFC4627: The application/json Media Type for JavaScript Object Notation (JSON)](http://www.ietf.org/rfc/rfc4627.txt)
@@ -115,3 +172,20 @@ Default type: object, With option type: string
115172
- [What is JavaScript's Max Int? What's the highest Integer value a Number can go to without losing precision?](http://stackoverflow.com/questions/307179/what-is-javascripts-max-int-whats-the-highest-integer-value-a-number-can-go-t)
116173
- [Large numbers erroneously rounded in Javascript](http://stackoverflow.com/questions/1379934/large-numbers-erroneously-rounded-in-javascript)
117174

175+
### Note on native BigInt support
176+
177+
#### Stringifying
178+
Full support out-of-the-box, stringifies BigInts as pure numbers (no quotes, no `n`)
179+
180+
#### Limitations
181+
- Roundtrip operations
182+
183+
`s === JSONbig.stringify(JSONbig.parse(s))` but
184+
185+
`o !== JSONbig.parse(JSONbig.stringify(o))`
186+
187+
when `o` has a value with something like `123n`.
188+
189+
`JSONbig` stringify `123n` as `123`, which becomes `number` (aka `123` not `123n`) by default when being reparsed.
190+
191+
There is currently no consistent way to deal with this issue, so we decided to leave it, handling this specific case is then up to users.

lib/parse.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ var json_parse = function (options) {
7676
// Default options one can override by passing options to the parse()
7777
var _options = {
7878
"strict": false, // not being strict means do not generate syntax errors for "duplicate key"
79-
"storeAsString": false // toggles whether the values should be stored as BigNumber (default) or a string
79+
"storeAsString": false, // toggles whether the values should be stored as BigNumber (default) or a string
80+
"alwaysParseAsBig": false, // toggles whether all numbers should be Big
81+
"useNativeBigInt": false // toggles whether to use native BigInt instead of bignumber.js
8082
};
8183

8284

@@ -88,6 +90,8 @@ var json_parse = function (options) {
8890
if (options.storeAsString === true) {
8991
_options.storeAsString = true;
9092
}
93+
_options.alwaysParseAsBig = options.alwaysParseAsBig === true ? options.alwaysParseAsBig : false
94+
_options.useNativeBigInt = options.useNativeBigInt === true ? options.useNativeBigInt : false
9195
}
9296

9397

@@ -174,8 +178,9 @@ var json_parse = function (options) {
174178
//if (number > 9007199254740992 || number < -9007199254740992)
175179
// Bignumber has stricter check: everything with length > 15 digits disallowed
176180
if (string.length > 15)
177-
return (_options.storeAsString === true) ? string : new BigNumber(string);
178-
return number;
181+
return _options.storeAsString ? string : _options.useNativeBigInt ? BigInt(string) : new BigNumber(string);
182+
else
183+
return !_options.alwaysParseAsBig ? number : _options.useNativeBigInt ? BigInt(number) : new BigNumber(number);
179184
}
180185
},
181186

@@ -191,12 +196,17 @@ var json_parse = function (options) {
191196
// When parsing for string values, we must look for " and \ characters.
192197

193198
if (ch === '"') {
199+
var startAt = at;
194200
while (next()) {
195201
if (ch === '"') {
202+
if (at - 1 > startAt)
203+
string += text.substring(startAt, at - 1);
196204
next();
197205
return string;
198206
}
199207
if (ch === '\\') {
208+
if (at - 1 > startAt)
209+
string += text.substring(startAt, at - 1);
200210
next();
201211
if (ch === 'u') {
202212
uffff = 0;
@@ -213,8 +223,7 @@ var json_parse = function (options) {
213223
} else {
214224
break;
215225
}
216-
} else {
217-
string += ch;
226+
startAt = at;
218227
}
219228
}
220229
}

lib/stringify.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ var JSON = module.exports;
249249

250250
case 'boolean':
251251
case 'null':
252+
case 'bigint':
252253

253254
// If the value is a boolean or null, convert it to a string. Note:
254255
// typeof null does not produce 'null'. The case is included here in

package-lock.json

Lines changed: 167 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "json-bigint",
3-
"version": "0.3.0",
3+
"version": "0.4.0",
44
"description": "JSON.parse with bigints support",
55
"main": "index.js",
66
"scripts": {
@@ -26,4 +26,4 @@
2626
"chai": "~1.9.1",
2727
"mocha": "~1.20.1"
2828
}
29-
}
29+
}

0 commit comments

Comments
 (0)