diff --git a/src/core/references/index.js b/src/core/references/index.js index f88725d..03c94b6 100644 --- a/src/core/references/index.js +++ b/src/core/references/index.js @@ -1,3 +1,4 @@ //@flow export type {URL, ReferenceDetector} from "./referenceDetector"; +export {MappedReferenceDetector} from "./mappedReferenceDetector"; diff --git a/src/core/references/mappedReferenceDetector.js b/src/core/references/mappedReferenceDetector.js new file mode 100644 index 0000000..3c3f294 --- /dev/null +++ b/src/core/references/mappedReferenceDetector.js @@ -0,0 +1,26 @@ +//@flow + +import type {NodeAddressT} from "../graph"; +import type {ReferenceDetector, URL} from "./referenceDetector"; + +/** + * A reference detector which uses a pregenerated `Map` as a + * lookup table. + * + * Note: this is sensitive to canonicalization issues because it's based on string + * comparisons. For example: + * - "http://foo.bar/123" != "http://foo.bar/123#chapter-2" + * - "http://foo.bar/?a=1&b=2" != "http://foo.bar/?b=2&a=1" + * - "http://foo.bar/space+bar" != "http://foo.bar/space%20bar" + */ +export class MappedReferenceDetector implements ReferenceDetector { + map: Map; + + constructor(map: Map) { + this.map = map; + } + + addressFromUrl(url: URL): ?NodeAddressT { + return this.map.get(url); + } +} diff --git a/src/core/references/mappedReferenceDetector.test.js b/src/core/references/mappedReferenceDetector.test.js new file mode 100644 index 0000000..f7ea37e --- /dev/null +++ b/src/core/references/mappedReferenceDetector.test.js @@ -0,0 +1,45 @@ +// @flow + +import {type NodeAddressT, NodeAddress} from "../graph"; +import type {URL, ReferenceDetector} from "./referenceDetector"; +import {MappedReferenceDetector} from "./mappedReferenceDetector"; + +const nodeA = NodeAddress.fromParts(["test", "A"]); +const nodeB = NodeAddress.fromParts(["test", "B"]); +const nodeC = NodeAddress.fromParts(["test", "C"]); + +describe("core/references/mappedReferenceDetector", () => { + describe("MappedReferenceDetector", () => { + it("should implement the ReferenceDetector interface", () => { + const _unused_toReferenceDetector = ( + x: MappedReferenceDetector + ): ReferenceDetector => x; + }); + + it("should return values of exactly matching keys in the map", () => { + // Given + const map: Map = new Map([ + ["http://foo.bar/a", nodeA], + ["http://foo.bar/b", nodeB], + ["http://foo.bar/c", nodeC], + ]); + + // When + const refs = new MappedReferenceDetector(map); + const n1a = refs.addressFromUrl("http://foo.bar/a"); + const n2a = refs.addressFromUrl("http://foo.bar/b"); + const n3a = refs.addressFromUrl("http://foo.bar/c"); + const n1b = refs.addressFromUrl("https://foo.bar/a"); + const n2b = refs.addressFromUrl("http://foo.bar/b?key=val"); + const n3b = refs.addressFromUrl("http://foo.bar/c#anchor"); + + // Then + expect(n1a).toEqual(nodeA); + expect(n2a).toEqual(nodeB); + expect(n3a).toEqual(nodeC); + expect(n1b).toEqual(undefined); + expect(n2b).toEqual(undefined); + expect(n3b).toEqual(undefined); + }); + }); +});