UNPKG

google-big-query-labels

Version:

Encode strings so they are compatible with google big query labels.

94 lines (70 loc) 2.37 kB
const bigInt = require('big-integer'); const prefix = 'l'; const labelAlphabet = '_-0123456789abcdefghijklmnopqrstuvwxyz'; const base64Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; const base64UrlAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; module.exports = { prefix, encode, decode, labelAlphabet, encodeBase64, decodeBase64, encodeBase64Url, decodeBase64Url }; function encode(toEncode, originCharacters) { const bigIntArg = toEncode.split('').reduce((memo, char) => { const index = originCharacters.indexOf(char); if (index === -1) { throw new TypeError(`Character ${char} is not in character set ${originCharacters}`); } return memo + `<${index}>`; // Prefixing with 1 to handle the case that the encoded string begins with // the first character in the provided alphabet e.g. A in base64Url. }, '1'); let encodedVal; try { encodedVal = bigInt(bigIntArg, originCharacters.length); } catch (e) { throw new TypeError(`${toEncode} is not a valid base ${base} string.`); } let str = ''; do { str = labelAlphabet.substr(encodedVal.mod(labelAlphabet.length).valueOf(), 1) + str; encodedVal = encodedVal.divide(labelAlphabet.length); } while (encodedVal.greater(0)); return prefix + str; } function decode(encoded, originCharacters) { let decodedVal = bigInt(0); const str = encoded.slice(1, encoded.length); const len = str.length; for (let pos = 0; pos < len; pos += 1) { const ch = str.substr(pos, 1); const encPos = labelAlphabet.indexOf(ch); if (encPos < 0) { throw new Error('Invalid encoded data'); } decodedVal = decodedVal.add(encPos); if (pos < len - 1) { decodedVal = decodedVal.multiply(labelAlphabet.length); } } const chars = decodedVal.toArray(originCharacters.length).value.map(digit => originCharacters[digit]); // Again, handles the leading 0 char index case. chars.shift(); return chars.join(''); } function encodeBase64(toEncode) { return encode(toEncode, base64Alphabet); } function decodeBase64(encoded) { return decode(encoded, base64Alphabet); } function encodeBase64Url(toEncode) { return encode(toEncode, base64UrlAlphabet); } function decodeBase64Url(toDecode) { return decode(toDecode, base64UrlAlphabet); }