From e372c6fdd424506437df432fadf14f2bbc898d93 Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Wed, 21 Dec 2022 10:05:28 +0330
Subject: [PATCH 01/23] feat:validator

---
 demo/validator/type.ts      |   3 +
 demo/validator/validator.ts | 110 ++++++++++++++++++++++++++++++++++++
 2 files changed, 113 insertions(+)
 create mode 100644 demo/validator/type.ts
 create mode 100644 demo/validator/validator.ts

diff --git a/demo/validator/type.ts b/demo/validator/type.ts
new file mode 100644
index 000000000..c0ae3aac1
--- /dev/null
+++ b/demo/validator/type.ts
@@ -0,0 +1,3 @@
+export interface valid {
+  [key: string]: valid | 'string' | 'number' | 'boolean';
+}
diff --git a/demo/validator/validator.ts b/demo/validator/validator.ts
new file mode 100644
index 000000000..3db69883d
--- /dev/null
+++ b/demo/validator/validator.ts
@@ -0,0 +1,110 @@
+import {isNumber} from '@alwatr/math';
+
+import type {valid} from './type.js';
+
+function validator<T extends Record<string, unknown>>(valueObj: Record<string, unknown>, params: valid): T {
+  const validObj: Record<string, unknown> = {};
+  for (const paramName in params) {
+    if (!Object.prototype.hasOwnProperty.call(params, paramName)) continue;
+    const type = params[paramName];
+    if (typeof params[paramName] === 'object') {
+      validObj[paramName] = validator<T>(valueObj[paramName] as Record<string, unknown>, params[paramName] as valid);
+    }
+
+    let value = valueObj[paramName] as string | number | boolean;
+
+    if (type === 'boolean') {
+      if (value === true) {
+        validObj[paramName] = true;
+      }
+      else if (value === false) {
+        validObj[paramName] = false;
+      }
+      else if (value === 1) {
+        validObj[paramName] = true;
+      }
+      else if (value === 0) {
+        validObj[paramName] = false;
+      }
+      else if (typeof value === 'string') {
+        value = value.trim();
+        if (value === 'true' || value === '1') {
+          validObj[paramName] = true;
+        }
+        else if (value === 'false' || value === '0') {
+          value = value.trim();
+          validObj[paramName] = false;
+        }
+      }
+      else {
+        throw new Error(undefined, {
+          cause: {
+            name: 'boolean_validator',
+            message: `'${value}' not valid`,
+          },
+        });
+      }
+    }
+    else if (type === 'number') {
+      if (isNumber(value)) {
+        validObj[paramName] = +value;
+      }
+      else {
+        throw new Error('invalid_type', {
+          cause: {
+            name: 'number_validator',
+            message: `'${value}' not valid`,
+          },
+        });
+      }
+    }
+    else if (type === 'string') {
+      validObj[paramName] = value.toString();
+    }
+  }
+
+  return validObj as T;
+}
+
+// number
+console.log(validator<{a: number}>({a: 2}, {a: 'number'}));
+console.log(validator<{a: number}>({a: '2'}, {a: 'number'}));
+
+// boolean
+console.log(validator<{a: boolean}>({a: '1'}, {a: 'boolean'}));
+console.log(validator<{a: boolean}>({a: 'true'}, {a: 'boolean'}));
+console.log(validator<{a: boolean}>({a: '0'}, {a: 'boolean'}));
+console.log(validator<{a: boolean}>({a: 'false'}, {a: 'boolean'}));
+
+// string
+console.log(validator<{a: string}>({a: false}, {a: 'string'}));
+console.log(validator<{a: string}>({a: 'false'}, {a: 'string'}));
+console.log(validator<{a: string}>({a: 1}, {a: 'string'}));
+
+// nested object
+console.log(
+    validator<{a: number; b: {c: boolean}}>(
+        {a: '2', b: {c: 'true', d: {e: 1}}},
+        {a: 'number', b: {c: 'boolean', d: {e: 'number'}}},
+    ),
+);
+
+// not valid
+try {
+  console.log(
+      validator<{a: number; b: {c: boolean}}>(
+          {a: '2', b: {c: 'true', d: {e: true}}},
+          {a: 'number', b: {c: 'boolean', d: {e: 'number'}}},
+      ),
+  );
+}
+catch (error) {
+  console.log((error as Error));
+}
+
+try {
+  console.log(validator<{a: boolean}>({a: 'trus'}, {a: 'boolean'}));
+}
+catch (error) {
+  console.log((error as Error));
+}

From c0cfdc21a99cf02bb4d56c00ba186429e72d3aa2 Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Wed, 21 Dec 2022 10:26:05 +0330
Subject: [PATCH 02/23] fix(validator): validate boolean

---
 demo/validator/validator.ts | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/demo/validator/validator.ts b/demo/validator/validator.ts
index 3db69883d..8f939fccf 100644
--- a/demo/validator/validator.ts
+++ b/demo/validator/validator.ts
@@ -35,9 +35,17 @@ function validator<T extends Record<string, unknown>>(valueObj: Record<string, u
           value = value.trim();
           validObj[paramName] = false;
         }
+        else {
+          throw new Error('invalid_type', {
+            cause: {
+              name: 'boolean_validator',
+              message: `'${value}' not valid`,
+            },
+          });
+        }
       }
       else {
-        throw new Error(undefined, {
+        throw new Error('invalid_type', {
           cause: {
             name: 'boolean_validator',
             message: `'${value}' not valid`,
@@ -99,12 +107,12 @@ try {
   );
 }
 catch (error) {
-  console.log((error as Error));
+  console.log(error as Error);
 }
 
 try {
-  console.log(validator<{a: boolean}>({a: 'trus'}, {a: 'boolean'}));
+  console.log(validator<{a: boolean}>({a: 'tru'}, {a: 'boolean'}));
 }
 catch (error) {
-  console.log((error as Error));
+  console.log(error as Error);
 }

From ee9b601198ea8dded43497df6824e09f65be86b3 Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Thu, 22 Dec 2022 11:20:18 +0330
Subject: [PATCH 03/23] fix(validator): remove extra trim

---
 demo/validator/validator.ts | 1 -
 1 file changed, 1 deletion(-)

diff --git a/demo/validator/validator.ts b/demo/validator/validator.ts
index 8f939fccf..11a8bac8e 100644
--- a/demo/validator/validator.ts
+++ b/demo/validator/validator.ts
@@ -32,7 +32,6 @@ function validator<T extends Record<string, unknown>>(valueObj: Record<string, u
           validObj[paramName] = true;
         }
         else if (value === 'false' || value === '0') {
-          value = value.trim();
           validObj[paramName] = false;
         }
         else {

From 5aa48c354c116655e7824366d4efcd5965172fe3 Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Sat, 24 Dec 2022 14:59:06 +0330
Subject: [PATCH 04/23] feat(validator): new package

---
 core/validator/README.md        | 210 ++++++++++++++++++++++++++++++++
 core/validator/package.json     |  38 ++++++
 core/validator/src/type.ts      |   3 +
 core/validator/src/validator.ts |  51 ++++++++
 core/validator/tsconfig.json    |  15 +++
 5 files changed, 317 insertions(+)
 create mode 100644 core/validator/README.md
 create mode 100644 core/validator/package.json
 create mode 100644 core/validator/src/type.ts
 create mode 100644 core/validator/src/validator.ts
 create mode 100644 core/validator/tsconfig.json

diff --git a/core/validator/README.md b/core/validator/README.md
new file mode 100644
index 000000000..9f8034124
--- /dev/null
+++ b/core/validator/README.md
@@ -0,0 +1,210 @@
+# Alwatr Math - `@alwatr/math`
+
+Simple useful Math library written in tiny TypeScript module.
+
+## API
+
+### `UnicodeDigits(fromLanguages: Array<UnicodeLangKeys> | 'all' | 'common', toLanguage: UnicodeLangKeys)`
+
+Translate number.
+
+- **fromLanguages** The source language to be translated.
+- **toLanguages** The dest language to be translated.
+
+Example:
+
+```ts
+const unicodeDigits = new UnicodeDigits('common', 'en');
+
+const list = [
+  '0123456789',
+  '٠١٢٣٤٥٦٧٨٩',
+  '߀߁߂߃߄߅߆߇߈߉',
+  '०१२३४५६७८९',
+  '০১২৩৪৫৬৭৮৯',
+  '੦੧੨੩੪੫੬੭੮੯',
+  '૦૧૨૩૪૫૬૭૮૯',
+  '୦୧୨୩୪୫୬୭୮୯',
+  '௦௧௨௩௪௫௬௭௮௯',
+].join('\n');
+
+console.log(unicodeDigits.translate(list));
+```
+
+### `unicodeDigits.translate(str: string): string`
+
+Convert the String of number of the source language to the destination language.
+
+- **str** is String of number of the source language.
+
+@TODO: update from ts files docs
+
+### `isNumber(value: unknown): boolean`
+
+Check the value is number or can convert to a number, for example string ' 123 ' can be converted to 123.
+
+#### Why is this needed?
+
+```ts
+console.log(typeof '123'); //=> 'string'
+console.log(+[]); //=> 0
+console.log(+''); //=> 0
+console.log(+'   '); //=> 0
+console.log(typeof NaN); //=> 'number'
+console.log(typeof Infinity); //=> 'number'
+```
+
+#### True
+
+<!-- prettier-ignore -->
+```ts
+import {isNumber} from 'https://esm.run/@alwatr/math';
+
+isNumber(5e3);               // true
+isNumber(0xff);              // true
+isNumber(-1.1);              // true
+isNumber(0);                 // true
+isNumber(1);                 // true
+isNumber(1.1);               // true
+isNumber('-1.1');            // true
+isNumber('0');               // true
+isNumber('0xff');            // true
+isNumber('1');               // true
+isNumber('1.1');             // true
+isNumber('5e3');             // true
+isNumber('012');             // true
+isNumber(parseInt('012'));   // true
+isNumber(parseFloat('012')); // true
+```
+
+#### False
+
+<!-- prettier-ignore -->
+```ts
+import {isNumber} from 'https://esm.run/@alwatr/math';
+
+isNumber(Infinity);          // false
+isNumber(NaN);               // false
+isNumber(null);              // false
+isNumber(undefined);         // false
+isNumber('');                // false
+isNumber('   ');             // false
+isNumber('foo');             // false
+isNumber([1]);               // false
+isNumber([]);                // false
+isNumber(function () {});    // false
+isNumber({});                // false
+```
+
+### `transformToRange(x: number, options}): number`
+
+Transform a number from one range to another.
+
+Options:
+
+```ts
+{
+  /**
+   * The input range [min, max].
+   *
+   */
+  in: [number, number];
+
+  /**
+   * The output (request) range [min, max].
+   */
+  out: [number, number];
+
+  /**
+   * If true, the output will be bounded to the output range (between min and max).
+   *
+   * In default behavior when x (input number) does not between input min~max range,
+   * the output value will be out of output min~max range.
+   *
+   */
+  bound?: boolean;
+}
+```
+
+#### Example
+
+```ts
+transformToRange(5, {in: [0, 10], out: [0, 100]}); // => 50
+```
+
+Make percentage of any value
+
+```ts
+transformToRange(2000, {in: [0, 5000], out: [0, 100]}); // => 40
+```
+
+Calculate progress-bar with
+
+```ts
+const progressOuterWith = 400; //px
+const gap = 5; //px (the visual gap between progressBar and component outer).
+const currentProgress = 30; //%
+
+const progressBarWith = transformToRange(currentProgress, {
+  in: [0, 100],
+  out: [componentPadding, progressOuterWith - componentPadding],
+  bound: true,
+});
+
+this.progressBar.style.width = `${progressBarWith}px`;
+```
+
+### Generate Random
+
+### `value`
+
+Returns a float random number between 0 and 1 (1 Not included).
+
+```ts
+console.log(random.value); // 0.7124123
+```
+
+### `random.integer(min: number, max: number): number`
+
+Generate a random integer between min and max.
+
+```ts
+console.log(random.integer(1, 10)); // somewhere between 1 and 10
+```
+
+### `random.float(min: number, max: number): number`
+
+Generate a random float between min and max.
+
+```ts
+console.log(random.float(1, 10)); // somewhere between 1 and 10
+```
+
+### `string: (min: number, max?: number): string`
+
+Generate a random string with random length.
+The string will contain only characters from the characters list.
+The length of the string will be between min and max (max included).
+If max not specified, the length will be set to min.
+
+```ts
+console.log(random.string(6)); // something like 'Aab1V2'
+```
+
+### `step(min: number, max: number, step: number): number`
+
+Generate a random integer between min and max with a step.
+
+```ts
+console.log(random.step(6, 10, 2)); // 6 or 8 or 10
+```
+
+### `shuffle(array: any[]): any[]`
+
+Shuffle an array.
+
+```ts
+const array = [1, 2, 3, 4, 5];
+random.shuffle(array);
+console.log(array); // [2, 4, 3, 1, 5]
+```
diff --git a/core/validator/package.json b/core/validator/package.json
new file mode 100644
index 000000000..bba05d334
--- /dev/null
+++ b/core/validator/package.json
@@ -0,0 +1,38 @@
+{
+  "name": "@alwatr/validator",
+  "version": "0.0.0",
+  "description": "Simple useful validator library written in tiny TypeScript module.",
+  "keywords": [
+    "validator",
+    "typescript",
+    "esm",
+    "alwatr"
+  ],
+  "main": "validator.js",
+  "type": "module",
+  "types": "validator.d.ts",
+  "author": "S. Ali Mihandoost <ali.mihandoost@gmail.com>",
+  "contributors": [
+    "S. Amir Mohammad Najafi <njfamirm@gmail.com> (njfamirm.ir)"
+  ],
+  "license": "MIT",
+  "files": [
+    "**/*.{d.ts.map,d.ts,js.map,js,html,md}"
+  ],
+  "publishConfig": {
+    "access": "public"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/AliMD/alwatr",
+    "directory": "core/validator"
+  },
+  "homepage": "https://github.com/AliMD/alwatr/tree/main/core/validator#readme",
+  "bugs": {
+    "url": "https://github.com/AliMD/alwatr/issues"
+  },
+  "dependencies": {
+    "tslib": "~2.4.1",
+    "@alwatr/validator": "~0.26.0"
+  }
+}
diff --git a/core/validator/src/type.ts b/core/validator/src/type.ts
new file mode 100644
index 000000000..3431136f0
--- /dev/null
+++ b/core/validator/src/type.ts
@@ -0,0 +1,3 @@
+export type schema = {
+  [key: string]: schema | 'string' | 'number' | 'boolean';
+}
diff --git a/core/validator/src/validator.ts b/core/validator/src/validator.ts
new file mode 100644
index 000000000..c6021e6d0
--- /dev/null
+++ b/core/validator/src/validator.ts
@@ -0,0 +1,51 @@
+import {isNumber} from '@alwatr/math';
+
+import type {schema} from './type.js';
+
+export {validator};
+
+function validator<DataType extends Record<string, unknown>>(value: Record<string, unknown>, schema: schema): DataType {
+  for (const paramName in schema) {
+    if (!Object.prototype.hasOwnProperty.call(schema, paramName)) continue;
+
+    const valueType = schema[paramName];
+    if (typeof schema[paramName] === 'object') {
+      value[paramName] =
+        validator<DataType>(value[paramName] as Record<string, unknown>, schema[paramName] as schema);
+    }
+
+    const validValue = value[paramName] as string | number | boolean;
+
+    if (valueType === 'boolean') {
+      if (validValue === true || validValue === false) {
+        value[paramName] = true;
+      }
+      else {
+        throw new Error('invalid_type', {
+          cause: {
+            name: 'boolean_validator',
+            message: `'${validValue}' not valid`,
+          },
+        });
+      }
+    }
+    else if (valueType === 'number') {
+      if (isNumber(validValue)) {
+        value[paramName] = +validValue;
+      }
+      else {
+        throw new Error('invalid_type', {
+          cause: {
+            name: 'number_validator',
+            message: `'${validValue}' not valid`,
+          },
+        });
+      }
+    }
+    else if (valueType === 'string') {
+      value[paramName] = validValue.toString();
+    }
+  }
+
+  return value as DataType;
+}
diff --git a/core/validator/tsconfig.json b/core/validator/tsconfig.json
new file mode 100644
index 000000000..cb6662a18
--- /dev/null
+++ b/core/validator/tsconfig.json
@@ -0,0 +1,15 @@
+{
+  "extends": "../../tsconfig.base",
+  "compilerOptions": {
+    "composite": true,
+    "tsBuildInfoFile": ".tsbuildinfo",
+    "rootDir": "src",
+    "outDir": "."
+  },
+
+  "include": ["src/**/*.ts"],
+  "exclude": [],
+  "references": [
+    {"path": "../math"}
+  ]
+}

From b48a30bac9f02f0b7edb3b4069c324f835f6d49b Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Sat, 24 Dec 2022 14:59:43 +0330
Subject: [PATCH 05/23] feat(validator): demo

---
 demo/package.json           |  3 +-
 demo/tsconfig.json          |  1 +
 demo/validator/type.ts      |  3 --
 demo/validator/validator.ts | 75 +------------------------------------
 yarn.lock                   |  7 ++++
 5 files changed, 11 insertions(+), 78 deletions(-)
 delete mode 100644 demo/validator/type.ts

diff --git a/demo/package.json b/demo/package.json
index f4163e8a4..0be43a2a8 100644
--- a/demo/package.json
+++ b/demo/package.json
@@ -6,7 +6,8 @@
   "type": "module",
   "private": "true",
   "contributors": [
-    "MohammadMahdi Zamanian <mm25zamanian@gmail.com>"
+    "MohammadMahdi Zamanian <mm25zamanian@gmail.com>",
+    "S. Amir Mohammad Najafi <njfamirm@gmail.com> (https://njfamirm.ir)"
   ],
   "dependencies": {
     "@alwatr/logger": "~0.27.0",
diff --git a/demo/tsconfig.json b/demo/tsconfig.json
index a7edd5a62..f5c072b88 100644
--- a/demo/tsconfig.json
+++ b/demo/tsconfig.json
@@ -22,5 +22,6 @@
     {"path": "../ui/element"},
     {"path": "../ui/icon"},
     {"path": "../core/storage-engine"},
+    {"path": "../core/validator"}
   ],
 }
diff --git a/demo/validator/type.ts b/demo/validator/type.ts
deleted file mode 100644
index c0ae3aac1..000000000
--- a/demo/validator/type.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export interface valid {
-  [key: string]: valid | 'string' | 'number' | 'boolean';
-}
diff --git a/demo/validator/validator.ts b/demo/validator/validator.ts
index 11a8bac8e..36912759f 100644
--- a/demo/validator/validator.ts
+++ b/demo/validator/validator.ts
@@ -1,77 +1,4 @@
-import {isNumber} from '@alwatr/math';
-
-import type {valid} from './type.js';
-
-function validator<T extends Record<string, unknown>>(valueObj: Record<string, unknown>, params: valid): T {
-  const validObj: Record<string, unknown> = {};
-  for (const paramName in params) {
-    if (!Object.prototype.hasOwnProperty.call(params, paramName)) continue;
-    const type = params[paramName];
-    if (typeof params[paramName] === 'object') {
-      validObj[paramName] = validator<T>(valueObj[paramName] as Record<string, unknown>, params[paramName] as valid);
-    }
-
-    let value = valueObj[paramName] as string | number | boolean;
-
-    if (type === 'boolean') {
-      if (value === true) {
-        validObj[paramName] = true;
-      }
-      else if (value === false) {
-        validObj[paramName] = false;
-      }
-      else if (value === 1) {
-        validObj[paramName] = true;
-      }
-      else if (value === 0) {
-        validObj[paramName] = false;
-      }
-      else if (typeof value === 'string') {
-        value = value.trim();
-        if (value === 'true' || value === '1') {
-          validObj[paramName] = true;
-        }
-        else if (value === 'false' || value === '0') {
-          validObj[paramName] = false;
-        }
-        else {
-          throw new Error('invalid_type', {
-            cause: {
-              name: 'boolean_validator',
-              message: `'${value}' not valid`,
-            },
-          });
-        }
-      }
-      else {
-        throw new Error('invalid_type', {
-          cause: {
-            name: 'boolean_validator',
-            message: `'${value}' not valid`,
-          },
-        });
-      }
-    }
-    else if (type === 'number') {
-      if (isNumber(value)) {
-        validObj[paramName] = +value;
-      }
-      else {
-        throw new Error('invalid_type', {
-          cause: {
-            name: 'number_validator',
-            message: `'${value}' not valid`,
-          },
-        });
-      }
-    }
-    else if (type === 'string') {
-      validObj[paramName] = value.toString();
-    }
-  }
-
-  return validObj as T;
-}
+import {validator} from '@alwatr/validator';
 
 // number
 console.log(validator<{a: number}>({a: 2}, {a: 'number'}));
diff --git a/yarn.lock b/yarn.lock
index a50785ccc..1887dbc1e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,6 +2,13 @@
 # yarn lockfile v1
 
 
+"@alwatr/math@~0.26.0":
+  version "0.26.0"
+  resolved "https://registry.yarnpkg.com/@alwatr/math/-/math-0.26.0.tgz#924cb6c0f0ada5929b96cf718d4b6238ceab6446"
+  integrity sha512-iP8GJErkWw4Yh/GAX1yUOM5jB+Jw6aSAVzGRgsurdwqIfeZVSkvgB5VCSU2ZR0t2OWju2OEUvPfEwV2cIbdLsw==
+  dependencies:
+    tslib "~2.4.1"
+
 "@ampproject/remapping@^2.1.0":
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"

From 4e99b8078455443e70aab5ebdbe30c21152b48ae Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Sat, 24 Dec 2022 15:00:36 +0330
Subject: [PATCH 06/23] feat(validator): throw value in error

---
 core/validator/src/validator.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/core/validator/src/validator.ts b/core/validator/src/validator.ts
index c6021e6d0..7ecbbf650 100644
--- a/core/validator/src/validator.ts
+++ b/core/validator/src/validator.ts
@@ -24,7 +24,7 @@ function validator<DataType extends Record<string, unknown>>(value: Record<strin
         throw new Error('invalid_type', {
           cause: {
             name: 'boolean_validator',
-            message: `'${validValue}' not valid`,
+            message: JSON.stringify(value),
           },
         });
       }
@@ -37,7 +37,7 @@ function validator<DataType extends Record<string, unknown>>(value: Record<strin
         throw new Error('invalid_type', {
           cause: {
             name: 'number_validator',
-            message: `'${validValue}' not valid`,
+            message: JSON.stringify(value),
           },
         });
       }

From 635866d81134df0db46fc44b7ed7575e0486f9cd Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Sat, 24 Dec 2022 15:02:13 +0330
Subject: [PATCH 07/23] fix(validator): deps

---
 core/validator/package.json | 2 +-
 yarn.lock                   | 7 -------
 2 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/core/validator/package.json b/core/validator/package.json
index bba05d334..ec1f23000 100644
--- a/core/validator/package.json
+++ b/core/validator/package.json
@@ -33,6 +33,6 @@
   },
   "dependencies": {
     "tslib": "~2.4.1",
-    "@alwatr/validator": "~0.26.0"
+    "@alwatr/math": "~0.26.0"
   }
 }
diff --git a/yarn.lock b/yarn.lock
index 1887dbc1e..a50785ccc 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,13 +2,6 @@
 # yarn lockfile v1
 
 
-"@alwatr/math@~0.26.0":
-  version "0.26.0"
-  resolved "https://registry.yarnpkg.com/@alwatr/math/-/math-0.26.0.tgz#924cb6c0f0ada5929b96cf718d4b6238ceab6446"
-  integrity sha512-iP8GJErkWw4Yh/GAX1yUOM5jB+Jw6aSAVzGRgsurdwqIfeZVSkvgB5VCSU2ZR0t2OWju2OEUvPfEwV2cIbdLsw==
-  dependencies:
-    tslib "~2.4.1"
-
 "@ampproject/remapping@^2.1.0":
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"

From af237db8e0c2f5cd37d487304f2097bed95e3a90 Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Mon, 26 Dec 2022 07:41:29 +0330
Subject: [PATCH 08/23] fix(validator): readme

---
 core/validator/README.md | 211 +--------------------------------------
 1 file changed, 2 insertions(+), 209 deletions(-)

diff --git a/core/validator/README.md b/core/validator/README.md
index 9f8034124..d9e0003ab 100644
--- a/core/validator/README.md
+++ b/core/validator/README.md
@@ -1,210 +1,3 @@
-# Alwatr Math - `@alwatr/math`
+# Alwatr Math - `@alwatr/validator`
 
-Simple useful Math library written in tiny TypeScript module.
-
-## API
-
-### `UnicodeDigits(fromLanguages: Array<UnicodeLangKeys> | 'all' | 'common', toLanguage: UnicodeLangKeys)`
-
-Translate number.
-
-- **fromLanguages** The source language to be translated.
-- **toLanguages** The dest language to be translated.
-
-Example:
-
-```ts
-const unicodeDigits = new UnicodeDigits('common', 'en');
-
-const list = [
-  '0123456789',
-  '٠١٢٣٤٥٦٧٨٩',
-  '߀߁߂߃߄߅߆߇߈߉',
-  '०१२३४५६७८९',
-  '০১২৩৪৫৬৭৮৯',
-  '੦੧੨੩੪੫੬੭੮੯',
-  '૦૧૨૩૪૫૬૭૮૯',
-  '୦୧୨୩୪୫୬୭୮୯',
-  '௦௧௨௩௪௫௬௭௮௯',
-].join('\n');
-
-console.log(unicodeDigits.translate(list));
-```
-
-### `unicodeDigits.translate(str: string): string`
-
-Convert the String of number of the source language to the destination language.
-
-- **str** is String of number of the source language.
-
-@TODO: update from ts files docs
-
-### `isNumber(value: unknown): boolean`
-
-Check the value is number or can convert to a number, for example string ' 123 ' can be converted to 123.
-
-#### Why is this needed?
-
-```ts
-console.log(typeof '123'); //=> 'string'
-console.log(+[]); //=> 0
-console.log(+''); //=> 0
-console.log(+'   '); //=> 0
-console.log(typeof NaN); //=> 'number'
-console.log(typeof Infinity); //=> 'number'
-```
-
-#### True
-
-<!-- prettier-ignore -->
-```ts
-import {isNumber} from 'https://esm.run/@alwatr/math';
-
-isNumber(5e3);               // true
-isNumber(0xff);              // true
-isNumber(-1.1);              // true
-isNumber(0);                 // true
-isNumber(1);                 // true
-isNumber(1.1);               // true
-isNumber('-1.1');            // true
-isNumber('0');               // true
-isNumber('0xff');            // true
-isNumber('1');               // true
-isNumber('1.1');             // true
-isNumber('5e3');             // true
-isNumber('012');             // true
-isNumber(parseInt('012'));   // true
-isNumber(parseFloat('012')); // true
-```
-
-#### False
-
-<!-- prettier-ignore -->
-```ts
-import {isNumber} from 'https://esm.run/@alwatr/math';
-
-isNumber(Infinity);          // false
-isNumber(NaN);               // false
-isNumber(null);              // false
-isNumber(undefined);         // false
-isNumber('');                // false
-isNumber('   ');             // false
-isNumber('foo');             // false
-isNumber([1]);               // false
-isNumber([]);                // false
-isNumber(function () {});    // false
-isNumber({});                // false
-```
-
-### `transformToRange(x: number, options}): number`
-
-Transform a number from one range to another.
-
-Options:
-
-```ts
-{
-  /**
-   * The input range [min, max].
-   *
-   */
-  in: [number, number];
-
-  /**
-   * The output (request) range [min, max].
-   */
-  out: [number, number];
-
-  /**
-   * If true, the output will be bounded to the output range (between min and max).
-   *
-   * In default behavior when x (input number) does not between input min~max range,
-   * the output value will be out of output min~max range.
-   *
-   */
-  bound?: boolean;
-}
-```
-
-#### Example
-
-```ts
-transformToRange(5, {in: [0, 10], out: [0, 100]}); // => 50
-```
-
-Make percentage of any value
-
-```ts
-transformToRange(2000, {in: [0, 5000], out: [0, 100]}); // => 40
-```
-
-Calculate progress-bar with
-
-```ts
-const progressOuterWith = 400; //px
-const gap = 5; //px (the visual gap between progressBar and component outer).
-const currentProgress = 30; //%
-
-const progressBarWith = transformToRange(currentProgress, {
-  in: [0, 100],
-  out: [componentPadding, progressOuterWith - componentPadding],
-  bound: true,
-});
-
-this.progressBar.style.width = `${progressBarWith}px`;
-```
-
-### Generate Random
-
-### `value`
-
-Returns a float random number between 0 and 1 (1 Not included).
-
-```ts
-console.log(random.value); // 0.7124123
-```
-
-### `random.integer(min: number, max: number): number`
-
-Generate a random integer between min and max.
-
-```ts
-console.log(random.integer(1, 10)); // somewhere between 1 and 10
-```
-
-### `random.float(min: number, max: number): number`
-
-Generate a random float between min and max.
-
-```ts
-console.log(random.float(1, 10)); // somewhere between 1 and 10
-```
-
-### `string: (min: number, max?: number): string`
-
-Generate a random string with random length.
-The string will contain only characters from the characters list.
-The length of the string will be between min and max (max included).
-If max not specified, the length will be set to min.
-
-```ts
-console.log(random.string(6)); // something like 'Aab1V2'
-```
-
-### `step(min: number, max: number, step: number): number`
-
-Generate a random integer between min and max with a step.
-
-```ts
-console.log(random.step(6, 10, 2)); // 6 or 8 or 10
-```
-
-### `shuffle(array: any[]): any[]`
-
-Shuffle an array.
-
-```ts
-const array = [1, 2, 3, 4, 5];
-random.shuffle(array);
-console.log(array); // [2, 4, 3, 1, 5]
-```
+Simple useful validator library written in tiny TypeScript module.

From 593b4a499529d995836c7a91abc979c4b3a5543b Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Mon, 26 Dec 2022 08:06:27 +0330
Subject: [PATCH 09/23] fix(validator): boolean validator

---
 core/validator/src/validator.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/validator/src/validator.ts b/core/validator/src/validator.ts
index 7ecbbf650..7b47940d1 100644
--- a/core/validator/src/validator.ts
+++ b/core/validator/src/validator.ts
@@ -18,7 +18,7 @@ function validator<DataType extends Record<string, unknown>>(value: Record<strin
 
     if (valueType === 'boolean') {
       if (validValue === true || validValue === false) {
-        value[paramName] = true;
+        value[paramName] = validValue;
       }
       else {
         throw new Error('invalid_type', {

From bd7391cd74ac7717b1a253604fa304b8279ddb71 Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Mon, 26 Dec 2022 08:06:49 +0330
Subject: [PATCH 10/23] chore(validator): improve logging

---
 core/validator/src/validator.ts | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/core/validator/src/validator.ts b/core/validator/src/validator.ts
index 7b47940d1..f262ecb63 100644
--- a/core/validator/src/validator.ts
+++ b/core/validator/src/validator.ts
@@ -9,6 +9,7 @@ function validator<DataType extends Record<string, unknown>>(value: Record<strin
     if (!Object.prototype.hasOwnProperty.call(schema, paramName)) continue;
 
     const valueType = schema[paramName];
+    // nested object
     if (typeof schema[paramName] === 'object') {
       value[paramName] =
         validator<DataType>(value[paramName] as Record<string, unknown>, schema[paramName] as schema);
@@ -23,7 +24,7 @@ function validator<DataType extends Record<string, unknown>>(value: Record<strin
       else {
         throw new Error('invalid_type', {
           cause: {
-            name: 'boolean_validator',
+            name: 'boolean',
             message: JSON.stringify(value),
           },
         });
@@ -36,7 +37,7 @@ function validator<DataType extends Record<string, unknown>>(value: Record<strin
       else {
         throw new Error('invalid_type', {
           cause: {
-            name: 'number_validator',
+            name: 'number',
             message: JSON.stringify(value),
           },
         });

From da915461583440d655f26c89c0c29b5c9cb74c6e Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Mon, 26 Dec 2022 08:07:45 +0330
Subject: [PATCH 11/23] feat(validator): export schema type

---
 core/validator/src/type.ts      | 4 ++--
 core/validator/src/validator.ts | 8 ++++----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/core/validator/src/type.ts b/core/validator/src/type.ts
index 3431136f0..966edd2cf 100644
--- a/core/validator/src/type.ts
+++ b/core/validator/src/type.ts
@@ -1,3 +1,3 @@
-export type schema = {
-  [key: string]: schema | 'string' | 'number' | 'boolean';
+export type Schema = {
+  [key: string]: Schema | 'string' | 'number' | 'boolean';
 }
diff --git a/core/validator/src/validator.ts b/core/validator/src/validator.ts
index f262ecb63..e0160875e 100644
--- a/core/validator/src/validator.ts
+++ b/core/validator/src/validator.ts
@@ -1,10 +1,10 @@
 import {isNumber} from '@alwatr/math';
 
-import type {schema} from './type.js';
+import type {Schema} from './type.js';
 
-export {validator};
+export {validator, Schema};
 
-function validator<DataType extends Record<string, unknown>>(value: Record<string, unknown>, schema: schema): DataType {
+function validator<DataType extends Record<string, unknown>>(value: Record<string, unknown>, schema: Schema): DataType {
   for (const paramName in schema) {
     if (!Object.prototype.hasOwnProperty.call(schema, paramName)) continue;
 
@@ -12,7 +12,7 @@ function validator<DataType extends Record<string, unknown>>(value: Record<strin
     // nested object
     if (typeof schema[paramName] === 'object') {
       value[paramName] =
-        validator<DataType>(value[paramName] as Record<string, unknown>, schema[paramName] as schema);
+        validator<DataType>(value[paramName] as Record<string, unknown>, schema[paramName] as Schema);
     }
 
     const validValue = value[paramName] as string | number | boolean;

From 4f11b61af433f348cc4a4bd5f837848c6c1298a4 Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Mon, 26 Dec 2022 08:19:49 +0330
Subject: [PATCH 12/23] feat(validator): update demo

---
 demo/validator/validator.ts | 24 ++++++++++--------------
 1 file changed, 10 insertions(+), 14 deletions(-)

diff --git a/demo/validator/validator.ts b/demo/validator/validator.ts
index 36912759f..3015e9c6d 100644
--- a/demo/validator/validator.ts
+++ b/demo/validator/validator.ts
@@ -5,20 +5,16 @@ console.log(validator<{a: number}>({a: 2}, {a: 'number'}));
 console.log(validator<{a: number}>({a: '2'}, {a: 'number'}));
 
 // boolean
-console.log(validator<{a: boolean}>({a: '1'}, {a: 'boolean'}));
-console.log(validator<{a: boolean}>({a: 'true'}, {a: 'boolean'}));
-console.log(validator<{a: boolean}>({a: '0'}, {a: 'boolean'}));
-console.log(validator<{a: boolean}>({a: 'false'}, {a: 'boolean'}));
+console.log(validator<{a: boolean}>({a: true}, {a: 'boolean'}));
+console.log(validator<{a: boolean}>({a: false}, {a: 'boolean'}));
 
 // string
-console.log(validator<{a: string}>({a: false}, {a: 'string'}));
-console.log(validator<{a: string}>({a: 'false'}, {a: 'string'}));
-console.log(validator<{a: string}>({a: 1}, {a: 'string'}));
+console.log(validator<{a: string}>({a: 'salam'}, {a: 'string'}));
 
 // nested object
 console.log(
-    validator<{a: number; b: {c: boolean}}>(
-        {a: '2', b: {c: 'true', d: {e: 1}}},
+    validator<{a: number; b: {c: boolean, d: {e: number}}}>(
+        {a: '2', b: {c: true, d: {e: 1}}},
         {a: 'number', b: {c: 'boolean', d: {e: 'number'}}},
     ),
 );
@@ -26,19 +22,19 @@ console.log(
 // not valid
 try {
   console.log(
-      validator<{a: number; b: {c: boolean}}>(
-          {a: '2', b: {c: 'true', d: {e: true}}},
+      validator<{a: number; b: {c: boolean, d: {e: number}}}>(
+          {a: '2', b: {c: true, d: {e: true}}},
           {a: 'number', b: {c: 'boolean', d: {e: 'number'}}},
       ),
   );
 }
 catch (error) {
-  console.log(error as Error);
+  console.log(error);
 }
 
 try {
-  console.log(validator<{a: boolean}>({a: 'tru'}, {a: 'boolean'}));
+  console.log(validator<{a: boolean}>({a: 'test'}, {a: 'boolean'}));
 }
 catch (error) {
-  console.log(error as Error);
+  console.log(error);
 }

From b68b2e4671ff30efcc817213e4bf9bee9c322d90 Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Mon, 26 Dec 2022 08:20:03 +0330
Subject: [PATCH 13/23] feat(validator): rename var

---
 core/validator/src/validator.ts | 33 +++++++++++++++++++++------------
 1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/core/validator/src/validator.ts b/core/validator/src/validator.ts
index e0160875e..e6b436b7c 100644
--- a/core/validator/src/validator.ts
+++ b/core/validator/src/validator.ts
@@ -5,21 +5,20 @@ import type {Schema} from './type.js';
 export {validator, Schema};
 
 function validator<DataType extends Record<string, unknown>>(value: Record<string, unknown>, schema: Schema): DataType {
-  for (const paramName in schema) {
-    if (!Object.prototype.hasOwnProperty.call(schema, paramName)) continue;
+  for (const instance in schema) {
+    if (!Object.prototype.hasOwnProperty.call(schema, instance)) continue;
 
-    const valueType = schema[paramName];
+    const valueType = schema[instance];
     // nested object
-    if (typeof schema[paramName] === 'object') {
-      value[paramName] =
-        validator<DataType>(value[paramName] as Record<string, unknown>, schema[paramName] as Schema);
+    if (typeof schema[instance] === 'object') {
+      value[instance] = validator<DataType>(value[instance] as Record<string, unknown>, schema[instance] as Schema);
     }
 
-    const validValue = value[paramName] as string | number | boolean;
+    const valueKey = value[instance] as string | number | boolean;
 
     if (valueType === 'boolean') {
-      if (validValue === true || validValue === false) {
-        value[paramName] = validValue;
+      if (valueKey === true || valueKey === false) {
+        value[instance] = valueKey;
       }
       else {
         throw new Error('invalid_type', {
@@ -31,8 +30,8 @@ function validator<DataType extends Record<string, unknown>>(value: Record<strin
       }
     }
     else if (valueType === 'number') {
-      if (isNumber(validValue)) {
-        value[paramName] = +validValue;
+      if (isNumber(valueKey)) {
+        value[instance] = +valueKey;
       }
       else {
         throw new Error('invalid_type', {
@@ -44,7 +43,17 @@ function validator<DataType extends Record<string, unknown>>(value: Record<strin
       }
     }
     else if (valueType === 'string') {
-      value[paramName] = validValue.toString();
+      if (typeof valueKey === 'string') {
+        value[instance] = valueKey;
+      }
+      else {
+        throw new Error('invalid_type', {
+          cause: {
+            name: 'string',
+            message: JSON.stringify(value),
+          },
+        });
+      }
     }
   }
 

From 720dbb7e9a1eb0fca53b70303e1b824348ae3709 Mon Sep 17 00:00:00 2001
From: Ali Mihandoost <ali.mihandoost@gmail.com>
Date: Sun, 1 Jan 2023 17:46:47 +0330
Subject: [PATCH 14/23] refactor(validator): review

---
 core/validator/src/type.ts      |  8 ++-
 core/validator/src/validator.ts | 92 +++++++++++++++++++++++----------
 2 files changed, 72 insertions(+), 28 deletions(-)

diff --git a/core/validator/src/type.ts b/core/validator/src/type.ts
index 966edd2cf..d5aebb766 100644
--- a/core/validator/src/type.ts
+++ b/core/validator/src/type.ts
@@ -1,3 +1,7 @@
-export type Schema = {
-  [key: string]: Schema | 'string' | 'number' | 'boolean';
+export type JsonSchema = {
+  [key: string]: JsonSchema | StringConstructor | NumberConstructor | BooleanConstructor;
+}
+
+export type ValidType = {
+  [key: string]: ValidType | string | number | boolean;
 }
diff --git a/core/validator/src/validator.ts b/core/validator/src/validator.ts
index e6b436b7c..739dfe125 100644
--- a/core/validator/src/validator.ts
+++ b/core/validator/src/validator.ts
@@ -1,61 +1,101 @@
 import {isNumber} from '@alwatr/math';
 
-import type {Schema} from './type.js';
+import type {JsonSchema, ValidType} from './type.js';
 
-export {validator, Schema};
+export {JsonSchema};
 
-function validator<DataType extends Record<string, unknown>>(value: Record<string, unknown>, schema: Schema): DataType {
-  for (const instance in schema) {
-    if (!Object.prototype.hasOwnProperty.call(schema, instance)) continue;
+export function validator<T extends ValidType>(
+    validSchema: JsonSchema,
+    targetObject: Record<string, unknown>,
+    path = '.',
+): T {
+  const validObject: ValidType = {};
 
-    const valueType = schema[instance];
-    // nested object
-    if (typeof schema[instance] === 'object') {
-      value[instance] = validator<DataType>(value[instance] as Record<string, unknown>, schema[instance] as Schema);
+  if (typeof targetObject !== 'object' || targetObject == null) {
+    throw new Error('invalid_type', {
+      cause: {
+        itemPath: path,
+        itemSchema: 'JsonSchema',
+        itemValue: String(targetObject),
+      },
+    });
+  }
+
+  for (const itemName in validSchema) {
+    if (!Object.prototype.hasOwnProperty.call(validSchema, itemName)) continue;
+
+    const itemPath = `${path}/${itemName}`;
+    const itemSchema = validSchema[itemName];
+
+    if (typeof itemSchema === 'object') {
+      // nested object
+      const itemValue = targetObject[itemName] as Record<string, unknown>;
+      validObject[itemName] = validator<ValidType>(itemSchema, itemValue, itemPath);
+      continue;
     }
+    // else
 
-    const valueKey = value[instance] as string | number | boolean;
+    const itemValue = targetObject[itemName] as string | number | boolean;
 
-    if (valueType === 'boolean') {
-      if (valueKey === true || valueKey === false) {
-        value[instance] = valueKey;
+    if (itemSchema === Boolean) {
+      const strValue = String(itemValue).toLowerCase();
+      if (strValue === 'true') {
+        validObject[itemName] = true;
+      }
+      else if (strValue === 'false') {
+        validObject[itemName] = false;
       }
       else {
         throw new Error('invalid_type', {
           cause: {
-            name: 'boolean',
-            message: JSON.stringify(value),
+            itemPath,
+            itemSchema: 'Boolean',
+            itemValue: String(itemValue),
           },
         });
       }
     }
-    else if (valueType === 'number') {
-      if (isNumber(valueKey)) {
-        value[instance] = +valueKey;
+
+    else if (itemSchema === Number) {
+      if (isNumber(itemValue)) {
+        validObject[itemName] = +itemValue;
       }
       else {
         throw new Error('invalid_type', {
           cause: {
-            name: 'number',
-            message: JSON.stringify(value),
+            itemPath,
+            itemSchema: 'Number',
+            itemValue: String(itemValue),
           },
         });
       }
     }
-    else if (valueType === 'string') {
-      if (typeof valueKey === 'string') {
-        value[instance] = valueKey;
+
+    else if (itemSchema === String) {
+      if (typeof itemValue === 'string') {
+        validObject[itemName] = itemValue;
       }
       else {
         throw new Error('invalid_type', {
           cause: {
-            name: 'string',
-            message: JSON.stringify(value),
+            itemPath,
+            itemSchema: 'String',
+            itemValue: String(itemValue),
           },
         });
       }
     }
+
+    else {
+      throw new Error('invalid_schema', {
+        cause: {
+          itemPath,
+          itemSchema: String(itemSchema),
+          itemValue: String(itemValue),
+        },
+      });
+    }
   }
 
-  return value as DataType;
+  return targetObject as T;
 }

From cc21a906b371f51696c3619fc0df0f392be99dee Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Sun, 1 Jan 2023 20:24:46 +0330
Subject: [PATCH 15/23] feat(validator): update demo

---
 core/validator/src/validator.ts |  6 +++---
 demo/validator/validator.ts     | 16 ++++++++--------
 yarn.lock                       |  7 +++++++
 3 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/core/validator/src/validator.ts b/core/validator/src/validator.ts
index 739dfe125..be918cb69 100644
--- a/core/validator/src/validator.ts
+++ b/core/validator/src/validator.ts
@@ -48,7 +48,7 @@ export function validator<T extends ValidType>(
       else {
         throw new Error('invalid_type', {
           cause: {
-            itemPath,
+            itemPath: itemPath,
             itemSchema: 'Boolean',
             itemValue: String(itemValue),
           },
@@ -63,7 +63,7 @@ export function validator<T extends ValidType>(
       else {
         throw new Error('invalid_type', {
           cause: {
-            itemPath,
+            itemPath: itemPath,
             itemSchema: 'Number',
             itemValue: String(itemValue),
           },
@@ -78,7 +78,7 @@ export function validator<T extends ValidType>(
       else {
         throw new Error('invalid_type', {
           cause: {
-            itemPath,
+            itemPath: itemPath,
             itemSchema: 'String',
             itemValue: String(itemValue),
           },
diff --git a/demo/validator/validator.ts b/demo/validator/validator.ts
index 3015e9c6d..3e51cb605 100644
--- a/demo/validator/validator.ts
+++ b/demo/validator/validator.ts
@@ -1,21 +1,21 @@
 import {validator} from '@alwatr/validator';
 
 // number
-console.log(validator<{a: number}>({a: 2}, {a: 'number'}));
-console.log(validator<{a: number}>({a: '2'}, {a: 'number'}));
+console.log(validator<{a: number}>({a: Number}, {a: 2}));
+console.log(validator<{a: number}>({a: Number}, {a: '2'}));
 
 // boolean
-console.log(validator<{a: boolean}>({a: true}, {a: 'boolean'}));
-console.log(validator<{a: boolean}>({a: false}, {a: 'boolean'}));
+console.log(validator<{a: boolean}>({a: Boolean}, {a: 'false'}));
+console.log(validator<{a: boolean}>({a: Boolean}, {a: 'true'}));
 
 // string
-console.log(validator<{a: string}>({a: 'salam'}, {a: 'string'}));
+console.log(validator<{a: string}>({a: String}, {a: 'salam'}));
 
 // nested object
 console.log(
     validator<{a: number; b: {c: boolean, d: {e: number}}}>(
+        {a: Number, b: {c: Boolean, d: {e: Number}}},
         {a: '2', b: {c: true, d: {e: 1}}},
-        {a: 'number', b: {c: 'boolean', d: {e: 'number'}}},
     ),
 );
 
@@ -23,8 +23,8 @@ console.log(
 try {
   console.log(
       validator<{a: number; b: {c: boolean, d: {e: number}}}>(
+          {a: Number, b: {c: Boolean, d: {e: Number}}},
           {a: '2', b: {c: true, d: {e: true}}},
-          {a: 'number', b: {c: 'boolean', d: {e: 'number'}}},
       ),
   );
 }
@@ -33,7 +33,7 @@ catch (error) {
 }
 
 try {
-  console.log(validator<{a: boolean}>({a: 'test'}, {a: 'boolean'}));
+  console.log(validator<{a: boolean}>({a: Boolean}, {a: 'test'}));
 }
 catch (error) {
   console.log(error);
diff --git a/yarn.lock b/yarn.lock
index a50785ccc..a4f304fd8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,6 +2,13 @@
 # yarn lockfile v1
 
 
+"@alwatr/math@~0.26.0":
+  version "0.26.1"
+  resolved "https://registry.yarnpkg.com/@alwatr/math/-/math-0.26.1.tgz#9165b9212fdf5a7c0576d8fa6aa2b58dc9a3d750"
+  integrity sha512-BPxV+Kl6Z3ErQVEH2JqLMEdhRNr70u0vXma/dPx81J+YbXiM5RP6ftxZto2wSuTvIcB++Wajg3KhIUke/wmJ7g==
+  dependencies:
+    tslib "~2.4.1"
+
 "@ampproject/remapping@^2.1.0":
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"

From 48779b1617e319cc3411aae3aaef2e94d303374c Mon Sep 17 00:00:00 2001
From: Ali Mihandoost <ali.mihandoost@gmail.com>
Date: Tue, 3 Jan 2023 15:16:36 +0330
Subject: [PATCH 16/23] fix(tsconfig): add missing core/validator

---
 tsconfig.json | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tsconfig.json b/tsconfig.json
index c5c50bc56..47100cfb1 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -20,6 +20,7 @@
     {"path": "./core/storage-engine"},
     {"path": "./core/storage-client"},
     {"path": "./core/token"},
+    {"path": "./core/validator"},
     {"path": "./core/type"},
 
     // ui

From 88bcfff8a144315884690367e738bd3249b3623c Mon Sep 17 00:00:00 2001
From: Ali Mihandoost <ali.mihandoost@gmail.com>
Date: Tue, 3 Jan 2023 15:16:56 +0330
Subject: [PATCH 17/23] refactor(validator): rollback cause.itemPath

---
 core/validator/src/validator.ts | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/core/validator/src/validator.ts b/core/validator/src/validator.ts
index be918cb69..739dfe125 100644
--- a/core/validator/src/validator.ts
+++ b/core/validator/src/validator.ts
@@ -48,7 +48,7 @@ export function validator<T extends ValidType>(
       else {
         throw new Error('invalid_type', {
           cause: {
-            itemPath: itemPath,
+            itemPath,
             itemSchema: 'Boolean',
             itemValue: String(itemValue),
           },
@@ -63,7 +63,7 @@ export function validator<T extends ValidType>(
       else {
         throw new Error('invalid_type', {
           cause: {
-            itemPath: itemPath,
+            itemPath,
             itemSchema: 'Number',
             itemValue: String(itemValue),
           },
@@ -78,7 +78,7 @@ export function validator<T extends ValidType>(
       else {
         throw new Error('invalid_type', {
           cause: {
-            itemPath: itemPath,
+            itemPath,
             itemSchema: 'String',
             itemValue: String(itemValue),
           },

From aa44ed0b18cca15a0c689f9bdb9ce584b0a55eb0 Mon Sep 17 00:00:00 2001
From: Ali Mihandoost <ali.mihandoost@gmail.com>
Date: Tue, 3 Jan 2023 15:20:52 +0330
Subject: [PATCH 18/23] fix(validator): return validObject

---
 core/validator/src/validator.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/validator/src/validator.ts b/core/validator/src/validator.ts
index 739dfe125..72477749e 100644
--- a/core/validator/src/validator.ts
+++ b/core/validator/src/validator.ts
@@ -97,5 +97,5 @@ export function validator<T extends ValidType>(
     }
   }
 
-  return targetObject as T;
+  return validObject as T;
 }

From c063f18b68d2b718bfbfd37abb95f8289eae62e0 Mon Sep 17 00:00:00 2001
From: Ali Mihandoost <ali.mihandoost@gmail.com>
Date: Tue, 3 Jan 2023 15:36:00 +0330
Subject: [PATCH 19/23] refactor(validator): change original object

---
 core/validator/src/validator.ts | 42 ++++++++++++++++++++-------------
 1 file changed, 25 insertions(+), 17 deletions(-)

diff --git a/core/validator/src/validator.ts b/core/validator/src/validator.ts
index 72477749e..f4bdf8f93 100644
--- a/core/validator/src/validator.ts
+++ b/core/validator/src/validator.ts
@@ -9,8 +9,6 @@ export function validator<T extends ValidType>(
     targetObject: Record<string, unknown>,
     path = '.',
 ): T {
-  const validObject: ValidType = {};
-
   if (typeof targetObject !== 'object' || targetObject == null) {
     throw new Error('invalid_type', {
       cause: {
@@ -21,29 +19,39 @@ export function validator<T extends ValidType>(
     });
   }
 
-  for (const itemName in validSchema) {
-    if (!Object.prototype.hasOwnProperty.call(validSchema, itemName)) continue;
+  for (const itemName in targetObject) {
+    if (!Object.prototype.hasOwnProperty.call(targetObject, itemName)) continue;
 
     const itemPath = `${path}/${itemName}`;
     const itemSchema = validSchema[itemName];
+    const itemValue = targetObject[itemName] as string | number | boolean | Record<string, unknown>;
 
-    if (typeof itemSchema === 'object') {
-      // nested object
-      const itemValue = targetObject[itemName] as Record<string, unknown>;
-      validObject[itemName] = validator<ValidType>(itemSchema, itemValue, itemPath);
-      continue;
+    if (itemSchema == null) {
+      throw new Error('invalid_type', {
+        cause: {
+          itemPath,
+          itemSchema: 'undefined',
+          itemValue: String(itemValue),
+        },
+      });
     }
-    // else
 
-    const itemValue = targetObject[itemName] as string | number | boolean;
+    else if (typeof itemSchema === 'object') {
+      // nested object
+      targetObject[itemName] = validator<ValidType>(
+          itemSchema,
+          itemValue as Record<string, unknown>,
+          itemPath,
+      );
+    }
 
-    if (itemSchema === Boolean) {
+    else if (itemSchema === Boolean) {
       const strValue = String(itemValue).toLowerCase();
       if (strValue === 'true') {
-        validObject[itemName] = true;
+        targetObject[itemName] = true;
       }
       else if (strValue === 'false') {
-        validObject[itemName] = false;
+        targetObject[itemName] = false;
       }
       else {
         throw new Error('invalid_type', {
@@ -58,7 +66,7 @@ export function validator<T extends ValidType>(
 
     else if (itemSchema === Number) {
       if (isNumber(itemValue)) {
-        validObject[itemName] = +itemValue;
+        targetObject[itemName] = +itemValue;
       }
       else {
         throw new Error('invalid_type', {
@@ -73,7 +81,7 @@ export function validator<T extends ValidType>(
 
     else if (itemSchema === String) {
       if (typeof itemValue === 'string') {
-        validObject[itemName] = itemValue;
+        targetObject[itemName] = itemValue;
       }
       else {
         throw new Error('invalid_type', {
@@ -97,5 +105,5 @@ export function validator<T extends ValidType>(
     }
   }
 
-  return validObject as T;
+  return targetObject as T;
 }

From 7c02422e9caf9ab5dd8e352714db346518229d59 Mon Sep 17 00:00:00 2001
From: Ali Mihandoost <ali.mihandoost@gmail.com>
Date: Tue, 3 Jan 2023 16:07:37 +0330
Subject: [PATCH 20/23] feat(validator): enum values

---
 core/validator/src/type.ts      | 17 +++++++++++++----
 core/validator/src/validator.ts | 18 ++++++++++--------
 2 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/core/validator/src/type.ts b/core/validator/src/type.ts
index d5aebb766..28a563b01 100644
--- a/core/validator/src/type.ts
+++ b/core/validator/src/type.ts
@@ -1,7 +1,16 @@
 export type JsonSchema = {
-  [key: string]: JsonSchema | StringConstructor | NumberConstructor | BooleanConstructor;
-}
+  [key: string]:
+    | JsonSchema
+    | StringConstructor
+    | NumberConstructor
+    | BooleanConstructor
+    | string
+    | number
+    | boolean
+    | null
+    | undefined;
+};
 
 export type ValidType = {
-  [key: string]: ValidType | string | number | boolean;
-}
+  [key: string]: ValidType | string | number | boolean | null | undefined;
+};
diff --git a/core/validator/src/validator.ts b/core/validator/src/validator.ts
index f4bdf8f93..389c6a890 100644
--- a/core/validator/src/validator.ts
+++ b/core/validator/src/validator.ts
@@ -93,15 +93,17 @@ export function validator<T extends ValidType>(
         });
       }
     }
-
     else {
-      throw new Error('invalid_schema', {
-        cause: {
-          itemPath,
-          itemSchema: String(itemSchema),
-          itemValue: String(itemValue),
-        },
-      });
+      if (itemValue !== itemSchema) {
+        throw new Error('invalid_type', {
+          cause: {
+            message: 'invalid enum value',
+            itemPath,
+            itemSchema: String(itemSchema),
+            itemValue: String(itemValue),
+          },
+        });
+      }
     }
   }
 

From 60829a6280fdc3138f8702cee776e0dae11f548f Mon Sep 17 00:00:00 2001
From: Ali Mihandoost <ali.mihandoost@gmail.com>
Date: Tue, 3 Jan 2023 16:08:09 +0330
Subject: [PATCH 21/23] feat(validator): additionalProperties

---
 core/validator/src/validator.ts | 48 ++++++++++++++++++---------------
 1 file changed, 26 insertions(+), 22 deletions(-)

diff --git a/core/validator/src/validator.ts b/core/validator/src/validator.ts
index 389c6a890..3424afdf3 100644
--- a/core/validator/src/validator.ts
+++ b/core/validator/src/validator.ts
@@ -7,11 +7,13 @@ export {JsonSchema};
 export function validator<T extends ValidType>(
     validSchema: JsonSchema,
     targetObject: Record<string, unknown>,
+    additionalProperties = false,
     path = '.',
 ): T {
   if (typeof targetObject !== 'object' || targetObject == null) {
     throw new Error('invalid_type', {
       cause: {
+        message: 'targetObject is not a function or null',
         itemPath: path,
         itemSchema: 'JsonSchema',
         itemValue: String(targetObject),
@@ -19,32 +21,36 @@ export function validator<T extends ValidType>(
     });
   }
 
-  for (const itemName in targetObject) {
-    if (!Object.prototype.hasOwnProperty.call(targetObject, itemName)) continue;
+  if (
+    additionalProperties === false &&
+    Object.keys(validSchema).sort().join() !== Object.keys(targetObject).sort().join()
+  ) {
+    throw new Error('invalid_type', {
+      cause: {
+        message: 'Object.keys(validSchema) !== Object.keys(targetObject)',
+        itemPath: path,
+        itemSchema: String(validSchema),
+        itemValue: String(targetObject),
+      },
+    });
+  }
+
+  for (const itemName in validSchema) {
+    if (!Object.prototype.hasOwnProperty.call(validSchema, itemName)) continue;
 
     const itemPath = `${path}/${itemName}`;
     const itemSchema = validSchema[itemName];
     const itemValue = targetObject[itemName] as string | number | boolean | Record<string, unknown>;
 
-    if (itemSchema == null) {
-      throw new Error('invalid_type', {
-        cause: {
-          itemPath,
-          itemSchema: 'undefined',
-          itemValue: String(itemValue),
-        },
-      });
-    }
-
-    else if (typeof itemSchema === 'object') {
+    if (typeof itemSchema === 'object' && itemSchema != null) {
       // nested object
       targetObject[itemName] = validator<ValidType>(
           itemSchema,
-          itemValue as Record<string, unknown>,
-          itemPath,
+        itemValue as Record<string, unknown>,
+        additionalProperties,
+        itemPath,
       );
     }
-
     else if (itemSchema === Boolean) {
       const strValue = String(itemValue).toLowerCase();
       if (strValue === 'true') {
@@ -56,6 +62,7 @@ export function validator<T extends ValidType>(
       else {
         throw new Error('invalid_type', {
           cause: {
+            message: 'invalid type',
             itemPath,
             itemSchema: 'Boolean',
             itemValue: String(itemValue),
@@ -63,7 +70,6 @@ export function validator<T extends ValidType>(
         });
       }
     }
-
     else if (itemSchema === Number) {
       if (isNumber(itemValue)) {
         targetObject[itemName] = +itemValue;
@@ -71,6 +77,7 @@ export function validator<T extends ValidType>(
       else {
         throw new Error('invalid_type', {
           cause: {
+            message: 'invalid type',
             itemPath,
             itemSchema: 'Number',
             itemValue: String(itemValue),
@@ -78,14 +85,11 @@ export function validator<T extends ValidType>(
         });
       }
     }
-
     else if (itemSchema === String) {
-      if (typeof itemValue === 'string') {
-        targetObject[itemName] = itemValue;
-      }
-      else {
+      if (typeof itemValue !== 'string') {
         throw new Error('invalid_type', {
           cause: {
+            message: 'invalid type',
             itemPath,
             itemSchema: 'String',
             itemValue: String(itemValue),

From 9e577cad18be45942d36d633932ef0aa2c2ec512 Mon Sep 17 00:00:00 2001
From: Ali Mihandoost <ali.mihandoost@gmail.com>
Date: Tue, 3 Jan 2023 16:22:48 +0330
Subject: [PATCH 22/23] feat(validator): demo

---
 core/validator/src/type.ts  |  3 +-
 demo/validator/validator.ts | 59 +++++++++++++++++++++----------------
 2 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/core/validator/src/type.ts b/core/validator/src/type.ts
index 28a563b01..b03c3331b 100644
--- a/core/validator/src/type.ts
+++ b/core/validator/src/type.ts
@@ -7,8 +7,7 @@ export type JsonSchema = {
     | string
     | number
     | boolean
-    | null
-    | undefined;
+    | null;
 };
 
 export type ValidType = {
diff --git a/demo/validator/validator.ts b/demo/validator/validator.ts
index 3e51cb605..07fbae639 100644
--- a/demo/validator/validator.ts
+++ b/demo/validator/validator.ts
@@ -1,40 +1,47 @@
 import {validator} from '@alwatr/validator';
 
-// number
-console.log(validator<{a: number}>({a: Number}, {a: 2}));
-console.log(validator<{a: number}>({a: Number}, {a: '2'}));
-
-// boolean
-console.log(validator<{a: boolean}>({a: Boolean}, {a: 'false'}));
-console.log(validator<{a: boolean}>({a: Boolean}, {a: 'true'}));
+console.log('basic test');
+console.log(
+    validator<
+      {num: number; str: string; bool: boolean; _null: null; undef: undefined; ali: 'ali'; five: 5; true: true}
+    >(
+        {num: Number, str: String, bool: Boolean, _null: null, undef: undefined, ali: 'ali', five: 5, true: true},
+        {num: 123, str: 'test', bool: false, _null: null, undef: undefined, ali: 'ali', five: 5, true: true},
+    ),
+);
 
-// string
-console.log(validator<{a: string}>({a: String}, {a: 'salam'}));
+console.log('sanitize value test');
+console.log(
+    validator<
+      {num: number; str: string; bool: boolean; _null: null; undef: undefined; ali: 'ali'; five: 5; true: true}
+    >(
+        {num: Number, str: String, bool: Boolean, _null: null, undef: undefined, ali: 'ali', five: 5, true: true},
+        {num: '123', str: 'test', bool: 'false', _null: null, undef: undefined, ali: 'ali', five: 5, true: true},
+    ),
+);
 
-// nested object
+console.log('nested value test');
 console.log(
-    validator<{a: number; b: {c: boolean, d: {e: number}}}>(
-        {a: Number, b: {c: Boolean, d: {e: Number}}},
-        {a: '2', b: {c: true, d: {e: 1}}},
+    validator<
+      {a: {num: number; str: string; bool: boolean; _null: null; undef: undefined; ali: 'ali'; five: 5; true: true}}
+    >(
+        {a: {num: Number, str: String, bool: Boolean, _null: null, undef: undefined, ali: 'ali', five: 5, true: true}},
+        {a: {num: '123', str: 'test', bool: 'false', _null: null, undef: undefined, ali: 'ali', five: 5, true: true}},
     ),
 );
 
-// not valid
+console.log('not valid test');
 try {
   console.log(
-      validator<{a: number; b: {c: boolean, d: {e: number}}}>(
-          {a: Number, b: {c: Boolean, d: {e: Number}}},
-          {a: '2', b: {c: true, d: {e: true}}},
+      validator<
+        {num: number}
+      >(
+          {num: Number},
+          {num: 'asd'},
       ),
   );
+  new Error('validator_not_work');
 }
-catch (error) {
-  console.log(error);
-}
-
-try {
-  console.log(validator<{a: boolean}>({a: Boolean}, {a: 'test'}));
-}
-catch (error) {
-  console.log(error);
+catch (err) {
+  console.log('test ok, error cause: ', (err as Error).cause);
 }

From d49929fca0007aa94482010b7a6245f0bb360bc0 Mon Sep 17 00:00:00 2001
From: "S. Amir Mohammad Najafi" <njfamirm@gmail.com>
Date: Tue, 3 Jan 2023 17:18:19 +0330
Subject: [PATCH 23/23] feat(validator): update demo

---
 core/validator/src/type.ts  |   2 +-
 demo/validator/validator.ts | 109 ++++++++++++++++++++++++++++++++----
 2 files changed, 98 insertions(+), 13 deletions(-)

diff --git a/core/validator/src/type.ts b/core/validator/src/type.ts
index b03c3331b..d770f237a 100644
--- a/core/validator/src/type.ts
+++ b/core/validator/src/type.ts
@@ -11,5 +11,5 @@ export type JsonSchema = {
 };
 
 export type ValidType = {
-  [key: string]: ValidType | string | number | boolean | null | undefined;
+  [key: string]: ValidType | string | number | boolean | null;
 };
diff --git a/demo/validator/validator.ts b/demo/validator/validator.ts
index 07fbae639..f151fe63c 100644
--- a/demo/validator/validator.ts
+++ b/demo/validator/validator.ts
@@ -3,30 +3,30 @@ import {validator} from '@alwatr/validator';
 console.log('basic test');
 console.log(
     validator<
-      {num: number; str: string; bool: boolean; _null: null; undef: undefined; ali: 'ali'; five: 5; true: true}
+      {num: number; str: string; bool: boolean; _null: null; ali: 'ali'; five: 5; true: true}
     >(
-        {num: Number, str: String, bool: Boolean, _null: null, undef: undefined, ali: 'ali', five: 5, true: true},
-        {num: 123, str: 'test', bool: false, _null: null, undef: undefined, ali: 'ali', five: 5, true: true},
+        {num: Number, str: String, bool: Boolean, _null: null, ali: 'ali', five: 5, true: true},
+        {num: 123, str: 'test', bool: false, _null: null, ali: 'ali', five: 5, true: true},
     ),
 );
 
 console.log('sanitize value test');
 console.log(
     validator<
-      {num: number; str: string; bool: boolean; _null: null; undef: undefined; ali: 'ali'; five: 5; true: true}
+      {num: number; str: string; bool: boolean; _null: null; ali: 'ali'; five: 5; true: true}
     >(
-        {num: Number, str: String, bool: Boolean, _null: null, undef: undefined, ali: 'ali', five: 5, true: true},
-        {num: '123', str: 'test', bool: 'false', _null: null, undef: undefined, ali: 'ali', five: 5, true: true},
+        {num: Number, str: String, bool: Boolean, _null: null, ali: 'ali', five: 5, true: true},
+        {num: '123', str: 'test', bool: 'false', _null: null, ali: 'ali', five: 5, true: true},
     ),
 );
 
 console.log('nested value test');
 console.log(
     validator<
-      {a: {num: number; str: string; bool: boolean; _null: null; undef: undefined; ali: 'ali'; five: 5; true: true}}
+      {a: {num: number; str: string; bool: boolean; _null: null; ali: 'ali'; five: 5; true: true}}
     >(
-        {a: {num: Number, str: String, bool: Boolean, _null: null, undef: undefined, ali: 'ali', five: 5, true: true}},
-        {a: {num: '123', str: 'test', bool: 'false', _null: null, undef: undefined, ali: 'ali', five: 5, true: true}},
+        {a: {num: Number, str: String, bool: Boolean, _null: null, ali: 'ali', five: 5, true: true}},
+        {a: {num: '123', str: 'test', bool: 'false', _null: null, ali: 'ali', five: 5, true: true}},
     ),
 );
 
@@ -37,11 +37,96 @@ try {
         {num: number}
       >(
           {num: Number},
-          {num: 'asd'},
+          {num: 'test'},
       ),
   );
-  new Error('validator_not_work');
+  throw new Error('validator_not_work');
 }
 catch (err) {
-  console.log('test ok, error cause: ', (err as Error).cause);
+  if ((err as Error).message !== 'validator_not_work') {
+    console.log('test ok, error message `%s`, error cause: %s', (err as Error).message, (err as Error).cause);
+  }
+  else {
+    throw err;
+  }
+}
+
+try {
+  console.log(
+      validator<
+        {num: boolean}
+      >(
+          {num: Boolean},
+          {num: 'true'},
+      ),
+  );
+  throw new Error('validator_not_work');
+}
+catch (err) {
+  if ((err as Error).message !== 'validator_not_work') {
+    console.log('test ok, error message `%s`, error cause: %s', (err as Error).message, (err as Error).cause);
+  }
+  else {
+    throw err;
+  }
+}
+
+try {
+  console.log(
+      validator<
+        {num: null}
+      >(
+          {num: null},
+          {num: 'test'},
+      ),
+  );
+  throw new Error('validator_not_work');
+}
+catch (err) {
+  if ((err as Error).message !== 'validator_not_work') {
+    console.log('test ok, error message `%s`, error cause: %s', (err as Error).message, (err as Error).cause);
+  }
+  else {
+    throw err;
+  }
+}
+
+try {
+  console.log(
+      validator<
+        {num: number}
+      >(
+          {num: Number},
+          {num: 'test'},
+      ),
+  );
+  throw new Error('validator_not_work');
+}
+catch (err) {
+  if ((err as Error).message !== 'validator_not_work') {
+    console.log('test ok, error message `%s`, error cause: %s', (err as Error).message, (err as Error).cause);
+  }
+  else {
+    throw err;
+  }
+}
+
+try {
+  console.log(
+      validator<
+        {num: string}
+      >(
+          {num: 'test'},
+          {num: 'tes'},
+      ),
+  );
+  throw new Error('validator_not_work');
+}
+catch (err) {
+  if ((err as Error).message !== 'validator_not_work') {
+    console.log('test ok, error message `%s`, error cause: %s', (err as Error).message, (err as Error).cause);
+  }
+  else {
+    throw err;
+  }
 }