Skip to content
This repository has been archived by the owner on Dec 12, 2021. It is now read-only.

Introduce excludes for custom exclusion on top of existing validator #180

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion specs/validators/format-spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
describe("validators.format", function() {
var format = validate.validators.format.bind(validate.validators.format)
, options1 = {pattern: /^foobar$/i}
, options2 = {pattern: "^foobar$", flags: "i"};
, options2 = {pattern: "^foobar$", flags: "i"}
, options3 = {pattern: /^foobar$/i, excludes: [function (v) {
return v === '';
}]};

afterEach(function() {
delete validate.validators.format.message;
Expand All @@ -11,35 +14,44 @@ describe("validators.format", function() {
it("allows empty values", function() {
expect(format(null, options1)).not.toBeDefined();
expect(format(null, options2)).not.toBeDefined();
expect(format(null, options3)).not.toBeDefined();
expect(format(undefined, options1)).not.toBeDefined();
expect(format(undefined, options2)).not.toBeDefined();
expect(format(undefined, options3)).not.toBeDefined();
expect(format("", options3)).not.toBeDefined();
});

it("allows values that matches the pattern", function() {
expect(format("fooBAR", options1)).not.toBeDefined();
expect(format("fooBAR", options2)).not.toBeDefined();
expect(format("fooBAR", options3)).not.toBeDefined();
});

it("doesn't allow values that doesn't matches the pattern", function() {
expect(format("", options1)).toBeDefined("is invalid");
expect(format("", options2)).toBeDefined("is invalid");
expect(format(" ", options1)).toBeDefined("is invalid");
expect(format(" ", options2)).toBeDefined("is invalid");
expect(format(" ", options3)).toBeDefined("is invalid");
expect(format("barfoo", options1)).toEqual("is invalid");
expect(format("barfoo", options2)).toEqual("is invalid");
expect(format("barfoo", options3)).toBeDefined("is invalid");
});

it("non strings are not allowed", function() {
var obj = {toString: function() { return "foobar"; }};
expect(format(obj, options1)).toBeDefined();
expect(format(obj, options2)).toBeDefined();
expect(format(obj, options3)).toBeDefined();
expect(format(3, options1)).toBeDefined();
expect(format(3, options2)).toBeDefined();
expect(format(3, options3)).toBeDefined();
});

it("non strings are not allowed", function() {
expect(format(3, options1)).toBeDefined();
expect(format(3, options2)).toBeDefined();
expect(format(3, options3)).toBeDefined();
});

it("doesn't allow partial matches", function() {
Expand Down
4 changes: 4 additions & 0 deletions specs/validators/inclusion-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ describe("validators.inclusion", function() {
it("allows empty values", function() {
expect(inclusion(null, {})).not.toBeDefined();
expect(inclusion(undefined, {})).not.toBeDefined();
expect(inclusion('', {
within: within,
excludes: [function (v) { return v === ''; }],
})).not.toBeDefined();
});

it("returns nothing if the value is allowed", function() {
Expand Down
5 changes: 5 additions & 0 deletions specs/validators/numericality-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ describe("validators.numericality", function() {
it("allows empty values", function() {
expect(numericality(null, {})).not.toBeDefined();
expect(numericality(undefined, {})).not.toBeDefined();
expect(numericality('', {excludes: [{
presence: {
allowEmpty: true,
},
}]})).not.toBeDefined();
});

it("allows numbers", function() {
Expand Down
45 changes: 45 additions & 0 deletions validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,29 @@
return false;
},

shouldValueBeExcluded: function (value, hooks) {
var ret = false;

for (var i = 0; i < hooks.length; i++) {
var hook = hooks[i];

if (v.isFunction(hook)) {
// Hook is a custom function
ret = !!hook(value); // Coerce to boolean
} else if (v.isObject(hook)) {
// Hook is a constraint
// Negate results from isDefined as we are talking about exclude
ret = !v.isDefined(v.single(value, hook));
}

if (ret) {
break;
}
}

return ret;
},

// Formats the specified strings with the given values like so:
// ```
// format("Foo: %{foo}", {foo: "bar"}) // "Foo bar"
Expand Down Expand Up @@ -818,6 +841,13 @@
return;
}

// Allows users to exclude value before further processing
var hooks = options.excludes || [];
if (v.shouldValueBeExcluded(value, hooks)) {
// Return if given value should be exclude
return;
}

options = v.extend({}, this.options, options);

var errors = []
Expand Down Expand Up @@ -992,6 +1022,13 @@
return message;
}

// Allows users to exclude value before further processing
var hooks = options.excludes || [];
if (v.shouldValueBeExcluded(value, hooks)) {
// Return if given value should be exclude
return;
}

if (v.isString(pattern)) {
pattern = new RegExp(options.pattern, options.flags);
}
Expand All @@ -1008,6 +1045,14 @@
if (v.isArray(options)) {
options = {within: options};
}

// Allows users to exclude value before further processing
var hooks = options.excludes || [];
if (v.shouldValueBeExcluded(value, hooks)) {
// Return if given value should be exclude
return;
}

options = v.extend({}, this.options, options);
if (v.contains(options.within, value)) {
return;
Expand Down