121 lines
3.2 KiB
JavaScript
121 lines
3.2 KiB
JavaScript
var _ = require('underscore');
|
|
var rules = require('./rules.js');
|
|
|
|
var Schema = function(schema) {
|
|
this.schema = schema;
|
|
};
|
|
|
|
var checkArray = function(schema, key, errors, values) {
|
|
var valid = true;
|
|
values.forEach(function(value, index) {
|
|
try {
|
|
if(schema.schema.schema) {
|
|
// if array has another schema, then we want objects!
|
|
value = rules.create(key, {type:'object'}).apply(value);
|
|
var results = (new Schema(schema.schema.schema)).validate(value);
|
|
if(!results.valid)
|
|
{
|
|
errors[key] = errors[key] || [];
|
|
errors[key][index] = results.errors;
|
|
} else {
|
|
values[index] = results.data;
|
|
}
|
|
}
|
|
else
|
|
values[index] = rules.create(key + "[" + index + "]", schema.schema).apply(value);
|
|
} catch (error) {
|
|
valid = false;
|
|
if (!_.isArray(errors[key])) errors[key] = [];
|
|
errors[key][index] = error;
|
|
}
|
|
});
|
|
return valid;
|
|
};
|
|
|
|
/*jshint loopfunc:true*/
|
|
Schema.prototype.validate = function(data, opts) {
|
|
var params = _.keys(this.schema);
|
|
var errors = {};
|
|
var values = {};
|
|
var value;
|
|
var get = typeof(data) == "function" ? data : function(p) {
|
|
return data[p];
|
|
};
|
|
|
|
for (var i = 0; i < params.length; i++) {
|
|
var schema = this.schema[params[i]];
|
|
|
|
try {
|
|
// if undefined, don't store it.
|
|
value = rules.create(params[i], schema).apply(get(params[i]));
|
|
|
|
// does this rule contain embedded schemas
|
|
if (typeof(schema.schema) == "object" &&
|
|
!_.isArray(schema.schema) &&
|
|
_.keys(schema.schema).length &&
|
|
!_.isUndefined(value)) {
|
|
|
|
if(schema.allownull && _.isNull(value)) {
|
|
values[params[i]] = null;
|
|
} else {
|
|
if (schema.type == "object") {
|
|
var results = (new Schema(schema.schema)).validate(value);
|
|
if(!results.valid) {
|
|
errors[params[i]] = results.errors;
|
|
} else {
|
|
values[params[i]] = results.data;
|
|
}
|
|
} else if (schema.type == "array") {
|
|
if( checkArray(schema, params[i], errors, value, get)){
|
|
values[params[i]] = value;
|
|
}
|
|
}
|
|
}
|
|
} else if (!_.isUndefined(value)) {
|
|
values[params[i]] = value;
|
|
}
|
|
|
|
} catch (error) {
|
|
errors[params[i]] = error;
|
|
}
|
|
}
|
|
|
|
if(opts && opts.strict) {
|
|
var origKeys = Object.keys(data);
|
|
|
|
var diff = origKeys.filter(function(i) {
|
|
return params.indexOf(i) < 0;
|
|
});
|
|
|
|
diff.forEach(function(field) {
|
|
errors[field] = "Additional key not defined in schema";
|
|
});
|
|
}
|
|
|
|
return {
|
|
data: values,
|
|
errors: errors,
|
|
valid: _.keys(errors).length === 0
|
|
};
|
|
};
|
|
|
|
exports.types = rules.types;
|
|
exports.test = function(value, schema) {
|
|
return (new Schema({
|
|
input: schema
|
|
})).validate({
|
|
input: value
|
|
});
|
|
};
|
|
exports.properties = rules.properties;
|
|
exports.filters = rules.filters;
|
|
exports.create = function(schema) {
|
|
return new Schema(schema);
|
|
};
|
|
exports.middleware = function(schema) {
|
|
return function(req, res, next) {
|
|
req.form = new Schema(schema).validate((req.method || req.route.method || '').toLowerCase() == "post" ? req.body : req.query);
|
|
next();
|
|
};
|
|
};
|