Socket
Socket
Sign inDemoInstall

anchor

Package Overview
Dependencies
Maintainers
1
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

anchor - npm Package Compare versions

Comparing version 0.3.0 to 0.4.0

test/arrayType.test.js

64

index.js

@@ -19,3 +19,2 @@ var _ = require('underscore');

return this;

@@ -28,20 +27,38 @@ }

// Enforce that the data matches the specified ruleset
// If it doesn't, throw an error.
// If the callback is specified, instead of throwing, use first arg
Anchor.prototype.to = function (ruleset, cb) {
Anchor.prototype.to = function (ruleset) {
// If callback is specififed, trigger it at the end
// also, handle error instead of throwing it
if (cb) this.cb = cb;
var errors = [];
// 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.match(this.data, ruleset, this);
// If ruleset doesn't contain any explicit rule keys,
// assume that this is a type
// If a callback was specified, trigger it
// If an error object was stowed away in the ctx, pass it along
// (otherwise we never should have made it this far, the error should have been thrown)
cb && cb(this.error);
// Look for explicit rules
for (var rule in ruleset) {
if (rule === 'type') {
// 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
errors = errors.concat(Anchor.match.type(this.data, ruleset['type']));
}
// Validate a non-type rule
else {
errors = errors.concat(Anchor.match.rule(this.data, rule, ruleset[rule]));
}
}
// If errors exist, return the list of them
if (errors.length) {
return errors;
}
// No errors, so return false
else return false;
};
Anchor.prototype.hasErrors = Anchor.prototype.to;
// Coerce the data to the specified ruleset if possible

@@ -54,6 +71,3 @@ // otherwise throw an error

// Coerce the data to the specified ruleset no matter what
Anchor.prototype.hurl = function (ruleset, cb) {
// If callback is specififed, trigger it at the end
// also, handle error instead of throwing it
if (cb) this.cb = cb;
Anchor.prototype.hurl = function (ruleset) {

@@ -71,9 +85,4 @@ // Iterate trough given data attributes

// If a callback has been passed pass the error there
if(typeof cb === 'function') {
return cb(err);
}
// Or just throw it
else throw err;
// just throw it
throw err;
}

@@ -86,7 +95,2 @@ }

Anchor.match(this.data, ruleset, this);
// If a callback was specified, trigger it
// If an error object was stowed away in the ctx, pass it along
// (otherwise we never should have made it this far, the error should have been thrown)
cb && cb(this.error);
};

@@ -93,0 +97,0 @@

var _ = require('underscore');
var rules = require('./rules');
module.exports = deepMatch;
module.exports = {
type: deepMatchType,
rule: match
};

@@ -10,2 +13,64 @@ // Max depth value

/**
* Match a miscellaneous rule
* Returns an empty list on success,
* or a list of errors if things go wrong
*/
function match ( data, ruleName, args ) {
var errors = [];
// Lowercase ruleName
ruleName = ruleName.toLowerCase();
// Ensure args is a list, then prepend it with data
if ( !_.isArray(args) ) {
args = [args];
}
args.unshift(data);
// Lookup rule and determine outcome
var outcome;
var rule = rules[ruleName];
if (!rule) {
throw new Error ('Unknown rule: ' + ruleName);
}
try {
outcome = rule.apply(rule, args);
}
catch (e) {
outcome = false;
}
// If outcome is false, an error occurred
if (!outcome) return failure(data, ruleName, args);
else return [];
// On failure-- stop and get out.
// If a cb was specified, call it with a first-arity error object.
// Otherwise, return a list of error objets.
function failure() {
// Construct error message
var errMsg = '';
var argStr = _.reduce(args, function (memo, arg, i) {
// Prepend w/ comma if this isn't the first argument
return ( (i > 0) ? ',' : '' ) + arg;
}, '');
errMsg += 'Validation error: "'+data+'" ';
errMsg += 'Rule "' + ruleName + '(' + argStr + ')" failed.';
// Construct error object
return [{
data: data,
message: errMsg,
rule: ruleName,
args: args
}];
}
}
/**
*

@@ -15,10 +80,12 @@ *

* Match a complex collection or model against a schema
* Return a list of errors (or an empty list if no errors were found)
*
*
*/
function deepMatch (data, ruleset, ctx, depth, keyName) {
function deepMatchType (data, ruleset, depth, keyName) {
var errors = [];
// If ruleset is not an object or array, use the provided function to validate
if (!_.isObject(ruleset)) {
return match(data,ruleset,ctx, keyName);
return matchType(data,ruleset, keyName);
}

@@ -30,3 +97,3 @@

if (depth > maxDepth) {
throw new Error ('Depth of object being parsed exceeds maxDepth (). Maybe it links to itself?');
throw new Error ('Depth of object being parsed exceeds maxDepth (). Maybe it\'s recursively referencing itself?');
}

@@ -41,3 +108,7 @@

// Handle plurals (arrays with a schema rule)
return _.all(data, matchArray);
// Match each object in data array against ruleset until error is detected
_.each(data, function (model) {
errors = errors.concat(deepMatchType(model, ruleset[0], depth+1, keyName));
});
return errors;
}

@@ -49,23 +120,17 @@

// Don't treat empty object as a ruleset
// Instead, treat it as 'object'
if (_.keys(ruleset).length === 0) {
return match(data, ruleset, ctx, keyName);
return matchType(data, ruleset, keyName);
}
else return _.all(ruleset,matchDict);
else {
// Iterate through rules in dictionary until error is detected
_.each(ruleset, function (subRule, key) {
errors = errors.concat(deepMatchType(data[key], ruleset[key], depth+1, key));
});
return errors;
}
}
// Leaf rules land here and execute the iterator
else return match(data, ruleset, ctx, keyName);
// Iterate through rules in dictionary until error is detected
function matchDict(subRule,key) {
if (ctx && ctx.error) return false;
else return deepMatch(data[key], ruleset[key], ctx, depth+1, key);
}
// Match each object in array against ruleset until error is detected
function matchArray(model) {
if (ctx && ctx.error) return false;
else return deepMatch(model, ruleset[0], ctx, depth+1, keyName);
}
else return matchType(data, ruleset, keyName);
}

@@ -88,6 +153,6 @@

* ruleName :: (STRING)
* returns a list of errors, or an empty list in the absense of them
*/
function match (datum, ruleName, ctx, keyName) {
function matchType (datum, ruleName, keyName) {
try {

@@ -104,3 +169,3 @@ var outcome, rule;

// {} specified as data type checks for any object
rule = _.isObject;
rule = _.isObject;
}

@@ -110,4 +175,8 @@ else if (_.isRegExp(ruleName)) {

rule = function (x) {
if (!_.isString(x)) return false;
x.match(ruleName);
// If argument to regex rule is not a string,
// fail on 'string' validation
if (!_.isString(x)) {
rule = rules['string'];
}
else x.match(ruleName);
};

@@ -125,8 +194,12 @@ }

// False outcome is a failure
if (!outcome) return failure(datum,ruleName, keyName);
else return outcome;
// If validation failed, return an error
if (!outcome) {
return failure(datum,ruleName, keyName);
}
// If everything is ok, return an empty list
else return [];
}
catch (e) {
failure(datum, ruleName, keyName);
return failure(datum, ruleName, keyName);
}

@@ -136,21 +209,19 @@

// If a cb was specified, call it with a first-arity error object.
// Otherwise, throw an error.
// Otherwise, return a list of error objets.
function failure(datum, ruleName, keyName) {
// Construct error
var err = '';
err += 'Validation error: "'+datum+'" ';
err += keyName ? '('+keyName+') ' : '';
err += 'is not of type "'+ruleName+'"';
err = new Error(err);
// Construct error message
var errMsg = '';
errMsg += 'Validation error: "'+datum+'" ';
errMsg += keyName ? '('+keyName+') ' : '';
errMsg += '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;
// Construct error object
return [{
property: keyName,
data: datum,
message: errMsg,
rule: ruleName
}];
}
}

@@ -6,3 +6,7 @@ var _ = require('underscore');

// Type rules
'empty' : function (x) { return x === ''; },
'required' : function (x) { return check(x).notEmpty(); },
'notEmpty' : function (x) { return check(x).notEmpty(); },
'undefined' : _.isUndefined,

@@ -18,4 +22,8 @@

'ip' : function (x){ return check(x).isIP(); },
'ipv4' : function (x){ return check(x).isIPv4(); },
'ipv6' : function (x){ return check(x).isIPv6(); },
'creditcard': function (x){ return check(x).isCreditCard();},
'uuid' : function (x, version){ return check(x).isUUID(version);},
'uuidv3' : function (x){ return check(x).isUUIDv3();},
'uuidv4' : function (x){ return check(x).isUUIDv4();},

@@ -33,2 +41,3 @@ 'int' : function (x) { return check(x).isInt(); },

'null' : _.isNull,
'notNull' : function (x) { return check(x).notNull(); },

@@ -39,6 +48,30 @@ 'boolean' : _.isBoolean,

'date' : _.isDate,
'date' : function (x) { return check(x).isDate(); },
'hexadecimal': function (x) { return check(x).hexadecimal(); },
'hexColor': function (x) { return check(x).hexColor(); },
'lowercase': function (x) { return check(x).lowercase(); },
'uppercase': function (x) { return check(x).uppercase(); },
// Miscellaneous rules
'after' : function (x,date) { return check(x).isAfter(date); },
'before' : function (x,date) { return check(x).isBefore(date); }
'before' : function (x,date) { return check(x).isBefore(date); },
};
'is' : function (x, regex) { return check(x).is(regex); },
'regex' : function (x, regex) { return check(x).regex(regex); },
'not' : function (x, regex) { return check(x).not(regex); },
'notRegex' : function (x, regex) { return check(x).notRegex(regex); },
'equals' : function (x, equals) { return check(x).equals(equals); },
'contains' : function (x, str) { return check(x).contains(str); },
'notContains': function (x, str) { return check(x).notContains(str); },
'len' : function (x, min, max) { return check(x).len(min, max); },
'in' : function (x, arrayOrString) { return check(x).isIn(arrayOrString); },
'notIn' : function (x, arrayOrString) { return check(x).notIn(arrayOrString); },
'max' : function (x, val) { return check(x).max(val); },
'min' : function (x, val) { return check(x).min(val); },
'minLength' : function (x, min) { return check(x).len(min); },
'maxLength' : function (x, max) { return check(x).len(0, max); }
};
{
"name": "anchor",
"version": "0.3.0",
"version": "0.4.0",
"description": "Recursive validation library with support for objects and lists",

@@ -5,0 +5,0 @@ "main": "index.js",

anchor
======
> IMPORTANT: Anchor is under **active development**! Please follow/star and keep up to date as the project develops.
> If you're interested in contributing, drop me a note at @mikermcneil. I welcome your feedback, ideas, and pull requests :)
Anchor is a javascript library that lets you define strict types.
<!-- err todo: It also helps you validate and normalize the usage of command line scripts and even individual functions. -->
Anchor is a javascript library that lets you define strict types. It also helps you validate and normalize the usage of command line scripts and even individual functions.
This makes it really useful for things like:

@@ -34,2 +31,4 @@ + Form validation on the client or server

<!--
## Basic Usage

@@ -84,2 +83,4 @@ ```javascript

-->
<!--

@@ -86,0 +87,0 @@ ## Custom rules

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc