nhb-toolbox
Version:
A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.
144 lines (143 loc) • 5.22 kB
JavaScript
import { isUUID } from '../guards/specials.js';
import { md5, sha1 } from './core.js';
import { _bytesToRandomHex, _checkUUIDVersion, _clockSeq14, _formatUUID, _isOptionV3V5, _randomNode48, _uuidTimestamp, } from './helpers.js';
import { randomHex } from './utils.js';
export function uuid(options) {
const { version = 'v4', uppercase = false } = options || {};
switch (version) {
case 'v1': {
const timestamp = _uuidTimestamp().toString(16).padStart(15, '0');
const vTimeHigh = (parseInt(timestamp.slice(0, -12).padStart(3, '0'), 16) | 0x1000)
.toString(16)
.padStart(4, '0');
const clockSeq = _clockSeq14();
const clockSeqHi = ((parseInt(clockSeq.slice(0, 2), 16) & 0x3f) | 0x80)
.toString(16)
.padStart(2, '0');
const raw = timestamp.slice(-8) +
timestamp.slice(-12, -8) +
vTimeHigh +
clockSeqHi +
clockSeq.slice(2) +
_randomNode48();
return _formatUUID(raw, 1, uppercase);
}
case 'v3': {
if (_isOptionV3V5(options)) {
const hash = md5(options.namespace + options.name);
return _formatUUID(hash, 3, uppercase);
}
throw new Error('v3 requires valid namespace (uuid) and name!');
}
case 'v4': {
const hex = _bytesToRandomHex(new Uint8Array(16));
return _formatUUID(hex, 4, uppercase);
}
case 'v5': {
if (_isOptionV3V5(options)) {
const hash = sha1(options.namespace + options.name).slice(0, 32);
return _formatUUID(hash, 5, uppercase);
}
throw new Error('v5 requires valid namespace (uuid) and name!');
}
case 'v6': {
const timestamp = _uuidTimestamp().toString(16).padStart(15, '0');
const vTimeLow = (parseInt(timestamp.slice(12).padStart(3, '0'), 16) | 0x6000)
.toString(16)
.padStart(4, '0');
const clockSeq = _clockSeq14();
const clockSeqHi = ((parseInt(clockSeq.slice(0, 2), 16) & 0x3f) | 0x80)
.toString(16)
.padStart(2, '0');
const raw = timestamp.slice(0, 8) +
timestamp.slice(8, 12) +
vTimeLow +
clockSeqHi +
clockSeq.slice(2) +
_randomNode48();
return _formatUUID(raw, 6, uppercase);
}
case 'v7': {
const tsHex = Date.now().toString(16).padStart(12, '0');
return _formatUUID(tsHex + randomHex(20), 7, uppercase);
}
case 'v8': {
const ts = BigInt(Date.now());
const bytes = new Uint8Array(16);
let temp = ts;
for (let i = 5; i >= 0; i--) {
bytes[i] = Number(temp & 0xffn);
temp >>= 8n;
}
const hex = _bytesToRandomHex(bytes);
return _formatUUID(hex, 8, uppercase);
}
default:
throw new RangeError('Unsupported UUID version!');
}
}
export function decodeUUID(uuid) {
if (!isUUID(uuid))
return null;
const plain = uuid.replace(/-/g, '');
const parts = uuid.toLowerCase().split('-');
const version = parseInt(parts[2][0], 16);
const variantNibble = parseInt(parts[3][0], 16);
let variant = 'RFC4122';
if ((variantNibble & 0b1000) === 0)
variant = 'NCS';
else if ((variantNibble & 0b1100) === 0b1000)
variant = 'RFC4122';
else if ((variantNibble & 0b1110) === 0b1100)
variant = 'Microsoft';
else
variant = 'Future';
const decoded = {
version,
variant,
raw: uuid,
plain,
singleInt: BigInt('0x' + plain),
};
const UUID_EPOCH_DIFF = 122192928000000000n;
if (version === 1 || version === 6) {
let tsHex = parts[2].slice(1) + parts[1] + parts[0];
if (version === 6)
tsHex = parts[0] + parts[1] + parts[2].slice(1);
const unixMs = Number((BigInt('0x' + tsHex) - UUID_EPOCH_DIFF) / 10000n);
decoded.timestamp = unixMs;
decoded.node = parts[4];
return decoded;
}
if (version === 7 || version === 8) {
const tsHex = parts.join('').slice(0, 12);
decoded.variant = version === 7 ? 'RFC4122' : 'Future';
decoded.timestamp = parseInt(tsHex, 16);
return decoded;
}
return decoded;
}
export function isUUIDv1(value) {
return _checkUUIDVersion(value, '1');
}
export function isUUIDv2(value) {
return _checkUUIDVersion(value, '2');
}
export function isUUIDv3(value) {
return _checkUUIDVersion(value, '3');
}
export function isUUIDv4(value) {
return _checkUUIDVersion(value, '4');
}
export function isUUIDv5(value) {
return _checkUUIDVersion(value, '5');
}
export function isUUIDv6(value) {
return _checkUUIDVersion(value, '6');
}
export function isUUIDv7(value) {
return _checkUUIDVersion(value, '7');
}
export function isUUIDv8(value) {
return _checkUUIDVersion(value, '8');
}