diff --git a/.github/workflows/mikeals-workflow.yml b/.github/workflows/mikeals-workflow.yml index 1b88e24a..d7787f0e 100644 --- a/.github/workflows/mikeals-workflow.yml +++ b/.github/workflows/mikeals-workflow.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [12.x, 14.x] + node-version: [12.x, 14.x, 16.x] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} diff --git a/README.md b/README.md index b48a5e68..0bce9b5e 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ # multiformats -This library defines common interfaces and low level building blocks for various interrelated multiformat technologies (multicodec, multihash, multibase, -and CID). They can be used to implement custom custom base -encoders / decoders / codecs, codec encoders /decoders and multihash hashers that comply to the interface that layers above assume. +This library defines common interfaces and low level building blocks for various interrelated multiformat technologies (multicodec, multihash, multibase, and CID). They can be used to implement custom custom base encoders / decoders / codecs, codec encoders /decoders and multihash hashers that comply to the interface that layers above assume. -Library provides implementations for most basics and many others can be found in linked repositories. +This library provides implementations for most basics and many others can be found in linked repositories. ## Interfaces @@ -45,9 +43,7 @@ block = await Block.create({ bytes: block.bytes, cid: block.cid, codec, hasher } ### Multibase Encoders / Decoders / Codecs -CIDs can be serialized to string representation using multibase encoders that -implement [`MultibaseEncoder`](https://github.com/multiformats/js-multiformats/blob/master/src/bases/interface.ts) interface. Library -provides quite a few implementations that can be imported: +CIDs can be serialized to string representation using multibase encoders that implement [`MultibaseEncoder`](https://github.com/multiformats/js-multiformats/blob/master/src/bases/interface.ts) interface. This library provides quite a few implementations that can be imported: ```js import { base64 } from "multiformats/bases/base64" @@ -55,9 +51,7 @@ cid.toString(base64.encoder) //> 'mAYAEEiCTojlxqRTl6svwqNJRVM2jCcPBxy+7mRTUfGDzy2gViA' ``` -Parsing CID string serialized CIDs requires multibase decoder that implements -[`MultibaseDecoder`](https://github.com/multiformats/js-multiformats/blob/master/src/bases/interface.ts) interface. Library provides a -decoder for every encoder it provides: +Parsing CID string serialized CIDs requires multibase decoder that implements [`MultibaseDecoder`](https://github.com/multiformats/js-multiformats/blob/master/src/bases/interface.ts) interface. This library provides a decoder for every encoder it provides: ```js CID.parse('mAYAEEiCTojlxqRTl6svwqNJRVM2jCcPBxy+7mRTUfGDzy2gViA', base64.decoder) @@ -93,35 +87,24 @@ v0.toV1().toString() ### Multicodec Encoders / Decoders / Codecs -Library defines [`BlockEncoder`, `BlockDecoder` and `BlockCodec` interfaces](https://github.com/multiformats/js-multiformats/blob/master/src/codecs/interface.ts) -and utility function to take care of the boilerplate when implementing them: +This library defines [`BlockEncoder`, `BlockDecoder` and `BlockCodec` interfaces](https://github.com/multiformats/js-multiformats/blob/master/src/codecs/interface.ts). Codec implementations should conform to the `BlockCodec` interface which implements both `BlockEncoder` and `BlockDecoder`. ```js -import { codec } from 'multiformats/codecs/codec' - -const json = codec({ +/** + * @template T + * @type {BlockCodec<0x0200, T>} + */ +export const { name, code, encode, decode } = { name: 'json', - // As per multiformats table - // https://github.com/multiformats/multicodec/blob/master/table.csv#L113 code: 0x0200, encode: json => new TextEncoder().encode(JSON.stringify(json)), decode: bytes => JSON.parse(new TextDecoder().decode(bytes)) -}) -``` - -Just like with multibase, here codecs are duals of `encoder` and `decoder` parts, -but they also implement both interfaces for convenience: - -```js -const hello = json.encoder.encode({ hello: 'world' }) -json.decode(b1) -//> { hello: 'world' } +} ``` ### Multihash Hashers -This library defines [`MultihashHasher` and `MultihashDigest` interfaces](https://github.com/multiformats/js-multiformats/blob/master/src/hashes/interface.ts) -and convinient function for implementing them: +This library defines [`MultihashHasher` and `MultihashDigest` interfaces](https://github.com/multiformats/js-multiformats/blob/master/src/hashes/interface.ts) and convinient function for implementing them: ```js import * as hasher from 'multiformats/hashes/hasher') @@ -141,8 +124,6 @@ CID.create(1, json.code, hash) //> CID(bagaaierasords4njcts6vs7qvdjfcvgnume4hqohf65zsfguprqphs3icwea) ``` - - # Implementations By default, no base encodings (other than base32 & base58btc), hash functions, @@ -179,7 +160,6 @@ import the ones you need yourself. | `dag-pb` | `@ipld/dag-pb` | [ipld/js-dag-pb](https://github.com/ipld/js-dag-pb) | | `dag-jose` | `dag-jose`| [ceramicnetwork/js-dag-jose](https://github.com/ceramicnetwork/js-dag-jose) | - ## TypeScript support This project is distributed with type definitions for TypeScript. diff --git a/package.json b/package.json index a034f502..f9dc7523 100644 --- a/package.json +++ b/package.json @@ -7,15 +7,14 @@ "type": "module", "scripts": { "build": "npm run build:js && npm run build:types", - "build:js": "npm_config_yes=true ipjs build --tests --main && npm run build:copy", + "build:js": "ipjs build --tests --main && npm run build:copy", "build:copy": "cp -a tsconfig.json src vendor test dist/ && rm -rf dist/test/ts-use", "build:types": "npm run build:copy && cd dist && tsc --build", "build:vendor": "npm run build:vendor:varint && npm run build:vendor:base-x", - "build:vendor:varint": "npx brrp -x varint > vendor/varint.js", - "build:vendor:base-x": "npx brrp -x @multiformats/base-x > vendor/base-x.js", - "publish": "npm_config_yes=true ipjs publish", + "build:vendor:varint": "npm_config_yes=true npx brrp -x varint > vendor/varint.js", + "build:vendor:base-x": "npm_config_yes=true npx brrp -x @multiformats/base-x > vendor/base-x.js", + "publish": "ipjs publish", "lint": "standard", - "check": "tsc --build --noErrorTruncation", "test:cjs": "npm run build:js && mocha dist/cjs/node-test/test-*.js && npm run test:cjs:browser", "test:node": "hundreds mocha test/test-*.js", "test:cjs:browser": "polendina --page --worker --serviceworker --cleanup dist/cjs/browser-test/test-*.js", @@ -75,9 +74,6 @@ "./hashes/identity": { "import": "./src/hashes/identity.js" }, - "./codecs/codec": { - "import": "./src/codecs/codec.js" - }, "./codecs/json": { "import": "./src/codecs/json.js" }, @@ -86,16 +82,16 @@ } }, "devDependencies": { - "@types/node": "^14.14.37", - "@typescript-eslint/eslint-plugin": "^4.20.0", - "@typescript-eslint/parser": "^4.20.0", - "c8": "^7.6.0", + "@types/node": "^14.14.41", + "@typescript-eslint/eslint-plugin": "^4.22.0", + "@typescript-eslint/parser": "^4.22.0", + "c8": "^7.7.1", "hundreds": "0.0.9", "ipjs": "^5.0.0", "mocha": "^8.3.2", "polendina": "^1.1.0", "standard": "^16.0.3", - "typescript": "^4.2.3" + "typescript": "^4.2.4" }, "standard": { "ignore": [ @@ -120,6 +116,9 @@ "homepage": "https://github.com/multiformats/js-multiformats#readme", "typesVersions": { "*": { + "bases/base64": [ + "types/bases/base64-import.d.ts" + ], "*": [ "types/*" ], diff --git a/src/codecs/codec.js b/src/codecs/codec.js deleted file mode 100644 index c1bd94aa..00000000 --- a/src/codecs/codec.js +++ /dev/null @@ -1,71 +0,0 @@ -// @ts-check - -/** - * @template {string} Name - * @template {number} Code - * @template T - * - * @param {Object} options - * @param {Name} options.name - * @param {Code} options.code - * @param {(data:T) => Uint8Array} options.encode - * @param {(bytes:Uint8Array) => T} options.decode - * @returns {import('./interface').BlockCodec} - */ -export const codec = ({ name, code, decode, encode }) => { - const decoder = new Decoder(name, code, decode) - const encoder = new Encoder(name, code, encode) - - return { name, code, decode, encode, decoder, encoder } -} - -/** - * @template {number} Code - * @template T - * @typedef {import('./interface').BlockEncoder} BlockEncoder - */ - -/** - * @class - * @template T - * @template {string} Name - * @template {number} Code - * @implements {BlockEncoder} - */ -export class Encoder { - /** - * @param {Name} name - * @param {Code} code - * @param {(data:T) => Uint8Array} encode - */ - constructor (name, code, encode) { - this.name = name - this.code = code - this.encode = encode - } -} - -/** - * @template {number} Code - * @template T - * @typedef {import('./interface').BlockDecoder} BlockDecoder - */ - -/** - * @class - * @template {number} Code - * @template T - * @implements {BlockDecoder} - */ -export class Decoder { - /** - * @param {string} name - * @param {Code} code - * @param {(bytes:Uint8Array) => T} decode - */ - constructor (name, code, decode) { - this.name = name - this.code = code - this.decode = decode - } -} diff --git a/src/codecs/interface.ts b/src/codecs/interface.ts index e7a98b52..dc8527c1 100644 --- a/src/codecs/interface.ts +++ b/src/codecs/interface.ts @@ -16,18 +16,12 @@ export interface BlockDecoder { } /** - * IPLD codec that is just Encoder + Decoder however it is - * separate those capabilties as sender requires encoder and receiver - * requires decoder. + * An IPLD codec is a combination of both encoder and decoder. */ -export interface BlockCodec extends BlockEncoder, BlockDecoder { - encoder: BlockEncoder, - decoder: BlockDecoder -} - +export interface BlockCodec extends BlockEncoder, BlockDecoder {} -// This just a hack to retain type information abouth the data that -// is incoded `T` Because it's a union `data` field is never going +// This just a hack to retain type information about the data that +// is encoded `T` Because it's a union `data` field is never going // to be usable anyway. export type ByteView = | Uint8Array diff --git a/src/codecs/json.js b/src/codecs/json.js index 09ea2a09..fd8be455 100644 --- a/src/codecs/json.js +++ b/src/codecs/json.js @@ -1,10 +1,18 @@ // @ts-check -import { codec } from './codec.js' +/** + * @template {number} Code + * @template T + * @typedef {import('./interface').BlockCodec} BlockCodec + */ -export const { name, code, decode, encode, decoder, encoder } = codec({ +/** + * @template T + * @type {BlockCodec<0x0200, T>} + */ +export const { name, code, encode, decode } = { name: 'json', code: 0x0200, encode: json => new TextEncoder().encode(JSON.stringify(json)), decode: bytes => JSON.parse(new TextDecoder().decode(bytes)) -}) +} diff --git a/src/codecs/raw.js b/src/codecs/raw.js index f2ee233f..9f2639db 100644 --- a/src/codecs/raw.js +++ b/src/codecs/raw.js @@ -1,11 +1,26 @@ // @ts-check import { coerce } from '../bytes.js' -import { codec } from './codec.js' -export const { name, code, decode, encode, decoder, encoder } = codec({ +/** + * @template {number} Code + * @template T + * @typedef {import('./interface').BlockCodec} BlockCodec + */ + +/** + * @param {Uint8Array} bytes + * @returns {Uint8Array} + */ +const raw = (bytes) => coerce(bytes) + +/** + * @template T + * @type {BlockCodec<0x55, Uint8Array>} + */ +export const { name, code, encode, decode } = { name: 'raw', - code: 85, - decode: coerce, - encode: coerce -}) + code: 0x55, + decode: raw, + encode: raw +} diff --git a/src/index.js b/src/index.js index 15931971..aed6be18 100644 --- a/src/index.js +++ b/src/index.js @@ -3,6 +3,5 @@ import * as varint from './varint.js' import * as bytes from './bytes.js' import * as hasher from './hashes/hasher.js' import * as digest from './hashes/digest.js' -import * as codec from './codecs/codec.js' -export { CID, hasher, digest, varint, bytes, codec } +export { CID, hasher, digest, varint, bytes } diff --git a/test/test-legacy.js b/test/test-legacy.js index 4e0468d0..63e55014 100644 --- a/test/test-legacy.js +++ b/test/test-legacy.js @@ -5,7 +5,6 @@ import { legacy } from 'multiformats/legacy' import * as rawCodec from 'multiformats/codecs/raw' import * as jsonCodec from 'multiformats/codecs/json' import { sha256, sha512 } from 'multiformats/hashes/sha2' -import { codec } from 'multiformats/codecs/codec' import { CID } from 'multiformats/cid' const same = assert.deepStrictEqual @@ -36,7 +35,7 @@ describe('multicodec', () => { raw = legacy(rawCodec, { hashes }) json = legacy(jsonCodec, { hashes }) link = await raw.util.cid(Buffer.from('test')) - custom = legacy(codec({ + custom = legacy({ name: 'custom', code: 6787678, encode: o => { @@ -52,7 +51,7 @@ describe('multicodec', () => { if (obj.o.link) obj.link = CID.asCID(link) return obj } - }), { hashes }) + }, { hashes }) }) test('encode/decode raw', () => { const buff = raw.util.serialize(Buffer.from('test')) diff --git a/test/test-multicodec.js b/test/test-multicodec.js index 38668b69..9f1ab164 100644 --- a/test/test-multicodec.js +++ b/test/test-multicodec.js @@ -3,7 +3,7 @@ import * as bytes from '../src/bytes.js' import assert from 'assert' import * as raw from 'multiformats/codecs/raw' import * as json from 'multiformats/codecs/json' -import { codec } from 'multiformats/codecs/codec' + const same = assert.deepStrictEqual const test = it @@ -31,37 +31,7 @@ describe('multicodec', () => { same(json.decode(buff), { hello: 'world' }) }) - test('json.encoder', () => { - const { encoder } = json - same(encoder === json.encoder, true, 'getter cached decoder') - - const buff = encoder.encode({ hello: 'world' }) - same(buff, bytes.fromString(JSON.stringify({ hello: 'world' }))) - }) - - test('json.decoder', () => { - const { decoder } = json - same(decoder === json.decoder, true, 'getter cached encoder') - - const buff = json.encode({ hello: 'world' }) - same(decoder.decode(buff), { hello: 'world' }) - }) - test('raw cannot encode string', async () => { await testThrow(() => raw.encode('asdf'), 'Unknown type, must be binary type') }) - - test('add with function', () => { - const blip = codec({ - code: 200, - name: 'blip', - encode: (a) => a[1], - decode: (a) => a - }) - - const two = bytes.fromString('two') - const three = bytes.fromString('three') - same(blip.encode(['one', two, three]), two) - same(blip.decode(three, 200), three) - }) }) diff --git a/test/ts-use/package.json b/test/ts-use/package.json index 44f4d5e7..c4ef82b8 100644 --- a/test/ts-use/package.json +++ b/test/ts-use/package.json @@ -5,6 +5,6 @@ "multiformats": "file:../../dist/" }, "scripts": { - "test": "npm install && npx -p typescript tsc --noEmit" + "test": "npm install && npm_config_yes=true npx -p typescript tsc --noEmit" } } diff --git a/tsconfig.json b/tsconfig.json index 2634e3f1..082f7583 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,17 +20,17 @@ "moduleResolution": "node", "declaration": true, "declarationMap": true, - "emitDeclarationOnly": true, "outDir": "types", "skipLibCheck": true, "stripInternal": true, "resolveJsonModule": true, + "emitDeclarationOnly": true, + "baseUrl": ".", "paths": { "multiformats": [ "src" ] - }, - "baseUrl": "." + } }, "include": [ "src"