Skip to content

Commit

Permalink
Merge pull request #2867 from hapijs/fix/exponential-numbers
Browse files Browse the repository at this point in the history
fix: better unsafe check of exponential numbers
  • Loading branch information
Marsup committed Oct 22, 2022
2 parents fb05636 + 2775bd4 commit 0f936dd
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 11 deletions.
9 changes: 9 additions & 0 deletions benchmarks/suite.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,5 +199,14 @@ module.exports = (Joi) => [
{ a: 'foo', b: 'bar' }
],
(schema, value) => schema.validate(value)
],
[
'Parsing of exponential numbers',
() => [
Joi.number(),
'+001231.0133210e003',
'90071992547409811e-1'
],
(schema, value) => schema.validate(value)
]
];
23 changes: 12 additions & 11 deletions lib/types/number.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ const Common = require('../common');

const internals = {
numberRx: /^\s*[+-]?(?:(?:\d+(?:\.\d*)?)|(?:\.\d+))(?:e([+-]?\d+))?\s*$/i,
precisionRx: /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/
precisionRx: /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/,
exponentialPartRegex: /[eE][+-]?\d+$/,
leadingSignAndZerosRegex: /^[+-]?(0*)?/,
dotRegex: /\./,
trailingZerosRegex: /0+$/
};


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

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

// Helpers

internals.normalizeExponent = function (str) {
internals.extractSignificantDigits = function (value) {

return str
.replace(/E/, 'e')
.replace(/\.(\d*[1-9])?0+e/, '.$1e')
.replace(/\.e/, 'e')
.replace(/e\+/, 'e')
.replace(/^\+/, '')
.replace(/^(-?)0+([1-9])/, '$1$2');
return value
.replace(internals.exponentialPartRegex, '')
.replace(internals.dotRegex, '')
.replace(internals.trailingZerosRegex, '')
.replace(internals.leadingSignAndZerosRegex, '');
};


Expand Down
8 changes: 8 additions & 0 deletions test/types/number.js
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,8 @@ describe('number', () => {
['-00100e-003', true, -0.1],
['-001231.0133210e003', true, -1231013.321],
['+001231.0133210e003', true, 1231013.321],
['1.9642346977926364E-5', true, 0.000019642346977926364],
['9.4e-1', true, 0.94],
['0.00000095', true, 0.00000095],
['.5', true, 0.5],
['1 some text', false, {
Expand Down Expand Up @@ -1999,6 +2001,12 @@ describe('number', () => {
type: 'number.unsafe',
context: { value: 90071992549000000, label: 'value' }
}],
['1.9642346977926366E-5', false, {
message: '"value" must be a safe number',
path: [],
type: 'number.unsafe',
context: { value: '1.9642346977926366E-5', label: 'value' }
}],
[9007199254740992, false, {
message: '"value" must be a safe number',
path: [],
Expand Down

0 comments on commit 0f936dd

Please sign in to comment.