Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

make it an npm module

  • Loading branch information...
commit 4971ed459f6784ff1ef54847b7798680936e3098 1 parent 7372b45
@bronson authored
View
20 LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2011 Scott Bronson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
View
7 README.md
@@ -2,15 +2,16 @@
- Small, light, zero dependencies.
- Can be used in Node, browsers, and Mongo/Couch Map/Reduce functions.
-- Offers an error object similar to ActiveRecord validations.
-- Can be used declaratively as well as immediately.
+- Can recursively test JSON data structures.
+- Easy to extend with your own validations.
+- Tests be used declaratively as well as immediately.
- Good test coverage.
### Declarative
var inRange = Valid.min(4).max(9)
- inRange(12) // throws an error
+ inRange.verify(12) // throws an error
var stringInRange = inRange.typeof('string').errorHandler(Valid.TrueFalse)
if(stringInRange.validate("not in range")) { /\* not executed \*/ }
View
94 lib/valid-engine.js
@@ -0,0 +1,94 @@
+// valid-engine.js Scott Bronson 2011
+// This file defines the core objects that make Valid run.
+// See valid.js for the default set of tests.
+
+
+// todo? is it possible to turn test objects into arrays?
+
+var Valid = function Valid() { };
+module.exports = Valid;
+
+
+Valid.GetChain = function GetChain() {
+ if(this === Valid) {
+ // we're the first item in a chain so create a Chain object
+ var chain = function Chain() {};
+ chain.prototype = this;
+ return new chain();
+ }
+ return this;
+};
+
+// Adds the given test to the current Chain.
+// If data is supplied, it's added to the passed-in test to help introspect when debugging.
+Valid.AddTest = function AddTest(test, data) {
+ var self = this.GetChain();
+ if(self._queue === undefined) self._queue = [];
+ if(data) test.data = data;
+ self._queue.push(test);
+ return self;
+};
+
+// Supply a function that that returns undefined on success or an error message on failure, produces a full, chainable test.
+// The first arg passed to your your function is the value to test, the rest are the args passed when adding the test.
+// i.e. Valid.t = SimpleTest(fn(){...}); Valid.t(4,2).check(9) would call your function with arguments 9, 4, 2.
+Valid.SimpleTest = function SimpleTest(fn) {
+ return function() {
+ var args = Array.prototype.slice.call(arguments, 0);
+ return this.AddTest( function SimpleTest(value) {
+ return fn.apply(this, [value].concat(args));
+ }, args);
+ };
+};
+
+Valid.ValidateQueue = function ValidateQueue(queue, value) {
+ if(!queue || queue.length < 1) return "no tests!";
+ for(var i=0; i<queue.length; i++) {
+ var error = queue[i].call(this, value);
+ if(error) return error;
+ }
+};
+
+
+// core api
+// TODO: test? check? verify? these names suck.
+
+// returns null if valid, the error string if invalid
+Valid.test = function test(value) {
+ var self = this.GetChain();
+ return self.GetChain().ValidateQueue(self._queue, value);
+};
+
+// returns true if valid, false if invalid
+Valid.check = function check(value) {
+ return !this.test(value);
+};
+
+// raises an error if invalid
+Valid.verify = function assert(value) {
+ var message = this.test(value);
+ if(message) throw value + " " + message;
+};
+
+// Allows you to reuse a chain as as a chainable test. If you get the error
+// Property 'myfunc' of object function Valid() { } is not a function
+// then you forgot to call define().
+//
+// It's really shameful that this function needs to exist.
+// In an ideal world you could just do this: Valid.null() = Valid.equal(null);
+// In our world, that only works if you don't call it: Valid.null.verify(1); Ugh.
+// Since Valid.equal(null) returns the chain object, if you call null:
+// Valid.null().verify(1) JS complains "Property null is not a function"
+// For this to work, JS needs to a callable object with a prototype chain.
+// And, without using nonstandard __proto__, I don't think that's possible...?
+Valid.define = function define() {
+ var queue = this._queue;
+ return function() {
+ var self = this.GetChain();
+ for(var i=0; i<queue.length; i++) {
+ self.AddTest(queue[i]);
+ }
+ return self;
+ };
+};
+
View
89 lib/valid.js
@@ -0,0 +1,89 @@
+// valid.js Scott Bronson 2011
+// This file defines the Valid object and some core validation tests.
+
+// todo? is it possible to turn test objects into arrays?
+
+var Valid = require('./valid-engine');
+module.exports = Valid;
+
+
+// core tests
+
+Valid.nop = Valid.SimpleTest(function Nop(val) { });
+Valid.fail = Valid.SimpleTest(function Fail(val,msg) { return msg || "failed"; });
+Valid.equal = Valid.SimpleTest(function Equal(val,want) { if(val !== want) return "is not equal to "+want; });
+Valid.mod = Valid.SimpleTest(function mod(val,by,rem) { if(val%by !== (rem||0)) return "mod "+by+" is "+(val%by)+" not "+rem; });
+
+Valid.type = Valid.SimpleTest(function Type(val,type) {
+ if(typeof type !== 'string') return "type requires a string argument, not "+(typeof type);
+ if(typeof val !== type) return "is of type " + (typeof val) + " not " + type;
+});
+
+Valid.messageFor = Valid.SimpleTest(function Msg(value, test, message) {
+ var error = this.ValidateQueue(test._queue, value);
+ if(error) return message;
+});
+
+Valid.not = Valid.SimpleTest(function Not(value, test, message) {
+ var error = this.ValidateQueue(test._queue, value);
+ if(!error) return message || "test succeeded";
+});
+
+// seems somewhat useless since V.a().b() is the same as V.and(V.a(),V.b())
+Valid.and = function and() {
+ var chains = arguments;
+ return this.AddTest( function And(value) {
+ for(var i=0; i<chains.length; i++) {
+ var error = this.ValidateQueue(chains[i]._queue, value);
+ if(error) return error;
+ }
+ }, chains);
+};
+
+Valid.or = function or() {
+ var chains = arguments;
+ return this.AddTest(function Or(value) {
+ var errors = [];
+ for(var i=0; i<chains.length; i++) {
+ var error = this.ValidateQueue(chains[i]._queue, value);
+ if(!error) return; // short circuit
+ errors.push(error);
+ }
+ return errors.length > 0 ? errors.join(" and ") : undefined;
+ }, chains);
+};
+
+Valid.match = function match(pattern, modifiers) {
+ if(typeof pattern !== 'function') pattern = new RegExp(pattern, modifiers);
+ return this.string().AddTest( function Match(value) {
+ if(!value.match(pattern)) return "does not match " + pattern;
+ });
+};
+
+
+// composite tests
+
+Valid.todo = function(name) {
+ return this.fail((name ? name : "this") + " is still todo");
+};
+
+Valid.undefined = Valid.equal(undefined).define();
+Valid.defined = Valid.not(Valid.undefined(), "is undefined").define();
+Valid.null = Valid.equal(null).define();
+Valid.notNull = Valid.not(Valid.null(), "is null").define();
+Valid.exists = Valid.messageFor(Valid.defined().notNull(), "does not exist").define();
+Valid.noexisty = Valid.not(Valid.exists(), "exists").define();
+Valid.boolean = Valid.type('boolean').define();
+Valid.true = Valid.equal(true).define();
+Valid.false = Valid.equal(false).define();
+Valid.number = Valid.type('number').define();
+Valid.integer = Valid.number().messageFor(Valid.mod(1), "is not an integer").define();
+Valid.string = Valid.type('string').define();
+Valid.blank = Valid.messageFor(Valid.or(Valid.noexisty(),Valid.match(/^\s*$/)), "is not blank").define();
+Valid.notBlank = Valid.not(Valid.blank(), "is blank").define();
+Valid.function = Valid.type('function').define();
+Valid.object = Valid.type('object').define();
+
+Valid.optional = function(test) { return Valid.or(Valid.messageFor(Valid.undefined(),"is optional"), test); };
+Valid.notEqual = function(arg) { return Valid.not(Valid.equal(arg), "is equal to " + arg); };
+
View
14 package.json
@@ -0,0 +1,14 @@
+{ "name" : "valid"
+, "description" : "Library to quickly validate JSON."
+, "version" : "0.1.0"
+, "keywords" : [ "validation", "schema", "test", "json" ]
+, "author" : { "name" : "Scott Bronson", "email" : "brons_valid@rinspin.com", "url" : "https://github.com/bronson" }
+, "contributors" : [ { "name": "Aaron Blohowiak", "url" : "https://github.com/aaronblohowiak" } ]
+, "licenses" : [ { "type" : "MIT", "url" : "https://github.com/bronson/valid/blob/master/LICENSE" } ]
+, "homepage" : "https://github.com/bronson/valid"
+, "repository" : { "type" : "git", "url" : "http://github.com/bronson/valid" }
+, "bugs" : { "web" : "https://github.com/bronson/valid/issues" }
+, "directories" : { "lib" : "./lib" }
+, "main" : "./lib"
+, "scripts" : { "test" : "node test/test-valid.js" }
+}
View
22 test-valid.js → test/test-valid.js
@@ -1,4 +1,4 @@
-var Valid = require('./valid');
+var Valid = require('../lib/valid');
// Like check() but throws if the result doesn't match the expectation
Valid.assert = function assert(value, expected) {
@@ -40,13 +40,13 @@ Valid.notEqual(null).assert(undefined);
Valid.notEqual(null).assert(null, "is equal to null");
-Valid.typeOf('undefined').assert(undefined);
+Valid.type('undefined').assert(undefined);
// typeof null returns 'object' on some JS implementations, use null()
-Valid.typeOf('number').assert(123);
-Valid.typeOf('string').assert('123');
-Valid.typeOf('garbage').assert('123', "is of type string not garbage");
-Valid.typeOf(undefined).assert(undefined, "typeOf requires a string argument, not undefined");
-Valid.typeOf(123).assert(123, "typeOf requires a string argument, not number");
+Valid.type('number').assert(123);
+Valid.type('string').assert('123');
+Valid.type('garbage').assert('123', "is of type string not garbage");
+Valid.type(undefined).assert(undefined, "type requires a string argument, not undefined");
+Valid.type(123).assert(123, "type requires a string argument, not number");
// booleans
Valid.boolean().assert(true);
@@ -90,9 +90,9 @@ Valid.equal(2).assert( Valid.match(/^abc$/)._queue.length ); // closure leak mea
Valid.and().assert(null); // passing 0 tests succeeds unconditionally
Valid.and( Valid.null() ).assert(null); // passing 1 arg success
Valid.and( Valid.null() ).assert(undefined, "is not equal to null"); // passing 1 arg failure
-Valid.and( Valid.typeOf('string'), Valid.match(/c$/), Valid.match(/^a/) ).assert('abc');
-Valid.and( Valid.typeOf('string'), Valid.match(/^bbc$/) ).assert('abc', "does not match /^bbc$/");
-Valid.and( Valid.typeOf('number'), Valid.match(/^abc$/) ).assert('abc', "is of type string not number");
+Valid.and( Valid.type('string'), Valid.match(/c$/), Valid.match(/^a/) ).assert('abc');
+Valid.and( Valid.type('string'), Valid.match(/^bbc$/) ).assert('abc', "does not match /^bbc$/");
+Valid.and( Valid.type('number'), Valid.match(/^abc$/) ).assert('abc', "is of type string not number");
Valid.or().assert(undefined); // passing 0 tests succeeds unconditionally
Valid.or( Valid.null() ).assert(null); // passing 1 arg success
@@ -101,7 +101,7 @@ Valid.or( Valid.null(), Valid.undefined() ).assert(undefined);
Valid.or( Valid.null(), Valid.undefined() ).assert(null);
Valid.or( Valid.null(), Valid.number(), Valid.string() ).assert('mosdef');
Valid.or( Valid.undefined(), Valid.match(/^abc$/), Valid.match(/def$/) ).assert('mosdef');
-Valid.or( Valid.typeOf('number'), Valid.match(/^bbc$/) ).assert('abc', "is of type string not number and does not match /^bbc$/");
+Valid.or( Valid.type('number'), Valid.match(/^bbc$/) ).assert('abc', "is of type string not number and does not match /^bbc$/");
var nullOrString = Valid.or(Valid.null(), Valid.string());
nullOrString.assert(null);
View
173 valid.js
@@ -1,173 +0,0 @@
-// valid.js Scott Bronson 2011
-// This file defines the Valid object and some core validation tests.
-
-// todo? is it possible to turn test objects into arrays?
-
-var Valid = function Valid() { };
-module.exports = Valid;
-
-
-Valid.GetChain = function GetChain() {
- if(this === Valid) {
- // we're the first item in a chain so create a Chain object
- var chain = function Chain() {};
- chain.prototype = this;
- return new chain();
- }
- return this;
-};
-
-// Adds the given test to the current Chain.
-// If data is supplied, it's added to the passed-in test to help introspect when debugging.
-Valid.AddTest = function AddTest(test, data) {
- var self = this.GetChain();
- if(self._queue === undefined) self._queue = [];
- if(data) test.data = data;
- self._queue.push(test);
- return self;
-};
-
-// Supply a function that that returns undefined on success or an error message on failure, produces a full, chainable test.
-// The first arg passed to your your function is the value to test, the rest are the args passed when adding the test.
-// i.e. Valid.t = SimpleTest(fn(){...}); Valid.t(4,2).check(9) would call your function with arguments 9, 4, 2.
-Valid.SimpleTest = function SimpleTest(fn) {
- return function() {
- var args = Array.prototype.slice.call(arguments, 0);
- return this.AddTest( function SimpleTest(value) {
- return fn.apply(this, [value].concat(args));
- }, args);
- };
-};
-
-Valid.ValidateQueue = function ValidateQueue(queue, value) {
- if(!queue || queue.length < 1) return "no tests!";
- for(var i=0; i<queue.length; i++) {
- var error = queue[i].call(this, value);
- if(error) return error;
- }
-};
-
-
-// core api
-// TODO: test? check? verify? these names suck.
-
-// returns null if valid, the error string if invalid
-Valid.test = function test(value) {
- var self = this.GetChain();
- return self.GetChain().ValidateQueue(self._queue, value);
-};
-
-// returns true if valid, false if invalid
-Valid.check = function check(value) {
- return !this.test(value);
-};
-
-// raises an error if invalid
-Valid.verify = function assert(value) {
- var message = this.test(value);
- if(message) throw value + " " + message;
-};
-
-// Allows you to reuse a chain as as a chainable test. If you get the error
-// Property 'myfunc' of object function Valid() { } is not a function
-// then you forgot to call define().
-//
-// It's really shameful that this function needs to exist.
-// In an ideal world you could just do this: Valid.null() = Valid.equal(null);
-// In our world, that only works if you don't call it: Valid.null.verify(1); Ugh.
-// Since Valid.equal(null) returns the chain object, if you call null:
-// Valid.null().verify(1) JS complains "Property null is not a function"
-// For this to work, JS needs to a callable object with a prototype chain.
-// And, without using nonstandard __proto__, I don't think that's possible...?
-Valid.define = function define() {
- var queue = this._queue;
- return function() {
- var self = this.GetChain();
- for(var i=0; i<queue.length; i++) {
- self.AddTest(queue[i]);
- }
- return self;
- };
-};
-
-
-// core tests
-
-Valid.nop = Valid.SimpleTest(function Nop(val) { });
-Valid.fail = Valid.SimpleTest(function Fail(val,msg) { return msg || "failed"; });
-Valid.equal = Valid.SimpleTest(function Equal(val,want) { if(val !== want) return "is not equal to "+want; });
-Valid.mod = Valid.SimpleTest(function mod(val,by,rem) { if(val%by !== (rem||0)) return "mod "+by+" is "+(val%by)+" not "+rem; });
-
-Valid.typeOf= Valid.SimpleTest(function Type(val,type) {
- if(typeof type !== 'string') return "typeOf requires a string argument, not "+(typeof type);
- if(typeof val !== type) return "is of type " + (typeof val) + " not " + type;
-});
-
-Valid.messageFor = Valid.SimpleTest(function Msg(value, test, message) {
- var error = this.ValidateQueue(test._queue, value);
- if(error) return message;
-});
-
-Valid.not = Valid.SimpleTest(function Not(value, test, message) {
- var error = this.ValidateQueue(test._queue, value);
- if(!error) return message || "test succeeded";
-});
-
-// seems somewhat useless since V.a().b() is the same as V.and(V.a(),V.b())
-Valid.and = function and() {
- var chains = arguments;
- return this.AddTest( function And(value) {
- for(var i=0; i<chains.length; i++) {
- var error = this.ValidateQueue(chains[i]._queue, value);
- if(error) return error;
- }
- }, chains);
-};
-
-Valid.or = function or() {
- var chains = arguments;
- return this.AddTest(function Or(value) {
- var errors = [];
- for(var i=0; i<chains.length; i++) {
- var error = this.ValidateQueue(chains[i]._queue, value);
- if(!error) return; // short circuit
- errors.push(error);
- }
- return errors.length > 0 ? errors.join(" and ") : undefined;
- }, chains);
-};
-
-Valid.match = function match(pattern, modifiers) {
- if(typeof pattern !== 'function') pattern = new RegExp(pattern, modifiers);
- return this.string().AddTest( function Match(value) {
- if(!value.match(pattern)) return "does not match " + pattern;
- });
-};
-
-
-// composite tests
-
-Valid.todo = function(name) {
- return this.fail((name ? name : "this") + " is still todo");
-};
-
-Valid.undefined = Valid.equal(undefined).define();
-Valid.defined = Valid.not(Valid.undefined(), "is undefined").define();
-Valid.null = Valid.equal(null).define();
-Valid.notNull = Valid.not(Valid.null(), "is null").define();
-Valid.exists = Valid.messageFor(Valid.defined().notNull(), "does not exist").define();
-Valid.noexisty = Valid.not(Valid.exists(), "exists").define();
-Valid.boolean = Valid.typeOf('boolean').define();
-Valid.true = Valid.equal(true).define();
-Valid.false = Valid.equal(false).define();
-Valid.number = Valid.typeOf('number').define();
-Valid.integer = Valid.number().messageFor(Valid.mod(1), "is not an integer").define();
-Valid.string = Valid.typeOf('string').define();
-Valid.blank = Valid.messageFor(Valid.or(Valid.noexisty(),Valid.match(/^\s*$/)), "is not blank").define();
-Valid.notBlank = Valid.not(Valid.blank(), "is blank").define();
-Valid.function = Valid.typeOf('function').define();
-Valid.object = Valid.typeOf('object').define();
-
-Valid.optional = function(test) { return Valid.or(Valid.messageFor(Valid.undefined(),"is optional"), test); };
-Valid.notEqual = function(arg) { return Valid.not(Valid.equal(arg), "is equal to " + arg); };
-
Please sign in to comment.
Something went wrong with that request. Please try again.