feat: async loading of meta-schema, #334

master
Evgeny Poberezkin 2016-11-08 00:49:29 +00:00
parent f95b83d890
commit 84b0531e39
2 changed files with 37 additions and 11 deletions

View File

@ -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.
* @this Ajv
* @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.
* @return {Promise} promise that resolves with a validating function.
*/
function compileAsync(schema, callback) {
function compileAsync(schema, meta, callback) {
/* eslint no-shadow: 0 */
/* global Promise */
/* jshint validthis: true */
var schemaObj;
var self = this;
if (typeof this._opts.loadSchema != 'function')
throw new Error('options.loadSchema should be a function');
var p = Promise.resolve().then(function () {
schemaObj = self._addSchema(schema);
if (typeof meta == 'function') {
callback = meta;
meta = undefined;
}
var p = loadMetaSchemaOf(schema).then(function () {
var schemaObj = self._addSchema(schema, undefined, meta);
return schemaObj.validate || _compileAsync(schemaObj);
});
@ -35,6 +40,14 @@ function compileAsync(schema, callback) {
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) {
try { return self._compile(schemaObj); }
catch(e) {
@ -54,7 +67,12 @@ function compileAsync(schema, callback) {
}
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);
});

View File

@ -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() {
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', {
type: 'string',
validate: function (sch, data) {
@ -188,12 +195,12 @@ describe('compileAsync method', function() {
});
return ajv.compileAsync(schema).then(function (validate) {
should.equal(loadCallCount, 2);
should.equal(loadCallCount, expectedLoadCallCount);
validate .should.be.a('function');
validate('foo') .should.equal(true);
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)
];
]);
function spec(validate) {
should.equal(loadCallCount, 2);
validate .should.be.a('function');
validate({ a: { b: 2 } }) .should.equal(true);
validate({ a: { b: 1 } }) .should.equal(false);