Skip to content
This repository has been archived by the owner on Aug 24, 2021. It is now read-only.

Commit

Permalink
fix: return Uint8Arrays (#63)
Browse files Browse the repository at this point in the history
Return `Uint8Array`s instead of node `Buffer`s.

BREAKING CHANGE:

- node `Buffer`s are not returned any more, only `Uint8Array`s
  • Loading branch information
achingbrain authored Jul 31, 2020
1 parent 47dfd56 commit 5e38957
Show file tree
Hide file tree
Showing 11 changed files with 88 additions and 82 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
},
"dependencies": {
"base-x": "^3.0.8",
"buffer": "^5.5.0",
"web-encoding": "^1.0.2"
},
"devDependencies": {
Expand Down
5 changes: 3 additions & 2 deletions src/base.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @ts-check
'use strict'
const { Buffer } = require('buffer')

const { encodeText } = require('./util')

/**
* @typedef {Object} Codec
Expand All @@ -20,7 +21,7 @@ class Base {
constructor (name, code, implementation, alphabet) {
this.name = name
this.code = code
this.codeBuf = Buffer.from(this.code)
this.codeBuf = encodeText(this.code)
this.alphabet = alphabet
this.engine = implementation(alphabet)
}
Expand Down
26 changes: 11 additions & 15 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,60 +6,56 @@
*/
'use strict'

const { Buffer } = require('buffer')
const constants = require('./constants')
const { decodeText, asBuffer } = require('./util')
const { encodeText, decodeText, concat } = require('./util')

/** @typedef {import("./base")} Base */

/**
* Create a new buffer with the multibase varint+code.
* Create a new Uint8Array with the multibase varint+code.
*
* @param {string|number} nameOrCode - The multibase name or code number.
* @param {Uint8Array} buf - The data to be prefixed with multibase.
* @returns {Buffer}
* @returns {Uint8Array}
* @throws {Error} Will throw if the encoding is not supported
*/
function multibase (nameOrCode, buf) {
if (!buf) {
throw new Error('requires an encoded buffer')
throw new Error('requires an encoded Uint8Array')
}
const { name, codeBuf } = encoding(nameOrCode)
validEncode(name, buf)

const buffer = Buffer.alloc(codeBuf.length + buf.length)
buffer.set(codeBuf, 0)
buffer.set(buf, codeBuf.length)

return buffer
return concat([codeBuf, buf], codeBuf.length + buf.length)
}

/**
* Encode data with the specified base and add the multibase prefix.
*
* @param {string|number} nameOrCode - The multibase name or code number.
* @param {Uint8Array} buf - The data to be encoded.
* @returns {Buffer}
* @returns {Uint8Array}
* @throws {Error} Will throw if the encoding is not supported
*
*/
function encode (nameOrCode, buf) {
const enc = encoding(nameOrCode)
const data = encodeText(enc.encode(buf))

return Buffer.concat([enc.codeBuf, Buffer.from(enc.encode(buf))])
return concat([enc.codeBuf, data], enc.codeBuf.length + data.length)
}

/**
* Takes a Uint8Array or string encoded with multibase header, decodes it and
* returns the decoded buffer
*
* @param {Uint8Array|string} data
* @returns {Buffer}
* @returns {Uint8Array}
* @throws {Error} Will throw if the encoding is not supported
*
*/
function decode (data) {
if (ArrayBuffer.isView(data)) {
if (data instanceof Uint8Array) {
data = decodeText(data)
}
const prefix = data[0]
Expand All @@ -69,7 +65,7 @@ function decode (data) {
data = data.toLowerCase()
}
const enc = encoding(data[0])
return asBuffer(enc.decode(data.substring(1)))
return enc.decode(data.substring(1))
}

/**
Expand Down
23 changes: 17 additions & 6 deletions src/util.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// @ts-check
'use strict'

const { Buffer } = require('buffer')
const { TextEncoder, TextDecoder } = require('web-encoding')

const textDecoder = new TextDecoder()
Expand All @@ -19,10 +18,22 @@ const textEncoder = new TextEncoder()
const encodeText = (text) => textEncoder.encode(text)

/**
* @param {ArrayBufferView} bytes
* @returns {Buffer}
* Returns a new Uint8Array created by concatenating the passed Arrays
*
* @param {Array<ArrayLike<Number>>} arrs
* @param {Number} length
* @returns {Uint8Array}
*/
const asBuffer = ({ buffer, byteLength, byteOffset }) =>
Buffer.from(buffer, byteOffset, byteLength)
function concat (arrs, length) {
const output = new Uint8Array(length)
let offset = 0

for (const arr of arrs) {
output.set(arr, offset)
offset += arr.length
}

return output
}

module.exports = { decodeText, encodeText, asBuffer }
module.exports = { decodeText, encodeText, concat }
36 changes: 17 additions & 19 deletions test/multibase.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@
'use strict'

const { expect } = require('aegir/utils/chai')
const { Buffer } = require('buffer')
const { encodeText } = require('../src/util')
const { encodeText, decodeText } = require('../src/util')
const multibase = require('../src')
const constants = require('../src/constants.js')

const unsupportedBases = []

const supportedBases = [

['base16', Buffer.from([0x01]).toString(), 'f01'],
['base16', Buffer.from([15]).toString(), 'f0f'],
['base16', decodeText(Uint8Array.from([0x01])), 'f01'],
['base16', decodeText(Uint8Array.from([15])), 'f0f'],
['base16', 'f', 'f66'],
['base16', 'fo', 'f666f'],
['base16', 'foo', 'f666f6f'],
Expand Down Expand Up @@ -85,7 +84,6 @@ const supportedBases = [
]

const they = (label, def) => {
it(`${label} (Buffer)`, def.bind(null, Buffer.from))
it(`${label} (Uint8Array)`, def.bind(null, encodeText))
}

Expand Down Expand Up @@ -120,27 +118,27 @@ describe('multibase', () => {
const output = elements[2]
const base = constants.names[name]
describe(name, () => {
they('adds multibase code to valid encoded buffer, by name', (encode) => {
they('adds multibase code to valid encoded Uint8Array, by name', (encode) => {
if (typeof input === 'string') {
const buf = encode(input)
const encodedBuf = encode(base.encode(buf))
const multibasedBuf = multibase(base.name, encodedBuf)
expect(multibasedBuf.toString()).to.equal(output)
expect(decodeText(multibasedBuf)).to.equal(output)
} else {
const encodedBuf = encode(base.encode(input))
const multibasedBuf = multibase(base.name, encodedBuf)
expect(multibasedBuf.toString()).to.equal(output)
expect(decodeText(multibasedBuf)).to.equal(output)
}
})

they('adds multibase code to valid encoded buffer, by code', (encode) => {
they('adds multibase code to valid encoded Uint8Array, by code', (encode) => {
const buf = encode(input)
const encodedBuf = encode(base.encode(buf))
const multibasedBuf = multibase(base.code, encodedBuf)
expect(multibasedBuf.toString()).to.equal(output)
expect(decodeText(multibasedBuf)).to.equal(output)
})

they('fails to add multibase code to invalid encoded buffer', (encode) => {
they('fails to add multibase code to invalid encoded Uint8Array', (encode) => {
const nonEncodedBuf = encode('^!@$%!#$%@#y')
expect(() => {
multibase(base.name, nonEncodedBuf)
Expand All @@ -152,7 +150,7 @@ describe('multibase', () => {
expect(name).to.equal(base.name)
})

they('isEncoded buffer', (encode) => {
they('isEncoded Uint8Array', (encode) => {
const multibasedStr = encode(output)
const name = multibase.isEncoded(multibasedStr)
expect(name).to.equal(base.name)
Expand All @@ -167,10 +165,10 @@ describe('multibase.encode ', () => {
const input = elements[1]
const output = elements[2]
describe(name, () => {
they('encodes a buffer', (encode) => {
they('encodes a Uint8Array', (encode) => {
const buf = encode(input)
const multibasedBuf = multibase.encode(name, buf)
expect(multibasedBuf.toString()).to.equal(output)
expect(decodeText(multibasedBuf)).to.equal(output)
})
})
}
Expand All @@ -180,7 +178,7 @@ describe('multibase.encode ', () => {
const decoded = multibase.decode(encodedStr)

const encoded = multibase.encode('c', decoded)
expect(encodedStr).to.be.eq(encoded.toString())
expect(encodedStr).to.be.eq(decodeText(encoded))
})
})

Expand All @@ -193,13 +191,13 @@ describe('multibase.decode', () => {
it('decodes a string', () => {
const multibasedStr = output
const buf = multibase.decode(multibasedStr)
expect(buf).to.eql(Buffer.from(input))
expect(buf).to.eql(encodeText(input))
})

they('decodes a buffer', (encode) => {
they('decodes a Uint8Array', (encode) => {
const multibasedBuf = encode(output)
const buf = multibase.decode(multibasedBuf)
expect(buf).to.eql(Buffer.from(input))
expect(buf).to.eql(encodeText(input))
})
})
}
Expand Down Expand Up @@ -241,7 +239,7 @@ describe('multibase.codes', () => {
})

describe('multibase.isEncoded', () => {
it('should not throw for non string/buffer input', () => {
it('should not throw for non String/Uint8Array input', () => {
const invalidInputs = [
null,
undefined,
Expand Down
24 changes: 12 additions & 12 deletions test/spec-test1.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-env mocha */
'use strict'

const { Buffer } = require('buffer')
const { decodeText, encodeText } = require('../src/util')
const { expect } = require('aegir/utils/chai')
const multibase = require('../src')
const constants = require('../src/constants.js')
Expand Down Expand Up @@ -37,33 +37,33 @@ describe('spec test1', () => {
const base = constants.names[name]

describe(name, () => {
it('should encode buffer by base name', () => {
const out = multibase.encode(name, Buffer.from(input))
expect(out.toString()).to.equal(output)
it('should encode Uint8Array by base name', () => {
const out = multibase.encode(name, encodeText(input))
expect(decodeText(out)).to.equal(output)
})

it('should encode buffer by base code', () => {
const out = multibase.encode(base.code, Buffer.from(input))
expect(out.toString()).to.equal(output)
it('should encode Uint8Array by base code', () => {
const out = multibase.encode(base.code, encodeText(input))
expect(decodeText(out)).to.equal(output)
})

it('should decode string', () => {
const out = multibase.decode(output)
expect(out.toString()).to.equal(input)
expect(decodeText(out)).to.equal(input)
})

it('should prefix encoded buffer', () => {
it('should prefix encoded Uint8Array', () => {
const base = constants.names[name]
const data = base.encode(Buffer.from(input))
const data = base.encode(encodeText(input))

expect(multibase(name, Buffer.from(data)).toString()).to.equal(output)
expect(decodeText(multibase(name, encodeText(data)))).to.equal(output)
})

it('should fail decode with invalid char', function () {
if (name === 'identity') {
return this.skip()
}
const nonEncodedBuf = Buffer.from(base.code + '^!@$%!#$%@#y')
const nonEncodedBuf = encodeText(base.code + '^!@$%!#$%@#y')
expect(() => {
multibase.decode(nonEncodedBuf)
}).to.throw(Error, 'invalid character \'^\' in \'^!@$%!#$%@#y\'')
Expand Down
12 changes: 6 additions & 6 deletions test/spec-test2.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-env mocha */
'use strict'

const { Buffer } = require('buffer')
const { decodeText, encodeText } = require('../src/util')
const { expect } = require('aegir/utils/chai')
const multibase = require('../src')
const constants = require('../src/constants.js')
Expand Down Expand Up @@ -38,18 +38,18 @@ describe('spec test2', () => {

describe(name, () => {
it('should encode buffer by base name', () => {
const out = multibase.encode(name, Buffer.from(input))
expect(out.toString()).to.equal(output)
const out = multibase.encode(name, encodeText(input))
expect(decodeText(out)).to.equal(output)
})

it('should encode buffer by base code', () => {
const out = multibase.encode(base.code, Buffer.from(input))
expect(out.toString()).to.equal(output)
const out = multibase.encode(base.code, encodeText(input))
expect(decodeText(out)).to.equal(output)
})

it('should decode string', () => {
const out = multibase.decode(output)
expect(out.toString()).to.equal(input)
expect(decodeText(out)).to.equal(input)
})
})
}
Expand Down
12 changes: 6 additions & 6 deletions test/spec-test3.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-env mocha */
'use strict'

const { Buffer } = require('buffer')
const { decodeText, encodeText } = require('../src/util')
const { expect } = require('aegir/utils/chai')
const multibase = require('../src')
const constants = require('../src/constants.js')
Expand Down Expand Up @@ -38,18 +38,18 @@ describe('spec test3', () => {

describe(name, () => {
it('should encode buffer by base name', () => {
const out = multibase.encode(name, Buffer.from(input))
expect(out.toString()).to.equal(output)
const out = multibase.encode(name, encodeText(input))
expect(decodeText(out)).to.equal(output)
})

it('should encode buffer by base code', () => {
const out = multibase.encode(base.code, Buffer.from(input))
expect(out.toString()).to.equal(output)
const out = multibase.encode(base.code, encodeText(input))
expect(decodeText(out)).to.equal(output)
})

it('should decode string', () => {
const out = multibase.decode(output)
expect(out.toString()).to.equal(input)
expect(decodeText(out)).to.equal(input)
})
})
}
Expand Down
Loading

0 comments on commit 5e38957

Please sign in to comment.