Repository: icebob/fastest-validator (js)

Issue:
UUID v7 and v8 do not pass validation
Despite being perfectly valid versions, [UUIDv7](https://datatracker.ietf.org/doc/html/rfc9562#name-uuid-version-7) and [UUIDv8](https://datatracker.ietf.org/doc/html/rfc9562#name-uuid-version-8) are flagged as invalid by the `uuid` type validator.

The UUID validator and types needs to be updated to properly take those two versions into account.

Actual behavior:
```js
const checkUUID = v.compile({ $$root: true, type: "uuid" });
checkUUID("01965dfe-77ac-78e2-9f69-51e5ce8bd080") // not true
```

Pull request:
fix false negative check on UUID v7 and v8
As per [RFC9562](https://datatracker.ietf.org/doc/html/rfc9562#table2) uuid v7 and v8 do exists and thus are perfectly valid versions.

I'm modifying the uuid regex to be able to validate those specific versions.

fix #352 

Patch:
diff --git a/index.d.ts b/index.d.ts
index a2db52f..dd43bd1 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -558,7 +558,7 @@ export interface RuleUUID extends RuleCustom {
 	/**
 	 * UUID version in range 0-6
 	 */
-	version?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
+	version?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
 }
 
 export interface RuleObjectID extends RuleCustom {
diff --git a/lib/rules/uuid.js b/lib/rules/uuid.js
index ab95f29..13d7489 100644
--- a/lib/rules/uuid.js
+++ b/lib/rules/uuid.js
@@ -1,6 +1,6 @@
 "use strict";
 
-const PATTERN = /^([0-9a-f]{8}-[0-9a-f]{4}-[1-6][0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}|[0]{8}-[0]{4}-[0]{4}-[0]{4}-[0]{12})$/i;
+const PATTERN = /^([0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}|[0]{8}-[0]{4}-[0]{4}-[0]{4}-[0]{12})$/i;
 
 /**	Signature: function(value, field, parent, errors, context)
  */
@@ -21,7 +21,7 @@ module.exports = function({ schema, messages }, path) {
 		const version = val.charAt(14) | 0;
 	`);
 
-	if(parseInt(schema.version) < 7) {
+	if(parseInt(schema.version) < 9) {
 		src.push(`
 			if (${schema.version} !== version) {
 				${this.makeError({ type: "uuidVersion", expected: schema.version, actual: "version", messages })}
@@ -40,6 +40,8 @@ module.exports = function({ schema, messages }, path) {
 		case 3:
 		case 4:
 		case 5:
+  		case 7:
+		case 8:
 			if (["8", "9", "a", "b"].indexOf(val.charAt(19)) === -1) {
 				${this.makeError({ type: "uuid",  actual: "value", messages })}
 			}


Test patch:
diff --git a/test/rules/uuid.spec.js b/test/rules/uuid.spec.js
index dfd094a..b302bc6 100644
--- a/test/rules/uuid.spec.js
+++ b/test/rules/uuid.spec.js
@@ -37,6 +37,7 @@ describe("Test rule: uuid", () => {
 		const check3 = v.compile({ $$root: true, type: "uuid", version: 3 });
 		const check4 = v.compile({ $$root: true, type: "uuid", version: 4 });
 		const check5 = v.compile({ $$root: true, type: "uuid", version: 5 });
+		const check7 = v.compile({ $$root: true, type: "uuid", version: 7 });
 		message = "The '' field must be a valid UUID version provided.";
 
 		expect(check0("00000000-0000-1000-0000-000000000000")).toEqual([{"actual": 1, "expected": 0, "type": "uuidVersion", message}]);
@@ -47,6 +48,7 @@ describe("Test rule: uuid", () => {
 		expect(check3("9a7b330a-a736-41e5-af7f-feaf819cdc9f")).toEqual([{"actual": 4, "expected": 3, "type": "uuidVersion", message}]);
 		expect(check4("9a7b330a-a736-21e5-af7f-feaf819cdc9f")).toEqual([{"actual": 2, "expected": 4, "type": "uuidVersion", message}]);
 		expect(check5("9a7b330a-a736-11e5-af7f-feaf819cdc9f")).toEqual([{"actual": 1, "expected": 5, "type": "uuidVersion", message}]);
+		expect(check7("019681ac-4f0f-86a2-866e-5408b2d861f8")).toEqual([{"actual": 8, "expected": 7, "type": "uuidVersion", message}]);
 	});
 
 	it("check valid version", () => {
@@ -57,6 +59,8 @@ describe("Test rule: uuid", () => {
 		const check4 = v.compile({ $$root: true, type: "uuid", version: 4 });
 		const check5 = v.compile({ $$root: true, type: "uuid", version: 5 });
 		const check6 = v.compile({ $$root: true, type: "uuid", version: 6 });
+		const check7 = v.compile({ $$root: true, type: "uuid", version: 7 });
+		const check8 = v.compile({ $$root: true, type: "uuid", version: 8 });
 
 		expect(check0("00000000-0000-0000-0000-000000000000")).toEqual(true);
 		expect(check1("45745c60-7b1a-11e8-9c9c-2d42b21b1a3e")).toEqual(true);
@@ -65,6 +69,8 @@ describe("Test rule: uuid", () => {
 		expect(check4("10ba038e-48da-487b-96e8-8d3b99b6d18a")).toEqual(true);
 		expect(check5("fdda765f-fc57-5604-a269-52a7df8164ec")).toEqual(true);
 		expect(check6("a9030619-8514-6970-e0f9-81b9ceb08a5f")).toEqual(true);
+		expect(check7("01965dfe-77ac-78e2-9f69-51e5ce8bd080")).toEqual(true);
+		expect(check8("019681ac-4f0f-86a2-866e-5408b2d861f8")).toEqual(true);
 	});
 
 	it("should not be case insensitive", () => {
@@ -74,6 +80,8 @@ describe("Test rule: uuid", () => {
 		const check4 = v.compile({ $$root: true, type: "uuid", version: 4 });
 		const check5 = v.compile({ $$root: true, type: "uuid", version: 5 });
 		const check6 = v.compile({ $$root: true, type: "uuid", version: 6 });
+		const check7 = v.compile({ $$root: true, type: "uuid", version: 7 });
+		const check8 = v.compile({ $$root: true, type: "uuid", version: 8 });
 
 		expect(check1("45745c60-7b1a-11e8-9c9c-2d42b21b1a3e")).toEqual(true);
 		expect(check2("9a7b330a-a736-21e5-af7f-feaf819cdc9f")).toEqual(true);
@@ -81,6 +89,8 @@ describe("Test rule: uuid", () => {
 		expect(check4("10ba038e-48da-487b-96e8-8d3b99b6d18a")).toEqual(true);
 		expect(check5("fdda765f-fc57-5604-a269-52a7df8164ec")).toEqual(true);
 		expect(check6("a9030619-8514-6970-e0f9-81b9ceb08a5f")).toEqual(true);
+		expect(check7("01965dfe-77ac-78e2-9f69-51e5ce8bd080")).toEqual(true);
+		expect(check8("019681ac-4f0f-86a2-866e-5408b2d861f8")).toEqual(true);
 
 		expect(check1("45745C60-7B1A-11E8-9C9C-2D42B21B1A3E")).toEqual(true);
 		expect(check2("9A7B330A-A736-21E5-AF7F-FEAF819CDC9F")).toEqual(true);
@@ -88,6 +98,8 @@ describe("Test rule: uuid", () => {
 		expect(check4("10BA038E-48DA-487B-96E8-8D3B99B6D18A")).toEqual(true);
 		expect(check5("FDDA765F-FC57-5604-A269-52A7DF8164EC")).toEqual(true);
 		expect(check6("A9030619-8514-6970-E0F9-81B9CEB08A5F")).toEqual(true);
+		expect(check7("01965DFE-77AC-78E2-9F69-51E5CE8BD080")).toEqual(true);
+		expect(check8("019681AC-4F0F-86A2-866E-5408B2D861F8")).toEqual(true);
 	});
 
 	it("should allow custom metas", async () => {
diff --git a/test/typescript/rules/uuid.spec.ts b/test/typescript/rules/uuid.spec.ts
index cee0c23..c1c9a5e 100644
--- a/test/typescript/rules/uuid.spec.ts
+++ b/test/typescript/rules/uuid.spec.ts
@@ -36,6 +36,7 @@ describe('TypeScript Definitions', () => {
 			const check3 = v.compile({ $$root: true, type: 'uuid', version: 3 } as RuleUUID);
 			const check4 = v.compile({ $$root: true, type: 'uuid', version: 4 } as RuleUUID);
 			const check5 = v.compile({ $$root: true, type: 'uuid', version: 5 } as RuleUUID);
+			const check7 = v.compile({ $$root: true, type: 'uuid', version: 7 } as RuleUUID);
 			message = 'The \'\' field must be a valid UUID version provided.';
 
 			expect(check0("00000000-0000-1000-0000-000000000000")).toEqual([{ "actual": 1, "expected": 0, "type": "uuidVersion", message }]);
@@ -45,6 +46,7 @@ describe('TypeScript Definitions', () => {
 			expect(check3('9a7b330a-a736-41e5-af7f-feaf819cdc9f')).toEqual([{ 'actual': 4, 'expected': 3, 'type': 'uuidVersion', message }]);
 			expect(check4('9a7b330a-a736-21e5-af7f-feaf819cdc9f')).toEqual([{ 'actual': 2, 'expected': 4, 'type': 'uuidVersion', message }]);
 			expect(check5('9a7b330a-a736-11e5-af7f-feaf819cdc9f')).toEqual([{ 'actual': 1, 'expected': 5, 'type': 'uuidVersion', message }]);
+			expect(check7("019681ac-4f0f-86a2-866e-5408b2d861f8")).toEqual([{"actual": 8, "expected": 7, "type": "uuidVersion", message}]);
 		});
 
 		it('check valid version', () => {
@@ -54,6 +56,9 @@ describe('TypeScript Definitions', () => {
 			const check3 = v.compile({ $$root: true, type: 'uuid', version: 3 } as RuleUUID);
 			const check4 = v.compile({ $$root: true, type: 'uuid', version: 4 } as RuleUUID);
 			const check5 = v.compile({ $$root: true, type: 'uuid', version: 5 } as RuleUUID);
+			const check6 = v.compile({ $$root: true, type: 'uuid', version: 6 } as RuleUUID);
+			const check7 = v.compile({ $$root: true, type: 'uuid', version: 7 } as RuleUUID);
+			const check8 = v.compile({ $$root: true, type: 'uuid', version: 8 } as RuleUUID);
 
 			expect(check0("00000000-0000-0000-0000-000000000000")).toEqual(true);
 			expect(check1('45745c60-7b1a-11e8-9c9c-2d42b21b1a3e')).toEqual(true);
@@ -61,6 +66,9 @@ describe('TypeScript Definitions', () => {
 			expect(check3('9125a8dc-52ee-365b-a5aa-81b0b3681cf6')).toEqual(true);
 			expect(check4('10ba038e-48da-487b-96e8-8d3b99b6d18a')).toEqual(true);
 			expect(check5('fdda765f-fc57-5604-a269-52a7df8164ec')).toEqual(true);
+			expect(check6('a9030619-8514-6970-e0f9-81b9ceb08a5f')).toEqual(true);
+			expect(check7('01965dfe-77ac-78e2-9f69-51e5ce8bd080')).toEqual(true);
+			expect(check8('019681ac-4f0f-86a2-866e-5408b2d861f8')).toEqual(true);
 		});
 
 		it("should not be case insensitive", () => {
@@ -70,6 +78,8 @@ describe('TypeScript Definitions', () => {
 			const check4 = v.compile({ $$root: true, type: "uuid", version: 4 } as RuleUUID);
 			const check5 = v.compile({ $$root: true, type: "uuid", version: 5 } as RuleUUID);
 			const check6 = v.compile({ $$root: true, type: "uuid", version: 6 } as RuleUUID);
+			const check7 = v.compile({ $$root: true, type: 'uuid', version: 7 } as RuleUUID);
+			const check8 = v.compile({ $$root: true, type: 'uuid', version: 8 } as RuleUUID);
 
 			expect(check1("45745c60-7b1a-11e8-9c9c-2d42b21b1a3e")).toEqual(true);
 			expect(check2("9a7b330a-a736-21e5-af7f-feaf819cdc9f")).toEqual(true);
@@ -77,6 +87,8 @@ describe('TypeScript Definitions', () => {
 			expect(check4("10ba038e-48da-487b-96e8-8d3b99b6d18a")).toEqual(true);
 			expect(check5("fdda765f-fc57-5604-a269-52a7df8164ec")).toEqual(true);
 			expect(check6("a9030619-8514-6970-e0f9-81b9ceb08a5f")).toEqual(true);
+			expect(check7("01965dfe-77ac-78e2-9f69-51e5ce8bd080")).toEqual(true);
+			expect(check8("019681ac-4f0f-86a2-866e-5408b2d861f8")).toEqual(true);
 
 			expect(check1("45745C60-7B1A-11E8-9C9C-2D42B21B1A3E")).toEqual(true);
 			expect(check2("9A7B330A-A736-21E5-AF7F-FEAF819CDC9F")).toEqual(true);
@@ -84,6 +96,8 @@ describe('TypeScript Definitions', () => {
 			expect(check4("10BA038E-48DA-487B-96E8-8D3B99B6D18A")).toEqual(true);
 			expect(check5("FDDA765F-FC57-5604-A269-52A7DF8164EC")).toEqual(true);
 			expect(check6("A9030619-8514-6970-E0F9-81B9CEB08A5F")).toEqual(true);
+			expect(check7("01965DFE-77AC-78E2-9F69-51E5CE8BD080")).toEqual(true);
+			expect(check8("019681AC-4F0F-86A2-866E-5408B2D861F8")).toEqual(true);
 		});
 	});
 });