feat: async loading of meta-schema, #334
parent
f95b83d890
commit
84b0531e39
|
@ -8,20 +8,25 @@ module.exports = compileAsync;
|
||||||
* `loadSchema` option should be a function that accepts schema uri and returns promise that resolves with the schema.
|
* `loadSchema` option should be a function that accepts schema uri and returns promise that resolves with the schema.
|
||||||
* @this Ajv
|
* @this Ajv
|
||||||
* @param {Object} schema schema object
|
* @param {Object} schema schema object
|
||||||
|
* @param {Boolean} meta optional true to compile meta-schema; this parameter can be skipped
|
||||||
* @param {Function} callback an optional node-style callback, it is called with 2 parameters: error (or null) and validating function.
|
* @param {Function} callback an optional node-style callback, it is called with 2 parameters: error (or null) and validating function.
|
||||||
* @return {Promise} promise that resolves with a validating function.
|
* @return {Promise} promise that resolves with a validating function.
|
||||||
*/
|
*/
|
||||||
function compileAsync(schema, callback) {
|
function compileAsync(schema, meta, callback) {
|
||||||
/* eslint no-shadow: 0 */
|
/* eslint no-shadow: 0 */
|
||||||
/* global Promise */
|
/* global Promise */
|
||||||
/* jshint validthis: true */
|
/* jshint validthis: true */
|
||||||
var schemaObj;
|
|
||||||
var self = this;
|
var self = this;
|
||||||
if (typeof this._opts.loadSchema != 'function')
|
if (typeof this._opts.loadSchema != 'function')
|
||||||
throw new Error('options.loadSchema should be a function');
|
throw new Error('options.loadSchema should be a function');
|
||||||
|
|
||||||
var p = Promise.resolve().then(function () {
|
if (typeof meta == 'function') {
|
||||||
schemaObj = self._addSchema(schema);
|
callback = meta;
|
||||||
|
meta = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
var p = loadMetaSchemaOf(schema).then(function () {
|
||||||
|
var schemaObj = self._addSchema(schema, undefined, meta);
|
||||||
return schemaObj.validate || _compileAsync(schemaObj);
|
return schemaObj.validate || _compileAsync(schemaObj);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -35,6 +40,14 @@ function compileAsync(schema, callback) {
|
||||||
return p;
|
return p;
|
||||||
|
|
||||||
|
|
||||||
|
function loadMetaSchemaOf(sch) {
|
||||||
|
var $schema = sch.$schema;
|
||||||
|
return $schema && !self.getSchema($schema)
|
||||||
|
? compileAsync.call(self, { $ref: $schema }, true)
|
||||||
|
: Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function _compileAsync(schemaObj) {
|
function _compileAsync(schemaObj) {
|
||||||
try { return self._compile(schemaObj); }
|
try { return self._compile(schemaObj); }
|
||||||
catch(e) {
|
catch(e) {
|
||||||
|
@ -54,7 +67,12 @@ function compileAsync(schema, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return schemaPromise.then(function (sch) {
|
return schemaPromise.then(function (sch) {
|
||||||
if (!added(ref)) self.addSchema(sch, ref);
|
if (!added(ref)) {
|
||||||
|
return loadMetaSchemaOf(sch).then(function () {
|
||||||
|
if (!added(ref)) self.addSchema(sch, ref, undefined, meta);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).then(function() {
|
||||||
return _compileAsync(schemaObj);
|
return _compileAsync(schemaObj);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -177,9 +177,16 @@ describe('compileAsync method', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe.skip('loading metaschemas (#334)', function() {
|
describe('loading metaschemas (#334)', function() {
|
||||||
it('should load metaschema if not available', function() {
|
it('should load metaschema if not available', function() {
|
||||||
var schema = { "$ref": "http://example.com/foobar.json" };
|
return test(SCHEMAS['http://example.com/foobar.json'], 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load metaschema of referenced schema if not available', function() {
|
||||||
|
return test({ "$ref": "http://example.com/foobar.json" }, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
function test(schema, expectedLoadCallCount) {
|
||||||
ajv.addKeyword('myFooBar', {
|
ajv.addKeyword('myFooBar', {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
validate: function (sch, data) {
|
validate: function (sch, data) {
|
||||||
|
@ -188,12 +195,12 @@ describe('compileAsync method', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
return ajv.compileAsync(schema).then(function (validate) {
|
return ajv.compileAsync(schema).then(function (validate) {
|
||||||
should.equal(loadCallCount, 2);
|
should.equal(loadCallCount, expectedLoadCallCount);
|
||||||
validate .should.be.a('function');
|
validate .should.be.a('function');
|
||||||
validate('foo') .should.equal(true);
|
validate('foo') .should.equal(true);
|
||||||
validate('bar') .should.equal(false);
|
validate('bar') .should.equal(false);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -237,13 +244,14 @@ describe('compileAsync method', function() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return Promise.all[
|
return Promise.all([
|
||||||
ajv.compileAsync(schema).then(spec),
|
ajv.compileAsync(schema).then(spec),
|
||||||
ajv.compileAsync(schema).then(spec),
|
ajv.compileAsync(schema).then(spec),
|
||||||
ajv.compileAsync(schema).then(spec)
|
ajv.compileAsync(schema).then(spec)
|
||||||
];
|
]);
|
||||||
|
|
||||||
function spec(validate) {
|
function spec(validate) {
|
||||||
|
should.equal(loadCallCount, 2);
|
||||||
validate .should.be.a('function');
|
validate .should.be.a('function');
|
||||||
validate({ a: { b: 2 } }) .should.equal(true);
|
validate({ a: { b: 2 } }) .should.equal(true);
|
||||||
validate({ a: { b: 1 } }) .should.equal(false);
|
validate({ a: { b: 1 } }) .should.equal(false);
|
||||||
|
|
Loading…
Reference in New Issue