Repository: icebob/fastest-validator
Pull request #120 (2020-03-21 16:30:18)

Rules default settings  
to change default rules behavior.
For example: object strict

```js
‍‍‍const v = new Validator({
   defaults: {
      object: {
         strict: 'remove'
      }
   }
})
```

coveralls: 
[![Coverage Status](https://coveralls.io/builds/29520861/badge)](https://coveralls.io/builds/29520861)

Coverage remained the same at 100.0% when pulling **57cd3b857edeeea3a09da5441e8e501c151fa70d on erfanium:newF** into **d1edb33b35bf82f7a7710e62e64304947d2c7007 on icebob:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/29520861/badge)](https://coveralls.io/builds/29520861)

Coverage remained the same at 100.0% when pulling **57cd3b857edeeea3a09da5441e8e501c151fa70d on erfanium:newF** into **d1edb33b35bf82f7a7710e62e64304947d2c7007 on icebob:master**.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4f7364c..41493b8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,11 +1,3 @@
---------------------------------------------------
-<a name="1.1.0"></a>
-# 1.1.0 (2020-03-22)
-
-## Changes
-- New user-defined 'alias' feature [#118](https://github.com/icebob/fastest-validator/issues/118) by [@erfanium](https://github.com/erfanium)
-- Add custom validation function for built-in rules [#119](https://github.com/icebob/fastest-validator/issues/119) by [@erfanium](https://github.com/erfanium)
-
 --------------------------------------------------
 <a name="1.0.2"></a>
 # 1.0.2 (2020-02-09)
diff --git a/README.md b/README.md
index 874ee57..8314d6d 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@
 * blazing fast! Really!
 * 15+ built-in validators
 * many sanitizations
-* custom validators & aliases
+* custom validators
 * nested objects & array handling
 * strict object validation
 * multiple validators
@@ -45,62 +45,38 @@ $ npm run bench
 ```
 
 # Table of contents
-- [fastest-validator ![NPM version](https://www.npmjs.com/package/fastest-validator) [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=The%20fastest%20JS%20validator%20library%20for%20NodeJS&url=https://github.com/icebob/fastest-validator&via=Icebobcsi&hashtags=nodejs,javascript)](#fastest-validator-img-src%22httpswwwnpmjscompackagefastest-validator%22-alt%22npm-version%22-img-src%22httpsimgshieldsiotwitterurlhttpshieldsiosvgstylesocial%22-alt%22tweet%22)
-  - [Key features](#key-features)
-- [How fast?](#how-fast)
-- [Table of contents](#table-of-contents)
-  - [Installation](#installation)
-    - [NPM](#npm)
-  - [Usage](#usage)
-    - [Simple method](#simple-method)
-    - [Fast method](#fast-method)
-    - [Browser usage](#browser-usage)
+- [Installations](#installation)
+- [Usage](#usage)
 - [Optional & required fields](#optional--required-fields)
 - [Strict validation](#strict-validation)
-  - [Remove additional fields](#remove-additional-fields)
 - [Multiple validators](#multiple-validators)
 - [Root element schema](#root-element-schema)
 - [Sanitizations](#sanitizations)
-  - [Default values](#default-values)
 - [Shorthand definitions](#shorthand-definitions)
-- [Alias definition](#alias-definition)
 - [Built-in validators](#built-in-validators)
-  - [`any`](#any)
-  - [`array`](#array)
-    - [Properties](#properties)
-  - [`boolean`](#boolean)
-    - [Properties](#properties-1)
-  - [`date`](#date)
-    - [Properties](#properties-2)
-  - [`email`](#email)
-    - [Properties](#properties-3)
-  - [`enum`](#enum)
-    - [Properties](#properties-4)
-  - [`equal`](#equal)
-    - [Properties](#properties-5)
-  - [`forbidden`](#forbidden)
-    - [Properties](#properties-6)
-  - [`function`](#function)
-  - [`luhn`](#luhn)
-  - [`mac`](#mac)
-  - [`multi`](#multi)
-  - [`number`](#number)
-    - [Properties](#properties-7)
-  - [`object`](#object)
-    - [Properties](#properties-8)
-  - [`string`](#string)
-    - [Properties](#properties-9)
-  - [`url`](#url)
-  - [`uuid`](#uuid)
-    - [Properties](#properties-10)
+    - [any](#any)
+    - [array](#array)
+    - [boolean](#boolean)
+    - [date](#date)
+    - [email](#email)
+    - [enum](#enum)
+    - [equal](#equal)
+    - [forbidden](#forbidden)
+    - [function](#function)
+    - [luhn](#luhn)
+    - [mac](#mac)
+    - [multi](#multi)
+    - [number](#number)
+    - [object](#object)
+    - [string](#string)
+    - [url](#url)
+    - [uuid](#uuid)
 - [Custom validator](#custom-validator)
 - [Custom error messages (l10n)](#custom-error-messages-l10n)
 - [Personalised Messages](#personalised-messages)
 - [Message types](#message-types)
-  - [Message fields](#message-fields)
 - [Development](#development)
 - [Test](#test)
-  - [Coverage report](#coverage-report)
 - [Contribution](#contribution)
 - [License](#license)
 - [Contact](#contact)
@@ -304,23 +280,6 @@ const schema = {
 }
 ```
 
-# Alias definition
-You can define custom aliases.
-
-```js
-v.alias('username', {
-    type: 'string',
-    min: 4,
-    max: 30
-    // ...
-});
-
-const schema = {
-    username: "username|max:100", // Using the 'username' alias
-    password: "string|min:6",
-}
-```
-
 # Built-in validators
 
 ## `any`
@@ -924,35 +883,6 @@ console.log(v.validate({ name: "John", weight: 8 }, schema));
 */
 ```
 
-Or you can use built-in validator with a `custom` checker function:
-```js
-let v = new Validator({
-    messages: {
-        // Register our new error message text
-        phoneNumber: "The phone number must be started with '+'!"
-    }
-});
-
-const schema = {
-    name: { type: "string", min: 3, max: 255 },
-    phone: { type: "string", length: 15, custom: v => 
-        v.startsWith("+") ? true : [{ type: "phoneNumber" }] 
-    }	
-};
-
-console.log(v.validate({ name: "John", phone: "+36-70-123-4567" }, schema));
-// Returns: true
-
-console.log(v.validate({ name: "John", phone: "36-70-123-4567" }, schema));
-/* Returns an array with errors:
-    [{
-        message: "The phone number must be started with '+'!",
-        field: 'phone',
-        type: 'phoneNumber'
-    }]
-*/
-```
-
 # Custom error messages (l10n)
 You can set your custom messages in the validator constructor.
 
diff --git a/examples/full.js b/examples/full.js
index 25d0838..187c817 100644
--- a/examples/full.js
+++ b/examples/full.js
@@ -3,8 +3,7 @@
 const Validator = require("../index");
 const v = new Validator({
 	messages: {
-		stringMin: "A(z) '{field}' mező túl rövid. Minimum: {expected}, Jelenleg: {actual}",
-		phoneNumber: "The phone number must be started with '+'! Actual: {actual}"
+		stringMin: "A(z) '{field}' mező túl rövid. Minimum: {expected}, Jelenleg: {actual}"
 	}
 });
 
@@ -38,7 +37,7 @@ const schema = {
 	apikey: "forbidden",
 	uuidv4: { type: "uuid", version: 4 },
 	uuid: "uuid",
-	phone: { type: "string", length: 15, custom: v => v.startsWith("+") ? true : [{ type: "phoneNumber" }] },
+	phone: { type: "string", length: 15, custom: v => v.startsWith("+") ? true : [{ type: "wrongPhoneFormat" }] },
 	action: "function",
 	created: "date",
 	now: { type: "date", convert: true }
diff --git a/index.d.ts b/index.d.ts
index 786d622..8328580 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -744,6 +744,13 @@ declare module 'fastest-validator' {
 		 * List of possible error messages
 		 */
 		messages?: MessagesType,
+
+		/**
+		 * Default settings for rules 
+		 */
+		defaults?: {
+			[key in ValidationRuleName]: ValidationSchema
+		}
 	};
 
 	class Validator {
diff --git a/lib/helpers/deep-extend.js b/lib/helpers/deep-extend.js
index 1c9a3bd..cb03fc7 100644
--- a/lib/helpers/deep-extend.js
+++ b/lib/helpers/deep-extend.js
@@ -1,16 +1,16 @@
 "use strict";
 
-function deepExtend(destination, source) {
+function deepExtend(destination, source, options = {}) {
 	for (let property in source) {
-		if (typeof source[property] === "object" &&
-			source[property] !== null) {
+		if (typeof source[property] === "object" && source[property] !== null) {
 			destination[property] = destination[property] || {};
-			deepExtend(destination[property], source[property]);
+			deepExtend(destination[property], source[property], options);
 		} else {
+			if (options.skipIfExist === true && destination[property] !== undefined ) continue;
 			destination[property] = source[property];
 		}
 	}
 	return destination;
 }
 
-module.exports = deepExtend;
\ No newline at end of file
+module.exports = deepExtend;
diff --git a/lib/validator.js b/lib/validator.js
index 0f0c8b3..529325d 100644
--- a/lib/validator.js
+++ b/lib/validator.js
@@ -41,9 +41,12 @@ class Validator {
 		this.opts = {
 			messages: deepExtend({}, defaultMessages)
 		};
+		this.defaults = {};
 
-		if (opts)
+		if (opts) {
 			deepExtend(this.opts, opts);
+			if (opts.defaults) deepExtend(this.defaults, opts.defaults);
+		}
 
 		this.messages = this.opts.messages;
 
@@ -294,10 +297,9 @@ class Validator {
 		}
 
 		const alias = this.aliases[schema.type];
-
 		if (alias) {
 			delete schema.type;
-			schema = Object.assign({}, alias, schema);
+			schema = deepExtend(schema, alias, { skipIfExist: true });
 		}
 
 		const ruleFunction = this.rules[schema.type];
@@ -306,7 +308,7 @@ class Validator {
 
 		const rule = {
 			messages: Object.assign({}, this.messages, schema.messages),
-			schema: schema,
+			schema: deepExtend(schema, this.defaults[schema.type], { skipIfExist: true }),
 			ruleFunction: ruleFunction,
 			customValidation: () => ""
 		};
diff --git a/package-lock.json b/package-lock.json
index a99b111..5e515a4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "fastest-validator",
-  "version": "1.1.0",
+  "version": "1.0.2",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/package.json b/package.json
index 81108fb..268fe61 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "fastest-validator",
-  "version": "1.1.0",
+  "version": "1.0.2",
   "description": "The fastest JS validator library for NodeJS",
   "main": "index.js",
   "browser": "dist/index.min.js",


Test patch:
diff --git a/test/helpers/deep-extend.spec.js b/test/helpers/deep-extend.spec.js
index e6fc301..8bb3a12 100644
--- a/test/helpers/deep-extend.spec.js
+++ b/test/helpers/deep-extend.spec.js
@@ -39,3 +39,21 @@ describe("deepExtend", () => {
 		});
 	});
 });
+
+describe("Test merge options", () => {
+	it("should consider skipIfExist option and not overwrite the existing properties", () => {
+		const result = deepExtend({
+			b: 5,
+			c: 6
+		}, {
+			b: 10,
+			e: "Hello"
+		}, { skipIfExist: true });
+
+		expect(result).toEqual({
+			b: 5,
+			c: 6,
+			e: "Hello"
+		});
+	});
+});
diff --git a/test/validator.spec.js b/test/validator.spec.js
index d067692..e748cf4 100644
--- a/test/validator.spec.js
+++ b/test/validator.spec.js
@@ -92,7 +92,6 @@ describe("Test add", () => {
 			source: `
 				if (value % 2 != 0)
 					${this.makeError({ type: "evenNumber",  actual: "value", messages })}
-
 				return value;
 			`
 		};
@@ -257,34 +256,27 @@ describe("Test compile (integration test)", () => {
 
 	/*
 	describe("Test check generator with custom path & parent", () => {
-
 		it("when schema is defined as an array, and custom path & parent are specified, they should be forwarded to validators", () => {
 			const v = new Validator();
 			const customValidator = jest.fn().mockReturnValue(true);	// Will be called with (value, schema, path, parent)
 			v.add("customValidator", customValidator);
-
 			const validate = v.compile([{ type: "customValidator" }]);
 			const parent = {};
 			const res = validate({ customValue: 4711 }, "customPath", parent);
-
 			expect(res).toBe(true);
 			expect(customValidator.mock.calls[0][2]).toBe("customPath");
 			expect(customValidator.mock.calls[0][3]).toBe(parent);
 		});
-
 		it("when schema is defined as an array, path & parent should be set to default values in validators", () => {
 			const v = new Validator();
 			const customValidator = jest.fn().mockReturnValue(true);	// Will be called with (value, schema, path, parent)
 			v.add("customValidator", customValidator);
-
 			const validate = v.compile([{ type: "customValidator" }]);
 			const res = validate({ customValue: 4711 });
-
 			expect(res).toBe(true);
 			expect(customValidator.mock.calls[0][2]).toBeUndefined();
 			expect(customValidator.mock.calls[0][3]).toBeNull();
 		});
-
 		it("when schema is defined as an object, and custom path is specified, it should be forwarded to validators", () => {
 			// Note: as the item we validate always must be an object, there is no use
 			// of specifying a custom parent, like for the schema-as-array above.
@@ -293,22 +285,17 @@ describe("Test compile (integration test)", () => {
 			const v = new Validator();
 			const customValidator = jest.fn().mockReturnValue(true);	// Will be called with (value, schema, path, parent)
 			v.add("customValidator", customValidator);
-
 			const validate = v.compile({ customValue: { type: "customValidator" } });
 			const res = validate({ customValue: 4711 }, "customPath");
-
 			expect(res).toBe(true);
 			expect(customValidator.mock.calls[0][2]).toBe("customPath.customValue");
 		});
-
 		it("when schema is defined as an object, path should be set to default value in validators", () => {
 			const v = new Validator();
 			const customValidator = jest.fn().mockReturnValue(true);	// Will be called with (value, schema, path, parent)
 			v.add("customValidator", customValidator);
-
 			const validate = v.compile({ customValue: { type: "customValidator" } });
 			const res = validate({ customValue: 4711 });
-
 			expect(res).toBe(true);
 			expect(customValidator.mock.calls[0][2]).toBe("customValue");
 		});
@@ -405,4 +392,64 @@ describe("Test custom validation for built-in rules", () => {
 	});
 });
 
+describe("Test default settings", () => {
+	const v = new Validator({
+		defaults: {
+			object: {
+				strict: "remove"
+			}
+		}
+	});	
+
+	it("should consider default settings", () => {
+		const check = v.compile({
+			foo: {
+				type: "object",
+				props: {
+					a: "string"
+				}
+			}
+		});
+
+		const o = {
+			foo: {
+				a: "x",
+				b: "y"
+			}
+		};
+
+		expect(check(o)).toBe(true);
+		expect(o).toEqual({
+			foo: {
+				a: "x"
+			}
+		});
+	});
 
+	it("should override default setting", () => {
+		const check = v.compile({
+			foo: {
+				type: "object",
+				strict: false,
+				props: {
+					a: "string"
+				}
+			}
+		});
+
+		const o = {
+			foo: {
+				a: "x",
+				b: "y"
+			},
+		};
+
+		expect(check(o)).toBe(true);
+		expect(o).toEqual({
+			foo: {
+				a: "x",
+				b: "y"
+			}
+		});
+	});
+});
\ No newline at end of file