UNPKG

8.29 kBSource Map (JSON)View Raw
1{"version":3,"file":"prefix-map.js","sourceRoot":"","sources":["prefix-map.ts"],"names":[],"mappings":"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","sourcesContent":["import { findIndex } from 'lodash'\n\n/**\n * A key-value map where the members' keys represent prefixes.\n *\n * Example:\n * const map = new PrefixMap()\n * map.insert(\"foo\", 1)\n * map.insert(\"bar\", 2)\n * map.get(\"foo\") // ⇒ 1\n * map.get(\"foo.bar\") // ⇒ 1 (\"foo\" is the longest known prefix of \"foo.bar\")\n * map.get(\"bar\") // ⇒ 2\n * map.get(\"bar.foo\") // ⇒ 2 (\"bar\" is the longest known prefix of \"bar.foo\")\n * map.get(\"random\") // ⇒ null\n */\nexport default class PrefixMap<T> {\n protected prefixes: string[]\n protected items: { [key: string]: T }\n\n constructor () {\n this.prefixes = []\n this.items = {}\n }\n\n keys () { return this.prefixes }\n\n size () { return this.prefixes.length }\n\n /**\n * Find the value of the longest matching prefix key.\n */\n resolve (key: string) {\n const prefix = this.resolvePrefix(key)\n\n return typeof prefix !== 'undefined' ? this.items[prefix] : undefined\n }\n\n /**\n * Find the longest matching prefix key.\n */\n resolvePrefix (key: string) {\n // Exact match\n if (this.items[key]) return key // redundant; optimization?\n // prefix match (the list is in descending length order, and secondarily, reverse-alphabetically)\n const index = findIndex(this.prefixes, (e: string) => key.startsWith(e + '.'))\n if (index === -1) return undefined\n const prefix = this.prefixes[index]\n return prefix\n }\n\n get (prefix: string): T | undefined { return this.items[prefix] }\n\n /**\n * Look up all keys that start with a certain prefix.\n */\n * getKeysStartingWith (prefix: string): IterableIterator<string> {\n // TODO: This could be done *much* more efficiently\n const predicate = (key: string) => key.startsWith(prefix)\n let index = -1\n // tslint:disable-next-line:no-conditional-assignment\n while ((index = findIndex(this.prefixes, predicate, index + 1)) !== -1) {\n yield this.prefixes[index]\n }\n }\n\n * getKeysPrefixesOf (search: string): IterableIterator<string> {\n const predicate = (key: string) => search.startsWith(key + '.')\n let index = -1\n // tslint:disable-next-line:no-conditional-assignment\n while ((index = findIndex(this.prefixes, predicate, index + 1)) !== -1) {\n yield this.prefixes[index]\n }\n }\n\n /**\n * @param {function(item, key)} fn\n */\n each (fn: (item: T, key: string) => void) {\n for (const prefix of this.prefixes) {\n fn(this.items[prefix], prefix)\n }\n }\n\n /**\n * Insert the prefix while keeping the prefixes sorted first in length order\n * and if two prefixes are the same length, sort them in reverse alphabetical order\n */\n insert (prefix: string, item: T) {\n if (!this.items[prefix]) {\n const index = findIndex(this.prefixes, (e) => {\n if (prefix.length === e.length) {\n return prefix > e\n }\n return prefix.length > e.length\n })\n\n if (index === -1) {\n this.prefixes.push(prefix)\n } else {\n this.prefixes.splice(index, 0, prefix)\n }\n }\n this.items[prefix] = item\n return item\n }\n\n delete (prefix: string) {\n const index = this.prefixes.indexOf(prefix)\n if (this.prefixes[index] === prefix) this.prefixes.splice(index, 1)\n delete this.items[prefix]\n }\n\n toJSON () {\n return this.items\n }\n\n /**\n * Find the shortest unambiguous prefix of an ILP address in a prefix map.\n *\n * This let's us figure out what addresses the selected route applies to. For\n * example, the most specific route for destination \"a.b.c\" might be \"a\", but\n * that doesn't mean that that route applies to any destination starting with\n * \"a\" because there may be a more specific route like \"a.c\".\n *\n * So we would call this utility function to find out that the least specific\n * prefix for which there are no other more specific routes is \"a.b\".\n *\n * In order to force a minimum prefix, it can be passed as the third parameter.\n * This function may make it even more specific if necessary to make it\n * unambiguous, but it will never return a less specific prefix.\n */\n getShortestUnambiguousPrefix (address: string, prefix = '') {\n if (!address.startsWith(prefix)) {\n throw new Error(`address must start with prefix. address=${address} prefix=${prefix}`)\n }\n\n this.keys().forEach((secondPrefix: string) => {\n if (secondPrefix === prefix) {\n return\n }\n\n while (secondPrefix.startsWith(prefix)) {\n if (secondPrefix === prefix) {\n return\n }\n\n const nextSegmentEnd = address.indexOf('.', prefix.length + 1)\n\n if (nextSegmentEnd === -1) {\n prefix = address\n return\n } else {\n prefix = address.slice(0, nextSegmentEnd)\n }\n }\n })\n\n return prefix\n }\n}\n"]}
\No newline at end of file