safe-bigint
Version:
Safely create a BigInt from a numerical string, even one larger than MAX_SAFE_INTEGER.
39 lines (32 loc) • 1.5 kB
JavaScript
'use strict';
var GetIntrinsic = require('get-intrinsic');
var callBound = require('call-bound');
var $BigInt = GetIntrinsic('%BigInt%', true);
var $Function = GetIntrinsic('%Function%');
var $toPrecision = callBound('Number.prototype.toPrecision');
var $split = callBound('String.prototype.split');
var $replace = callBound('String.prototype.replace');
// eslint-disable-next-line no-extra-parens
var MAX_SAFE_INTEGER = /** @type {9007199254740991} */ (Number.MAX_SAFE_INTEGER) || 9007199254740991; // Math.pow(2, 53) - 1;
var needsBigIntHack = require('./needs-hack');
/** @type {import('.')} */
module.exports = needsBigIntHack ? function safeBigInt(int) {
if (typeof int === 'bigint') {
return int;
}
if (int > MAX_SAFE_INTEGER || -int > MAX_SAFE_INTEGER) {
// construct a maximum-precision string of digits
// from a native serialization like <digits>.<zeroes> or <digit>.<digits>e+<exponent>
var preciseParts = $split($toPrecision(+int, 100), 'e');
var significand = $replace(preciseParts[0], /(\.[0-9]*?)0*$/, '$1');
var baseTenExponent = +(preciseParts[1] || 0);
if (baseTenExponent > 0) {
var significandScale = (significand + '.').indexOf('.');
baseTenExponent -= significand.length - 1 - significandScale;
}
var digits = $replace(significand, '.', '') + Array(baseTenExponent + 1).join('0');
return $Function('return ' + digits + 'n')();
}
// @ts-expect-error TS can't figure out that needsBigIntHack implies $BigInt
return $BigInt(int);
} : $BigInt;