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.
		
		
		
		
			
				
					45 lines
				
				1.3 KiB
			
		
		
			
		
	
	
					45 lines
				
				1.3 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								let crypto = require('crypto')
							 | 
						||
| 
								 | 
							
								let { urlAlphabet } = require('./url-alphabet/index.cjs')
							 | 
						||
| 
								 | 
							
								const POOL_SIZE_MULTIPLIER = 128
							 | 
						||
| 
								 | 
							
								let pool, poolOffset
							 | 
						||
| 
								 | 
							
								let fillPool = bytes => {
							 | 
						||
| 
								 | 
							
								  if (!pool || pool.length < bytes) {
							 | 
						||
| 
								 | 
							
								    pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER)
							 | 
						||
| 
								 | 
							
								    crypto.randomFillSync(pool)
							 | 
						||
| 
								 | 
							
								    poolOffset = 0
							 | 
						||
| 
								 | 
							
								  } else if (poolOffset + bytes > pool.length) {
							 | 
						||
| 
								 | 
							
								    crypto.randomFillSync(pool)
							 | 
						||
| 
								 | 
							
								    poolOffset = 0
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  poolOffset += bytes
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								let random = bytes => {
							 | 
						||
| 
								 | 
							
								  fillPool(bytes)
							 | 
						||
| 
								 | 
							
								  return pool.subarray(poolOffset - bytes, poolOffset)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								let customRandom = (alphabet, size, getRandom) => {
							 | 
						||
| 
								 | 
							
								  let mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1
							 | 
						||
| 
								 | 
							
								  let step = Math.ceil((1.6 * mask * size) / alphabet.length)
							 | 
						||
| 
								 | 
							
								  return () => {
							 | 
						||
| 
								 | 
							
								    let id = ''
							 | 
						||
| 
								 | 
							
								    while (true) {
							 | 
						||
| 
								 | 
							
								      let bytes = getRandom(step)
							 | 
						||
| 
								 | 
							
								      let i = step
							 | 
						||
| 
								 | 
							
								      while (i--) {
							 | 
						||
| 
								 | 
							
								        id += alphabet[bytes[i] & mask] || ''
							 | 
						||
| 
								 | 
							
								        if (id.length === size) return id
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								let customAlphabet = (alphabet, size) => customRandom(alphabet, size, random)
							 | 
						||
| 
								 | 
							
								let nanoid = (size = 21) => {
							 | 
						||
| 
								 | 
							
								  fillPool(size)
							 | 
						||
| 
								 | 
							
								  let id = ''
							 | 
						||
| 
								 | 
							
								  for (let i = poolOffset - size; i < poolOffset; i++) {
							 | 
						||
| 
								 | 
							
								    id += urlAlphabet[pool[i] & 63]
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return id
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								module.exports = { nanoid, customAlphabet, customRandom, urlAlphabet, random }
							 |