Comparing version 0.2.0 to 0.2.1
126
index.js
@@ -24,3 +24,3 @@ var _ = require('underscore'); | ||
// Built-in data type rules | ||
Anchor.prototype.rules = require('./rules'); | ||
Anchor.prototype.rules = require('./lib/rules'); | ||
@@ -31,11 +31,10 @@ // Enforce that the data matches the specified ruleset | ||
Anchor.prototype.to = function (ruleset, cb) { | ||
var self = this; | ||
// If callback is specififed, trigger it at the end | ||
// also, handle error instead of throwing it | ||
if (cb) self.cb = cb; | ||
if (cb) this.cb = cb; | ||
// Use deep match to descend into the collection and verify each item and/or key | ||
// Stop at default maxDepth (50) to prevent infinite loops in self-associations | ||
Anchor.deepMatch(self.data, ruleset, self); | ||
Anchor.match(this.data, ruleset, this); | ||
@@ -45,3 +44,3 @@ // If a callback was specified, trigger it | ||
// (otherwise we never should have made it this far, the error should have been thrown) | ||
cb && cb(self.error); | ||
cb && cb(this.error); | ||
}; | ||
@@ -87,120 +86,7 @@ | ||
// Deep-match a complex collection or model against a schema | ||
Anchor.match = require('./lib/match.js'); | ||
// Return whether a piece of data matches a rule | ||
// ruleName :: (STRING) | ||
Anchor.match = function match (datum, ruleName, ctx) { | ||
try { | ||
var outcome, rule; | ||
// Determine rule | ||
if (_.isEqual(ruleName,[])) { | ||
// [] specified as data type checks for an array | ||
rule = _.isArray; | ||
} | ||
else if (_.isEqual(ruleName,{})) { | ||
// {} specified as data type checks for any object | ||
rule = _.isObject; | ||
} | ||
else if (_.isRegExp(ruleName)) { | ||
// Allow regexes to be used | ||
rule = function (x) { | ||
if (!_.isString(x)) return false; | ||
x.match(ruleName); | ||
}; | ||
} | ||
else rule = Anchor.prototype.rules[ruleName]; | ||
// Determine outcome | ||
if (!rule) { | ||
throw new Error ('Unknown rule: ' + ruleName); | ||
} | ||
else outcome = rule(datum); | ||
// False outcome is a failure | ||
if (!outcome) return failure(datum,ruleName); | ||
else return outcome; | ||
} | ||
catch (e) { | ||
failure(datum, ruleName); | ||
} | ||
// On failure-- stop and get out. | ||
// If a cb was specified, call it with a first-arity error object. | ||
// Otherwise, throw an error. | ||
function failure(datum, ruleName) { | ||
// Construct error | ||
var err = new Error ('Validation error: "'+datum+'" is not of type "'+ruleName+'"'); | ||
// Handle the error in callback instead of throwing it | ||
if (ctx.cb) { | ||
ctx.error = err; | ||
return false; | ||
} | ||
// Or throw error if there was no callback | ||
else throw err; | ||
} | ||
}; | ||
// Match a complex collection or model against a schema | ||
Anchor.deepMatch = function deepMatch (data, ruleset, ctx, depth, maxDepth) { | ||
// If ruleset is not an object or array, use the provided function to validate | ||
if (!_.isObject(ruleset)) { | ||
return Anchor.match(data,ruleset,ctx); | ||
} | ||
// Default value for maxDepth and depth | ||
maxDepth = maxDepth || 50; | ||
depth = depth || 0; | ||
if (depth > maxDepth) { | ||
throw new Error ('Depth of object being parsed exceeds maxDepth (). Maybe it links to itself?'); | ||
} | ||
// If this is a schema rule, check each item in the data collection | ||
if (_.isArray(ruleset) && ruleset.length !== 0) { | ||
if (ruleset.length > 1) { | ||
throw new Error ('[] (or schema) rules can contain only one item.'); | ||
} | ||
// Handle plurals (arrays with a schema rule) | ||
return _.all(data, matchArray); | ||
} | ||
// If the current rule is an object, check each key | ||
else if (!_.isArray(ruleset) && _.isObject(ruleset)) { | ||
// Don't treat empty object as a ruleset | ||
if (_.keys(ruleset).length === 0) { | ||
return Anchor.match(data, ruleset, ctx); | ||
} | ||
else return _.all(ruleset,matchDict); | ||
} | ||
// Leaf rules land here and execute the iterator | ||
else return Anchor.match(data, ruleset, ctx); | ||
// Iterate through rules in dictionary until error is detected | ||
function matchDict(subRule,key) { | ||
if (ctx && ctx.error) return false; | ||
else return Anchor.deepMatch(data[key], ruleset[key], ctx, depth+1); | ||
} | ||
// Match each object in array against ruleset until error is detected | ||
function matchArray(model) { | ||
if (ctx && ctx.error) return false; | ||
else return Anchor.deepMatch(model, ruleset[0], ctx, depth+1); | ||
} | ||
}; | ||
function todo() { | ||
throw new Error("Not implemented yet! If you'd like to contribute, tweet @mikermcneil."); | ||
} |
{ | ||
"name": "anchor", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "Recursive validation library with support for objects and lists", | ||
@@ -21,4 +21,5 @@ "main": "index.js", | ||
"validator": "~0.4.22", | ||
"underscore": "~1.4.3" | ||
"underscore": "~1.4.3", | ||
"async": "~0.2.6" | ||
} | ||
} |
@@ -44,6 +44,6 @@ anchor | ||
// If you want to handle the error instead of throwing it, add .error | ||
anchor('something').to("string").error(function (err) { | ||
// If you want to handle the error instead of throwing it, use a callback | ||
anchor('something').to("string", function (err) { | ||
// Err is an error object with a subset of the original data that didn't pass | ||
// Specifying .error will prevent an error from being thrown | ||
// Specifying a callback will prevent an error from being thrown | ||
}); | ||
@@ -84,2 +84,3 @@ | ||
<!-- | ||
## Custom rules | ||
@@ -178,3 +179,3 @@ | ||
// You can use the same .error notation from above in your definition to handle the error yourself | ||
// You can use the same callback from above in your definition to handle the error yourself | ||
$.get = anchor($.get).usage( | ||
@@ -184,4 +185,4 @@ ['urlish',{}, 'function'], | ||
['urlish',{}], | ||
['urlish'] | ||
).error(function (err) { | ||
['urlish'], | ||
function (err) { | ||
// Do something about the error here | ||
@@ -237,13 +238,4 @@ }); | ||
<!-- | ||
> The api will have to change a bit here, so omitting this part for now. | ||
Or even use deferred object notation! | ||
``` | ||
$.getById.url('/user').id(3).done(cb); | ||
$.getById('/user').id(3); | ||
``` | ||
--> | ||
## Default values | ||
@@ -441,2 +433,4 @@ You can also specify default values. If it's not required, if a value listed in defaults is undefined, the default value will be substituted. A value should not have a default AND be required-- one or the other. | ||
--> | ||
## Tests | ||
@@ -443,0 +437,0 @@ ``` |
var _ = require('underscore'); | ||
var anchor = require('../index.js'); | ||
var testRule = require('./testRule.js'); | ||
var testRule = require('./util/testRule.js'); | ||
@@ -5,0 +5,0 @@ describe('arrays', function() { |
var _ = require('underscore'); | ||
var anchor = require('../index.js'); | ||
var testRule = require('./testRule.js'); | ||
var testRule = require('./util/testRule.js'); | ||
@@ -5,0 +5,0 @@ |
var _ = require('underscore'); | ||
var anchor = require('../index.js'); | ||
var testRule = require('./testRule.js'); | ||
var testRule = require('./util/testRule.js'); | ||
@@ -5,0 +5,0 @@ describe('error usage', function() { |
var _ = require('underscore'); | ||
var anchor = require('../index.js'); | ||
var testRule = require('./testRule.js'); | ||
var testRule = require('./util/testRule.js'); | ||
@@ -5,0 +5,0 @@ describe('objects', function() { |
var _ = require('underscore'); | ||
var anchor = require('../index.js'); | ||
var testRule = require('./testRule.js'); | ||
var testRule = require('./util/testRule.js'); | ||
var shouldFail = require('./util/shouldFail.js'); | ||
describe('usage', function() { | ||
@@ -50,11 +50,2 @@ | ||
}); | ||
}); | ||
// Return function which flip-flops error state of callback | ||
function shouldFail (cb) { | ||
return function (err) { | ||
if (!err) return cb('Should have thrown error!'); | ||
else return cb(); | ||
}; | ||
} | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
13
28781
3
585
454
+ Addedasync@~0.2.6
+ Addedasync@0.2.10(transitive)