Skip to content

Commit 99c8aaa

Browse files
authored
chore: replace multibase with multiformats (#20)
Swaps the multibase library for multiformats as it's much smaller. The supported encodings are the same so it should be a non-breaking change.
1 parent 744af83 commit 99c8aaa

File tree

10 files changed

+132
-68
lines changed

10 files changed

+132
-68
lines changed

.aegir.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/** @type {import('aegir').PartialOptions} */
44
module.exports = {
55
build: {
6-
bundlesizeMax: '11KB',
6+
bundlesizeMax: '7KB',
77
config: {
88
entryPoints: ['index.js']
99
}

.github/workflows/main.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
strategy:
2727
matrix:
2828
os: [windows-latest, ubuntu-latest, macos-latest]
29-
node: [12, 14, 15]
29+
node: [12, 14, 16]
3030
fail-fast: true
3131
steps:
3232
- uses: actions/checkout@v2
@@ -43,8 +43,7 @@ jobs:
4343
- uses: actions/checkout@v2
4444
- uses: microsoft/playwright-github-action@v1
4545
- run: npm install
46-
- run: npx aegir test -t browser -t webworker --bail --cov
47-
- uses: codecov/codecov-action@v1
46+
- run: npx aegir test -t browser -t webworker --bail
4847
test-firefox:
4948
needs: check
5049
runs-on: ubuntu-latest

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ console.info(equals(a, a)) // true
8585

8686
Returns a new `Uint8Array` created from the passed string and interpreted as the passed encoding.
8787

88-
Supports `utf8` and any of the [multiformats encodings](https://www.npmjs.com/package/multibase#supported-encodings-see-srcconstantsjs).
88+
Supports `utf8` and any of the [multibase encodings](https://github.com/multiformats/multibase/blob/master/multibase.csv) as implemented by the [multiformats module](https://www.npmjs.com/package/multiformats).
8989

9090
#### Example
9191

@@ -102,7 +102,7 @@ console.info(fromString('01234', 'ascii')) // Uint8Array[48, 49 ...
102102

103103
Returns a string created from the passed `Uint8Array` in the passed encoding.
104104

105-
Supports `utf8` and any of the [multiformats encodings](https://www.npmjs.com/package/multibase#supported-encodings-see-srcconstantsjs).
105+
Supports `utf8` and any of the [multibase encodings](https://github.com/multiformats/multibase/blob/master/multibase.csv) as implemented by the [multiformats module](https://www.npmjs.com/package/multiformats).
106106

107107
#### Example
108108

from-string.js

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,15 @@
11
'use strict'
22

3-
const { encoding: getCodec } = require('multibase')
4-
const utf8Encoder = new TextEncoder()
3+
const bases = require('./util/bases')
54

65
/**
7-
* @typedef {import('multibase/src/types').BaseName | 'utf8' | 'utf-8' | 'ascii' | undefined} SupportedEncodings
6+
* @typedef {import('./util/bases').SupportedEncodings} SupportedEncodings
87
*/
98

10-
/**
11-
* Interprets each character in a string as a byte and
12-
* returns a Uint8Array of those bytes.
13-
*
14-
* @param {string} string - The string to turn into an array
15-
*/
16-
function asciiStringToUint8Array (string) {
17-
const array = new Uint8Array(string.length)
18-
19-
for (let i = 0; i < string.length; i++) {
20-
array[i] = string.charCodeAt(i)
21-
}
22-
23-
return array
24-
}
25-
269
/**
2710
* Create a `Uint8Array` from the passed string
2811
*
29-
* Supports `utf8`, `utf-8` and any encoding supported by the multibase module.
12+
* Supports `utf8`, `utf-8`, `hex`, and any encoding supported by the multiformats module.
3013
*
3114
* Also `ascii` which is similar to node's 'binary' encoding.
3215
*
@@ -35,15 +18,14 @@ function asciiStringToUint8Array (string) {
3518
* @returns {Uint8Array}
3619
*/
3720
function fromString (string, encoding = 'utf8') {
38-
if (encoding === 'utf8' || encoding === 'utf-8') {
39-
return utf8Encoder.encode(string)
40-
}
21+
const base = bases[encoding]
4122

42-
if (encoding === 'ascii') {
43-
return asciiStringToUint8Array(string)
23+
if (!base) {
24+
throw new Error(`Unsupported encoding "${encoding}"`)
4425
}
4526

46-
return getCodec(encoding).decode(string)
27+
// add multibase prefix
28+
return base.decoder.decode(`${base.prefix}${string}`)
4729
}
4830

4931
module.exports = fromString

package.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
"xor.js",
2828
"dist/*.ts",
2929
"dist/*.map",
30-
"dist/*.js"
30+
"dist/*.js",
31+
"util/*.js"
3132
],
3233
"repository": {
3334
"type": "git",
@@ -36,18 +37,19 @@
3637
"scripts": {
3738
"prepare": "aegir build --no-bundle",
3839
"test": "aegir test",
39-
"lint": "aegir lint",
40+
"lint": "aegir ts -p check && aegir lint",
4041
"release": "aegir release",
4142
"release-minor": "aegir release --type minor",
4243
"release-major": "aegir release --type major",
4344
"build": "aegir build"
4445
},
4546
"license": "MIT",
4647
"dependencies": {
47-
"multibase": "^4.0.1"
48+
"multiformats": "^9.4.1"
4849
},
4950
"devDependencies": {
50-
"aegir": "^33.1.0"
51+
"aegir": "^34.0.2",
52+
"util": "^0.12.4"
5153
},
5254
"eslintConfig": {
5355
"extends": "ipfs",

test/from-string.spec.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33

44
const { expect } = require('aegir/utils/chai')
55
const fromString = require('../from-string')
6+
const toString = require('../to-string')
7+
const bases = require('../util/bases')
8+
9+
/** @type {import('../util/bases').SupportedEncodings[]} */
10+
// @ts-ignore Object.keys returns a string[]
11+
const supportedBases = Object.keys(bases)
612

713
describe('Uint8Array fromString', () => {
814
it('creates a Uint8Array from a string', () => {
@@ -12,14 +18,16 @@ describe('Uint8Array fromString', () => {
1218
expect(fromString(str)).to.deep.equal(arr)
1319
})
1420

15-
it('creates a Uint8Array from a base16 string', () => {
16-
const str = '00010203aabbcc'
17-
const arr = Uint8Array.from([0, 1, 2, 3, 170, 187, 204])
21+
supportedBases.forEach(base => {
22+
it(`creates a Uint8Array from a ${base} string`, () => {
23+
const arr = Uint8Array.from([0, 1, 2, 3])
24+
const str = toString(arr, base)
1825

19-
expect(fromString(str, 'base16')).to.deep.equal(arr)
26+
expect(fromString(str, base)).to.deep.equal(arr)
27+
})
2028
})
2129

22-
it('creates a Uint8Array from a base64 string', () => {
30+
it('creates a Uint8Array from a base64 string with non-printable utf8 characters', () => {
2331
const str = 'AAECA6q7zA'
2432
const arr = Uint8Array.from([0, 1, 2, 3, 170, 187, 204])
2533

test/to-string.spec.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,28 @@ describe('Uint8Array toString', () => {
1212
expect(toString(arr)).to.deep.equal(str)
1313
})
1414

15-
it('creates a hex string from a Uint8Array', () => {
15+
it('creates a hex string from a Uint8Array with non-printable utf8 characters', () => {
1616
const str = '00010203aabbcc'
1717
const arr = Uint8Array.from([0, 1, 2, 3, 170, 187, 204])
1818

1919
expect(toString(arr, 'base16')).to.deep.equal(str)
2020
})
2121

22-
it('creates a base64 string from a Uint8Array', () => {
22+
it('creates a base32 string from a Uint8Array with non-printable utf8 characters', () => {
23+
const str = 'aaaqea5kxpga'
24+
const arr = Uint8Array.from([0, 1, 2, 3, 170, 187, 204])
25+
26+
expect(toString(arr, 'base32')).to.deep.equal(str)
27+
})
28+
29+
it('creates a base36 string from a Uint8Array with non-printable utf8 characters', () => {
30+
const str = '0e52zorf0'
31+
const arr = Uint8Array.from([0, 1, 2, 3, 170, 187, 204])
32+
33+
expect(toString(arr, 'base36')).to.deep.equal(str)
34+
})
35+
36+
it('creates a base64 string from a Uint8Array with non-printable utf8 characters', () => {
2337
const str = 'AAECA6q7zA'
2438
const arr = Uint8Array.from([0, 1, 2, 3, 170, 187, 204])
2539

to-string.js

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,11 @@
11
'use strict'
22

3-
const { encoding: getCodec } = require('multibase')
4-
const utf8Decoder = new TextDecoder('utf8')
3+
const bases = require('./util/bases')
54

65
/**
7-
* @typedef {import('multibase/src/types').BaseName | 'utf8' | 'utf-8' | 'ascii' | undefined} SupportedEncodings
6+
* @typedef {import('./util/bases').SupportedEncodings} SupportedEncodings
87
*/
98

10-
/**
11-
* Turns a Uint8Array of bytes into a string with each
12-
* character being the char code of the corresponding byte
13-
*
14-
* @param {Uint8Array} array - The array to turn into a string
15-
*/
16-
function uint8ArrayToAsciiString (array) {
17-
let string = ''
18-
19-
for (let i = 0; i < array.length; i++) {
20-
string += String.fromCharCode(array[i])
21-
}
22-
return string
23-
}
24-
259
/**
2610
* Turns a `Uint8Array` into a string.
2711
*
@@ -34,15 +18,14 @@ function uint8ArrayToAsciiString (array) {
3418
* @returns {string}
3519
*/
3620
function toString (array, encoding = 'utf8') {
37-
if (encoding === 'utf8' || encoding === 'utf-8') {
38-
return utf8Decoder.decode(array)
39-
}
21+
const base = bases[encoding]
4022

41-
if (encoding === 'ascii') {
42-
return uint8ArrayToAsciiString(array)
23+
if (!base) {
24+
throw new Error(`Unsupported encoding "${encoding}"`)
4325
}
4426

45-
return getCodec(encoding).encode(array)
27+
// strip multibase prefix
28+
return base.encoder.encode(array).substring(1)
4629
}
4730

4831
module.exports = toString

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
{
2-
"extends": "./node_modules/aegir/src/config/tsconfig.aegir.json",
2+
"extends": "aegir/src/config/tsconfig.aegir.json",
33
"compilerOptions": {
44
"outDir": "dist"
55
},
66
"include": [
77
"test",
8+
"util",
89
"*.js",
910
".aegir.js"
1011
]

util/bases.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
'use strict'
2+
3+
const { bases } = require('multiformats/basics')
4+
5+
/**
6+
* @typedef {import('multiformats/bases/interface').MultibaseCodec<any>} MultibaseCodec
7+
*/
8+
9+
/**
10+
* @param {string} name
11+
* @param {string} prefix
12+
* @param {(buf: Uint8Array) => string} encode
13+
* @param {(str: string) => Uint8Array} decode
14+
* @returns {MultibaseCodec}
15+
*/
16+
function createCodec (name, prefix, encode, decode) {
17+
return {
18+
name,
19+
prefix,
20+
encoder: {
21+
name,
22+
prefix,
23+
encode
24+
},
25+
decoder: {
26+
decode
27+
}
28+
}
29+
}
30+
31+
const string = createCodec('utf8', 'u', (buf) => {
32+
const decoder = new TextDecoder('utf8')
33+
return 'u' + decoder.decode(buf)
34+
}, (str) => {
35+
const encoder = new TextEncoder()
36+
return encoder.encode(str.substring(1))
37+
})
38+
39+
const ascii = createCodec('ascii', 'a', (buf) => {
40+
let string = 'a'
41+
42+
for (let i = 0; i < buf.length; i++) {
43+
string += String.fromCharCode(buf[i])
44+
}
45+
return string
46+
}, (str) => {
47+
str = str.substring(1)
48+
const buf = new Uint8Array(str.length)
49+
50+
for (let i = 0; i < str.length; i++) {
51+
buf[i] = str.charCodeAt(i)
52+
}
53+
54+
return buf
55+
})
56+
57+
/**
58+
* @typedef {'utf8' | 'utf-8' | 'hex' | 'latin1' | 'ascii' | 'binary' | keyof bases } SupportedEncodings
59+
*/
60+
61+
/**
62+
* @type {Record<SupportedEncodings, MultibaseCodec>}
63+
*/
64+
const BASES = {
65+
'utf8': string,
66+
'utf-8': string,
67+
'hex': bases.base16,
68+
'latin1': ascii,
69+
'ascii': ascii,
70+
'binary': ascii,
71+
72+
...bases
73+
}
74+
75+
module.exports = BASES

0 commit comments

Comments
 (0)