From d5f39238e417e4ff2fdc058d1452b01472ff96b0 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Thu, 15 Feb 2024 14:40:59 +0000 Subject: [PATCH] feat: support decoding ArrayBuffers Expands supported input types to include `ArrayBuffer`s to make it easiser for users to use modules like `fetch` that don't return `Uint8Array`s. --- package.json | 2 +- src/index.js | 24 +++++++++++++++++++++--- test/test-basics.spec.js | 9 +++++++++ test/ts-use/src/main.ts | 9 +++++++++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 5f2a756..5374465 100644 --- a/package.json +++ b/package.json @@ -162,7 +162,7 @@ }, "dependencies": { "cborg": "^4.0.0", - "multiformats": "^13.0.0" + "multiformats": "^13.1.0" }, "devDependencies": { "@ipld/garbage": "^6.0.0", diff --git a/src/index.js b/src/index.js index 269cf71..2346b7c 100644 --- a/src/index.js +++ b/src/index.js @@ -8,6 +8,10 @@ import { base64 } from 'multiformats/bases/base64' * @template T * @typedef {import('multiformats/codecs/interface').ByteView} ByteView */ +/** + * @template T + * @typedef {import('multiformats/codecs/interface').ArrayBufferView} ArrayBufferView + */ /** * @template T * @typedef {import('multiformats').ToString} ToString @@ -16,6 +20,19 @@ import { base64 } from 'multiformats/bases/base64' * @typedef {import('cborg/interface').DecodeTokenizer} DecodeTokenizer */ +/** + * @template T + * @param {ByteView | ArrayBufferView} buf + * @returns {ByteView} + */ +function toByteView (buf) { + if (buf instanceof ArrayBuffer) { + return new Uint8Array(buf, 0, buf.byteLength) + } + + return buf +} + /** * cidEncoder will receive all Objects during encode, it needs to filter out * anything that's not a CID and return `null` for that so it's encoded as @@ -246,13 +263,14 @@ export const encode = (node) => cborgJson.encode(node, encodeOptions) /** * @template T - * @param {ByteView} data + * @param {ByteView | ArrayBufferView} data * @returns {T} */ export const decode = (data) => { + const buf = toByteView(data) // the tokenizer is stateful so we need a single instance of it - const options = Object.assign(decodeOptions, { tokenizer: new DagJsonTokenizer(data, decodeOptions) }) - return cborgJson.decode(data, options) + const options = Object.assign(decodeOptions, { tokenizer: new DagJsonTokenizer(buf, decodeOptions) }) + return cborgJson.decode(buf, options) } /** diff --git a/test/test-basics.spec.js b/test/test-basics.spec.js index c64256a..5819502 100644 --- a/test/test-basics.spec.js +++ b/test/test-basics.spec.js @@ -30,6 +30,15 @@ describe('basic dag-json', () => { same(bytes.toString(recode(byts)), expected) }) + it('encode decode with ArrayBuffer', () => { + const byts = encode({ hello: 'world' }) + same(JSON.parse(bytes.toString(recode(byts))), { hello: 'world' }) + const o = { link, byts: bytes.fromString('asdf'), n: null, o: {} } + const byts2 = encode(o) + same(decode(byts2), o) + same(bytes.isBinary(decode(byts2).byts.buffer), true) + }) + describe('reserved space', () => { it('allow alternative types', () => { // wrong types diff --git a/test/ts-use/src/main.ts b/test/ts-use/src/main.ts index 4ac245f..caa4ea0 100644 --- a/test/ts-use/src/main.ts +++ b/test/ts-use/src/main.ts @@ -15,6 +15,9 @@ function useCodecFeature (codec: BlockCodec<297, any>) { // use only as a BlockDecoder useDecoder(codec) + // use with ArrayBuffer input type + useDecoderWithArrayBuffer(codec) + // use as a full BlockCodec which does both BlockEncoder & BlockDecoder useBlockCodec(codec) } @@ -32,6 +35,12 @@ function useDecoder (decoder: BlockDecoder (decoder: BlockDecoder) { + deepStrictEqual(decoder.code, 297) + deepStrictEqual(decoder.decode(Uint8Array.from([34, 98, 108, 105, 112, 34 ]).buffer), 'blip') + console.log('[TS] ✓ { decoder: BlockDecoder }') +} + function useBlockCodec (blockCodec: BlockCodec) { deepStrictEqual(blockCodec.code, 297) deepStrictEqual(blockCodec.name, 'dag-json')