occamsrazor-validator
This is an helper library that helps to perform variable validation with a simple syntax.
The main goal of the library is to be used for duck-typing. For this reason:
- It detects what an object is rather than what it is not
- It returns a "score" (or null). The score is based on how many validation pass and gives you an index of how specific is a validation
It is a part of occamsrazor (https://github.com/sithmel/occamsrazor.js) that uses this library for picking the right adapter for a specific set of arguments.
Importing the library
var validator = require('occamsrazor-validator');
What is a validators
Ultimately a validator is a function. When it runs against an object, it returns null or a score.
Null value means that an object doesn't fit in the validator's constraints.
The score represent how well the object fits (its specificity). For example:
var isAnything = validator();
"validator()"" creates the simplest validator. It matches everything with score 1:
isAnything('hello');
isAnything({width: 10});
You can chain a function to create a more strict validation:
var hasWheels = isAnything.match(function (obj){
return 'wheels' in obj;
});
or
var hasWheels = validator().match(function (obj){
return 'wheels' in obj;
});
So for example, the score of this new validator will be 2::
hasWheels({wheels: 4});
hasWheels({feet: 2});
You can go on having a more specific validator:
var hasWheelsAndWings = hasWheels.match(function (obj){
return 'wings' in obj;
});
Every validator has a function "score" that returns its specificity:
isAnything.score()
hasWheels.score()
hasWheelsAndWings.score()
In order to write validators you can use duck typing, type checking or whatever check you want to use:
var has_wings = validator().match(function (obj){
return 'wings' in obj;
});
var is_a_car = validator().match(function (obj){
return Car.prototype.isPrototypeOf(obj);
});
var is_year = validator().match(function (obj){
var re = /[0-9]{4}/;
return !!obj.match(re);
});
The "match" method allows to extend a validator using a terse syntax. You have already seen that it can take a function as argument.
You can also pass a string or a regular expression for matching a string:
var is_hello = validator().match('hello');
var contains_nuts = validator().match(/nut/);
is_hello('hello');
contains_nuts('hazelnut');
Or numbers::
var is_ten = validator().match(10);
is_ten(10);
It works for booleans and null in the same way.
If you pass an array of strings it will match with an object containing all the attributes with those names:
var has_width_and_height = validator().match(['width', 'height']);
Finally you can perform deep property checking using an object and combining the previous checks::
var has_width_and_height_10 = validator().match({width: 10, height: 10});
var has_center = validator().match({center: ['x', 'y']});
var recipe_has_nuts = validator().match({recipe: {ingredients: /nuts/}});
var is_heavy = validator().match({weight: function (obj){return obj > 100}});
There are other 2 helpers available for checking against the prototype or the constructor function::
var is_prototype_rect = validator().isPrototypeOf(rect.prototype);
var is_instance_rect = validator().isInstanceOf(Rect);
If you need a custom validator you can extend the object validator.shortcut_validators::
validator.shortcut_validators.isSquare = function (){
return function (obj){
return 'width' in obj && 'height' in obj && obj.width === obj.height;
};
};
Of course you can combine all the methods we have seen so far::
var is_instance_a_square = validator()
.isInstanceOf(Rect)
.match(['width', 'height'])
.isSquare();
Syntax
Validator function
Syntax:
validator();
Returns a generic validator. It will validate every object with score 1.
validator().score
Syntax:
a_validator.score();
Returns the score returned by this validator. It can be useful for debugging or introspection.
validator().important
Syntax:
a_validator.important([n]);
It bumps the score by n (default to 64).
validator().match
Add a check to the validator, it uses a special syntax (used by default by .add, .one).
Syntax:
var validator = validator().match(function);
var validator = validator().match(string);
var validator = validator().match(null);
var validator = validator().match(boolean);
var validator = validator().match(regular_expression);
var validator = validator().match([array of property names]);
var validator = validator().match({propName1: "string", propName2: {propName3: "string"}});
This last form allows to perform the validation check recursively, walking the properties of the object.
In a property is undefined the value will match any value.
For example:
var hasCenterX = validator().match({center: {x: undefined}});
var hasCenterX10 = validator().match({center: {x: "10"}});
var hasCenter5or10 = validator().match({center: {x : function (c){
return c === "5" || c === "10";
}}});
validator().isPrototypeOf
Check if an object is a prototype of another.
Syntax:
var validator = validator().isPrototypeOf(obj);
validator().instanceOf
Check if an object is an instance of a constructor.
Syntax:
var validator = validator().instanceOf(ContructorFunc);
validator.shortcut_validators
It is an object where you can add your shortcut validators.
"match" and "isPrototypeOf" are added here but you can add your own if you need.