feat: invalidDefaults option to warn when defaults are ignored, fixes #957
parent
2aa49aebd4
commit
c081061a1e
|
@ -798,13 +798,14 @@ console.log(validate(data)); // true
|
|||
console.log(data); // [ 1, "foo" ]
|
||||
```
|
||||
|
||||
`default` keywords in other cases are ignored:
|
||||
`default` keywords in other cases are invalid:
|
||||
|
||||
- not in `properties` or `items` subschemas
|
||||
- in schemas inside `anyOf`, `oneOf` and `not` (see [#42](https://github.com/epoberezkin/ajv/issues/42))
|
||||
- in `if` subschema of `switch` keyword
|
||||
- in schemas generated by custom macro keywords
|
||||
|
||||
The [`invalidDefaults` option](#options) customizes Ajv's behavior for invalid defaults (`false` ignores invalid defaults, `true` raises an error, and `"log"` outputs a warning).
|
||||
|
||||
## Coercing data types
|
||||
|
||||
|
@ -1070,6 +1071,7 @@ Defaults:
|
|||
removeAdditional: false,
|
||||
useDefaults: false,
|
||||
coerceTypes: false,
|
||||
invalidDefaults: false,
|
||||
// asynchronous validation options:
|
||||
transpile: undefined, // requires ajv-async package
|
||||
// advanced options:
|
||||
|
@ -1151,6 +1153,10 @@ Defaults:
|
|||
- `false` (default) - no type coercion.
|
||||
- `true` - coerce scalar data types.
|
||||
- `"array"` - in addition to coercions between scalar types, coerce scalar data to an array with one element and vice versa (as required by the schema).
|
||||
- _invalidDefaults_: specify behavior for invalid `default` keywords in schemas. Option values:
|
||||
- `false` (default) - ignore invalid defaults
|
||||
- `true` - if an invalid default is present, throw an error
|
||||
- `"log"` - if an invalid default is present, log warning
|
||||
|
||||
|
||||
##### Asynchronous validation options
|
||||
|
|
|
@ -180,6 +180,7 @@ declare namespace ajv {
|
|||
removeAdditional?: boolean | 'all' | 'failing';
|
||||
useDefaults?: boolean | 'shared';
|
||||
coerceTypes?: boolean | 'array';
|
||||
invalidDefaults?: boolean | 'log';
|
||||
async?: boolean | string;
|
||||
transpile?: string | ((code: string) => string);
|
||||
meta?: boolean | object;
|
||||
|
|
|
@ -39,7 +39,7 @@ Ajv.$dataMetaSchema = $dataMetaSchema;
|
|||
|
||||
var META_SCHEMA_ID = 'http://json-schema.org/draft-07/schema';
|
||||
|
||||
var META_IGNORE_OPTIONS = [ 'removeAdditional', 'useDefaults', 'coerceTypes' ];
|
||||
var META_IGNORE_OPTIONS = [ 'removeAdditional', 'useDefaults', 'coerceTypes', 'invalidDefaults' ];
|
||||
var META_SUPPORT_DATA = ['/properties'];
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,15 +1,25 @@
|
|||
{{## def.assignDefault:
|
||||
if ({{=$passData}} === undefined
|
||||
{{? it.opts.useDefaults == 'empty' }}
|
||||
|| {{=$passData}} === null
|
||||
|| {{=$passData}} === ''
|
||||
{{? it.compositeRule }}
|
||||
{{? it.opts.invalidDefaults }}
|
||||
{{? it.opts.invalidDefaults === 'log' }}
|
||||
{{ it.logger.warn('default is ignored for: ' + $passData); }}
|
||||
{{??}}
|
||||
{{ throw new Error('default is ignored for: ' + $passData); }}
|
||||
{{?}}
|
||||
{{?}}
|
||||
)
|
||||
{{=$passData}} = {{? it.opts.useDefaults == 'shared' }}
|
||||
{{= it.useDefault($sch.default) }}
|
||||
{{??}}
|
||||
{{= JSON.stringify($sch.default) }}
|
||||
{{?}};
|
||||
{{??}}
|
||||
if ({{=$passData}} === undefined
|
||||
{{? it.opts.useDefaults == 'empty' }}
|
||||
|| {{=$passData}} === null
|
||||
|| {{=$passData}} === ''
|
||||
{{?}}
|
||||
)
|
||||
{{=$passData}} = {{? it.opts.useDefaults == 'shared' }}
|
||||
{{= it.useDefault($sch.default) }}
|
||||
{{??}}
|
||||
{{= JSON.stringify($sch.default) }}
|
||||
{{?}};
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
|
|
|
@ -72,6 +72,13 @@
|
|||
|
||||
it.dataPathArr = [undefined];
|
||||
}}
|
||||
{{? it.opts.invalidDefaults && it.schema.default !== undefined }}
|
||||
{{? it.opts.invalidDefaults === 'log' }}
|
||||
{{ it.logger.warn('default is ignored in the schema root'); }}
|
||||
{{??}}
|
||||
{{ throw new Error('default is ignored in the schema root'); }}
|
||||
{{?}}
|
||||
{{?}}
|
||||
|
||||
var vErrors = null; {{ /* don't edit, used in replace */ }}
|
||||
var errors = 0; {{ /* don't edit, used in replace */ }}
|
||||
|
@ -177,7 +184,7 @@
|
|||
{{? $rulesGroup.type }}
|
||||
if ({{= it.util.checkDataType($rulesGroup.type, $data) }}) {
|
||||
{{?}}
|
||||
{{? it.opts.useDefaults && !it.compositeRule }}
|
||||
{{? it.opts.useDefaults }}
|
||||
{{? $rulesGroup.type == 'object' && it.schema.properties }}
|
||||
{{# def.defaultProperties }}
|
||||
{{?? $rulesGroup.type == 'array' && Array.isArray(it.schema.items) }}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
var Ajv = require('../ajv');
|
||||
var getAjvInstances = require('../ajv_instances');
|
||||
require('../chai').should();
|
||||
var should = require('../chai').should();
|
||||
|
||||
|
||||
describe('useDefaults options', function() {
|
||||
|
@ -220,4 +220,90 @@ describe('useDefaults options', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalidDefaults option', function() {
|
||||
it('should throw an error given an invalid default in the schema root when invalidDefaults is true', function() {
|
||||
var ajv = new Ajv({useDefaults: true, invalidDefaults: true});
|
||||
var schema = {
|
||||
default: 5,
|
||||
properties: {}
|
||||
};
|
||||
should.throw(function() { ajv.compile(schema); });
|
||||
});
|
||||
|
||||
it('should throw an error given an invalid default in oneOf when invalidDefaults is true', function() {
|
||||
var ajv = new Ajv({useDefaults: true, invalidDefaults: true});
|
||||
var schema = {
|
||||
oneOf: [
|
||||
{ enum: ['foo', 'bar'] },
|
||||
{
|
||||
properties: {
|
||||
foo: {
|
||||
default: true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
should.throw(function() { ajv.compile(schema); });
|
||||
});
|
||||
|
||||
it('should log a warning given an invalid default in the schema root when invalidDefaults is "log"', function() {
|
||||
var warnArg = null;
|
||||
var ajv = new Ajv({
|
||||
useDefaults: true,
|
||||
invalidDefaults: 'log',
|
||||
logger: {
|
||||
log: function() {
|
||||
throw new Error('should not be called');
|
||||
},
|
||||
warn: function(warning) {
|
||||
warnArg = warning;
|
||||
},
|
||||
error: function() {
|
||||
throw new Error('should not be called');
|
||||
}
|
||||
}
|
||||
});
|
||||
var schema = {
|
||||
default: 5,
|
||||
properties: {}
|
||||
};
|
||||
ajv.compile(schema);
|
||||
should.equal(warnArg, 'default is ignored in the schema root');
|
||||
});
|
||||
|
||||
it('should log a warning given an invalid default in oneOf when invalidDefaults is "log"', function() {
|
||||
var warnArg = null;
|
||||
var ajv = new Ajv({
|
||||
useDefaults: true,
|
||||
invalidDefaults: 'log',
|
||||
logger: {
|
||||
log: function() {
|
||||
throw new Error('should not be called');
|
||||
},
|
||||
warn: function(warning) {
|
||||
warnArg = warning;
|
||||
},
|
||||
error: function() {
|
||||
throw new Error('should not be called');
|
||||
}
|
||||
}
|
||||
});
|
||||
var schema = {
|
||||
oneOf: [
|
||||
{ enum: ['foo', 'bar'] },
|
||||
{
|
||||
properties: {
|
||||
foo: {
|
||||
default: true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
ajv.compile(schema);
|
||||
should.equal(warnArg, 'default is ignored for: data.foo');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue