From 91169e3dd52ccde855f70d15c0e8cbc9bd29dcf8 Mon Sep 17 00:00:00 2001 From: John Bufe Date: Sun, 3 Apr 2016 19:06:06 -0400 Subject: [PATCH] feat(validators): Add validator for each object in an array Added a new validator, `each`, which applies a validation function provided in the options to each of the objects in the array being validated. Closes #1 --- specs/validators/each-spec.js | 71 +++++++++++++++++++++++++++++++++++ validate.js | 32 ++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 specs/validators/each-spec.js diff --git a/specs/validators/each-spec.js b/specs/validators/each-spec.js new file mode 100644 index 0000000..4cd8bbc --- /dev/null +++ b/specs/validators/each-spec.js @@ -0,0 +1,71 @@ +describe('validators.each', function() { + var each = validate.validators.each.bind(validate.validators.each); + + var isPositive = function(number) { + if (number > 0) { + return undefined; + } else { + return 'negative'; + } + }; + + afterEach(function() { + delete validate.validators.each.message; + delete validate.validators.each.options; + }); + + it("allows undefined values", function() { + expect(each(null, {})).not.toBeDefined(); + expect(each(undefined, {})).not.toBeDefined(); + }); + + it("does not allow values that aren't arrays", function() { + expect(each({}, {})).toBeDefined(); + expect(each(function () {}, {})).toBeDefined(); + expect(each("", {})).toBeDefined(); + expect(each(1, {})).toBeDefined(); + expect(each(true, {})).toBeDefined(); + }); + + it("has a default error message", function() { + expect(each({}, {})).toEqual("must be an array"); + }); + + it("allows for a message to be attached to the validator", function() { + var validatorMessage = "validatorMessage"; + validate.validators.each.message = validatorMessage; + expect(each({}, {})).toEqual(validatorMessage); + }); + + it("allows for a message to be passed as an option to override ", function() { + var optionMessage = "optionMessage"; + validate.validators.each.message = "validatorMessage"; + expect(each({}, {message : optionMessage})).toEqual(optionMessage); + }); + + it("accepts the value if no validator function is provided", function () { + expect(each([], {})).not.toBeDefined(); + expect(each([], {validator : {}})).not.toBeDefined(); + expect(each([], {validator : ""})).not.toBeDefined(); + expect(each([], {validator : 1})).not.toBeDefined(); + expect(each([], {validator : []})).not.toBeDefined(); + expect(each([], {validator : true})).not.toBeDefined(); + expect(each([], {validator : null})).not.toBeDefined(); + }); + + it("accepts an empty array", function () { + expect(each([], {validator : function () {}})).not.toBeDefined(); + expect(each([], {validator : function () {return 'error';}})).not.toBeDefined(); + }); + + it("accepts a valid array", function () { + var array = [1, 2, 3, 4, 5]; + expect(each(array, {validator : isPositive})).not.toBeDefined(); + }); + + it("returns an array of errors if anything fails", function () { + var array = [-1, 2, 3, 4, 5]; + expect(each(array, {validator : isPositive})).toEqual(['negative', undefined, undefined, undefined, undefined]); + }); + +}); diff --git a/validate.js b/validate.js index 1182cf4..a1d97ae 100644 --- a/validate.js +++ b/validate.js @@ -1127,6 +1127,38 @@ if (!PATTERN.exec(value)) { return message; } + }, + + each: function(value, options) { + // Allow null and undefined values + if (!v.isDefined(value)) { + return; + } + + options = v.extend({}, this.options, options); + + if (!v.isArray(value)) { + return options.message || this.message || "must be an array"; + } + + if (!v.isFunction(options.validator)) { + return; + } + + var errors = []; + var numErrors = 0; + value.forEach(function validateEach (data) { + var error = options.validator(data); + errors.push(error); + if (error) { + numErrors++; + } + }); + if (numErrors > 0) { + return errors; + } else { + return; + } } };