From 6c2591f71363f6fc7aa9eaae655c770917e6dee4 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Fri, 17 Dec 2021 11:23:37 +0100 Subject: [PATCH] feat: convert to typescript Converts this module to typescript with ESM-only publishing. Part of the wider effor to move libp2p to the bright new future of proper types and ESM: https://github.com/libp2p/js-libp2p/issues/1021 --- .github/workflows/main.yml | 148 +++++++------- .gitignore | 3 +- package.json | 59 +++--- src/{codec.js => codec.ts} | 154 +++++--------- src/{convert.js => convert.ts} | 120 ++++------- src/{index.js => index.ts} | 190 ++++++++---------- src/{ip.js => ip.ts} | 54 ++--- src/protocols-table.js | 105 ---------- src/protocols-table.ts | 83 ++++++++ src/resolvers/dns.browser.js | 7 - src/resolvers/dns.browser.ts | 3 + src/resolvers/dns.js | 3 - src/resolvers/dns.ts | 3 + src/resolvers/{index.js => index.ts} | 26 +-- src/types.d.ts | 14 -- test/{codec.spec.js => codec.spec.ts} | 10 +- test/{convert.spec.js => convert.spec.ts} | 30 ++- test/{index.spec.js => index.spec.ts} | 40 ++-- test/{protocols.spec.js => protocols.spec.ts} | 12 +- test/{resolvers.spec.js => resolvers.spec.ts} | 19 +- tsconfig.json | 10 +- 21 files changed, 448 insertions(+), 645 deletions(-) rename src/{codec.js => codec.ts} (53%) rename src/{convert.js => convert.ts} (62%) rename src/{index.js => index.ts} (80%) rename src/{ip.js => ip.ts} (64%) delete mode 100644 src/protocols-table.js create mode 100644 src/protocols-table.ts delete mode 100644 src/resolvers/dns.browser.js create mode 100644 src/resolvers/dns.browser.ts delete mode 100644 src/resolvers/dns.js create mode 100644 src/resolvers/dns.ts rename src/resolvers/{index.js => index.ts} (55%) delete mode 100644 src/types.d.ts rename test/{codec.spec.js => codec.spec.ts} (87%) rename test/{convert.spec.js => convert.spec.ts} (61%) rename test/{index.spec.js => index.spec.ts} (97%) rename test/{protocols.spec.js => protocols.spec.ts} (68%) rename test/{resolvers.spec.js => resolvers.spec.ts} (93%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e06e02db..c1b9c1bd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,78 +1,78 @@ name: ci on: - push: - branches: - - master - pull_request: - branches: - - master + push: + branches: + - master + pull_request: + branches: + - master jobs: - check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: npm install - - run: npx aegir lint - - run: npx aegir ts -p check - - run: npx aegir build - - run: npx aegir dep-check - - uses: ipfs/aegir/actions/bundle-size@master - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - test-node: - needs: check - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [windows-latest, ubuntu-latest, macos-latest] - node: [14, 15] - fail-fast: true - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node }} - - run: npm install - - run: npx aegir test -t node --bail --cov - - uses: codecov/codecov-action@v1 - test-chrome: - needs: check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: microsoft/playwright-github-action@v1 - - run: npm install - - run: npx aegir test -t browser --bail --cov - - run: npx aegir test -t webworker --bail - - uses: codecov/codecov-action@v1 - test-firefox: - needs: check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: microsoft/playwright-github-action@v1 - - run: npm install - - run: npx aegir test -t browser -t webworker --bail -- --browser firefox - test-webkit: - needs: check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: microsoft/playwright-github-action@v1 - - run: npm install - - run: npx aegir test -t browser -t webworker --bail -- --browser webkit - test-electron-main: - needs: check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: npm install - - run: npx xvfb-maybe aegir test -t electron-main --bail - test-electron-renderer: - needs: check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: npm install - - run: npx xvfb-maybe aegir test -t electron-renderer --bail + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: npm run lint + - run: npm run build + - run: npm run dep-check + test-node: + needs: check + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + node: [16] + fail-fast: true + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node }} + - run: npm install + - run: npm run build + - run: npm run test:node -- --bail --cov + - uses: codecov/codecov-action@v1 + test-chrome: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 16 + - run: npm install + - run: npm run build + - run: npm run test:browser -- -t browser -t webworker --bail + test-firefox: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 16 + - run: npm install + - run: npm run build + - run: npm run test:browser -- -t browser -t webworker --bail -- --browser firefox + test-electron-main: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 16 + - run: npm install + - run: npm run build + - run: npx xvfb-maybe npm run test:electron --bail + # test-electron-renderer: + # needs: check + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v2 + # - uses: actions/setup-node@v2 + # with: + # node-version: 16 + # - run: npm install + # - run: npx xvfb-maybe aegir test -t electron-renderer --bail diff --git a/.gitignore b/.gitignore index 1a9d6b63..dd7f96ea 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,5 @@ test/test-data/go-ipfs-repo/LOG.old # while testing npm5 package-lock.json -yarn.lock \ No newline at end of file +yarn.lock +.nyc_output \ No newline at end of file diff --git a/package.json b/package.json index 2aa9442f..750f1326 100644 --- a/package.json +++ b/package.json @@ -2,25 +2,35 @@ "name": "multiaddr", "version": "10.0.1", "description": "multiaddr implementation (binary + string representation of network addresses)", - "leadMaintainer": "Jacob Heun ", - "main": "src/index.js", - "types": "dist/src/index.d.ts", - "scripts": { - "lint": "aegir lint", - "test": "npm run test:node && npm run test:browser", - "test:node": "aegir test --ts -t node", - "test:browser": "aegir test -t browser", - "prepare": "aegir build", - "release": "aegir release", - "release-minor": "aegir release --type minor", - "release-major": "aegir release --type major", - "docs": "aegir docs", - "size": "aegir build -b" - }, + "type": "module", + "types": "./dist/src/index.d.ts", "files": [ "src", - "dist" + "dist/src", + "!**/*.tsbuildinfo" ], + "eslintConfig": { + "extends": "ipfs", + "parserOptions": { + "sourceType": "module" + } + }, + "scripts": { + "pretest": "npm run build", + "test": "aegir test -f ./dist/test/**/*.js", + "test:browser": "aegir test -t browser -f ./dist/test/**/*.js", + "test:node": "aegir test -t node -f ./dist/test/**/*.js", + "test:electron": "aegir test -t electron-main -f ./dist/test/**/*.js", + "lint": "aegir ts -p check && aegir lint", + "release": "aegir release --docs", + "release-minor": "aegir release --target node --type minor --docs", + "release-major": "aegir release --type major --docs", + "build": "tsc", + "dep-check": "aegir dep-check dist/src/**/*.js dist/test/**/*.js" + }, + "browser": { + "./dist/src/resolvers/dns.js": "./dist/src/resolvers/dns.browser.js" + }, "repository": "github:multiformats/js-multiaddr", "keywords": [ "multiaddr", @@ -30,11 +40,8 @@ "license": "MIT", "bugs": "https://github.com/multiformats/js-multiaddr/issues", "homepage": "https://github.com/multiformats/js-multiaddr", - "browser": { - "./src/resolvers/dns.js": "./src/resolvers/dns.browser.js" - }, "dependencies": { - "dns-over-http-resolver": "^1.2.3", + "dns-over-http-resolver": "^2.0.1", "err-code": "^3.0.1", "is-ip": "^3.1.0", "multiformats": "^9.4.5", @@ -43,18 +50,10 @@ }, "devDependencies": { "@types/varint": "^6.0.0", - "aegir": "^35.0.1", - "sinon": "^11.1.1", + "aegir": "^36.1.1", + "sinon": "^12.0.1", "util": "^0.12.3" }, - "aegir": { - "build": { - "bundlesizeMax": "22kB" - } - }, - "eslintConfig": { - "extends": "ipfs" - }, "contributors": [ "David Dias ", "Jacob Heun ", diff --git a/src/codec.js b/src/codec.ts similarity index 53% rename from src/codec.js rename to src/codec.ts index 66bc232b..44829df4 100644 --- a/src/codec.js +++ b/src/codec.ts @@ -1,42 +1,14 @@ -'use strict' +import { convertToBytes, convertToString } from './convert.js' +import { getProtocol } from './protocols-table.js' +import varint from 'varint' +import { concat as uint8ArrayConcat } from 'uint8arrays/concat' +import { toString as uint8ArrayToString } from 'uint8arrays/to-string' +import type { Protocol } from './protocols-table.js' -const convert = require('./convert') -const protocols = require('./protocols-table') -const varint = require('varint') -const { concat: uint8ArrayConcat } = require('uint8arrays/concat') -const { toString: uint8ArrayToString } = require('uint8arrays/to-string') - -// export codec -module.exports = { - stringToStringTuples, - stringTuplesToString, - - tuplesToStringTuples, - stringTuplesToTuples, - - bytesToTuples, - tuplesToBytes, - - bytesToString, - stringToBytes, - - fromString, - fromBytes, - validateBytes, - isValidBytes, - cleanPath, - - ParseError, - protoFromTuple, - - sizeForAddr -} - -// string -> [[str name, str addr]... ] /** - * @param {string} str + * string -> [[str name, str addr]... ] */ -function stringToStringTuples (str) { +export function stringToStringTuples (str: string) { const tuples = [] const parts = str.split('/').slice(1) // skip first empty elem if (parts.length === 1 && parts[0] === '') { @@ -45,7 +17,7 @@ function stringToStringTuples (str) { for (let p = 0; p < parts.length; p++) { const part = parts[p] - const proto = protocols(part) + const proto = getProtocol(part) if (proto.size === 0) { tuples.push([part]) @@ -58,7 +30,7 @@ function stringToStringTuples (str) { } // if it's a path proto, take the rest - if (proto.path) { + if (proto.path === true) { tuples.push([ part, // TODO: should we need to check each path part to see if it's a proto? @@ -75,17 +47,15 @@ function stringToStringTuples (str) { return tuples } -// [[str name, str addr]... ] -> string /** - * @param {[number, string?][]} tuples + * [[str name, str addr]... ] -> string */ -function stringTuplesToString (tuples) { - /** @type {Array} */ - const parts = [] +export function stringTuplesToString (tuples: Array<[number, string?]>) { + const parts: string[] = [] tuples.map((tup) => { const proto = protoFromTuple(tup) parts.push(proto.name) - if (tup.length > 1) { + if (tup.length > 1 && tup[1] != null) { parts.push(tup[1]) } return null @@ -94,19 +64,17 @@ function stringTuplesToString (tuples) { return cleanPath(parts.join('/')) } -// [[str name, str addr]... ] -> [[int code, Uint8Array]... ] /** - * @param {Array} tuples - * @returns {[number , Uint8Array?][]} + * [[str name, str addr]... ] -> [[int code, Uint8Array]... ] */ -function stringTuplesToTuples (tuples) { +export function stringTuplesToTuples (tuples: Array): Array<[number, Uint8Array?]> { return tuples.map((tup) => { if (!Array.isArray(tup)) { tup = [tup] } const proto = protoFromTuple(tup) if (tup.length > 1) { - return [proto.code, convert.toBytes(proto.code, tup[1])] + return [proto.code, convertToBytes(proto.code, tup[1])] } return [proto.code] }) @@ -116,31 +84,26 @@ function stringTuplesToTuples (tuples) { * Convert tuples to string tuples * * [[int code, Uint8Array]... ] -> [[int code, str addr]... ] - * - * @param {Array<[number, Uint8Array?]>} tuples - * @returns {Array<[number, string?]>} */ - -function tuplesToStringTuples (tuples) { +export function tuplesToStringTuples (tuples: Array<[number, Uint8Array?]>): Array<[number, string?]> { return tuples.map(tup => { const proto = protoFromTuple(tup) - if (tup[1]) { - return [proto.code, convert.toString(proto.code, tup[1])] + if (tup[1] != null) { + return [proto.code, convertToString(proto.code, tup[1])] } return [proto.code] }) } -// [[int code, Uint8Array ]... ] -> Uint8Array /** - * @param {[number, Uint8Array?][]} tuples + * [[int code, Uint8Array ]... ] -> Uint8Array */ -function tuplesToBytes (tuples) { - return fromBytes(uint8ArrayConcat(tuples.map((/** @type {any[]} */ tup) => { +export function tuplesToBytes (tuples: Array<[number, Uint8Array?]>) { + return fromBytes(uint8ArrayConcat(tuples.map((tup) => { const proto = protoFromTuple(tup) let buf = Uint8Array.from(varint.encode(proto.code)) - if (tup.length > 1) { + if (tup.length > 1 && tup[1] != null) { buf = uint8ArrayConcat([buf, tup[1]]) // add address buffer } @@ -148,11 +111,7 @@ function tuplesToBytes (tuples) { }))) } -/** - * @param {import("./types").Protocol} p - * @param {Uint8Array | number[]} addr - */ -function sizeForAddr (p, addr) { +export function sizeForAddr (p: Protocol, addr: Uint8Array | number[]) { if (p.size > 0) { return p.size / 8 } else if (p.size === 0) { @@ -163,20 +122,14 @@ function sizeForAddr (p, addr) { } } -/** - * - * @param {Uint8Array} buf - * @returns {Array<[number, Uint8Array?]>} - */ -function bytesToTuples (buf) { - /** @type {Array<[number, Uint8Array?]>} */ - const tuples = [] +export function bytesToTuples (buf: Uint8Array): Array<[number, Uint8Array?]> { + const tuples: Array<[number, Uint8Array?]> = [] let i = 0 while (i < buf.length) { const code = varint.decode(buf, i) const n = varint.decode.bytes - const p = protocols(code) + const p = getProtocol(code) const size = sizeForAddr(p, buf.slice(i + n)) @@ -201,21 +154,19 @@ function bytesToTuples (buf) { return tuples } -// Uint8Array -> String /** - * @param {Uint8Array} buf + * Uint8Array -> String */ -function bytesToString (buf) { +export function bytesToString (buf: Uint8Array) { const a = bytesToTuples(buf) const b = tuplesToStringTuples(a) return stringTuplesToString(b) } -// String -> Uint8Array /** - * @param {string} str + * String -> Uint8Array */ -function stringToBytes (str) { +export function stringToBytes (str: string) { str = cleanPath(str) const a = stringToStringTuples(str) const b = stringTuplesToTuples(a) @@ -223,28 +174,25 @@ function stringToBytes (str) { return tuplesToBytes(b) } -// String -> Uint8Array /** - * @param {string} str + * String -> Uint8Array */ -function fromString (str) { +export function fromString (str: string) { return stringToBytes(str) } -// Uint8Array -> Uint8Array /** - * @param {Uint8Array} buf + * Uint8Array -> Uint8Array */ -function fromBytes (buf) { +export function fromBytes (buf: Uint8Array) { const err = validateBytes(buf) - if (err) throw err + if (err != null) { + throw err + } return Uint8Array.from(buf) // copy } -/** - * @param {Uint8Array} buf - */ -function validateBytes (buf) { +export function validateBytes (buf: Uint8Array) { try { bytesToTuples(buf) // try to parse. will throw if breaks } catch (err) { @@ -252,31 +200,19 @@ function validateBytes (buf) { } } -/** - * @param {Uint8Array} buf - */ -function isValidBytes (buf) { +export function isValidBytes (buf: Uint8Array) { return validateBytes(buf) === undefined } -/** - * @param {string} str - */ -function cleanPath (str) { +export function cleanPath (str: string) { return '/' + str.trim().split('/').filter((/** @type {any} */ a) => a).join('/') } -/** - * @param {string} str - */ -function ParseError (str) { +export function ParseError (str: string) { return new Error('Error parsing address: ' + str) } -/** - * @param {any[]} tup - */ -function protoFromTuple (tup) { - const proto = protocols(tup[0]) +export function protoFromTuple (tup: any[]) { + const proto = getProtocol(tup[0]) return proto } diff --git a/src/convert.js b/src/convert.ts similarity index 62% rename from src/convert.js rename to src/convert.ts index c3152010..e35613d2 100644 --- a/src/convert.js +++ b/src/convert.ts @@ -1,40 +1,31 @@ -'use strict' - -const ip = require('./ip') -const protocols = require('./protocols-table') -const { CID } = require('multiformats/cid') -const { base32 } = require('multiformats/bases/base32') -const { base58btc } = require('multiformats/bases/base58') -const Digest = require('multiformats/hashes/digest') -const varint = require('varint') -const { toString: uint8ArrayToString } = require('uint8arrays/to-string') -const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string') -const { concat: uint8ArrayConcat } = require('uint8arrays/concat') - -module.exports = Convert - -// converts (serializes) addresses + +import * as ip from './ip.js' +import { getProtocol } from './protocols-table.js' +import { CID } from 'multiformats/cid' +import { base32 } from 'multiformats/bases/base32' +import { base58btc } from 'multiformats/bases/base58' +import * as Digest from 'multiformats/hashes/digest' +import varint from 'varint' +import { toString as uint8ArrayToString } from 'uint8arrays/to-string' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { concat as uint8ArrayConcat } from 'uint8arrays/concat' + /** - * @param {string} proto - * @param {string | Uint8Array} a + * converts (serializes) addresses */ -function Convert (proto, a) { +export function convert (proto: string, a: string | Uint8Array) { if (a instanceof Uint8Array) { - return Convert.toString(proto, a) + return convertToString(proto, a) } else { - return Convert.toBytes(proto, a) + return convertToBytes(proto, a) } } /** * Convert [code,Uint8Array] to string - * - * @param {number|string} proto - * @param {Uint8Array} buf - * @returns {string} */ -Convert.toString = function convertToString (proto, buf) { - const protocol = protocols(proto) +export function convertToString (proto: number | string, buf: Uint8Array) { + const protocol = getProtocol(proto) switch (protocol.code) { case 4: // ipv4 case 41: // ipv6 @@ -65,8 +56,8 @@ Convert.toString = function convertToString (proto, buf) { } } -Convert.toBytes = function convertToBytes (/** @type {string | number } */ proto, /** @type {string} */ str) { - const protocol = protocols(proto) +export function convertToBytes (proto: string | number, str: string) { + const protocol = getProtocol(proto) switch (protocol.code) { case 4: // ipv4 return ip2bytes(str) @@ -98,31 +89,22 @@ Convert.toBytes = function convertToBytes (/** @type {string | number } */ proto } } -/** - * @param {string} ipString - */ -function ip2bytes (ipString) { +function ip2bytes (ipString: string) { if (!ip.isIP(ipString)) { throw new Error('invalid ip address') } return ip.toBytes(ipString) } -/** - * @param {Uint8Array} ipBuff - */ -function bytes2ip (ipBuff) { - const ipString = ip.toString(ipBuff) - if (!ipString || !ip.isIP(ipString)) { +function bytes2ip (ipBuff: Uint8Array) { + const ipString = ip.toString(ipBuff, 0, ipBuff.length) + if (ipString == null || !ip.isIP(ipString)) { throw new Error('invalid ip address') } return ipString } -/** - * @param {number} port - */ -function port2bytes (port) { +function port2bytes (port: number) { const buf = new ArrayBuffer(2) const view = new DataView(buf) view.setUint16(0, port) @@ -130,27 +112,18 @@ function port2bytes (port) { return new Uint8Array(buf) } -/** - * @param {Uint8Array} buf - */ -function bytes2port (buf) { +function bytes2port (buf: Uint8Array) { const view = new DataView(buf.buffer) return view.getUint16(buf.byteOffset) } -/** - * @param {string} str - */ -function str2bytes (str) { +function str2bytes (str: string) { const buf = uint8ArrayFromString(str) const size = Uint8Array.from(varint.encode(buf.length)) return uint8ArrayConcat([size, buf], size.length + buf.length) } -/** - * @param {Uint8Array} buf - */ -function bytes2str (buf) { +function bytes2str (buf: Uint8Array) { const size = varint.decode(buf) buf = buf.slice(varint.decode.bytes) @@ -161,10 +134,7 @@ function bytes2str (buf) { return uint8ArrayToString(buf) } -/** - * @param {string} hash - base58btc string - */ -function mh2bytes (hash) { +function mh2bytes (hash: string) { let mh if (hash[0] === 'Q' || hash[0] === '1') { @@ -180,11 +150,8 @@ function mh2bytes (hash) { /** * Converts bytes to bas58btc string - * - * @param {Uint8Array} buf - * @returns {string} base58btc string */ -function bytes2mh (buf) { +function bytes2mh (buf: Uint8Array) { const size = varint.decode(buf) const address = buf.slice(varint.decode.bytes) @@ -195,16 +162,13 @@ function bytes2mh (buf) { return uint8ArrayToString(address, 'base58btc') } -/** - * @param {string} str - */ -function onion2bytes (str) { +function onion2bytes (str: string) { const addr = str.split(':') if (addr.length !== 2) { - throw new Error('failed to parse onion addr: ' + addr + ' does not contain a port number') + throw new Error(`failed to parse onion addr: ["'${addr.join('", "')}'"]' does not contain a port number`) } if (addr[0].length !== 16) { - throw new Error('failed to parse onion addr: ' + addr[0] + ' not a Tor onion address.') + throw new Error(`failed to parse onion addr: ${addr[0]} not a Tor onion address.`) } // onion addresses do not include the multibase prefix, add it before decoding @@ -219,19 +183,16 @@ function onion2bytes (str) { return uint8ArrayConcat([buf, portBuf], buf.length + portBuf.length) } -/** - * @param {string} str - */ -function onion32bytes (str) { +function onion32bytes (str: string) { const addr = str.split(':') if (addr.length !== 2) { - throw new Error('failed to parse onion addr: ' + addr + ' does not contain a port number') + throw new Error(`failed to parse onion addr: ["'${addr.join('", "')}'"]' does not contain a port number`) } if (addr[0].length !== 56) { - throw new Error('failed to parse onion addr: ' + addr[0] + ' not a Tor onion3 address.') + throw new Error(`failed to parse onion addr: ${addr[0]} not a Tor onion3 address.`) } // onion addresses do not include the multibase prefix, add it before decoding - const buf = base32.decode('b' + addr[0]) + const buf = base32.decode(`b${addr[0]}`) // onion port number const port = parseInt(addr[1], 10) @@ -242,13 +203,10 @@ function onion32bytes (str) { return uint8ArrayConcat([buf, portBuf], buf.length + portBuf.length) } -/** - * @param {Uint8Array} buf - */ -function bytes2onion (buf) { +function bytes2onion (buf: Uint8Array) { const addrBytes = buf.slice(0, buf.length - 2) const portBytes = buf.slice(buf.length - 2) const addr = uint8ArrayToString(addrBytes, 'base32') const port = bytes2port(portBytes) - return addr + ':' + port + return `${addr}:${port}` } diff --git a/src/index.js b/src/index.ts similarity index 80% rename from src/index.js rename to src/index.ts index a1737e62..79cb3513 100644 --- a/src/index.js +++ b/src/index.ts @@ -1,24 +1,40 @@ -'use strict' - -const codec = require('./codec') -const protocols = require('./protocols-table') -const varint = require('varint') -const { CID } = require('multiformats/cid') -const { base58btc } = require('multiformats/bases/base58') -const errCode = require('err-code') +import * as codec from './codec.js' +import { getProtocol, names } from './protocols-table.js' +import varint from 'varint' +import { CID } from 'multiformats/cid' +import { base58btc } from 'multiformats/bases/base58' +import errCode from 'err-code' +import { toString as uint8ArrayToString } from 'uint8arrays/to-string' +import { equals as uint8ArrayEquals } from 'uint8arrays/equals' + const inspect = Symbol.for('nodejs.util.inspect.custom') -const { toString: uint8ArrayToString } = require('uint8arrays/to-string') -const { equals: uint8ArrayEquals } = require('uint8arrays/equals') -/** - * @typedef {(addr: Multiaddr) => Promise} Resolver - * @typedef {string | Multiaddr | Uint8Array | null} MultiaddrInput - * @typedef {import('./types').MultiaddrObject} MultiaddrObject - * @typedef {import('./types').Protocol} Protocol - */ +export interface Protocol { + code: number + size: number + name: string + resolvable?: boolean | undefined + path?: boolean | undefined +} + +export interface MultiaddrObject { + family: 4 | 6 + host: string + transport: string + port: number +} -/** @type {Map} */ -const resolvers = new Map() +export interface NodeAddress { + family: 4 | 6 + address: string + port: number +} + +export type MultiaddrInput = string | Multiaddr | Uint8Array | null + +export interface Resolver { (addr: Multiaddr): Promise } + +const resolvers = new Map() const symbol = Symbol.for('@multiformats/js-multiaddr/multiaddr') /** @@ -27,7 +43,11 @@ const symbol = Symbol.for('@multiformats/js-multiaddr/multiaddr') * public key. * */ -class Multiaddr { +export class Multiaddr { + static resolvers = resolvers + + public bytes: Uint8Array + /** * @example * ```js @@ -37,7 +57,7 @@ class Multiaddr { * * @param {MultiaddrInput} [addr] - If String or Uint8Array, needs to adhere to the address format of a [multiaddr](https://github.com/multiformats/multiaddr#string-format) */ - constructor (addr) { + constructor (addr?: MultiaddrInput) { // default if (addr == null) { addr = '' @@ -97,13 +117,15 @@ class Multiaddr { * ``` */ toOptions () { - /** @type {MultiaddrObject} */ - const opts = {} const parsed = this.toString().split('/') - opts.family = parsed[1] === 'ip4' ? 4 : 6 - opts.host = parsed[2] - opts.transport = parsed[3] - opts.port = parseInt(parsed[4]) + + const opts = { + family: parsed[1] === 'ip4' ? 4 : 6, + host: parsed[2], + transport: parsed[3], + port: parseInt(parsed[4]) + } + return opts } @@ -119,11 +141,9 @@ class Multiaddr { * // [ { code: 4, size: 32, name: 'ip4' }, * // { code: 6, size: 16, name: 'tcp' } ] * ``` - * - * @returns {Protocol[]} protocols - All the protocols the address is composed of */ protos () { - return this.protoCodes().map(code => Object.assign({}, protocols(code))) + return this.protoCodes().map(code => Object.assign({}, getProtocol(code))) } /** @@ -135,18 +155,16 @@ class Multiaddr { * Multiaddr('/ip4/127.0.0.1/tcp/4001').protoCodes() * // [ 4, 6 ] * ``` - * - * @returns {number[]} protocol codes */ protoCodes () { - const codes = [] + const codes: number[] = [] const buf = this.bytes let i = 0 while (i < buf.length) { const code = varint.decode(buf, i) const n = varint.decode.bytes - const p = protocols(code) + const p = getProtocol(code) const size = codec.sizeForAddr(p, buf.slice(i + n)) i += (size + n) @@ -165,8 +183,6 @@ class Multiaddr { * new Multiaddr('/ip4/127.0.0.1/tcp/4001').protoNames() * // [ 'ip4', 'tcp' ] * ``` - * - * @returns {string[]} protocol names */ protoNames () { return this.protos().map(proto => proto.name) @@ -221,7 +237,7 @@ class Multiaddr { * * @param {MultiaddrInput} addr - Multiaddr to add into this Multiaddr */ - encapsulate (addr) { + encapsulate (addr: MultiaddrInput) { addr = new Multiaddr(addr) return new Multiaddr(this.toString() + addr.toString()) } @@ -245,14 +261,13 @@ class Multiaddr { * ``` * * @param {Multiaddr | string} addr - Multiaddr to remove from this Multiaddr - * @returns {Multiaddr} */ - decapsulate (addr) { + decapsulate (addr: Multiaddr | string) { const addrString = addr.toString() const s = this.toString() const i = s.lastIndexOf(addrString) if (i < 0) { - throw new Error('Address ' + this + ' does not contain subaddress: ' + addr) + throw new Error(`Address ${this.toString()} does not contain subaddress: ${addr.toString()}`) } return new Multiaddr(s.slice(0, i)) } @@ -274,11 +289,8 @@ class Multiaddr { * new Multiaddr('/ip4/127.0.0.1/tcp/8080').decapsulateCode(421).toString() * // '/ip4/127.0.0.1/tcp/8080' * ``` - * - * @param {number} code - The code of the protocol to decapsulate from this Multiaddr - * @returns {Multiaddr} */ - decapsulateCode (code) { + decapsulateCode (code: number) { const tuples = this.tuples() for (let i = tuples.length - 1; i >= 0; i--) { if (tuples[i][0] === code) { @@ -299,13 +311,11 @@ class Multiaddr { * // should return QmValidBase58string or null if the id is missing or invalid * const peerId = mh1.getPeerId() * ``` - * - * @returns {string | null} peerId - The id of the peer or null if invalid or missing from the ma */ - getPeerId () { + getPeerId (): string | null { try { const tuples = this.stringTuples().filter((tuple) => { - if (tuple[0] === protocols.names.ipfs.code) { + if (tuple[0] === names.ipfs.code) { return true } return false @@ -313,7 +323,7 @@ class Multiaddr { // Get the last ipfs tuple ['ipfs', 'peerid string'] const tuple = tuples.pop() - if (tuple && tuple[1]) { + if (tuple?.[1] != null) { const peerIdStr = tuple[1] // peer id is base58btc encoded string but not multibase encoded so add the `z` @@ -342,25 +352,23 @@ class Multiaddr { * * // should return utf8 string or null if the id is missing or invalid * const path = mh1.getPath() - * ```js - * - * @returns {string | null} path - The path of the multiaddr, or null if no path protocol is present + * ``` */ - getPath () { + getPath (): string | null { let path = null try { path = this.stringTuples().filter((tuple) => { - const proto = protocols(tuple[0]) - if (proto.path) { + const proto = getProtocol(tuple[0]) + if (proto.path === true) { return true } return false })[0][1] - if (!path) { + if (path == null) { path = null } - } catch (e) { + } catch { path = null } return path @@ -383,11 +391,8 @@ class Multiaddr { * mh1.equals(mh2) * // false * ``` - * - * @param {Multiaddr} addr - * @returns {boolean} */ - equals (addr) { + equals (addr: { bytes: Uint8Array }) { return uint8ArrayEquals(this.bytes, addr.bytes) } @@ -405,19 +410,17 @@ class Multiaddr { * // * // ] * ``` - * - * @returns {Promise>} */ async resolve () { const resolvableProto = this.protos().find((p) => p.resolvable) // Multiaddr is not resolvable? - if (!resolvableProto) { + if (resolvableProto == null) { return [this] } const resolver = resolvers.get(resolvableProto.name) - if (!resolver) { + if (resolver == null) { throw errCode(new Error(`no available resolver for ${resolvableProto.name}`), 'ERR_NO_AVAILABLE_RESOLVER') } @@ -437,11 +440,8 @@ class Multiaddr { * new Multiaddr('/ip4/127.0.0.1/tcp/4001').nodeAddress() * // {family: 4, address: '127.0.0.1', port: 4001} * ``` - * - * @returns {{family: 4 | 6, address: string, port: number}} - * @throws {Error} Throws error if Multiaddr is not a Thin Waist address */ - nodeAddress () { + nodeAddress (): NodeAddress { const codes = this.protoCodes() const names = this.protoNames() const parts = this.toString().split('/').slice(1) @@ -487,11 +487,9 @@ class Multiaddr { * mh4.isThinWaistAddress() * // false * ``` - * - * @param {Multiaddr} [addr] - Defaults to using `this` instance */ - isThinWaistAddress (addr) { - const protos = (addr || this).protos() + isThinWaistAddress (addr?: Multiaddr) { + const protos = (addr ?? this).protos() if (protos.length !== 2) { return false @@ -518,9 +516,13 @@ class Multiaddr { * @param {{family: 4 | 6, address: string, port: number}} addr * @param {string} transport */ - static fromNodeAddress (addr, transport) { - if (!addr) { throw new Error('requires node address object') } - if (!transport) { throw new Error('requires transport protocol') } + static fromNodeAddress (addr: NodeAddress, transport: string) { + if (addr == null) { + throw new Error('requires node address object') + } + if (transport == null) { + throw new Error('requires transport protocol') + } let ip switch (addr.family) { case 4: @@ -530,18 +532,15 @@ class Multiaddr { ip = 'ip6' break default: - throw Error(`Invalid addr family. Got '${addr.family}' instead of 4 or 6`) + throw Error('Invalid addr family, should be 4 or 6.') } return new Multiaddr('/' + [ip, addr.address, transport, addr.port].join('/')) } /** * Returns if something is a Multiaddr that is a name - * - * @param {Multiaddr} addr - * @returns {boolean} isName */ - static isName (addr) { + static isName (addr: Multiaddr) { if (!Multiaddr.isMultiaddr(addr)) { return false } @@ -552,12 +551,9 @@ class Multiaddr { /** * Check if object is a CID instance - * - * @param {any} value - * @returns {value is Multiaddr} */ - static isMultiaddr (value) { - return value instanceof Multiaddr || Boolean(value && value[symbol]) + static isMultiaddr (value: any) { + return value instanceof Multiaddr ?? Boolean(value?.[symbol]) } /** @@ -570,8 +566,6 @@ class Multiaddr { * console.log(new Multiaddr('/ip4/127.0.0.1/tcp/4001')) * // '' * ``` - * - * @returns {string} */ [inspect] () { return '' * ``` - * - * @returns {string} */ inspect () { return ' { result[offset++] = parseInt(byte, 10) & 0xff }) } else if (isV6(ip)) { @@ -27,14 +22,14 @@ const toBytes = function (ip, buff, offset) { let i for (i = 0; i < sections.length; i++) { const isv4 = isV4(sections[i]) - let v4Buffer + let v4Buffer: Uint8Array | undefined if (isv4) { v4Buffer = toBytes(sections[i]) sections[i] = uint8ArrayToString(v4Buffer.slice(0, 2), 'base16') } - if (v4Buffer && ++i < 8) { + if (v4Buffer != null && ++i < 8) { sections.splice(i, 0, uint8ArrayToString(v4Buffer.slice(2, 4), 'base16')) } } @@ -45,14 +40,14 @@ const toBytes = function (ip, buff, offset) { while (sections.length < 8) sections.push('0') } else if (sections.length < 8) { for (i = 0; i < sections.length && sections[i] !== ''; i++); - const argv = [i, '1'] + const argv: [number, number, ...string[]] = [i, 1] for (i = 9 - sections.length; i > 0; i--) { argv.push('0') } sections.splice.apply(sections, argv) } - result = buff || new Uint8Array(offset + 16) + result = new Uint8Array(offset + 16) for (i = 0; i < sections.length; i++) { const word = parseInt(sections[i], 16) result[offset++] = (word >> 8) & 0xff @@ -60,7 +55,7 @@ const toBytes = function (ip, buff, offset) { } } - if (!result) { + if (result == null) { throw Error('Invalid ip address: ' + ip) } @@ -68,18 +63,17 @@ const toBytes = function (ip, buff, offset) { } // Copied from https://github.com/indutny/node-ip/blob/master/lib/ip.js#L63 -// @ts-ignore - this is copied from the link above better to keep it the same -const toString = function (buff, offset, length) { +export const toString = function (buf: Uint8Array, offset: number, length: number) { offset = ~~offset - length = length || (buff.length - offset) + length = length ?? (buf.length - offset) const result = [] - let string - const view = new DataView(buff.buffer) + let string = '' + const view = new DataView(buf.buffer) if (length === 4) { // IPv4 for (let i = 0; i < length; i++) { - result.push(buff[offset + i]) + result.push(buf[offset + i]) } string = result.join('.') } else if (length === 16) { @@ -94,11 +88,3 @@ const toString = function (buff, offset, length) { return string } - -module.exports = { - isIP, - isV4, - isV6, - toBytes, - toString -} diff --git a/src/protocols-table.js b/src/protocols-table.js deleted file mode 100644 index 3431af59..00000000 --- a/src/protocols-table.js +++ /dev/null @@ -1,105 +0,0 @@ -'use strict' -/** @typedef {import("./types").Protocol} Protocol */ - -/** - * Protocols - * - * @param {number | string} proto - * @returns {Protocol} - */ -function Protocols (proto) { - if (typeof (proto) === 'number') { - if (Protocols.codes[proto]) { - return Protocols.codes[proto] - } - - throw new Error('no protocol with code: ' + proto) - } else if (typeof (proto) === 'string') { - if (Protocols.names[proto]) { - return Protocols.names[proto] - } - - throw new Error('no protocol with name: ' + proto) - } - - throw new Error('invalid protocol id type: ' + proto) -} - -const V = -1 -Protocols.lengthPrefixedVarSize = V -Protocols.V = V - -/** @type {Array<[number, number, string, (string|boolean)?, string?]>} */ -Protocols.table = [ - [4, 32, 'ip4'], - [6, 16, 'tcp'], - [33, 16, 'dccp'], - [41, 128, 'ip6'], - [42, V, 'ip6zone'], - [53, V, 'dns', 'resolvable'], - [54, V, 'dns4', 'resolvable'], - [55, V, 'dns6', 'resolvable'], - [56, V, 'dnsaddr', 'resolvable'], - [132, 16, 'sctp'], - [273, 16, 'udp'], - [275, 0, 'p2p-webrtc-star'], - [276, 0, 'p2p-webrtc-direct'], - [277, 0, 'p2p-stardust'], - [290, 0, 'p2p-circuit'], - [301, 0, 'udt'], - [302, 0, 'utp'], - [400, V, 'unix', false, 'path'], - // `ipfs` is added before `p2p` for legacy support. - // All text representations will default to `p2p`, but `ipfs` will - // still be supported - [421, V, 'ipfs'], - // `p2p` is the preferred name for 421, and is now the default - [421, V, 'p2p'], - [443, 0, 'https'], - [444, 96, 'onion'], - [445, 296, 'onion3'], - [446, V, 'garlic64'], - [460, 0, 'quic'], - [477, 0, 'ws'], - [478, 0, 'wss'], - [479, 0, 'p2p-websocket-star'], - [480, 0, 'http'], - [777, V, 'memory'] -] -/** @type {Record} */ -Protocols.names = {} -/** @type {Record} */ -Protocols.codes = {} - -// populate tables -Protocols.table.map(row => { - const proto = p.apply(null, row) - Protocols.codes[proto.code] = proto - Protocols.names[proto.name] = proto - return null -}) - -Protocols.object = p - -/** - * - * Create a protocol - * - * @param {number} code - * @param {number} size - * @param {string} name - * @param {any} [resolvable] - * @param {any} [path] - * @returns {Protocol} - */ -function p (code, size, name, resolvable, path) { - return { - code, - size, - name, - resolvable: Boolean(resolvable), - path: Boolean(path) - } -} - -module.exports = Protocols diff --git a/src/protocols-table.ts b/src/protocols-table.ts new file mode 100644 index 00000000..7f369402 --- /dev/null +++ b/src/protocols-table.ts @@ -0,0 +1,83 @@ +export interface Protocol { + code: number + size: number + name: string + resolvable?: boolean + path?: boolean +} + +const V = -1 +export const names: Record = {} +export const codes: Record = {} + +export const table: Array<[code: number, size: number, name: string, resolvable?: boolean, path?: boolean]> = [ + [4, 32, 'ip4'], + [6, 16, 'tcp'], + [33, 16, 'dccp'], + [41, 128, 'ip6'], + [42, V, 'ip6zone'], + [53, V, 'dns', true], + [54, V, 'dns4', true], + [55, V, 'dns6', true], + [56, V, 'dnsaddr', true], + [132, 16, 'sctp'], + [273, 16, 'udp'], + [275, 0, 'p2p-webrtc-star'], + [276, 0, 'p2p-webrtc-direct'], + [277, 0, 'p2p-stardust'], + [290, 0, 'p2p-circuit'], + [301, 0, 'udt'], + [302, 0, 'utp'], + [400, V, 'unix', false, true], + // `ipfs` is added before `p2p` for legacy support. + // All text representations will default to `p2p`, but `ipfs` will + // still be supported + [421, V, 'ipfs'], + // `p2p` is the preferred name for 421, and is now the default + [421, V, 'p2p'], + [443, 0, 'https'], + [444, 96, 'onion'], + [445, 296, 'onion3'], + [446, V, 'garlic64'], + [460, 0, 'quic'], + [477, 0, 'ws'], + [478, 0, 'wss'], + [479, 0, 'p2p-websocket-star'], + [480, 0, 'http'], + [777, V, 'memory'] +] + +// populate tables +table.forEach(row => { + const proto = createProtocol(...row) + codes[proto.code] = proto + names[proto.name] = proto +}) + +export function createProtocol (code: number, size: number, name: string, resolvable?: any, path?: any): Protocol { + return { + code, + size, + name, + resolvable: Boolean(resolvable), + path: Boolean(path) + } +} + +export function getProtocol (proto: number | string) { + if (typeof proto === 'number') { + if (codes[proto] != null) { + return codes[proto] + } + + throw new Error(`no protocol with code: ${proto}`) + } else if (typeof proto === 'string') { + if (names[proto] != null) { + return names[proto] + } + + throw new Error(`no protocol with name: ${proto}`) + } + + throw new Error(`invalid protocol id type: ${typeof proto}`) +} diff --git a/src/resolvers/dns.browser.js b/src/resolvers/dns.browser.js deleted file mode 100644 index b5d16980..00000000 --- a/src/resolvers/dns.browser.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict' - -/** @type {import('dns').promises.Resolver} */ -// @ts-ignore - has no types -const dns = require('dns-over-http-resolver') - -module.exports = dns diff --git a/src/resolvers/dns.browser.ts b/src/resolvers/dns.browser.ts new file mode 100644 index 00000000..fbb6f1eb --- /dev/null +++ b/src/resolvers/dns.browser.ts @@ -0,0 +1,3 @@ +import dns from 'dns-over-http-resolver' + +export default dns diff --git a/src/resolvers/dns.js b/src/resolvers/dns.js deleted file mode 100644 index 32bde6bf..00000000 --- a/src/resolvers/dns.js +++ /dev/null @@ -1,3 +0,0 @@ -'use strict' - -module.exports = require('dns').promises.Resolver diff --git a/src/resolvers/dns.ts b/src/resolvers/dns.ts new file mode 100644 index 00000000..681d36aa --- /dev/null +++ b/src/resolvers/dns.ts @@ -0,0 +1,3 @@ +import { Resolver } from 'dns/promises' + +export default Resolver diff --git a/src/resolvers/index.js b/src/resolvers/index.ts similarity index 55% rename from src/resolvers/index.js rename to src/resolvers/index.ts index da082b24..bbfc9196 100644 --- a/src/resolvers/index.js +++ b/src/resolvers/index.ts @@ -1,8 +1,8 @@ -'use strict' +import { getProtocol } from '../protocols-table.js' +import Resolver from './dns.js' +import type { Multiaddr } from '../index.js' -const protocols = require('../protocols-table') - -const { code: dnsaddrCode } = protocols('dnsaddr') +const { code: dnsaddrCode } = getProtocol('dnsaddr') /** * @typedef {import('..').Multiaddr} Multiaddr @@ -10,27 +10,23 @@ const { code: dnsaddrCode } = protocols('dnsaddr') /** * Resolver for dnsaddr addresses. - * - * @param {Multiaddr} addr - * @returns {Promise} */ -async function dnsaddrResolver (addr) { - const Resolver = require('./dns') +export async function dnsaddrResolver (addr: Multiaddr) { const resolver = new Resolver() const peerId = addr.getPeerId() - const [, hostname] = addr.stringTuples().find(([proto]) => proto === dnsaddrCode) || [] + const [, hostname] = addr.stringTuples().find(([proto]) => proto === dnsaddrCode) ?? [] + + if (hostname == null) { + throw new Error('No hostname found in multiaddr') + } const records = await resolver.resolveTxt(`_dnsaddr.${hostname}`) let addresses = records.flat().map((a) => a.split('=')[1]) - if (peerId) { + if (peerId != null) { addresses = addresses.filter((entry) => entry.includes(peerId)) } return addresses } - -module.exports = { - dnsaddrResolver -} diff --git a/src/types.d.ts b/src/types.d.ts deleted file mode 100644 index 5f3185fd..00000000 --- a/src/types.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -export interface Protocol { - code: number - size: number - name: string - resolvable?: boolean | undefined - path?: boolean | undefined -} - -export interface MultiaddrObject { - family: 4 | 6 - host: string - transport: string - port: number -} diff --git a/test/codec.spec.js b/test/codec.spec.ts similarity index 87% rename from test/codec.spec.js rename to test/codec.spec.ts index f183a18b..8dad83ce 100644 --- a/test/codec.spec.js +++ b/test/codec.spec.ts @@ -1,10 +1,8 @@ /* eslint-env mocha */ -'use strict' - -const codec = require('../src/codec') -const varint = require('varint') -const { expect } = require('aegir/utils/chai') -const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string') +import * as codec from '../src/codec.js' +import varint from 'varint' +import { expect } from 'aegir/utils/chai.js' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' describe('codec', () => { describe('.stringToStringTuples', () => { diff --git a/test/convert.spec.js b/test/convert.spec.ts similarity index 61% rename from test/convert.spec.js rename to test/convert.spec.ts index 20382209..9cd38bbd 100644 --- a/test/convert.spec.js +++ b/test/convert.spec.ts @@ -1,14 +1,12 @@ /* eslint-env mocha */ -'use strict' - -const convert = require('../src/convert') -const { expect } = require('aegir/utils/chai') -const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string') +import * as convert from '../src/convert.js' +import { expect } from 'aegir/utils/chai.js' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' describe('convert', () => { it('handles ip4 buffers', () => { expect( - convert('ip4', uint8ArrayFromString('c0a80001', 'base16')) + convert.convertToString('ip4', uint8ArrayFromString('c0a80001', 'base16')) ).to.eql( '192.168.0.1' ) @@ -16,7 +14,7 @@ describe('convert', () => { it('handles ip6 buffers', () => { expect( - convert('ip6', uint8ArrayFromString('abcd0000000100020003000400050006', 'base16')) + convert.convertToString('ip6', uint8ArrayFromString('abcd0000000100020003000400050006', 'base16')) ).to.eql( 'abcd:0:1:2:3:4:5:6' ) @@ -24,7 +22,7 @@ describe('convert', () => { it('handles ipv6 strings', () => { expect( - convert('ip6', 'ABCD::1:2:3:4:5:6') + convert.convertToBytes('ip6', 'ABCD::1:2:3:4:5:6') ).to.eql( uint8ArrayFromString('ABCD0000000100020003000400050006', 'base16upper') ) @@ -32,7 +30,7 @@ describe('convert', () => { it('handles ip4 strings', () => { expect( - convert('ip4', '192.168.0.1') + convert.convertToBytes('ip4', '192.168.0.1') ).to.eql( uint8ArrayFromString('c0a80001', 'base16') ) @@ -40,7 +38,7 @@ describe('convert', () => { it('throws on invalid ip4 conversion', () => { expect( - () => convert('ip4', '555.168.0.1') + () => convert.convertToBytes('ip4', '555.168.0.1') ).to.throw( /invalid ip address/ ) @@ -48,7 +46,7 @@ describe('convert', () => { it('throws on invalid ip6 conversion', () => { expect( - () => convert('ip6', 'FFFF::GGGG') + () => convert.convertToBytes('ip6', 'FFFF::GGGG') ).to.throw( /invalid ip address/ ) @@ -57,7 +55,7 @@ describe('convert', () => { describe('.toBytes', () => { it('defaults to hex conversion', () => { expect( - convert.toBytes('ws', 'c0a80001') + convert.convertToBytes('ws', 'c0a80001') ).to.eql( Uint8Array.from([192, 168, 0, 1]) ) @@ -68,7 +66,7 @@ describe('convert', () => { it('throws on inconsistent ipfs links', () => { const valid = uint8ArrayFromString('03221220d52ebb89d85b02a284948203a62ff28389c57c9f42beec4ec20db76a68911c0b', 'base16') expect( - () => convert.toString('ipfs', valid.slice(0, valid.length - 8)) + () => convert.convertToString('ipfs', valid.slice(0, valid.length - 8)) ).to.throw( /inconsistent length/ ) @@ -76,17 +74,17 @@ describe('convert', () => { it('defaults to hex conversion', () => { expect( - convert.toString('ws', Uint8Array.from([192, 168, 0, 1])) + convert.convertToString('ws', Uint8Array.from([192, 168, 0, 1])) ).to.eql( 'c0a80001' ) }) it('respects byteoffset during conversion', () => { - const bytes = convert.toBytes('sctp', '1234') + const bytes = convert.convertToBytes('sctp', '1234') const buffer = new Uint8Array(bytes.byteLength + 5) buffer.set(bytes, 5) - expect(convert.toString('sctp', buffer.subarray(5))).to.equal('1234') + expect(convert.convertToString('sctp', buffer.subarray(5))).to.equal('1234') }) }) }) diff --git a/test/index.spec.js b/test/index.spec.ts similarity index 97% rename from test/index.spec.js rename to test/index.spec.ts index ef8b32aa..1b92520f 100644 --- a/test/index.spec.js +++ b/test/index.spec.ts @@ -1,14 +1,12 @@ /* eslint max-nested-callbacks: ["error", 8] */ /* eslint-env mocha */ -'use strict' - -const { Multiaddr } = require('../src') -const { expect } = require('aegir/utils/chai') -const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string') +import { Multiaddr } from '../src/index.js' +import { expect } from 'aegir/utils/chai.js' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { codes } from '../src/protocols-table.js' describe('construction', () => { - /** @type {Multiaddr} */ - let udpAddr + let udpAddr: Multiaddr it('create multiaddr', () => { udpAddr = new Multiaddr('/ip4/127.0.0.1/udp/1234') @@ -52,30 +50,29 @@ describe('construction', () => { it('throws on truthy non string or buffer', () => { const errRegex = /addr must be a string/ - // @ts-ignore + // @ts-expect-error expect(() => new Multiaddr({})).to.throw(errRegex) - // @ts-ignore + // @ts-expect-error expect(() => new Multiaddr([])).to.throw(errRegex) - // @ts-ignore + // @ts-expect-error expect(() => new Multiaddr(138)).to.throw(errRegex) - // @ts-ignore + // @ts-expect-error expect(() => new Multiaddr(true)).to.throw(errRegex) }) it('throws on falsy non string or buffer', () => { const errRegex = /addr must be a string/ - // @ts-ignore + // @ts-expect-error expect(() => new Multiaddr(NaN)).to.throw(errRegex) - // @ts-ignore + // @ts-expect-error expect(() => new Multiaddr(false)).to.throw(errRegex) - // @ts-ignore + // @ts-expect-error expect(() => new Multiaddr(0)).to.throw(errRegex) }) }) describe('requiring varint', () => { - /** @type {Multiaddr} */ - let uTPAddr + let uTPAddr: Multiaddr it('create multiaddr', () => { uTPAddr = new Multiaddr('/ip4/127.0.0.1/udp/1234/utp') @@ -118,8 +115,8 @@ describe('manipulation', () => { expect(udpAddr.protoCodes()).to.deep.equal([4, 273]) expect(udpAddr.protoNames()).to.deep.equal(['ip4', 'udp']) - expect(udpAddr.protos()).to.deep.equal([Multiaddr.protocols.codes[4], Multiaddr.protocols.codes[273]]) - expect(udpAddr.protos()[0] === Multiaddr.protocols.codes[4]).to.equal(false) + expect(udpAddr.protos()).to.deep.equal([codes[4], codes[273]]) + expect(udpAddr.protos()[0] === codes[4]).to.equal(false) const udpAddrbytes2 = udpAddr.encapsulate('/udp/5678') expect(udpAddrbytes2.toString()).to.equal('/ip4/127.0.0.1/udp/1234/udp/5678') @@ -726,7 +723,7 @@ describe('helpers', () => { describe('.fromNodeAddress', () => { it('throws on missing address object', () => { expect( - // @ts-ignore + // @ts-expect-error () => Multiaddr.fromNodeAddress() ).to.throw( /requires node address/ @@ -735,7 +732,7 @@ describe('helpers', () => { it('throws on missing transport', () => { expect( - // @ts-ignore + // @ts-expect-error () => Multiaddr.fromNodeAddress({ address: '0.0.0.0' }) ).to.throw( /requires transport protocol/ @@ -758,8 +755,7 @@ describe('helpers', () => { describe('.isThinWaistAddress', () => { const families = ['ip4', 'ip6'] const transports = ['tcp', 'udp'] - /** @type {Record} */ - const addresses = { + const addresses: Record = { ip4: '192.168.0.1', ip6: '2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095' } diff --git a/test/protocols.spec.js b/test/protocols.spec.ts similarity index 68% rename from test/protocols.spec.js rename to test/protocols.spec.ts index a6e12a01..5aa0c7c5 100644 --- a/test/protocols.spec.js +++ b/test/protocols.spec.ts @@ -1,14 +1,12 @@ /* eslint-env mocha */ -'use strict' - -const protocols = require('../src/protocols-table') -const { expect } = require('aegir/utils/chai') +import { getProtocol } from '../src/protocols-table.js' +import { expect } from 'aegir/utils/chai.js' describe('protocols', () => { describe('throws on non existent protocol', () => { it('number', () => { expect( - () => protocols(1234) + () => getProtocol(1234) ).to.throw( /no protocol with code/ ) @@ -16,7 +14,7 @@ describe('protocols', () => { it('string', () => { expect( - () => protocols('hello') + () => getProtocol('hello') ).to.throw( /no protocol with name/ ) @@ -25,7 +23,7 @@ describe('protocols', () => { it('else', () => { expect( // @ts-expect-error - () => protocols({ hi: 34 }) + () => getProtocol({ hi: 34 }) ).to.throw( /invalid protocol id type/ ) diff --git a/test/resolvers.spec.js b/test/resolvers.spec.ts similarity index 93% rename from test/resolvers.spec.js rename to test/resolvers.spec.ts index 9d5959f5..7716269d 100644 --- a/test/resolvers.spec.js +++ b/test/resolvers.spec.ts @@ -1,12 +1,9 @@ /* eslint-env mocha */ -'use strict' - -const { expect } = require('aegir/utils/chai') -const sinon = require('sinon') - -const { Multiaddr } = require('../src') -const resolvers = require('../src/resolvers') -const Resolver = require('../src/resolvers/dns') +import { expect } from 'aegir/utils/chai.js' +import sinon from 'sinon' +import { Multiaddr } from '../src/index.js' +import * as resolvers from '../src/resolvers/index.js' +import Resolver from '../src/resolvers/dns.js' const dnsaddrStub1 = [ ['dnsaddr=/dnsaddr/ams-1.bootstrap.libp2p.io/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd'], @@ -85,11 +82,11 @@ describe('multiaddr resolve', () => { // Resolve const resolvedInitialMas = await ma.resolve() - const resolvedSecondMas = await Promise.all(resolvedInitialMas.map(nm => { + const resolvedSecondMas = await Promise.all(resolvedInitialMas.map(async nm => { // nm.resolvers.set('dnsaddr', resolvers.dnsaddrResolver) - return nm.resolve() + return await nm.resolve() })) - // @ts-ignore + const resolvedMas = resolvedSecondMas.flat() expect(resolvedMas).to.have.length(dnsaddrStub2.length) diff --git a/tsconfig.json b/tsconfig.json index 83d980a2..f296f994 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,10 +1,12 @@ { "extends": "aegir/src/config/tsconfig.aegir.json", "compilerOptions": { - "outDir": "dist" + "outDir": "dist", + "emitDeclarationOnly": false, + "module": "ES2020" }, "include": [ - "test", - "src" + "src", + "test" ] -} \ No newline at end of file +}