diff --git a/.travis.yml b/.travis.yml index f217408..b437ba0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,16 @@ language: node_js cache: npm +dist: bionic stages: - check - test - cov +branches: + only: + - master + - /^release\/.*$/ + node_js: - 'lts/*' - 'node' @@ -21,7 +27,6 @@ jobs: include: - stage: check script: - - npx aegir commitlint --travis - npx aegir dep-check - npm run lint @@ -35,7 +40,7 @@ jobs: name: firefox addons: firefox: latest - script: npx aegir test -t browser -t webworker -- --browsers FirefoxHeadless + script: npx aegir test -t browser -t webworker -- --browser firefox - stage: test name: electron-main diff --git a/package.json b/package.json index 662c0ee..d5d1a9f 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "src", "dist" ], + "types": "./dist/src/index.d.ts", "main": "src/index.js", "browser": { "fs": false @@ -29,28 +30,27 @@ "url": "https://github.com/ipfs/is-ipfs.git" }, "scripts": { + "prepare": "aegir build --no-bundle", "test:node": "aegir test --target node", "test:browser": "aegir test --target browser", "test": "aegir test", + "prepublishOnly": "aegir build", "lint": "aegir lint && aegir lint-package-json", "release": "aegir release", "release-minor": "aegir release --type minor", - "release-major": "aegir release --type major", - "build": "aegir build", - "coverage": "aegir coverage", - "coverage-publish": "aegir coverage --upload" + "release-major": "aegir release --type major" }, "dependencies": { "cids": "^1.1.5", - "iso-url": "^1.0.0", + "iso-url": "^1.1.0", "mafmt": "^8.0.4", "multiaddr": "^8.1.2", - "multibase": "^3.1.1", - "multihashes": "^3.1.2", + "multibase": "^4.0.1", + "multihashes": "^4.0.0", "uint8arrays": "^2.0.5" }, "devDependencies": { - "aegir": "^30.3.0", + "aegir": "^31.0.0", "pre-commit": "^1.2.2" }, "engines": { diff --git a/src/index.js b/src/index.js index ad18edb..24bde7e 100644 --- a/src/index.js +++ b/src/index.js @@ -21,6 +21,9 @@ const subdomainProtocolMatch = 2 // Fully qualified domain name (FQDN) that has an explicit .tld suffix const fqdnWithTld = /^(([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])\.)+([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])$/ +/** + * @param {*} hash + */ function isMultihash (hash) { const formatted = convertToString(hash) try { @@ -31,6 +34,9 @@ function isMultihash (hash) { } } +/** + * @param {*} hash + */ function isMultibase (hash) { try { return multibase.isEncoded(hash) @@ -39,6 +45,9 @@ function isMultibase (hash) { } } +/** + * @param {*} hash + */ function isCID (hash) { try { new CID(hash) // eslint-disable-line no-new @@ -48,6 +57,9 @@ function isCID (hash) { } } +/** + * @param {*} input + */ function isMultiaddr (input) { if (!input) return false if (Multiaddr.isMultiaddr(input)) return true @@ -59,10 +71,19 @@ function isMultiaddr (input) { } } +/** + * @param {string | Uint8Array | Multiaddr} input + */ function isPeerMultiaddr (input) { return isMultiaddr(input) && (mafmt.P2P.matches(input) || mafmt.DNS.matches(input)) } +/** + * @param {string | Uint8Array} input + * @param {RegExp | string} pattern + * @param {number} [protocolMatch=1] + * @param {number} [hashMatch=2] + */ function isIpfs (input, pattern, protocolMatch = defaultProtocolMatch, hashMatch = defaultHashMath) { const formatted = convertToString(input) if (!formatted) { @@ -83,14 +104,21 @@ function isIpfs (input, pattern, protocolMatch = defaultProtocolMatch, hashMatch if (hash && pattern === subdomainGatewayPattern) { // when doing checks for subdomain context // ensure hash is case-insensitive - // (browsers force-lowercase authority compotent anyway) + // (browsers force-lowercase authority component anyway) hash = hash.toLowerCase() } return isCID(hash) } -function isIpns (input, pattern, protocolMatch = defaultProtocolMatch, hashMatch) { +/** + * + * @param {string | Uint8Array} input + * @param {string | RegExp} pattern + * @param {number} [protocolMatch=1] + * @param {number} [hashMatch=1] + */ +function isIpns (input, pattern, protocolMatch = defaultProtocolMatch, hashMatch = defaultHashMath) { const formatted = convertToString(input) if (!formatted) { return false @@ -133,10 +161,16 @@ function isIpns (input, pattern, protocolMatch = defaultProtocolMatch, hashMatch return true } +/** + * @param {any} input + */ function isString (input) { return typeof input === 'string' } +/** + * @param {Uint8Array | string} input + */ function convertToString (input) { if (input instanceof Uint8Array) { return uint8ArrayToString(input, 'base58btc') @@ -149,14 +183,35 @@ function convertToString (input) { return false } +/** + * @param {string | Uint8Array} url + */ const ipfsSubdomain = (url) => isIpfs(url, subdomainGatewayPattern, subdomainProtocolMatch, subdomainIdMatch) +/** + * @param {string | Uint8Array} url + */ const ipnsSubdomain = (url) => isIpns(url, subdomainGatewayPattern, subdomainProtocolMatch, subdomainIdMatch) +/** + * @param {string | Uint8Array} url + */ const subdomain = (url) => ipfsSubdomain(url) || ipnsSubdomain(url) +/** + * @param {string | Uint8Array} url + */ const ipfsUrl = (url) => isIpfs(url, pathGatewayPattern) || ipfsSubdomain(url) +/** + * @param {string | Uint8Array} url + */ const ipnsUrl = (url) => isIpns(url, pathGatewayPattern) || ipnsSubdomain(url) +/** + * @param {string | Uint8Array} url + */ const url = (url) => ipfsUrl(url) || ipnsUrl(url) || subdomain(url) +/** + * @param {string | Uint8Array} path + */ const path = (path) => isIpfs(path, pathPattern) || isIpns(path, pathPattern) module.exports = { @@ -164,6 +219,9 @@ module.exports = { multiaddr: isMultiaddr, peerMultiaddr: isPeerMultiaddr, cid: isCID, + /** + * @param {CID | string | Uint8Array} cid + */ base32cid: (cid) => (isMultibase(cid) === 'base32' && isCID(cid)), ipfsSubdomain, ipnsSubdomain, @@ -173,10 +231,22 @@ module.exports = { ipnsUrl, url, pathGatewayPattern: pathGatewayPattern, + /** + * @param {string | Uint8Array} path + */ ipfsPath: (path) => isIpfs(path, pathPattern), + /** + * @param {string | Uint8Array} path + */ ipnsPath: (path) => isIpns(path, pathPattern), path, pathPattern, + /** + * @param {string | Uint8Array} x + */ urlOrPath: (x) => url(x) || path(x), + /** + * @param {string | Uint8Array | CID} path + */ cidPath: path => isString(path) && !isCID(path) && isIpfs(`/ipfs/${path}`, pathPattern) } diff --git a/test/test-cid.spec.js b/test/test-cid.spec.js index 68d42d8..f3d090e 100644 --- a/test/test-cid.spec.js +++ b/test/test-cid.spec.js @@ -101,6 +101,7 @@ describe('ipfs base32cid', () => { }) it('isIPFS.base32cid should not match an invalid CID data type', (done) => { + // @ts-ignore data type is invalid const actual = isIPFS.base32cid(4) expect(actual).to.equal(false) done() diff --git a/test/test-multiaddr.spec.js b/test/test-multiaddr.spec.js index ee5a984..0ab9066 100644 --- a/test/test-multiaddr.spec.js +++ b/test/test-multiaddr.spec.js @@ -159,6 +159,7 @@ describe('ipfs peerMultiaddr', () => { }) it('isIPFS.peerMultiaddr should not match an invalid multiaddr data type', (done) => { + // @ts-ignore data type is invalid const actual = isIPFS.peerMultiaddr(4) expect(actual).to.equal(false) done() diff --git a/test/test-path.spec.js b/test/test-path.spec.js index a200f1d..53e8562 100644 --- a/test/test-path.spec.js +++ b/test/test-path.spec.js @@ -148,6 +148,7 @@ describe('ipfs path', () => { }) it('isIPFS.cidPath should not match a non string', () => { + // @ts-ignore data type is invalid const actual = isIPFS.cidPath({ toString: () => 'QmYHNYAaYK5hm3ZhZFx5W9H6xydKDGimjdgJMrMSdnctEm/path/to/file' }) expect(actual).to.equal(false) }) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..77830df --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "./node_modules/aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src", + "test" + ] +}