Repository: icebob/fastest-validator
Pull request #151 (2020-06-09 17:34:03)

Enhancement: empty property added to `email` rule 
The `empty` property was added to the `email` rule (#116)

What was done:
- changes on `email.js`
- tests (including the Typescript ones)
- README.md was updated


Patch:
diff --git a/README.md b/README.md
index d76e190..cd89a51 100644
--- a/README.md
+++ b/README.md
@@ -555,6 +555,7 @@ v.validate({ email: "abc@gmail" }, schema); // Fail
 ### Properties
 Property | Default  | Description
 -------- | -------- | -----------
+`empty`  | `false`   | If `true`, the validator accepts an empty array `""`.
 `mode`   | `quick`  | Checker method. Can be `quick` or `precise`.
 `normalize`   | `false`  | Normalize the e-mail address (trim & lower-case). _It's a sanitizer, it will change the value in the original object._
 
diff --git a/index.d.ts b/index.d.ts
index a9ba6fd..e5a5df8 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -131,6 +131,11 @@ declare module "fastest-validator" {
 		 * Name of built-in validator
 		 */
 		type: "email";
+		/**
+		 * If true, the validator accepts an empty string ""
+		 * @default true
+		 */
+		empty?: boolean;
 		/**
 		 * Checker method. Can be quick or precise
 		 */
diff --git a/lib/messages.js b/lib/messages.js
index 5234463..3d7a9ea 100644
--- a/lib/messages.js
+++ b/lib/messages.js
@@ -55,6 +55,7 @@ module.exports = {
 	function: "The '{field}' field must be a function.",
 
 	email: "The '{field}' field must be a valid e-mail.",
+	emailEmpty: "The '{field}' field must not be empty.",
 
 	luhn: "The '{field}' field must be a valid checksum luhn.",
 
diff --git a/lib/rules/email.js b/lib/rules/email.js
index ec187d1..a2df05a 100644
--- a/lib/rules/email.js
+++ b/lib/rules/email.js
@@ -18,6 +18,18 @@ module.exports = function({ schema, messages }, path, context) {
 		}
 	`);
 
+	if (!schema.empty) {
+		src.push(`
+			if (value.length === 0) {
+				return ${this.makeError({ type: "emailEmpty", actual: "value", messages })}
+			}
+		`);
+	} else {
+		src.push(`
+			if (value.length === 0) return value;
+		`);
+	}
+
 	if (schema.normalize) {
 		sanitized = true;
 		src.push(`


Test patch:
diff --git a/test/messages.spec.js b/test/messages.spec.js
index f25f3aa..46976e6 100644
--- a/test/messages.spec.js
+++ b/test/messages.spec.js
@@ -42,6 +42,7 @@ describe("Test Messages", () => {
 		expect(msg.dateMax).toBeDefined();
 		expect(msg.forbidden).toBeDefined();
 		expect(msg.email).toBeDefined();
+		expect(msg.emailEmpty).toBeDefined();
 		expect(msg.url).toBeDefined();
 		expect(msg.enumValue).toBeDefined();
 		expect(msg.equalValue).toBeDefined();
diff --git a/test/rules/email.spec.js b/test/rules/email.spec.js
index 52d2a0e..7c3315f 100644
--- a/test/rules/email.spec.js
+++ b/test/rules/email.spec.js
@@ -4,6 +4,12 @@ const Validator = require("../../lib/validator");
 const v = new Validator();
 
 describe("Test rule: email", () => {
+	it("should check empty values", () => {
+		const check = v.compile({ $$root: true, type: "email", empty: true });
+
+		expect(check("john.doe@company.net")).toEqual(true);
+		expect(check("")).toEqual(true);
+	});
 
 	it("should check values", () => {
 		const check = v.compile({ $$root: true, type: "email" });
@@ -11,7 +17,7 @@ describe("Test rule: email", () => {
 
 		expect(check(0)).toEqual([{ type: "string", actual: 0, message }]);
 		expect(check(1)).toEqual([{ type: "string", actual: 1, message }]);
-		expect(check("")).toEqual([{ type: "email", actual: "", message: "The '' field must be a valid e-mail." }]);
+		expect(check("")).toEqual([{ type: "emailEmpty", actual: "", message: "The '' field must not be empty." }]);
 		expect(check("true")).toEqual([{ type: "email", actual: "true", message: "The '' field must be a valid e-mail." }]);
 		expect(check([])).toEqual([{ type: "string", actual: [], message }]);
 		expect(check({})).toEqual([{ type: "string", actual: {}, message }]);
diff --git a/test/typescript/rules/email.spec.ts b/test/typescript/rules/email.spec.ts
new file mode 100644
index 0000000..8e4f1d5
--- /dev/null
+++ b/test/typescript/rules/email.spec.ts
@@ -0,0 +1,81 @@
+/// <reference path="../../../index.d.ts" /> // here we make a reference to exists module definition
+import ValidatorType, {RuleEmail, RuleURL} from 'fastest-validator'; // here we importing type definition of default export
+
+const Validator: typeof ValidatorType = require('../../../index'); // here we importing real Validator Constructor
+const v: ValidatorType = new Validator();
+
+describe("Test rule: email", () => {
+	it("should check empty values", () => {
+		const check = v.compile({ $$root: true, type: "email", empty: true } as RuleEmail);
+
+		expect(check("john.doe@company.net")).toEqual(true);
+		expect(check("")).toEqual(true);
+	});
+
+	it("should check values", () => {
+		const check = v.compile({ $$root: true, type: "email" } as RuleEmail);
+		const message = "The '' field must be a string.";
+
+		expect(check(0)).toEqual([{ type: "string", actual: 0, message }]);
+		expect(check(1)).toEqual([{ type: "string", actual: 1, message }]);
+		expect(check("")).toEqual([{ type: "emailEmpty", actual: "", message: "The '' field must not be empty." }]);
+		expect(check("true")).toEqual([{ type: "email", actual: "true", message: "The '' field must be a valid e-mail." }]);
+		expect(check([])).toEqual([{ type: "string", actual: [], message }]);
+		expect(check({})).toEqual([{ type: "string", actual: {}, message }]);
+		expect(check(false)).toEqual([{ type: "string", actual: false, message }]);
+		expect(check(true)).toEqual([{ type: "string", actual: true, message }]);
+	});
+
+	it("should check values with quick pattern", () => {
+		const check = v.compile({ $$root: true, type: "email" } as RuleEmail);
+		const message = "The '' field must be a valid e-mail.";
+
+		expect(check("abcdefg")).toEqual([{ type: "email", actual: "abcdefg", message }]);
+		expect(check("1234")).toEqual([{ type: "email", actual: "1234", message }]);
+		expect(check("abc@gmail")).toEqual([{ type: "email", actual: "abc@gmail", message }]);
+		expect(check("@gmail.com")).toEqual([{ type: "email", actual: "@gmail.com", message }]);
+
+		// Invalid but we are in quick mode
+		expect(check("https://john@company.net")).toEqual(true);
+
+		expect(check("john.doe@company.net")).toEqual(true);
+		expect(check("james.123.45@mail.co.uk")).toEqual(true);
+		expect(check("admin@nasa.space")).toEqual(true);
+	});
+
+	it("should check values", () => {
+		const check = v.compile({ $$root: true, type: "email", mode: "precise" } as RuleEmail);
+		const message = "The '' field must be a valid e-mail.";
+
+		expect(check("abcdefg")).toEqual([{ type: "email", actual: "abcdefg", message }]);
+		expect(check("1234")).toEqual([{ type: "email", actual: "1234", message }]);
+		expect(check("abc@gmail")).toEqual([{ type: "email", actual: "abc@gmail", message }]);
+		expect(check("@gmail.com")).toEqual([{ type: "email", actual: "@gmail.com", message }]);
+		expect(check("https://john@company.net")).toEqual([{ type: "email", actual: "https://john@company.net", message }]);
+
+		expect(check("john.doe@company.net")).toEqual(true);
+		expect(check("james.123.45@mail.co.uk")).toEqual(true);
+		expect(check("admin@nasa.space")).toEqual(true);
+	});
+
+	it("should not normalize", () => {
+		const check = v.compile({ email: { type: "email" } as RuleEmail });
+
+		const obj = { email: "John.Doe@Gmail.COM" };
+		expect(check(obj)).toEqual(true);
+		expect(obj).toEqual({
+			email: "John.Doe@Gmail.COM"
+		});
+	});
+
+	it("should normalize", () => {
+		const check = v.compile({ email: { type: "email", normalize: true } as RuleEmail });
+
+		const obj = { email: " John.Doe@Gmail.COM   " };
+		expect(check(obj)).toEqual(true);
+		expect(obj).toEqual({
+			email: "john.doe@gmail.com"
+		});
+	});
+
+});