Repository: icebob/fastest-validator (js)

Issue:
Wrong `this` value in custom validators
It seems the `this` is not set correctly in the `custom` validators. Before the 1.0 it pointed to the `Validator` instance but since 1.x it's not.

```js
const Validator = require("../index");

const v = new Validator({
    debug: true,
    useNewCustomCheckerFunction: true,
});

const schema = {
    name: { type: "string", min: 3, max: 255, custom(val) {
        console.log("this", this);
        return val;
    } }
};

console.log(v.validate({ name: "John" }, schema));
```

Output

```
this [ [Function: anonymous], [Function: anonymous] ]
true
```

Pull request description:
bind every `fn` to validator instance
fixes #230 

Patch:
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 0630b24..3372100 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -8,7 +8,7 @@
 			"type": "node",
 			"request": "launch",
 			"name": "Launch dev",
-			"program": "${workspaceRoot}\\examples\\async.js"
+			"program": "${workspaceRoot}\\examples\\custom.js"
 		},
 		{
 			"type": "node",
diff --git a/README.md b/README.md
index 6dd765f..92c9223 100644
--- a/README.md
+++ b/README.md
@@ -117,8 +117,8 @@ import FastestValidator from "https://esm.sh/fastest-validator@1"
 
 const v = new FastestValidator();
 const check = v.compile({
-    name: "string",
-    age: "number",
+	name: "string",
+	age: "number",
 });
 
 console.log(check({ name: "Erf", age: 18 })); //true
@@ -1177,20 +1177,20 @@ const v = new Validator({
 });
 
 const schema = {
-    $$async: true,
-    name: { type: "string" },
-    username: {
-        type: "string",
+	$$async: true,
+	name: { type: "string" },
+	username: {
+		type: "string",
         min: 2,
-        custom: async (v, errors) => {
-            // E.g. checking in the DB that the value is unique.
-            const res = await DB.checkUsername(v);
+		custom: async (v, errors) => {
+			// E.g. checking in the DB that the value is unique.
+			const res = await DB.checkUsername(v);
             if (!res) 
                 errors.push({ type: "unique", actual: value });
 
             return v;
-        }
-    }
+		}
+	}
     // ...
 };
 
@@ -1207,24 +1207,6 @@ const check = v.compile(schema);
 console.log("Is async?", check.async);
 ```
 
-## Meta information for custom validators
-You can pass any extra meta information for the custom validators which is available via `context.meta`.
-
-```js
-const schema = {
-    name: { type: "string", custom: (value, errors, schema, name, parent, context) => {
-        // Access to the meta
-        return context.meta.a;
-    } },
-};
-const check = v.compile(schema);
-
-const res = check(obj, {
-    // Passes meta information
-    meta: { a: "from-meta" }
-});
-```
-
 # Custom error messages (l10n)
 You can set your custom messages in the validator constructor.
 
diff --git a/examples/async.js b/examples/async.js
index bd63146..bbb35fe 100644
--- a/examples/async.js
+++ b/examples/async.js
@@ -26,9 +26,9 @@ const schema = {
 		type: "string",
 		min: 4,
 		max: 25,
-		custom: async (v, errors, schema, name, parent, context) => {
+		custom: async (v) => {
 			await new Promise(resolve => setTimeout(resolve, 1000));
-			return context.meta.name;
+			return v.toUpperCase();
 		}
 	},
 
@@ -55,5 +55,5 @@ console.log("Is async?", check.async);
 		username: "johndoe   ",
 		age: 21
 	};
-	console.log(await check(data, { meta: { name: "Jane Doe" }}), data);
+	console.log(await check(data), data);
 })();
diff --git a/index.d.ts b/index.d.ts
index 46c964f..997d2bc 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -894,13 +894,11 @@ declare module "fastest-validator" {
 
 	export interface Context {
 		index: number;
-		async: boolean;
 		rules: ValidationRuleObject[];
 		fn: Function[];
 		customs: {
 			[ruleName: string]: { schema: RuleCustom; messages: MessagesType };
 		};
-		meta?: object;
 	}
 
 	export interface CheckerFunctionError {
@@ -944,17 +942,14 @@ declare module "fastest-validator" {
 		toHexString(): string;
 	}
 
-	export interface CheckFunctionOptions {
-		meta?: object | null;
-	}
 
 	export interface SyncCheckFunction {
-		(value: any, opts?: CheckFunctionOptions): true | ValidationError[]
+		(value: any): true | ValidationError[]
 		async: false
 	 }
 
 	 export interface AsyncCheckFunction {
-		(value: any, opts?: CheckFunctionOptions): Promise<true | ValidationError[]>
+		(value: any): Promise<true | ValidationError[]>
 		async: true
 	 }
 
diff --git a/lib/validator.js b/lib/validator.js
index 693ca38..ea12c1f 100644
--- a/lib/validator.js
+++ b/lib/validator.js
@@ -162,7 +162,6 @@ class Validator {
 		this.cache.clear();
 		delete schema.$$async;
 
-		/* istanbul ignore next */
 		if (context.async && !AsyncFunction) {
 			throw new Error("Asynchronous mode is not supported.");
 		}
@@ -225,10 +224,8 @@ class Validator {
 
 		this.cache.clear();
 
-		const resFn = function (data, opts) {
+		const resFn = function (data) {
 			context.data = data;
-			if (opts && opts.meta)
-				context.meta = opts.meta;
 			return checkFn.call(self, data, context);
 		};
 		resFn.async = context.async;
@@ -274,7 +271,7 @@ class Validator {
 			res.source = res.source.replace(/%%INDEX%%/g, rule.index);
 			const FnClass = context.async ? AsyncFunction : Function;
 			const fn = new FnClass("value", "field", "parent", "errors", "context", res.source);
-			context.fn[rule.index] = fn;
+			context.fn[rule.index] = fn.bind(this);
 			sourceCode.push(this.wrapRequiredCheckSourceCode(rule, innerSrc.replace(/%%INDEX%%/g, rule.index), context, resVar));
 			sourceCode.push(this.makeCustomValidator({vName: resVar, path: customPath, schema: rule.schema, context, messages: rule.messages, ruleIndex: rule.index}));
 		}


Test patch:
diff --git a/test/integration.spec.js b/test/integration.spec.js
index adfa637..7ee3be9 100644
--- a/test/integration.spec.js
+++ b/test/integration.spec.js
@@ -1225,7 +1225,7 @@ describe("Test async mode", () => {
 	});
 
 	it("should call custom async validators", async () => {
-		const obj = {
+		let obj = {
 			id: 3,
 			name: "John",
 			username: "   john.doe  ",
@@ -1260,28 +1260,3 @@ describe("Test async mode", () => {
 	});
 
 });
-
-describe("Test context meta", () => {
-	const v = new Validator({ useNewCustomCheckerFunction: true });
-
-	const schema = {
-		name: { type: "string", custom: (value, errors, schema, name, parent, context) => {
-			expect(context.meta).toEqual({ a: "from-meta" });
-			return context.meta.a;
-		} },
-	};
-	const check = v.compile(schema);
-
-	it("should call custom async validators", () => {
-		const obj = {
-			name: "John"
-		};
-
-		const res = check(obj, {
-			meta: { a: "from-meta" }
-		});
-
-		expect(res).toBe(true);
-		expect(obj).toEqual({ name: "from-meta" });
-	});
-});
diff --git a/test/typescript/integration.spec.ts b/test/typescript/integration.spec.ts
index ecf18f2..bb6cf12 100644
--- a/test/typescript/integration.spec.ts
+++ b/test/typescript/integration.spec.ts
@@ -1283,29 +1283,5 @@ describe("Test async mode", () => {
 			message: "The 'age' field must be an even number! Actual: 31",
 		}]);
 	});
-});
-
-describe("Test context meta", () => {
-	const v = new Validator({ useNewCustomCheckerFunction: true });
-
-	const schema = {
-		name: { type: "string", custom: (value, errors, schema, name, parent, context) => {
-			expect(context.meta).toEqual({ a: "from-meta" });
-			return context.meta.a;
-		} },
-	};
-	const check = v.compile(schema);
 
-	it("should call custom async validators", () => {
-		const obj = {
-			name: "John"
-		};
-
-		const res = check(obj, {
-			meta: { a: "from-meta" }
-		});
-
-		expect(res).toBe(true);
-		expect(obj).toEqual({ name: "from-meta" });
-	});
 });
diff --git a/test/validator.spec.js b/test/validator.spec.js
index 0bafe68..af8396a 100644
--- a/test/validator.spec.js
+++ b/test/validator.spec.js
@@ -446,7 +446,6 @@ describe("Test custom validation v1", () => {
 	});
 
 	it("should compile without error", () => {
-		const fn = jest.fn();
 		const check = v.compile({
 			num: {
 				type: "number",
@@ -454,7 +453,6 @@ describe("Test custom validation v1", () => {
 				max: 15,
 				integer: true,
 				custom(value){
-					fn(value);
 					if (value % 2 !== 0) return [{ type: "evenNumber", actual: value }];
 				}
 			}
@@ -472,7 +470,7 @@ describe("Test custom validation v1", () => {
 				max: 15,
 				integer: true,
 				custom(value){
-					fn(value);
+					fn(this, value);
 					if (value % 2 !== 0) return [{ type: "evenNumber", actual: value }];
 				}
 			}
@@ -480,7 +478,7 @@ describe("Test custom validation v1", () => {
 
 		const res = check({num: 12});
 		expect(res).toBe(true);
-		expect(fn).toBeCalledWith(12);
+		expect(fn).toBeCalledWith(v, 12);
 
 		expect(check({num: 8})[0].type).toEqual("numberMin");
 		expect(check({num: 18})[0].type).toEqual("numberMax");
@@ -534,7 +532,7 @@ describe("Test custom validation", () => {
 				max: 15,
 				integer: true,
 				custom(value, errors){
-					fn(value, errors);
+					fn(this ,value, errors);
 					if (value % 2 !== 0) errors.push({ type: "evenNumber", actual: value });
 					return value;
 				}
@@ -547,7 +545,7 @@ describe("Test custom validation", () => {
 	it("should work correctly with custom validator", () => {
 		const res = check({num: 12});
 		expect(res).toBe(true);
-		expect(fn).toBeCalledWith(12, []);
+		expect(fn).toBeCalledWith(v, 12, []);
 
 		expect(check({num: 8})[0].type).toEqual("numberMin");
 		expect(check({num: 18})[0].type).toEqual("numberMax");