hashids
Advanced tools
Comparing version 1.2.2 to 2.0.0-prerelease.2
module.exports = { | ||
presets: [ | ||
[ | ||
'@babel/preset-env', | ||
{ | ||
modules: process.env.BABEL_MODULES ? false : 'umd', | ||
} | ||
], | ||
], | ||
plugins: [ | ||
'@babel/plugin-syntax-dynamic-import' | ||
] | ||
presets: [ | ||
[ | ||
'@babel/preset-env', | ||
{ | ||
modules: false, | ||
...(process.env.NODE_ENV === 'test' | ||
? { | ||
targets: { | ||
node: 'current', | ||
}, | ||
} | ||
: {}), | ||
}, | ||
], | ||
'@babel/preset-typescript', | ||
], | ||
plugins: [ | ||
'@babel/plugin-syntax-bigint', | ||
...(process.env.BABEL_MODULES | ||
? [] | ||
: ['@babel/plugin-transform-modules-umd']), | ||
], | ||
moduleId: 'Hashids', | ||
} |
@@ -5,6 +5,7 @@ { | ||
"main": "dist/hashids.js", | ||
"homepage": "https://github.com/ivanakimov/hashids.js", | ||
"homepage": "https://github.com/niieani/hashids.js", | ||
"license": "MIT", | ||
"authors": [ | ||
"Ivan Akimov <ivan@barreleye.com> (https://twitter.com/IvanAkimov)" | ||
"Ivan Akimov <ivan@barreleye.com> (https://twitter.com/IvanAkimov)", | ||
"Bazyli Brzóska <npm@invent.life> (https://twitter.com/niieani)" | ||
], | ||
@@ -11,0 +12,0 @@ "ignore": [ |
@@ -1,4 +0,29 @@ | ||
# CHANGELOG | ||
**2.0.0**: | ||
This is pretty much a TypeScript rewrite. | ||
### Breaking changes | ||
- BREAKING CHANGE: Hashids now throws errors when being constructed with incorrect options (previously, it silently falled back to defaults) | ||
- BREAKING CHANGE: when used from Node (without ESM enabled), you now need to `require('hashids/cjs')` | ||
### Features | ||
- transparent support of `BigInt`s. If your environment supports them, | ||
you can use the standard API to encode and decode them. | ||
Note that trying to decode a `BigInt` hashid on an unsupported environment will throw an error. | ||
- lifted the limitation that the alphabet cannot containin spaces | ||
- both the alphabet and salt may now contain multi-byte characters (e.g. for an emoji-based alphabet) | ||
### Chores | ||
- upgraded all dependencies | ||
- tests now use `jest` testing framework | ||
- extracted static methods to helper functions | ||
- converted the implementation to TypeScript | ||
- added `prettier` | ||
- added stricter `eslint` rules | ||
**1.2.2**: | ||
@@ -28,3 +53,3 @@ | ||
- looks like some bad input could generate negative numbers, which when passed to `_encode` would crash because it can't handle those <https://github.com/ivanakimov/hashids.js/issues/34> | ||
*NOTE:* do not use `1.1.3`, it wasn't re-built | ||
_NOTE:_ do not use `1.1.3`, it wasn't re-built | ||
@@ -56,10 +81,10 @@ **1.1.2**: | ||
```javascript | ||
var hashids = new Hashids(); | ||
```javascript | ||
var hashids = new Hashids(); | ||
hashids.encode(1, 2, 3); // o2fXhV | ||
hashids.encode([1, 2, 3]); // o2fXhV | ||
hashids.encode('1', '2', '3'); // o2fXhV | ||
hashids.encode(['1', '2', '3']); // o2fXhV | ||
``` | ||
hashids.encode(1, 2, 3); // o2fXhV | ||
hashids.encode([1, 2, 3]); // o2fXhV | ||
hashids.encode('1', '2', '3'); // o2fXhV | ||
hashids.encode(['1', '2', '3']); // o2fXhV | ||
``` | ||
@@ -72,13 +97,9 @@ **1.0.2**: | ||
- *require.js* support by [@nleclerc](https://github.com/nleclerc): <https://github.com/ivanakimov/hashids.js/pull/12> | ||
- _require.js_ support by [@nleclerc](https://github.com/nleclerc): <https://github.com/ivanakimov/hashids.js/pull/12> | ||
**1.0.0**: | ||
- Several public functions are renamed to be more appropriate: | ||
- Function `encrypt()` changed to `encode()` | ||
- Function `decrypt()` changed to `decode()` | ||
- Function `encryptHex()` changed to `encodeHex()` | ||
- Function `decryptHex()` changed to `decodeHex()` | ||
- Several public functions are renamed to be more appropriate: - Function `encrypt()` changed to `encode()` - Function `decrypt()` changed to `decode()` - Function `encryptHex()` changed to `encodeHex()` - Function `decryptHex()` changed to `decodeHex()` | ||
Hashids was designed to encode integers, primary ids at most. We've had several requests to encrypt sensitive data with Hashids and this is the wrong algorithm for that. So to encourage more appropriate use, `encrypt/decrypt` is being "downgraded" to `encode/decode`. | ||
Hashids was designed to encode integers, primary ids at most. We've had several requests to encrypt sensitive data with Hashids and this is the wrong algorithm for that. So to encourage more appropriate use, `encrypt/decrypt` is being "downgraded" to `encode/decode`. | ||
@@ -109,3 +130,3 @@ - Version tag added: `1.0` | ||
Warning: If you are using 0.1.2 or below, updating to this version will change your hashes. | ||
Warning: If you are using 0.1.2 or below, updating to this version will change your hashes. | ||
@@ -117,3 +138,3 @@ - Updated default alphabet (thanks to [@speps](https://github.com/speps)) | ||
Warning: If you are using 0.1.1 or below, updating to this version will change your hashes. | ||
Warning: If you are using 0.1.1 or below, updating to this version will change your hashes. | ||
@@ -120,0 +141,0 @@ - Minimum hash length can now be specified |
@@ -1,6 +0,450 @@ | ||
"use strict"; | ||
// this file here is for backwards compatibility with an earlier CommonJS version | ||
const Hashids = require("./index").default; | ||
Object.defineProperty(Hashids, "__esModule", {value: true}); | ||
module.exports = Hashids; | ||
Hashids.default = module.exports; | ||
(function (global, factory) { | ||
if (typeof define === "function" && define.amd) { | ||
define("Hashids", ["exports"], factory); | ||
} else if (typeof exports !== "undefined") { | ||
factory(exports); | ||
} else { | ||
var mod = { | ||
exports: {} | ||
}; | ||
factory(mod.exports); | ||
global.Hashids = mod.exports; | ||
} | ||
})(this, function (_exports) { | ||
"use strict"; | ||
Object.defineProperty(_exports, "__esModule", { | ||
value: true | ||
}); | ||
_exports.unicodeSubstr = _exports.onlyChars = _exports.withoutChars = _exports.keepUniqueChars = _exports.default = void 0; | ||
function _toArray(arr) { return _arrayWithHoles(arr) || _iterableToArray(arr) || _nonIterableRest(); } | ||
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } | ||
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } | ||
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } | ||
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } | ||
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } | ||
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; } } | ||
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } | ||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } | ||
var Hashids = | ||
/*#__PURE__*/ | ||
function () { | ||
function Hashids() { | ||
var salt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; | ||
var minLength = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; | ||
var alphabet = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'; | ||
var seps = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'cfhistuCFHISTU'; | ||
_classCallCheck(this, Hashids); | ||
this.salt = salt; | ||
this.minLength = minLength; | ||
if (typeof minLength !== 'number') { | ||
throw new Error("Hashids: Provided 'minLength' has to be a number (is ".concat(_typeof(minLength), ")")); | ||
} | ||
if (typeof salt !== 'string') { | ||
throw new Error("Hashids: Provided 'salt' has to be a string (is ".concat(_typeof(salt), ")")); | ||
} | ||
if (typeof alphabet !== 'string') { | ||
throw new Error("Hashids: Provided alphabet has to be a string (is ".concat(_typeof(alphabet), ")")); | ||
} | ||
var uniqueAlphabet = keepUniqueChars(alphabet); | ||
if (uniqueAlphabet.length < minAlphabetLength) { | ||
throw new Error("Hashids: alphabet must contain at least ".concat(minAlphabetLength, " unique characters, provided: ").concat(uniqueAlphabet)); | ||
} | ||
/** `alphabet` should not contains `seps` */ | ||
this.alphabet = withoutChars(uniqueAlphabet, seps); | ||
/** `seps` should contain only characters present in `alphabet` */ | ||
var filteredSeps = onlyChars(seps, uniqueAlphabet); | ||
this.seps = shuffle(filteredSeps, salt); | ||
var sepsLength; | ||
var diff; | ||
if (_toConsumableArray(this.seps).length === 0 || _toConsumableArray(this.alphabet).length / _toConsumableArray(this.seps).length > sepDiv) { | ||
sepsLength = Math.ceil(_toConsumableArray(this.alphabet).length / sepDiv); | ||
if (sepsLength > _toConsumableArray(this.seps).length) { | ||
diff = sepsLength - _toConsumableArray(this.seps).length; | ||
this.seps += unicodeSubstr(this.alphabet, 0, diff); | ||
this.alphabet = unicodeSubstr(this.alphabet, diff); | ||
} | ||
} | ||
this.alphabet = shuffle(this.alphabet, salt); | ||
var guardCount = Math.ceil(_toConsumableArray(this.alphabet).length / guardDiv); | ||
if (_toConsumableArray(this.alphabet).length < 3) { | ||
this.guards = unicodeSubstr(this.seps, 0, guardCount); | ||
this.seps = unicodeSubstr(this.seps, guardCount); | ||
} else { | ||
this.guards = unicodeSubstr(this.alphabet, 0, guardCount); | ||
this.alphabet = unicodeSubstr(this.alphabet, guardCount); | ||
} | ||
} | ||
_createClass(Hashids, [{ | ||
key: "encode", | ||
value: function encode(first) { | ||
for (var _len = arguments.length, numbers = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
numbers[_key - 1] = arguments[_key]; | ||
} | ||
var ret = ''; | ||
if (Array.isArray(first)) { | ||
numbers = first; | ||
} else { | ||
// eslint-disable-next-line eqeqeq | ||
numbers = [].concat(_toConsumableArray(first != null ? [first] : []), _toConsumableArray(numbers)); | ||
} | ||
if (!numbers.length) { | ||
return ret; | ||
} | ||
if (!numbers.every(isIntegerNumber)) { | ||
numbers = numbers.map(function (n) { | ||
return typeof n === 'bigint' || typeof n === 'number' ? n : safeParseInt10(String(n)); | ||
}); | ||
} | ||
if (!numbers.every(isPositiveAndFinite)) { | ||
return ret; | ||
} | ||
return this._encode(numbers); | ||
} | ||
}, { | ||
key: "decode", | ||
value: function decode(id) { | ||
if (!id || typeof id !== 'string' || id.length === 0) return []; | ||
return this._decode(id, this.alphabet); | ||
} | ||
/** | ||
* @description Splits a hex string into groups of 12-digit hexadecimal numbers, | ||
* then prefixes each with '1' and encodes the resulting array of numbers | ||
* | ||
* Encoding '00000000000f00000000000f000f' would be the equivalent of: | ||
* Hashids.encode([0x100000000000f, 0x100000000000f, 0x1000f]) | ||
* | ||
* This means that if your environment supports BigInts, | ||
* you will get different (shorter) results if you provide | ||
* a BigInt representation of your hex and use `encode` directly, e.g.: | ||
* Hashids.encode(BigInt(`0x${hex}`)) | ||
* | ||
* To decode such a representation back to a hex string, use the following snippet: | ||
* Hashids.decode(id)[0].toString(16) | ||
*/ | ||
}, { | ||
key: "encodeHex", | ||
value: function encodeHex(hex) { | ||
switch (_typeof(hex)) { | ||
case 'bigint': | ||
hex = hex.toString(16); | ||
break; | ||
case 'string': | ||
if (!/^[0-9a-fA-F]+$/.test(hex)) return ''; | ||
break; | ||
default: | ||
throw new Error("Hashids: The provided value is neither a string, nor a BigInt (got: ".concat(_typeof(hex), ")")); | ||
} | ||
var numbers = splitAtIntervalAndMap(hex, 12, function (part) { | ||
return parseInt("1".concat(part), 16); | ||
}); | ||
return this.encode(numbers); | ||
} | ||
}, { | ||
key: "decodeHex", | ||
value: function decodeHex(id) { | ||
return this.decode(id).map(function (number) { | ||
return number.toString(16).slice(1); | ||
}).join(''); | ||
} | ||
}, { | ||
key: "_encode", | ||
value: function _encode(numbers) { | ||
var _this = this; | ||
var ret; | ||
var alphabet = this.alphabet; | ||
var numbersIdInt = numbers.reduce(function (last, number, i) { | ||
return last + (typeof number === 'bigint' ? Number(number % BigInt(i + 100)) : number % (i + 100)); | ||
}, 0); | ||
ret = _toConsumableArray(alphabet)[numbersIdInt % _toConsumableArray(alphabet).length]; | ||
var lottery = ret; | ||
var seps = _toConsumableArray(this.seps); | ||
var guards = _toConsumableArray(this.guards); | ||
numbers.forEach(function (number, i) { | ||
var buffer = lottery + _this.salt + alphabet; | ||
alphabet = shuffle(alphabet, unicodeSubstr(buffer, 0)); | ||
var last = toAlphabet(number, alphabet); | ||
ret += last; | ||
if (i + 1 < numbers.length) { | ||
var charCode = last.codePointAt(0) + i; | ||
var extraNumber = typeof number === 'bigint' ? Number(number % BigInt(charCode)) : number % charCode; | ||
ret += seps[extraNumber % seps.length]; | ||
} | ||
}); | ||
if (_toConsumableArray(ret).length < this.minLength) { | ||
var prefixGuardIndex = (numbersIdInt + _toConsumableArray(ret)[0].codePointAt(0)) % guards.length; | ||
ret = guards[prefixGuardIndex] + ret; | ||
if (_toConsumableArray(ret).length < this.minLength) { | ||
var suffixGuardIndex = (numbersIdInt + _toConsumableArray(ret)[2].codePointAt(0)) % guards.length; | ||
ret = ret + guards[suffixGuardIndex]; | ||
} | ||
} | ||
var halfLength = Math.floor(_toConsumableArray(alphabet).length / 2); | ||
while (_toConsumableArray(ret).length < this.minLength) { | ||
alphabet = shuffle(alphabet, alphabet); | ||
ret = unicodeSubstr(alphabet, halfLength) + ret + unicodeSubstr(alphabet, 0, halfLength); | ||
var excess = _toConsumableArray(ret).length - this.minLength; | ||
if (excess > 0) { | ||
ret = unicodeSubstr(ret, excess / 2, this.minLength); | ||
} | ||
} | ||
return ret; | ||
} | ||
}, { | ||
key: "_decode", | ||
value: function _decode(id, alphabet) { | ||
var _this2 = this; | ||
var idGuardsArray = splitAtMatch(id, function (char) { | ||
return _this2.guards.includes(char); | ||
}); | ||
var splitIndex = idGuardsArray.length === 3 || idGuardsArray.length === 2 ? 1 : 0; | ||
var idBreakdown = idGuardsArray[splitIndex]; | ||
var idBreakdownArray = _toConsumableArray(idBreakdown); | ||
if (idBreakdownArray.length === 0) return []; | ||
var _idBreakdownArray = _toArray(idBreakdownArray), | ||
lotteryChar = _idBreakdownArray[0], | ||
chars = _idBreakdownArray.slice(1); | ||
var rest = chars.join(''); | ||
var idArray = splitAtMatch(rest, function (char) { | ||
return _this2.seps.includes(char); | ||
}); | ||
var _idArray$reduce = idArray.reduce(function (_ref, subId) { | ||
var result = _ref.result, | ||
lastAlphabet = _ref.lastAlphabet; | ||
var buffer = lotteryChar + _this2.salt + lastAlphabet; | ||
var nextAlphabet = shuffle(lastAlphabet, unicodeSubstr(buffer, 0, _toConsumableArray(lastAlphabet).length)); | ||
return { | ||
result: [].concat(_toConsumableArray(result), [fromAlphabet(subId, nextAlphabet)]), | ||
lastAlphabet: nextAlphabet | ||
}; | ||
}, { | ||
result: [], | ||
lastAlphabet: alphabet | ||
}), | ||
result = _idArray$reduce.result; | ||
if (this._encode(result) !== id) return []; | ||
return result; | ||
} | ||
}]); | ||
return Hashids; | ||
}(); | ||
_exports.default = Hashids; | ||
var minAlphabetLength = 16; | ||
var sepDiv = 3.5; | ||
var guardDiv = 12; | ||
var keepUniqueChars = function keepUniqueChars(str) { | ||
return Array.from(new Set(str)).join(''); | ||
}; | ||
_exports.keepUniqueChars = keepUniqueChars; | ||
var withoutChars = function withoutChars(_ref2, _ref3) { | ||
var _ref4 = _toArray(_ref2), | ||
str = _ref4.slice(0); | ||
var _ref5 = _toArray(_ref3), | ||
without = _ref5.slice(0); | ||
return str.filter(function (char) { | ||
return !without.includes(char); | ||
}).join(''); | ||
}; | ||
_exports.withoutChars = withoutChars; | ||
var onlyChars = function onlyChars(_ref6, _ref7) { | ||
var _ref8 = _toArray(_ref6), | ||
str = _ref8.slice(0); | ||
var _ref9 = _toArray(_ref7), | ||
only = _ref9.slice(0); | ||
return str.filter(function (char) { | ||
return only.includes(char); | ||
}).join(''); | ||
}; | ||
_exports.onlyChars = onlyChars; | ||
var unicodeSubstr = function unicodeSubstr(_ref10, from, to) { | ||
var _ref11 = _toArray(_ref10), | ||
str = _ref11.slice(0); | ||
return str.slice(from, to === undefined ? undefined : from + to).join(''); | ||
}; | ||
_exports.unicodeSubstr = unicodeSubstr; | ||
var isIntegerNumber = function isIntegerNumber(n) { | ||
return typeof n === 'bigint' || !Number.isNaN(Number(n)) && Math.floor(Number(n)) === n; | ||
}; | ||
var isPositiveAndFinite = function isPositiveAndFinite(n) { | ||
return typeof n === 'bigint' || n >= 0 && Number.isSafeInteger(n); | ||
}; | ||
function shuffle(alphabet, _ref12) { | ||
var _ref13 = _toArray(_ref12), | ||
salt = _ref13.slice(0); | ||
var integer; | ||
if (!salt.length) { | ||
return alphabet; | ||
} | ||
var alphabetChars = _toConsumableArray(alphabet); | ||
for (var i = alphabetChars.length - 1, v = 0, p = 0; i > 0; i--, v++) { | ||
v %= salt.length; | ||
p += integer = salt[v].codePointAt(0); | ||
var j = (integer + v + p) % i // swap characters at positions i and j | ||
; | ||
var _ref14 = [alphabetChars[i], alphabetChars[j]]; | ||
alphabetChars[j] = _ref14[0]; | ||
alphabetChars[i] = _ref14[1]; | ||
} | ||
return alphabetChars.join(''); | ||
} | ||
var toAlphabet = function toAlphabet(input, _ref15) { | ||
var _ref16 = _toArray(_ref15), | ||
alphabet = _ref16.slice(0); | ||
var id = ''; | ||
if (typeof input === 'bigint') { | ||
var alphabetLength = BigInt(alphabet.length); | ||
do { | ||
id = alphabet[Number(input % alphabetLength)] + id; | ||
input = input / alphabetLength; | ||
} while (input); | ||
} else { | ||
do { | ||
id = alphabet[input % alphabet.length] + id; | ||
input = Math.floor(input / alphabet.length); | ||
} while (input); | ||
} | ||
return id; | ||
}; | ||
var fromAlphabet = function fromAlphabet(_ref17, _ref18) { | ||
var _ref19 = _toArray(_ref17), | ||
input = _ref19.slice(0); | ||
var _ref20 = _toArray(_ref18), | ||
alphabet = _ref20.slice(0); | ||
return input.map(function (item) { | ||
return alphabet.indexOf(item); | ||
}).reduce(function (carry, index) { | ||
if (typeof carry === 'bigint') { | ||
return carry * BigInt(alphabet.length) + BigInt(index); | ||
} | ||
var value = carry * alphabet.length + index; | ||
var isSafeValue = Number.isSafeInteger(value); | ||
if (isSafeValue) { | ||
return value; | ||
} else { | ||
if (typeof BigInt === 'function') { | ||
return BigInt(carry) * BigInt(alphabet.length) + BigInt(index); | ||
} else { | ||
// we do not have support for BigInt: | ||
throw new Error("Unable to decode the provided string, due to lack of support for BigInt numbers in the current environment"); | ||
} | ||
} | ||
}, 0); | ||
}; | ||
var splitAtMatch = function splitAtMatch(_ref21, match) { | ||
var _ref22 = _toArray(_ref21), | ||
chars = _ref22.slice(0); | ||
return chars.reduce(function (groups, char) { | ||
return match(char) ? [].concat(_toConsumableArray(groups), ['']) : [].concat(_toConsumableArray(groups.slice(0, -1)), [groups[groups.length - 1] + char]); | ||
}, ['']); | ||
}; | ||
var safeToParseNumberRegExp = /^\+?[0-9]+$/; | ||
var safeParseInt10 = function safeParseInt10(str) { | ||
return safeToParseNumberRegExp.test(str) ? parseInt(str, 10) : NaN; | ||
}; | ||
/** note: this doesn't need to support unicode, since it's used to split hex strings only */ | ||
var splitAtIntervalAndMap = function splitAtIntervalAndMap(str, nth, map) { | ||
return Array.from({ | ||
length: Math.ceil(str.length / nth) | ||
}, function (_, index) { | ||
return map(str.slice(index * nth, (index + 1) * nth)); | ||
}); | ||
}; | ||
}); | ||
//# sourceMappingURL=hashids.js.map |
@@ -1,2 +0,2 @@ | ||
!function(t,e){if("function"==typeof define&&define.amd)define(["exports"],e);else if("undefined"!=typeof exports)e(exports);else{var s={};e(s),t.Hashids=s}}(this,function(t){"use strict";function h(t,e){for(var s=0;s<e.length;s++){var h=e[s];h.enumerable=h.enumerable||!1,h.configurable=!0,"value"in h&&(h.writable=!0),Object.defineProperty(t,h.key,h)}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var e=function(){function u(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"",e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:0,s=2<arguments.length&&void 0!==arguments[2]?arguments[2]:"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,u);var h,a,n="";this.escapeRegExp=function(t){return t.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},this.parseInt=function(t,e){return/^(-|\+)?([0-9]+|Infinity)$/.test(t)?parseInt(t,e):NaN},this.seps="cfhistuCFHISTU",this.minLength=0<parseInt(e,10)?e:0,this.salt="string"==typeof t?t:"","string"==typeof s&&(this.alphabet=s);for(var r=0;r!==this.alphabet.length;r++)-1===n.indexOf(this.alphabet.charAt(r))&&(n+=this.alphabet.charAt(r));if(this.alphabet=n,this.alphabet.length<16)throw"error: alphabet must contain at least X unique characters".replace("X",16);if(-1!==this.alphabet.search(" "))throw"error: alphabet cannot contain spaces";for(var i=0;i!==this.seps.length;i++){var l=this.alphabet.indexOf(this.seps.charAt(i));-1===l?this.seps=this.seps.substr(0,i)+" "+this.seps.substr(i+1):this.alphabet=this.alphabet.substr(0,l)+" "+this.alphabet.substr(l+1)}this.alphabet=this.alphabet.replace(/ /g,""),this.seps=this.seps.replace(/ /g,""),this.seps=this._shuffle(this.seps,this.salt),(!this.seps.length||3.5<this.alphabet.length/this.seps.length)&&(h=Math.ceil(this.alphabet.length/3.5))>this.seps.length&&(a=h-this.seps.length,this.seps+=this.alphabet.substr(0,a),this.alphabet=this.alphabet.substr(a)),this.alphabet=this._shuffle(this.alphabet,this.salt);var p=Math.ceil(this.alphabet.length/12);this.alphabet.length<3?(this.guards=this.seps.substr(0,p),this.seps=this.seps.substr(p)):(this.guards=this.alphabet.substr(0,p),this.alphabet=this.alphabet.substr(p))}var t,e,s;return t=u,(e=[{key:"encode",value:function(){for(var t=arguments.length,e=new Array(t),s=0;s<t;s++)e[s]=arguments[s];if(!e.length)return"";if(e[0]&&e[0].constructor===Array&&!(e=e[0]).length)return"";for(var h=0;h!==e.length;h++)if(e[h]=this.parseInt(e[h],10),!(0<=e[h]))return"";return this._encode(e)}},{key:"decode",value:function(t){return t&&t.length&&"string"==typeof t?this._decode(t,this.alphabet):[]}},{key:"encodeHex",value:function(t){if(t=t.toString(),!/^[0-9a-fA-F]+$/.test(t))return"";for(var e=t.match(/[\w\W]{1,12}/g),s=0;s!==e.length;s++)e[s]=parseInt("1"+e[s],16);return this.encode.apply(this,e)}},{key:"decodeHex",value:function(t){for(var e=[],s=this.decode(t),h=0;h!==s.length;h++)e+=s[h].toString(16).substr(1);return e}},{key:"_encode",value:function(t){for(var e,s=this.alphabet,h=0,a=0;a!==t.length;a++)h+=t[a]%(a+100);for(var n=e=s.charAt(h%s.length),r=0;r!==t.length;r++){var i=t[r],l=n+this.salt+s;s=this._shuffle(s,l.substr(0,s.length));var p=this._toAlphabet(i,s);if(e+=p,r+1<t.length){var u=(i%=p.charCodeAt(0)+r)%this.seps.length;e+=this.seps.charAt(u)}}if(e.length<this.minLength){var o=(h+e[0].charCodeAt(0))%this.guards.length,f=this.guards[o];(e=f+e).length<this.minLength&&(o=(h+e[2].charCodeAt(0))%this.guards.length,e+=f=this.guards[o])}for(var c=parseInt(s.length/2,10);e.length<this.minLength;){var g=(e=(s=this._shuffle(s,s)).substr(c)+e+s.substr(0,c)).length-this.minLength;0<g&&(e=e.substr(g/2,this.minLength))}return e}},{key:"_decode",value:function(t,e){var s=[],h=0,a=new RegExp("[".concat(this.escapeRegExp(this.guards),"]"),"g"),n=t.replace(a," "),r=n.split(" ");if(3!==r.length&&2!==r.length||(h=1),void 0!==(n=r[h])[0]){var i=n[0];n=n.substr(1),a=new RegExp("[".concat(this.escapeRegExp(this.seps),"]"),"g"),r=(n=n.replace(a," ")).split(" ");for(var l=0;l!==r.length;l++){var p=r[l],u=i+this.salt+e;e=this._shuffle(e,u.substr(0,e.length)),s.push(this._fromAlphabet(p,e))}this.encode(s)!==t&&(s=[])}return s}},{key:"_shuffle",value:function(t,e){var s;if(!e.length)return t;for(var h=(t=t.split("")).length-1,a=0,n=0,r=0;0<h;h--,a++){a%=e.length,n+=s=e.charCodeAt(a);var i=t[r=(s+a+n)%h];t[r]=t[h],t[h]=i}return t=t.join("")}},{key:"_toAlphabet",value:function(t,e){for(var s="";s=e.charAt(t%e.length)+s,t=parseInt(t/e.length,10););return s}},{key:"_fromAlphabet",value:function(t,s){return t.split("").map(function(t){return s.indexOf(t)}).reduce(function(t,e){return t*s.length+e},0)}}])&&h(t.prototype,e),s&&h(t,s),u}();t.default=e}); | ||
!function(t,e){if("function"==typeof define&&define.amd)define("Hashids",["exports"],e);else if("undefined"!=typeof exports)e(exports);else{var n={};e(n),t.Hashids=n}}(this,function(t){"use strict";function l(t){return function(t){if(Array.isArray(t))return t}(t)||e(t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function f(t){return function(t){if(Array.isArray(t)){for(var e=0,n=new Array(t.length);e<t.length;e++)n[e]=t[e];return n}}(t)||e(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}function e(t){if(Symbol.iterator in Object(t)||"[object Arguments]"===Object.prototype.toString.call(t))return Array.from(t)}function c(t){return(c="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function r(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}Object.defineProperty(t,"__esModule",{value:!0}),t.unicodeSubstr=t.onlyChars=t.withoutChars=t.keepUniqueChars=t.default=void 0;var n=function(){function h(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"",e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:0,n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:"cfhistuCFHISTU";if(function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,h),this.salt=t,"number"!=typeof(this.minLength=e))throw new Error("Hashids: Provided 'minLength' has to be a number (is ".concat(c(e),")"));if("string"!=typeof t)throw new Error("Hashids: Provided 'salt' has to be a string (is ".concat(c(t),")"));if("string"!=typeof n)throw new Error("Hashids: Provided alphabet has to be a string (is ".concat(c(n),")"));var i=b(n);if(i.length<g)throw new Error("Hashids: alphabet must contain at least ".concat(g," unique characters, provided: ").concat(i));this.alphabet=v(i,r);var o,a,s=y(r,i);this.seps=w(s,t),(0===f(this.seps).length||f(this.alphabet).length/f(this.seps).length>d)&&(o=Math.ceil(f(this.alphabet).length/d))>f(this.seps).length&&(a=o-f(this.seps).length,this.seps+=m(this.alphabet,0,a),this.alphabet=m(this.alphabet,a)),this.alphabet=w(this.alphabet,t);var u=Math.ceil(f(this.alphabet).length/p);f(this.alphabet).length<3?(this.guards=m(this.seps,0,u),this.seps=m(this.seps,u)):(this.guards=m(this.alphabet,0,u),this.alphabet=m(this.alphabet,u))}return function(t,e,n){e&&r(t.prototype,e),n&&r(t,n)}(h,[{key:"encode",value:function(t){for(var e=arguments.length,n=new Array(1<e?e-1:0),r=1;r<e;r++)n[r-1]=arguments[r];return(n=Array.isArray(t)?t:[].concat(f(null!=t?[t]:[]),f(n))).length?(n.every(i)||(n=n.map(function(t){return"bigint"==typeof t||"number"==typeof t?t:s(String(t))})),n.every(o)?this._encode(n):""):""}},{key:"decode",value:function(t){return t&&"string"==typeof t&&0!==t.length?this._decode(t,this.alphabet):[]}},{key:"encodeHex",value:function(t){switch(c(t)){case"bigint":t=t.toString(16);break;case"string":if(!/^[0-9a-fA-F]+$/.test(t))return"";break;default:throw new Error("Hashids: The provided value is neither a string, nor a BigInt (got: ".concat(c(t),")"))}var e=u(t,12,function(t){return parseInt("1".concat(t),16)});return this.encode(e)}},{key:"decodeHex",value:function(t){return this.decode(t).map(function(t){return t.toString(16).slice(1)}).join("")}},{key:"_encode",value:function(a){var s,u=this,h=this.alphabet,t=a.reduce(function(t,e,n){return t+("bigint"==typeof e?Number(e%BigInt(n+100)):e%(n+100))},0),l=s=f(h)[t%f(h).length],c=f(this.seps),e=f(this.guards);if(a.forEach(function(t,e){var n=l+u.salt+h;h=w(h,m(n,0));var r=A(t,h);if(s+=r,e+1<a.length){var i=r.codePointAt(0)+e,o="bigint"==typeof t?Number(t%BigInt(i)):t%i;s+=c[o%c.length]}}),f(s).length<this.minLength){var n=(t+f(s)[0].codePointAt(0))%e.length;if(f(s=e[n]+s).length<this.minLength){var r=(t+f(s)[2].codePointAt(0))%e.length;s+=e[r]}}for(var i=Math.floor(f(h).length/2);f(s).length<this.minLength;){h=w(h,h);var o=f(s=m(h,i)+s+m(h,0,i)).length-this.minLength;0<o&&(s=m(s,o/2,this.minLength))}return s}},{key:"_decode",value:function(t,e){var a=this,n=S(t,function(t){return a.guards.includes(t)}),r=f(n[3===n.length||2===n.length?1:0]);if(0===r.length)return[];var i=l(r),s=i[0],o=i.slice(1).join(""),u=S(o,function(t){return a.seps.includes(t)}).reduce(function(t,e){var n=t.result,r=t.lastAlphabet,i=s+a.salt+r,o=w(r,m(i,0,f(r).length));return{result:[].concat(f(n),[I(e,o)]),lastAlphabet:o}},{result:[],lastAlphabet:e}).result;return this._encode(u)!==t?[]:u}}]),h}();t.default=n;var g=16,d=3.5,p=12,b=function(t){return Array.from(new Set(t)).join("")};t.keepUniqueChars=b;var v=function(t,e){var n=l(t).slice(0),r=l(e).slice(0);return n.filter(function(t){return!r.includes(t)}).join("")};t.withoutChars=v;var y=function(t,e){var n=l(t).slice(0),r=l(e).slice(0);return n.filter(function(t){return r.includes(t)}).join("")};t.onlyChars=y;var m=function(t,e,n){return l(t).slice(0).slice(e,void 0===n?void 0:e+n).join("")};t.unicodeSubstr=m;var i=function(t){return"bigint"==typeof t||!Number.isNaN(Number(t))&&Math.floor(Number(t))===t},o=function(t){return"bigint"==typeof t||0<=t&&Number.isSafeInteger(t)};function w(t,e){var n,r=l(e).slice(0);if(!r.length)return t;for(var i=f(t),o=i.length-1,a=0,s=0;0<o;o--,a++){s+=n=r[a%=r.length].codePointAt(0);var u=(n+a+s)%o,h=[i[o],i[u]];i[u]=h[0],i[o]=h[1]}return i.join("")}var A=function(t,e){var n=l(e).slice(0),r="";if("bigint"==typeof t)for(var i=BigInt(n.length);r=n[Number(t%i)]+r,t/=i;);else for(;r=n[t%n.length]+r,t=Math.floor(t/n.length););return r},I=function(t,e){var n=l(t).slice(0),r=l(e).slice(0);return n.map(function(t){return r.indexOf(t)}).reduce(function(t,e){if("bigint"==typeof t)return t*BigInt(r.length)+BigInt(e);var n=t*r.length+e;if(Number.isSafeInteger(n))return n;if("function"==typeof BigInt)return BigInt(t)*BigInt(r.length)+BigInt(e);throw new Error("Unable to decode the provided string, due to lack of support for BigInt numbers in the current environment")},0)},S=function(t,n){return l(t).slice(0).reduce(function(t,e){return n(e)?[].concat(f(t),[""]):[].concat(f(t.slice(0,-1)),[t[t.length-1]+e])},[""])},a=/^\+?[0-9]+$/,s=function(t){return a.test(t)?parseInt(t,10):NaN},u=function(n,r,i){return Array.from({length:Math.ceil(n.length/r)},function(t,e){return i(n.slice(e*r,(e+1)*r))})}}); | ||
//# sourceMappingURL=hashids.min.js.map |
103
package.json
{ | ||
"author": "Ivan Akimov <ivan@barreleye.com> (https://twitter.com/IvanAkimov)", | ||
"author": "hashids.org <npm@invent.life> (https://github.com/hashids)", | ||
"name": "hashids", | ||
"description": "Generate YouTube-like ids from numbers. Use Hashids when you do not want to expose your database ids to the user.", | ||
"version": "1.2.2", | ||
"contributors": [ | ||
{ | ||
"name": "Ivan Akimov", | ||
"email": "ivan@barreleye.com", | ||
"url": "https://twitter.com/IvanAkimov" | ||
}, | ||
{ | ||
"name": "Bazyli Brzóska", | ||
"email": "npm@invent.life", | ||
"url": "https://twitter.com/niieani" | ||
} | ||
], | ||
"version": "2.0.0-prerelease.2", | ||
"homepage": "http://hashids.org/javascript", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/ivanakimov/hashids.js.git" | ||
"url": "https://github.com/niieani/hashids.js.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/ivanakimov/hashids.js/issues" | ||
"url": "https://github.com/niieani/hashids.js/issues" | ||
}, | ||
"main": "dist/hashids", | ||
"module": "dist/hashids-esm", | ||
"main": "dist/hashids.mjs", | ||
"module": "dist/hashids.mjs", | ||
"browser": "dist/hashids.min", | ||
"scripts": { | ||
"precommit": "npm run lint && npm run test", | ||
"lint": "eslint lib tests", | ||
"test": "mocha tests --require @babel/register", | ||
"test-modules": "node --experimental-modules node_modules/mocha/bin/_mocha tests-mjs", | ||
"coverage": "nyc npm test && nyc report --reporter=text-lcov | coveralls", | ||
"build:node": "babel lib/hashids.js --source-maps -o dist/index.js", | ||
"build:modules": "BABEL_MODULES=1 babel lib/hashids.js --source-maps -o dist/hashids.mjs && cp dist/hashids.mjs dist/hashids-esm.js", | ||
"rename:global": "sed -i '' 's/global.hashids/global.Hashids/g' dist/index.js", | ||
"minify": "cd dist && uglifyjs index.js -o hashids.min.js --source-map \"url=hashids.min.js.map\" --compress --mangle", | ||
"build": "npm run test && npm run build:node && npm run build:modules && npm run rename:global && npm run minify", | ||
"clean": "rm -rf coverage .nyc_output npm-debug.log", | ||
"all": "npm run lint && npm run coverage && npm run build && npm run clean" | ||
"lint": "eslint lib/* tests/*", | ||
"prettier:check": "prettier --check lib/* tests*/*", | ||
"prettier:write": "prettier --write lib/* tests*/*", | ||
"test": "jest", | ||
"coverage": "jest --coverage && cat coverage/lcov.info | coveralls", | ||
"build:umd": "babel lib/hashids.ts --source-maps -o dist/hashids.js", | ||
"build:modules": "BABEL_MODULES=1 babel lib/hashids.ts --source-maps -o dist/hashids.mjs", | ||
"minify": "cd dist && uglifyjs hashids.js -o hashids.min.js --source-map \"url=hashids.min.js.map\" --compress --mangle", | ||
"build": "yarn run build:umd && yarn run build:modules && yarn run minify", | ||
"clean": "rm -rf coverage yarn-debug.log", | ||
"all": "yarn run lint && yarn run coverage && yarn run build && yarn run clean", | ||
"semantic-release": "semantic-release" | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "yarn run lint && yarn run test" | ||
} | ||
}, | ||
"browserslist": [ | ||
@@ -39,14 +56,25 @@ "last 2 version", | ||
"devDependencies": { | ||
"@babel/cli": "^7.0.0", | ||
"@babel/core": "^7.0.0", | ||
"@babel/plugin-syntax-dynamic-import": "7.0.0", | ||
"@babel/preset-env": "^7.0.0", | ||
"@babel/register": "^7.0.0", | ||
"babel-eslint": "9.0.0", | ||
"chai": "^4.1.2", | ||
"coveralls": "^3.0.2", | ||
"eslint": "^5.4.0", | ||
"husky": "^0.14.3", | ||
"mocha": "^5.2.0", | ||
"nyc": "^13.0.1", | ||
"@babel/cli": "^7.5.5", | ||
"@babel/core": "^7.5.5", | ||
"@babel/plugin-syntax-bigint": "^7.4.4", | ||
"@babel/preset-env": "^7.5.5", | ||
"@babel/preset-typescript": "^7.3.3", | ||
"@babel/register": "^7.5.5", | ||
"@types/jest": "^24.0.17", | ||
"@types/node": "^12.7.1", | ||
"@typescript-eslint/eslint-plugin": "^2.0.0", | ||
"@typescript-eslint/parser": "^2.0.0", | ||
"babel-eslint": "^10.0.2", | ||
"coveralls": "^3.0.6", | ||
"eslint": "^6.1.0", | ||
"eslint-config-prettier": "^6.0.0", | ||
"eslint-plugin-eslint-comments": "^3.1.2", | ||
"eslint-plugin-import": "^2.18.2", | ||
"eslint-plugin-jest": "^22.15.1", | ||
"expect": "^24.8.0", | ||
"husky": "^3.0.3", | ||
"jest": "^24.8.0", | ||
"prettier": "^1.18.2", | ||
"semantic-release": "^16.0.0-beta.22", | ||
"typescript": "^3.5.3", | ||
"uglify-js": "^3.4.8" | ||
@@ -67,3 +95,16 @@ }, | ||
"decrypt" | ||
] | ||
], | ||
"prettier": { | ||
"semi": false, | ||
"tabWidth": 2, | ||
"singleQuote": true, | ||
"trailingComma": "all", | ||
"arrowParens": "always", | ||
"bracketSpacing": false | ||
}, | ||
"jest": { | ||
"collectCoverageFrom": [ | ||
"lib/**/*.ts" | ||
] | ||
} | ||
} |
187
README.md
@@ -0,4 +1,3 @@ | ||
[![hashids](http://hashids.org/public/img/hashids.gif 'Hashids')](http://hashids.org/) | ||
[![hashids](http://hashids.org/public/img/hashids.gif "Hashids")](http://hashids.org/) | ||
[![Build Status][travis-image]][travis-url] | ||
@@ -13,8 +12,7 @@ [![Coveralls Status][coveralls-image]][coveralls-url] | ||
Getting started | ||
------- | ||
## Getting started | ||
Install Hashids via: | ||
- [node.js](https://nodejs.org): `npm install --save hashids` | ||
- [node.js](https://nodejs.org): `yarn add hashids` | ||
- [bower](http://bower.io/): `bower install hashids` | ||
@@ -25,5 +23,23 @@ - [jam](http://jamjs.org/): `jam install hashids` | ||
Use in the browser (wherever ES5 is supported; 5KB): | ||
Use in ESM-compatible environments (webpack, modern browsers): | ||
```javascript | ||
import Hashids from 'hashids' | ||
const hashids = new Hashids() | ||
console.log(hashids.encode(1)) | ||
``` | ||
Use in Node.js: | ||
```javascript | ||
const Hashids = require('hashids/cjs') | ||
const hashids = new Hashids() | ||
console.log(hashids.encode(1)) | ||
``` | ||
Use in the browser without ESM (wherever ES5 is supported; 5KB): | ||
```javascript | ||
<script type="text/javascript" src="hashids.min.js"></script> | ||
@@ -38,33 +54,27 @@ <script type="text/javascript"> | ||
Use in Node.js: | ||
## Quick example | ||
```javascript | ||
var Hashids = require('hashids'); | ||
var hashids = new Hashids(); | ||
const hashids = new Hashids() | ||
console.log(hashids.encode(1)); | ||
const id = hashids.encode(1, 2, 3) // o2fXhV | ||
const numbers = hashids.decode(id) // [1, 2, 3] | ||
``` | ||
Quick example | ||
------- | ||
## More options | ||
```javascript | ||
var hashids = new Hashids(); | ||
var id = hashids.encode(1, 2, 3); // o2fXhV | ||
var numbers = hashids.decode(id); // [1, 2, 3] | ||
``` | ||
More options | ||
------- | ||
**A few more ways to pass to `encode()`:** | ||
```javascript | ||
var hashids = new Hashids(); | ||
const hashids = new Hashids() | ||
console.log(hashids.encode(1, 2, 3)); // o2fXhV | ||
console.log(hashids.encode([1, 2, 3])); // o2fXhV | ||
console.log(hashids.encode('1', '2', '3')); // o2fXhV | ||
console.log(hashids.encode(['1', '2', '3'])); // o2fXhV | ||
console.log(hashids.encode(1, 2, 3)) // o2fXhV | ||
console.log(hashids.encode([1, 2, 3])) // o2fXhV | ||
// strings containing integers are coerced to numbers: | ||
console.log(hashids.encode('1', '2', '3')) // o2fXhV | ||
console.log(hashids.encode(['1', '2', '3'])) // o2fXhV | ||
// BigInt support: | ||
console.log(hashids.encode([1n, 2n, 3n])) // o2fXhV | ||
// Hex notation BigInt: | ||
console.log(hashids.encode([0x1n, 0x2n, 0x3n])) // o2fXhV | ||
``` | ||
@@ -74,10 +84,10 @@ | ||
Pass a project name to make your ids unique: | ||
Pass a "salt" to make your ids unique (e.g. a project name): | ||
```javascript | ||
var hashids = new Hashids('My Project'); | ||
console.log(hashids.encode(1, 2, 3)); // Z4UrtW | ||
var hashids = new Hashids('My Project') | ||
console.log(hashids.encode(1, 2, 3)) // Z4UrtW | ||
var hashids = new Hashids('My Other Project'); | ||
console.log(hashids.encode(1, 2, 3)); // gPUasb | ||
var hashids = new Hashids('My Other Project') | ||
console.log(hashids.encode(1, 2, 3)) // gPUasb | ||
``` | ||
@@ -87,10 +97,10 @@ | ||
Note that ids are only padded to fit **at least** a certain length. It doesn't mean that your ids will be *exactly* that length. | ||
Note that ids are only padded to fit **at least** a certain length. It doesn't mean that your ids will be _exactly_ that length. | ||
```javascript | ||
var hashids = new Hashids(); // no padding | ||
console.log(hashids.encode(1)); // jR | ||
const hashids = new Hashids() // no padding | ||
console.log(hashids.encode(1)) // jR | ||
var hashids = new Hashids('', 10); // pad to length 10 | ||
console.log(hashids.encode(1)); // VolejRejNm | ||
const hashids = new Hashids('', 10) // pad to length 10 | ||
console.log(hashids.encode(1)) // VolejRejNm | ||
``` | ||
@@ -101,4 +111,4 @@ | ||
```javascript | ||
var hashids = new Hashids('', 0, 'abcdefghijklmnopqrstuvwxyz'); // all lowercase | ||
console.log(hashids.encode(1, 2, 3)); // mdfphx | ||
const hashids = new Hashids('', 0, 'abcdefghijklmnopqrstuvwxyz') // all lowercase | ||
console.log(hashids.encode(1, 2, 3)) // mdfphx | ||
``` | ||
@@ -108,24 +118,41 @@ | ||
Since v2.0 you can even use emojis as the alphabet. | ||
**Encode hex instead of numbers:** | ||
Useful if you want to encode [Mongo](https://www.mongodb.com/)'s ObjectIds. Note that *there is no limit* on how large of a hex number you can pass (it does not have to be Mongo's ObjectId). | ||
Useful if you want to encode numbers like [Mongo](https://www.mongodb.com/)'s ObjectIds. | ||
Note that there is _no_ limit on how large of a hex number you can pass. | ||
```javascript | ||
var hashids = new Hashids(); | ||
var hashids = new Hashids() | ||
var id = hashids.encodeHex('507f1f77bcf86cd799439011'); // y42LW46J9luq3Xq9XMly | ||
var hex = hashids.decodeHex(id); // 507f1f77bcf86cd799439011 | ||
var id = hashids.encodeHex('507f1f77bcf86cd799439011') // y42LW46J9luq3Xq9XMly | ||
var hex = hashids.decodeHex(id) // 507f1f77bcf86cd799439011 | ||
``` | ||
Pitfalls | ||
------- | ||
Please note that this is not the equivalent of: | ||
```javascript | ||
const hashids = new Hashids() | ||
const id = Hashids.encode(BigInt('0x507f1f77bcf86cd799439011')) // y8qpJL3ZgzJ8lWk4GEV | ||
const hex = Hashids.decode(id)[0].toString(16) // 507f1f77bcf86cd799439011 | ||
``` | ||
The difference between the two is that the built-in `encodeHex` will | ||
always result in the same length, even if it contained leading zeros. | ||
For example `hashids.encodeHex('00000000') would encode to`qExOgK7`and decode back to`'00000000'` (length information is preserved). | ||
## Pitfalls | ||
1. When decoding, output is always an array of numbers (even if you encode only one number): | ||
```javascript | ||
var hashids = new Hashids(); | ||
```javascript | ||
const hashids = new Hashids() | ||
var id = hashids.encode(1); | ||
console.log(hashids.decode(id)); // [1] | ||
``` | ||
const id = hashids.encode(1) | ||
console.log(hashids.decode(id)) // [1] | ||
``` | ||
@@ -135,13 +162,12 @@ 2. Encoding negative numbers is not supported. | ||
```javascript | ||
var hashids = new Hashids(); | ||
```javascript | ||
const hashids = new Hashids() | ||
var id = hashids.encode('123a'); | ||
console.log(id === ''); // true | ||
``` | ||
const id = hashids.encode('123a') | ||
console.log(id === '') // true | ||
``` | ||
4. Do not use this library as a security tool and do not encode sensitive data. This is **not** an encryption library. | ||
Randomness | ||
------- | ||
## Randomness | ||
@@ -153,4 +179,4 @@ The primary purpose of Hashids is to obfuscate ids. It's not meant or tested to be used as a security or compression tool. Having said that, this algorithm does try to make these ids random and unpredictable: | ||
```javascript | ||
var hashids = new Hashids(); | ||
console.log(hashids.encode(5, 5, 5)); // A6t1tQ | ||
const hashids = new Hashids() | ||
console.log(hashids.encode(5, 5, 5)) // A6t1tQ | ||
``` | ||
@@ -161,39 +187,42 @@ | ||
```javascript | ||
var hashids = new Hashids(); | ||
const hashids = new Hashids() | ||
console.log(hashids.encode(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); // wpfLh9iwsqt0uyCEFjHM | ||
console.log(hashids.encode(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) // wpfLh9iwsqt0uyCEFjHM | ||
console.log(hashids.encode(1)); // jR | ||
console.log(hashids.encode(2)); // k5 | ||
console.log(hashids.encode(3)); // l5 | ||
console.log(hashids.encode(4)); // mO | ||
console.log(hashids.encode(5)); // nR | ||
console.log(hashids.encode(1)) // jR | ||
console.log(hashids.encode(2)) // k5 | ||
console.log(hashids.encode(3)) // l5 | ||
console.log(hashids.encode(4)) // mO | ||
console.log(hashids.encode(5)) // nR | ||
``` | ||
Curses! #$%@ | ||
------- | ||
## Curses! #\$%@ | ||
This code was written with the intent of placing created ids in visible places, like the URL. Therefore, the algorithm tries to avoid generating most common English curse words by generating ids that never have the following letters next to each other: | ||
c, f, h, i, s, t, u | ||
c, f, h, i, s, t, u | ||
License | ||
------- | ||
## BigInt | ||
MIT License. See the [LICENSE](LICENSE) file. You can use Hashids in open source projects and commercial products. Don't break the Internet. Kthxbye. | ||
If your environment supports `BigInt`, you can use the standard API | ||
to encode and decode them the same way as ordinary numbers. | ||
[travis-url]: https://travis-ci.org/ivanakimov/hashids.js | ||
[travis-image]: https://travis-ci.org/ivanakimov/hashids.js.svg | ||
Trying to decode a `BigInt`-encoded hashid on an unsupported environment will throw an error. | ||
[coveralls-url]: https://coveralls.io/github/ivanakimov/hashids.js | ||
[coveralls-image]: https://coveralls.io/repos/github/ivanakimov/hashids.js/badge.svg | ||
## License | ||
MIT License. See the [LICENSE](LICENSE) file. | ||
You can use Hashids in open source projects and commercial products. | ||
Don't break the Internet. Kthxbye. | ||
[travis-url]: https://travis-ci.org/niieani/hashids.js | ||
[travis-image]: https://travis-ci.org/niieani/hashids.js.svg | ||
[coveralls-url]: https://coveralls.io/github/niieani/hashids.js | ||
[coveralls-image]: https://coveralls.io/repos/github/niieani/hashids.js/badge.svg | ||
[npm-downloads-image]: https://img.shields.io/npm/dm/hashids.svg?style=flat-square | ||
[npm-version-image]: https://img.shields.io/npm/v/hashids.svg | ||
[npm-url]: https://www.npmjs.com/package/hashids | ||
[license-url]: https://github.com/ivanakimov/hashids.js/blob/master/LICENSE | ||
[license-url]: https://github.com/niieani/hashids.js/blob/master/LICENSE | ||
[license-image]: https://img.shields.io/packagist/l/hashids/hashids.svg?style=flat | ||
[chat-url]: https://gitter.im/hashids/hashids?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge | ||
[chat-image]: https://badges.gitter.im/Join%20Chat.svg |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
483925
38
1724
219
24
1
2