16
16
*/
17
17
18
18
import { debugAssert } from './assert' ;
19
+ import { PlatformSupport } from '../platform/platform' ;
19
20
20
21
export type EventHandler < E > = ( value : E ) => void ;
21
22
export interface Indexable {
@@ -27,11 +28,27 @@ export class AutoId {
27
28
// Alphanumeric characters
28
29
const chars =
29
30
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' ;
31
+ // The largest byte value that is a multiple of `char.length`.
32
+ const maxMultiple = Math . floor ( 256 / chars . length ) * chars . length ;
33
+ debugAssert (
34
+ 0 < maxMultiple && maxMultiple < 256 ,
35
+ `Expect maxMultiple to be (0, 256), but got ${ maxMultiple } `
36
+ ) ;
37
+
30
38
let autoId = '' ;
31
- for ( let i = 0 ; i < 20 ; i ++ ) {
32
- autoId += chars . charAt ( Math . floor ( Math . random ( ) * chars . length ) ) ;
39
+ const targetLength = 20 ;
40
+ while ( autoId . length < targetLength ) {
41
+ const bytes = PlatformSupport . getPlatform ( ) . randomBytes ( 40 ) ;
42
+ for ( let i = 0 ; i < bytes . length ; ++ i ) {
43
+ // Only accept values that are [0, maxMultiple), this ensures they can
44
+ // be evenly mapped to indices of `chars` via a modulo operation.
45
+ if ( autoId . length < targetLength && bytes [ i ] < maxMultiple ) {
46
+ autoId += chars . charAt ( bytes [ i ] % chars . length ) ;
47
+ }
48
+ }
33
49
}
34
- debugAssert ( autoId . length === 20 , 'Invalid auto ID: ' + autoId ) ;
50
+ debugAssert ( autoId . length === targetLength , 'Invalid auto ID: ' + autoId ) ;
51
+
35
52
return autoId ;
36
53
}
37
54
}
0 commit comments