if( !_.isArray(pn) ) {
pn = [''+pn]
}
var all = []
_.each(pn, function(n){
if( n.match( /[*?]/ ) ) {
all = all.concat( _.keys(gex(n).on(ctxt.point)) )
}
else all.push(n);
})
return all
}
function truefn(){return true}
function falsefn(){return false}
function noval(v){return _.isUndefined(v)||_.isNull(v)}
var valrule = function( pass ) {
return function(ctxt,cb) {
var v = ctxt.point
var p = ctxt.rule.spec
if( !_.isUndefined(v) ) {
if( !pass(v, p) ) {
return ctxt.util.fail(ctxt,cb)
}
}
return cb();
}
}
var rulemap = {
atmostone$: quantrule( function(f){return f<=1}, 'atmostone$'),
exactlyone$: quantrule( function(f){return 1==f}, 'exactlyone$'),
atleastone$: quantrule( function(f){return 1<=f}, 'atleastone$'),
required$: childrule( function(ctxt,p,v){return !_.isUndefined(v)}, falsefn, 'required$' ),
notempty$: childrule(
function(ctxt,p,v){
return !_.isUndefined(v) && !_.isNull(v) && '' !== v
},
truefn,
'notempty$'
),
string$: childrule( function(ctxt,p,v){return noval(v) || _.isString(v)}, truefn, 'string$' ),
integer$: childrule( function(ctxt,p,v){return noval(v) || _.isNumber(v) && v===(v|0)}, truefn, 'integer$' ),
number$: childrule( function(ctxt,p,v){return noval(v) || _.isNumber(v)}, truefn, 'number$' ),
boolean$: childrule( function(ctxt,p,v){return noval(v) || _.isBoolean(v)}, truefn, 'boolean$' ),
date$: childrule( function(ctxt,p,v){return noval(v) || _.isDate(v)}, truefn, 'date$' ),
array$: childrule( function(ctxt,p,v){return noval(v) || _.isArray(v)}, truefn, 'array$' ),
object$: childrule( function(ctxt,p,v){return noval(v) || _.isObject(v) && !_.isArray(v)}, truefn, 'object$' ),
function$: childrule( function(ctxt,p,v){return noval(v) || _.isFunction(v)}, truefn, 'function$' ),
lt$: valrule( function(p,v){return p < v} ),
lte$: valrule( function(p,v){return p <= v} ),
gt$: valrule( function(p,v){return p > v} ),
gte$: valrule( function(p,v){return p >= v} ),
min$: valrule( function(p,v){return p >= v}),
max$: valrule( function(p,v){return p <= v}),
uniq$: function(ctxt,cb){
var value = ctxt.point
var o = {}
for( var i=0; i<value.length;i++ ) {
if(_.has(o, value[i])){
return ctxt.util.fail(ctxt,cb)
} else {
o[value[i]]= 1
}
}
return cb()
},
only$: function(ctxt,cb) {
var pn = ctxt.util.proplist(ctxt)
for( var p in ctxt.point ) {
if( !_.include(pn,p) ) {
ctxt.prop = p
return ctxt.util.fail(ctxt,cb)
}
}
return cb();
},
wild$: function(ctxt,cb) {
var value = ctxt.point
if( !_.isUndefined(value) ) {
if( !gex(ctxt.rule.spec).on(value) ) {
return ctxt.util.fail(ctxt,cb)
}
}
return cb();
},
eq$: function(ctxt,cb) {
var value = ctxt.point
if( !_.isUndefined(value) ) {
if( ctxt.rule.spec !== value ) {
return ctxt.util.fail(ctxt,cb)
}
}
return cb();
},
minlen$: lenrule( function(valuelen, conditionlen){return valuelen >= conditionlen} ),
maxlen$: lenrule( function(valuelen, conditionlen){return valuelen <= conditionlen} ),
re$: function(ctxt,cb) {
var value = ctxt.point
if( !_.isUndefined(value) ) {
value = ''+value
var redef = ctxt.rule.spec
var reopt = void(0)
var m = /^\/(.*)\/(\w*)$/.exec(ctxt.rule.spec)
if( m ) {
redef = m[1]
reopt = m[2]
}
var re = new RegExp(redef,reopt)
if( !re.exec(value) ) {
return ctxt.util.fail(ctxt,cb)
}
}
return cb();
},
type$: function(ctxt,cb) {
var pn = ctxt.util.proplist(ctxt)
var checkmap = {
string:_.isString,
number:_.isNumber,
integer:function(v){return _.isNumber(v) && v===(v|0)},
boolean:_.isBoolean,
date:_.isDate,
array:_.isArray,
object:function(v){return _.isObject(v) && !_.isArray(v) && !_.isDate(v)},
'function':function(v){return _.isFunction(v)}
}
var found = 0;
_.each(pn, function(p){
var check = checkmap[p.toLowerCase()]
if( check ) {
found += check(ctxt.point)
}
})
if( !found ) {
return ctxt.util.fail(ctxt,cb)
}
return cb();
},
format$: function(ctxt,cb) {
var pn = ctxt.util.proplist(ctxt)
var checkmap = {
datetime: function checkFormatRegex(v) { return /\d{4}-(0[1-9]|1[1-2])-([0-2]\d|3[0-1])T([0-1]\d|2[0-4]):[0-5]\d:[0-5]\dZ/.test(v) },
date: function checkFormatRegex(v) { return /\d{4}-[0-1][0-2]-[0-2]\d/.test(v) },
time: function checkFormatRegex(v) { return /([0-1]\d|2[0-4]):[0-5]\d:[0-5]\dZ/.test(v) },
utcmillisec: _.isNumber,
re: _.isRegExp
}
var found = 0;
_.each(pn, function(p){
var check = checkmap[p.toLowerCase()]
if( check ) {
found += check(ctxt.point)
}
})
if( !found ) {
return ctxt.util.fail(ctxt,cb)
}
return cb();
},
default$: function(ctxt,cb) {
return cb();
},
enum$: function(ctxt,cb) {
var value = ctxt.point
var okvals = ctxt.rule.spec
var avalue = []
if ( _.isArray(value) ) {
avalue = value
}
else {
avalue[0] = value
}
var iserror = 0
if( avalue ) {
_.each(avalue, function(p){
iserror += (-1 == okvals.indexOf(p) )
})
}
if ( iserror ){
return ctxt.util.fail(ctxt,cb)
}
return cb();
},