From 25367517a03bd94b0fc349ab6f02a5679a9f8e86 Mon Sep 17 00:00:00 2001 From: Volker Mische Date: Fri, 26 Mar 2021 12:21:19 +0100 Subject: [PATCH 1/6] feat!: named exports instead of default exports It also removes the `Codec` class and exports a plain object instead. This has consequences for imports. BREAKING CHANGE: Only use names exports as default exports don't play well with CommonJS + Typescript typing. This means that when you use ESM imports, e.g. the raw codec is no longer imported as ```js import raw from 'multiformats/codecs/raw' ``` but as ```js import * as raw from 'multiformats/codecs/raw' ``` The CJS import for codecs don't change, it's still `const raw = require('multiformats/codecs/raw`. Though other imports change, so ```js import CID from 'multiformats/cid' const CID = require('multiformats/cid') ``` is now ```js import { CID } from 'multiformats/cid' const { CID } = require ('multiformats/cid') ``` --- README.md | 4 ++-- src/basics.js | 4 ++-- src/cid.js | 2 +- src/codecs/codec.js | 50 +++++------------------------------------ src/codecs/json.js | 2 +- src/codecs/raw.js | 8 +++---- src/hashes/identity.js | 2 +- src/index.js | 2 +- src/legacy.js | 5 ++--- test/test-block.js | 2 +- test/test-legacy.js | 8 +++---- test/test-multicodec.js | 4 ++-- test/test-multihash.js | 2 +- test/ts-use/src/main.ts | 2 +- 14 files changed, 29 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 37ba16df..36c55794 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ Library provides implementations for most basics and many others can be found in ## Interfaces ```js -import CID from 'multiformats/cid' -import json from 'multiformats/codecs/json' +import { CID } from 'multiformats/cid' +import * as json from 'multiformats/codecs/json' import { sha256 } from 'multiformats/hashes/sha2' const bytes = json.encode({ hello: 'world' }) diff --git a/src/basics.js b/src/basics.js index 66974a19..8c183b3d 100644 --- a/src/basics.js +++ b/src/basics.js @@ -4,8 +4,8 @@ import * as base32 from './bases/base32.js' import * as base58 from './bases/base58.js' import * as sha2 from './hashes/sha2.js' -import raw from './codecs/raw.js' -import json from './codecs/json.js' +import * as raw from './codecs/raw.js' +import * as json from './codecs/json.js' import { CID, hasher, digest, varint, bytes } from './index.js' diff --git a/src/cid.js b/src/cid.js index cd5fbb54..57b47fa0 100644 --- a/src/cid.js +++ b/src/cid.js @@ -18,7 +18,7 @@ import { coerce } from './bytes.js' * @typedef {import('./bases/interface').MultibaseDecoder} MultibaseDecoder */ -export default class CID { +export class CID { /** * @param {0|1} version * @param {number} code diff --git a/src/codecs/codec.js b/src/codecs/codec.js index 5dd08675..767bb4ee 100644 --- a/src/codecs/codec.js +++ b/src/codecs/codec.js @@ -11,8 +11,12 @@ * @param {(data:T) => Uint8Array} options.encode * @param {(bytes:Uint8Array) => T} options.decode */ -export const codec = ({ name, code, decode, encode }) => - new Codec(name, code, encode, decode) +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 @@ -64,45 +68,3 @@ export class Decoder { this.decode = decode } } - -/** - * @template {number} Code - * @template T - * @typedef {import('./interface').BlockCodec} BlockCodec - */ - -/** - * @class - * @template {string} Name - * @template {number} Code - * @template T - * @implements {BlockCodec} - */ -export class Codec { - /** - * @param {Name} name - * @param {Code} code - * @param {(data:T) => Uint8Array} encode - * @param {(bytes:Uint8Array) => T} decode - */ - constructor (name, code, encode, decode) { - this.name = name - this.code = code - this.encode = encode - this.decode = decode - } - - get decoder () { - const { name, code, decode } = this - const decoder = new Decoder(name, code, decode) - Object.defineProperty(this, 'decoder', { value: decoder }) - return decoder - } - - get encoder () { - const { name, code, encode } = this - const encoder = new Encoder(name, code, encode) - Object.defineProperty(this, 'encoder', { value: encoder }) - return encoder - } -} diff --git a/src/codecs/json.js b/src/codecs/json.js index c0bc11de..09ea2a09 100644 --- a/src/codecs/json.js +++ b/src/codecs/json.js @@ -2,7 +2,7 @@ import { codec } from './codec.js' -export default codec({ +export const { name, code, decode, encode, decoder, encoder } = codec({ name: 'json', code: 0x0200, encode: json => new TextEncoder().encode(JSON.stringify(json)), diff --git a/src/codecs/raw.js b/src/codecs/raw.js index b17fe69c..63ccda36 100644 --- a/src/codecs/raw.js +++ b/src/codecs/raw.js @@ -7,11 +7,11 @@ import { codec } from './codec.js' * @param {Uint8Array} bytes * @returns {Uint8Array} */ -const raw = (bytes) => coerce(bytes) +const rawEncodeDecode = (bytes) => coerce(bytes) -export default codec({ +export const { name, code, decode, encode, decoder, encoder } = codec({ name: 'raw', code: 85, - decode: raw, - encode: raw + decode: rawEncodeDecode, + encode: rawEncodeDecode }) diff --git a/src/hashes/identity.js b/src/hashes/identity.js index 700cb7cc..1a928578 100644 --- a/src/hashes/identity.js +++ b/src/hashes/identity.js @@ -3,7 +3,7 @@ import { from } from './hasher.js' import { coerce } from '../bytes.js' -export default from({ +export const identity = from({ name: 'identity', code: 0x0, encode: (input) => coerce(input) diff --git a/src/index.js b/src/index.js index 989edc65..15931971 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -import CID from './cid.js' +import { CID } from './cid.js' import * as varint from './varint.js' import * as bytes from './bytes.js' import * as hasher from './hashes/hasher.js' diff --git a/src/legacy.js b/src/legacy.js index c179e8e1..9ce81e4e 100644 --- a/src/legacy.js +++ b/src/legacy.js @@ -1,7 +1,7 @@ import OldCID from 'cids' import * as bytes from './bytes.js' import { Buffer } from 'buffer' -import CID from './cid.js' +import { CID } from './cid.js' /** * @template {number} Code @@ -11,7 +11,7 @@ import CID from './cid.js' * @param {Object} options.hashes */ -const legacy = (codec, { hashes }) => { +export const legacy = (codec, { hashes }) => { /** * @param {*} obj */ @@ -139,7 +139,6 @@ const legacy = (codec, { hashes }) => { return { defaultHashAlg, codec: codec.code, util, resolver } } -export default legacy /** * @typedef {import('./hashes/interface').MultihashHasher} MultihashHasher */ diff --git a/test/test-block.js b/test/test-block.js index 8521b170..a7be1999 100644 --- a/test/test-block.js +++ b/test/test-block.js @@ -1,5 +1,5 @@ /* globals describe, it */ -import codec from 'multiformats/codecs/json' +import * as codec from 'multiformats/codecs/json' import { sha256 as hasher } from 'multiformats/hashes/sha2' import * as main from 'multiformats/block' import { CID, bytes } from 'multiformats' diff --git a/test/test-legacy.js b/test/test-legacy.js index e856cbc8..4e0468d0 100644 --- a/test/test-legacy.js +++ b/test/test-legacy.js @@ -1,12 +1,12 @@ /* globals before, describe, it */ import { Buffer } from 'buffer' import assert from 'assert' -import legacy from 'multiformats/legacy' -import rawCodec from 'multiformats/codecs/raw' -import jsonCodec from 'multiformats/codecs/json' +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' +import { CID } from 'multiformats/cid' const same = assert.deepStrictEqual const test = it diff --git a/test/test-multicodec.js b/test/test-multicodec.js index 3ab9b44a..38668b69 100644 --- a/test/test-multicodec.js +++ b/test/test-multicodec.js @@ -1,8 +1,8 @@ /* globals describe, it */ import * as bytes from '../src/bytes.js' import assert from 'assert' -import raw from 'multiformats/codecs/raw' -import json from 'multiformats/codecs/json' +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 diff --git a/test/test-multihash.js b/test/test-multihash.js index 6ebef024..f11c8135 100644 --- a/test/test-multihash.js +++ b/test/test-multihash.js @@ -5,7 +5,7 @@ import valid from './fixtures/valid-multihash.js' import invalid from './fixtures/invalid-multihash.js' import crypto from 'crypto' import { sha256, sha512, __browser } from 'multiformats/hashes/sha2' -import identity from 'multiformats/hashes/identity' +import { identity } from 'multiformats/hashes/identity' import { decode as decodeDigest, create as createDigest } from 'multiformats/hashes/digest' const test = it const encode = name => data => coerce(crypto.createHash(name).update(data).digest()) diff --git a/test/ts-use/src/main.ts b/test/ts-use/src/main.ts index cbb376e9..d57c5688 100644 --- a/test/ts-use/src/main.ts +++ b/test/ts-use/src/main.ts @@ -1,6 +1,6 @@ import * as Block from 'multiformats/block' import { sha256 } from 'multiformats/hashes/sha2' -import json from 'multiformats/codecs/json' +import * as json from 'multiformats/codecs/json' const main = async () => { const block = await Block.encode({ From a3553aa762f562e6b1c05233d8b0fc0c877ce3e4 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Tue, 30 Mar 2021 15:19:26 +1100 Subject: [PATCH 2/6] fixup! feat!: named exports instead of default exports --- src/bytes.js | 3 ++- src/codecs/codec.js | 1 + src/codecs/interface.ts | 5 ++++- src/codecs/raw.js | 10 ++-------- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/bytes.js b/src/bytes.js index 6774d44a..a10ce3ec 100644 --- a/src/bytes.js +++ b/src/bytes.js @@ -33,7 +33,8 @@ const equals = (aa, bb) => { } /** - * @param {ArrayBufferView|ArrayBuffer} o + * @param {ArrayBufferView|ArrayBuffer|Uint8Array} o + * @returns {Uint8Array} */ const coerce = o => { if (o instanceof Uint8Array && o.constructor.name === 'Uint8Array') return o diff --git a/src/codecs/codec.js b/src/codecs/codec.js index 767bb4ee..02cd5f71 100644 --- a/src/codecs/codec.js +++ b/src/codecs/codec.js @@ -10,6 +10,7 @@ * @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) diff --git a/src/codecs/interface.ts b/src/codecs/interface.ts index 3474ff38..e7a98b52 100644 --- a/src/codecs/interface.ts +++ b/src/codecs/interface.ts @@ -20,7 +20,10 @@ export interface BlockDecoder { * separate those capabilties as sender requires encoder and receiver * requires decoder. */ -export interface BlockCodec extends BlockEncoder, BlockDecoder { } +export interface BlockCodec extends BlockEncoder, BlockDecoder { + encoder: BlockEncoder, + decoder: BlockDecoder +} // This just a hack to retain type information abouth the data that diff --git a/src/codecs/raw.js b/src/codecs/raw.js index 63ccda36..f2ee233f 100644 --- a/src/codecs/raw.js +++ b/src/codecs/raw.js @@ -3,15 +3,9 @@ import { coerce } from '../bytes.js' import { codec } from './codec.js' -/** - * @param {Uint8Array} bytes - * @returns {Uint8Array} - */ -const rawEncodeDecode = (bytes) => coerce(bytes) - export const { name, code, decode, encode, decoder, encoder } = codec({ name: 'raw', code: 85, - decode: rawEncodeDecode, - encode: rawEncodeDecode + decode: coerce, + encode: coerce }) From 1532d9e37c7ca8de8169a3a2f0213638c3b57527 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Tue, 30 Mar 2021 15:32:05 +1100 Subject: [PATCH 3/6] chore: update deps --- package.json | 21 ++++++++++----------- src/bases/base32.js | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 5e7ed5f0..ab701515 100644 --- a/package.json +++ b/package.json @@ -84,16 +84,16 @@ } }, "devDependencies": { - "@types/node": "14.14.3", - "@typescript-eslint/eslint-plugin": "^4.6.0", - "@typescript-eslint/parser": "^4.6.0", - "c8": "^7.3.5", + "@types/node": "^14.14.37", + "@typescript-eslint/eslint-plugin": "^4.20.0", + "@typescript-eslint/parser": "^4.20.0", + "c8": "^7.6.0", "hundreds": "0.0.9", - "ipjs": "^3.4.4", - "mocha": "^8.2.0", + "ipjs": "^5.0.0", + "mocha": "^8.3.2", "polendina": "^1.1.0", - "standard": "^15.0.0", - "typescript": "^4.0.3" + "standard": "^16.0.3", + "typescript": "^4.2.3" }, "standard": { "ignore": [ @@ -102,9 +102,8 @@ ] }, "dependencies": { - "buffer": "^5.6.1", - "cids": "^1.0.2", - "lodash.transform": "^4.6.0" + "buffer": "^6.0.3", + "cids": "^1.1.6" }, "directories": { "test": "test" diff --git a/src/bases/base32.js b/src/bases/base32.js index 0857a23c..19edce27 100644 --- a/src/bases/base32.js +++ b/src/bases/base32.js @@ -5,7 +5,7 @@ import { withAlphabet } from './base.js' * @param {input} alphabet */ function decode (input, alphabet) { - input = input.replace(new RegExp('=', 'g'), '') + input = input.replace(/=/g, '') const length = input.length let bits = 0 From 1f9131933ae0de7b0042c2f5501643047c2ee67c Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Tue, 30 Mar 2021 17:26:43 +1100 Subject: [PATCH 4/6] feat!: publish with "main", distribute src & TS map to src --- package.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ab701515..6bf540ac 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ "type": "module", "scripts": { "build": "npm run build:js && npm run build:types", - "build:js": "npm_config_yes=true ipjs build --tests", - "build:types": "tsc --emitDeclarationOnly --declarationDir dist/types", + "build:js": "npm_config_yes=true ipjs build --tests --main", + "build:types": "cp tsconfig.json dist && cp -a src vendor dist/ && cd dist && tsc --emitDeclarationOnly --declarationDir types", "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", @@ -120,6 +120,9 @@ "*": { "*": [ "types/*" + ], + "cjs/src/index.js": [ + "types/index.d.ts" ] } } From be187e6ec42c89100bf6d6a0d95d51e526a1c0ba Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Tue, 30 Mar 2021 11:29:38 -0700 Subject: [PATCH 5/6] fix: types mapping - "*" match seems to cause multiple path substitutions microsoft/TypeScript#41284 that packge name prefix seems to resolve - add types field which acts as main in TS --- package.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 6bf540ac..e8766581 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.0.0-dev", "description": "Interface for multihash, multicodec, multibase and CID", "main": "./src/index.js", + "types": "./types/index.d.ts", "type": "module", "scripts": { "build": "npm run build:js && npm run build:types", @@ -118,11 +119,8 @@ "homepage": "https://github.com/multiformats/js-multiformats#readme", "typesVersions": { "*": { - "*": [ + "multiformats/*": [ "types/*" - ], - "cjs/src/index.js": [ - "types/index.d.ts" ] } } From 56073f3f248620ea15ac6691d909037b41ed29b4 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Tue, 30 Mar 2021 14:17:49 -0700 Subject: [PATCH 6/6] fix: type mapping - modify scripts to use newer tsc --bulid command - generate types on prepare so linking to git dependency works - workaround douple substitution by mapping types/* to itself (see microsoft/TypeScript#41284) --- .gitignore | 1 + package.json | 12 ++++++++---- test/ts-use/tsconfig.json | 4 +++- tsconfig.json | 3 ++- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 594cec7c..9eb050f9 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ package-lock.json node_modules .DS_Store yarn.lock +types diff --git a/package.json b/package.json index e8766581..d3847cab 100644 --- a/package.json +++ b/package.json @@ -8,20 +8,21 @@ "scripts": { "build": "npm run build:js && npm run build:types", "build:js": "npm_config_yes=true ipjs build --tests --main", - "build:types": "cp tsconfig.json dist && cp -a src vendor dist/ && cd dist && tsc --emitDeclarationOnly --declarationDir types", + "build:types": "cp tsconfig.json dist && cp -a src vendor dist/ && 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", "lint": "standard", - "check": "tsc --noEmit --noErrorTruncation", + "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", "test:ts": "npm run build:types && npm run test --prefix test/ts-use", "test": "npm run lint && npm run test:node && npm run test:cjs && npm run test:ts", "test:node-v12": "mocha test/test-*.js && npm run test:cjs", - "coverage": "c8 --reporter=html mocha test/test-*.js && npm_config_yes=true npx st -d coverage -p 8080" + "coverage": "c8 --reporter=html mocha test/test-*.js && npm_config_yes=true npx st -d coverage -p 8080", + "prepare": "tsc --build" }, "c8": { "exclude": [ @@ -119,7 +120,10 @@ "homepage": "https://github.com/multiformats/js-multiformats#readme", "typesVersions": { "*": { - "multiformats/*": [ + "*": [ + "types/*" + ], + "types/*": [ "types/*" ] } diff --git a/test/ts-use/tsconfig.json b/test/ts-use/tsconfig.json index d73a2b15..ff147598 100644 --- a/test/ts-use/tsconfig.json +++ b/test/ts-use/tsconfig.json @@ -1,7 +1,9 @@ { "compilerOptions": { "strict": true, + "moduleResolution": "node", "noImplicitAny": true, - "skipLibCheck": true + "skipLibCheck": true, + "incremental": true } } diff --git a/tsconfig.json b/tsconfig.json index 4ce54b0e..2634e3f1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,8 @@ "moduleResolution": "node", "declaration": true, "declarationMap": true, - "outDir": "dist", + "emitDeclarationOnly": true, + "outDir": "types", "skipLibCheck": true, "stripInternal": true, "resolveJsonModule": true,