diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 0bc3b42..d401a77 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -5,7 +5,7 @@ updates:
schedule:
interval: daily
time: "10:00"
- open-pull-requests-limit: 10
+ open-pull-requests-limit: 20
commit-message:
prefix: "deps"
prefix-development: "deps(dev)"
diff --git a/README.md b/README.md
index 5b5a7b6..335c844 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+# @multiformats/multiaddr-matcher
+
[](http://multiformats.io)
[](https://codecov.io/gh/multiformats/js-multiaddr-matcher)
[](https://github.com/multiformats/js-multiaddr-matcher/actions/workflows/js-test-and-release.yml?query=branch%3Amain)
@@ -6,6 +8,21 @@
# About
+
+
This module exports various matchers that can be used to infer the type of a
passed multiaddr.
@@ -44,7 +61,7 @@ $ npm i @multiformats/multiaddr-matcher
## Browser `
@@ -58,8 +75,8 @@ Loading this module through a script tag will make it's exports available as `Mu
Licensed under either of
-- Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / )
-- MIT ([LICENSE-MIT](LICENSE-MIT) / )
+- Apache 2.0, ([LICENSE-APACHE](https://github.com/multiformats/js-multiaddr-matcher/LICENSE-APACHE) / )
+- MIT ([LICENSE-MIT](https://github.com/multiformats/js-multiaddr-matcher/LICENSE-MIT) / )
# Contribution
diff --git a/package.json b/package.json
index 5017c63..958f7aa 100644
--- a/package.json
+++ b/package.json
@@ -11,11 +11,31 @@
"bugs": {
"url": "https://github.com/multiformats/js-multiaddr-matcher/issues"
},
+ "publishConfig": {
+ "access": "public",
+ "provenance": true
+ },
"keywords": [
"multiaddr"
],
"type": "module",
"types": "./dist/src/index.d.ts",
+ "typesVersions": {
+ "*": {
+ "*": [
+ "*",
+ "dist/*",
+ "dist/src/*",
+ "dist/src/*/index"
+ ],
+ "src/*": [
+ "*",
+ "dist/*",
+ "dist/src/*",
+ "dist/src/*/index"
+ ]
+ }
+ },
"files": [
"src",
"dist",
@@ -26,6 +46,10 @@
".": {
"types": "./dist/src/index.d.ts",
"import": "./dist/src/index.js"
+ },
+ "./utils": {
+ "types": "./dist/src/utils.d.ts",
+ "import": "./dist/src/utils.js"
}
},
"eslintConfig": {
diff --git a/src/index.ts b/src/index.ts
index 9c0ee4f..ca47d9f 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -33,224 +33,29 @@
*/
import { isIPv4, isIPv6 } from '@chainsafe/is-ip'
-import { type Multiaddr } from '@multiformats/multiaddr'
-import { base58btc } from 'multiformats/bases/base58'
-import { base64url } from 'multiformats/bases/base64'
-
-/**
- * Split a multiaddr into path components
- */
-const toParts = (ma: Multiaddr): string[] => {
- return ma.toString().split('/').slice(1)
-}
+import { and, or, literal, string, peerId, optional, fmt, func, number, certhash } from './utils.js'
+import type { Multiaddr } from '@multiformats/multiaddr'
/**
* A matcher accepts multiaddr components and either fails to match and returns
* false or returns a sublist of unmatched components
*/
-interface Matcher {
+export interface Matcher {
match(parts: string[]): string[] | false
pattern: string
}
-const func = (fn: (val: string) => boolean): Matcher => {
- return {
- match: (vals) => {
- if (vals.length < 1) {
- return false
- }
-
- if (fn(vals[0])) {
- return vals.slice(1)
- }
-
- return false
- },
- pattern: 'fn'
- }
-}
-
-const literal = (str: string): Matcher => {
- return {
- match: (vals) => func((val) => val === str).match(vals),
- pattern: str
- }
-}
-
-const string = (): Matcher => {
- return {
- match: (vals) => func((val) => typeof val === 'string').match(vals),
- pattern: '{string}'
- }
-}
-
-const number = (): Matcher => {
- return {
- match: (vals) => func((val) => !isNaN(parseInt(val))).match(vals),
- pattern: '{number}'
- }
-}
-
-const peerId = (): Matcher => {
- return {
- match: (vals) => {
- if (vals.length < 2) {
- return false
- }
-
- if (vals[0] !== 'p2p' && vals[0] !== 'ipfs') {
- return false
- }
-
- // Q is RSA, 1 is Ed25519 or Secp256k1
- if (vals[1].startsWith('Q') || vals[1].startsWith('1')) {
- try {
- base58btc.decode(`z${vals[1]}`)
- } catch (err) {
- return false
- }
- } else {
- return false
- }
-
- return vals.slice(2)
- },
- pattern: '/p2p/{peerid}'
- }
-}
-
-const certhash = (): Matcher => {
- return {
- match: (vals) => {
- if (vals.length < 2) {
- return false
- }
-
- if (vals[0] !== 'certhash') {
- return false
- }
-
- try {
- base64url.decode(vals[1])
- } catch {
- return false
- }
-
- return vals.slice(2)
- },
- pattern: '/certhash/{certhash}'
- }
-}
-
-const optional = (matcher: Matcher): Matcher => {
- return {
- match: (vals) => {
- const result = matcher.match(vals)
-
- if (result === false) {
- return vals
- }
-
- return result
- },
- pattern: `optional(${matcher.pattern})`
- }
-}
-
-const or = (...matchers: Matcher[]): Matcher => {
- return {
- match: (vals) => {
- let matches: string[] | undefined
-
- for (const matcher of matchers) {
- const result = matcher.match(vals)
-
- // no match
- if (result === false) {
- continue
- }
-
- // choose greediest matcher
- if (matches == null || result.length < matches.length) {
- matches = result
- }
- }
-
- if (matches == null) {
- return false
- }
-
- return matches
- },
- pattern: `or(${matchers.map(m => m.pattern).join(', ')})`
- }
-}
-
-const and = (...matchers: Matcher[]): Matcher => {
- return {
- match: (vals) => {
- for (const matcher of matchers) {
- // pass what's left of the array
- const result = matcher.match(vals)
-
- // no match
- if (result === false) {
- return false
- }
-
- vals = result
- }
-
- return vals
- },
- pattern: `and(${matchers.map(m => m.pattern).join(', ')})`
- }
-}
-
-function fmt (...matchers: Matcher[]): MultiaddrMatcher {
- function match (ma: Multiaddr): string[] | false {
- let parts = toParts(ma)
-
- for (const matcher of matchers) {
- const result = matcher.match(parts)
-
- if (result === false) {
- return false
- }
-
- parts = result
- }
-
- return parts
- }
-
- function matches (ma: Multiaddr): boolean {
- const result = match(ma)
-
- return result !== false
- }
-
- function exactMatch (ma: Multiaddr): boolean {
- const result = match(ma)
-
- if (result === false) {
- return false
- }
-
- return result.length === 0
- }
-
- return {
- matches,
- exactMatch
- }
-}
-
/**
* A MultiaddrMatcher allows interpreting a multiaddr as a certain type of
* multiaddr
*/
export interface MultiaddrMatcher {
+ /**
+ * The matchers that make up this MultiaddrMatcher - useful if you want to
+ * make your own custom matchers
+ */
+ matchers: Matcher[]
+
/**
* Returns true if the passed multiaddr can be treated as this type of
* multiaddr
diff --git a/src/utils.ts b/src/utils.ts
new file mode 100644
index 0000000..e1f4ce4
--- /dev/null
+++ b/src/utils.ts
@@ -0,0 +1,205 @@
+import { base58btc } from 'multiformats/bases/base58'
+import { base64url } from 'multiformats/bases/base64'
+import type { Matcher, MultiaddrMatcher } from './index.js'
+import type { Multiaddr } from '@multiformats/multiaddr'
+
+/**
+ * Split a multiaddr into path components
+ */
+const toParts = (ma: Multiaddr): string[] => {
+ return ma.toString().split('/').slice(1)
+}
+
+export const func = (fn: (val: string) => boolean): Matcher => {
+ return {
+ match: (vals) => {
+ if (vals.length < 1) {
+ return false
+ }
+
+ if (fn(vals[0])) {
+ return vals.slice(1)
+ }
+
+ return false
+ },
+ pattern: 'fn'
+ }
+}
+
+export const literal = (str: string): Matcher => {
+ return {
+ match: (vals) => func((val) => val === str).match(vals),
+ pattern: str
+ }
+}
+
+export const string = (): Matcher => {
+ return {
+ match: (vals) => func((val) => typeof val === 'string').match(vals),
+ pattern: '{string}'
+ }
+}
+
+export const number = (): Matcher => {
+ return {
+ match: (vals) => func((val) => !isNaN(parseInt(val))).match(vals),
+ pattern: '{number}'
+ }
+}
+
+export const peerId = (): Matcher => {
+ return {
+ match: (vals) => {
+ if (vals.length < 2) {
+ return false
+ }
+
+ if (vals[0] !== 'p2p' && vals[0] !== 'ipfs') {
+ return false
+ }
+
+ // Q is RSA, 1 is Ed25519 or Secp256k1
+ if (vals[1].startsWith('Q') || vals[1].startsWith('1')) {
+ try {
+ base58btc.decode(`z${vals[1]}`)
+ } catch (err) {
+ return false
+ }
+ } else {
+ return false
+ }
+
+ return vals.slice(2)
+ },
+ pattern: '/p2p/{peerid}'
+ }
+}
+
+export const certhash = (): Matcher => {
+ return {
+ match: (vals) => {
+ if (vals.length < 2) {
+ return false
+ }
+
+ if (vals[0] !== 'certhash') {
+ return false
+ }
+
+ try {
+ base64url.decode(vals[1])
+ } catch {
+ return false
+ }
+
+ return vals.slice(2)
+ },
+ pattern: '/certhash/{certhash}'
+ }
+}
+
+export const optional = (matcher: Matcher): Matcher => {
+ return {
+ match: (vals) => {
+ const result = matcher.match(vals)
+
+ if (result === false) {
+ return vals
+ }
+
+ return result
+ },
+ pattern: `optional(${matcher.pattern})`
+ }
+}
+
+export const or = (...matchers: Matcher[]): Matcher => {
+ return {
+ match: (vals) => {
+ let matches: string[] | undefined
+
+ for (const matcher of matchers) {
+ const result = matcher.match(vals)
+
+ // no match
+ if (result === false) {
+ continue
+ }
+
+ // choose greediest matcher
+ if (matches == null || result.length < matches.length) {
+ matches = result
+ }
+ }
+
+ if (matches == null) {
+ return false
+ }
+
+ return matches
+ },
+ pattern: `or(${matchers.map(m => m.pattern).join(', ')})`
+ }
+}
+
+export const and = (...matchers: Matcher[]): Matcher => {
+ return {
+ match: (vals) => {
+ for (const matcher of matchers) {
+ // pass what's left of the array
+ const result = matcher.match(vals)
+
+ // no match
+ if (result === false) {
+ return false
+ }
+
+ vals = result
+ }
+
+ return vals
+ },
+ pattern: `and(${matchers.map(m => m.pattern).join(', ')})`
+ }
+}
+
+export function fmt (...matchers: Matcher[]): MultiaddrMatcher {
+ function match (ma: Multiaddr): string[] | false {
+ let parts = toParts(ma)
+
+ for (const matcher of matchers) {
+ const result = matcher.match(parts)
+
+ if (result === false) {
+ return false
+ }
+
+ parts = result
+ }
+
+ return parts
+ }
+
+ function matches (ma: Multiaddr): boolean {
+ const result = match(ma)
+
+ return result !== false
+ }
+
+ function exactMatch (ma: Multiaddr): boolean {
+ const result = match(ma)
+
+ if (result === false) {
+ return false
+ }
+
+ return result.length === 0
+ }
+
+ return {
+ matchers,
+ matches,
+ exactMatch
+ }
+}
diff --git a/typedoc.json b/typedoc.json
index f599dc7..afe3bc6 100644
--- a/typedoc.json
+++ b/typedoc.json
@@ -1,5 +1,6 @@
{
"entryPoints": [
- "./src/index.ts"
+ "./src/index.ts",
+ "./src/utils.ts"
]
}