ajv-keywords
Advanced tools
Comparing version 1.1.1 to 1.2.0
'use strict'; | ||
module.exports = { | ||
'typeof': require('./typeof'), | ||
'instanceof': require('./instanceof'), | ||
propertyNames: require('./propertyNames'), | ||
range: require('./range'), | ||
propertyNames: require('./propertyNames'), | ||
regexp: require('./regexp') | ||
regexp: require('./regexp'), | ||
'typeof': require('./typeof'), | ||
dynamicDefaults: require('./dynamicDefaults') | ||
}; |
'use strict'; | ||
module.exports = defFunc; | ||
var CONSTRUCTORS = { | ||
@@ -15,42 +13,42 @@ Object: Object, | ||
/* istanbul ignore else */ | ||
if (typeof Buffer != 'undefined') | ||
CONSTRUCTORS.Buffer = Buffer; | ||
module.exports = function defFunc(ajv) { | ||
/* istanbul ignore else */ | ||
if (typeof Buffer != 'undefined') | ||
CONSTRUCTORS.Buffer = Buffer; | ||
var definition = defFunc.definition = { | ||
compile: function (schema) { | ||
if (typeof schema == 'string') { | ||
var Constructor = getConstructor(schema); | ||
defFunc.definition = { | ||
compile: function (schema) { | ||
if (typeof schema == 'string') { | ||
var Constructor = getConstructor(schema); | ||
return function (data) { | ||
return data instanceof Constructor; | ||
}; | ||
} | ||
var constructors = schema.map(getConstructor); | ||
return function (data) { | ||
return data instanceof Constructor; | ||
for (var i=0; i<constructors.length; i++) | ||
if (data instanceof constructors[i]) return true; | ||
return false; | ||
}; | ||
}, | ||
CONSTRUCTORS: CONSTRUCTORS, | ||
metaSchema: { | ||
anyOf: [ | ||
{ type: 'string' }, | ||
{ | ||
type: 'array', | ||
items: { type: 'string' } | ||
} | ||
] | ||
} | ||
}; | ||
var constructors = schema.map(getConstructor); | ||
return function (data) { | ||
for (var i=0; i<constructors.length; i++) | ||
if (data instanceof constructors[i]) return true; | ||
return false; | ||
}; | ||
}, | ||
CONSTRUCTORS: CONSTRUCTORS, | ||
metaSchema: { | ||
anyOf: [ | ||
{ type: 'string' }, | ||
{ | ||
type: 'array', | ||
items: { type: 'string' } | ||
} | ||
] | ||
ajv.addKeyword('instanceof', defFunc.definition); | ||
function getConstructor(c) { | ||
var Constructor = CONSTRUCTORS[c]; | ||
if (Constructor) return Constructor; | ||
throw new Error('invalid "instanceof" keyword value ' + c); | ||
} | ||
}; | ||
function defFunc(ajv) { | ||
ajv.addKeyword('instanceof', definition); | ||
} | ||
function getConstructor(c) { | ||
var Constructor = CONSTRUCTORS[c]; | ||
if (Constructor) return Constructor; | ||
throw new Error('invalid "instanceof" keyword value'); | ||
} |
'use strict'; | ||
module.exports = function (ajv) { | ||
ajv.addKeyword('propertyNames', { | ||
module.exports = function defFunc(ajv) { | ||
defFunc.definition = { | ||
type: 'object', | ||
@@ -47,3 +47,5 @@ compile: function(schema) { | ||
errors: true | ||
}); | ||
}; | ||
ajv.addKeyword('propertyNames', defFunc.definition); | ||
}; |
'use strict'; | ||
module.exports = defFunc; | ||
module.exports = function defFunc(ajv) { | ||
defFunc.definition = { | ||
type: 'number', | ||
macro: function (schema, parentSchema) { | ||
var min = schema[0] | ||
, max = schema[1] | ||
, exclusive = parentSchema.exclusiveRange; | ||
var definition = defFunc.definition = { | ||
type: 'number', | ||
macro: function (schema, parentSchema) { | ||
var min = schema[0] | ||
, max = schema[1] | ||
, exclusive = parentSchema.exclusiveRange; | ||
validateRangeSchema(min, max, exclusive); | ||
validateRangeSchema(min, max, exclusive); | ||
return { | ||
minimum: min, | ||
exclusiveMinimum: exclusive, | ||
maximum: max, | ||
exclusiveMaximum: exclusive | ||
}; | ||
}, | ||
metaSchema: { | ||
type: 'array', | ||
minItems: 2, | ||
maxItems: 2, | ||
items: { type: 'number' } | ||
} | ||
}; | ||
return { | ||
minimum: min, | ||
exclusiveMinimum: exclusive, | ||
maximum: max, | ||
exclusiveMaximum: exclusive | ||
}; | ||
}, | ||
metaSchema: { | ||
type: 'array', | ||
minItems: 2, | ||
maxItems: 2, | ||
items: { type: 'number' } | ||
} | ||
}; | ||
function defFunc(ajv) { | ||
ajv.addKeyword('range', definition); | ||
ajv.addKeyword('range', defFunc.definition); | ||
ajv.addKeyword('exclusiveRange'); | ||
} | ||
function validateRangeSchema(min, max, exclusive) { | ||
if (exclusive !== undefined && typeof exclusive != 'boolean') | ||
throw new Error('Invalid schema for exclusiveRange keyword, should be boolean'); | ||
function validateRangeSchema(min, max, exclusive) { | ||
if (exclusive !== undefined && typeof exclusive != 'boolean') | ||
throw new Error('Invalid schema for exclusiveRange keyword, should be boolean'); | ||
if (min > max || (exclusive && min == max)) | ||
throw new Error('There are no numbers in range'); | ||
} | ||
if (min > max || (exclusive && min == max)) | ||
throw new Error('There are no numbers in range'); | ||
} | ||
}; |
'use strict'; | ||
module.exports = function (ajv) { | ||
ajv.addKeyword('regexp', { | ||
module.exports = function defFunc(ajv) { | ||
defFunc.definition = { | ||
type: 'string', | ||
@@ -32,3 +32,5 @@ inline: function (it, keyword, schema) { | ||
} | ||
}); | ||
}; | ||
ajv.addKeyword('regexp', defFunc.definition); | ||
}; |
'use strict'; | ||
module.exports = defFunc; | ||
var KNOWN_TYPES = ['undefined', 'string', 'number', 'object', 'function', 'boolean', 'symbol']; | ||
var definition = defFunc.definition = { | ||
inline: function (it, keyword, schema) { | ||
var data = 'data' + (it.dataLevel || ''); | ||
if (typeof schema == 'string') return 'typeof ' + data + ' == "' + schema + '"'; | ||
schema = 'validate.schema' + it.schemaPath + '.' + keyword; | ||
return schema + '.indexOf(typeof ' + data + ') >= 0'; | ||
}, | ||
metaSchema: { | ||
anyOf: [ | ||
{ | ||
type: 'string', | ||
enum: KNOWN_TYPES | ||
}, | ||
{ | ||
type: 'array', | ||
items: { | ||
module.exports = function defFunc(ajv) { | ||
defFunc.definition = { | ||
inline: function (it, keyword, schema) { | ||
var data = 'data' + (it.dataLevel || ''); | ||
if (typeof schema == 'string') return 'typeof ' + data + ' == "' + schema + '"'; | ||
schema = 'validate.schema' + it.schemaPath + '.' + keyword; | ||
return schema + '.indexOf(typeof ' + data + ') >= 0'; | ||
}, | ||
metaSchema: { | ||
anyOf: [ | ||
{ | ||
type: 'string', | ||
enum: KNOWN_TYPES | ||
}, | ||
{ | ||
type: 'array', | ||
items: { | ||
type: 'string', | ||
enum: KNOWN_TYPES | ||
} | ||
} | ||
} | ||
] | ||
} | ||
] | ||
} | ||
}; | ||
ajv.addKeyword('typeof', defFunc.definition); | ||
}; | ||
function defFunc(ajv) { | ||
ajv.addKeyword('typeof', definition); | ||
} |
{ | ||
"name": "ajv-keywords", | ||
"version": "1.1.1", | ||
"version": "1.2.0", | ||
"description": "Custom JSON-Schema keywords for ajv validator", | ||
@@ -28,14 +28,15 @@ "main": "index.js", | ||
"peerDependencies": { | ||
"ajv": ">=4.2.0" | ||
"ajv": ">=4.9.0" | ||
}, | ||
"devDependencies": { | ||
"ajv": "^4.7.4", | ||
"ajv": "^4.9.0", | ||
"ajv-pack": "^0.2.0", | ||
"chai": "^3.5.0", | ||
"coveralls": "^2.11.9", | ||
"eslint": "^2.11.1", | ||
"eslint": "^3.6.0", | ||
"istanbul": "^0.4.3", | ||
"mocha": "^2.5.3", | ||
"pre-commit": "^1.1.3" | ||
"mocha": "^3.0.2", | ||
"pre-commit": "^1.1.3", | ||
"uuid": "^3.0.1" | ||
} | ||
} |
125
README.md
@@ -10,2 +10,16 @@ # ajv-keywords | ||
## Contents | ||
- [Install](#install) | ||
- [Usage](#usage) | ||
- [Keywords](#keywords) | ||
- [typeof](#typeof) | ||
- [instanceof](#instanceof) | ||
- [range and exclusiveRange](#range-and-exclusiverange) | ||
- [propertyNames](#propertynames) | ||
- [regexp](#regexp) | ||
- [dynamicDefaults](#dynamicdefaults) | ||
- [License](#license) | ||
## Install | ||
@@ -172,4 +186,115 @@ | ||
### `dynamicDefaults` | ||
This keyword allows to assign dynamic defaults to properties, such as timestamps, unique IDs etc. | ||
This keyword only works if `useDefaults` options is used and not inside `anyOf` keywrods etc., in the same way as [default keyword treated by Ajv](https://github.com/epoberezkin/ajv#assigning-defaults). | ||
The keyword should be added on the object level. Its value should be an object with each property corresponding to a property name, in the same way as in standard `properties` keyword. The value of each property can be: | ||
- an identifier of default function (a string) | ||
- an object with properties `func` (an identifier) and `args` (an object with parameters that will be passed to this function during schema compilation - see examples). | ||
The properties used in `dynamicDefaults` should not be added to `required` keyword (or validation will fail), because unlike `default` this keyword is processed after validation. | ||
There are several predefined dynamic default functions: | ||
- `"timestamp"` - current timestamp in milliseconds | ||
- `"datetime"' - current date and time as string (ISO, valid according to `date-time` format) | ||
- `"date"' - current date as string (ISO, valid according to `date` format) | ||
- `"time"` - current time as string (ISO, valid according to `time` format) | ||
- `"random"` - pseudo-random number in [0, 1) interval | ||
- `"randomint"` - pseudo-random integer number. If string is used as a property value, the function will randomly return 0 or 1. If object `{func: 'randomint', max: N}` is used then the default will be an integer number in [0, N) interval. | ||
- `"seq"` - sequential integer number starting from 0. If string is used as a property value, the default sequence will be used. If object `{func: 'seq', name: 'foo'}` is used then the sequence with name `"foo"` will be used. Sequences are global, even if different ajv instances are used. | ||
```javascript | ||
var schema = { | ||
type: 'object', | ||
dynamicDefaults: { | ||
ts: 'datetime', | ||
r: { func: 'randomint', max: 100 }, | ||
id: { func: 'seq', name: 'id' } | ||
}, | ||
properties: { | ||
ts: { | ||
type: 'string', | ||
format: 'datetime' | ||
}, | ||
r: { | ||
type: 'integer', | ||
minimum: 0, | ||
maximum: 100, | ||
exclusiveMaximum: true | ||
}, | ||
id: { | ||
type: 'integer', | ||
minimum: 0 | ||
} | ||
} | ||
}; | ||
var data = {}; | ||
ajv.validate(data); // true | ||
data; // { ts: '2016-12-01T22:07:28.829Z', r: 25, id: 0 } | ||
var data1 = {}; | ||
ajv.validate(data1); // true | ||
data1; // { ts: '2016-12-01T22:07:29.832Z', r: 68, id: 1 } | ||
ajv.validate(data1); // true | ||
data1; // didn't change, as all properties were defined | ||
``` | ||
You can add your own dynamic default function to be recognised by this keyword: | ||
```javascript | ||
var uuid = require('uuid'); | ||
function uuidV4() { return uuid.v4(); } | ||
var definition = require('ajv-keywords').get('dynamicDefaults').definition; | ||
// or require('ajv-keywords/keywords/dynamicDefaults').definition; | ||
definition.DEFAULTS.uuid = uuidV4; | ||
var schema = { | ||
dynamicDefaults: { id: 'uuid' }, | ||
properties: { id: { type: 'string', format: 'uuid' } } | ||
}; | ||
var data = {}; | ||
ajv.validate(schema, data); // true | ||
data; // { id: 'a1183fbe-697b-4030-9bcc-cfeb282a9150' }; | ||
var data1 = {}; | ||
ajv.validate(schema, data1); // true | ||
data1; // { id: '5b008de7-1669-467a-a5c6-70fa244d7209' } | ||
``` | ||
You also can define dynamic default that accepts parameters, e.g. version of uuid: | ||
```javascript | ||
var uuid = require('uuid'); | ||
function getUuid(args) { | ||
var version = 'v' + (arvs && args.v || 4); | ||
return function() { | ||
return uuid[version](); | ||
}; | ||
} | ||
var definition = require('ajv-keywords').get('dynamicDefaults').definition; | ||
definition.DEFAULTS.uuid = getUuid; | ||
var schema = { | ||
dynamicDefaults: { | ||
id1: 'uuid', // v4 | ||
id2: { func: 'uuid', v: 4 }, // v4 | ||
id3: { func: 'uuid', v: 1 } // v1 | ||
} | ||
}; | ||
``` | ||
## License | ||
[MIT](https://github.com/JSONScript/ajv-keywords/blob/master/LICENSE) |
37560
21
727
299
9