var assign = require('object-assign'); var mschema = require('mschema'); var v = require('validator'); /** * Custom types. * To add a custom type, add a key with the type name and a value * in the form {parent: {...}, assertValid: function(d) {...}} * where parent is the base mschema spec and validate is a function * accepting one data point and throwing an array of errors if invalid. * * Error array format is derived from mschema and is in the form * [{property: x, constraint: x, actual: x, expected: x, message: x} ... ] */ var types = { /** * Larger text inputs. Currently just proxies to string type. */ 'text': { parent: {type: 'string'}, // Let parent handle validation assertValid: function(s) {} } } /** * OKSchema! * Meant as a thin wrapper around some existing schema validation * module, mostly to allow for the extension of types. */ function OKSchema(spec) { if (!(this instanceof OKSchema)) return new OKSchema(spec); if (!spec) throw new Error('No spec provided to OKSchema'); spec = assign({}, spec); // Cache the mschema version of our spec this._mschemaSpec = Object.keys(spec).reduce(function(cache, prop) { // If custom type, return its parent spec var type = spec[prop].type; if (types[type]) { cache[prop] = types[type].parent; // Otherwise, it's already in mschema format } else { cache[prop] = spec[prop]; } return cache; }, {}); Object.defineProperty(this, 'spec', { value: spec, writable: false }); } OKSchema.prototype.assertValid = function(data) { data = data || {}; var spec = this.spec; // Run through custom validators, they'll throw if invalid Object.keys(data).forEach(function(prop) { var type = spec[prop].type; if (types[type]) { types[type].assertValid(data[prop]); } }); var result = mschema.validate(data, this.toMschema()); if (!result.valid) throw result.errors; }; /** * Return our custom spec as an mschema spec */ OKSchema.prototype.toMschema = function() { return this._mschemaSpec; }; module.exports = OKSchema;