nanohash
Version:
Generate 64bits-based numeric ids readable as short strings too!
235 lines (234 loc) • 8.15 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const generate_1 = __importDefault(require("nanoid/generate"));
const fauna = __importStar(require("./fauna"));
exports.fauna = fauna;
const hashtable_1 = require("./hashtable");
function inverseTable(htable) {
return Object.entries(htable).reduce((table, [key, code]) => {
table[code] = key;
return table;
}, {});
}
exports.presets = {
HUMAN_READABLE_REF: {
// Let's you create a short readable folder reference (0/O and 1/I are banned)
alphabet: 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789',
size: 5
},
SHORT_REF: {
// Let's you create a short code similar to youtube (ex: ysX7j1)
alphabet: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
size: 6
}
};
/**
* Creates an instance of nanohash based on size and alphabet needs
* @example
*
* ```javascript
* const nhash = nanohash({ size: 6, alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" })
* ```
*/
class NanoHash {
constructor(options = {}) {
this.size = 6;
this.maxSize = 9;
this.alphabet = exports.presets.SHORT_REF.alphabet;
this.prefix = '1';
/**
* Generates a unique numeric string ID (reversible to code)
*
* @returns {NanoHash.ID}
*
* @example
*
* const code = nhash.generate()
* // output: Xe7ZRY
*/
this.generate = () => {
return this.hash(generate_1.default(this.alphabet, this.size));
};
/**
* Generates n iterations of unique numeric string ID (each reversible to code)
*
* @param {number} [n=10]
* @returns {NanoHash.ID[]}
*
* @example
*
* ```javascript
* const code = nhash.bulk(5)
* // output: [ '1075226254449', '1563743314555', '1015201022261', '1271320203729', '1465116152533' ]
* ```
*/
this.bulk = (n = 10) => {
return Array(n)
.fill(undefined)
.map(this.generate);
};
/**
* Convert a string code to a numeric string ID (reversible)
*
* @param {NanoHash.code} code
* @returns {NanoHash.ID}
*
* @example
*
* ```javascript
* const countryID = nhash.hash("France")
* // output: 1412710231214
* ```
*/
this.hash = (code) => {
if (code.length > this.maxSize)
throw new Error(`Code cannot be longer than ${this.maxSize}`);
let firstNumberAlphabet = '12345678';
return ((firstNumberAlphabet.includes(this.prefix) ? this.prefix : '1') +
`${code}`
.split('')
.map((c) => {
try {
return this.hashtable[c];
}
catch (error) {
throw new Error(`The character: ${c} can't be used`);
}
})
.join(''));
};
/**
* Returns a code from an ID (made from .hash() or .generate())
*
* @param {NanoHash.ID} [id='']
* @returns {NanoHash.code}
*
* @example
*
* ```javascript
* const countryName = nhash.dehash("1412710231214")
* // output: France
* ```
*/
this.dehash = (id = '') => {
return `${id}`
.slice(1)
.match(/.{1,2}/g)
.map((c) => {
try {
return this.codetable[c];
}
catch (error) {
throw new Error(`The code: ${c} doesn't exist`);
}
})
.join('');
};
/**
* Returns a code from a Fauna ID (generated by Fauna)
*
* @param {NanoHash.FaunaID} faunaId
* @returns {NanoHash.FaunaCode}
*
* @example
*
* ```javascript
* const code = nhash.faunaCode("258296287713034771")
* // output: эh3ъmöýRt
* ```
*/
this.faunaCode = (faunaId) => {
let id = `${faunaId}`;
let firstCharacter = '';
let isOdd = id.length % 2 > 0;
if (isOdd) {
firstCharacter = id.slice(0, 1);
try {
firstCharacter = hashtable_1.reversedNumbers[firstCharacter];
}
catch (error) {
console.error(`Couldn't find ${firstCharacter} in reversedNumbers hash`);
}
id = id.slice(1);
}
return (firstCharacter +
id
.match(/.{1,2}/g)
.map((c) => {
try {
return this.codetable99[c];
}
catch (error) {
throw new Error(`The code: ${c} doesn't exist`);
}
})
.join(''));
};
/**
* Returns a Fauna ID from a code (from .faunaCode())
*
* @param {NanoHash.FaunaCode} faunaCode
* @returns {NanoHash.FaunaID}
*
* @example
*
* ```javascript
* const faunaID = nhash.faunaId("эh3ъmöýRt")
* // output: 258296287713034771
* ```
*/
this.faunaId = (faunaCode) => {
let code = `${faunaCode}`;
let firstCharacter = '';
let hasSpecialFirstCharacter = code.startsWith('_');
if (hasSpecialFirstCharacter) {
firstCharacter = code.slice(0, 2);
const reversedNumbersCodeTable = inverseTable(hashtable_1.reversedNumbers);
try {
firstCharacter = reversedNumbersCodeTable[firstCharacter];
}
catch (error) {
console.error(`Couldn't find ${firstCharacter} in reversedNumbers hash`);
}
code = code.slice(2);
}
return (firstCharacter +
code
.split('')
.map((c) => {
try {
return hashtable_1.hashtable99[c];
}
catch (error) {
throw new Error(`The character: ${c} can't be used`);
}
})
.join(''));
};
let { size = exports.presets.SHORT_REF.size, maxSize = 9, hashtable = {}, alphabet = exports.presets.SHORT_REF.alphabet } = options;
if (maxSize > 9) {
this.maxSize = 9;
}
if (size > maxSize) {
throw new Error(`Size cannot be higher than ${maxSize}`);
}
this.size = size;
this.alphabet = alphabet;
this.hashtable = Object.assign(hashtable_1.hashtable, hashtable || {});
this.codetable = inverseTable(this.hashtable);
this.hashtable99 = hashtable_1.hashtable99;
this.codetable99 = inverseTable(this.hashtable99);
}
}
exports.NanoHash = NanoHash;
exports.nanohash = (...args) => new NanoHash(...args);