diff --git a/package.json b/package.json index 86c29525..7849794f 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "dist" ], "scripts": { - "prepare": "aegir build", + "prepare": "aegir build --no-bundle", "lint": "aegir lint", "test:browser": "aegir test --target browser", "test:node": "aegir test --target node", @@ -41,12 +41,12 @@ "repository": "github:multiformats/js-multihash", "dependencies": { "multibase": "^3.1.0", - "uint8arrays": "^1.0.0", + "uint8arrays": "^2.0.5", "varint": "^6.0.0" }, "devDependencies": { - "aegir": "^29.0.1", - "ipfs-utils": "^5.0.0" + "aegir": "^30.3.0", + "ipfs-utils": "^5.0.1" }, "eslintConfig": { "extends": "ipfs" diff --git a/src/constants.js b/src/constants.js index 29fb7d4c..5790415b 100644 --- a/src/constants.js +++ b/src/constants.js @@ -13,7 +13,7 @@ */ /** - * @type { Object } + * @type { Record } */ const names = Object.freeze({ 'identity': 0x00, diff --git a/src/index.js b/src/index.js index 5b0a4dd2..09809c08 100644 --- a/src/index.js +++ b/src/index.js @@ -16,7 +16,8 @@ const codes = /** @type {import('./types').CodeNameMap} */({}) // eslint-disable-next-line guard-for-in for (const key in names) { - codes[names[key]] = key + const name = /** @type {HashName} */(key) + codes[names[name]] = name } /** @@ -86,7 +87,7 @@ function decode (bytes) { throw new Error('multihash too short. must be > 2 bytes.') } - const code = varint.decode(bytes) + const code = /** @type {HashCode} */(varint.decode(bytes)) if (!isValidCode(code)) { throw new Error(`multihash unknown function code: 0x${code.toString(16)}`) } @@ -166,6 +167,7 @@ function coerceCode (name) { throw new Error(`Hash function code should be a number. Got: ${code}`) } + // @ts-ignore if (codes[code] === undefined && !isAppCode(code)) { throw new Error(`Unrecognized function code: ${code}`) } diff --git a/src/types.ts b/src/types.ts index 63df2de5..40e2c21b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import { HashCode, HashName } from './constants.js' +import type { HashCode, HashName } from './constants.js' export type CodeNameMap = Record export type NameCodeMap = Record diff --git a/test/index.spec.js b/test/index.spec.js index f39894bf..3d531881 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -12,7 +12,20 @@ const uint8ArrayToString = require('uint8arrays/to-string') const uint8ArrayFromString = require('uint8arrays/from-string') const uint8ArrayEquals = require('uint8arrays/equals') +/** + * @typedef {import('../src/constants.js').HashName} HashName + * @typedef {import('../src/constants.js').HashCode} HashCode + */ + +/** + * @param {string | number} code + * @param {number} size + * @param {string} hex + */ function sample (code, size, hex) { + /** + * @param {number | string} i + */ const toHex = (i) => { if (typeof i === 'string') { return i @@ -23,6 +36,10 @@ function sample (code, size, hex) { return uint8ArrayFromString(`${toHex(code)}${toHex(size)}${hex}`, 'base16') } +/** + * @param {string} description + * @param {(test: { encodeText: (text: string) => Uint8Array, encodeHex: (text: string) => Uint8Array }) => void} test + */ const they = (description, test) => { it(description, () => test({ encodeText: (text) => uint8ArrayFromString(text), @@ -195,7 +212,7 @@ describe('multihash', () => { it('invalid', () => { invalidCases.forEach((test) => { expect( - () => mh.validate(sample(test.encoding.varint || test.code, test.size, test.hex)) + () => mh.validate(sample(test.code, test.size, test.hex)) ).to.throw() }) @@ -257,7 +274,7 @@ describe('multihash', () => { false ) - for (var m = 0x10; m <= 0xff; m++) { + for (let m = 0x10; m <= 0xff; m++) { expect( mh.isAppCode(m) ).to.equal( @@ -269,17 +286,18 @@ describe('multihash', () => { describe('coerceCode', () => { it('valid', () => { - /** @type {Partial> } */ const names = { sha1: 0x11, 'sha2-256': 0x12, 'sha2-512': 0x13, 'sha3-512': 0x14 } - - Object.keys(names).forEach((name) => { + /** @type {keyof typeof names} */ + let name + // eslint-disable-next-line guard-for-in + for (name in names) { expect( - mh.coerceCode(/** @type {import('../src/constants.js').HashName} */(name)) + mh.coerceCode(name) ).to.be.eql( names[name] ) @@ -289,7 +307,7 @@ describe('multihash', () => { ).to.be.eql( names[name] ) - }) + } }) they('invalid', ({ encodeText }) => { @@ -309,6 +327,7 @@ describe('multihash', () => { }) expect( + // @ts-expect-error () => mh.coerceCode(encodeText('hello')) ).to.throw( /should be a number/ diff --git a/tsconfig.json b/tsconfig.json index e605b61a..c5150deb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,10 +1,15 @@ { "extends": "./node_modules/aegir/src/config/tsconfig.aegir.json", "compilerOptions": { - "outDir": "dist" + "outDir": "dist", + "baseUrl": "./", + "paths": { + "*": ["./types/*"] + } }, "include": [ "test", // remove this line if you don't want to type-check tests - "src" + "src", + "types" ] } diff --git a/types/varint/index.d.ts b/types/varint/index.d.ts new file mode 100644 index 00000000..108baaff --- /dev/null +++ b/types/varint/index.d.ts @@ -0,0 +1,39 @@ +export const encode: { + /** + * Encodes `num` into `buffer` starting at `offset`. returns `buffer`, with the encoded varint written into it. + * `varint.encode.bytes` will now be set to the number of bytes modified. + */ + (num: number, buffer: Uint8Array, offset?: number): Uint8Array + + /** + * Encodes `num` into `array` starting at `offset`. returns `array`, with the encoded varint written into it. + * If `array` is not provided, it will default to a new array. + * `varint.encode.bytes` will now be set to the number of bytes modified. + */ + (num: number, array?: number[], offset?: number): number[] + + /** + * Similar to `decode.bytes` when encoding a number it can be useful to know how many bytes where written (especially if you pass an output array). + * You can access this via `varint.encode.bytes` which holds the number of bytes written in the last encode. + */ + bytes: number +} + +export const decode: { + /** + * Decodes `data`, which can be either a buffer or array of integers, from position `offset` or default 0 and returns the decoded original integer. + * Throws a `RangeError` when `data` does not represent a valid encoding. + */ + (buf: Uint8Array | Buffer | number[], offset?: number): number + + /** + * If you also require the length (number of bytes) that were required to decode the integer you can access it via `varint.decode.bytes`. + * This is an integer property that will tell you the number of bytes that the last .decode() call had to use to decode. + */ + bytes: number +} + +/** + * returns the number of bytes this number will be encoded as, up to a maximum of 8. + */ +export function encodingLength (num: number): number diff --git a/update-constants.js b/update-constants.js index 45dc7870..5f22fec5 100644 --- a/update-constants.js +++ b/update-constants.js @@ -43,7 +43,7 @@ const run = async () => { */ /** - * @type { Object } + * @type { Record } */ const names = Object.freeze({ ${processed}