Skip to content

Commit

Permalink
fix handling of fractional number part and some special cases in `Num…
Browse files Browse the repository at this point in the history
…ber.fromString`
  • Loading branch information
zloirock committed Oct 28, 2023
1 parent 79ea4a7 commit f7b095e
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- Simplified `structuredClone` polyfill, avoided second tree pass in cases of transferring
- Added support of `SuppressedError` to `structuredClone` polyfill
- Removed unspecified unnecessary `ArrayBuffer` and `DataView` dependencies of `structuredClone` lack of which could cause errors in some entries in IE10-
- Fixed handling of fractional number part and some special cases in [`Number.fromString`](https://github.com/tc39/proposal-number-fromstring)
- Compat data improvements:
- Updated Opera Android 78 compat data mapping

Expand Down
19 changes: 12 additions & 7 deletions packages/core-js/modules/esnext.number.from-string.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,35 @@ var INVALID_RADIX = 'Invalid radix';
var $RangeError = RangeError;
var $SyntaxError = SyntaxError;
var $TypeError = TypeError;
var valid = /^[\da-z]+$/;
var pow = Math.pow;
var valid = /^[\d.a-z]+$/;
var charAt = uncurryThis(''.charAt);
var exec = uncurryThis(valid.exec);
var numberToString = uncurryThis(1.0.toString);
var stringSlice = uncurryThis(''.slice);
var split = uncurryThis(''.split);

// `Number.fromString` method
// https://github.com/tc39/proposal-number-fromstring
$({ target: 'Number', stat: true, forced: true }, {
fromString: function fromString(string, radix) {
var sign = 1;
var R, mathNum;
if (typeof string != 'string') throw new $TypeError(INVALID_NUMBER_REPRESENTATION);
if (!string.length) throw new $SyntaxError(INVALID_NUMBER_REPRESENTATION);
if (string === 'NaN') return NaN;
if (charAt(string, 0) === '-') {
sign = -1;
string = stringSlice(string, 1);
if (!string.length) throw new $SyntaxError(INVALID_NUMBER_REPRESENTATION);
if (!string.length || string === '0') throw new $SyntaxError(INVALID_NUMBER_REPRESENTATION);
}
R = radix === undefined ? 10 : toIntegerOrInfinity(radix);
if (string === 'Infinity') return sign * Infinity;
var R = radix === undefined ? 10 : toIntegerOrInfinity(radix);
if (R < 2 || R > 36) throw new $RangeError(INVALID_RADIX);
if (!exec(valid, string) || numberToString(mathNum = parseInt(string, R), R) !== string) {
throw new $SyntaxError(INVALID_NUMBER_REPRESENTATION);
}
if (!exec(valid, string)) throw new $SyntaxError(INVALID_NUMBER_REPRESENTATION);
var parts = split(string, '.');
var mathNum = parseInt(parts[0], R);
if (parts.length > 1) mathNum += parseInt(parts[1], R) / pow(R, parts[1].length);
if (numberToString(mathNum, R) !== string) throw new $SyntaxError(INVALID_NUMBER_REPRESENTATION);
return sign * mathNum;
}
});
17 changes: 17 additions & 0 deletions tests/unit-global/esnext.number.from-string.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,26 @@ QUnit.test('Number.fromString', assert => {
assert.same(fromString('10', radix), radix, `Radix ${ radix }`);
}
assert.throws(() => fromString('10', -4294967294), RangeError, 'Radix uses ToInteger #1');

assert.same(fromString('NaN'), NaN);
assert.same(fromString('NaN', 2), NaN);
assert.same(fromString('Infinity'), Infinity);
assert.same(fromString('Infinity', 2), Infinity);
assert.same(fromString('-Infinity'), -Infinity);
assert.same(fromString('-Infinity', 2), -Infinity);

assert.same(fromString('10', 2.5), 2, 'Radix uses ToInteger #2');
assert.same(fromString('42'), 42);
assert.same(fromString('42', 10), 42);
assert.same(fromString('3.14159', 10), 3.14159);
assert.same(fromString('-100.11', 2), -4.75);
assert.same(fromString('202.1', 3), 20.333333333333332);

assert.same(fromString('0'), 0);
assert.same(fromString('0', 2), 0);
assert.throws(() => fromString('-0'), SyntaxError);
assert.throws(() => fromString('-0', 2), SyntaxError);

assert.throws(() => fromString('0xc0ffee'), SyntaxError);
assert.throws(() => fromString('0o755'), SyntaxError);
assert.throws(() => fromString('0b00101010'), SyntaxError);
Expand Down
17 changes: 17 additions & 0 deletions tests/unit-pure/esnext.number.from-string.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,26 @@ QUnit.test('Number.fromString', assert => {
assert.same(fromString('10', radix), radix, `Radix ${ radix }`);
}
assert.throws(() => fromString('10', -4294967294), RangeError, 'Radix uses ToInteger #1');

assert.same(fromString('NaN'), NaN);
assert.same(fromString('NaN', 2), NaN);
assert.same(fromString('Infinity'), Infinity);
assert.same(fromString('Infinity', 2), Infinity);
assert.same(fromString('-Infinity'), -Infinity);
assert.same(fromString('-Infinity', 2), -Infinity);

assert.same(fromString('10', 2.5), 2, 'Radix uses ToInteger #2');
assert.same(fromString('42'), 42);
assert.same(fromString('42', 10), 42);
assert.same(fromString('3.14159', 10), 3.14159);
assert.same(fromString('-100.11', 2), -4.75);
assert.same(fromString('202.1', 3), 20.333333333333332);

assert.same(fromString('0'), 0);
assert.same(fromString('0', 2), 0);
assert.throws(() => fromString('-0'), SyntaxError);
assert.throws(() => fromString('-0', 2), SyntaxError);

assert.throws(() => fromString('0xc0ffee'), SyntaxError);
assert.throws(() => fromString('0o755'), SyntaxError);
assert.throws(() => fromString('0b00101010'), SyntaxError);
Expand Down

0 comments on commit f7b095e

Please sign in to comment.