package.dist.short-unique-id.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of short-unique-id Show documentation
Show all versions of short-unique-id Show documentation
Generate random or sequential UUID of any length
The newest version!
"use strict";
var ShortUniqueId = (() => {
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
// src/index.ts
var src_exports = {};
__export(src_exports, {
DEFAULT_OPTIONS: () => DEFAULT_OPTIONS,
DEFAULT_UUID_LENGTH: () => DEFAULT_UUID_LENGTH,
default: () => ShortUniqueId
});
// package.json
var version = "5.2.0";
// src/index.ts
var DEFAULT_UUID_LENGTH = 6;
var DEFAULT_OPTIONS = {
dictionary: "alphanum",
shuffle: true,
debug: false,
length: DEFAULT_UUID_LENGTH,
counter: 0
};
var _ShortUniqueId = class _ShortUniqueId {
constructor(argOptions = {}) {
__publicField(this, "counter");
__publicField(this, "debug");
__publicField(this, "dict");
__publicField(this, "version");
__publicField(this, "dictIndex", 0);
__publicField(this, "dictRange", []);
__publicField(this, "lowerBound", 0);
__publicField(this, "upperBound", 0);
__publicField(this, "dictLength", 0);
__publicField(this, "uuidLength");
__publicField(this, "_digit_first_ascii", 48);
__publicField(this, "_digit_last_ascii", 58);
__publicField(this, "_alpha_lower_first_ascii", 97);
__publicField(this, "_alpha_lower_last_ascii", 123);
__publicField(this, "_hex_last_ascii", 103);
__publicField(this, "_alpha_upper_first_ascii", 65);
__publicField(this, "_alpha_upper_last_ascii", 91);
__publicField(this, "_number_dict_ranges", {
digits: [this._digit_first_ascii, this._digit_last_ascii]
});
__publicField(this, "_alpha_dict_ranges", {
lowerCase: [this._alpha_lower_first_ascii, this._alpha_lower_last_ascii],
upperCase: [this._alpha_upper_first_ascii, this._alpha_upper_last_ascii]
});
__publicField(this, "_alpha_lower_dict_ranges", {
lowerCase: [this._alpha_lower_first_ascii, this._alpha_lower_last_ascii]
});
__publicField(this, "_alpha_upper_dict_ranges", {
upperCase: [this._alpha_upper_first_ascii, this._alpha_upper_last_ascii]
});
__publicField(this, "_alphanum_dict_ranges", {
digits: [this._digit_first_ascii, this._digit_last_ascii],
lowerCase: [this._alpha_lower_first_ascii, this._alpha_lower_last_ascii],
upperCase: [this._alpha_upper_first_ascii, this._alpha_upper_last_ascii]
});
__publicField(this, "_alphanum_lower_dict_ranges", {
digits: [this._digit_first_ascii, this._digit_last_ascii],
lowerCase: [this._alpha_lower_first_ascii, this._alpha_lower_last_ascii]
});
__publicField(this, "_alphanum_upper_dict_ranges", {
digits: [this._digit_first_ascii, this._digit_last_ascii],
upperCase: [this._alpha_upper_first_ascii, this._alpha_upper_last_ascii]
});
__publicField(this, "_hex_dict_ranges", {
decDigits: [this._digit_first_ascii, this._digit_last_ascii],
alphaDigits: [this._alpha_lower_first_ascii, this._hex_last_ascii]
});
__publicField(this, "_dict_ranges", {
_number_dict_ranges: this._number_dict_ranges,
_alpha_dict_ranges: this._alpha_dict_ranges,
_alpha_lower_dict_ranges: this._alpha_lower_dict_ranges,
_alpha_upper_dict_ranges: this._alpha_upper_dict_ranges,
_alphanum_dict_ranges: this._alphanum_dict_ranges,
_alphanum_lower_dict_ranges: this._alphanum_lower_dict_ranges,
_alphanum_upper_dict_ranges: this._alphanum_upper_dict_ranges,
_hex_dict_ranges: this._hex_dict_ranges
});
/* tslint:disable consistent-return */
__publicField(this, "log", (...args) => {
const finalArgs = [...args];
finalArgs[0] = `[short-unique-id] ${args[0]}`;
if (this.debug === true) {
if (typeof console !== "undefined" && console !== null) {
return console.log(...finalArgs);
}
}
});
/* tslint:enable consistent-return */
__publicField(this, "_normalizeDictionary", (dictionary, shuffle) => {
let finalDict;
if (dictionary && Array.isArray(dictionary) && dictionary.length > 1) {
finalDict = dictionary;
} else {
finalDict = [];
let i;
this.dictIndex = i = 0;
const rangesName = `_${dictionary}_dict_ranges`;
const ranges = this._dict_ranges[rangesName];
Object.keys(ranges).forEach((rangeType) => {
const rangeTypeKey = rangeType;
this.dictRange = ranges[rangeTypeKey];
this.lowerBound = this.dictRange[0];
this.upperBound = this.dictRange[1];
for (this.dictIndex = i = this.lowerBound; this.lowerBound <= this.upperBound ? i < this.upperBound : i > this.upperBound; this.dictIndex = this.lowerBound <= this.upperBound ? i += 1 : i -= 1) {
finalDict.push(String.fromCharCode(this.dictIndex));
}
});
}
if (shuffle) {
const PROBABILITY = 0.5;
finalDict = finalDict.sort(() => Math.random() - PROBABILITY);
}
return finalDict;
});
/** Change the dictionary after initialization. */
__publicField(this, "setDictionary", (dictionary, shuffle) => {
this.dict = this._normalizeDictionary(dictionary, shuffle);
this.dictLength = this.dict.length;
this.setCounter(0);
});
__publicField(this, "seq", () => {
return this.sequentialUUID();
});
/**
* Generates UUID based on internal counter that's incremented after each ID generation.
* @alias `const uid = new ShortUniqueId(); uid.seq();`
*/
__publicField(this, "sequentialUUID", () => {
let counterDiv;
let counterRem;
let id = "";
counterDiv = this.counter;
do {
counterRem = counterDiv % this.dictLength;
counterDiv = Math.trunc(counterDiv / this.dictLength);
id += this.dict[counterRem];
} while (counterDiv !== 0);
this.counter += 1;
return id;
});
__publicField(this, "rnd", (uuidLength = this.uuidLength || DEFAULT_UUID_LENGTH) => {
return this.randomUUID(uuidLength);
});
/**
* Generates UUID by creating each part randomly.
* @alias `const uid = new ShortUniqueId(); uid.rnd(uuidLength: number);`
*/
__publicField(this, "randomUUID", (uuidLength = this.uuidLength || DEFAULT_UUID_LENGTH) => {
let id;
let randomPartIdx;
let j;
if (uuidLength === null || typeof uuidLength === "undefined" || uuidLength < 1) {
throw new Error("Invalid UUID Length Provided");
}
const isPositive = uuidLength >= 0;
id = "";
for (j = 0; j < uuidLength; j += 1) {
randomPartIdx = parseInt(
(Math.random() * this.dictLength).toFixed(0),
10
) % this.dictLength;
id += this.dict[randomPartIdx];
}
return id;
});
__publicField(this, "fmt", (format, date) => {
return this.formattedUUID(format, date);
});
/**
* Generates custom UUID with the provided format string.
* @alias `const uid = new ShortUniqueId(); uid.fmt(format: string);`
*/
__publicField(this, "formattedUUID", (format, date) => {
const fnMap = {
"$r": this.randomUUID,
"$s": this.sequentialUUID,
"$t": this.stamp
};
const result = format.replace(
/\$[rs]\d{0,}|\$t0|\$t[1-9]\d{1,}/g,
(m) => {
const fn = m.slice(0, 2);
const len = parseInt(m.slice(2), 10);
if (fn === "$s") {
return fnMap[fn]().padStart(len, "0");
}
if (fn === "$t" && date) {
return fnMap[fn](len, date);
}
return fnMap[fn](len);
}
);
return result;
});
/**
* Calculates total number of possible UUIDs.
*
* Given that:
*
* - `H` is the total number of possible UUIDs
* - `n` is the number of unique characters in the dictionary
* - `l` is the UUID length
*
* Then `H` is defined as `n` to the power of `l`:
*
*
*
* This function returns `H`.
*/
__publicField(this, "availableUUIDs", (uuidLength = this.uuidLength) => {
return parseFloat(
Math.pow([...new Set(this.dict)].length, uuidLength).toFixed(0)
);
});
/**
* Calculates approximate number of hashes before first collision.
*
* Given that:
*
* - `H` is the total number of possible UUIDs, or in terms of this library,
* the result of running `availableUUIDs()`
* - the expected number of values we have to choose before finding the
* first collision can be expressed as the quantity `Q(H)`
*
* Then `Q(H)` can be approximated as the square root of the product of half
* of pi times `H`:
*
*
*
* This function returns `Q(H)`.
*
* (see [Poisson distribution](https://en.wikipedia.org/wiki/Poisson_distribution))
*/
__publicField(this, "approxMaxBeforeCollision", (rounds = this.availableUUIDs(this.uuidLength)) => {
return parseFloat(
Math.sqrt(Math.PI / 2 * rounds).toFixed(20)
);
});
/**
* Calculates probability of generating duplicate UUIDs (a collision) in a
* given number of UUID generation rounds.
*
* Given that:
*
* - `r` is the maximum number of times that `randomUUID()` will be called,
* or better said the number of _rounds_
* - `H` is the total number of possible UUIDs, or in terms of this library,
* the result of running `availableUUIDs()`
*
* Then the probability of collision `p(r; H)` can be approximated as the result
* of dividing the square root of the product of half of pi times `r` by `H`:
*
*
*
* This function returns `p(r; H)`.
*
* (see [Poisson distribution](https://en.wikipedia.org/wiki/Poisson_distribution))
*
* (Useful if you are wondering _"If I use this lib and expect to perform at most
* `r` rounds of UUID generations, what is the probability that I will hit a duplicate UUID?"_.)
*/
__publicField(this, "collisionProbability", (rounds = this.availableUUIDs(this.uuidLength), uuidLength = this.uuidLength) => {
return parseFloat(
(this.approxMaxBeforeCollision(rounds) / this.availableUUIDs(uuidLength)).toFixed(20)
);
});
/**
* Calculate a "uniqueness" score (from 0 to 1) of UUIDs based on size of
* dictionary and chosen UUID length.
*
* Given that:
*
* - `H` is the total number of possible UUIDs, or in terms of this library,
* the result of running `availableUUIDs()`
* - `Q(H)` is the approximate number of hashes before first collision,
* or in terms of this library, the result of running `approxMaxBeforeCollision()`
*
* Then `uniqueness` can be expressed as the additive inverse of the probability of
* generating a "word" I had previously generated (a duplicate) at any given iteration
* up to the the total number of possible UUIDs expressed as the quotiend of `Q(H)` and `H`:
*
*
*
* (Useful if you need a value to rate the "quality" of the combination of given dictionary
* and UUID length. The closer to 1, higher the uniqueness and thus better the quality.)
*/
__publicField(this, "uniqueness", (rounds = this.availableUUIDs(this.uuidLength)) => {
const score = parseFloat(
(1 - this.approxMaxBeforeCollision(rounds) / rounds).toFixed(20)
);
return score > 1 ? 1 : score < 0 ? 0 : score;
});
/**
* Return the version of this module.
*/
__publicField(this, "getVersion", () => {
return this.version;
});
/**
* Generates a UUID with a timestamp that can be extracted using `uid.parseStamp(stampString);`.
*
* ```js
* const uidWithTimestamp = uid.stamp(32);
* console.log(uidWithTimestamp);
* // GDa608f973aRCHLXQYPTbKDbjDeVsSb3
*
* console.log(uid.parseStamp(uidWithTimestamp));
* // 2021-05-03T06:24:58.000Z
* ```
*/
__publicField(this, "stamp", (finalLength, date) => {
const hexStamp = Math.floor(+(date || /* @__PURE__ */ new Date()) / 1e3).toString(16);
if (typeof finalLength === "number" && finalLength === 0) {
return hexStamp;
}
if (typeof finalLength !== "number" || finalLength < 10) {
throw new Error(
[
"Param finalLength must be a number greater than or equal to 10,",
"or 0 if you want the raw hexadecimal timestamp"
].join("\n")
);
}
const idLength = finalLength - 9;
const rndIdx = Math.round(Math.random() * (idLength > 15 ? 15 : idLength));
const id = this.randomUUID(idLength);
return `${id.substring(0, rndIdx)}${hexStamp}${id.substring(rndIdx)}${rndIdx.toString(16)}`;
});
/**
* Extracts the date embeded in a UUID generated using the `uid.stamp(finalLength);` method.
*
* ```js
* const uidWithTimestamp = uid.stamp(32);
* console.log(uidWithTimestamp);
* // GDa608f973aRCHLXQYPTbKDbjDeVsSb3
*
* console.log(uid.parseStamp(uidWithTimestamp));
* // 2021-05-03T06:24:58.000Z
* ```
*/
__publicField(this, "parseStamp", (suid, format) => {
if (format && !/t0|t[1-9]\d{1,}/.test(format)) {
throw new Error("Cannot extract date from a formated UUID with no timestamp in the format");
}
const stamp = format ? format.replace(
/\$[rs]\d{0,}|\$t0|\$t[1-9]\d{1,}/g,
(m) => {
const fnMap = {
"$r": (len2) => [...Array(len2)].map(() => "r").join(""),
"$s": (len2) => [...Array(len2)].map(() => "s").join(""),
"$t": (len2) => [...Array(len2)].map(() => "t").join("")
};
const fn = m.slice(0, 2);
const len = parseInt(m.slice(2), 10);
return fnMap[fn](len);
}
).replace(
/^(.*?)(t{8,})(.*)$/g,
(_m, p1, p2) => {
return suid.substring(p1.length, p1.length + p2.length);
}
) : suid;
if (stamp.length === 8) {
return new Date(parseInt(stamp, 16) * 1e3);
}
if (stamp.length < 10) {
throw new Error("Stamp length invalid");
}
const rndIdx = parseInt(stamp.substring(stamp.length - 1), 16);
return new Date(parseInt(stamp.substring(rndIdx, rndIdx + 8), 16) * 1e3);
});
/**
* Set the counter to a specific value.
*/
__publicField(this, "setCounter", (counter) => {
this.counter = counter;
});
/**
* Validate given UID contains only characters from the instanced dictionary or optionally provided dictionary.
*/
__publicField(this, "validate", (uid, dictionary) => {
const finalDictionary = dictionary ? this._normalizeDictionary(dictionary) : this.dict;
return uid.split("").every((c) => finalDictionary.includes(c));
});
const options = __spreadValues(__spreadValues({}, DEFAULT_OPTIONS), argOptions);
this.counter = 0;
this.debug = false;
this.dict = [];
this.version = version;
const {
dictionary,
shuffle,
length,
counter
} = options;
this.uuidLength = length;
this.setDictionary(dictionary, shuffle);
this.setCounter(counter);
this.debug = options.debug;
this.log(this.dict);
this.log(
`Generator instantiated with Dictionary Size ${this.dictLength} and counter set to ${this.counter}`
);
this.log = this.log.bind(this);
this.setDictionary = this.setDictionary.bind(this);
this.setCounter = this.setCounter.bind(this);
this.seq = this.seq.bind(this);
this.sequentialUUID = this.sequentialUUID.bind(this);
this.rnd = this.rnd.bind(this);
this.randomUUID = this.randomUUID.bind(this);
this.fmt = this.fmt.bind(this);
this.formattedUUID = this.formattedUUID.bind(this);
this.availableUUIDs = this.availableUUIDs.bind(this);
this.approxMaxBeforeCollision = this.approxMaxBeforeCollision.bind(this);
this.collisionProbability = this.collisionProbability.bind(this);
this.uniqueness = this.uniqueness.bind(this);
this.getVersion = this.getVersion.bind(this);
this.stamp = this.stamp.bind(this);
this.parseStamp = this.parseStamp.bind(this);
return this;
}
};
/** @hidden */
__publicField(_ShortUniqueId, "default", _ShortUniqueId);
var ShortUniqueId = _ShortUniqueId;
return __toCommonJS(src_exports);
})();
//# sourceMappingURL=short-unique-id.js.map
'undefined'!=typeof module&&(module.exports=ShortUniqueId.default),'undefined'!=typeof window&&(ShortUniqueId=ShortUniqueId.default);