Skip to content

Commit 78d3624

Browse files
authored
Merge pull request #23 from mauricedoepke/master
fixes #22
2 parents 4364ce2 + 7017cf7 commit 78d3624

File tree

2 files changed

+296
-3
lines changed

2 files changed

+296
-3
lines changed

lib/validator.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,15 @@ Validator.prototype._processRule = function(rule, name, iterate) {
109109
throw new Error("Invalid '" + rule.type + "' type in validator schema!");
110110
}
111111

112+
113+
/**
114+
* !IMPORTANT!: For the functioning of multiRule cases it is important that
115+
* pushing of object and array special rules is done in directly after this
116+
* simple rule.
117+
* If you which to push other checks, do it before the simple ones or after
118+
* the array special case.
119+
* See the comments in _checkWrapper for further explanation.
120+
*/
112121
checks.push({
113122
fn: this.rules[rule.type],
114123
type: rule.type,
@@ -125,7 +134,8 @@ Validator.prototype._processRule = function(rule, name, iterate) {
125134
type: rule.type,
126135
name: name,
127136
schema: rule,
128-
iterate: iterate
137+
iterate: iterate,
138+
secondPart: true //first part is the "primitive" typeof check above
129139
});
130140
}
131141

@@ -137,7 +147,8 @@ Validator.prototype._processRule = function(rule, name, iterate) {
137147
type: rule.type,
138148
name: name,
139149
schema: rule,
140-
iterate: true
150+
iterate: true,
151+
secondPart: true //first part is the "primitive" typeof check above
141152
});
142153
}
143154

@@ -181,18 +192,37 @@ Validator.prototype._checkWrapper = function(rules, isMultipleRules) {
181192
} else {
182193
// Call the checker function
183194
if (check.iterate) {
195+
let errorInCurrentArray = false;
184196
const l = value.length;
185197
for (let i = 0; i < l; i++) {
186198
let _stack = stack + "[" + i + "]";
187199
let res = check.fn.call(self, value[i], schema, _stack, obj);
188-
if (res !== true)
200+
if (res !== true) {
201+
errorInCurrentArray = true;
189202
self.handleResult(errors, _stack, res);
203+
}
204+
}
205+
/**
206+
* If this is second part of a multiRule array check and the array
207+
* is valid, then the rule is valid.
208+
*/
209+
if (!errorInCurrentArray && isMultipleRules && check.secondPart) {
210+
return true;
190211
}
191212
} else {
192213
let res = check.fn.call(self, value, schema, stack, obj);
193214

194215
if (isMultipleRules) {
195216
if (res === true) {
217+
/**
218+
* Object and array checks are divided into two internal checks. In case of a multiRule
219+
* we have to make sure to check both parts. Thus we we continue to also do the second
220+
* check if their is one.
221+
*/
222+
const nextRule = rules[i+1]
223+
if (nextRule && nextRule.secondPart){
224+
continue;
225+
}
196226
// Jump out after first success and clear previous errors
197227
return true;
198228
}

test/validator.spec.js

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,3 +631,266 @@ describe("Test multiple rules", () => {
631631
});
632632

633633
});
634+
635+
describe("Test multiple rules with objects", () => {
636+
const v = new Validator();
637+
638+
let schema = {
639+
list: [
640+
{
641+
type: "object",
642+
props: {
643+
name: {type: "string"},
644+
age: {type: "number"},
645+
}
646+
},
647+
{
648+
type: "object",
649+
props: {
650+
country: {type: "string"},
651+
code: {type: "string"},
652+
}
653+
}
654+
]
655+
};
656+
657+
let check = v.compile(schema);
658+
659+
it("should give true if first object is given", () => {
660+
let obj = { list: {
661+
name: "Joe",
662+
age: 34
663+
} };
664+
665+
let res = check(obj);
666+
667+
expect(res).toBe(true);
668+
});
669+
670+
it("should give true if second object is given", () => {
671+
let obj = { list: {
672+
country: "germany",
673+
code: "de"
674+
}};
675+
676+
let res = check(obj);
677+
678+
expect(res).toBe(true);
679+
});
680+
681+
it("should give error if the object is broken", () => {
682+
let obj = { list: {
683+
name: "Average",
684+
age: "Joe"
685+
} };
686+
687+
let res = check(obj);
688+
689+
expect(res).toBeInstanceOf(Array);
690+
expect(res.length).toBe(3);
691+
expect(res[0].type).toBe("number");
692+
expect(res[0].field).toBe("list.age");
693+
694+
expect(res[1].type).toBe("required");
695+
expect(res[1].field).toBe("list.country");
696+
});
697+
698+
it("should give error if the object is only partly given", () => {
699+
let obj = { list: {} };
700+
let res = check(obj);
701+
702+
expect(res).toBeInstanceOf(Array);
703+
expect(res.length).toBe(4);
704+
expect(res[0].type).toBe("required");
705+
expect(res[0].field).toBe("list.name");
706+
707+
expect(res[1].type).toBe("required");
708+
expect(res[1].field).toBe("list.age");
709+
710+
});
711+
712+
});
713+
714+
describe("Test multiple rules with objects within array", () => {
715+
const v = new Validator();
716+
717+
let schema = {
718+
list: {
719+
type: "array",
720+
items: [
721+
{
722+
type: "object",
723+
props: {
724+
name: {type: "string"},
725+
age: {type: "number"},
726+
}
727+
},
728+
{
729+
type: "object",
730+
props: {
731+
country: {type: "string"},
732+
code: {type: "string"},
733+
}
734+
}
735+
]
736+
}
737+
};
738+
739+
let check = v.compile(schema);
740+
741+
it("should give true if one valid object is given", () => {
742+
let obj = { list: [
743+
{
744+
name: "Joe",
745+
age: 34
746+
}
747+
]};
748+
let res = check(obj);
749+
expect(res).toBe(true);
750+
751+
let obj2 = { list: [
752+
{
753+
country: "germany",
754+
code: "de"
755+
}
756+
]};
757+
let res2 = check(obj2);
758+
expect(res2).toBe(true);
759+
});
760+
761+
it("should give true if three valid objects given", () => {
762+
let obj = { list: [
763+
{
764+
name: "Joe",
765+
age: 34
766+
},
767+
{
768+
country: "germany",
769+
code: "de"
770+
},
771+
{
772+
country: "hungary",
773+
code: "hu"
774+
}
775+
]};
776+
let res = check(obj);
777+
expect(res).toBe(true);
778+
});
779+
780+
it("should give error if one object is broken", () => {
781+
let obj = { list: [
782+
{
783+
name: "Joe",
784+
age: 34
785+
},
786+
{
787+
country: "germany",
788+
},
789+
{
790+
country: "hungary",
791+
code: "hu"
792+
}
793+
]};
794+
795+
let res = check(obj);
796+
797+
expect(res).toBeInstanceOf(Array);
798+
expect(res.length).toBe(3);
799+
expect(res[0].type).toBe("required");
800+
expect(res[0].field).toBe("list[1].name");
801+
802+
expect(res[1].type).toBe("required");
803+
expect(res[1].field).toBe("list[1].age");
804+
});
805+
806+
it("should give error if one object is empty", () => {
807+
let obj = { list: [
808+
{
809+
name: "Joe",
810+
age: 34
811+
},
812+
{
813+
country: "hungary",
814+
code: "hu"
815+
},
816+
{
817+
}
818+
]};
819+
820+
let res = check(obj);
821+
822+
expect(res).toBeInstanceOf(Array);
823+
expect(res.length).toBe(4);
824+
expect(res[0].type).toBe("required");
825+
expect(res[0].field).toBe("list[2].name");
826+
827+
expect(res[1].type).toBe("required");
828+
expect(res[1].field).toBe("list[2].age");
829+
830+
});
831+
832+
});
833+
834+
describe("Test multiple rules with arrays", () => {
835+
const v = new Validator();
836+
837+
let schema = {
838+
list: [
839+
{
840+
type: "array",
841+
items: "string"
842+
},
843+
{
844+
type: "array",
845+
items: "number"
846+
}
847+
]
848+
};
849+
850+
let check = v.compile(schema);
851+
852+
it("should give true if first array is given", () => {
853+
let obj = { list: ["hello", "there", "this", "is", "a", "test"] };
854+
855+
let res = check(obj);
856+
857+
expect(res).toBe(true);
858+
});
859+
860+
it("should give true if second array is given", () => {
861+
let obj = { list: [1, 3, 3, 7] };
862+
863+
let res = check(obj);
864+
865+
expect(res).toBe(true);
866+
});
867+
868+
it("should give error if the array is broken", () => {
869+
let obj = { list: ["hello", 3] };
870+
871+
let res = check(obj);
872+
873+
expect(res).toBeInstanceOf(Array);
874+
expect(res.length).toBe(2);
875+
expect(res[0].type).toBe("string");
876+
expect(res[0].field).toBe("list[1]");
877+
878+
expect(res[1].type).toBe("number");
879+
expect(res[1].field).toBe("list[0]");
880+
});
881+
882+
it("should give error if the array is broken", () => {
883+
let obj = { list: [true, false] };
884+
let res = check(obj);
885+
886+
expect(res).toBeInstanceOf(Array);
887+
expect(res.length).toBe(4);
888+
expect(res[0].type).toBe("string");
889+
expect(res[0].field).toBe("list[0]");
890+
891+
expect(res[1].type).toBe("string");
892+
expect(res[1].field).toBe("list[1]");
893+
894+
});
895+
896+
});

0 commit comments

Comments
 (0)