feat: use only $id by default, closes #641

master
Evgeny Poberezkin 2017-12-02 12:32:45 +00:00
parent 896aa8d08e
commit ce62f117ee
12 changed files with 197 additions and 279 deletions

View File

@ -1033,7 +1033,7 @@ Defaults:
schemas: {},
logger: undefined,
// referenced schema options:
schemaId: undefined // recommended '$id'
schemaId: '$id',
missingRefs: true,
extendRefs: 'ignore', // recommended 'fail'
loadSchema: undefined, // function(uri: string): Promise {}
@ -1088,9 +1088,9 @@ Defaults:
##### Referenced schema options
- _schemaId_: this option defines which keywords are used as schema URI. Option value:
- `"$id"` (recommended) - only use `$id` keyword as schema URI (as specified in JSON Schema draft-06/07), ignore `id` keyword (if it is present a warning will be logged).
- `"$id"` (default) - only use `$id` keyword as schema URI (as specified in JSON Schema draft-06/07), ignore `id` keyword (if it is present a warning will be logged).
- `"id"` - only use `id` keyword as schema URI (as specified in JSON Schema draft-04), ignore `$id` keyword (if it is present a warning will be logged).
- `undefined` (default) - use both `$id` and `id` keywords as schema URI. If both are present (in the same schema object) and different the exception will be thrown during schema compilation.
- `"auto"` - use both `$id` and `id` keywords as schema URI. If both are present (in the same schema object) and different the exception will be thrown during schema compilation.
- _missingRefs_: handling of missing referenced schemas. Option values:
- `true` (default) - if the reference cannot be resolved during compilation the exception is thrown. The thrown error has properties `missingRef` (with hash fragment) and `missingSchema` (without it). Both properties are resolved relative to the current base id (usually schema id, unless it was substituted).
- `"ignore"` - to log error during compilation and always pass validation.

View File

@ -374,9 +374,9 @@ function _compile(schemaObj, root) {
function chooseGetId(opts) {
switch (opts.schemaId) {
case '$id': return _get$Id;
case 'auto': return _get$IdOrId;
case 'id': return _getId;
default: return _get$IdOrId;
default: return _get$Id;
}
}

View File

@ -33,9 +33,9 @@ describe('Ajv', function () {
});
it('should throw if different schema has the same id', function() {
ajv.compile({ id: '//e.com/int.json', type: 'integer' });
ajv.compile({ $id: '//e.com/int.json', type: 'integer' });
should.throw(function() {
ajv.compile({ id: '//e.com/int.json', type: 'integer', minimum: 1 });
ajv.compile({ $id: '//e.com/int.json', type: 'integer', minimum: 1 });
});
});
@ -74,24 +74,24 @@ describe('Ajv', function () {
});
it('should validate against previously compiled schema by id (also see addSchema)', function() {
ajv.validate({ id: '//e.com/int.json', type: 'integer' }, 1) .should.equal(true);
ajv.validate({ $id: '//e.com/int.json', type: 'integer' }, 1) .should.equal(true);
ajv.validate('//e.com/int.json', 1) .should.equal(true);
ajv.validate('//e.com/int.json', '1') .should.equal(false);
ajv.compile({ id: '//e.com/str.json', type: 'string' }) .should.be.a('function');
ajv.compile({ $id: '//e.com/str.json', type: 'string' }) .should.be.a('function');
ajv.validate('//e.com/str.json', 'a') .should.equal(true);
ajv.validate('//e.com/str.json', 1) .should.equal(false);
});
it('should throw exception if no schema with ref', function() {
ajv.validate({ id: 'integer', type: 'integer' }, 1) .should.equal(true);
ajv.validate({ $id: 'integer', type: 'integer' }, 1) .should.equal(true);
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",
"$id": "http://e.com/types.json",
"definitions": {
"int": { "type": "integer" },
"str": { "type": "string" }
@ -104,10 +104,10 @@ describe('Ajv', function () {
it('should return schema fragment by id', function() {
ajv.addSchema({
"id": "http://e.com/types.json",
"$id": "http://e.com/types.json",
"definitions": {
"int": { "id": "#int", "type": "integer" },
"str": { "id": "#str", "type": "string" }
"int": { "$id": "#int", "type": "integer" },
"str": { "$id": "#str", "type": "string" }
}
});
@ -137,13 +137,13 @@ describe('Ajv', function () {
});
it('should add and compile schema with id', function() {
ajv.addSchema({ id: '//e.com/int.json', type: 'integer' });
ajv.addSchema({ $id: '//e.com/int.json', type: 'integer' });
ajv.validate('//e.com/int.json', 1) .should.equal(true);
ajv.validate('//e.com/int.json', '1') .should.equal(false);
});
it('should normalize schema keys and ids', function() {
ajv.addSchema({ id: '//e.com/int.json#', type: 'integer' }, 'int#');
ajv.addSchema({ $id: '//e.com/int.json#', type: 'integer' }, 'int#');
ajv.validate('int', 1) .should.equal(true);
ajv.validate('int', '1') .should.equal(false);
ajv.validate('//e.com/int.json', 1) .should.equal(true);
@ -156,8 +156,8 @@ describe('Ajv', function () {
it('should add and compile array of schemas with ids', function() {
ajv.addSchema([
{ id: '//e.com/int.json', type: 'integer' },
{ id: '//e.com/str.json', type: 'string' }
{ $id: '//e.com/int.json', type: 'integer' },
{ $id: '//e.com/str.json', type: 'string' }
]);
var validate0 = ajv.getSchema('//e.com/int.json');
@ -210,7 +210,7 @@ describe('Ajv', function () {
it('should throw if schema id is not a string', function() {
try {
ajv.addSchema({ id: 1, type: 'integer' });
ajv.addSchema({ $id: 1, type: 'integer' });
throw new Error('should have throw exception');
} catch(e) {
e.message .should.equal('schema id must be string');
@ -233,7 +233,7 @@ describe('Ajv', function () {
});
it('should return compiled schema by id or ref', function() {
ajv.addSchema({ id: '//e.com/int.json', type: 'integer' });
ajv.addSchema({ $id: '//e.com/int.json', type: 'integer' });
var validate = ajv.getSchema('//e.com/int.json');
validate(1) .should.equal(true);
validate('1') .should.equal(false);
@ -252,7 +252,7 @@ describe('Ajv', function () {
it('should return schema fragment by ref', function() {
ajv.addSchema({
"id": "http://e.com/types.json",
"$id": "http://e.com/types.json",
"definitions": {
"int": { "type": "integer" },
"str": { "type": "string" }
@ -266,7 +266,7 @@ describe('Ajv', function () {
it('should return schema fragment by ref with protocol-relative URIs', function() {
ajv.addSchema({
"id": "//e.com/types.json",
"$id": "//e.com/types.json",
"definitions": {
"int": { "type": "integer" },
"str": { "type": "string" }
@ -280,10 +280,10 @@ describe('Ajv', function () {
it('should return schema fragment by id', function() {
ajv.addSchema({
"id": "http://e.com/types.json",
"$id": "http://e.com/types.json",
"definitions": {
"int": { "id": "#int", "type": "integer" },
"str": { "id": "#str", "type": "string" }
"int": { "$id": "#int", "type": "integer" },
"str": { "$id": "#str", "type": "string" }
}
});
@ -310,7 +310,7 @@ describe('Ajv', function () {
});
it('should remove schema by id', function() {
var schema = { id: '//e.com/int.json', type: 'integer' }
var schema = { $id: '//e.com/int.json', type: 'integer' }
, str = stableStringify(schema);
ajv.addSchema(schema);
@ -333,11 +333,11 @@ describe('Ajv', function () {
});
it('should remove schema with id by schema object', function() {
var schema = { id: '//e.com/int.json', type: 'integer' }
var schema = { $id: '//e.com/int.json', type: 'integer' }
, str = stableStringify(schema);
ajv.addSchema(schema);
ajv._cache.get(str) .should.be.an('object');
ajv.removeSchema({ id: '//e.com/int.json', type: 'integer' });
ajv.removeSchema({ $id: '//e.com/int.json', type: 'integer' });
// should.not.exist(ajv.getSchema('//e.com/int.json'));
should.not.exist(ajv._cache.get(str));
});
@ -350,7 +350,7 @@ describe('Ajv', function () {
});
it('should remove all schemas but meta-schemas if called without an arguments', function() {
var schema1 = { id: '//e.com/int.json', type: 'integer' }
var schema1 = { $id: '//e.com/int.json', type: 'integer' }
, str1 = stableStringify(schema1);
ajv.addSchema(schema1);
ajv._cache.get(str1) .should.be.an('object');
@ -366,12 +366,12 @@ describe('Ajv', function () {
});
it('should remove all schemas but meta-schemas with key/id matching pattern', function() {
var schema1 = { id: '//e.com/int.json', type: 'integer' }
var schema1 = { $id: '//e.com/int.json', type: 'integer' }
, str1 = stableStringify(schema1);
ajv.addSchema(schema1);
ajv._cache.get(str1) .should.be.an('object');
var schema2 = { id: 'str.json', type: 'string' }
var schema2 = { $id: 'str.json', type: 'string' }
, str2 = stableStringify(schema2);
ajv.addSchema(schema2, '//e.com/str.json');
ajv._cache.get(str2) .should.be.an('object');

View File

@ -10,50 +10,50 @@ describe('compileAsync method', function() {
var SCHEMAS = {
"http://example.com/object.json": {
"id": "http://example.com/object.json",
"$id": "http://example.com/object.json",
"properties": {
"a": { "type": "string" },
"b": { "$ref": "int2plus.json" }
}
},
"http://example.com/int2plus.json": {
"id": "http://example.com/int2plus.json",
"$id": "http://example.com/int2plus.json",
"type": "integer",
"minimum": 2
},
"http://example.com/tree.json": {
"id": "http://example.com/tree.json",
"$id": "http://example.com/tree.json",
"type": "array",
"items": { "$ref": "leaf.json" }
},
"http://example.com/leaf.json": {
"id": "http://example.com/leaf.json",
"$id": "http://example.com/leaf.json",
"properties": {
"name": { "type": "string" },
"subtree": { "$ref": "tree.json" }
}
},
"http://example.com/recursive.json": {
"id": "http://example.com/recursive.json",
"$id": "http://example.com/recursive.json",
"properties": {
"b": { "$ref": "parent.json" }
},
"required": ["b"]
},
"http://example.com/invalid.json": {
"id": "http://example.com/recursive.json",
"$id": "http://example.com/recursive.json",
"properties": {
"invalid": { "type": "number" }
},
"required": "invalid"
},
"http://example.com/foobar.json": {
"id": "http://example.com/foobar.json",
"$id": "http://example.com/foobar.json",
"$schema": "http://example.com/foobar_meta.json",
"myFooBar": "foo"
},
"http://example.com/foobar_meta.json": {
"id": "http://example.com/foobar_meta.json",
"$id": "http://example.com/foobar_meta.json",
"type": "object",
"properties": {
"myFooBar": {
@ -71,7 +71,7 @@ describe('compileAsync method', function() {
it('should compile schemas loading missing schemas with options.loadSchema function', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json" }
}
@ -87,7 +87,7 @@ describe('compileAsync method', function() {
it('should compile schemas loading missing schemas and return function via callback', function (done) {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json" }
}
@ -105,7 +105,7 @@ describe('compileAsync method', function() {
it('should correctly load schemas when missing reference has JSON path', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json#/properties/b" }
}
@ -121,7 +121,7 @@ describe('compileAsync method', function() {
it('should correctly compile with remote schemas that have mutual references', function() {
var schema = {
"id": "http://example.com/root.json",
"$id": "http://example.com/root.json",
"properties": {
"tree": { "$ref": "tree.json" }
}
@ -143,7 +143,7 @@ describe('compileAsync method', function() {
it('should correctly compile with remote schemas that reference the compiled schema', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "recursive.json" }
}
@ -161,7 +161,7 @@ describe('compileAsync method', function() {
it('should resolve reference containing "properties" segment with the same property (issue #220)', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": {
"$ref": "object.json#/properties/a"
@ -206,7 +206,7 @@ describe('compileAsync method', function() {
it('should return compiled schema on the next tick if there are no references (#51)', function() {
var schema = {
"id": "http://example.com/int2plus.json",
"$id": "http://example.com/int2plus.json",
"type": "integer",
"minimum": 2
};
@ -238,7 +238,7 @@ describe('compileAsync method', function() {
it('should queue calls so only one compileAsync executes at a time (#52)', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json" }
}
@ -261,7 +261,7 @@ describe('compileAsync method', function() {
it('should throw exception if loadSchema is not passed', function (done) {
var schema = {
"id": "http://example.com/int2plus.json",
"$id": "http://example.com/int2plus.json",
"type": "integer",
"minimum": 2
};
@ -281,7 +281,7 @@ describe('compileAsync method', function() {
describe('should return error via callback', function() {
it('if passed schema is invalid', function (done) {
var invalidSchema = {
"id": "http://example.com/int2plus.json",
"$id": "http://example.com/int2plus.json",
"type": "integer",
"minimum": "invalid"
};
@ -290,7 +290,7 @@ describe('compileAsync method', function() {
it('if loaded schema is invalid', function (done) {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "invalid.json" }
}
@ -300,7 +300,7 @@ describe('compileAsync method', function() {
it('if required schema is loaded but the reference cannot be resolved', function (done) {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json#/definitions/not_found" }
}
@ -310,7 +310,7 @@ describe('compileAsync method', function() {
it('if loadSchema returned error', function (done) {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json" }
}
@ -346,7 +346,7 @@ describe('compileAsync method', function() {
describe('should return error via promise', function() {
it('if passed schema is invalid', function() {
var invalidSchema = {
"id": "http://example.com/int2plus.json",
"$id": "http://example.com/int2plus.json",
"type": "integer",
"minimum": "invalid"
};
@ -355,7 +355,7 @@ describe('compileAsync method', function() {
it('if loaded schema is invalid', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "invalid.json" }
}
@ -365,7 +365,7 @@ describe('compileAsync method', function() {
it('if required schema is loaded but the reference cannot be resolved', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json#/definitions/not_found" }
}

View File

@ -291,7 +291,7 @@ describe('async schemas, formats and keywords', function() {
it('should validate refs between two async schemas', function() {
var schemaObj = {
id: 'http://e.com/obj.json#',
$id: 'http://e.com/obj.json#',
$async: true,
type: 'object',
properties: {
@ -300,7 +300,7 @@ describe('async schemas, formats and keywords', function() {
};
var schemaWord = {
id: 'http://e.com/word.json#',
$id: 'http://e.com/word.json#',
$async: true,
anyOf: [
{
@ -316,7 +316,7 @@ describe('async schemas, formats and keywords', function() {
it('should fail compilation if sync schema references async schema', function() {
var schema = {
id: 'http://e.com/obj.json#',
$id: 'http://e.com/obj.json#',
type: 'object',
properties: {
foo: { $ref: 'http://e.com/word.json#' }
@ -324,7 +324,7 @@ describe('async schemas, formats and keywords', function() {
};
var schemaWord = {
id: 'http://e.com/word.json#',
$id: 'http://e.com/word.json#',
$async: true,
anyOf: [
{
@ -345,7 +345,7 @@ describe('async schemas, formats and keywords', function() {
ajv.compile(schema);
});
schema.id = 'http://e.com/obj2.json#';
schema.$id = 'http://e.com/obj2.json#';
schema.$async = true;
ajv.compile(schema);

View File

@ -365,10 +365,10 @@ describe('Type coercion', function () {
};
var schemaRecursive2 = {
id: 'http://e.com/schema.json#',
$id: 'http://e.com/schema.json#',
definitions: {
foo: {
id: 'http://e.com/foo.json#',
$id: 'http://e.com/foo.json#',
type: [ 'object', 'number' ],
properties: {
foo: { $ref: '#' }

View File

@ -19,7 +19,7 @@ describe('issue #8: schema with shared references', function() {
};
var schema = {
id: 'obj.json#',
$id: 'obj.json#',
type: 'object',
properties: {
foo: propertySchema,
@ -51,7 +51,7 @@ describe('issue #50: references with "definitions"', function () {
var ajv = new Ajv;
ajv[method]({
id: 'http://example.com/test/person.json#',
$id: 'http://example.com/test/person.json#',
definitions: {
name: { type: 'string' }
},
@ -62,7 +62,7 @@ describe('issue #50: references with "definitions"', function () {
});
ajv[method]({
id: 'http://example.com/test/employee.json#',
$id: 'http://example.com/test/employee.json#',
type: 'object',
properties: {
person: { $ref: '/test/person.json#' },
@ -109,7 +109,7 @@ describe('issue #182, NaN validation', function() {
describe('issue #204, options schemas and $data used together', function() {
it('should use v5 metaschemas by default', function() {
var ajv = new Ajv({
schemas: [{id: 'str', type: 'string'}],
schemas: [{$id: 'str', type: 'string'}],
$data: true
});
@ -184,7 +184,7 @@ describe('issue #210, mutual recursive $refs that are schema fragments', functio
var ajv = new Ajv;
ajv.addSchema({
"id" : "foo",
"$id" : "foo",
"definitions": {
"bar": {
"properties": {
@ -200,7 +200,7 @@ describe('issue #210, mutual recursive $refs that are schema fragments', functio
});
ajv.addSchema({
"id" : "boo",
"$id" : "boo",
"type": "object",
"required": ["quux"],
"properties": {
@ -218,7 +218,7 @@ describe('issue #210, mutual recursive $refs that are schema fragments', functio
var ajv = new Ajv;
ajv.addSchema({
"id" : "foo",
"$id" : "foo",
"definitions": {
"bar": {
"properties": {
@ -234,7 +234,7 @@ describe('issue #210, mutual recursive $refs that are schema fragments', functio
});
ajv.addSchema({
"id" : "boo",
"$id" : "boo",
"definitions": {
"buu": {
"type": "object",
@ -257,15 +257,15 @@ describe('issue #210, mutual recursive $refs that are schema fragments', functio
describe('issue #240, mutually recursive fragment refs reference a common schema', function() {
var apiSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
id: 'schema://api.schema#',
$id: 'schema://api.schema#',
resource: {
id: '#resource',
$id: '#resource',
properties: {
id: { type: 'string' }
}
},
resourceIdentifier: {
id: '#resource_identifier',
$id: '#resource_identifier',
properties: {
id: { type: 'string' },
type: { type: 'string' }
@ -275,7 +275,7 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
var domainSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
id: 'schema://domain.schema#',
$id: 'schema://domain.schema#',
properties: {
data: {
oneOf: [
@ -291,7 +291,7 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
var librarySchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
id: 'schema://library.schema#',
$id: 'schema://library.schema#',
properties: {
name: { type: 'string' },
links: {
@ -305,7 +305,7 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
},
definitions: {
resource_identifier: {
id: '#resource_identifier',
$id: '#resource_identifier',
allOf: [
{
properties: {
@ -323,7 +323,7 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
var catalogItemSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
id: 'schema://catalog_item.schema#',
$id: 'schema://catalog_item.schema#',
properties: {
name: { type: 'string' },
links: {
@ -334,7 +334,7 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
},
definitions: {
resource_identifier: {
id: '#resource_identifier',
$id: '#resource_identifier',
allOf: [
{
properties: {
@ -352,7 +352,7 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
var catalogItemResourceIdentifierSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
id: 'schema://catalog_item_resource_identifier.schema#',
$id: 'schema://catalog_item_resource_identifier.schema#',
allOf: [
{
properties: {
@ -382,7 +382,7 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
var librarySchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
id: 'schema://library.schema#',
$id: 'schema://library.schema#',
properties: {
name: { type: 'string' },
links: {
@ -396,7 +396,7 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
},
definitions: {
resource_identifier: {
id: '#resource_identifier',
$id: '#resource_identifier',
allOf: [
{
properties: {
@ -414,7 +414,7 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
var catalogItemSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
id: 'schema://catalog_item.schema#',
$id: 'schema://catalog_item.schema#',
properties: {
name: { type: 'string' },
links: {
@ -425,7 +425,7 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
},
definitions: {
resource_identifier: {
id: '#resource_identifier',
$id: '#resource_identifier',
allOf: [
{
properties: {
@ -463,7 +463,6 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
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;
ajv.addMetaSchema(require('../lib/refs/json-schema-draft-04.json'));
var hyperSchema = require('./remotes/hyper-schema.json');
ajv.addMetaSchema(hyperSchema);
});

View File

@ -12,11 +12,11 @@ var remoteRefs = {
'http://localhost:1234/folder/folderInteger.json': require('./JSON-Schema-Test-Suite/remotes/folder/folderInteger.json'),
};
runTest(getAjvInstances(options, {meta: false}), 4, typeof window == 'object'
runTest(getAjvInstances(options, {meta: false, schemaId: 'id'}), 4, typeof window == 'object'
? suite(require('./JSON-Schema-Test-Suite/tests/draft4/{**/,}*.json', {mode: 'list'}))
: './JSON-Schema-Test-Suite/tests/draft4/{**/,}*.json');
runTest(getAjvInstances(options), 6, typeof window == 'object'
runTest(getAjvInstances(options, {schemaId: 'auto'}), 6, typeof window == 'object'
? suite(require('./JSON-Schema-Test-Suite/tests/draft6/{**/,}*.json', {mode: 'list'}))
: './JSON-Schema-Test-Suite/tests/draft6/{**/,}*.json');

View File

@ -11,7 +11,7 @@ describe('Ajv Options', function () {
var ajv = new Ajv({ removeAdditional: 'all' });
ajv.addSchema({
id: '//test/fooBar',
$id: '//test/fooBar',
properties: { foo: { type: 'string' }, bar: { type: 'string' } }
});
@ -30,7 +30,7 @@ describe('Ajv Options', function () {
var ajv = new Ajv({ removeAdditional: true });
ajv.addSchema({
id: '//test/fooBar',
$id: '//test/fooBar',
properties: { foo: { type: 'string' }, bar: { type: 'string' } },
additionalProperties: false
});
@ -50,7 +50,7 @@ describe('Ajv Options', function () {
var ajv = new Ajv({ removeAdditional: 'failing' });
ajv.addSchema({
id: '//test/fooBar',
$id: '//test/fooBar',
properties: { foo: { type: 'string' }, bar: { type: 'string' } },
additionalProperties: { type: 'string' }
});
@ -66,7 +66,7 @@ describe('Ajv Options', function () {
object.should.not.have.property('fizz');
ajv.addSchema({
id: '//test/fooBar2',
$id: '//test/fooBar2',
properties: { foo: { type: 'string' }, bar: { type: 'string' } },
additionalProperties: { type: 'string', pattern: '^to-be-', maxLength: 10 }
});
@ -347,9 +347,9 @@ describe('Ajv Options', function () {
it('should add schemas from array', function() {
var ajv = new Ajv({ schemas: [
{ id: 'int', type: 'integer' },
{ id: 'str', type: 'string' },
{ id: 'obj', properties: { int: { $ref: 'int' }, str: { $ref: 'str' } } }
{ $id: 'int', type: 'integer' },
{ $id: 'str', type: 'string' },
{ $id: 'obj', properties: { int: { $ref: 'int' }, str: { $ref: 'str' } } }
]});
ajv.validate('obj', { int: 123, str: 'foo' }) .should.equal(true);
@ -669,26 +669,26 @@ describe('Ajv Options', function () {
describe('compile and validate', function() {
it('should add schema', function() {
var schema = { id: 'str', type: 'string' };
var schema = { $id: 'str', type: 'string' };
var validate = ajv.compile(schema);
validate('abc') .should.equal(true);
validate(1) .should.equal(false);
ajv.getSchema('str') .should.equal(validate);
schema = { id: 'int', type: 'integer' };
schema = { $id: 'int', type: 'integer' };
ajv.validate(schema, 1) .should.equal(true);
ajv.validate(schema, 'abc') .should.equal(false);
ajv.getSchema('int') .should.be.a('function');
});
it('should throw with duplicate ID', function() {
ajv.compile({ id: 'str', type: 'string' });
ajv.compile({ $id: 'str', type: 'string' });
should.throw(function() {
ajv.compile({ id: 'str', minLength: 2 });
ajv.compile({ $id: 'str', minLength: 2 });
});
var schema = { id: 'int', type: 'integer' };
var schema2 = { id: 'int', minimum: 0 };
var schema = { $id: 'int', type: 'integer' };
var schema2 = { $id: 'int', minimum: 0 };
ajv.validate(schema, 1) .should.equal(true);
should.throw(function() {
ajv.validate(schema2, 1);
@ -708,26 +708,26 @@ describe('Ajv Options', function () {
describe('compile and validate', function() {
it('should NOT add schema', function() {
var schema = { id: 'str', type: 'string' };
var schema = { $id: 'str', type: 'string' };
var validate = ajv.compile(schema);
validate('abc') .should.equal(true);
validate(1) .should.equal(false);
should.equal(ajv.getSchema('str'), undefined);
schema = { id: 'int', type: 'integer' };
schema = { $id: 'int', type: 'integer' };
ajv.validate(schema, 1) .should.equal(true);
ajv.validate(schema, 'abc') .should.equal(false);
should.equal(ajv.getSchema('int'), undefined);
});
it('should NOT throw with duplicate ID', function() {
ajv.compile({ id: 'str', type: 'string' });
ajv.compile({ $id: 'str', type: 'string' });
should.not.throw(function() {
ajv.compile({ id: 'str', minLength: 2 });
ajv.compile({ $id: 'str', minLength: 2 });
});
var schema = { id: 'int', type: 'integer' };
var schema2 = { id: 'int', minimum: 0 };
var schema = { $id: 'int', type: 'integer' };
var schema2 = { $id: 'int', minimum: 0 };
ajv.validate(schema, 1) .should.equal(true);
should.not.throw(function() {
ajv.validate(schema2, 1) .should.equal(true);
@ -1134,21 +1134,20 @@ describe('Ajv Options', function () {
describe('schemaId', function() {
describe('= undefined (default)', function() {
it('should throw if both id and $id are available and different', function() {
var ajv = new Ajv;
describe('= "$id" (default)', function() {
it('should use $id and ignore id', function() {
test(new Ajv);
test(new Ajv({schemaId: '$id'}));
ajv.compile({
id: 'mySchema',
$id: 'mySchema'
});
function test(ajv) {
ajv.addSchema({ $id: 'mySchema1', type: 'string' });
var validate = ajv.getSchema('mySchema1');
validate('foo') .should.equal(true);
validate(1) .should.equal(false);
should.throw(function() {
ajv.compile({
id: 'mySchema1',
$id: 'mySchema2'
});
});
validate = ajv.compile({ id: 'mySchema2', type: 'string' });
should.not.exist(ajv.getSchema('mySchema2'));
}
});
});
@ -1166,17 +1165,35 @@ describe('Ajv Options', function () {
});
});
describe('= "$id"', function() {
it('should use $id and ignore id', function() {
var ajv = new Ajv({schemaId: '$id'});
describe('= "auto"', function() {
it('should use both id and $id', function() {
var ajv = new Ajv({schemaId: 'auto'});
ajv.addSchema({ $id: 'mySchema1', type: 'string' });
var validate = ajv.getSchema('mySchema1');
validate('foo') .should.equal(true);
validate(1) .should.equal(false);
validate = ajv.compile({ id: 'mySchema2', type: 'string' });
should.not.exist(ajv.getSchema('mySchema2'));
ajv.addSchema({ id: 'mySchema2', type: 'string' });
validate = ajv.getSchema('mySchema2');
validate('foo') .should.equal(true);
validate(1) .should.equal(false);
});
it('should throw if both id and $id are available and different', function() {
var ajv = new Ajv({schemaId: 'auto'});
ajv.compile({
id: 'mySchema',
$id: 'mySchema'
});
should.throw(function() {
ajv.compile({
id: 'mySchema1',
$id: 'mySchema2'
});
});
});
});
});

View File

@ -1,167 +1,69 @@
{
"$schema": "http://json-schema.org/draft-04/hyper-schema#",
"id": "http://json-schema.org/draft-04/hyper-schema#",
"$schema": "http://json-schema.org/draft-07/hyper-schema#",
"$id": "http://json-schema.org/draft-07/hyper-schema#",
"title": "JSON Hyper-Schema",
"allOf": [
{
"$ref": "http://json-schema.org/draft-04/schema#"
"definitions": {
"schemaArray": {
"allOf": [
{ "$ref": "http://json-schema.org/draft-07/schema#/definitions/schemaArray" },
{
"items": { "$ref": "#" }
}
]
}
],
},
"allOf": [ { "$ref": "http://json-schema.org/draft-07/schema#" } ],
"properties": {
"additionalItems": {
"anyOf": [
{
"type": "boolean"
},
{
"$ref": "#"
}
]
},
"additionalProperties": {
"anyOf": [
{
"type": "boolean"
},
{
"$ref": "#"
}
]
},
"additionalItems": { "$ref": "#" },
"additionalProperties": { "$ref": "#"},
"dependencies": {
"additionalProperties": {
"anyOf": [
{
"$ref": "#"
},
{
"type": "array"
}
{ "$ref": "#" },
{ "type": "array" }
]
}
},
"items": {
"anyOf": [
{
"$ref": "#"
},
{
"$ref": "#/definitions/schemaArray"
}
{ "$ref": "#" },
{ "$ref": "#/definitions/schemaArray" }
]
},
"definitions": {
"additionalProperties": {
"$ref": "#"
}
"additionalProperties": { "$ref": "#" }
},
"patternProperties": {
"additionalProperties": {
"$ref": "#"
}
"additionalProperties": { "$ref": "#" }
},
"properties": {
"additionalProperties": {
"$ref": "#"
}
},
"allOf": {
"$ref": "#/definitions/schemaArray"
},
"anyOf": {
"$ref": "#/definitions/schemaArray"
},
"oneOf": {
"$ref": "#/definitions/schemaArray"
},
"not": {
"$ref": "#"
"additionalProperties": { "$ref": "#" }
},
"if": {"$ref": "#"},
"then": {"$ref": "#"},
"else": {"$ref": "#"},
"allOf": { "$ref": "#/definitions/schemaArray" },
"anyOf": { "$ref": "#/definitions/schemaArray" },
"oneOf": { "$ref": "#/definitions/schemaArray" },
"not": { "$ref": "#" },
"contains": { "$ref": "#" },
"propertyNames": { "$ref": "#" },
"base": {
"type": "string",
"format": "uri-template"
},
"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": "#"
}
"$ref": "http://json-schema.org/draft-07/hyper-schema#/links"
}
}
},
"links": [
{
"rel": "self",
"href": "{+id}"
},
{
"rel": "full",
"href": "{+($ref)}"
"href": "{+%24id}"
}
]
}

View File

@ -20,28 +20,28 @@ describe('resolve', function () {
it('should resolve ids in schema', function() {
// Example from http://json-schema.org/latest/json-schema-core.html#anchor29
var schema = {
"id": "http://x.y.z/rootschema.json#",
"$id": "http://x.y.z/rootschema.json#",
"schema1": {
"id": "#foo",
"$id": "#foo",
"description": "schema1",
"type": "integer"
},
"schema2": {
"id": "otherschema.json",
"$id": "otherschema.json",
"description": "schema2",
"nested": {
"id": "#bar",
"$id": "#bar",
"description": "nested",
"type": "string"
},
"alsonested": {
"id": "t/inner.json#a",
"$id": "t/inner.json#a",
"description": "alsonested",
"type": "boolean"
}
},
"schema3": {
"id": "some://where.else/completely#",
"$id": "some://where.else/completely#",
"description": "schema3",
"type": "null"
},
@ -65,13 +65,13 @@ describe('resolve', function () {
it('should throw if the same id resolves to two different schemas', function() {
instances.forEach(function (ajv) {
ajv.compile({
"id": "http://example.com/1.json",
"$id": "http://example.com/1.json",
"type": "integer"
});
should.throw(function() {
ajv.compile({
"additionalProperties": {
"id": "http://example.com/1.json",
"$id": "http://example.com/1.json",
"type": "string"
}
});
@ -80,11 +80,11 @@ describe('resolve', function () {
should.throw(function() {
ajv.compile({
"items": {
"id": "#int",
"$id": "#int",
"type": "integer"
},
"additionalProperties": {
"id": "#int",
"$id": "#int",
"type": "string"
}
});
@ -98,7 +98,7 @@ describe('resolve', function () {
it('should resolve fragment', function() {
instances.forEach(function(ajv) {
var schema = {
"id": "//e.com/types",
"$id": "//e.com/types",
"definitions": {
"int": { "type": "integer" }
}
@ -166,7 +166,7 @@ describe('resolve', function () {
instances.forEach(function (ajv) {
try {
ajv.compile({
"id": opts.baseId,
"$id": opts.baseId,
"properties": { "a": { "$ref": opts.ref } }
});
} catch(e) {
@ -180,14 +180,14 @@ describe('resolve', function () {
describe('inline referenced schemas without refs in them', function() {
var schemas = [
{ id: 'http://e.com/obj.json#',
{ $id: 'http://e.com/obj.json#',
properties: { a: { $ref: 'int.json#' } } },
{ id: 'http://e.com/int.json#',
{ $id: 'http://e.com/int.json#',
type: 'integer', minimum: 2, maximum: 4 },
{ id: 'http://e.com/obj1.json#',
{ $id: 'http://e.com/obj1.json#',
definitions: { int: { type: 'integer', minimum: 2, maximum: 4 } },
properties: { a: { $ref: '#/definitions/int' } } },
{ id: 'http://e.com/list.json#',
{ $id: 'http://e.com/list.json#',
items: { $ref: 'obj.json#' } }
];
@ -220,7 +220,7 @@ describe('resolve', function () {
var schemaMessage = {
$schema: "http://json-schema.org/draft-07/schema#",
id: "http://e.com/message.json#",
$id: "http://e.com/message.json#",
type: "object",
required: ["header"],
properties: {
@ -236,7 +236,7 @@ describe('resolve', function () {
// header schema
var schemaHeader = {
$schema: "http://json-schema.org/draft-07/schema#",
id: "http://e.com/header.json#",
$id: "http://e.com/header.json#",
type: "object",
properties: {
version: {
@ -270,14 +270,14 @@ describe('resolve', function () {
var v = ajv.getSchema('http://e.com/message.json#');
v(validMessage) .should.equal(true);
v.schema.id .should.equal('http://e.com/message.json#');
v.schema.$id .should.equal('http://e.com/message.json#');
v(invalidMessage) .should.equal(false);
v.errors .should.have.length(1);
v.schema.id .should.equal('http://e.com/message.json#');
v.schema.$id .should.equal('http://e.com/message.json#');
v(validMessage) .should.equal(true);
v.schema.id .should.equal('http://e.com/message.json#');
v.schema.$id .should.equal('http://e.com/message.json#');
});

View File

@ -6,7 +6,7 @@ var jsonSchemaTest = require('json-schema-test')
, suite = require('./browser_test_suite')
, after = require('./after_test');
var instances = getAjvInstances(options, {unknownFormats: ['allowedUnknown']});
var instances = getAjvInstances(options, {schemaId: 'auto', unknownFormats: ['allowedUnknown']});
var remoteRefs = {
'http://localhost:1234/integer.json': require('./JSON-Schema-Test-Suite/remotes/integer.json'),