pharmacy
Version:
Browser and Node.js library for creating validators and sanitizers
208 lines (181 loc) • 5.64 kB
JavaScript
;
const Pharmacy = require('./pharmacy.js');
module.exports = Store;
/**
* Store is a set of rules and recipes which is an equivalent of a validator.
*
* @param {StoreOptions} options Store options object.
*/
function Store(options) {
options = options || {};
this._rules = {};
this._recipes = {};
this.executeFunctions = options.executeFunctions || true;
if (typeof options.rules === 'object') {
let rules = options.rules;
Object.getOwnPropertyNames(rules).forEach((name) => {
this.addRule(name, rules[name]);
});
}
if (typeof options.recipes === 'object') {
let recipes = options.recipes;
Object.getOwnPropertyNames(recipes).forEach((name) => {
this.addRecipe(name, recipes[name]);
});
}
if (options.hasOwnProperty('field')) {
let field = options.field;
if (typeof field === 'object') {
// Extend Pharmacy.Field with new methods and properties.
let Field = function (options) {
Pharmacy.Field.call(this, options);
};
Object.setPrototypeOf(Field.prototype, Pharmacy.Field.prototype);
Object.getOwnPropertyNames(field).forEach(name => {
Field.prototype[name] = field[name];
});
this.Field = Field;
} else if (typeof field === 'function') {
this.Field = field;
}
} else {
this.Field = Pharmacy.Field;
}
}
/**
* Add rule to list of supported rules. Beacuse of stores can has different
* rules like JsonSchema or mongo query sanitizers they should be filled with
* rules before use.
*
* @param {string} name Rule name.
* @param {PharmacyRule|object} rule Rule descriptor object or an instance.
*/
Store.prototype.addRule = function (name, rule) {
this._rules[name] = Pharmacy.Rule.to(rule);
};
/**
* Get rule by name.
*
* @param {string} name Rule name.
* @return {Pharmacy.Rule}
* @throws {Error} Throws an Error if rule not found.
*/
Store.prototype.getRule = function (name) {
if (! this.hasRule(name)) {
throw new Error('Rule "' + name + '" not found');
}
return this._rules[name];
};
/**
* Check if rule is exists in a library and returns it.
*
* @param {string} name Rule name.
* @return {Pharmacy.Rule|undefined} Rule instance or undefined.
*/
Store.prototype.findRule = function (name) {
if (! this.hasRule(name)) {
return;
}
return this._rules[name];
};
/**
* Check if rule is exists in store rules library.
*
* @param {string} name Rule name.
* @return {Boolean}
*/
Store.prototype.hasRule = function (name) {
return this._rules.hasOwnProperty(name);
};
/**
* Add pharmacy recipe to store.
*
* @param {string} name Recipe name.
* @param {Pharmacy.Recipe|object} recipe Pharmacy recipe instance or object.
* If object is passed then it will be
* converted into recipe.
*/
Store.prototype.addRecipe = function (name, recipe) {
this._recipes[name] = Pharmacy.Recipe.to(recipe);
};
/**
* Get recipe from store library.
*
* @param {string} name Recipe name.
* @return {Pharmacy.Recipe} Pharmacy recipe.
* @throws {Error} Throws an error when recipe not found.
*/
Store.prototype.getRecipe = function (name) {
if (! this.hasRecipe(name)) {
throw new Error('Recipe "' + name + '" not found.');
}
return this._recipes[name];
};
/**
* Find recipe if it exists.
*
* @param {string} name Recipe name.
* @return {Pharmacy.Recipe|undefined} Return recipe if it exists and undefined
* in other cases.
*/
Store.prototype.findRecipe = function (name) {
if (! this.hasRecipe(name)) {
return;
}
return this._recipes[name];
};
/**
* Check if recipe is exists in store recipes library.
*
* @param {name} name Recipe name.
* @return {Boolean}
*/
Store.prototype.hasRecipe = function (name) {
return this._recipes.hasOwnProperty(name);
};
/**
* Validate value with recipe. Result promise retur validation report and fails
* only if there is some extra error occurs while validation process.
*
* @param {*} value Value data.
* @param {Pharmacy.Recipe|string|object} recipe Recipe to validate value.
* @param {object} options Validation options like initial path.
* @return {Promise} Return a promise.
*/
Store.prototype.validate = function (value, recipe, options) {
if (typeof recipe === 'object' && recipe !== null) {
recipe = Pharmacy.Recipe.to(recipe);
} else if (typeof recipe === 'string') {
recipe = this.getRecipe(recipe);
} else {
throw new Error('Recipe should be an object or a string');
}
var opts = Object.assign({
path: null,
}, options);
var field = new this.Field({
path: opts.path,
value: value,
recipe: recipe,
store: this
});
return field.validate();
};
/**
* Sanitizer returns sanitized data and fails if validation failed.
*
* @param {*} value Value to sanitize.
* @param {Pharmacy.Recipe|string|object} recipe Pharmacy recipe, store's
* recipe name or recipe
* descriptor.
* @return {Promise}
*/
Store.prototype.sanitize = function (value, recipe) {
return this.validate(value, recipe).then(function (report) {
if (report.isValid()) {
return report.value;
} else {
throw new Pharmacy.Error('Data validation failed');
}
});
};