Permalink
Browse files

add date handling

  • Loading branch information...
bronson committed Oct 7, 2011
1 parent c830583 commit 55725b777bcb27990a9cc11cffb92d0b71973e1b
Showing with 65 additions and 122 deletions.
  1. +23 −6 README.md
  2. +0 −114 kitchen-sink.js
  3. +14 −0 lib/valid.js
  4. +28 −2 test/valid.test.js
View
@@ -47,14 +47,11 @@ A lightweight, chaining validation library.
This library is scary new.
-- try to shrink the api, implement kitchen-sink
-- npm publish
+- terminology: exists/notExists, and oneOf/notOneOf vs. in/notIn
- pass a json schema to array()? factor into RunSubtest & have everything call this.
-- write isDate, isBefore, isAfter
-- write isEmail() isIP() isUrl() isUUID()
+- npm publish
- Pass error message to Valid constructor? make errorMessage a synonym for message?
- test coverage?
-- Allow putting value first? i.e. Valid(9).lt(12).gt(10) throws "9 is not greater than 10"
- write an assertion function? Valid.assert(12).integer().min(5);
- convert to using nested functions instead of the `__queue` array?
- 'not' should try to modify the error message on the way through
@@ -83,8 +80,9 @@ should be reasonably readable.
- Presence: defined(), undef(), \*undefined(), nil(), \*null(), notNull()
- Equality: equal(a[,b...]), notEqual(...), oneOf(arrayOrObject), \*in(arrayOrObject)
-- Comparison: eq(n), lt(n), le(n), ge(n), gt(n), ne(n)
+- Comparison: eq(n), lt(n), le(n), ge(n), gt(n), ne(n), min(n), max(n)
- Numbers: number(), integer(), mod(x[,rem]), even(), odd()
+- Dates: date(), before([date]), after([date])
- Arrays: array([validationForEachItem]), len(min,max), empty()
- Strings: string(), len(min,max), blank(), notBlank()
- Regexps: match(regex[,modifiers]), nomatch(regex[,modifiers])
@@ -149,6 +147,25 @@ Or just rename them:
Valid.any = Valid.or;
```
+Here's a rogue's gallery of examples. Drop them in your code, customize as needed.
+You call them like any other validation: `Valid.isNumeric().len(2)`.
+
+```javascript
+ // TODO: test these!
+ Validator.boolean = Valid.type('boolean').message('must be a boolean').define();
+ Validator.true = Valid.equal(true).message('must be true').define();
+ Validator.false = Valid.equal(false).message('must be false').define();
+ Validator.isAlpha = Valid.match(/^[a-zA-Z]+$/).message("must be only letters").define();
+ Validator.isAlphanumeric = Valid.match(/^[a-zA-Z0-9]+$/).message("must be letters or numbers").define();
+ Validator.isNumeric = Valid.match(/^-?[0-9]+$/).message("must be numeric").define();
+ Validator.isLowercase = Valid.match(/^[a-z]+$/).message("must be lower-case letters").define();
+ Validator.isUppercase = Valid.match(/^[A-Z]+$/).message("must be upper-case letters").define();
+ Validator.noOutsideWS = Valid.noMatch(/^\s+|\s+$/).message("must not have leading or trailing whitespace").define();
+ Validator.noConsecutiveWS= Valid.noMatch(/\s\s/).message("must not have consecutive whitespace").define();
+ Validator.noControlChars = Valid.noMatch(/[\x00-\x19\x7F]/).message("must not have control characters").define();
+ Validator.saneString = Valid.noOutsideWS().noConsecutiveWS().noControlChars().define();
+```
+
# Weirdness
View
@@ -1,114 +0,0 @@
-// This module contains all the synonyms I could think of.
-// It's meant to show how to use composability... I'm not sure it makes
-// sense to use it yourself. But, if you want to:
-//
-// TODO: test this
-// var Valid = require('valid').extend(require('valid/synonyms'));
-
-Valid = require('valid');
-
-
-
-
-Valid.isOneOf = Valid.in; // can also use isOneOf = Valid.in(). Same result.
-
-
-// type validations
-Valid.isUndefined = Valid.typeOf('undefined');
-Valid.isNull = Valid.typeOf('null');
-Valid.isBoolean = Valid.typeOf('boolean');
-Valid.isNumber = Valid.typeOf('number');
-Valid.isString = Valid.typeOf('string');
-Valid.isFunction = Valid.typeOf('function');
-Valid.isObject = Valid.typeOf('object');
-Valid.isArray = Valid.todo;
-valid.instanceOf = Valid.todo;
-
-Valid.exists = Valid.not(Valid.isUndefined).not(Valid.isNull);
-
-// common integer validations
-Valid.isInteger = Valid.todo();
-Valid.mod = Valid.todo();
-
-// common string validations
-Valid.blank = Valid.match(/^\s*$/);
-Valid.nonBlank = Valid.not(Valid.blank);
-
-
-
-// Onvalid dialect
-
-0nvalid.and = Valid.and;
-0nvalid.or = Valid.or;
-0nvalid.not = Valid.not;
-0nvalid.regex = Valid.match;
-0nvalid.nor = Valid.not(Valid.or);
-0nvalid.opt = Valid.optional;
-0nvalid.exists = Valid.not(Valid.isUndefined);
-0nvalid.notExists = Valid.not(Valid.exists);
-0nvalid.all = Valid.todo; // return _.every (ps, function (p) {return _.contains(p, vs);});
-0nvalid._in = Valid.in;
-0nvalid.nin = Valid.not(Valid.in);
-0nvalid.eq = Valid.todo;
-0nvalid.ne = Valid.todo;
-0nvalid.gt = Valid.todo;
-0nvalid.gte = Valid.todo;
-0nvalid.lt = Valid.todo;
-0nvalid.lte = Valid.todo;
-
-0nvalid.isLowercase = Valid.todo;
-0nvalid.isUppercase = Valid.todo;
-0nvalid.isHexString = Valid.todo;
-
-0nvalid.validate = Valid.todo; // takes different arguments from Valid.validate
-
-
-// node-validator dialect
-
-Validator.is = Valid.match;
-Validator.not = Valid.not(Validator.is); // very different from Valid.not
-Validator.isEmail = Valid.isEmail;
-Validator.isUrl = Valid.isUrl;
-Validator.isIP = Valid.isIP;
-Validator.isAlpha = Valid.match(/^[a-zA-Z]+$/);
-Validator.isAlphanumeric = Valid.match(/^[a-zA-Z0-9]+$/);
-Validator.isNumeric = Valid.match(/^-?[0-9]+$/);
-Validator.isLowercase = Valid.match(/^[a-z0-9]+$/);
-Validator.isUppercase = Valid.match(/^[A-Z0-9]+$/);
-Validator.isInt = Valid.match(/^(?:-?(?:0|[1-9][0-9]*))$/);
-Validator.isDecimal = Valid.match(/^(?:-?(?:0|[1-9][0-9]*))?(?:\.[0-9]*)?$/);
-Validator.isFloat = Valid.isDecimal;
-Validator.isNull = Valid.isNull;
-Validator.notNull = Valid.not(Validator.isNull);
-Validator.notEmpty Valid.nonBlank;
-Validator.equals = Valid.todo;
-Validator.contains = Valid.todo; // if(this.str.indexOf(str) === -1) error('Invalid characters');
-Validator.notContains = Valid.not(Validator.contains);
-Validator.regex = Valid.match;
-Validator.notRegex = Valid.not(Validator.regex);
-Validator.len = Valid.todo;
-Validator.isUUID = Valid.isUUID;
-Validator.isDate = Valid.todo;
-Validator.isAfter = Valid.todo;
-Validator.isBefore = Valid.todo;
-Validator.in = Valid.in;
-Validator.notIn = Valid.not(Validator.in);
-Validator.min = Valid.todo;
-Validator.max = Valid.todo;
-Validator.isArray = Valid.isArray;
-
-Validator.check = function(str, fail_msg) {
- // Validator converts null and NaN to '', and numbers to strings. Ugh.
- this.str = (str == null || (isNaN(str) && str.length == undefined)) ? '' : str;
- if (typeof this.str == 'number') this.str += '';
- return Valid.check(str);
-}
-
-/* test the synopsis
-var check = Validator.check;
-check('test@email.com').len(6, 64).isEmail(); // Methods are chainable
-check('abc').isInt(); // Throws 'Invalid integer'
-check('abc', 'Please enter a number').isInt(); // Throws 'Please enter a number'
-check('abcdefghijklmnopzrtsuvqxyz').is(/^[a-z]+$/);
-*/
-
View
@@ -146,6 +146,20 @@ Valid.array = Valid.SimpleValidation(function Arry(value, validation) {
}
});
+Valid.date = Valid.SimpleValidation(function(value) {
+ if(isNaN(Date.parse(value))) return "must be a date";
+});
+
+Valid.before = Valid.SimpleValidation(function Before(value,when) {
+ if(when === undefined) when = new Date();
+ if(Date.parse(value) > when) return "must be before " + when;
+});
+
+Valid.after = Valid.SimpleValidation(function After(value,when) {
+ if(when === undefined) when = new Date();
+ if(Date.parse(value) < when) return "must be after " + when;
+});
+
Valid.len = Valid.SimpleValidation(function Len(value,min,max) {
var items = typeof value === 'string' ? 'character' : 'element';
if(typeof value === 'null' || typeof value === 'undefined' || typeof value.length === 'undefined') return "must have a length field";
View
@@ -7,10 +7,17 @@ var Valid = require('../lib/valid');
// throws an error if the result doesn't exactly match the expectation
Valid.assert = function assert(value, expected) {
+ // need to duck type because typeof and instanceof don't work reliably
+ var isRegExp = function(o) { return o && o.test && o.exec && o.source && (o.global === true || o.global === false) && (o.ignoreCase === true || o.ignoreCase === false) && (o.multiline === true || o.multiline === false) };
+
var actual = this.check(value);
- if(expected !== actual) {
+ var acstr = (actual === undefined ? "success" : "'" + actual + "'");
+ if(isRegExp(expected)) {
+ if(!actual.match(expected)) {
+ throw Error(value + ": " + expected + " doesn't match " + acstr);
+ }
+ } else if(expected !== actual) {
var exstr = (expected === undefined ? "success" : "'" + expected + "'");
- var acstr = (actual === undefined ? "success" : "'" + actual + "'");
throw Error(value + ": expected " + exstr + " but got " + acstr);
}
};
@@ -114,6 +121,25 @@ Valid.odd().assert(17);
Valid.odd().assert(12, "must be odd");
Valid.odd().assert(0, "must be odd");
+// dates
+Valid.date().assert(new Date);
+Valid.date().assert("Dec 25, 1989");
+Valid.date().assert(null, "must be a date");
+Valid.date().assert('zqm', "must be a date");
+var today = new Date();
+var past = new Date();
+past.setFullYear(past.getFullYear() - 1);
+var future = new Date();
+future.setFullYear(future.getFullYear() + 1);
+Valid.after().assert(future);
+Valid.before().assert(past);
+Valid.after().assert(past, /^must be after /);
+Valid.before().assert(future, /^must be before /);
+Valid.after(past).assert(today);
+Valid.before(future).assert(today);
+Valid.after(future).assert(today, /^must be after /);
+Valid.before(past).assert(today, /^must be before /);
+
// strings
Valid.string().assert(' 123');
Valid.string().assert(undefined, "must be a string");

0 comments on commit 55725b7

Please sign in to comment.