export class Guid { private constructor(guid: string) { if (!guid) { throw new TypeError('Invalid argument; `value` has no value.'); } this.value = Guid.EMPTY; if (guid && Guid.isGuid(guid)) { this.value = guid; } } public static validator = new RegExp('^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$', 'i'); public static EMPTY = '00000000-0000-0000-0000-000000000000'; private value: string; public static isGuid(guid: any) { const value: string = guid.toString(); return guid && (guid instanceof Guid || Guid.validator.test(value)); } public static create(): Guid { return new Guid([Guid.gen(2), Guid.gen(1), Guid.gen(1), Guid.gen(1), Guid.gen(3)].join('-')); } public static createEmpty(): Guid { return new Guid('emptyguid'); } public static parse(guid: string): Guid { return new Guid(guid); } public static raw(): string { return [Guid.gen(2), Guid.gen(1), Guid.gen(1), Guid.gen(1), Guid.gen(3)].join('-'); } private static gen(count: number) { let out = ''; for (let i = 0; i < count; i++) { // tslint:disable-next-line:no-bitwise out += (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); } return out; } public equals(other: Guid): boolean { // Comparing string `value` against provided `guid` will auto-call // toString on `guid` for comparison return Guid.isGuid(other) && this.value === other.toString(); } public isEmpty(): boolean { return this.value === Guid.EMPTY; } public toString(): string { return this.value; } public toJSON(): any { return this.value; } }