From 33e6897f0745b38e1755da358c1af9d1e627bbd5 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Sat, 10 Apr 2021 15:10:32 +1000 Subject: [PATCH] feat!: latest multiformats, full types check & gen & publish BREAKING CHANGE: * use multiformats@7 and its non-default exports and updated types * export types based on latest multiformats structure * publish with "main" Unlikely to be breaking in practice for anyone not using types, may not even break for those using types. --- .github/workflows/mikeals-workflow.yml | 2 +- example-prepare.js | 2 +- example.js | 2 +- package.json | 67 +++++++++++++++++------- index.js => src/index.js | 71 ++++++++++++++++++++++---- src/interface.ts | 34 ++++++++++++ pb-decode.js => src/pb-decode.js | 39 ++++++++++++-- pb-encode.js => src/pb-encode.js | 64 +++++++++++++++++++---- test/test-basics.js | 13 ++++- test/test-compat.js | 14 +++-- test/test-edges.js | 23 ++++++--- test/test-forms.js | 20 ++++++-- test/test-pb.js | 2 +- test/ts-use/.gitignore | 3 ++ test/ts-use/package.json | 11 ++++ test/ts-use/src/main.ts | 49 ++++++++++++++++++ test/ts-use/tsconfig.json | 9 ++++ tsconfig.json | 42 +++++++++++++++ 18 files changed, 404 insertions(+), 63 deletions(-) rename index.js => src/index.js (80%) create mode 100644 src/interface.ts rename pb-decode.js => src/pb-decode.js (85%) rename pb-encode.js => src/pb-encode.js (77%) create mode 100644 test/ts-use/.gitignore create mode 100644 test/ts-use/package.json create mode 100644 test/ts-use/src/main.ts create mode 100644 test/ts-use/tsconfig.json create mode 100644 tsconfig.json diff --git a/.github/workflows/mikeals-workflow.yml b/.github/workflows/mikeals-workflow.yml index 1b88e24..d7787f0 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/example-prepare.js b/example-prepare.js index a011262..9e28acb 100644 --- a/example-prepare.js +++ b/example-prepare.js @@ -1,4 +1,4 @@ -import CID from 'multiformats/cid' +import { CID } from 'multiformats/cid' import { prepare } from '@ipld/dag-pb' console.log(prepare({ Data: 'some data' })) diff --git a/example.js b/example.js index 56538df..c696860 100644 --- a/example.js +++ b/example.js @@ -1,4 +1,4 @@ -import CID from 'multiformats/cid' +import { CID } from 'multiformats/cid' import { sha256 } from 'multiformats/hashes/sha2' import * as dagPB from '@ipld/dag-pb' diff --git a/package.json b/package.json index 4536f73..76e96fb 100644 --- a/package.json +++ b/package.json @@ -1,41 +1,70 @@ { "name": "@ipld/dag-pb", - "version": "0.0.0", + "version": "0.0.0-dev", "description": "JS implementation of DAG-PB", + "main": "./src/index.js", + "types": "./types/src/index.d.ts", "type": "module", - "exports": { - "import": "./index.js" - }, "scripts": { "lint": "standard", - "build": "npm_config_yes=true npx ipjs@latest build --tests", - "publish": "npm_config_yes=true npx ipjs@latest publish", - "test:cjs": "npm run build && mocha dist/cjs/node-test/test-*.js", + "build": "npm run build:js && npm run build:types", + "build:js": "ipjs build --tests --main && npm run build:copy", + "build:copy": "cp -a tsconfig.json src *.js dist/ && mkdir -p dist/test && cp test/*.js dist/test/", + "build:types": "npm run build:copy && cd dist && tsc --build", + "publish": "ipjs publish", + "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:browser": "polendina --cleanup dist/cjs/node-test/test-*.js", - "test": "npm run lint && npm run test:node && npm run test:cjs && npm run test:browser", - "coverage": "c8 --reporter=html mocha test/test-*.js && npx st -d coverage -p 8080" + "test:cjs:browser": "polendina --page --worker --serviceworker --cleanup dist/cjs/node-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", + "coverage": "c8 --reporter=html mocha test/test-*.js && npm_config_yes=true npx st -d coverage -p 8080" + }, + "exports": { + "import": "./src/index.js" }, "license": "(Apache-2.0 AND MIT)", "repository": { "type": "git", "url": "https://github.com/ipld/js-dag-pb.git" }, + "keywords": [ + "IPFS", + "IPLD" + ], + "bugs": { + "url": "https://github.com/ipld/js-dag-pb/issues" + }, + "homepage": "https://github.com/ipld/js-dag-pb", "dependencies": { - "multiformats": "^4.0.0" + "multiformats": "^7.0.0" }, "devDependencies": { - "c8": "^7.3.1", + "@types/chai": "^4.2.16", + "@types/mocha": "^8.2.2", "chai": "^4.2.0", "chai-subset": "^1.6.0", - "hundreds": "0.0.8", + "hundreds": "^0.0.9", + "ipjs": "^5.0.0", "mocha": "^8.1.3", "polendina": "^1.1.0", - "standard": "^14.3.4" + "standard": "^16.0.3", + "typescript": "^4.2.3" }, - "author": "Rod Vagg ", - "keywords": [ - "IPFS", - "IPLD" - ] + "standard": { + "ignore": [ + "dist", + "test/ts-use/src/main.js" + ] + }, + "typesVersions": { + "*": { + "*": [ + "types/*" + ], + "types/*": [ + "types/*" + ] + } + }, + "author": "Rod Vagg " } diff --git a/index.js b/src/index.js similarity index 80% rename from index.js rename to src/index.js index 607fd9e..46d5098 100644 --- a/index.js +++ b/src/index.js @@ -1,14 +1,28 @@ -import CID from 'multiformats/cid' -import decodeNode from './pb-decode.js' -import encodeNode from './pb-encode.js' +import { CID } from 'multiformats/cid' +import { decodeNode } from './pb-decode.js' +import { encodeNode } from './pb-encode.js' + +/** + * @template {number} Code + * @template T + * @typedef {import('multiformats/codecs/interface').BlockCodec} BlockCodec + */ + +/** + * @typedef {import('./interface').PBLink} PBLink + * @typedef {import('./interface').PBNode} PBNode + */ -const code = 0x70 -const name = 'dag-pb' const pbNodeProperties = ['Data', 'Links'] const pbLinkProperties = ['Hash', 'Name', 'Tsize'] const textEncoder = new TextEncoder() +/** + * @param {PBLink} a + * @param {PBLink} b + * @returns {number} + */ function linkComparator (a, b) { if (a === b) { return 0 @@ -31,10 +45,21 @@ function linkComparator (a, b) { return x < y ? -1 : y < x ? 1 : 0 } +/** + * @param {any} node + * @param {string[]} properties + * @returns {boolean} + */ function hasOnlyProperties (node, properties) { return !Object.keys(node).some((p) => !properties.includes(p)) } +/** + * Converts a CID, or a PBLink-like object to a PBLink + * + * @param {any} link + * @returns {PBLink} + */ function asLink (link) { if (typeof link.asCID === 'object') { const Hash = CID.asCID(link) @@ -84,7 +109,11 @@ function asLink (link) { return pbl } -function prepare (node) { +/** + * @param {any} node + * @returns {PBNode} + */ +export function prepare (node) { if (node instanceof Uint8Array || typeof node === 'string') { node = { Data: node } } @@ -93,6 +122,7 @@ function prepare (node) { throw new TypeError('Invalid DAG-PB form') } + /** @type {PBNode} */ const pbn = {} if (node.Data) { @@ -113,7 +143,10 @@ function prepare (node) { return pbn } -function validate (node) { +/** + * @param {PBNode} node + */ +export function validate (node) { /* type PBLink struct { Hash optional Link @@ -156,6 +189,7 @@ function validate (node) { throw new TypeError('Invalid DAG-PB form (link must have a Hash)') } + // @ts-ignore private property for TS if (link.Hash.asCID !== link.Hash) { throw new TypeError('Invalid DAG-PB form (link Hash must be a CID)') } @@ -174,7 +208,11 @@ function validate (node) { } } -function encode (node) { +/** + * @param {PBNode} node + * @returns {Uint8Array} + */ +function _encode (node) { validate(node) const pbn = {} @@ -200,7 +238,11 @@ function encode (node) { return encodeNode(pbn) } -function decode (bytes) { +/** + * @param {Uint8Array} bytes + * @returns {PBNode} + */ +function _decode (bytes) { const pbn = decodeNode(bytes) const node = {} @@ -231,4 +273,13 @@ function decode (bytes) { return node } -export { name, code, encode, decode, prepare, validate } +/** + * @template T + * @type {BlockCodec<0x70, PBNode>} + */ +export const { name, code, decode, encode } = { + name: 'dag-pb', + code: 0x70, + encode: _encode, + decode: _decode +} diff --git a/src/interface.ts b/src/interface.ts new file mode 100644 index 0000000..a004987 --- /dev/null +++ b/src/interface.ts @@ -0,0 +1,34 @@ +import { CID } from 'multiformats/cid' + +/* + PBNode and PBLink match the DAG-PB logical format, as described at: + https://github.com/ipld/specs/blob/master/block-layer/codecs/dag-pb.md#logical-format +*/ + +export interface PBLink { + Name?: string, + Tsize?: number, + Hash: CID +} + +export interface PBNode { + Data?: Uint8Array, + Links: PBLink[] +} + +// Raw versions of PBNode and PBLink used internally to deal with the underlying +// encode/decode byte interface. +// A future iteration could make pb-encode.js and pb-decode.js aware of PBNode +// and PBLink specifics (including CID and optionals). + +export interface RawPBLink { + Name: string, + Tsize: number, + Hash: Uint8Array +} + +export interface RawPBNode { + Data: Uint8Array, + Links: RawPBLink[] +} + diff --git a/pb-decode.js b/src/pb-decode.js similarity index 85% rename from pb-decode.js rename to src/pb-decode.js index bb2f922..8325b0d 100644 --- a/pb-decode.js +++ b/src/pb-decode.js @@ -1,5 +1,18 @@ const textDecoder = new TextDecoder() +/** + * @typedef {import('./interface').RawPBLink} RawPBLink + */ + +/** + * @typedef {import('./interface').RawPBNode} RawPBNode + */ + +/** + * @param {Uint8Array} bytes + * @param {number} offset + * @returns {[number, number]} + */ function decodeVarint (bytes, offset) { let v = 0 @@ -22,6 +35,11 @@ function decodeVarint (bytes, offset) { return [v, offset] } +/** + * @param {Uint8Array} bytes + * @param {number} offset + * @returns {[Uint8Array, number]} + */ function decodeBytes (bytes, offset) { let byteLen ;[byteLen, offset] = decodeVarint(bytes, offset) @@ -39,6 +57,11 @@ function decodeBytes (bytes, offset) { return [bytes.subarray(offset, postOffset), postOffset] } +/** + * @param {Uint8Array} bytes + * @param {number} index + * @returns {[number, number, number]} + */ function decodeKey (bytes, index) { let wire ;[wire, index] = decodeVarint(bytes, index) @@ -46,7 +69,12 @@ function decodeKey (bytes, index) { return [wire & 0x7, wire >> 3, index] } +/** + * @param {Uint8Array} bytes + * @returns {RawPBLink} + */ function decodeLink (bytes) { + /** @type {RawPBLink} */ const link = {} const l = bytes.length let index = 0 @@ -106,10 +134,16 @@ function decodeLink (bytes) { return link } -function decodeNode (bytes) { +/** + * @param {Uint8Array} bytes + * @returns {RawPBNode} + */ +export function decodeNode (bytes) { const l = bytes.length let index = 0 + /** @type {RawPBLink[]} */ const links = [] + /** @type {Uint8Array|void} */ let data while (index < l) { @@ -144,6 +178,7 @@ function decodeNode (bytes) { throw new Error('protobuf: (PBNode) unexpected end of data') } + /** @type {RawPBNode} */ const node = {} if (data) { node.Data = data @@ -151,5 +186,3 @@ function decodeNode (bytes) { node.Links = links return node } - -export default decodeNode diff --git a/pb-encode.js b/src/pb-encode.js similarity index 77% rename from pb-encode.js rename to src/pb-encode.js index 09c37bc..b73791a 100644 --- a/pb-encode.js +++ b/src/pb-encode.js @@ -2,9 +2,24 @@ const textEncoder = new TextEncoder() const maxInt32 = 2 ** 32 const maxUInt32 = 2 ** 31 +/** + * @typedef {import('./interface').RawPBLink} RawPBLink + */ + +/** + * @typedef {import('./interface').RawPBNode} RawPBNode + */ + // the encoders work backward from the end of the bytes array -// encodeLink() is passed a slice of the parent byte array that ends where this -// link needs to end, so it packs to the right-most part of the passed `bytes` + +/** + * encodeLink() is passed a slice of the parent byte array that ends where this + * link needs to end, so it packs to the right-most part of the passed `bytes` + * + * @param {RawPBLink} link + * @param {Uint8Array} bytes + * @returns {number} + */ function encodeLink (link, bytes) { let i = bytes.length @@ -37,8 +52,13 @@ function encodeLink (link, bytes) { return bytes.length - i } -// encodes a PBNode into a new byte array of precisely the correct size -function encodeNode (node) { +/** + * Encodes a PBNode into a new byte array of precisely the correct size + * + * @param {RawPBNode} node + * @returns {Uint8Array} + */ +export function encodeNode (node) { const size = sizeNode(node) const bytes = new Uint8Array(size) let i = size @@ -62,7 +82,12 @@ function encodeNode (node) { return bytes } -// work out exactly how many bytes this link takes up +/** + * work out exactly how many bytes this link takes up + * + * @param {RawPBLink} link + * @returns + */ function sizeLink (link) { let n = 0 @@ -83,7 +108,12 @@ function sizeLink (link) { return n } -// work out exactly how many bytes this node takes up +/** + * Work out exactly how many bytes this node takes up + * + * @param {RawPBNode} node +* @returns {number} + */ function sizeNode (node) { let n = 0 @@ -102,6 +132,12 @@ function sizeNode (node) { return n } +/** + * @param {Uint8Array} bytes + * @param {number} offset + * @param {number} v + * @returns {number} + */ function encodeVarint (bytes, offset, v) { offset -= sov(v) const base = offset @@ -121,7 +157,12 @@ function encodeVarint (bytes, offset, v) { return base } -// size of varint +/** + * size of varint + * + * @param {number} x + * @returns {number} + */ function sov (x) { if (x % 2 === 0) { x++ @@ -129,7 +170,12 @@ function sov (x) { return Math.floor((len64(x) + 6) / 7) } -// golang math/bits, how many bits does it take to represent this integer? +/** + * golang math/bits, how many bits does it take to represent this integer? + * + * @param {number} x + * @returns {number} + */ function len64 (x) { let n = 0 if (x >= maxInt32) { @@ -166,5 +212,3 @@ const len8tab = [ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ] - -export default encodeNode diff --git a/test/test-basics.js b/test/test-basics.js index fd55642..9891ea1 100644 --- a/test/test-basics.js +++ b/test/test-basics.js @@ -1,15 +1,24 @@ /* eslint-env mocha */ import chai from 'chai' +// @ts-ignore import chaiSubset from 'chai-subset' import { bytes } from 'multiformats' -import CID from 'multiformats/cid' +import { CID } from 'multiformats/cid' import { sha256 } from 'multiformats/hashes/sha2' import { encode, decode, code, prepare } from '@ipld/dag-pb' chai.use(chaiSubset) const { assert } = chai +/** + * @typedef {import('@ipld/dag-pb').PBLink} PBLink + */ + +/** + * @param {PBLink[]} links + * @returns + */ function linkCidsToStrings (links) { return links.map((l) => { return { @@ -50,6 +59,7 @@ describe('Basics', () => { assert.instanceOf(result, Uint8Array) const node = decode(result) + // @ts-ignore chaiSubset assert.containSubset(linkCidsToStrings(node.Links), linkCidsToStrings([{ Hash: CID.parse('QmWDtUQj38YLW8v3q4A6LwPn4vYKEbuKWpgSm6bjKW6Xfe') }])) @@ -65,6 +75,7 @@ describe('Basics', () => { assert.instanceOf(result, Uint8Array) const node = decode(result) + // @ts-ignore chaiSubset assert.containSubset(linkCidsToStrings(node.Links), linkCidsToStrings(links)) }) diff --git a/test/test-compat.js b/test/test-compat.js index 7d983f8..fa8af80 100644 --- a/test/test-compat.js +++ b/test/test-compat.js @@ -4,28 +4,32 @@ import chai from 'chai' import { bytes } from 'multiformats' -import CID from 'multiformats/cid' +import { CID } from 'multiformats/cid' import { encode, decode } from '@ipld/dag-pb' -import encodeNode from '../pb-encode.js' -import decodeNode from '../pb-decode.js' +import { encodeNode } from '../src/pb-encode.js' +import { decodeNode } from '../src/pb-decode.js' const { assert } = chai // Hash is raw+identity 0x0001020304 CID(bafkqabiaaebagba) const acid = CID.decode(Uint8Array.from([1, 85, 0, 5, 0, 1, 2, 3, 4])) +/** + * @param {{node:any, expectedBytes:string, expectedForm:string}} testCase + * @param {boolean} [bypass] + */ function verifyRoundTrip (testCase, bypass) { const actualBytes = (bypass ? encodeNode : encode)(testCase.node) assert.strictEqual(bytes.toHex(actualBytes), testCase.expectedBytes) const roundTripNode = (bypass ? decodeNode : decode)(actualBytes) if (roundTripNode.Data) { + // @ts-ignore this can't be a string, but we're making it so for ease of test roundTripNode.Data = bytes.toHex(roundTripNode.Data) } if (roundTripNode.Links) { for (const link of roundTripNode.Links) { if (link.Hash) { - // they're CIDs which don't stringify well - // or consistent with our fixtures + // @ts-ignore this can't be a string, but we're making it so for ease of test link.Hash = bytes.toHex(bypass ? link.Hash : link.Hash.bytes) } } diff --git a/test/test-edges.js b/test/test-edges.js index c2703e5..f347aa2 100644 --- a/test/test-edges.js +++ b/test/test-edges.js @@ -2,8 +2,8 @@ import chai from 'chai' import { bytes } from 'multiformats' -import encodeNode from '../pb-encode.js' -import decodeNode from '../pb-decode.js' +import { encodeNode } from '../src/pb-encode.js' +import { decodeNode } from '../src/pb-decode.js' const { assert } = chai const acidBytes = Uint8Array.from([1, 85, 0, 5, 0, 1, 2, 3, 4]) @@ -14,24 +14,35 @@ describe('Edge cases', () => { let form = { Links: [{ Hash: acidBytes, Tsize: Number.MAX_SAFE_INTEGER - 1 }] } let expected = '12140a0901550005000102030418feffffffffffff0f' - assert.strictEqual(bytes.toHex(encodeNode(form)), expected) + assert.strictEqual( + bytes.toHex( + // @ts-ignore RawPBLink needs Name but we don't have one + encodeNode(form)) + , expected) assert.deepEqual(decodeNode(bytes.fromHex(expected)), form) form = { Links: [{ Hash: acidBytes, Tsize: Number.MAX_SAFE_INTEGER }] } expected = '12140a0901550005000102030418ffffffffffffff0f' - assert.strictEqual(bytes.toHex(encodeNode(form)), expected) + assert.strictEqual( + bytes.toHex( + // @ts-ignore RawPBLink needs Name but we don't have one + encodeNode(form)) + , expected) assert.deepEqual(decodeNode(bytes.fromHex(expected)), form) // too big, we can decode but not encode, it's a tiny bit too hard to bother form = { Links: [{ Hash: acidBytes, Tsize: Number.MAX_SAFE_INTEGER + 1 }] } expected = '12140a09015500050001020304188080808080808010' - assert.throws(() => encodeNode(form), /too large/) + assert.throws(() => { + // @ts-ignore RawPBLink needs Name but we don't have one + encodeNode(form) + }, /too large/) assert.deepEqual(decodeNode(bytes.fromHex(expected)), form) }) it('fail to encode negative large', () => { assert.throws(() => { - encodeNode({ Links: [{ Hash: acidBytes, Tsize: -1 }] }) + encodeNode({ Links: [{ Hash: acidBytes, Name: 'yoik', Tsize: -1 }], Data: new Uint8Array(0) }) }, /negative/) }) }) diff --git a/test/test-forms.js b/test/test-forms.js index 8f32fcd..439f156 100644 --- a/test/test-forms.js +++ b/test/test-forms.js @@ -1,16 +1,20 @@ /* eslint-env mocha */ import chai from 'chai' -import CID from 'multiformats/cid' +import { CID } from 'multiformats/cid' import { encode, validate } from '@ipld/dag-pb' const { assert } = chai +/** + * @typedef {import('@ipld/dag-pb').PBNode} PBNode + */ + const acid = CID.parse('bafkqabiaaebagba') describe('Forms (Data Model)', () => { it('validate good forms', () => { - const doesntThrow = (good) => { + const doesntThrow = (/** @type {PBNode} */ good) => { validate(good) const byts = encode(good) assert.instanceOf(byts, Uint8Array) @@ -38,9 +42,15 @@ describe('Forms (Data Model)', () => { }) it('validate fails bad forms', () => { - const throws = (bad) => { - assert.throws(() => validate(bad)) - assert.throws(() => encode(bad)) + const throws = (/** @type {any} */ bad) => { + assert.throws(() => { + // @ts-ignore because type checking is the point + validate(bad) + }) + assert.throws(() => { + // @ts-ignore because type checking is the point + encode(bad) + }) } for (const bad of [true, false, null, 0, 101, -101, 'blip', [], Infinity, Symbol.for('boop'), Uint8Array.from([1, 2, 3])]) { diff --git a/test/test-pb.js b/test/test-pb.js index 2bf140c..214d6fe 100644 --- a/test/test-pb.js +++ b/test/test-pb.js @@ -2,7 +2,7 @@ import chai from 'chai' import { bytes } from 'multiformats' -import decodeNode from '../pb-decode.js' +import { decodeNode } from '../src/pb-decode.js' const { assert } = chai diff --git a/test/ts-use/.gitignore b/test/ts-use/.gitignore new file mode 100644 index 0000000..6881777 --- /dev/null +++ b/test/ts-use/.gitignore @@ -0,0 +1,3 @@ +node_modules +src/main.js +tsconfig.tsbuildinfo diff --git a/test/ts-use/package.json b/test/ts-use/package.json new file mode 100644 index 0000000..76c1008 --- /dev/null +++ b/test/ts-use/package.json @@ -0,0 +1,11 @@ +{ + "name": "ts-use", + "private": true, + "dependencies": { + "@ipld/dag-pb": "file:../../dist/", + "multiformats": "file:../../node_modules/multiformats" + }, + "scripts": { + "test": "npm install && npx -p typescript tsc && node src/main.js" + } +} diff --git a/test/ts-use/src/main.ts b/test/ts-use/src/main.ts new file mode 100644 index 0000000..892b3ae --- /dev/null +++ b/test/ts-use/src/main.ts @@ -0,0 +1,49 @@ +import { deepStrictEqual } from 'assert' + +import { BlockEncoder, BlockDecoder, BlockCodec } from 'multiformats/codecs/interface' +import * as dagPB from '@ipld/dag-pb' +import { PBNode } from '@ipld/dag-pb' + +const exampleNode:PBNode = { Data: Uint8Array.from([0, 1, 2, 3, 4]), Links: [] } +const exampleBytes = [0x0a, 5, 0, 1, 2, 3, 4] + +const main = () => { + // make sure we have a full CodecFeature + useCodecFeature(dagPB) +} + +function useCodecFeature (codec: BlockCodec<0x70, any>) { + // use only as a BlockEncoder + useEncoder(codec) + + // use only as a BlockDecoder + useDecoder(codec) + + // use as a full BlockCodec which does both BlockEncoder & BlockDecoder + useBlockCodec(codec) +} + +function useEncoder (encoder: BlockEncoder) { + deepStrictEqual(encoder.code, 0x70) + deepStrictEqual(encoder.name, 'dag-pb') + deepStrictEqual(Array.from(encoder.encode(exampleNode)), exampleBytes) + console.log('[TS] ✓ { encoder: BlockEncoder }') +} + +function useDecoder (decoder: BlockDecoder) { + deepStrictEqual(decoder.code, 0x70) + deepStrictEqual(decoder.decode(Uint8Array.from(exampleBytes)), exampleNode) + console.log('[TS] ✓ { decoder: BlockDecoder }') +} + +function useBlockCodec (blockCodec: BlockCodec) { + deepStrictEqual(blockCodec.code, 0x70) + deepStrictEqual(blockCodec.name, 'dag-pb') + deepStrictEqual(Array.from(blockCodec.encode(exampleNode)), exampleBytes) + deepStrictEqual(blockCodec.decode(Uint8Array.from(exampleBytes)), exampleNode) + console.log('[TS] ✓ {}:BlockCodec') +} + +main() + +export default main diff --git a/test/ts-use/tsconfig.json b/test/ts-use/tsconfig.json new file mode 100644 index 0000000..ff14759 --- /dev/null +++ b/test/ts-use/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "strict": true, + "moduleResolution": "node", + "noImplicitAny": true, + "skipLibCheck": true, + "incremental": true + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..3efe946 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,42 @@ +{ + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": false, + "noImplicitAny": true, + "noImplicitThis": true, + "noFallthroughCasesInSwitch": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "strictFunctionTypes": false, + "strictNullChecks": true, + "strictPropertyInitialization": true, + "strictBindCallApply": true, + "strict": true, + "alwaysStrict": true, + "esModuleInterop": true, + "target": "ES2018", + "moduleResolution": "node", + "declaration": true, + "declarationMap": true, + "outDir": "types", + "skipLibCheck": true, + "stripInternal": true, + "resolveJsonModule": true, + "emitDeclarationOnly": true, + "baseUrl": ".", + "paths": { + "@ipld/dag-pb": [ + "src" + ] + } + }, + "exclude": [ + "node_modules", + "esm", + "cjs", + "example*.js" + ], + "compileOnSave": false +}