Repository: icebob/fastest-validator
Pull request #164 (2020-06-16 17:47:18)

Add plugin support
```js
// Plugin Side
function myPlugin(validator){
    // you can modify validator here
    // e.g.: validator.add(...)
}
// Validator Side
const v = new Validator();
v.plugin(myPlugin)
```


Patch:
diff --git a/README.md b/README.md
index 812ccc5..a7da48f 100644
--- a/README.md
+++ b/README.md
@@ -102,6 +102,7 @@ $ npm run bench
 - [Personalised Messages](#personalised-messages)
 - [Message types](#message-types)
   - [Message fields](#message-fields)
+- [Plugins](#plugins)
 - [Development](#development)
 - [Test](#test)
   - [Coverage report](#coverage-report)
@@ -1199,6 +1200,21 @@ v.validate({ firstname: "John", lastname: 23 }, schema );
 ]
 */
 ```
+# Plugins
+You can apply plugins:
+```js
+// Plugin Side
+function myPlugin(validator){
+    // you can modify validator here
+    // e.g.: validator.add(...)
+}
+
+// Validator Side
+const v = new Validator();
+v.plugin(myPlugin)
+
+```
+
 # Message types
 Name                | Default text
 ------------------- | -------------
diff --git a/index.d.ts b/index.d.ts
index c8ec553..1e50202 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -827,6 +827,11 @@ declare module "fastest-validator" {
 		customRules?: {
 			[key: string]: CompilationFunction
 		}
+
+		/**
+	 	 * For set plugins.
+	 	 */
+		plugins?: PluginFn<any>[]
 	}
 
 	export interface CompilationRule {
@@ -878,6 +883,8 @@ declare module "fastest-validator" {
 		context: Context
 	) => { sanitized?: boolean; source: string };
 
+	export type PluginFn<T = void> = (validator: Validator) => T
+
 	export default class Validator {
 		/**
 		 * List of possible error messages
@@ -914,6 +921,13 @@ declare module "fastest-validator" {
 		 */
 		alias(name: string, validationRule: ValidationRuleObject): void;
 
+		/**
+	 	 * Add a plugin
+	 	 *
+		 * @param {Function} fn
+	 	*/
+		plugin<T = void>(fn: PluginFn<T>): T
+
 		/**
 		 * Build error message
 		 * @return {ValidationError}
diff --git a/lib/validator.js b/lib/validator.js
index 840b3c7..273d7ef 100644
--- a/lib/validator.js
+++ b/lib/validator.js
@@ -60,6 +60,12 @@ class Validator {
 			if (opts.customRules) {
 				for (const ruleName in opts.customRules) this.add(ruleName, opts.customRules[ruleName]);
 			}
+
+			if (opts.plugins) {
+				const plugins = opts.plugins;
+				if (!Array.isArray(plugins)) throw new Error("Plugins type must be array");
+				plugins.forEach(this.plugin.bind(this));
+			}
 		}
 	}
 
@@ -421,6 +427,16 @@ class Validator {
 		if (this.rules[name]) throw new Error("Alias name must not be a rule name");
 		this.aliases[name] = validationRule;
 	}
+
+	/**
+	 * Add a plugin
+	 *
+	 * @param {Function} fn
+	 */
+	plugin(fn) {
+		if (typeof fn !== "function") throw new Error("Plugin fn type must be function");
+		return fn(this);
+	}
 }
 
 module.exports = Validator;


Test patch:
diff --git a/test/validator.spec.js b/test/validator.spec.js
index 112036b..00864c0 100644
--- a/test/validator.spec.js
+++ b/test/validator.spec.js
@@ -80,6 +80,16 @@ describe("Test constructor", () => {
 		expect(v.rules.b).toEqual(customRules.b);
 	});
 
+	it("should apply plugins", () => {
+		const plugin = jest.fn();
+		const v = new Validator({
+			plugins: [plugin]
+		});
+
+		expect(plugin).toBeCalledTimes(1);
+		expect(plugin).toBeCalledWith(v);
+	});
+
 });
 
 describe("Test validate", () => {
@@ -625,3 +635,15 @@ describe("Test objects shorthand", () => {
 	});
 });
 
+describe("Test plugins", () => {
+	const v = new Validator();
+
+	it("should apply plugin", () => {
+		const plugin = jest.fn();
+		v.plugin(plugin);
+
+		expect(plugin).toBeCalledTimes(1);
+		expect(plugin).toBeCalledWith(v);
+	});
+});
+