1 | function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
|
2 |
|
3 | function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
|
4 |
|
5 | function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
|
6 |
|
7 | function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
|
8 |
|
9 | var Hashids =
|
10 |
|
11 | function () {
|
12 | function Hashids(salt, minLength, alphabet, seps) {
|
13 | if (salt === void 0) {
|
14 | salt = '';
|
15 | }
|
16 |
|
17 | if (minLength === void 0) {
|
18 | minLength = 0;
|
19 | }
|
20 |
|
21 | if (alphabet === void 0) {
|
22 | alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
|
23 | }
|
24 |
|
25 | if (seps === void 0) {
|
26 | seps = 'cfhistuCFHISTU';
|
27 | }
|
28 |
|
29 | this.minLength = minLength;
|
30 |
|
31 | if (typeof minLength !== 'number') {
|
32 | throw new TypeError("Hashids: Provided 'minLength' has to be a number (is " + typeof minLength + ")");
|
33 | }
|
34 |
|
35 | if (typeof salt !== 'string') {
|
36 | throw new TypeError("Hashids: Provided 'salt' has to be a string (is " + typeof salt + ")");
|
37 | }
|
38 |
|
39 | if (typeof alphabet !== 'string') {
|
40 | throw new TypeError("Hashids: Provided alphabet has to be a string (is " + typeof alphabet + ")");
|
41 | }
|
42 |
|
43 | var saltChars = Array.from(salt);
|
44 | var alphabetChars = Array.from(alphabet);
|
45 | var sepsChars = Array.from(seps);
|
46 | this.salt = saltChars;
|
47 | var uniqueAlphabet = keepUnique(alphabetChars);
|
48 |
|
49 | if (uniqueAlphabet.length < minAlphabetLength) {
|
50 | throw new Error("Hashids: alphabet must contain at least " + minAlphabetLength + " unique characters, provided: " + uniqueAlphabet);
|
51 | }
|
52 |
|
53 |
|
54 |
|
55 | this.alphabet = withoutChars(uniqueAlphabet, sepsChars);
|
56 |
|
57 |
|
58 | var filteredSeps = onlyChars(sepsChars, uniqueAlphabet);
|
59 | this.seps = shuffle(filteredSeps, saltChars);
|
60 | var sepsLength;
|
61 | var diff;
|
62 |
|
63 | if (this.seps.length === 0 || this.alphabet.length / this.seps.length > sepDiv) {
|
64 | sepsLength = Math.ceil(this.alphabet.length / sepDiv);
|
65 |
|
66 | if (sepsLength > this.seps.length) {
|
67 | var _this$seps;
|
68 |
|
69 | diff = sepsLength - this.seps.length;
|
70 |
|
71 | (_this$seps = this.seps).push.apply(_this$seps, _toConsumableArray(this.alphabet.slice(0, diff)));
|
72 |
|
73 | this.alphabet = this.alphabet.slice(diff);
|
74 | }
|
75 | }
|
76 |
|
77 | this.alphabet = shuffle(this.alphabet, saltChars);
|
78 | var guardCount = Math.ceil(this.alphabet.length / guardDiv);
|
79 |
|
80 | if (this.alphabet.length < 3) {
|
81 | this.guards = this.seps.slice(0, guardCount);
|
82 | this.seps = this.seps.slice(guardCount);
|
83 | } else {
|
84 | this.guards = this.alphabet.slice(0, guardCount);
|
85 | this.alphabet = this.alphabet.slice(guardCount);
|
86 | }
|
87 |
|
88 | this.guardsRegExp = makeAnyOfCharsRegExp(this.guards);
|
89 | this.sepsRegExp = makeAnyOfCharsRegExp(this.seps);
|
90 | this.allowedCharsRegExp = makeAtLeastSomeCharRegExp([].concat(_toConsumableArray(this.alphabet), _toConsumableArray(this.guards), _toConsumableArray(this.seps)));
|
91 | }
|
92 |
|
93 | var _proto = Hashids.prototype;
|
94 |
|
95 | _proto.encode = function encode(first) {
|
96 | for (var _len = arguments.length, numbers = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
97 | numbers[_key - 1] = arguments[_key];
|
98 | }
|
99 |
|
100 | var ret = '';
|
101 |
|
102 | if (Array.isArray(first)) {
|
103 | numbers = first;
|
104 | } else {
|
105 |
|
106 | numbers = [].concat(_toConsumableArray(first != null ? [first] : []), _toConsumableArray(numbers));
|
107 | }
|
108 |
|
109 | if (!numbers.length) {
|
110 | return ret;
|
111 | }
|
112 |
|
113 | if (!numbers.every(isIntegerNumber)) {
|
114 | numbers = numbers.map(function (n) {
|
115 | return typeof n === 'bigint' || typeof n === 'number' ? n : safeParseInt10(String(n));
|
116 | });
|
117 | }
|
118 |
|
119 | if (!numbers.every(isPositiveAndFinite)) {
|
120 | return ret;
|
121 | }
|
122 |
|
123 | return this._encode(numbers).join('');
|
124 | };
|
125 |
|
126 | _proto.decode = function decode(id) {
|
127 | if (!id || typeof id !== 'string' || id.length === 0) return [];
|
128 | return this._decode(id);
|
129 | }
|
130 | |
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 | ;
|
146 |
|
147 | _proto.encodeHex = function encodeHex(hex) {
|
148 | switch (typeof hex) {
|
149 | case 'bigint':
|
150 | hex = hex.toString(16);
|
151 | break;
|
152 |
|
153 | case 'string':
|
154 | if (!/^[0-9a-fA-F]+$/.test(hex)) return '';
|
155 | break;
|
156 |
|
157 | default:
|
158 | throw new Error("Hashids: The provided value is neither a string, nor a BigInt (got: " + typeof hex + ")");
|
159 | }
|
160 |
|
161 | var numbers = splitAtIntervalAndMap(hex, 12, function (part) {
|
162 | return parseInt("1" + part, 16);
|
163 | });
|
164 | return this.encode(numbers);
|
165 | };
|
166 |
|
167 | _proto.decodeHex = function decodeHex(id) {
|
168 | return this.decode(id).map(function (number) {
|
169 | return number.toString(16).slice(1);
|
170 | }).join('');
|
171 | };
|
172 |
|
173 | _proto._encode = function _encode(numbers) {
|
174 | var _this = this;
|
175 |
|
176 | var alphabet = this.alphabet;
|
177 | var numbersIdInt = numbers.reduce(function (last, number, i) {
|
178 | return last + (typeof number === 'bigint' ? Number(number % BigInt(i + 100)) : number % (i + 100));
|
179 | }, 0);
|
180 | var ret = [alphabet[numbersIdInt % alphabet.length]];
|
181 | var lottery = ret.slice();
|
182 | var seps = this.seps;
|
183 | var guards = this.guards;
|
184 | numbers.forEach(function (number, i) {
|
185 | var _ret;
|
186 |
|
187 | var buffer = lottery.concat(_this.salt, alphabet);
|
188 | alphabet = shuffle(alphabet, buffer);
|
189 | var last = toAlphabet(number, alphabet);
|
190 |
|
191 | (_ret = ret).push.apply(_ret, _toConsumableArray(last));
|
192 |
|
193 | if (i + 1 < numbers.length) {
|
194 | var charCode = last[0].codePointAt(0) + i;
|
195 | var extraNumber = typeof number === 'bigint' ? Number(number % BigInt(charCode)) : number % charCode;
|
196 | ret.push(seps[extraNumber % seps.length]);
|
197 | }
|
198 | });
|
199 |
|
200 | if (ret.length < this.minLength) {
|
201 | var prefixGuardIndex = (numbersIdInt + ret[0].codePointAt(0)) % guards.length;
|
202 | ret.unshift(guards[prefixGuardIndex]);
|
203 |
|
204 | if (ret.length < this.minLength) {
|
205 | var suffixGuardIndex = (numbersIdInt + ret[2].codePointAt(0)) % guards.length;
|
206 | ret.push(guards[suffixGuardIndex]);
|
207 | }
|
208 | }
|
209 |
|
210 | var halfLength = Math.floor(alphabet.length / 2);
|
211 |
|
212 | while (ret.length < this.minLength) {
|
213 | var _ret2, _ret3;
|
214 |
|
215 | alphabet = shuffle(alphabet, alphabet);
|
216 |
|
217 | (_ret2 = ret).unshift.apply(_ret2, _toConsumableArray(alphabet.slice(halfLength)));
|
218 |
|
219 | (_ret3 = ret).push.apply(_ret3, _toConsumableArray(alphabet.slice(0, halfLength)));
|
220 |
|
221 | var excess = ret.length - this.minLength;
|
222 |
|
223 | if (excess > 0) {
|
224 | var halfOfExcess = excess / 2;
|
225 | ret = ret.slice(halfOfExcess, halfOfExcess + this.minLength);
|
226 | }
|
227 | }
|
228 |
|
229 | return ret;
|
230 | };
|
231 |
|
232 | _proto.isValidId = function isValidId(id) {
|
233 | return this.allowedCharsRegExp.test(id);
|
234 | };
|
235 |
|
236 | _proto._decode = function _decode(id) {
|
237 | if (!this.isValidId(id)) {
|
238 | throw new Error("The provided ID (" + id + ") is invalid, as it contains characters that do not exist in the alphabet (" + this.guards.join('') + this.seps.join('') + this.alphabet.join('') + ")");
|
239 | }
|
240 |
|
241 | var idGuardsArray = id.split(this.guardsRegExp);
|
242 | var splitIndex = idGuardsArray.length === 3 || idGuardsArray.length === 2 ? 1 : 0;
|
243 | var idBreakdown = idGuardsArray[splitIndex];
|
244 | if (idBreakdown.length === 0) return [];
|
245 | var lotteryChar = idBreakdown[Symbol.iterator]().next().value;
|
246 | var idArray = idBreakdown.slice(lotteryChar.length).split(this.sepsRegExp);
|
247 | var lastAlphabet = this.alphabet;
|
248 | var result = [];
|
249 |
|
250 | for (var _iterator = idArray, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
|
251 | var _ref;
|
252 |
|
253 | if (_isArray) {
|
254 | if (_i >= _iterator.length) break;
|
255 | _ref = _iterator[_i++];
|
256 | } else {
|
257 | _i = _iterator.next();
|
258 | if (_i.done) break;
|
259 | _ref = _i.value;
|
260 | }
|
261 |
|
262 | var subId = _ref;
|
263 | var buffer = [lotteryChar].concat(_toConsumableArray(this.salt), _toConsumableArray(lastAlphabet));
|
264 | var nextAlphabet = shuffle(lastAlphabet, buffer.slice(0, lastAlphabet.length));
|
265 | result.push(fromAlphabet(Array.from(subId), nextAlphabet));
|
266 | lastAlphabet = nextAlphabet;
|
267 | }
|
268 |
|
269 |
|
270 | if (this._encode(result).join('') !== id) return [];
|
271 | return result;
|
272 | };
|
273 |
|
274 | return Hashids;
|
275 | }();
|
276 |
|
277 | export { Hashids as default };
|
278 | var minAlphabetLength = 16;
|
279 | var sepDiv = 3.5;
|
280 | var guardDiv = 12;
|
281 | export var keepUnique = function keepUnique(content) {
|
282 | return Array.from(new Set(content));
|
283 | };
|
284 | export var withoutChars = function withoutChars(chars, _withoutChars) {
|
285 | return chars.filter(function (char) {
|
286 | return !_withoutChars.includes(char);
|
287 | });
|
288 | };
|
289 | export var onlyChars = function onlyChars(chars, keepChars) {
|
290 | return chars.filter(function (char) {
|
291 | return keepChars.includes(char);
|
292 | });
|
293 | };
|
294 |
|
295 | var isIntegerNumber = function isIntegerNumber(n) {
|
296 | return typeof n === 'bigint' || !Number.isNaN(Number(n)) && Math.floor(Number(n)) === n;
|
297 | };
|
298 |
|
299 | var isPositiveAndFinite = function isPositiveAndFinite(n) {
|
300 | return typeof n === 'bigint' || n >= 0 && Number.isSafeInteger(n);
|
301 | };
|
302 |
|
303 | function shuffle(alphabetChars, saltChars) {
|
304 | if (saltChars.length === 0) {
|
305 | return alphabetChars;
|
306 | }
|
307 |
|
308 | var integer;
|
309 | var transformed = alphabetChars.slice();
|
310 |
|
311 | for (var i = transformed.length - 1, v = 0, p = 0; i > 0; i--, v++) {
|
312 | v %= saltChars.length;
|
313 | p += integer = saltChars[v].codePointAt(0);
|
314 | var j = (integer + v + p) % i;
|
315 |
|
316 | var a = transformed[i];
|
317 | var b = transformed[j];
|
318 | transformed[j] = a;
|
319 | transformed[i] = b;
|
320 | }
|
321 |
|
322 | return transformed;
|
323 | }
|
324 |
|
325 | var toAlphabet = function toAlphabet(input, alphabetChars) {
|
326 | var id = [];
|
327 |
|
328 | if (typeof input === 'bigint') {
|
329 | var alphabetLength = BigInt(alphabetChars.length);
|
330 |
|
331 | do {
|
332 | id.unshift(alphabetChars[Number(input % alphabetLength)]);
|
333 | input = input / alphabetLength;
|
334 | } while (input > BigInt(0));
|
335 | } else {
|
336 | do {
|
337 | id.unshift(alphabetChars[input % alphabetChars.length]);
|
338 | input = Math.floor(input / alphabetChars.length);
|
339 | } while (input > 0);
|
340 | }
|
341 |
|
342 | return id;
|
343 | };
|
344 |
|
345 | var fromAlphabet = function fromAlphabet(inputChars, alphabetChars) {
|
346 | return inputChars.reduce(function (carry, item) {
|
347 | var index = alphabetChars.indexOf(item);
|
348 |
|
349 | if (index === -1) {
|
350 | throw new Error("The provided ID (" + inputChars.join('') + ") is invalid, as it contains characters that do not exist in the alphabet (" + alphabetChars.join('') + ")");
|
351 | }
|
352 |
|
353 | if (typeof carry === 'bigint') {
|
354 | return carry * BigInt(alphabetChars.length) + BigInt(index);
|
355 | }
|
356 |
|
357 | var value = carry * alphabetChars.length + index;
|
358 | var isSafeValue = Number.isSafeInteger(value);
|
359 |
|
360 | if (isSafeValue) {
|
361 | return value;
|
362 | } else {
|
363 | if (typeof BigInt === 'function') {
|
364 | return BigInt(carry) * BigInt(alphabetChars.length) + BigInt(index);
|
365 | } else {
|
366 |
|
367 | throw new Error("Unable to decode the provided string, due to lack of support for BigInt numbers in the current environment");
|
368 | }
|
369 | }
|
370 | }, 0);
|
371 | };
|
372 |
|
373 | var safeToParseNumberRegExp = /^\+?[0-9]+$/;
|
374 |
|
375 | var safeParseInt10 = function safeParseInt10(str) {
|
376 | return safeToParseNumberRegExp.test(str) ? parseInt(str, 10) : NaN;
|
377 | };
|
378 |
|
379 | var splitAtIntervalAndMap = function splitAtIntervalAndMap(str, nth, map) {
|
380 | return Array.from({
|
381 | length: Math.ceil(str.length / nth)
|
382 | }, function (_, index) {
|
383 | return map(str.slice(index * nth, (index + 1) * nth));
|
384 | });
|
385 | };
|
386 |
|
387 | var makeAnyOfCharsRegExp = function makeAnyOfCharsRegExp(chars) {
|
388 | return new RegExp(chars.map(function (char) {
|
389 | return escapeRegExp(char);
|
390 | })
|
391 |
|
392 | .sort(function (a, b) {
|
393 | return b.length - a.length;
|
394 | }).join('|'));
|
395 | };
|
396 |
|
397 | var makeAtLeastSomeCharRegExp = function makeAtLeastSomeCharRegExp(chars) {
|
398 | return new RegExp("^[" + chars.map(function (char) {
|
399 | return escapeRegExp(char);
|
400 | })
|
401 |
|
402 | .sort(function (a, b) {
|
403 | return b.length - a.length;
|
404 | }).join('') + "]+$");
|
405 | };
|
406 |
|
407 | var escapeRegExp = function escapeRegExp(text) {
|
408 | return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
409 | };
|
410 |
|
411 |
|
\ | No newline at end of file |