Skip to content

Commit 0f936dd

Browse files
authored
Merge pull request #2867 from hapijs/fix/exponential-numbers
fix: better unsafe check of exponential numbers
2 parents fb05636 + 2775bd4 commit 0f936dd

3 files changed

Lines changed: 29 additions & 11 deletions

File tree

benchmarks/suite.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,5 +199,14 @@ module.exports = (Joi) => [
199199
{ a: 'foo', b: 'bar' }
200200
],
201201
(schema, value) => schema.validate(value)
202+
],
203+
[
204+
'Parsing of exponential numbers',
205+
() => [
206+
Joi.number(),
207+
'+001231.0133210e003',
208+
'90071992547409811e-1'
209+
],
210+
(schema, value) => schema.validate(value)
202211
]
203212
];

lib/types/number.js

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ const Common = require('../common');
88

99
const internals = {
1010
numberRx: /^\s*[+-]?(?:(?:\d+(?:\.\d*)?)|(?:\.\d+))(?:e([+-]?\d+))?\s*$/i,
11-
precisionRx: /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/
11+
precisionRx: /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/,
12+
exponentialPartRegex: /[eE][+-]?\d+$/,
13+
leadingSignAndZerosRegex: /^[+-]?(0*)?/,
14+
dotRegex: /\./,
15+
trailingZerosRegex: /0+$/
1216
};
1317

1418

@@ -39,8 +43,7 @@ module.exports = Any.extend({
3943

4044
if (!schema._flags.unsafe) {
4145
if (value.match(/e/i)) {
42-
const constructed = internals.normalizeExponent(`${result.value / Math.pow(10, matches[1])}e${matches[1]}`);
43-
if (constructed !== internals.normalizeExponent(value)) {
46+
if (internals.extractSignificantDigits(value) !== internals.extractSignificantDigits(String(result.value))) {
4447
result.errors = error('number.unsafe');
4548
return result;
4649
}
@@ -297,15 +300,13 @@ module.exports = Any.extend({
297300

298301
// Helpers
299302

300-
internals.normalizeExponent = function (str) {
303+
internals.extractSignificantDigits = function (value) {
301304

302-
return str
303-
.replace(/E/, 'e')
304-
.replace(/\.(\d*[1-9])?0+e/, '.$1e')
305-
.replace(/\.e/, 'e')
306-
.replace(/e\+/, 'e')
307-
.replace(/^\+/, '')
308-
.replace(/^(-?)0+([1-9])/, '$1$2');
305+
return value
306+
.replace(internals.exponentialPartRegex, '')
307+
.replace(internals.dotRegex, '')
308+
.replace(internals.trailingZerosRegex, '')
309+
.replace(internals.leadingSignAndZerosRegex, '');
309310
};
310311

311312

test/types/number.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,8 @@ describe('number', () => {
11461146
['-00100e-003', true, -0.1],
11471147
['-001231.0133210e003', true, -1231013.321],
11481148
['+001231.0133210e003', true, 1231013.321],
1149+
['1.9642346977926364E-5', true, 0.000019642346977926364],
1150+
['9.4e-1', true, 0.94],
11491151
['0.00000095', true, 0.00000095],
11501152
['.5', true, 0.5],
11511153
['1 some text', false, {
@@ -1999,6 +2001,12 @@ describe('number', () => {
19992001
type: 'number.unsafe',
20002002
context: { value: 90071992549000000, label: 'value' }
20012003
}],
2004+
['1.9642346977926366E-5', false, {
2005+
message: '"value" must be a safe number',
2006+
path: [],
2007+
type: 'number.unsafe',
2008+
context: { value: '1.9642346977926366E-5', label: 'value' }
2009+
}],
20022010
[9007199254740992, false, {
20032011
message: '"value" must be a safe number',
20042012
path: [],

0 commit comments

Comments
 (0)