-
Notifications
You must be signed in to change notification settings - Fork 79
Remove json-bigint dependency #1305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 4 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -298,6 +298,80 @@ function compareVersions(version1, version2, operator) { | |||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // Feature detection for JSON.parse context parameter support | ||||||||||||||||||||||||||||||||||||||||||||
| // Test once at module load time to avoid repeated checks | ||||||||||||||||||||||||||||||||||||||||||||
| let isContextSupported = false; | ||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||
| // Try to use context parameter with a simple test | ||||||||||||||||||||||||||||||||||||||||||||
| JSON.parse('{"test":1}', (key, value, context) => { | ||||||||||||||||||||||||||||||||||||||||||||
| if (context && context.source !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||
| isContextSupported = true; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| return value; | ||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||
| // Context parameter not supported, will use regex fallback | ||||||||||||||||||||||||||||||||||||||||||||
| isContextSupported = false; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||
| * Parse JSON string with support for large integers (beyond Number.MAX_SAFE_INTEGER). | ||||||||||||||||||||||||||||||||||||||||||||
| * Large integers are automatically converted to strings to preserve precision. | ||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||
| * Uses feature detection to determine the best parsing strategy: | ||||||||||||||||||||||||||||||||||||||||||||
| * - If context parameter is supported (Node.js >= 21.0.0, modern runtimes): | ||||||||||||||||||||||||||||||||||||||||||||
| * Uses native JSON.parse() with context parameter for optimal performance | ||||||||||||||||||||||||||||||||||||||||||||
| * - Otherwise (older environments): | ||||||||||||||||||||||||||||||||||||||||||||
| * Preprocesses JSON string with regex to convert unsafe integers before parsing | ||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||
| * @param {string} str - JSON string to parse | ||||||||||||||||||||||||||||||||||||||||||||
| * @returns {any} Parsed JSON object with unsafe integers as strings | ||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||
| * @example | ||||||||||||||||||||||||||||||||||||||||||||
| * parseJSONWithBigInt('{"value": 9007199254740992}') | ||||||||||||||||||||||||||||||||||||||||||||
| * // Returns: { value: '9007199254740992' } | ||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||
| * parseJSONWithBigInt('{"value": 100}') | ||||||||||||||||||||||||||||||||||||||||||||
| * // Returns: { value: 100 } | ||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||
| function parseJSONWithBigInt(str) { | ||||||||||||||||||||||||||||||||||||||||||||
| // For environments supporting context parameter, use it | ||||||||||||||||||||||||||||||||||||||||||||
| // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse | ||||||||||||||||||||||||||||||||||||||||||||
| if (isContextSupported) { | ||||||||||||||||||||||||||||||||||||||||||||
| return JSON.parse(str, (key, value, context) => { | ||||||||||||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||||||||||||
| Number.isInteger(value) && | ||||||||||||||||||||||||||||||||||||||||||||
| !Number.isSafeInteger(Number(context.source)) | ||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||
| return context.source; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| return value; | ||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // For environments without context parameter support, preprocess the JSON string | ||||||||||||||||||||||||||||||||||||||||||||
| // to convert large integers (outside the safe integer range) to strings before parsing. | ||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||
| // The regex matches integers that are actual JSON values, not inside strings. | ||||||||||||||||||||||||||||||||||||||||||||
| // It matches after: colon (:), comma (,), or open bracket ([) | ||||||||||||||||||||||||||||||||||||||||||||
| // and before: comma (,), close brace (}), or close bracket (]) | ||||||||||||||||||||||||||||||||||||||||||||
| const processed = str.replace( | ||||||||||||||||||||||||||||||||||||||||||||
| /(?:[:,[])\s*(-?\d+)(?=\s*[,}\]])/g, | ||||||||||||||||||||||||||||||||||||||||||||
| (match, number) => { | ||||||||||||||||||||||||||||||||||||||||||||
| const num = Number(number); | ||||||||||||||||||||||||||||||||||||||||||||
| // If the number is not safe, convert it to a string | ||||||||||||||||||||||||||||||||||||||||||||
| if (!Number.isSafeInteger(num)) { | ||||||||||||||||||||||||||||||||||||||||||||
| // Preserve the prefix character (: or , or [) | ||||||||||||||||||||||||||||||||||||||||||||
| const prefix = match.charAt(0); | ||||||||||||||||||||||||||||||||||||||||||||
| return `${prefix} "${number}"`; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| return match; | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
359
to
378
|
||||||||||||||||||||||||||||||||||||||||||||
| /(?:[:,[])\s*(-?\d+)(?=\s*[,}\]])/g, | |
| (match, number) => { | |
| const num = Number(number); | |
| // If the number is not safe, convert it to a string | |
| if (!Number.isSafeInteger(num)) { | |
| // Preserve the prefix character (: or , or [) | |
| const prefix = match.charAt(0); | |
| return `${prefix} "${number}"`; | |
| } | |
| return match; | |
| /(?<=^|[:,\[{])\s*(-?\d+)(?=\s*[,}\]])/g, | |
| (numberMatch, number, offset, string) => { | |
| const num = Number(number); | |
| // If the number is not safe, convert it to a string | |
| if (!Number.isSafeInteger(num)) { | |
| // Find the prefix character (if any) | |
| const prefixMatch = string.slice(Math.max(0, offset - 1), offset); | |
| const prefix = /[:,\[{]/.test(prefixMatch) ? prefixMatch : ''; | |
| return `${prefix} "${number}"`; | |
| } | |
| return numberMatch; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Converting the string to
Numberbefore checking if it's safe defeats the purpose of the check. For integers beyondNumber.MAX_SAFE_INTEGER,Number(number)will lose precision during conversion (e.g.,Number('9007199254740993')becomes9007199254740992), making the subsequent safety check unreliable. Instead, compare the absolute value of the integer string againstNumber.MAX_SAFE_INTEGERwithout conversion, or useBigIntfor comparison.