From 6029aee9b06bfb02ddea4b656293448f9c407c60 Mon Sep 17 00:00:00 2001 From: Anderson Date: Fri, 19 May 2023 19:45:05 -0400 Subject: [PATCH 1/3] refactor: add a helper methd to assert if BigInt is available --- src/util.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/util.ts b/src/util.ts index e62d69f..09ed748 100644 --- a/src/util.ts +++ b/src/util.ts @@ -92,13 +92,12 @@ export const fromAlphabet = ( if (isSafeValue) { return value } - if (typeof BigInt === 'function') { - return BigInt(carry) * BigInt(alphabetChars.length) + BigInt(index) - } - // we do not have support for BigInt: - throw new Error( + + throwIfBigIntNotAvailable( `Unable to decode the provided string, due to lack of support for BigInt numbers in the current environment`, ) + + return BigInt(carry) * BigInt(alphabetChars.length) + BigInt(index) }, 0) const safeToParseNumberRegExp = /^\+?\d+$/ @@ -137,3 +136,11 @@ export const makeAtLeastSomeCharRegExp = (chars: string[]) => const escapeRegExp = (text: string) => text.replace(/[\s#$()*+,.?[\\\]^{|}-]/g, '\\$&') + +const throwIfBigIntNotAvailable = ( + errorMessage: string = 'BigInt is not available in this environment', +) => { + if (typeof BigInt !== 'function') { + throw new TypeError(errorMessage) + } +} From ab7903937094aeef05a101f33d59dd041de6cddb Mon Sep 17 00:00:00 2001 From: Anderson Date: Fri, 19 May 2023 19:45:44 -0400 Subject: [PATCH 2/3] feat: parse numeric strings as BigInt on supported systems --- src/util.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/util.ts b/src/util.ts index 09ed748..51c2883 100644 --- a/src/util.ts +++ b/src/util.ts @@ -102,8 +102,23 @@ export const fromAlphabet = ( const safeToParseNumberRegExp = /^\+?\d+$/ -export const safeParseInt10 = (str: string) => - safeToParseNumberRegExp.test(str) ? Number.parseInt(str, 10) : Number.NaN +export const safeParseInt10 = (str: string) => { + if (!safeToParseNumberRegExp.test(str)) { + return Number.NaN + } + + const int10 = Number.parseInt(str, 10) + + if (Number.isSafeInteger(int10)) { + return int10 + } + + throwIfBigIntNotAvailable( + 'Unable to encode the provided BigInt string without loss of information due to lack of support for BigInt type in the current environment', + ) + + return BigInt(str) +} export const splitAtIntervalAndMap = ( str: string, From b6eb11018f92e8210427ef0d51a2b164ad8788aa Mon Sep 17 00:00:00 2001 From: Anderson Date: Fri, 19 May 2023 19:46:15 -0400 Subject: [PATCH 3/3] test: add test for encoding big numeric strings --- src/tests/bigint.test.ts | 46 +++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/tests/bigint.test.ts b/src/tests/bigint.test.ts index 773e2dc..5f6d5d2 100644 --- a/src/tests/bigint.test.ts +++ b/src/tests/bigint.test.ts @@ -4,20 +4,42 @@ const hashids = new Hashids() const _BigInt = typeof BigInt === 'function' ? BigInt : undefined describe('BigInt environment', () => { - beforeAll(() => { - // @ts-expect-error wrong output - delete global.BigInt - }) + describe('BigInt on unsupported environment', () => { + beforeAll(() => { + // @ts-expect-error wrong output + delete global.BigInt + }) + + afterAll(() => { + if (_BigInt) global.BigInt = _BigInt + }) - afterAll(() => { - if (_BigInt) global.BigInt = _BigInt + it('throws decoding BigInt on unsupported environment', () => { + expect(() => + hashids.decode('N95VW0Lo06rQBvJDOE2BVvREP86AqvYN4O9g9p'), + ).toThrowErrorMatchingInlineSnapshot( + `"Unable to decode the provided string, due to lack of support for BigInt numbers in the current environment"`, + ) + }) + + it('throws encoding a big numeric string on unsupported environment', () => { + expect(() => + hashids.encode('90071992547409910123456789'), + ).toThrowErrorMatchingInlineSnapshot( + `"Unable to encode the provided BigInt string without loss of information due to lack of support for BigInt type in the current environment"`, + ) + }) }) - it('throws decoding BigInt on unsupported environment', () => { - expect(() => - hashids.decode('N95VW0Lo06rQBvJDOE2BVvREP86AqvYN4O9g9p'), - ).toThrowErrorMatchingInlineSnapshot( - `"Unable to decode the provided string, due to lack of support for BigInt numbers in the current environment"`, - ) + describe('BigInt on supported environment', () => { + it('decodes big numeric string on supported environment', () => { + const id = '90071992547409910123456789' + const encodedId = hashids.encode(id) + const [decodedId] = hashids.decode(encodedId) + + expect(encodedId).toBeTruthy() + expect(decodedId).toBeTruthy() + expect(id).toBe(decodedId?.toString()) + }) }) })