hashids
Version:
Generate YouTube-like ids from numbers. Use Hashids when you do not want to expose your database ids to the user.
108 lines • 4.92 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeAtLeastSomeCharRegExp = exports.makeAnyOfCharsRegExp = exports.splitAtIntervalAndMap = exports.safeParseInt10 = exports.fromAlphabet = exports.toAlphabet = exports.shuffle = exports.isPositiveAndFinite = exports.isIntegerNumber = exports.onlyChars = exports.withoutChars = exports.keepUnique = void 0;
const keepUnique = (content) => [
...new Set(content),
];
exports.keepUnique = keepUnique;
const withoutChars = (chars, charsToExclude) => chars.filter((char) => !charsToExclude.includes(char));
exports.withoutChars = withoutChars;
const onlyChars = (chars, keepChars) => chars.filter((char) => keepChars.includes(char));
exports.onlyChars = onlyChars;
const isIntegerNumber = (n) => typeof n === 'bigint' ||
(!Number.isNaN(Number(n)) && Math.floor(Number(n)) === n);
exports.isIntegerNumber = isIntegerNumber;
const isPositiveAndFinite = (n) => typeof n === 'bigint' || (n >= 0 && Number.isSafeInteger(n));
exports.isPositiveAndFinite = isPositiveAndFinite;
function shuffle(alphabetChars, saltChars) {
if (saltChars.length === 0) {
return alphabetChars;
}
let integer;
const transformed = [...alphabetChars];
for (let i = transformed.length - 1, v = 0, p = 0; i > 0; i--, v++) {
v %= saltChars.length;
// eslint-disable-next-line no-multi-assign
p += integer = saltChars[v].codePointAt(0);
const j = (integer + v + p) % i;
// swap characters at positions i and j
const a = transformed[i];
const b = transformed[j];
transformed[j] = a;
transformed[i] = b;
}
return transformed;
}
exports.shuffle = shuffle;
const toAlphabet = (input, alphabetChars) => {
const id = [];
let value = input;
if (typeof value === 'bigint') {
const alphabetLength = BigInt(alphabetChars.length);
do {
id.unshift(alphabetChars[Number(value % alphabetLength)]);
value /= alphabetLength;
} while (value > BigInt(0));
}
else {
do {
id.unshift(alphabetChars[value % alphabetChars.length]);
value = Math.floor(value / alphabetChars.length);
} while (value > 0);
}
return id;
};
exports.toAlphabet = toAlphabet;
const fromAlphabet = (inputChars, alphabetChars) => inputChars.reduce((carry, item) => {
const index = alphabetChars.indexOf(item);
if (index === -1) {
throw new Error(`The provided ID (${inputChars.join('')}) is invalid, as it contains characters that do not exist in the alphabet (${alphabetChars.join('')})`);
}
if (typeof carry === 'bigint') {
return carry * BigInt(alphabetChars.length) + BigInt(index);
}
const value = carry * alphabetChars.length + index;
const isSafeValue = Number.isSafeInteger(value);
if (isSafeValue) {
return value;
}
throwIfBigIntNotAvailable(`Unable to decode the provided string, due to lack of support for BigInt numbers in the current environment`);
return BigInt(carry) * BigInt(alphabetChars.length) + BigInt(index);
}, 0);
exports.fromAlphabet = fromAlphabet;
const safeToParseNumberRegExp = /^\+?\d+$/;
const safeParseInt10 = (str) => {
if (!safeToParseNumberRegExp.test(str)) {
return Number.NaN;
}
const int10 = Number.parseInt(str, 10);
if (Number.isSafeInteger(int10)) {
return int10;
}
throwIfBigIntNotAvailable('Unable to encode the provided BigInt string without loss of information due to lack of support for BigInt type in the current environment');
return BigInt(str);
};
exports.safeParseInt10 = safeParseInt10;
const splitAtIntervalAndMap = (str, nth, map) => Array.from({ length: Math.ceil(str.length / nth) }, (_, index) => map(str.slice(index * nth, (index + 1) * nth)));
exports.splitAtIntervalAndMap = splitAtIntervalAndMap;
const makeAnyOfCharsRegExp = (chars) => new RegExp(chars
.map((char) => escapeRegExp(char))
// we need to sort these from longest to shortest,
// as they may contain multibyte unicode characters (these should come first)
.sort((a, b) => b.length - a.length)
.join('|'));
exports.makeAnyOfCharsRegExp = makeAnyOfCharsRegExp;
const makeAtLeastSomeCharRegExp = (chars) => new RegExp(`^[${chars
.map((char) => escapeRegExp(char))
// we need to sort these from longest to shortest,
// as they may contain multibyte unicode characters (these should come first)
.sort((a, b) => b.length - a.length)
.join('')}]+$`);
exports.makeAtLeastSomeCharRegExp = makeAtLeastSomeCharRegExp;
const escapeRegExp = (text) => text.replace(/[\s#$()*+,.?[\\\]^{|}-]/g, '\\$&');
const throwIfBigIntNotAvailable = (errorMessage = 'BigInt is not available in this environment') => {
if (typeof BigInt !== 'function') {
throw new TypeError(errorMessage);
}
};
//# sourceMappingURL=util.js.map