1- import { bufferToUuidHexString , uuidHexStringToBuffer , uuidValidateString } from './uuid_utils' ;
21import { isUint8Array } from './parser/utils' ;
32import type { EJSONOptions } from './extended_json' ;
43import { BSONError } from './error' ;
@@ -288,7 +287,7 @@ export class Binary extends BSONValue {
288287 }
289288 } else if ( '$uuid' in doc ) {
290289 type = 4 ;
291- data = uuidHexStringToBuffer ( doc . $uuid ) ;
290+ data = UUID . bytesFromString ( doc . $uuid ) ;
292291 }
293292 if ( ! data ) {
294293 throw new BSONError ( `Unexpected Binary Extended JSON format ${ JSON . stringify ( doc ) } ` ) ;
@@ -311,42 +310,40 @@ export class Binary extends BSONValue {
311310export type UUIDExtended = {
312311 $uuid : string ;
313312} ;
313+
314314const 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;
315317
316318/**
317319 * A class representation of the BSON UUID type.
318320 * @public
319321 */
320322export class UUID extends Binary {
321- static cacheHexString : boolean ;
322-
323- /** UUID hexString cache @internal */
324- private __id ?: string ;
325-
323+ static cacheHexString = false ;
326324 /**
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.
328328 *
329329 * @param input - Can be a 32 or 36 character hex string (dashes excluded/included) or a 16 byte binary Buffer.
330330 */
331331 constructor ( input ?: string | Uint8Array | UUID ) {
332332 let bytes : Uint8Array ;
333- let hexStr ;
334333 if ( input == null ) {
335334 bytes = UUID . generate ( ) ;
336335 } else if ( input instanceof UUID ) {
337336 bytes = ByteUtils . toLocalBufferType ( new Uint8Array ( input . buffer ) ) ;
338- hexStr = input . __id ;
339337 } else if ( ArrayBuffer . isView ( input ) && input . byteLength === UUID_BYTE_LENGTH ) {
340338 bytes = ByteUtils . toLocalBufferType ( input ) ;
341339 } else if ( typeof input === 'string' ) {
342- bytes = uuidHexStringToBuffer ( input ) ;
340+ bytes = UUID . bytesFromString ( input ) ;
343341 } else {
344342 throw new BSONError (
345343 '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).'
346344 ) ;
347345 }
348346 super ( bytes , BSON_BINARY_SUBTYPE_UUID_NEW ) ;
349- this . __id = hexStr ;
350347 }
351348
352349 /**
@@ -359,28 +356,23 @@ export class UUID extends Binary {
359356
360357 set id ( value : Uint8Array ) {
361358 this . buffer = value ;
362-
363- if ( UUID . cacheHexString ) {
364- this . __id = bufferToUuidHexString ( value ) ;
365- }
366359 }
367360
368361 /**
369362 * Returns the UUID id as a 32 or 36 character hex string representation, excluding/including dashes (defaults to 36 character dash separated)
370363 * @param includeDashes - should the string exclude dash-separators.
371364 * */
372365 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 ( '-' ) ;
381374 }
382-
383- return uuidHexString ;
375+ return ByteUtils . toHex ( this . buffer ) ;
384376 }
385377
386378 /**
@@ -446,37 +438,32 @@ export class UUID extends Binary {
446438 * Checks if a value is a valid bson UUID
447439 * @param input - UUID, string or Buffer to validate.
448440 */
449- static isValid ( input : string | Uint8Array | UUID ) : boolean {
441+ static isValid ( input : string | Uint8Array | UUID | Binary ) : boolean {
450442 if ( ! input ) {
451443 return false ;
452444 }
453445
454- if ( input instanceof UUID ) {
455- return true ;
456- }
457-
458446 if ( typeof input === 'string' ) {
459- return uuidValidateString ( input ) ;
447+ return UUID . isValidUUIDString ( input ) ;
460448 }
461449
462450 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 ;
469452 }
470453
471- return false ;
454+ return (
455+ input . _bsontype === 'Binary' &&
456+ input . sub_type === this . SUBTYPE_UUID &&
457+ input . buffer . byteLength === 16
458+ ) ;
472459 }
473460
474461 /**
475462 * Creates an UUID from a hex string representation of an UUID.
476463 * @param hexString - 32 or 36 character hex string (dashes excluded/included).
477464 */
478465 static override createFromHexString ( hexString : string ) : UUID {
479- const buffer = uuidHexStringToBuffer ( hexString ) ;
466+ const buffer = UUID . bytesFromString ( hexString ) ;
480467 return new UUID ( buffer ) ;
481468 }
482469
@@ -485,6 +472,26 @@ export class UUID extends Binary {
485472 return new UUID ( ByteUtils . fromBase64 ( base64 ) ) ;
486473 }
487474
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+
488495 /**
489496 * Converts to a string representation of this Id.
490497 *
0 commit comments