feat: allow refs to fragments in "getSchema" and "validate" methods, closes #47

master
Evgeny Poberezkin 2016-08-15 21:16:59 +01:00
parent 66dd12bc45
commit 2d9241a658
4 changed files with 90 additions and 7 deletions

View File

@ -39,6 +39,7 @@ function Ajv(opts) {
opts = this._opts = util.copy(opts) || {};
this._schemas = {};
this._refs = {};
this._fragments = {};
this._formats = formats(opts.format);
this._cache = opts.cache || new Cache;
this._loadingSchemas = {};
@ -187,13 +188,34 @@ function Ajv(opts) {
switch (typeof schemaObj) {
case 'object': return schemaObj.validate || _compile(schemaObj);
case 'string': return getSchema(schemaObj);
case 'undefined': return _getSchemaFragment(keyRef);
}
}
function _getSchemaFragment(ref) {
var res = resolve.schema.call(self, { schema: {} }, ref);
if (res) {
var schema = res.schema
, root = res.root
, baseId = res.baseId;
var v = compileSchema.call(self, schema, root, undefined, baseId);
self._fragments[ref] = new SchemaObject({
ref: ref,
fragment: true,
schema: schema,
root: root,
baseId: baseId,
validate: v
});
return v;
}
}
function _getSchemaObj(keyRef) {
keyRef = resolve.normalizeId(keyRef);
return self._schemas[keyRef] || self._refs[keyRef];
return self._schemas[keyRef] || self._refs[keyRef] || self._fragments[keyRef];
}

View File

@ -12,6 +12,7 @@ resolve.fullPath = getFullPath;
resolve.url = resolveUrl;
resolve.ids = resolveIds;
resolve.inlineRef = inlineRef;
resolve.schema = resolveSchema;
/**
* [resolve and compile the references ($ref)]
@ -36,7 +37,7 @@ function resolve(compile, root, ref) {
: refVal.validate || this._compile(refVal);
}
var res = _resolve.call(this, root, ref);
var res = resolveSchema.call(this, root, ref);
var schema, v, baseId;
if (res) {
schema = res.schema;
@ -56,8 +57,14 @@ function resolve(compile, root, ref) {
}
/* @this Ajv */
function _resolve(root, ref) {
/**
* Resolve schema, its root and baseId
* @this Ajv
* @param {Object} root root object with properties schema, refVal, refs
* @param {String} ref reference to resolve
* @return {Object} object with properties schema, root, baseId
*/
function resolveSchema(root, ref) {
/* jshint validthis: true */
var p = url.parse(ref, false, true)
, refPath = _getFullPath(p)
@ -91,7 +98,7 @@ function _resolve(root, ref) {
/* @this Ajv */
function resolveRecursive(root, ref, parsedRef) {
/* jshint validthis: true */
var res = _resolve.call(this, root, ref);
var res = resolveSchema.call(this, root, ref);
if (res) {
var schema = res.schema;
var baseId = res.baseId;
@ -119,7 +126,7 @@ function getJsonPointer(parsedRef, baseId, schema, root) {
if (schema.id && !PREVENT_SCOPE_CHANGE[part]) baseId = resolveUrl(baseId, schema.id);
if (schema.$ref) {
var $ref = resolveUrl(baseId, schema.$ref);
var res = _resolve.call(this, root, $ref);
var res = resolveSchema.call(this, root, $ref);
if (res) {
schema = res.schema;
root = res.root;

View File

@ -1,6 +1,6 @@
{
"name": "ajv",
"version": "4.4.1",
"version": "4.5.0",
"description": "Another JSON Schema Validator",
"main": "lib/ajv.js",
"typings": "lib/ajv.d.ts",

View File

@ -88,6 +88,32 @@ describe('Ajv', function () {
ajv.validate('integer', 1) .should.equal(true);
should.throw(function() { ajv.validate('string', 'foo'); });
});
it('should validate schema fragment by ref', function() {
ajv.addSchema({
"id": "http://e.com/types.json",
"definitions": {
"int": { "type": "integer" },
"str": { "type": "string" }
}
});
ajv.validate('http://e.com/types.json#/definitions/int', 1) .should.equal(true);
ajv.validate('http://e.com/types.json#/definitions/int', '1') .should.equal(false);
});
it('should return schema fragment by id', function() {
ajv.addSchema({
"id": "http://e.com/types.json",
"definitions": {
"int": { "id": "#int", "type": "integer" },
"str": { "id": "#str", "type": "string" }
}
});
ajv.validate('http://e.com/types.json#int', 1) .should.equal(true);
ajv.validate('http://e.com/types.json#int', '1') .should.equal(false);
});
});
@ -210,6 +236,34 @@ describe('Ajv', function () {
v(1) .should.equal(true);
v('1') .should.equal(false);
});
it('should return schema fragment by ref', function() {
ajv.addSchema({
"id": "http://e.com/types.json",
"definitions": {
"int": { "type": "integer" },
"str": { "type": "string" }
}
});
var vInt = ajv.getSchema('http://e.com/types.json#/definitions/int');
vInt(1) .should.equal(true);
vInt('1') .should.equal(false);
});
it('should return schema fragment by id', function() {
ajv.addSchema({
"id": "http://e.com/types.json",
"definitions": {
"int": { "id": "#int", "type": "integer" },
"str": { "id": "#str", "type": "string" }
}
});
var vInt = ajv.getSchema('http://e.com/types.json#int');
vInt(1) .should.equal(true);
vInt('1') .should.equal(false);
});
});