Skip to content

Commit f3cb494

Browse files
authored
Merge pull request #1219 from issacgerges/strict-numbers
Add option for strictNumbers. Resolves #1128.
2 parents 77334b4 + edd8c92 commit f3cb494

File tree

6 files changed

+71
-9
lines changed

6 files changed

+71
-9
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,7 @@ Defaults:
11561156
// strict mode options
11571157
strictDefaults: false,
11581158
strictKeywords: false,
1159+
strictNumbers: false,
11591160
// asynchronous validation options:
11601161
transpile: undefined, // requires ajv-async package
11611162
// advanced options:
@@ -1250,7 +1251,9 @@ Defaults:
12501251
- `false` (default) - unknown keywords are not reported
12511252
- `true` - if an unknown keyword is present, throw an error
12521253
- `"log"` - if an unknown keyword is present, log warning
1253-
1254+
- _strictNumbers_: validate numbers strictly, failing validation for NaN and Infinity. Option values:
1255+
- `false` (default) - NaN or Infinity will pass validation for numeric types
1256+
- `true` - NaN or Infinity will not pass validation for numeric types
12541257

12551258
##### Asynchronous validation options
12561259

lib/ajv.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ declare namespace ajv {
183183
coerceTypes?: boolean | 'array';
184184
strictDefaults?: boolean | 'log';
185185
strictKeywords?: boolean | 'log';
186+
strictNumbers?: boolean;
186187
async?: boolean | string;
187188
transpile?: string | ((code: string) => string);
188189
meta?: boolean | object;

lib/compile/util.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ function copy(o, to) {
3636
}
3737

3838

39-
function checkDataType(dataType, data, negate) {
39+
function checkDataType(dataType, data, strictNumbers, negate) {
4040
var EQUAL = negate ? ' !== ' : ' === '
4141
, AND = negate ? ' || ' : ' && '
4242
, OK = negate ? '!' : ''
@@ -49,15 +49,18 @@ function checkDataType(dataType, data, negate) {
4949
NOT + 'Array.isArray(' + data + '))';
5050
case 'integer': return '(typeof ' + data + EQUAL + '"number"' + AND +
5151
NOT + '(' + data + ' % 1)' +
52-
AND + data + EQUAL + data + ')';
52+
AND + data + EQUAL + data +
53+
(strictNumbers ? (AND + OK + 'isFinite(' + data + ')') : '') + ')';
54+
case 'number': return '(typeof ' + data + EQUAL + '"' + dataType + '"' +
55+
(strictNumbers ? (AND + OK + 'isFinite(' + data + ')') : '') + ')';
5356
default: return 'typeof ' + data + EQUAL + '"' + dataType + '"';
5457
}
5558
}
5659

5760

58-
function checkDataTypes(dataTypes, data) {
61+
function checkDataTypes(dataTypes, data, strictNumbers) {
5962
switch (dataTypes.length) {
60-
case 1: return checkDataType(dataTypes[0], data, true);
63+
case 1: return checkDataType(dataTypes[0], data, strictNumbers, true);
6164
default:
6265
var code = '';
6366
var types = toHash(dataTypes);
@@ -70,7 +73,7 @@ function checkDataTypes(dataTypes, data) {
7073
}
7174
if (types.number) delete types.integer;
7275
for (var t in types)
73-
code += (code ? ' && ' : '' ) + checkDataType(t, data, true);
76+
code += (code ? ' && ' : '' ) + checkDataType(t, data, strictNumbers, true);
7477

7578
return code;
7679
}

lib/dot/uniqueItems.jst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
for (;i--;) {
3939
var item = {{=$data}}[i];
4040
{{ var $method = 'checkDataType' + ($typeIsArray ? 's' : ''); }}
41-
if ({{= it.util[$method]($itemType, 'item', true) }}) continue;
41+
if ({{= it.util[$method]($itemType, 'item', it.opts.strictNumbers, true) }}) continue;
4242
{{? $typeIsArray}}
4343
if (typeof item == 'string') item = '"' + item;
4444
{{?}}

lib/dot/validate.jst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@
140140
, $method = $typeIsArray ? 'checkDataTypes' : 'checkDataType';
141141
}}
142142

143-
if ({{= it.util[$method]($typeSchema, $data, true) }}) {
143+
if ({{= it.util[$method]($typeSchema, $data, it.opts.strictNumbers, true) }}) {
144144
#}}
145145

146146
{{? it.schema.$ref && $refKeywords }}
@@ -192,7 +192,7 @@
192192
{{~ it.RULES:$rulesGroup }}
193193
{{? $shouldUseGroup($rulesGroup) }}
194194
{{? $rulesGroup.type }}
195-
if ({{= it.util.checkDataType($rulesGroup.type, $data) }}) {
195+
if ({{= it.util.checkDataType($rulesGroup.type, $data, it.opts.strictNumbers) }}) {
196196
{{?}}
197197
{{? it.opts.useDefaults }}
198198
{{? $rulesGroup.type == 'object' && it.schema.properties }}

spec/options/strictNumbers.spec.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
'use strict';
2+
3+
var Ajv = require('../ajv');
4+
5+
describe('structNumbers option', function() {
6+
var ajv;
7+
describe('strictNumbers default', testWithoutStrictNumbers(new Ajv()));
8+
describe('strictNumbers = false', testWithoutStrictNumbers(new Ajv({strictNumbers: false})));
9+
describe('strictNumbers = true', function() {
10+
beforeEach(function () {
11+
ajv = new Ajv({strictNumbers: true});
12+
});
13+
14+
it('should fail validation for NaN/Infinity as type number', function() {
15+
var validate = ajv.compile({type: 'number'});
16+
validate("1.1").should.equal(false);
17+
validate(1.1).should.equal(true);
18+
validate(1).should.equal(true);
19+
validate(NaN).should.equal(false);
20+
validate(Infinity).should.equal(false);
21+
});
22+
23+
it('should fail validation for NaN as type integer', function() {
24+
var validate = ajv.compile({type: 'integer'});
25+
validate("1.1").should.equal(false);
26+
validate(1.1).should.equal(false);
27+
validate(1).should.equal(true);
28+
validate(NaN).should.equal(false);
29+
validate(Infinity).should.equal(false);
30+
});
31+
});
32+
});
33+
34+
35+
function testWithoutStrictNumbers(_ajv) {
36+
return function () {
37+
it('should NOT fail validation for NaN/Infinity as type number', function() {
38+
var validate = _ajv.compile({type: 'number'});
39+
validate("1.1").should.equal(false);
40+
validate(1.1).should.equal(true);
41+
validate(1).should.equal(true);
42+
validate(NaN).should.equal(true);
43+
validate(Infinity).should.equal(true);
44+
});
45+
46+
it('should NOT fail validation for NaN/Infinity as type integer', function() {
47+
var validate = _ajv.compile({type: 'integer'});
48+
validate("1.1").should.equal(false);
49+
validate(1.1).should.equal(false);
50+
validate(1).should.equal(true);
51+
validate(NaN).should.equal(false);
52+
validate(Infinity).should.equal(true);
53+
});
54+
};
55+
}

0 commit comments

Comments
 (0)