Skip to content

Commit

Permalink
feat: add base256emoji
Browse files Browse the repository at this point in the history
  • Loading branch information
rvagg committed Jun 8, 2022
1 parent 712c1c4 commit be1313d
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 26 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ import the ones you need yourself.
`base64`, `base64pad`, `base64url`, `base64urlpad` | `multiformats/bases/base64` | [multiformats/js-multiformats](https://github.com/multiformats/js-multiformats/tree/master/bases) |
`base58btc`, `base58flick4` | `multiformats/bases/base58` | [multiformats/js-multiformats](https://github.com/multiformats/js-multiformats/tree/master/bases) |

Other (less useful) bases implemented in [multiformats/js-multiformats](https://github.com/multiformats/js-multiformats/tree/master/bases) include: `base2`, `base8`, `base10`, `base36` and `base256emoji`.

### Multihash hashers

| hashes | import | repo |
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@
"./bases/base64": {
"import": "./src/bases/base64.js"
},
"./bases/base256emoji": {
"import": "./src/bases/base256emoji.js"
},
"./hashes/hasher": {
"import": "./src/hashes/hasher.js"
},
Expand Down
14 changes: 12 additions & 2 deletions src/bases/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ class Decoder {
constructor (name, prefix, baseDecode) {
this.name = name
this.prefix = prefix
/* c8 ignore next 3 */
if (prefix.codePointAt(0) === undefined) {
throw new Error('Invalid prefix character')
}
/** @private */
this.prefixCodePoint = /** @type {number} */ (prefix.codePointAt(0))
this.baseDecode = baseDecode
}

Expand All @@ -92,8 +98,12 @@ class Decoder {
*/
decode (text) {
if (typeof text === 'string') {
switch (text[0]) {
case this.prefix: {
switch (text.codePointAt(0)) {
case this.prefixCodePoint: {
if (this.prefixCodePoint > 255) {
// special case for base256emoji, slow and hacky
return this.baseDecode(Array.from(text).slice(1).join(''))
}
return this.baseDecode(text.slice(1))
}
default: {
Expand Down
39 changes: 39 additions & 0 deletions src/bases/base256emoji.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { from } from './base.js'

const alphabet = '🚀 🪐 ☄ 🛰 🌌 🌑 🌒 🌓 🌔 🌕 🌖 🌗 🌘 🌍 🌏 🌎 ☉ ☀ 💻 🖥 💾 💿 😂 ❤ 😍 🤣 😊 🙏 💕 😭 😘 👍 😅 👏 😁 🔥 🥰 💔 💖 💙 😢 🤔 😆 🙄 💪 😉 ☺ 👌 🤗 💜 😔 😎 😇 🌹 🤦 🎉 💞 ✌ ✨ 🤷 😱 😌 🌸 🙌 😋 💗 💚 😏 💛 🙂 💓 🤩 😄 😀 🖤 😃 💯 🙈 👇 🎶 😒 🤭 ❣ 😜 💋 👀 😪 😑 💥 🙋 😞 😩 😡 🤪 👊 🥳 😥 🤤 👉 💃 😳 ✋ 😚 😝 😴 🌟 😬 🙃 🍀 🌷 😻 😓 ⭐ ✅ 🥺 🌈 😈 🤘 💦 ✔ 😣 🏃 💐 ☹ 🎊 💘 😠 ☝ 😕 🌺 🎂 🌻 😐 🖕 💝 🙊 😹 🗣 💫 💀 👑 🎵 🤞 😛 🔴 😤 🌼 😫 ⚽ 🤙 ☕ 🏆 🤫 👈 😮 🙆 🍻 🍃 🐶 💁 😲 🌿 🧡 🎁 ⚡ 🌞 🎈 ❌ ✊ 👋 😰 🤨 😶 🤝 🚶 💰 🍓 💢 🤟 🙁 🚨 💨 🤬 ✈ 🎀 🍺 🤓 😙 💟 🌱 😖 👶 🥴 ▶ ➡ ❓ 💎 💸 ⬇ 😨 🌚 🦋 😷 🕺 ⚠ 🙅 😟 😵 👎 🤲 🤠 🤧 📌 🔵 💅 🧐 🐾 🍒 😗 🤑 🌊 🤯 🐷 ☎ 💧 😯 💆 👆 🎤 🙇 🍑 ❄ 🌴 💣 🐸 💌 📍 🥀 🤢 👅 💡 💩 👐 📸 👻 🤐 🤮 🎼 🥵 🚩 🍎 🍊 👼 💍 📣 🥂'.split(' ')
const alphabetBytesToChars = /** @type {string[]} */ (alphabet.reduce((p, c, i) => { p[i] = c; return p }, /** @type {string[]} */([])))
const alphabetCharsToBytes = /** @type {number[]} */ (alphabet.reduce((p, c, i) => { p[/** @type {number} */ (c.codePointAt(0))] = i; return p }, /** @type {number[]} */([])))

/**
* @param {Uint8Array} data
* @returns {string}
*/
function encode (data) {
return data.reduce((p, c) => {
p += alphabetBytesToChars[c]
return p
}, '')
}

/**
* @param {string} str
* @returns {Uint8Array}
*/
function decode (str) {
const byts = []
for (const char of str) {
const byt = alphabetCharsToBytes[/** @type {number} */ (char.codePointAt(0))]
if (byt === undefined) {
throw new Error(`Non-base256emoji character: ${char}`)
}
byts.push(byt)
}
return new Uint8Array(byts)
}

export const base256emoji = from({
prefix: '🚀',
name: 'base256emoji',
encode,
decode
})
36 changes: 13 additions & 23 deletions test/test-multibase-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { bases } from 'multiformats/basics'
import { fromString } from '../src/bytes.js'
import chai from 'chai'
import chaiAsPromised from 'chai-as-promised'
import { base256emoji } from '../src/bases/base256emoji.js'

bases.base256emoji = base256emoji

chai.use(chaiAsPromised)
const { assert } = chai
Expand Down Expand Up @@ -35,7 +38,8 @@ const encoded = [
['base64', 'mRGVjZW50cmFsaXplIGV2ZXJ5dGhpbmchIQ'],
['base64pad', 'MRGVjZW50cmFsaXplIGV2ZXJ5dGhpbmchIQ=='],
['base64url', 'uRGVjZW50cmFsaXplIGV2ZXJ5dGhpbmchIQ'],
['base64urlpad', 'URGVjZW50cmFsaXplIGV2ZXJ5dGhpbmchIQ==']
['base64urlpad', 'URGVjZW50cmFsaXplIGV2ZXJ5dGhpbmchIQ=='],
['base256emoji', '🚀💛✋💃✋😻😈🥺🤤🍀🌟💐✋😅✋💦✋🥺🏃😈😴🌟😻😝👏👏']
]
},
{
Expand Down Expand Up @@ -63,7 +67,8 @@ const encoded = [
['base64', 'meWVzIG1hbmkgIQ'],
['base64pad', 'MeWVzIG1hbmkgIQ=='],
['base64url', 'ueWVzIG1hbmkgIQ'],
['base64urlpad', 'UeWVzIG1hbmkgIQ==']
['base64urlpad', 'UeWVzIG1hbmkgIQ=='],
['base256emoji', '🚀🏃✋🌈😅🌷🤤😻🌟😅👏']
]
},
{
Expand Down Expand Up @@ -91,7 +96,8 @@ const encoded = [
['base64', 'maGVsbG8gd29ybGQ'],
['base64pad', 'MaGVsbG8gd29ybGQ='],
['base64url', 'uaGVsbG8gd29ybGQ'],
['base64urlpad', 'UaGVsbG8gd29ybGQ=']
['base64urlpad', 'UaGVsbG8gd29ybGQ='],
['base256emoji', '🚀😴✋🍀🍀😓😅✔😓🥺🍀😳']
]
},
{
Expand Down Expand Up @@ -119,7 +125,8 @@ const encoded = [
['base64', 'mAHllcyBtYW5pICE'],
['base64pad', 'MAHllcyBtYW5pICE='],
['base64url', 'uAHllcyBtYW5pICE'],
['base64urlpad', 'UAHllcyBtYW5pICE=']
['base64urlpad', 'UAHllcyBtYW5pICE='],
['base256emoji', '🚀🚀🏃✋🌈😅🌷🤤😻🌟😅👏']
]
},
{
Expand Down Expand Up @@ -147,24 +154,8 @@ const encoded = [
['base64', 'mAAB5ZXMgbWFuaSAh'],
['base64pad', 'MAAB5ZXMgbWFuaSAh'],
['base64url', 'uAAB5ZXMgbWFuaSAh'],
['base64urlpad', 'UAAB5ZXMgbWFuaSAh']
]
},
{
input: 'hello world',
tests: [
['base16', 'f68656c6c6f20776f726c64'],
['base16upper', 'F68656C6C6F20776F726C64'],
['base32', 'bnbswy3dpeb3w64tmmq'],
['base32upper', 'BNBSWY3DPEB3W64TMMQ'],
['base32hex', 'vd1imor3f41rmusjccg'],
['base32hexupper', 'VD1IMOR3F41RMUSJCCG'],
['base32pad', 'cnbswy3dpeb3w64tmmq======'],
['base32padupper', 'CNBSWY3DPEB3W64TMMQ======'],
['base32hexpad', 'td1imor3f41rmusjccg======'],
['base32hexpadupper', 'TD1IMOR3F41RMUSJCCG======'],
['base36', 'kfuvrsivvnfrbjwajo'],
['base36upper', 'KFUVRSIVVNFRBJWAJO']
['base64urlpad', 'UAAB5ZXMgbWFuaSAh'],
['base256emoji', '🚀🚀🚀🏃✋🌈😅🌷🤤😻🌟😅👏']
]
}
]
Expand Down Expand Up @@ -196,7 +187,6 @@ describe('spec test', () => {
return this.skip()
}

console.info('expect', `Non-${base.name} character`)
assert.throws(() => base.decode(base.prefix + '^!@$%!#$%@#y'), `Non-${base.name} character`)
})
}
Expand Down
2 changes: 1 addition & 1 deletion test/test-traversal.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ describe('traversal', () => {
/** @type {[]} */
const links = []
const value = createNode(fromString('test'), links)
const block = await main.encode({ value: value, codec, hasher })
const block = await main.encode({ value, codec, hasher })
const cid = block.cid
const expectedCallArray = [cid.toString()]
/** @type {string[]} */
Expand Down

0 comments on commit be1313d

Please sign in to comment.