diff --git a/.changeset/curly-snakes-whisper.md b/.changeset/curly-snakes-whisper.md new file mode 100644 index 00000000..9ced3bae --- /dev/null +++ b/.changeset/curly-snakes-whisper.md @@ -0,0 +1,5 @@ +--- +"@tsplus/runtime": patch +--- + +Add UUID Brand diff --git a/packages/runtime/_src/Brand.ts b/packages/runtime/_src/Brand.ts index 3df963aa..14a941d5 100644 --- a/packages/runtime/_src/Brand.ts +++ b/packages/runtime/_src/Brand.ts @@ -123,8 +123,7 @@ export type Regex = Brand.Validated export function deriveRegexValidation( ...[regexStr]: V extends `Regex(${infer R extends string})` ? [R] : never ): Brand.Validation { - const r = new RegExp(regexStr) - return validation((b) => r.test(b)) + return validation((b) => new RegExp(regexStr).test(b)) } export type Min = Brand.Validated @@ -207,3 +206,9 @@ export type Int = Brand.ValidatedWith /** @tsplus implicit */ export const Finite = Brand.validation((n: number) => Number.isFinite(n)) export type Finite = Brand.ValidatedWith + +/** @tsplus implicit */ +export const UUID = Brand.validation((s) => + /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi.test(s) +) +export type UUID = Brand.ValidatedWith diff --git a/packages/runtime/_src/global.ts b/packages/runtime/_src/global.ts index 1ef5d82c..f98d660d 100644 --- a/packages/runtime/_src/global.ts +++ b/packages/runtime/_src/global.ts @@ -3,7 +3,7 @@ import "@tsplus/stdlib/global" /** * @tsplus global */ -import { Brand, Finite, Int, Max, Min, Positive, Range, Regex } from "@tsplus/runtime/Brand" +import { Brand, Finite, Int, Max, Min, Positive, Range, Regex, UUID } from "@tsplus/runtime/Brand" /** * @tsplus global */ diff --git a/packages/runtime/_test/Guard.test.ts b/packages/runtime/_test/Guard.test.ts index 1a25bfdc..fa433b9b 100644 --- a/packages/runtime/_test/Guard.test.ts +++ b/packages/runtime/_test/Guard.test.ts @@ -1,3 +1,5 @@ +import crypto from "node:crypto" + describe("Guard", () => { it("literal", () => { const guardStr: Guard<"Tag"> = Derive() @@ -241,4 +243,12 @@ describe("Guard", () => { console.log(x) }) }) + it("uuid", () => { + const guard = Derive>() + assert.isFalse(guard.is("NotValud-UUID")) + for (let i = 0; i < 100; i++) { + const uuid = crypto.randomUUID() + assert.isTrue(guard.is(uuid)) + } + }) })