feat: support validating [meta-]schemas against themselves, closes #259

master
Evgeny Poberezkin 2016-08-07 00:37:30 +01:00
parent 804764dbec
commit c103dc04b9
3 changed files with 186 additions and 7 deletions

View File

@ -106,8 +106,7 @@ function Ajv(opts) {
* @return {Function} validating function
*/
function compile(schema, _meta) {
var schemaObj = _addSchema(schema);
schemaObj.meta = _meta;
var schemaObj = _addSchema(schema, undefined, _meta);
return schemaObj.validate || _compile(schemaObj);
}
@ -127,8 +126,7 @@ function Ajv(opts) {
// can key/id have # inside?
key = resolve.normalizeId(key || schema.id);
checkUnique(key);
var schemaObj = self._schemas[key] = _addSchema(schema, _skipValidation, true);
schemaObj.meta = _meta;
self._schemas[key] = _addSchema(schema, _skipValidation, _meta, true);
}
@ -248,7 +246,7 @@ function Ajv(opts) {
}
function _addSchema(schema, skipValidation, shouldAddSchema) {
function _addSchema(schema, skipValidation, meta, shouldAddSchema) {
if (typeof schema != 'object') throw new Error('schema should be object');
var jsonStr = stableStringify(schema);
var cached = self._cache.get(jsonStr);
@ -259,7 +257,9 @@ function Ajv(opts) {
var id = resolve.normalizeId(schema.id);
if (id && shouldAddSchema) checkUnique(id);
if (self._opts.validateSchema !== false && !skipValidation)
var willValidate = self._opts.validateSchema !== false && !skipValidation;
var recursiveMeta;
if (willValidate && !(recursiveMeta = schema.id && schema.id == schema.$schema))
validateSchema(schema, true);
var localRefs = resolve.ids.call(self, schema);
@ -268,12 +268,15 @@ function Ajv(opts) {
id: id,
schema: schema,
localRefs: localRefs,
jsonStr: jsonStr
jsonStr: jsonStr,
meta: meta
});
if (id[0] != '#' && shouldAddSchema) self._refs[id] = schemaObj;
self._cache.put(jsonStr, schemaObj);
if (willValidate && recursiveMeta) validateSchema(schema, true);
return schemaObj;
}

View File

@ -457,3 +457,12 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
validate({ data: { type: 'Foo', id: '123' } }) .should.equal(false);
}
});
describe('issue #259, support validating [meta-]schemas against themselves', function() {
it('should add schema before validation if "id" is the same as "$schema"', function() {
var ajv = new Ajv;
var hyperSchema = require('./remotes/hyper-schema.json');
ajv.addMetaSchema(hyperSchema);
});
});

View File

@ -0,0 +1,167 @@
{
"$schema": "http://json-schema.org/draft-04/hyper-schema#",
"id": "http://json-schema.org/draft-04/hyper-schema#",
"title": "JSON Hyper-Schema",
"allOf": [
{
"$ref": "http://json-schema.org/draft-04/schema#"
}
],
"properties": {
"additionalItems": {
"anyOf": [
{
"type": "boolean"
},
{
"$ref": "#"
}
]
},
"additionalProperties": {
"anyOf": [
{
"type": "boolean"
},
{
"$ref": "#"
}
]
},
"dependencies": {
"additionalProperties": {
"anyOf": [
{
"$ref": "#"
},
{
"type": "array"
}
]
}
},
"items": {
"anyOf": [
{
"$ref": "#"
},
{
"$ref": "#/definitions/schemaArray"
}
]
},
"definitions": {
"additionalProperties": {
"$ref": "#"
}
},
"patternProperties": {
"additionalProperties": {
"$ref": "#"
}
},
"properties": {
"additionalProperties": {
"$ref": "#"
}
},
"allOf": {
"$ref": "#/definitions/schemaArray"
},
"anyOf": {
"$ref": "#/definitions/schemaArray"
},
"oneOf": {
"$ref": "#/definitions/schemaArray"
},
"not": {
"$ref": "#"
},
"links": {
"type": "array",
"items": {
"$ref": "#/definitions/linkDescription"
}
},
"fragmentResolution": {
"type": "string"
},
"media": {
"type": "object",
"properties": {
"type": {
"description": "A media type, as described in RFC 2046",
"type": "string"
},
"binaryEncoding": {
"description": "A content encoding scheme, as described in RFC 2045",
"type": "string"
}
}
},
"pathStart": {
"description": "Instances' URIs must start with this value for this schema to apply to them",
"type": "string",
"format": "uri"
}
},
"definitions": {
"schemaArray": {
"type": "array",
"items": {
"$ref": "#"
}
},
"linkDescription": {
"title": "Link Description Object",
"type": "object",
"required": [ "href", "rel" ],
"properties": {
"href": {
"description": "a URI template, as defined by RFC 6570, with the addition of the $, ( and ) characters for pre-processing",
"type": "string"
},
"rel": {
"description": "relation to the target resource of the link",
"type": "string"
},
"title": {
"description": "a title for the link",
"type": "string"
},
"targetSchema": {
"description": "JSON Schema describing the link target",
"$ref": "#"
},
"mediaType": {
"description": "media type (as defined by RFC 2046) describing the link target",
"type": "string"
},
"method": {
"description": "method for requesting the target of the link (e.g. for HTTP this might be \"GET\" or \"DELETE\")",
"type": "string"
},
"encType": {
"description": "The media type in which to submit data along with the request",
"type": "string",
"default": "application/json"
},
"schema": {
"description": "Schema describing the data to submit along with the request",
"$ref": "#"
}
}
}
},
"links": [
{
"rel": "self",
"href": "{+id}"
},
{
"rel": "full",
"href": "{+($ref)}"
}
]
}