1
- import { bufferToUuidHexString , uuidHexStringToBuffer , uuidValidateString } from './uuid_utils' ;
2
1
import { isUint8Array } from './parser/utils' ;
3
2
import type { EJSONOptions } from './extended_json' ;
4
3
import { BSONError } from './error' ;
@@ -288,7 +287,7 @@ export class Binary extends BSONValue {
288
287
}
289
288
} else if ( '$uuid' in doc ) {
290
289
type = 4 ;
291
- data = uuidHexStringToBuffer ( doc . $uuid ) ;
290
+ data = UUID . bytesFromString ( doc . $uuid ) ;
292
291
}
293
292
if ( ! data ) {
294
293
throw new BSONError ( `Unexpected Binary Extended JSON format ${ JSON . stringify ( doc ) } ` ) ;
@@ -311,42 +310,40 @@ export class Binary extends BSONValue {
311
310
export type UUIDExtended = {
312
311
$uuid : string ;
313
312
} ;
313
+
314
314
const UUID_BYTE_LENGTH = 16 ;
315
+ const UUID_WITHOUT_DASHES = / ^ [ 0 - 9 A - F ] { 32 } $ / i;
316
+ const UUID_WITH_DASHES = / ^ [ 0 - 9 A - F ] { 8 } - [ 0 - 9 A - F ] { 4 } - [ 0 - 9 A - F ] { 4 } - [ 0 - 9 A - F ] { 4 } - [ 0 - 9 A - F ] { 12 } $ / i;
315
317
316
318
/**
317
319
* A class representation of the BSON UUID type.
318
320
* @public
319
321
*/
320
322
export class UUID extends Binary {
321
- static cacheHexString : boolean ;
322
-
323
- /** UUID hexString cache @internal */
324
- private __id ?: string ;
325
-
323
+ static cacheHexString = false ;
326
324
/**
327
- * Create an UUID type
325
+ * Create a UUID type
326
+ *
327
+ * When the argument to the constructor is omitted a random v4 UUID will be generated.
328
328
*
329
329
* @param input - Can be a 32 or 36 character hex string (dashes excluded/included) or a 16 byte binary Buffer.
330
330
*/
331
331
constructor ( input ?: string | Uint8Array | UUID ) {
332
332
let bytes : Uint8Array ;
333
- let hexStr ;
334
333
if ( input == null ) {
335
334
bytes = UUID . generate ( ) ;
336
335
} else if ( input instanceof UUID ) {
337
336
bytes = ByteUtils . toLocalBufferType ( new Uint8Array ( input . buffer ) ) ;
338
- hexStr = input . __id ;
339
337
} else if ( ArrayBuffer . isView ( input ) && input . byteLength === UUID_BYTE_LENGTH ) {
340
338
bytes = ByteUtils . toLocalBufferType ( input ) ;
341
339
} else if ( typeof input === 'string' ) {
342
- bytes = uuidHexStringToBuffer ( input ) ;
340
+ bytes = UUID . bytesFromString ( input ) ;
343
341
} else {
344
342
throw new BSONError (
345
343
'Argument passed in UUID constructor must be a UUID, a 16 byte Buffer or a 32/36 character hex string (dashes excluded/included, format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).'
346
344
) ;
347
345
}
348
346
super ( bytes , BSON_BINARY_SUBTYPE_UUID_NEW ) ;
349
- this . __id = hexStr ;
350
347
}
351
348
352
349
/**
@@ -359,28 +356,23 @@ export class UUID extends Binary {
359
356
360
357
set id ( value : Uint8Array ) {
361
358
this . buffer = value ;
362
-
363
- if ( UUID . cacheHexString ) {
364
- this . __id = bufferToUuidHexString ( value ) ;
365
- }
366
359
}
367
360
368
361
/**
369
362
* Returns the UUID id as a 32 or 36 character hex string representation, excluding/including dashes (defaults to 36 character dash separated)
370
363
* @param includeDashes - should the string exclude dash-separators.
371
364
* */
372
365
toHexString ( includeDashes = true ) : string {
373
- if ( UUID . cacheHexString && this . __id ) {
374
- return this . __id ;
375
- }
376
-
377
- const uuidHexString = bufferToUuidHexString ( this . id , includeDashes ) ;
378
-
379
- if ( UUID . cacheHexString ) {
380
- this . __id = uuidHexString ;
366
+ if ( includeDashes ) {
367
+ return [
368
+ ByteUtils . toHex ( this . buffer . subarray ( 0 , 4 ) ) ,
369
+ ByteUtils . toHex ( this . buffer . subarray ( 4 , 6 ) ) ,
370
+ ByteUtils . toHex ( this . buffer . subarray ( 6 , 8 ) ) ,
371
+ ByteUtils . toHex ( this . buffer . subarray ( 8 , 10 ) ) ,
372
+ ByteUtils . toHex ( this . buffer . subarray ( 10 , 16 ) )
373
+ ] . join ( '-' ) ;
381
374
}
382
-
383
- return uuidHexString ;
375
+ return ByteUtils . toHex ( this . buffer ) ;
384
376
}
385
377
386
378
/**
@@ -446,37 +438,32 @@ export class UUID extends Binary {
446
438
* Checks if a value is a valid bson UUID
447
439
* @param input - UUID, string or Buffer to validate.
448
440
*/
449
- static isValid ( input : string | Uint8Array | UUID ) : boolean {
441
+ static isValid ( input : string | Uint8Array | UUID | Binary ) : boolean {
450
442
if ( ! input ) {
451
443
return false ;
452
444
}
453
445
454
- if ( input instanceof UUID ) {
455
- return true ;
456
- }
457
-
458
446
if ( typeof input === 'string' ) {
459
- return uuidValidateString ( input ) ;
447
+ return UUID . isValidUUIDString ( input ) ;
460
448
}
461
449
462
450
if ( isUint8Array ( input ) ) {
463
- // check for length & uuid version (https://tools.ietf.org/html/rfc4122#section-4.1.3)
464
- if ( input . byteLength !== UUID_BYTE_LENGTH ) {
465
- return false ;
466
- }
467
-
468
- return ( input [ 6 ] & 0xf0 ) === 0x40 && ( input [ 8 ] & 0x80 ) === 0x80 ;
451
+ return input . byteLength === UUID_BYTE_LENGTH ;
469
452
}
470
453
471
- return false ;
454
+ return (
455
+ input . _bsontype === 'Binary' &&
456
+ input . sub_type === this . SUBTYPE_UUID &&
457
+ input . buffer . byteLength === 16
458
+ ) ;
472
459
}
473
460
474
461
/**
475
462
* Creates an UUID from a hex string representation of an UUID.
476
463
* @param hexString - 32 or 36 character hex string (dashes excluded/included).
477
464
*/
478
465
static override createFromHexString ( hexString : string ) : UUID {
479
- const buffer = uuidHexStringToBuffer ( hexString ) ;
466
+ const buffer = UUID . bytesFromString ( hexString ) ;
480
467
return new UUID ( buffer ) ;
481
468
}
482
469
@@ -485,6 +472,26 @@ export class UUID extends Binary {
485
472
return new UUID ( ByteUtils . fromBase64 ( base64 ) ) ;
486
473
}
487
474
475
+ /** @internal */
476
+ static bytesFromString ( representation : string ) {
477
+ if ( ! UUID . isValidUUIDString ( representation ) ) {
478
+ throw new BSONError (
479
+ 'UUID string representation must be 32 hex digits or canonical hyphenated representation'
480
+ ) ;
481
+ }
482
+ return ByteUtils . fromHex ( representation . replace ( / - / g, '' ) ) ;
483
+ }
484
+
485
+ /**
486
+ * @internal
487
+ *
488
+ * Validates a string to be a hex digit sequence with or without dashes.
489
+ * The canonical hyphenated representation of a uuid is hex in 8-4-4-4-12 groups.
490
+ */
491
+ static isValidUUIDString ( representation : string ) {
492
+ return UUID_WITHOUT_DASHES . test ( representation ) || UUID_WITH_DASHES . test ( representation ) ;
493
+ }
494
+
488
495
/**
489
496
* Converts to a string representation of this Id.
490
497
*
0 commit comments