From: Josh Kelley Date: Sun, 16 Feb 2025 17:24:26 +0000 (-0500) Subject: [fix] Handle non-primitives in isNumber (#12034) X-Git-Tag: v4.4.8~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2f425290ee077d9d013af77fa978d6b6d6885634;p=thirdparty%2FChart.js.git [fix] Handle non-primitives in isNumber (#12034) While investigating https://github.com/chartjs/chartjs-plugin-zoom/issues/928, I found that `isNonPrimitive` will throw TypeError on a Moment.js object after it's passed through Chart.js's options proxy, because the object has its `Symbol.toPrimitive`, `toString`, and `valueOf` all set to null. (See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#string_coercion for background reading.) Since isNumber appears to be a low-level function that can take any arbitrary input, it seems worth letting it handle this case. --- diff --git a/src/helpers/helpers.math.ts b/src/helpers/helpers.math.ts index da463aeb0..0fd2a9513 100644 --- a/src/helpers/helpers.math.ts +++ b/src/helpers/helpers.math.ts @@ -57,8 +57,15 @@ export function _factorize(value: number) { return result; } +/** + * Verifies that attempting to coerce n to string or number won't throw a TypeError. + */ +function isNonPrimitive(n: unknown) { + return typeof n === 'symbol' || (typeof n === 'object' && n !== null && !(Symbol.toPrimitive in n || 'toString' in n || 'valueOf' in n)); +} + export function isNumber(n: unknown): n is number { - return !isNaN(parseFloat(n as string)) && isFinite(n as number); + return !isNonPrimitive(n) && !isNaN(parseFloat(n as string)) && isFinite(n as number); } export function almostWhole(x: number, epsilon: number) { diff --git a/test/specs/helpers.math.tests.js b/test/specs/helpers.math.tests.js index b6b8e125f..938742959 100644 --- a/test/specs/helpers.math.tests.js +++ b/test/specs/helpers.math.tests.js @@ -103,6 +103,8 @@ describe('Chart.helpers.math', function() { expect(math.isNumber(NaN)).toBe(false); expect(math.isNumber(undefined)).toBe(false); expect(math.isNumber('cbc')).toBe(false); + expect(math.isNumber(Symbol())).toBe(false); + expect(math.isNumber(Object.create(null))).toBe(false); }); it('should compute shortest distance between angles', function() {