json-with-bigint 3.3.4 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -7
- package/__tests__/performance.cjs +2 -0
- package/__tests__/unit.cjs +2 -0
- package/json-with-bigint.cjs +41 -0
- package/json-with-bigint.d.cts +2 -27
- package/json-with-bigint.d.ts +2 -27
- package/json-with-bigint.js +41 -0
- package/json-with-bigint.min.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
JS library that allows you to easily serialize and deserialize data with BigInt values
|
|
4
4
|
|
|
5
|
-
## Why would I need
|
|
5
|
+
## Why would I need json-with-bigint?
|
|
6
6
|
|
|
7
7
|
3 reasons:
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ JS library that allows you to easily serialize and deserialize data with BigInt
|
|
|
10
10
|
2. Native JSON.stringify() and JSON.parse() methods in JS can't work with BigInt
|
|
11
11
|
3. Other libraries and pieces of code that you'll find either can't solve this problem while supporting consistent round-trip operations (meaning, you will not get the same BigInt values if you serialize and then deserialize them) or requires you to specify which properties in JSON include BigInt values, or to change your JSON or the way you want to work with your data
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## json-with-bigint advantages
|
|
14
14
|
|
|
15
15
|
✔️ Supports consistent round-trip operations with JSON
|
|
16
16
|
|
|
@@ -24,9 +24,9 @@ JSONParse(JSONStringify(data)).bigNumber === 9007199254740992n // true
|
|
|
24
24
|
|
|
25
25
|
✔️ No need to change your JSON or the way you want to work with your data
|
|
26
26
|
|
|
27
|
-
✔️ You don't have to memorize this library's API, you already know it. Just skip the dot, and that's it (JSONParse()
|
|
27
|
+
✔️ You don't have to memorize this library's API, you already know it. Just skip the dot, and that's it (`JSONParse()`, `JSONStringify()`)
|
|
28
28
|
|
|
29
|
-
✔️ Parses and stringifies all other values other than big numbers the same way as native JSON methods in JS do. You can just replace every `JSON.parse` and `JSON.
|
|
29
|
+
✔️ Parsed big number values are just regular BigInt. Parses and stringifies all other values other than big numbers the same way as native JSON methods in JS do. Signatures match too. You can just replace every `JSON.parse()` and `JSON.strinfigy()` in your project with `JSONParse()` and `JSONStringify()`, and it will work
|
|
30
30
|
|
|
31
31
|
✔️ Correctly parses float numbers and negative numbers
|
|
32
32
|
|
|
@@ -40,11 +40,15 @@ JSONParse(JSONStringify(data)).bigNumber === 9007199254740992n // true
|
|
|
40
40
|
|
|
41
41
|
✔️ Can be used as both ESM and CommonJS module
|
|
42
42
|
|
|
43
|
-
✔️
|
|
43
|
+
✔️ No transpilers needed. Runs even in ES5 environments
|
|
44
44
|
|
|
45
|
-
✔️
|
|
45
|
+
✔️ Actively supported
|
|
46
46
|
|
|
47
|
-
✔️
|
|
47
|
+
✔️ Size: 988 bytes (minified and gzipped)
|
|
48
|
+
|
|
49
|
+
✔️ No dependencies. Even the dev ones
|
|
50
|
+
|
|
51
|
+
✔️ Extensively covered by tests
|
|
48
52
|
|
|
49
53
|
## Getting Started
|
|
50
54
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// ------ Performance tests ------
|
|
2
|
+
// To test both JSONParseV2() and JSONParse(), switch Node.js version (latest vs something old, like 12.3.0)
|
|
3
|
+
|
|
2
4
|
const { performance } = require("perf_hooks");
|
|
3
5
|
const { JSONParse, JSONStringify } = require("../json-with-bigint.cjs");
|
|
4
6
|
|
package/__tests__/unit.cjs
CHANGED
package/json-with-bigint.cjs
CHANGED
|
@@ -51,6 +51,45 @@ const JSONStringify = (value, replacer, space) => {
|
|
|
51
51
|
return denoisedJSON;
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
+
/*
|
|
55
|
+
Function to check if the JSON.parse's context.source feature is supported.
|
|
56
|
+
*/
|
|
57
|
+
const isContextSourceSupported = () => {
|
|
58
|
+
let supported = false;
|
|
59
|
+
|
|
60
|
+
JSON.parse('{"test": 1}', (key, value, context) => {
|
|
61
|
+
if (key === "test" && context && context.source === "1") {
|
|
62
|
+
supported = true;
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return supported;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/*
|
|
71
|
+
Faster (2x) and simpler function to parse JSON.
|
|
72
|
+
Based on JSON.parse's context.source feature, which is not universally available now.
|
|
73
|
+
Does not support the legacy custom format, used in the first version of this library.
|
|
74
|
+
*/
|
|
75
|
+
const JSONParseV2 = (text, reviver) => {
|
|
76
|
+
const intRegex = /^-?\d+$/;
|
|
77
|
+
|
|
78
|
+
return JSON.parse(text, (key, value, context) => {
|
|
79
|
+
const isBigNumber =
|
|
80
|
+
typeof value === "number" &&
|
|
81
|
+
(value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER);
|
|
82
|
+
const isInt = intRegex.test(context.source);
|
|
83
|
+
const isBigInt = isBigNumber && isInt;
|
|
84
|
+
|
|
85
|
+
if (isBigInt) return BigInt(context.source);
|
|
86
|
+
|
|
87
|
+
if (typeof reviver !== "function") return value;
|
|
88
|
+
|
|
89
|
+
return reviver(key, value, context);
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
|
|
54
93
|
/*
|
|
55
94
|
Function to parse JSON.
|
|
56
95
|
If JSON has number values greater than Number.MAX_SAFE_INTEGER, we convert those values to a custom format, then parse them to BigInt values.
|
|
@@ -59,6 +98,8 @@ const JSONStringify = (value, replacer, space) => {
|
|
|
59
98
|
const JSONParse = (text, reviver) => {
|
|
60
99
|
if (!text) return originalParse(text, reviver);
|
|
61
100
|
|
|
101
|
+
if (isContextSourceSupported()) return JSONParseV2(text, reviver); // Shortcut to a faster (2x) and simpler version
|
|
102
|
+
|
|
62
103
|
const MAX_INT = Number.MAX_SAFE_INTEGER.toString();
|
|
63
104
|
const MAX_DIGITS = MAX_INT.length;
|
|
64
105
|
const stringsOrLargeNumbers =
|
package/json-with-bigint.d.cts
CHANGED
|
@@ -1,28 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
[x: string]: Json;
|
|
3
|
-
};
|
|
1
|
+
export const JSONStringify: typeof JSON.stringify;
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export type Json =
|
|
8
|
-
| null
|
|
9
|
-
| undefined
|
|
10
|
-
| string
|
|
11
|
-
| number
|
|
12
|
-
| bigint
|
|
13
|
-
| boolean
|
|
14
|
-
| JsonObject
|
|
15
|
-
| {}
|
|
16
|
-
| JsonArray;
|
|
17
|
-
|
|
18
|
-
export function JSONStringify(
|
|
19
|
-
data: Exclude<Json, undefined>,
|
|
20
|
-
space?: string | number
|
|
21
|
-
): string;
|
|
22
|
-
|
|
23
|
-
export function JSONStringify(
|
|
24
|
-
data: undefined,
|
|
25
|
-
space?: string | number
|
|
26
|
-
): undefined;
|
|
27
|
-
|
|
28
|
-
export function JSONParse<T extends Json = Json>(serializedData: string): T;
|
|
3
|
+
export const JSONParse: typeof JSON.parse;
|
package/json-with-bigint.d.ts
CHANGED
|
@@ -1,28 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
[x: string]: Json;
|
|
3
|
-
};
|
|
1
|
+
export const JSONStringify: typeof JSON.stringify;
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export type Json =
|
|
8
|
-
| null
|
|
9
|
-
| undefined
|
|
10
|
-
| string
|
|
11
|
-
| number
|
|
12
|
-
| bigint
|
|
13
|
-
| boolean
|
|
14
|
-
| JsonObject
|
|
15
|
-
| {}
|
|
16
|
-
| JsonArray;
|
|
17
|
-
|
|
18
|
-
export function JSONStringify(
|
|
19
|
-
data: Exclude<Json, undefined>,
|
|
20
|
-
space?: string | number
|
|
21
|
-
): string;
|
|
22
|
-
|
|
23
|
-
export function JSONStringify(
|
|
24
|
-
data: undefined,
|
|
25
|
-
space?: string | number
|
|
26
|
-
): undefined;
|
|
27
|
-
|
|
28
|
-
export function JSONParse<T extends Json = Json>(serializedData: string): T;
|
|
3
|
+
export const JSONParse: typeof JSON.parse;
|
package/json-with-bigint.js
CHANGED
|
@@ -51,6 +51,45 @@ export const JSONStringify = (value, replacer, space) => {
|
|
|
51
51
|
return denoisedJSON;
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
+
/*
|
|
55
|
+
Function to check if the JSON.parse's context.source feature is supported.
|
|
56
|
+
*/
|
|
57
|
+
const isContextSourceSupported = () => {
|
|
58
|
+
let supported = false;
|
|
59
|
+
|
|
60
|
+
JSON.parse('{"test": 1}', (key, value, context) => {
|
|
61
|
+
if (key === "test" && context && context.source === "1") {
|
|
62
|
+
supported = true;
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return supported;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/*
|
|
71
|
+
Faster (2x) and simpler function to parse JSON.
|
|
72
|
+
Based on JSON.parse's context.source feature, which is not universally available now.
|
|
73
|
+
Does not support the legacy custom format, used in the first version of this library.
|
|
74
|
+
*/
|
|
75
|
+
const JSONParseV2 = (text, reviver) => {
|
|
76
|
+
const intRegex = /^-?\d+$/;
|
|
77
|
+
|
|
78
|
+
return JSON.parse(text, (key, value, context) => {
|
|
79
|
+
const isBigNumber =
|
|
80
|
+
typeof value === "number" &&
|
|
81
|
+
(value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER);
|
|
82
|
+
const isInt = intRegex.test(context.source);
|
|
83
|
+
const isBigInt = isBigNumber && isInt;
|
|
84
|
+
|
|
85
|
+
if (isBigInt) return BigInt(context.source);
|
|
86
|
+
|
|
87
|
+
if (typeof reviver !== "function") return value;
|
|
88
|
+
|
|
89
|
+
return reviver(key, value, context);
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
|
|
54
93
|
/*
|
|
55
94
|
Function to parse JSON.
|
|
56
95
|
If JSON has number values greater than Number.MAX_SAFE_INTEGER, we convert those values to a custom format, then parse them to BigInt values.
|
|
@@ -59,6 +98,8 @@ export const JSONStringify = (value, replacer, space) => {
|
|
|
59
98
|
export const JSONParse = (text, reviver) => {
|
|
60
99
|
if (!text) return originalParse(text, reviver);
|
|
61
100
|
|
|
101
|
+
if (isContextSourceSupported()) return JSONParseV2(text, reviver); // Shortcut to a faster (2x) and simpler version
|
|
102
|
+
|
|
62
103
|
const MAX_INT = Number.MAX_SAFE_INTEGER.toString();
|
|
63
104
|
const MAX_DIGITS = MAX_INT.length;
|
|
64
105
|
const stringsOrLargeNumbers =
|
package/json-with-bigint.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const noiseValue=/^-?\d+n+$/,originalStringify=JSON.stringify,originalParse=JSON.parse;export const JSONStringify=(n,r
|
|
1
|
+
const noiseValue=/^-?\d+n+$/,originalStringify=JSON.stringify,originalParse=JSON.parse;export const JSONStringify=(n,t,r)=>{if("rawJSON"in JSON)return originalStringify(n,((n,r)=>"bigint"==typeof r?JSON.rawJSON(r.toString()):"function"==typeof t?t(n,r):(Array.isArray(t)&&t.includes(n),r)),r);if(!n)return originalStringify(n,t,r);const e=originalStringify(n,((n,r)=>"string"==typeof r&&Boolean(r.match(noiseValue))||"bigint"==typeof r?r.toString()+"n":"function"==typeof t?t(n,r):(Array.isArray(t)&&t.includes(n),r)),r);return e.replace(/([\[:])?"(-?\d+)n"($|([\\n]|\s)*(\s|[\\n])*[,\}\]])/g,"$1$2$3").replace(/([\[:])?("-?\d+n+)n("$|"([\\n]|\s)*(\s|[\\n])*[,\}\]])/g,"$1$2$3")};const isContextSourceSupported=()=>{let n=!1;return JSON.parse('{"test": 1}',((t,r,e)=>("test"===t&&e&&"1"===e.source&&(n=!0),r))),n},JSONParseV2=(n,t)=>{const r=/^-?\d+$/;return JSON.parse(n,((n,e,i)=>{const o="number"==typeof e&&(e>Number.MAX_SAFE_INTEGER||e<Number.MIN_SAFE_INTEGER),s=r.test(i.source);return o&&s?BigInt(i.source):"function"!=typeof t?e:t(n,e,i)}))};export const JSONParse=(n,t)=>{if(!n)return originalParse(n,t);if(isContextSourceSupported())return JSONParseV2(n,t);const r=Number.MAX_SAFE_INTEGER.toString(),e=r.length,i=/^"-?\d+n+"$/,o=/^-?\d+n$/,s=n.replace(/"(?:\\.|[^"])*"|-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?/g,((n,t,o,s)=>{const a='"'===n[0];if(a&&Boolean(n.match(i)))return n.substring(0,n.length-1)+'n"';const u=o||s,g=t&&(t.length<e||t.length===e&&t<=r);return a||u||g?n:'"'+n+'n"'}));return originalParse(s,((n,r,e)=>{if("string"==typeof r&&Boolean(r.match(o)))return BigInt(r.substring(0,r.length-1));return"string"==typeof r&&Boolean(r.match(noiseValue))?r.substring(0,r.length-1):"function"!=typeof t?r:t(n,r,e)}))};
|