From 55c3f6af6a6460d0fe992533c4060df590447570 Mon Sep 17 00:00:00 2001 From: Gary Mathews Date: Fri, 16 Jun 2023 18:34:46 -0700 Subject: [PATCH] feat: support uuidv6, uuidv7 and uuidv8 guid types --- API.md | 2 +- lib/index.d.ts | 2 +- lib/types/string.js | 5 +- test/index.ts | 4 +- test/types/string.js | 323 ++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 326 insertions(+), 10 deletions(-) diff --git a/API.md b/API.md index f0af66ea..c9537770 100755 --- a/API.md +++ b/API.md @@ -2796,7 +2796,7 @@ Requires the string value to be a valid GUID. - `options` - optional settings: - `version` - specifies one or more acceptable versions. Can be an Array or String with the following values: - `uuidv1`, `uuidv2`, `uuidv3`, `uuidv4`, or `uuidv5`. If no `version` is specified then it is assumed to be a generic `guid` + `uuidv1`, `uuidv2`, `uuidv3`, `uuidv4`, `uuidv5`, `uuidv6`, `uuidv7` or `uuidv8`. If no `version` is specified then it is assumed to be a generic `guid` which will not validate the version or variant of the guid and just check for general structure format. - `separator` - defines the allowed or required GUID separator where: - `true` - a separator is required, can be either `:` or `-`. diff --git a/lib/index.d.ts b/lib/index.d.ts index aec9bb5c..d1cf90d5 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -381,7 +381,7 @@ declare namespace Joi { cidr?: PresenceMode; } - type GuidVersions = 'uuidv1' | 'uuidv2' | 'uuidv3' | 'uuidv4' | 'uuidv5'; + type GuidVersions = 'uuidv1' | 'uuidv2' | 'uuidv3' | 'uuidv4' | 'uuidv5' | 'uuidv6' | 'uuidv7' | 'uuidv8'; interface GuidOptions { version?: GuidVersions[] | GuidVersions; diff --git a/lib/types/string.js b/lib/types/string.js index cdaffc40..387c992b 100755 --- a/lib/types/string.js +++ b/lib/types/string.js @@ -39,7 +39,10 @@ const internals = { uuidv2: '2', uuidv3: '3', uuidv4: '4', - uuidv5: '5' + uuidv5: '5', + uuidv6: '6', + uuidv7: '7', + uuidv8: '8' }, guidSeparators: new Set([undefined, true, false, '-', ':']), diff --git a/test/index.ts b/test/index.ts index 628d21a4..0369e023 100644 --- a/test/index.ts +++ b/test/index.ts @@ -873,12 +873,12 @@ strSchema = strSchema.uri(); strSchema = strSchema.uri(uriOpts); strSchema = strSchema.guid(); strSchema = strSchema.guid({ - version: ['uuidv1', 'uuidv2', 'uuidv3', 'uuidv4', 'uuidv5'], + version: ['uuidv1', 'uuidv2', 'uuidv3', 'uuidv4', 'uuidv5', 'uuidv6', 'uuidv7', 'uuidv8'], }); strSchema = strSchema.guid({ version: 'uuidv4' }); strSchema = strSchema.uuid(); strSchema = strSchema.uuid({ - version: ['uuidv1', 'uuidv2', 'uuidv3', 'uuidv4', 'uuidv5'], + version: ['uuidv1', 'uuidv2', 'uuidv3', 'uuidv4', 'uuidv5', 'uuidv6', 'uuidv7', 'uuidv8'], }); strSchema = strSchema.uuid({ version: 'uuidv4' }); strSchema = strSchema.hex(); diff --git a/test/types/string.js b/test/types/string.js index fdc34744..296ac415 100755 --- a/test/types/string.js +++ b/test/types/string.js @@ -1179,7 +1179,7 @@ describe('string', () => { it('describes various versions of a guid', () => { - const schema = Joi.string().guid({ version: ['uuidv1', 'uuidv3', 'uuidv5'] }); + const schema = Joi.string().guid({ version: ['uuidv1', 'uuidv3', 'uuidv5', 'uuidv8'] }); expect(schema.describe()).to.equal({ type: 'string', @@ -1188,7 +1188,7 @@ describe('string', () => { name: 'guid', args: { options: { - version: ['uuidv1', 'uuidv3', 'uuidv5'] + version: ['uuidv1', 'uuidv3', 'uuidv5', 'uuidv8'] } } } @@ -2038,7 +2038,7 @@ describe('string', () => { it('throws when options.version is invalid', () => { expect(() => Joi.string().guid({ version: 42 })).to.throw('version at position 0 must be a string'); - expect(() => Joi.string().guid({ version: '42' })).to.throw('version at position 0 must be one of uuidv1, uuidv2, uuidv3, uuidv4, uuidv5'); + expect(() => Joi.string().guid({ version: '42' })).to.throw('version at position 0 must be one of uuidv1, uuidv2, uuidv3, uuidv4, uuidv5, uuidv6, uuidv7, uuidv8'); }); it('throws when options.separator is invalid', () => { @@ -2654,12 +2654,325 @@ describe('string', () => { ]); }); - it('validates multiple uuid versions (1,3,5)', () => { + it('validates uuidv6', () => { - Helper.validate(Joi.string().guid({ version: ['uuidv1', 'uuidv3', 'uuidv5'] }), [ + Helper.validate(Joi.string().guid({ version: ['uuidv6'] }), [ + ['{D1A5279D-B27D-6CD4-A05E-EFDD53D08E8D}', true], + ['{B59511BD6A5F6DF09ECF562A108D8A2E}', true], + ['69593D62-71EA-6548-85E4-04FC71357423', true], + ['677E2553DD4D63B09DA77414DB1EB8EA', true], + ['{5ba3bba3-729a-6717-88c1-b7c4b7ba80db}', true], + ['{7e9081b59a6d6cc1a8c347f69fb4198d}', true], + ['0c74f13f-fa83-6c48-9b33-68921dd72463', true], + ['b4b2fb69c6246e5eb0698e0c6ec66618', true], + ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D-B27D-6CD4-C05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-6CD4-C05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{283B67B2-430F-6E6F-97E6-19041992-C1B0}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{283B67B2-430F-6E6F-97E6-19041992-C1B0}', + label: 'value' + } + }], + ['{D1A5279D-B27D-6CD4-A05E-EFDD53D08E8D', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-6CD4-A05E-EFDD53D08E8D', + label: 'value' + } + }], + ['{D1A5279D-B27D-6CD4-A05E-EFDD53D08E8D]', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-6CD4-A05E-EFDD53D08E8D]', + label: 'value' + } + }], + ['D1A5279D-B27D-6CD4-A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: 'D1A5279D-B27D-6CD4-A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D:B27D-6CD4-A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D:B27D-6CD4-A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D-B27D:6CD4-A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D:6CD4-A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D-B27D-6CD4:A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-6CD4:A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D-B27D-6CD4-A05E:EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-6CD4-A05E:EFDD53D08E8D}', + label: 'value' + } + }] + ]); + }); + + it('validates uuidv7', () => { + + Helper.validate(Joi.string().guid({ version: ['uuidv7'] }), [ + ['{D1A5279D-B27D-7CD4-A05E-EFDD53D08E8D}', true], + ['{B59511BD6A5F7DF09ECF562A108D8A2E}', true], + ['69593D62-71EA-7548-85E4-04FC71357423', true], + ['677E2553DD4D73B09DA77414DB1EB8EA', true], + ['{5ba3bba3-729a-7717-88c1-b7c4b7ba80db}', true], + ['{7e9081b59a6d7cc1a8c347f69fb4198d}', true], + ['0c74f13f-fa83-7c48-9b33-68921dd72463', true], + ['b4b2fb69c6247e5eb0698e0c6ec66618', true], + ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D-B27D-7CD4-C05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-7CD4-C05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{283B67B2-430F-7E6F-97E6-19041992-C1B0}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{283B67B2-430F-7E6F-97E6-19041992-C1B0}', + label: 'value' + } + }], + ['{D1A5279D-B27D-7CD4-A05E-EFDD53D08E8D', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-7CD4-A05E-EFDD53D08E8D', + label: 'value' + } + }], + ['{D1A5279D-B27D-7CD4-A05E-EFDD53D08E8D]', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-7CD4-A05E-EFDD53D08E8D]', + label: 'value' + } + }], + ['D1A5279D-B27D-7CD4-A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: 'D1A5279D-B27D-7CD4-A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D:B27D-7CD4-A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D:B27D-7CD4-A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D-B27D:7CD4-A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D:7CD4-A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D-B27D-7CD4:A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-7CD4:A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D-B27D-7CD4-A05E:EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-7CD4-A05E:EFDD53D08E8D}', + label: 'value' + } + }] + ]); + }); + + it('validates uuidv8', () => { + + Helper.validate(Joi.string().guid({ version: ['uuidv8'] }), [ + ['{D1A5279D-B27D-8CD4-A05E-EFDD53D08E8D}', true], + ['{B59511BD6A5F8DF09ECF562A108D8A2E}', true], + ['69593D62-71EA-8548-85E4-04FC71357423', true], + ['677E2553DD4D83B09DA77414DB1EB8EA', true], + ['{5ba3bba3-729a-8717-88c1-b7c4b7ba80db}', true], + ['{7e9081b59a6d8cc1a8c347f69fb4198d}', true], + ['0c74f13f-fa83-8c48-9b33-68921dd72463', true], + ['b4b2fb69c6248e5eb0698e0c6ec66618', true], + ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D-B27D-8CD4-C05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-8CD4-C05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{283B67B2-430F-8E6F-97E6-19041992-C1B0}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{283B67B2-430F-8E6F-97E6-19041992-C1B0}', + label: 'value' + } + }], + ['{D1A5279D-B27D-8CD4-A05E-EFDD53D08E8D', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-8CD4-A05E-EFDD53D08E8D', + label: 'value' + } + }], + ['{D1A5279D-B27D-8CD4-A05E-EFDD53D08E8D]', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-8CD4-A05E-EFDD53D08E8D]', + label: 'value' + } + }], + ['D1A5279D-B27D-8CD4-A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: 'D1A5279D-B27D-8CD4-A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D:B27D-8CD4-A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D:B27D-8CD4-A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D-B27D:8CD4-A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D:8CD4-A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D-B27D-8CD4:A05E-EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-8CD4:A05E-EFDD53D08E8D}', + label: 'value' + } + }], + ['{D1A5279D-B27D-8CD4-A05E:EFDD53D08E8D}', false, { + message: '"value" must be a valid GUID', + path: [], + type: 'string.guid', + context: { + value: '{D1A5279D-B27D-8CD4-A05E:EFDD53D08E8D}', + label: 'value' + } + }] + ]); + }); + + it('validates multiple uuid versions (1,3,5,7)', () => { + + Helper.validate(Joi.string().guid({ version: ['uuidv1', 'uuidv3', 'uuidv5', 'uuidv7'] }), [ ['{D1A5279D-B27D-1CD4-805E-EFDD53D08E8D}', true], ['{D1A5279D-B27D-3CD4-905E-EFDD53D08E8D}', true], ['{D1A5279D-B27D-5CD4-A05E-EFDD53D08E8D}', true], + ['{D1A5279D-B27D-7CD4-A05E-EFDD53D08E8D}', true], ['{B59511BD6A5F5DF09ECF562A108D8A2E}', true], ['69593D62-71EA-5548-85E4-04FC71357423', true], ['677E2553DD4D53B09DA77414DB1EB8EA', true],