Skip to content

fix multi validate with object strict remove #272

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
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
15 changes: 8 additions & 7 deletions lib/rules/multi.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,33 @@ module.exports = function({ schema, messages }, path, context) {
const src = [];

src.push(`
var prevErrLen = errors.length;
var errBefore;
var hasValid = false;
var newVal = value;
var checkErrors = [];
`);

for (let i = 0; i < schema.rules.length; i++) {
src.push(`
if (!hasValid) {
errBefore = errors.length;
var _errors = [];
`);

const rule = this.getRuleFromSchema(schema.rules[i]);
src.push(this.compileRule(rule, context, path, `var tmpVal = ${context.async ? "await " : ""}context.fn[%%INDEX%%](value, field, parent, errors, context);`, "tmpVal"));
src.push(this.compileRule(rule, context, path, `var tmpVal = ${context.async ? "await " : ""}context.fn[%%INDEX%%](value, field, parent, _errors, context);`, "tmpVal"));
src.push(`
if (errors.length == errBefore) {
if (_errors.length == 0) {
hasValid = true;
newVal = tmpVal;
} else {
Array.prototype.push.apply(checkErrors, _errors);
}
}
`);
}

src.push(`
if (hasValid) {
errors.length = prevErrLen;
if (!hasValid) {
Array.prototype.push.apply(errors, checkErrors);
}

return newVal;
Expand Down
30 changes: 18 additions & 12 deletions lib/rules/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,31 +69,37 @@ module.exports = function ({ schema, messages }, path, context) {

// Strict handler
if (schema.strict) {
sourceCode.push(`
if (errors.length === 0) {
`);
const allowedProps = Object.keys(subSchema);

sourceCode.push(`
field = parentField;
var invalidProps = [];
var props = Object.keys(parentObj);

for (let i = 0; i < props.length; i++) {
if (${JSON.stringify(allowedProps)}.indexOf(props[i]) === -1) {
invalidProps.push(props[i]);
field = parentField;
var invalidProps = [];
var props = Object.keys(parentObj);

for (let i = 0; i < props.length; i++) {
if (${JSON.stringify(allowedProps)}.indexOf(props[i]) === -1) {
invalidProps.push(props[i]);
}
}
}
if (invalidProps.length) {
if (invalidProps.length) {
`);
if (schema.strict == "remove") {
sourceCode.push(`
invalidProps.forEach(function(field) {
delete parentObj[field];
});
invalidProps.forEach(function(field) {
delete parentObj[field];
});
`);
} else {
sourceCode.push(`
${this.makeError({ type: "objectStrict", expected: "\"" + allowedProps.join(", ") + "\"", actual: "invalidProps.join(', ')", messages })}
`);
}
sourceCode.push(`
}
`);
sourceCode.push(`
}
`);
Expand Down
63 changes: 60 additions & 3 deletions test/rules/multi.spec.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"use strict";

const Validator = require("../../lib/validator");
const v = new Validator({
useNewCustomCheckerFunction: true,
});

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

Expand All @@ -31,4 +31,61 @@ describe("Test rule: multi", () => {
// it("should value equals to other field", () => {
// // TODO: move from validator.spec.js
// });

describe("object strict test", function () {
it("should pass simple test", () => {
const v = new Validator({
useNewCustomCheckerFunction: true,
});
const check = v.compile({
$$root: true,
type: "multi",
rules: ["string", "number"]
});
expect(check(1)).toBe(true);
expect(check("1")).toBe(true);
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"}]);
});
it("should pass object strict remove", () => {
const v = new Validator({
useNewCustomCheckerFunction: true,
});

v.alias("targetA", {
type: "object", strict: "remove", props: {
a: "number"
}
});

v.alias("targetB", {
type: "object", strict: "remove", props: {
b: "number"
}
});

v.alias("targetC", {
type: "object", props: {
c: "number"
}
});

const check = v.compile({
$$root: true,
type: "multi",
rules: ["targetA", "targetB", "targetC"]
});

expect(check({a: 1})).toBe(true);

const testB = {b: 2, z: 3};
expect(check(testB)).toBe(true);
expect(testB).toEqual({b: 2});

const testC = {c: 3, d: 4};
expect(check(testC)).toBe(true);
expect(testC).toEqual({c: 3, d: 4});

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"}]);
});
});
});