Skip to content

Commit a3421ed

Browse files
authored
Merge pull request #272 from 0x0a0d/fix_multi_validator_with_object_strict_remove
fix multi validate with object strict remove
2 parents 8601a67 + 0a90f14 commit a3421ed

File tree

3 files changed

+86
-22
lines changed

3 files changed

+86
-22
lines changed

lib/rules/multi.js

+8-7
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,33 @@ module.exports = function({ schema, messages }, path, context) {
66
const src = [];
77

88
src.push(`
9-
var prevErrLen = errors.length;
10-
var errBefore;
119
var hasValid = false;
1210
var newVal = value;
11+
var checkErrors = [];
1312
`);
1413

1514
for (let i = 0; i < schema.rules.length; i++) {
1615
src.push(`
1716
if (!hasValid) {
18-
errBefore = errors.length;
17+
var _errors = [];
1918
`);
2019

2120
const rule = this.getRuleFromSchema(schema.rules[i]);
22-
src.push(this.compileRule(rule, context, path, `var tmpVal = ${context.async ? "await " : ""}context.fn[%%INDEX%%](value, field, parent, errors, context);`, "tmpVal"));
21+
src.push(this.compileRule(rule, context, path, `var tmpVal = ${context.async ? "await " : ""}context.fn[%%INDEX%%](value, field, parent, _errors, context);`, "tmpVal"));
2322
src.push(`
24-
if (errors.length == errBefore) {
23+
if (_errors.length == 0) {
2524
hasValid = true;
2625
newVal = tmpVal;
26+
} else {
27+
Array.prototype.push.apply(checkErrors, _errors);
2728
}
2829
}
2930
`);
3031
}
3132

3233
src.push(`
33-
if (hasValid) {
34-
errors.length = prevErrLen;
34+
if (!hasValid) {
35+
Array.prototype.push.apply(errors, checkErrors);
3536
}
3637
3738
return newVal;

lib/rules/object.js

+18-12
Original file line numberDiff line numberDiff line change
@@ -69,31 +69,37 @@ module.exports = function ({ schema, messages }, path, context) {
6969

7070
// Strict handler
7171
if (schema.strict) {
72+
sourceCode.push(`
73+
if (errors.length === 0) {
74+
`);
7275
const allowedProps = Object.keys(subSchema);
7376

7477
sourceCode.push(`
75-
field = parentField;
76-
var invalidProps = [];
77-
var props = Object.keys(parentObj);
78-
79-
for (let i = 0; i < props.length; i++) {
80-
if (${JSON.stringify(allowedProps)}.indexOf(props[i]) === -1) {
81-
invalidProps.push(props[i]);
78+
field = parentField;
79+
var invalidProps = [];
80+
var props = Object.keys(parentObj);
81+
82+
for (let i = 0; i < props.length; i++) {
83+
if (${JSON.stringify(allowedProps)}.indexOf(props[i]) === -1) {
84+
invalidProps.push(props[i]);
85+
}
8286
}
83-
}
84-
if (invalidProps.length) {
87+
if (invalidProps.length) {
8588
`);
8689
if (schema.strict == "remove") {
8790
sourceCode.push(`
88-
invalidProps.forEach(function(field) {
89-
delete parentObj[field];
90-
});
91+
invalidProps.forEach(function(field) {
92+
delete parentObj[field];
93+
});
9194
`);
9295
} else {
9396
sourceCode.push(`
9497
${this.makeError({ type: "objectStrict", expected: "\"" + allowedProps.join(", ") + "\"", actual: "invalidProps.join(', ')", messages })}
9598
`);
9699
}
100+
sourceCode.push(`
101+
}
102+
`);
97103
sourceCode.push(`
98104
}
99105
`);

test/rules/multi.spec.js

+60-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
"use strict";
22

33
const Validator = require("../../lib/validator");
4-
const v = new Validator({
5-
useNewCustomCheckerFunction: true,
6-
});
74

85
describe("Test rule: multi", () => {
6+
const v = new Validator({
7+
useNewCustomCheckerFunction: true,
8+
});
99
it("should call item's custom checker function", () => {
1010
const fn = jest.fn((v) => v);
1111

@@ -31,4 +31,61 @@ describe("Test rule: multi", () => {
3131
// it("should value equals to other field", () => {
3232
// // TODO: move from validator.spec.js
3333
// });
34+
35+
describe("object strict test", function () {
36+
it("should pass simple test", () => {
37+
const v = new Validator({
38+
useNewCustomCheckerFunction: true,
39+
});
40+
const check = v.compile({
41+
$$root: true,
42+
type: "multi",
43+
rules: ["string", "number"]
44+
});
45+
expect(check(1)).toBe(true);
46+
expect(check("1")).toBe(true);
47+
expect(check({a: 1})).toEqual([{"actual": {"a": 1}, "field": undefined, "message": "The '' field must be a string.", "type": "string"}, {"actual": {"a": 1}, "field": undefined, "message": "The '' field must be a number.", "type": "number"}]);
48+
});
49+
it("should pass object strict remove", () => {
50+
const v = new Validator({
51+
useNewCustomCheckerFunction: true,
52+
});
53+
54+
v.alias("targetA", {
55+
type: "object", strict: "remove", props: {
56+
a: "number"
57+
}
58+
});
59+
60+
v.alias("targetB", {
61+
type: "object", strict: "remove", props: {
62+
b: "number"
63+
}
64+
});
65+
66+
v.alias("targetC", {
67+
type: "object", props: {
68+
c: "number"
69+
}
70+
});
71+
72+
const check = v.compile({
73+
$$root: true,
74+
type: "multi",
75+
rules: ["targetA", "targetB", "targetC"]
76+
});
77+
78+
expect(check({a: 1})).toBe(true);
79+
80+
const testB = {b: 2, z: 3};
81+
expect(check(testB)).toBe(true);
82+
expect(testB).toEqual({b: 2});
83+
84+
const testC = {c: 3, d: 4};
85+
expect(check(testC)).toBe(true);
86+
expect(testC).toEqual({c: 3, d: 4});
87+
88+
expect(check({d: 4})).toEqual([{"actual": undefined, "field": "a", "message": "The 'a' field is required.", "type": "required"}, {"actual": undefined, "field": "b", "message": "The 'b' field is required.", "type": "required"}, {"actual": undefined, "field": "c", "message": "The 'c' field is required.", "type": "required"}]);
89+
});
90+
});
3491
});

0 commit comments

Comments
 (0)