From 0f1bec435f7dbcd37a879de0e444ed3bf55c7b35 Mon Sep 17 00:00:00 2001 From: piebev Date: Fri, 4 Jul 2014 10:45:01 +0200 Subject: [PATCH] - improved error messages - fixed regular expression in key validation (bug in original js-schema) --- js-schema.debug.js | 41 ++++++++++++++++++++++----------------- js-schema.min.js | 2 +- lib/extensions/Array.js | 2 +- lib/extensions/Boolean.js | 2 +- lib/extensions/Number.js | 2 +- lib/patterns/nothing.js | 2 +- lib/patterns/object.js | 27 +++++++++++++++----------- lib/patterns/or.js | 4 ++-- lib/patterns/regexp.js | 2 +- 9 files changed, 47 insertions(+), 37 deletions(-) diff --git a/js-schema.debug.js b/js-schema.debug.js index 60129f5..6e5685f 100644 --- a/js-schema.debug.js +++ b/js-schema.debug.js @@ -173,7 +173,7 @@ var ArraySchema = module.exports = Schema.extensions.ArraySchema = Schema.extend try { this.itemSchema.validate(instance[i]) } catch(e) { - throw new Error('array contains invalid entry at ' + i + ' --> ' + e) + throw new Error('array contains invalid entry at ' + i + ' --> ' + e.message) } } @@ -224,7 +224,7 @@ var Schema = _dereq_('../BaseSchema') var BooleanSchema = module.exports = Schema.extensions.BooleanSchema = new Schema.extend({ validate : function(instance) { - if (!Object(instance) instanceof Boolean) + if (! (Object(instance) instanceof Boolean)) throw new Error('not a Boolean') return true @@ -302,7 +302,7 @@ var NumberSchema = module.exports = Schema.extensions.NumberSchema = Schema.exte publicFunctions : [ 'min', 'above', 'max', 'below', 'step' ], validate : function(instance) { - if (! Object(instance) instanceof Number) + if (! (Object(instance) instanceof Number)) throw new Error('not a Number') if (!(this.exclusiveMinimum ? instance > this.minimum : instance >= this.minimum)) @@ -574,7 +574,7 @@ var Schema = _dereq_('../BaseSchema') var NothingSchema = module.exports = Schema.patterns.NothingSchema = Schema.extend({ validate : function(instance) { if (instance != null) - throw new Error('must be null') + throw new Error('must be null or not present') return true }, @@ -623,15 +623,20 @@ var ObjectSchema = module.exports = Schema.patterns.ObjectSchema = Schema.extend // Simple string properties Object.keys(this.stringProps).every(function(key) { - if (self.stringProps[key].min === 0 && !(key in instance)) { - return true; + if (!(key in instance)) { + if (self.stringProps[key].min === 0 ) { + return true; + } else { + throw new Error('Key "' + key + '" must be present') + } } try { self.stringProps[key].value.validate(instance[key]) } catch(e) { - throw new Error('Parse error for key "' + key + '" --> ' + e); + throw new Error('invalid key "' + key + '" --> ' + e.message); } + return true }) // If there are no RegExp and other validator, that's all @@ -639,28 +644,28 @@ var ObjectSchema = module.exports = Schema.patterns.ObjectSchema = Schema.extend // Regexp and other properties var checked - for (var key in instance) { + for (var instancekey in instance) { // Checking the key against every key regexps checked = false Object.keys(this.regexpProps).every(function(key) { - if (!self.regexpProps[key].key.test(key)) return true + if (!self.regexpProps[key].key.test(instancekey)) return true checked = true try { - self.regexpProps[key].value.validate(instance[key]) + self.regexpProps[key].value.validate(instance[instancekey]) } catch(e) { - throw new Error('lala'); - // throw new Error('Parse error for regexp in key "' + key + '" --> ' + e); + throw new Error('no match regexp in key "' + instancekey + '" --> ' + e.message); } + return true }) // If the key is not matched by regexps and by simple string checks // then check it against this.other - if (!checked && !(key in this.stringProps)) { + if (!checked && !(instancekey in this.stringProps)) { try { - this.other.validate(instance[key]) + this.other.validate(instance[instancekey]) } catch(e) { - throw new Error('Parse error for key "' + key + '" --> ' + e); + throw new Error('invalid key "' + instancekey + '" --> ' + e.message); } } } @@ -821,7 +826,7 @@ var OrSchema = module.exports = Schema.patterns.OrSchema = Schema.extend({ try { sch.validate(instance) } catch (e) { - error += e + error += e.message return false } return true; @@ -829,7 +834,7 @@ var OrSchema = module.exports = Schema.patterns.OrSchema = Schema.extend({ throw new Error('All following conditions are false: ' + error); } - return true;; + return true; }, toJSON : Schema.session(function() { @@ -917,7 +922,7 @@ var RegexpSchema = module.exports = Schema.patterns.RegexpSchema = Schema.extend }, validate : function(instance) { - if (! Object(instance) instanceof String) { + if (! (Object(instance) instanceof String)) { throw new Error('not a String') } if (this.regexp && !this.regexp.test(instance)) diff --git a/js-schema.min.js b/js-schema.min.js index 2f36c9d..2367a8a 100644 --- a/js-schema.min.js +++ b/js-schema.min.js @@ -1 +1 @@ -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.schema=e()}}(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o0&&instance.lengththis.max)throw new Error("array does contain too many entries ("+instance.length+" instead of "+this.min)}for(var i=0;i "+e)}}return true},toJSON:Schema.session(function(){var json=Schema.prototype.toJSON.call(this,true);if(json["$ref"]!=null)return json;json.type="array";if(this.min>0)json.minItems=this.min;if(this.maxthis.minimum:instance>=this.minimum))throw new Error(instance+" does not exceed minimum "+this.minimum);if(!(this.exclusiveMaximum?instance2?args[2]:args[1],regexp="^"+charset+"{"+(min||0)+","+(max||"")+"}$";return new RegexpSchema(RegExp(regexp)).wrap()};String.schema=(new RegexpSchema).wrap()},{"../patterns/regexp":17}],10:[function(_dereq_,module,exports){var Schema=_dereq_("../BaseSchema");var AnythingSchema=module.exports=Schema.patterns.AnythingSchema=Schema.extend({validate:function(instance){if(instance==null)throw new Error("may not be null");return true},toJSON:function(){return{type:"any"}}});var anything=AnythingSchema.instance=new AnythingSchema;Schema.fromJS.def(function(sch){if(sch===undefined)return anything});Schema.fromJSON.def(function(sch){if(sch.type==="any")return anything})},{"../BaseSchema":2}],11:[function(_dereq_,module,exports){var Schema=_dereq_("../BaseSchema");var ClassSchema=module.exports=Schema.patterns.ClassSchema=Schema.extend({initialize:function(constructor){this.constructor=constructor},validate:function(instance){if(!(instance instanceof this.constructor))throw new Error("not a class constructor");return true}});Schema.fromJS.def(function(constructor){if(!(constructor instanceof Function))return;if(constructor.schema instanceof Function){return constructor.schema.unwrap()}else{return new ClassSchema(constructor)}})},{"../BaseSchema":2}],12:[function(_dereq_,module,exports){var Schema=_dereq_("../BaseSchema");var equal=function(a,b){if(Object(a)!==a||Object(b)!==b)return a===b;if(a instanceof Array!==b instanceof Array)return false;if(Object.keys(a).length!==Object.keys(b).length)return false;for(var key in a){if(!equal(a[key],b[key]))return false}return true};var EqualitySchema=module.exports=Schema.patterns.EqualitySchema=Schema.extend({initialize:function(object){this.object=object},validate:function(instance){if(!equal(instance,this.object))throw new Error(instance+" not equal to "+this.object.toString());return true},toJSON:function(){var json=Schema.prototype.toJSON.call(this);json["enum"]=[this.object];return json}});Schema.fromJS.def(function(sch){if(sch instanceof Array&&sch.length===1)return new EqualitySchema(sch[0])})},{"../BaseSchema":2}],13:[function(_dereq_,module,exports){var Schema=_dereq_("../BaseSchema");var NothingSchema=module.exports=Schema.patterns.NothingSchema=Schema.extend({validate:function(instance){if(instance!=null)throw new Error("must be null");return true},toJSON:function(){return{type:"null"}}});var nothing=NothingSchema.instance=new NothingSchema;Schema.fromJS.def(function(sch){if(sch===null)return nothing});Schema.fromJSON.def(function(sch){if(sch.type==="null")return nothing})},{"../BaseSchema":2}],14:[function(_dereq_,module,exports){var Schema=_dereq_("../BaseSchema"),anything=_dereq_("./anything").instance,nothing=_dereq_("./nothing").instance;var ObjectSchema=module.exports=Schema.patterns.ObjectSchema=Schema.extend({initialize:function(properties,other){var self=this;this.other=other||anything;this.properties=properties||[];this.stringProps={},this.regexpProps=[];this.properties.forEach(function(property){if(typeof property.key==="string"){self.stringProps[property.key]=property}else{self.regexpProps.push(property)}})},validate:function(instance){var self=this;if(instance==null)throw new Error("No data");Object.keys(this.stringProps).every(function(key){if(self.stringProps[key].min===0&&!(key in instance)){return true}try{self.stringProps[key].value.validate(instance[key])}catch(e){throw new Error('Parse error for key "'+key+'" --> '+e)}});if(!this.regexpProps.length&&this.other===anything)return true;var checked;for(var key in instance){checked=false;Object.keys(this.regexpProps).every(function(key){if(!self.regexpProps[key].key.test(key))return true;checked=true;try{self.regexpProps[key].value.validate(instance[key])}catch(e){throw new Error("lala")}});if(!checked&&!(key in this.stringProps)){try{this.other.validate(instance[key])}catch(e){throw new Error('Parse error for key "'+key+'" --> '+e)}}}return true},toJSON:Schema.session(function(){var i,property,regexp,json=Schema.prototype.toJSON.call(this,true);if(json["$ref"]!=null)return json;json.type="object";for(i in this.stringProps){property=this.stringProps[i];json.properties=json.properties||{};json.properties[property.key]=property.value.toJSON();if(property.min===1)json.properties[property.key].required=true;if(property.title)json.properties[property.key].title=property.title}for(i=0;i0&&instance.lengththis.max)throw new Error("array does contain too many entries ("+instance.length+" instead of "+this.min)}for(var i=0;i "+e.message)}}return true},toJSON:Schema.session(function(){var json=Schema.prototype.toJSON.call(this,true);if(json["$ref"]!=null)return json;json.type="array";if(this.min>0)json.minItems=this.min;if(this.maxthis.minimum:instance>=this.minimum))throw new Error(instance+" does not exceed minimum "+this.minimum);if(!(this.exclusiveMaximum?instance2?args[2]:args[1],regexp="^"+charset+"{"+(min||0)+","+(max||"")+"}$";return new RegexpSchema(RegExp(regexp)).wrap()};String.schema=(new RegexpSchema).wrap()},{"../patterns/regexp":17}],10:[function(_dereq_,module,exports){var Schema=_dereq_("../BaseSchema");var AnythingSchema=module.exports=Schema.patterns.AnythingSchema=Schema.extend({validate:function(instance){if(instance==null)throw new Error("may not be null");return true},toJSON:function(){return{type:"any"}}});var anything=AnythingSchema.instance=new AnythingSchema;Schema.fromJS.def(function(sch){if(sch===undefined)return anything});Schema.fromJSON.def(function(sch){if(sch.type==="any")return anything})},{"../BaseSchema":2}],11:[function(_dereq_,module,exports){var Schema=_dereq_("../BaseSchema");var ClassSchema=module.exports=Schema.patterns.ClassSchema=Schema.extend({initialize:function(constructor){this.constructor=constructor},validate:function(instance){if(!(instance instanceof this.constructor))throw new Error("not a class constructor");return true}});Schema.fromJS.def(function(constructor){if(!(constructor instanceof Function))return;if(constructor.schema instanceof Function){return constructor.schema.unwrap()}else{return new ClassSchema(constructor)}})},{"../BaseSchema":2}],12:[function(_dereq_,module,exports){var Schema=_dereq_("../BaseSchema");var equal=function(a,b){if(Object(a)!==a||Object(b)!==b)return a===b;if(a instanceof Array!==b instanceof Array)return false;if(Object.keys(a).length!==Object.keys(b).length)return false;for(var key in a){if(!equal(a[key],b[key]))return false}return true};var EqualitySchema=module.exports=Schema.patterns.EqualitySchema=Schema.extend({initialize:function(object){this.object=object},validate:function(instance){if(!equal(instance,this.object))throw new Error(instance+" not equal to "+this.object.toString());return true},toJSON:function(){var json=Schema.prototype.toJSON.call(this);json["enum"]=[this.object];return json}});Schema.fromJS.def(function(sch){if(sch instanceof Array&&sch.length===1)return new EqualitySchema(sch[0])})},{"../BaseSchema":2}],13:[function(_dereq_,module,exports){var Schema=_dereq_("../BaseSchema");var NothingSchema=module.exports=Schema.patterns.NothingSchema=Schema.extend({validate:function(instance){if(instance!=null)throw new Error("must be null or not present");return true},toJSON:function(){return{type:"null"}}});var nothing=NothingSchema.instance=new NothingSchema;Schema.fromJS.def(function(sch){if(sch===null)return nothing});Schema.fromJSON.def(function(sch){if(sch.type==="null")return nothing})},{"../BaseSchema":2}],14:[function(_dereq_,module,exports){var Schema=_dereq_("../BaseSchema"),anything=_dereq_("./anything").instance,nothing=_dereq_("./nothing").instance;var ObjectSchema=module.exports=Schema.patterns.ObjectSchema=Schema.extend({initialize:function(properties,other){var self=this;this.other=other||anything;this.properties=properties||[];this.stringProps={},this.regexpProps=[];this.properties.forEach(function(property){if(typeof property.key==="string"){self.stringProps[property.key]=property}else{self.regexpProps.push(property)}})},validate:function(instance){var self=this;if(instance==null)throw new Error("No data");Object.keys(this.stringProps).every(function(key){if(!(key in instance)){if(self.stringProps[key].min===0){return true}else{throw new Error('Key "'+key+'" must be present')}}try{self.stringProps[key].value.validate(instance[key])}catch(e){throw new Error('invalid key "'+key+'" --> '+e.message)}return true});if(!this.regexpProps.length&&this.other===anything)return true;var checked;for(var instancekey in instance){checked=false;Object.keys(this.regexpProps).every(function(key){if(!self.regexpProps[key].key.test(instancekey))return true;checked=true;try{self.regexpProps[key].value.validate(instance[instancekey])}catch(e){throw new Error('no match regexp in key "'+instancekey+'" --> '+e.message)}return true});if(!checked&&!(instancekey in this.stringProps)){try{this.other.validate(instance[instancekey])}catch(e){throw new Error('invalid key "'+instancekey+'" --> '+e.message)}}}return true},toJSON:Schema.session(function(){var i,property,regexp,json=Schema.prototype.toJSON.call(this,true);if(json["$ref"]!=null)return json;json.type="object";for(i in this.stringProps){property=this.stringProps[i];json.properties=json.properties||{};json.properties[property.key]=property.value.toJSON();if(property.min===1)json.properties[property.key].required=true;if(property.title)json.properties[property.key].title=property.title}for(i=0;i ' + e) + throw new Error('array contains invalid entry at ' + i + ' --> ' + e.message) } } diff --git a/lib/extensions/Boolean.js b/lib/extensions/Boolean.js index aa669d0..efceea3 100644 --- a/lib/extensions/Boolean.js +++ b/lib/extensions/Boolean.js @@ -2,7 +2,7 @@ var Schema = require('../BaseSchema') var BooleanSchema = module.exports = Schema.extensions.BooleanSchema = new Schema.extend({ validate : function(instance) { - if (!Object(instance) instanceof Boolean) + if (! (Object(instance) instanceof Boolean)) throw new Error('not a Boolean') return true diff --git a/lib/extensions/Number.js b/lib/extensions/Number.js index bc75679..09c7e4c 100644 --- a/lib/extensions/Number.js +++ b/lib/extensions/Number.js @@ -47,7 +47,7 @@ var NumberSchema = module.exports = Schema.extensions.NumberSchema = Schema.exte publicFunctions : [ 'min', 'above', 'max', 'below', 'step' ], validate : function(instance) { - if (! Object(instance) instanceof Number) + if (! (Object(instance) instanceof Number)) throw new Error('not a Number') if (!(this.exclusiveMinimum ? instance > this.minimum : instance >= this.minimum)) diff --git a/lib/patterns/nothing.js b/lib/patterns/nothing.js index 79f88a4..dc42fc3 100644 --- a/lib/patterns/nothing.js +++ b/lib/patterns/nothing.js @@ -3,7 +3,7 @@ var Schema = require('../BaseSchema') var NothingSchema = module.exports = Schema.patterns.NothingSchema = Schema.extend({ validate : function(instance) { if (instance != null) - throw new Error('must be null') + throw new Error('must be null or not present') return true }, diff --git a/lib/patterns/object.js b/lib/patterns/object.js index 98d82cd..a47e522 100644 --- a/lib/patterns/object.js +++ b/lib/patterns/object.js @@ -27,15 +27,20 @@ var ObjectSchema = module.exports = Schema.patterns.ObjectSchema = Schema.extend // Simple string properties Object.keys(this.stringProps).every(function(key) { - if (self.stringProps[key].min === 0 && !(key in instance)) { - return true; + if (!(key in instance)) { + if (self.stringProps[key].min === 0 ) { + return true; + } else { + throw new Error('Key "' + key + '" must be present') + } } try { self.stringProps[key].value.validate(instance[key]) } catch(e) { - throw new Error('Parse error for key "' + key + '" --> ' + e); + throw new Error('invalid key "' + key + '" --> ' + e.message); } + return true }) // If there are no RegExp and other validator, that's all @@ -43,28 +48,28 @@ var ObjectSchema = module.exports = Schema.patterns.ObjectSchema = Schema.extend // Regexp and other properties var checked - for (var key in instance) { + for (var instancekey in instance) { // Checking the key against every key regexps checked = false Object.keys(this.regexpProps).every(function(key) { - if (!self.regexpProps[key].key.test(key)) return true + if (!self.regexpProps[key].key.test(instancekey)) return true checked = true try { - self.regexpProps[key].value.validate(instance[key]) + self.regexpProps[key].value.validate(instance[instancekey]) } catch(e) { - throw new Error('lala'); - // throw new Error('Parse error for regexp in key "' + key + '" --> ' + e); + throw new Error('no match regexp in key "' + instancekey + '" --> ' + e.message); } + return true }) // If the key is not matched by regexps and by simple string checks // then check it against this.other - if (!checked && !(key in this.stringProps)) { + if (!checked && !(instancekey in this.stringProps)) { try { - this.other.validate(instance[key]) + this.other.validate(instance[instancekey]) } catch(e) { - throw new Error('Parse error for key "' + key + '" --> ' + e); + throw new Error('invalid key "' + instancekey + '" --> ' + e.message); } } } diff --git a/lib/patterns/or.js b/lib/patterns/or.js index 5fdf76f..932af03 100644 --- a/lib/patterns/or.js +++ b/lib/patterns/or.js @@ -12,7 +12,7 @@ var OrSchema = module.exports = Schema.patterns.OrSchema = Schema.extend({ try { sch.validate(instance) } catch (e) { - error += e + error += e.message return false } return true; @@ -20,7 +20,7 @@ var OrSchema = module.exports = Schema.patterns.OrSchema = Schema.extend({ throw new Error('All following conditions are false: ' + error); } - return true;; + return true; }, toJSON : Schema.session(function() { diff --git a/lib/patterns/regexp.js b/lib/patterns/regexp.js index 840f887..9acf215 100644 --- a/lib/patterns/regexp.js +++ b/lib/patterns/regexp.js @@ -6,7 +6,7 @@ var RegexpSchema = module.exports = Schema.patterns.RegexpSchema = Schema.extend }, validate : function(instance) { - if (! Object(instance) instanceof String) { + if (! (Object(instance) instanceof String)) { throw new Error('not a String') } if (this.regexp && !this.regexp.test(instance))