fastest-validator
Advanced tools
Comparing version 0.2.0 to 0.3.0
@@ -32,3 +32,3 @@ module.exports = { | ||
"no-console": [ | ||
"off" | ||
"error" | ||
], | ||
@@ -35,0 +35,0 @@ "no-unused-vars": [ |
@@ -6,20 +6,6 @@ "use strict"; | ||
messages: { | ||
stringMin: "A '{name}' mező túl rövid. Minimum: {0}, Jelenleg: {1}" | ||
stringMin: "A(z) '{name}' mező túl rövid. Minimum: {0}, Jelenleg: {1}" | ||
} | ||
}); | ||
/* | ||
v.add("url", (value, schema) => { | ||
const PATTERN = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g; | ||
if (typeof value !== "string") { | ||
return { msg: "string" }; | ||
} | ||
if (!PATTERN.test(value)) { | ||
return { msg: "url" } | ||
} | ||
return true; | ||
});*/ | ||
const schema = { | ||
@@ -33,4 +19,14 @@ id: { type: "number", min: 1, max: 100 }, | ||
sex: { type: "string", enum: ["male", "female"] }, | ||
roles: { type: "array", enum: ["admin", "user"] }, | ||
//comments: { type: "array", items: { type: "object" } }, | ||
roles: { type: "array", items: { type: "string" }, enum: ["admin", "user"] }, | ||
friends: { type: "array", items: { type: "number", positive: true }}, | ||
comments: { type: "array", items: { type: "object", props: { | ||
user: { type: "number", positive: true, integer: true }, | ||
content: { type: "string" }, | ||
voters: { type: "array", optional: true, items: { type: "number", optional: true }} | ||
} } }, | ||
multiarray: { type: "array", empty: false, items: { | ||
type: "array", empty: true, items: { | ||
type: "number" | ||
} | ||
}}, | ||
email: { type: "email", optional: true }, | ||
@@ -55,2 +51,25 @@ homepage: { type: "url", optional: true }, | ||
], | ||
friends: [ | ||
5, | ||
10, | ||
2 | ||
], | ||
comments: [ | ||
{ user: 1, content: "Cool!" }, | ||
{ user: 2, content: "Very fast!" }, | ||
{ user: 1, content: "", voters: [1] } | ||
], | ||
multiarray: [ | ||
[ | ||
], | ||
[ | ||
5, | ||
10, | ||
"a" | ||
] | ||
], | ||
email: "john.doe@clipboard.space", | ||
@@ -57,0 +76,0 @@ homepage: "http://google.com", |
"use strict"; | ||
const PRECISE_PATTERN = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; | ||
const QUICK_PATTERN = /^\S+@\S+\.\S+$/; | ||
const BASIC_PATTERN = /^\S+@\S+\.\S+$/; | ||
/* | ||
Alternative: | ||
http://codereview.stackexchange.com/questions/38305/validating-email-without-regex | ||
*/ | ||
module.exports = function checkEmail(value, schema) { | ||
@@ -17,7 +12,6 @@ if (typeof value !== "string") { | ||
let pattern; | ||
if (schema.mode == "precise") | ||
pattern = PRECISE_PATTERN; | ||
else | ||
pattern = QUICK_PATTERN; | ||
pattern = BASIC_PATTERN; | ||
@@ -29,2 +23,2 @@ if (!pattern.test(value)) { | ||
return true; | ||
}; | ||
}; |
"use strict"; | ||
let defaultsDeep = require("lodash/defaultsDeep"); | ||
let flatten = require("lodash/flatten"); | ||
let defaultMessages = require("./messages"); | ||
@@ -46,53 +47,104 @@ let glob = require("glob"); | ||
*/ | ||
Validator.prototype.compile = function(schema, parentPath) { | ||
Validator.prototype.compile = function(schema) { | ||
const self = this; | ||
let rules; | ||
// Process the whole schema | ||
if (Array.isArray(schema)) { | ||
if (schema.length !== 1) | ||
throw new Error("If the schema is an Array, must be only one element!"); | ||
rules = self._processRule(schema[0], null, false); | ||
} else if (schema != null && typeof schema === "object") { | ||
rules = flatten(Object.keys(schema).map(name => self._processRule(schema[name], name, false))); | ||
} else | ||
throw new Error("Invalid schema!"); | ||
return this._checkWrapper(rules); | ||
}; | ||
/** | ||
* Process a rule item & return checker functions | ||
* | ||
* @param {Object} rule | ||
* @param {String} name | ||
* @param {Boolean} iterate | ||
*/ | ||
Validator.prototype._processRule = function(rule, name, iterate) { | ||
let checks = []; | ||
Object.keys(schema).forEach(name => { | ||
const path = parentPath ? [parentPath, name].join(".") : name; | ||
let rule = schema[name]; | ||
if (typeof rule === "string") { | ||
rule = { | ||
type: rule | ||
}; | ||
} | ||
if (typeof rule === "string") { | ||
rule = { | ||
type: rule | ||
}; | ||
} | ||
if (this.rules[rule.type]) { | ||
checks.push({ | ||
fn: this.rules[rule.type], | ||
type: rule.type, | ||
name: name, | ||
schema: rule, | ||
path: path | ||
}); | ||
} else | ||
throw new Error("Invalid '" + rule.type + "' type in validator schema!"); | ||
if (this.rules[rule.type]) { | ||
checks.push({ | ||
fn: this.rules[rule.type], | ||
type: rule.type, | ||
name: name, | ||
schema: rule, | ||
iterate: iterate | ||
}); | ||
} else | ||
throw new Error("Invalid '" + rule.type + "' type in validator schema!"); | ||
// Nested schema | ||
if (rule.type === "object" && rule.props) { | ||
// Compile the child schema | ||
checks.push({ | ||
fn: this.compile(rule.props, path), | ||
type: rule.type, | ||
name: name, | ||
schema: rule, | ||
path: path | ||
}); | ||
} | ||
}); | ||
// Nested schema | ||
if (rule.type === "object" && rule.props) { | ||
// Compile the child schema | ||
checks.push({ | ||
fn: this.compile(rule.props), | ||
type: rule.type, | ||
name: name, | ||
schema: rule, | ||
iterate: iterate | ||
}); | ||
} | ||
// Array schema | ||
if (rule.type === "array" && rule.items) { | ||
// Compile the array schema | ||
checks.push({ | ||
fn: this._checkWrapper(this._processRule(rule.items, null, false)), | ||
type: rule.type, | ||
name: name, | ||
schema: rule, | ||
iterate: true | ||
}); | ||
} | ||
return checks; | ||
}; | ||
/** | ||
* Create a wrapper function for compiled schema. | ||
* | ||
* @param {Array} rules | ||
*/ | ||
Validator.prototype._checkWrapper = function(rules) { | ||
const self = this; | ||
// Compiled validator function | ||
return function(obj) { | ||
return function(obj, _schema, pathStack) { | ||
let errors = []; | ||
const count = checks.length; | ||
const count = rules.length; | ||
for (let i = 0; i < count; i++) { | ||
const check = checks[i]; | ||
const check = rules[i]; | ||
const schema = check.schema; | ||
const value = obj[check.name]; | ||
let value; | ||
let stack; | ||
if (check.name) { | ||
value = obj[check.name]; | ||
stack = (pathStack ? pathStack + "." : "") + check.name; | ||
} else { | ||
value = obj; | ||
stack = pathStack ? pathStack : ""; | ||
} | ||
// Check required fields | ||
if ((value === undefined || value === null) && check.type !== "forbidden") { | ||
if (schema.optional !== true) { | ||
self.handleResult(errors, check.path, self.makeError("required")); | ||
self.handleResult(errors, stack, self.makeError("required")); | ||
} else | ||
@@ -103,5 +155,15 @@ continue; | ||
// Call the checker function | ||
let res = check.fn.call(self, value, schema); | ||
if (res !== true) | ||
self.handleResult(errors, check.path, res); | ||
if (check.iterate) { | ||
const l = value.length; | ||
for (let i = 0; i < l; i++) { | ||
let _stack = stack + "[" + i + "]"; | ||
let res = check.fn.call(self, value[i], schema, _stack); | ||
if (res !== true) | ||
self.handleResult(errors, _stack, res); | ||
} | ||
} else { | ||
let res = check.fn.call(self, value, schema, stack); | ||
if (res !== true) | ||
self.handleResult(errors, stack, res); | ||
} | ||
} | ||
@@ -108,0 +170,0 @@ } |
{ | ||
"name": "fastest-validator", | ||
"version": "0.1.0", | ||
"version": "0.3.0", | ||
"dependencies": { | ||
@@ -5,0 +5,0 @@ "balanced-match": { |
{ | ||
"name": "fastest-validator", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "The fastest JS validator library for NodeJS", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -14,2 +14,4 @@ "use strict"; | ||
expect(v.add).toBeInstanceOf(Function); | ||
expect(Object.keys(v.rules).length).toBe(11); | ||
}); | ||
@@ -79,3 +81,3 @@ | ||
expect(validFn).toHaveBeenCalledTimes(1); | ||
expect(validFn).toHaveBeenCalledWith(5, schema.a); | ||
expect(validFn).toHaveBeenCalledWith(5, schema.a, "a"); | ||
}); | ||
@@ -86,3 +88,2 @@ | ||
describe("Test resolveMessage", () => { | ||
const v = new Validator(); | ||
@@ -103,5 +104,139 @@ | ||
describe("Test compile (unit test)", () => { | ||
describe("Test compile", () => { | ||
const v = new Validator(); | ||
v._processRule = jest.fn(); | ||
it("should call processRule", () => { | ||
v.compile({ | ||
id: { type: "number" }, | ||
name: { type: "string", min: 5}, | ||
status: "boolean" | ||
}); | ||
expect(v._processRule).toHaveBeenCalledTimes(3); | ||
expect(v._processRule).toHaveBeenCalledWith({"type": "number"}, "id", false); | ||
expect(v._processRule).toHaveBeenCalledWith({"type": "string", "min": 5}, "name", false); | ||
expect(v._processRule).toHaveBeenCalledWith("boolean", "status", false); | ||
}); | ||
it("should call processRule for root-level array", () => { | ||
v._processRule.mockClear(); | ||
v.compile([{ type: "array", items: "number" }]); | ||
expect(v._processRule).toHaveBeenCalledTimes(1); | ||
expect(v._processRule).toHaveBeenCalledWith({"type": "array", items: "number"}, null, false); | ||
}); | ||
it("should throw error is the schema is null", () => { | ||
expect(() => { | ||
v.compile(); | ||
}).toThrowError("Invalid schema!"); | ||
expect(() => { | ||
v.compile(null); | ||
}).toThrowError("Invalid schema!"); | ||
expect(() => { | ||
v.compile("Nothing"); | ||
}).toThrowError("Invalid schema!"); | ||
expect(() => { | ||
v.compile(1); | ||
}).toThrowError("Invalid schema!"); | ||
}); | ||
it("should throw error is the schema array element count is not 1", () => { | ||
expect(() => { | ||
v.compile([]); | ||
}).toThrowError(); | ||
expect(() => { | ||
v.compile([], []); | ||
}).toThrowError(); | ||
}); | ||
}); | ||
describe("Test _processRule", () => { | ||
const v = new Validator(); | ||
v.compile = jest.fn(); | ||
v._checkWrapper = jest.fn(); | ||
it("should return array of rules", () => { | ||
let res = v._processRule({ type: "number", positive: true }, "id", false); | ||
expect(res).toBeInstanceOf(Array); | ||
expect(res.length).toBe(1); | ||
expect(res[0].fn).toBeInstanceOf(Function); | ||
expect(res[0].type).toBe("number"); | ||
expect(res[0].name).toBe("id"); | ||
expect(res[0].schema).toEqual({ type: "number", positive: true }); | ||
expect(res[0].iterate).toBe(false); | ||
}); | ||
it("should convert shorthand definition", () => { | ||
let res = v._processRule("string", "name", false); | ||
expect(res).toBeInstanceOf(Array); | ||
expect(res.length).toBe(1); | ||
expect(res[0].fn).toBeInstanceOf(Function); | ||
expect(res[0].type).toBe("string"); | ||
expect(res[0].name).toBe("name"); | ||
expect(res[0].schema).toEqual({ type: "string" }); | ||
expect(res[0].iterate).toBe(false); | ||
}); | ||
it("should throw error if the type is invalid", () => { | ||
expect(() => { | ||
v._processRule({ type: "unknow" }, "id", false); | ||
}).toThrowError("Invalid 'unknow' type in validator schema!"); | ||
}); | ||
it("should call compile if type is object", () => { | ||
let res = v._processRule({ type: "object", props: { | ||
id: "number" | ||
} }, "item", false); | ||
expect(res).toBeInstanceOf(Array); | ||
expect(res.length).toBe(2); | ||
expect(res[0].fn).toBeInstanceOf(Function); | ||
expect(res[0].type).toBe("object"); | ||
expect(res[0].name).toBe("item"); | ||
expect(res[0].iterate).toBe(false); | ||
//expect(res[1].fn).toBeInstanceOf(Function); | ||
expect(res[1].type).toBe("object"); | ||
expect(res[1].name).toBe("item"); | ||
expect(res[1].iterate).toBe(false); | ||
expect(v.compile).toHaveBeenCalledTimes(1); | ||
expect(v.compile).toHaveBeenCalledWith({id: "number"}); | ||
}); | ||
it("should call checkWrapper & processRule if type is Array", () => { | ||
let res = v._processRule({ type: "array", items: "number" }, "list", false); | ||
expect(res).toBeInstanceOf(Array); | ||
expect(res.length).toBe(2); | ||
expect(res[0].fn).toBeInstanceOf(Function); | ||
expect(res[0].type).toBe("array"); | ||
expect(res[0].name).toBe("list"); | ||
expect(res[0].iterate).toBe(false); | ||
//expect(res[1].fn).toBeInstanceOf(Function); | ||
expect(res[1].type).toBe("array"); | ||
expect(res[1].name).toBe("list"); | ||
expect(res[1].iterate).toBe(true); | ||
expect(v._checkWrapper).toHaveBeenCalledTimes(1); | ||
expect(v._checkWrapper).toHaveBeenCalledWith([{"fn": expect.any(Function), "iterate": false, "name": null, "schema": {"type": "number"}, "type": "number"}]); | ||
}); | ||
}); | ||
describe("Test compile (integration test)", () => { | ||
describe("Test check generator with good obj", () => { | ||
@@ -131,6 +266,6 @@ | ||
expect(v.rules.number).toHaveBeenCalledTimes(1); | ||
expect(v.rules.number).toHaveBeenCalledWith(5, schema.id); | ||
expect(v.rules.number).toHaveBeenCalledWith(5, schema.id, "id"); | ||
expect(v.rules.string).toHaveBeenCalledTimes(1); | ||
expect(v.rules.string).toHaveBeenCalledWith("John", schema.name); | ||
expect(v.rules.string).toHaveBeenCalledWith("John", schema.name, "name"); | ||
}); | ||
@@ -140,3 +275,3 @@ | ||
describe("Test check generator with simple def schema", () => { | ||
describe("Test check generator with shorthand schema", () => { | ||
@@ -165,6 +300,6 @@ const v = new Validator(); | ||
expect(v.rules.number).toHaveBeenCalledTimes(1); | ||
expect(v.rules.number).toHaveBeenCalledWith(5, { type: "number" }); | ||
expect(v.rules.number).toHaveBeenCalledWith(5, { type: "number" }, "id"); | ||
expect(v.rules.string).toHaveBeenCalledTimes(1); | ||
expect(v.rules.string).toHaveBeenCalledWith("John", { type: "string" }); | ||
expect(v.rules.string).toHaveBeenCalledWith("John", { type: "string" }, "name"); | ||
}); | ||
@@ -210,17 +345,2 @@ | ||
describe("Test exception for unknow types", () => { | ||
const v = new Validator(); | ||
const schema = { | ||
name: { type: "unknow" } | ||
}; | ||
it("should throw exception", () => { | ||
expect(() => { | ||
v.compile(schema); | ||
}).toThrowError("Invalid 'unknow' type in validator schema!"); | ||
}); | ||
}); | ||
}); | ||
@@ -325,2 +445,182 @@ | ||
}); | ||
describe("Test nested array", () => { | ||
const v = new Validator(); | ||
let schema = { | ||
arr1: { type: "array", items: { | ||
type: "array", empty: false, items: { | ||
type: "number" | ||
} | ||
}} | ||
}; | ||
let check = v.compile(schema); | ||
it("should give true if obj is valid", () => { | ||
let obj = { | ||
arr1: [ | ||
[ | ||
5, | ||
10 | ||
], | ||
[ | ||
1, | ||
2 | ||
] | ||
] | ||
}; | ||
let res = check(obj); | ||
expect(res).toBe(true); | ||
}); | ||
it("should give error 'not a number'", () => { | ||
let obj = { | ||
arr1: [ | ||
[ | ||
5, | ||
10 | ||
], | ||
[ | ||
"1", | ||
2 | ||
] | ||
] | ||
}; | ||
let res = check(obj); | ||
expect(res.length).toBe(1); | ||
expect(res[0].type).toBe("number"); | ||
expect(res[0].field).toBe("arr1[1][0]"); | ||
}); | ||
it("should give error 'empty array'", () => { | ||
let obj = { | ||
arr1: [ | ||
[ | ||
], | ||
[ | ||
1, | ||
2 | ||
] | ||
] | ||
}; | ||
let res = check(obj); | ||
expect(res.length).toBe(1); | ||
expect(res[0].type).toBe("arrayEmpty"); | ||
expect(res[0].field).toBe("arr1[0]"); | ||
}); | ||
}); | ||
describe("Test 3-level array", () => { | ||
const v = new Validator(); | ||
let schema = { | ||
arr1: { type: "array", items: { | ||
type: "array", items: { | ||
type: "array", items: "string" | ||
} | ||
}} | ||
}; | ||
let check = v.compile(schema); | ||
it("should give true if obj is valid", () => { | ||
let obj = { | ||
arr1: [ | ||
[ | ||
[ "apple", "peach" ], | ||
[ "pineapple", "plum" ] | ||
], | ||
[ | ||
[ "orange", "lemon", "lime"] | ||
] | ||
] | ||
}; | ||
let res = check(obj); | ||
expect(res).toBe(true); | ||
}); | ||
it("should give error 'not a string'", () => { | ||
let obj = { | ||
arr1: [ | ||
[ | ||
[ "apple", "peach" ], | ||
[ "pineapple", "plum" ] | ||
], | ||
[ | ||
[ "orange", {}, "lime"] | ||
] | ||
] | ||
}; | ||
let res = check(obj); | ||
expect(res.length).toBe(1); | ||
expect(res[0].type).toBe("string"); | ||
expect(res[0].field).toBe("arr1[1][0][1]"); | ||
}); | ||
}); | ||
describe("Test root-level array", () => { | ||
const v = new Validator(); | ||
let schema = [{ type: "array", items: { | ||
type: "object", props: { | ||
id: "number", | ||
name: "string" | ||
} | ||
}}]; | ||
let check = v.compile(schema); | ||
it("should give true if obj is valid", () => { | ||
let obj = [ | ||
{ id: 1, name: "John" }, | ||
{ id: 2, name: "Jane" }, | ||
{ id: 3, name: "James" } | ||
]; | ||
let res = check(obj); | ||
expect(res).toBe(true); | ||
}); | ||
it("should give error if an element is not object", () => { | ||
let obj = [ | ||
{ id: 1, name: "John" }, | ||
{ id: 2, name: "Jane" }, | ||
123 | ||
]; | ||
let res = check(obj); | ||
expect(res.length).toBe(3); | ||
expect(res[0].type).toBe("object"); | ||
expect(res[0].field).toBe("[2]"); | ||
}); | ||
it("should give error if an element is not object", () => { | ||
let obj = [ | ||
{ id: 1, name: "John" }, | ||
{ id: 2, _name: "Jane" } | ||
]; | ||
let res = check(obj); | ||
expect(res.length).toBe(1); | ||
expect(res[0].type).toBe("required"); | ||
expect(res[0].field).toBe("[1].name"); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
148656
40
1657