UUID as a buffer.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

104 lines
2.8 KiB

  1. import { v4 } from 'uuid'
  2. interface UuidProto {
  3. length: number,
  4. toString(this: UuidProto): string,
  5. toJSON(this: UuidProto): string,
  6. }
  7. export class Uuid extends Buffer {
  8. static STRING_PATTERN = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
  9. private static _toUuidString(this: Uuid, encoding?: string) {
  10. const thisBuffer = this as unknown as Buffer;
  11. if (typeof encoding === 'string') {
  12. const buffer = Buffer.from(thisBuffer);
  13. return buffer.toString(encoding as BufferEncoding);
  14. }
  15. let uuidStr = ''
  16. for (let i = 0; i < this.length; i += 1) {
  17. if (
  18. i === 4
  19. || i === 6
  20. || i === 8
  21. || i === 10
  22. ) {
  23. uuidStr += '-'
  24. }
  25. uuidStr += thisBuffer[i].toString(16).padStart(2, '0')
  26. }
  27. return uuidStr;
  28. }
  29. private static _toJSON(this: Uuid) {
  30. const thisBuffer = this as unknown as Buffer;
  31. const toUuidString = Uuid._toUuidString.bind(thisBuffer);
  32. return toUuidString();
  33. }
  34. private static _attachMethods(uuid: UuidProto) {
  35. uuid.toString = Uuid._toUuidString.bind(uuid as unknown as Buffer);
  36. uuid.toJSON = Uuid._toJSON.bind(uuid as unknown as Buffer);
  37. uuid.constructor = Uuid;
  38. }
  39. static v4(): Uuid {
  40. const uuidBuffer = Buffer.alloc(16)
  41. const uuid = v4(null, uuidBuffer) as unknown as UuidProto;
  42. Uuid._attachMethods(uuid);
  43. return uuid as unknown as Uuid;
  44. }
  45. static from(arg: unknown): Uuid {
  46. if (typeof arg === 'string') {
  47. if (Uuid.STRING_PATTERN.test(arg)) {
  48. const uuidStrStripped = arg.replaceAll('-', '')
  49. const uuidBytes = [] as number[];
  50. for (let i = 0; i < 16; i += 1) {
  51. uuidBytes.push(
  52. parseInt(`${uuidStrStripped[i * 2]}${uuidStrStripped[i * 2 + 1]}`, 16)
  53. )
  54. }
  55. const uuid = Buffer.from(uuidBytes) as unknown as UuidProto
  56. Uuid._attachMethods(uuid);
  57. return uuid as unknown as Buffer;
  58. }
  59. throw new TypeError(`Malformed UUID string: ${arg}`);
  60. }
  61. if (
  62. arg instanceof ArrayBuffer
  63. || arg instanceof Uint8Array
  64. || arg instanceof Buffer
  65. ) {
  66. if (arg.byteLength !== 16) {
  67. throw new TypeError('Value could not be represented as UUID.');
  68. }
  69. const uuid = Buffer.from(arg) as unknown as UuidProto;
  70. Uuid._attachMethods(uuid);
  71. return uuid as unknown as Buffer;
  72. }
  73. if (Array.isArray(arg)) {
  74. if (arg.length !== 16) {
  75. throw new TypeError('Value could not be represented as UUID.');
  76. }
  77. const uuid = Buffer.from(arg) as unknown as UuidProto
  78. Uuid._attachMethods(uuid);
  79. return uuid as unknown as Buffer;
  80. }
  81. throw new TypeError('Invalid argument');
  82. }
  83. constructor() {
  84. super(String.fromCharCode(...new Array(16).fill(0)));
  85. const thisBuffer = this as unknown as UuidProto;
  86. Uuid._attachMethods(thisBuffer);
  87. }
  88. }