Last active
August 12, 2021 08:29
-
-
Save click2install/f69ec65d70c75c72cea4daaf3f9cdc48 to your computer and use it in GitHub Desktop.
[Guid] - Typescript Guid with a similar API to a C# Guid struct
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { expect } from "chai"; | |
import { describe, it } from "mocha"; | |
import * as faker from "faker"; | |
import { Guid, GuidFormat } from "../Guid"; | |
describe(nameof(Guid), () => | |
{ | |
const empty = "00000000-0000-0000-0000-000000000000"; | |
describe(".newGuid()", () => | |
{ | |
it("should create a Guid", () => | |
{ | |
const actual = Guid.newGuid(); | |
expect(actual).to.be.an.instanceof(Guid); | |
}); | |
it("should create a v4 Guid", () => | |
{ | |
const guid = Guid.newGuid(); | |
const actual = guid.toString().slice(14, 15); | |
expect(actual).to.equal("4"); | |
}); | |
it(`should not equal ${empty}`, () => | |
{ | |
const actual = Guid.newGuid(); | |
expect(actual).to.not.equal(Guid.empty()); | |
expect(actual.toString()).to.not.equal(empty); | |
}); | |
}); | |
describe(".empty()", () => | |
{ | |
it("should create a Guid", () => | |
{ | |
const actual = Guid.newGuid(); | |
expect(actual).to.be.an.instanceof(Guid); | |
}); | |
it(`should equal ${empty}`, () => | |
{ | |
const actual = Guid.empty(); | |
expect(actual.toString()).to.equal(empty); | |
}); | |
}); | |
describe(".parse(value)", () => | |
{ | |
it(`should parse a valid guid string`, () => | |
{ | |
const guid = faker.random.uuid(); | |
const actual = Guid.parse(guid); | |
expect(actual).to.be.an.instanceof(Guid); | |
expect(actual.toString()).to.equal(guid); | |
}); | |
it(`should parse a ${nameof(Guid)} without dashes`, () => | |
{ | |
const expected = faker.random.uuid(); | |
const actual = Guid.parse(expected.replace(/-/g, "")); | |
expect(actual).to.be.an.instanceof(Guid); | |
expect(actual.toString()).to.equal(expected); | |
}); | |
it(`should throw when parsing an invalid ${nameof(Guid)}`, () => | |
{ | |
const actual = "zzzzzzzz-zzzz-4zzz-zzzz-zzzzzzzzzzzz"; | |
expect(() => Guid.parse(actual)).to.throw(SyntaxError); | |
}); | |
}); | |
describe(".isGuid(value)", () => | |
{ | |
it(`should return true for an existing ${nameof(Guid)}`, () => | |
{ | |
const actual = Guid.isGuid(Guid.newGuid()); | |
expect(actual).to.equal(true); | |
}); | |
it(`should return true for a valid hex string`, () => | |
{ | |
const actual = Guid.isGuid(faker.random.uuid()); | |
expect(actual).to.equal(true); | |
}); | |
it(`should return true for a valid hex string without dashes`, () => | |
{ | |
const actual = Guid.isGuid(faker.random.uuid().replace(/-/g, "")); | |
expect(actual).to.equal(true); | |
}); | |
it(`should return false for an invalid hex string`, () => | |
{ | |
const actual = Guid.isGuid("zzzzzzzz-zzzz-4zzz-zzzz-zzzzzzzzzzzz"); | |
expect(actual).to.equal(false); | |
}); | |
it(`should return false for an invalid string`, () => | |
{ | |
const actual = Guid.isGuid(faker.random.word()); | |
expect(actual).to.equal(false); | |
}); | |
}); | |
describe(".equals(value)", () => | |
{ | |
it(`should return true for the same ${nameof(Guid)} instance`, () => | |
{ | |
const guid = Guid.newGuid(); | |
const actual = guid.equals(guid); | |
expect(actual).to.equal(true); | |
}); | |
it(`should return true for the different ${nameof(Guid)} instance with same value`, () => | |
{ | |
const left = Guid.newGuid(); | |
const right = Guid.parse(left.toString()); | |
const actual = left.equals(right); | |
expect(actual).to.equal(true); | |
}); | |
it(`should return false when the ${nameof(Guid)} value is not the same`, () => | |
{ | |
const left = Guid.newGuid(); | |
const right = Guid.newGuid(); | |
const actual = left.equals(right); | |
expect(actual).to.equal(false); | |
}); | |
}); | |
describe(".toString(format)", () => | |
{ | |
it(`should return a dashed ${nameof(Guid)} when no arguments are given`, () => | |
{ | |
const uuid = faker.random.uuid(); | |
const guid = Guid.parse(uuid); | |
const actual = guid.toString(); | |
expect(actual).to.equal(uuid); | |
}); | |
it(`should return a dashed ${nameof(Guid)} when the ${nameof.full(GuidFormat.Hyphens)} format is supplied`, () => | |
{ | |
const uuid = faker.random.uuid(); | |
const guid = Guid.parse(uuid); | |
const actual = guid.toString(GuidFormat.Hyphens); | |
expect(actual).to.equal(uuid); | |
}); | |
it(`should return a non-dashed ${nameof(Guid)} when the ${nameof.full(GuidFormat.Digits)} format is supplied`, () => | |
{ | |
const uuid = faker.random.uuid(); | |
const guid = Guid.parse(uuid); | |
const actual = guid.toString(GuidFormat.Digits); | |
expect(actual).to.equal(uuid.replace(/-/g, "")); | |
}); | |
it(`should return a braced ${nameof(Guid)} when the ${nameof.full(GuidFormat.Braces)} format is supplied`, () => | |
{ | |
const uuid = faker.random.uuid(); | |
const guid = Guid.parse(uuid); | |
const actual = guid.toString(GuidFormat.Braces); | |
expect(actual).to.equal(`{${uuid}}`); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// NOTE: requires https://www.npmjs.com/package/ts-nameof | |
import { v4 as uuid, NIL, validate } from "uuid"; | |
export class Guid | |
{ | |
/** | |
* Returns an new v4 Guid as xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx. | |
* | |
* @static | |
* @public | |
* @returns Guid | |
*/ | |
static newGuid(): Guid | |
{ | |
return new Guid(uuid()); | |
} | |
/** | |
* Returns an empty Guid as 00000000-0000-0000-0000-000000000000. | |
* | |
* @static | |
* @public | |
* @returns Guid | |
*/ | |
static empty(): Guid | |
{ | |
return new Guid(NIL); | |
} | |
/** | |
* Parses the given value to a Guid if possible, otherwise throws a SyntaxError. | |
* | |
* @static | |
* @public | |
* @param {string} value The value to parse to a Guid. | |
* @returns Guid | |
*/ | |
static parse(value: string): Guid | |
{ | |
if (validate(value)) | |
{ | |
return new Guid(value); | |
} | |
if (/^[a-f0-9]{32}$/gi.test(value)) | |
{ | |
const regex = /^([a-f0-9]{8})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{12})$/gi; | |
const guid = value.replace(regex, "$1-$2-$3-$4-$5"); | |
if (validate(guid)) | |
{ | |
return new Guid(guid); | |
} | |
} | |
throw new SyntaxError(`Unknown format to create ${nameof(Guid)}.`); | |
} | |
/** | |
* Returns a boolean indicating if the given value is a valid Guid. | |
* | |
* @static | |
* @public | |
* @param {Guid|string} value The value to check for being a valid Guid. | |
* @returns boolean | |
*/ | |
static isGuid(value: Guid | string): boolean | |
{ | |
try | |
{ | |
Guid.parse(value.toString()); | |
return true; | |
} | |
catch | |
{ | |
return false; | |
} | |
} | |
#value: string; | |
// private ctor so all Guid are created with the factory functions newGuid or empty. | |
private constructor(value: string | Guid) | |
{ | |
this.#value = value.toString(); | |
} | |
/** | |
* Returns a boolean indicating whether or not the Guid values are equivalent. | |
* Equivalency is based on the Guid value, not reference equality. | |
* | |
* @public | |
* @param {Guid} value | |
* @memberof Guid | |
* @returns boolean | |
*/ | |
equals(value: Guid): boolean | |
{ | |
return value.#value === this.#value; | |
} | |
/** | |
* Returns a string representation of the Guid. | |
* | |
* @public | |
* @param {GuidFormat} [format="D"] | |
* @memberof Guid | |
* @returns string | |
*/ | |
toString(format: GuidFormat = GuidFormat.Hyphens): string | |
{ | |
const formatter = | |
{ | |
[GuidFormat.Hyphens]: () => this.#value.toLowerCase(), | |
[GuidFormat.Digits]: () => this.#value.replace(/-/gi, "").toLowerCase(), | |
[GuidFormat.Braces]: () => `{${this.#value.toLowerCase()}}` | |
}[format]; | |
return formatter(); | |
} | |
} | |
/** | |
* Enum for formatting a Guid string. | |
* | |
* @public | |
* @readonly | |
* @enum {string} | |
*/ | |
export enum GuidFormat | |
{ | |
/** | |
* Lowercase standard v4 Guid as 32 digits separated by hyphens: xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx | |
*/ | |
Hyphens = "D", | |
/** | |
* Lowercase standard v4 Guid as 32 digits: xxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxx | |
*/ | |
Digits = "N", | |
/** | |
* Lowercase standard v4 Guid as 32 digits separated by hyphens, enclosed in braces: {xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx} | |
*/ | |
Braces = "B" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment