From ce62f117ee1e485aca2bef662615f936e1449c19 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Sat, 2 Dec 2017 12:32:45 +0000 Subject: [PATCH] feat: use only $id by default, closes #641 --- README.md | 6 +- lib/ajv.js | 4 +- spec/ajv.spec.js | 52 +++++----- spec/async.spec.js | 48 +++++----- spec/async_validate.spec.js | 10 +- spec/coercion.spec.js | 4 +- spec/issues.spec.js | 43 ++++----- spec/json-schema.spec.js | 4 +- spec/options.spec.js | 91 +++++++++++------- spec/remotes/hyper-schema.json | 170 +++++++-------------------------- spec/resolve.spec.js | 42 ++++---- spec/schema-tests.spec.js | 2 +- 12 files changed, 197 insertions(+), 279 deletions(-) diff --git a/README.md b/README.md index 04e35ff..daa8b6e 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/lib/ajv.js b/lib/ajv.js index 2c1b890..b379508 100644 --- a/lib/ajv.js +++ b/lib/ajv.js @@ -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; } } diff --git a/spec/ajv.spec.js b/spec/ajv.spec.js index 7eec3b6..8c5e23a 100644 --- a/spec/ajv.spec.js +++ b/spec/ajv.spec.js @@ -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'); diff --git a/spec/async.spec.js b/spec/async.spec.js index 5363e32..bcac5a4 100644 --- a/spec/async.spec.js +++ b/spec/async.spec.js @@ -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" } } diff --git a/spec/async_validate.spec.js b/spec/async_validate.spec.js index 039483a..04d47ce 100644 --- a/spec/async_validate.spec.js +++ b/spec/async_validate.spec.js @@ -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); diff --git a/spec/coercion.spec.js b/spec/coercion.spec.js index 0aa5abf..42f2f58 100644 --- a/spec/coercion.spec.js +++ b/spec/coercion.spec.js @@ -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: '#' } diff --git a/spec/issues.spec.js b/spec/issues.spec.js index 6b0d1b9..ee181bb 100644 --- a/spec/issues.spec.js +++ b/spec/issues.spec.js @@ -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); }); diff --git a/spec/json-schema.spec.js b/spec/json-schema.spec.js index bde31a2..2ceb640 100644 --- a/spec/json-schema.spec.js +++ b/spec/json-schema.spec.js @@ -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'); diff --git a/spec/options.spec.js b/spec/options.spec.js index 5ae18dd..616a4e2 100644 --- a/spec/options.spec.js +++ b/spec/options.spec.js @@ -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' + }); + }); }); }); }); diff --git a/spec/remotes/hyper-schema.json b/spec/remotes/hyper-schema.json index fee0cfb..349ee2d 100644 --- a/spec/remotes/hyper-schema.json +++ b/spec/remotes/hyper-schema.json @@ -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}" } ] } diff --git a/spec/resolve.spec.js b/spec/resolve.spec.js index 2db8956..1aa0017 100644 --- a/spec/resolve.spec.js +++ b/spec/resolve.spec.js @@ -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#'); }); diff --git a/spec/schema-tests.spec.js b/spec/schema-tests.spec.js index bcca994..e6e5c3a 100644 --- a/spec/schema-tests.spec.js +++ b/spec/schema-tests.spec.js @@ -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'),