UniRef: add GithubReferenceDetector (#1543)
As a RelationalView is not designed for multiple repositories, we should implement our own merging of mappings obtained from RelationalViews. fromRelationalViews is a factory function which does this for us. And by accepting an array of RelationalViews it's more apparent it should be used this way.
This commit is contained in:
parent
f16119af43
commit
063c08d974
|
@ -0,0 +1,37 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import dedent from "../../util/dedent";
|
||||||
|
import {type NodeAddressT, NodeAddress} from "../../core/graph";
|
||||||
|
import {MappedReferenceDetector, type URL} from "../../core/references";
|
||||||
|
import {RelationalView} from "./relationalView";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a GithubReferenceDetector using multiple RelationalView.
|
||||||
|
* As RelationalView should only be used for one repository at a time, you will
|
||||||
|
* commonly want to compose several of them into one GithubReferenceDetector.
|
||||||
|
*
|
||||||
|
* Note: duplicates are normally expected. However for any URL, the corresponding
|
||||||
|
* NodeAddressT should be the same, or we'll throw an error.
|
||||||
|
*/
|
||||||
|
export function fromRelationalViews(
|
||||||
|
views: $ReadOnlyArray<RelationalView>
|
||||||
|
): GithubReferenceDetector {
|
||||||
|
const map: Map<URL, NodeAddressT> = new Map();
|
||||||
|
for (const view of views) {
|
||||||
|
for (const [url, addr] of view.urlReferenceMap().entries()) {
|
||||||
|
const existing = map.get(url);
|
||||||
|
if (existing && existing != addr) {
|
||||||
|
throw new Error(dedent`\
|
||||||
|
An entry for ${url} already existed, but with a different NodeAddressT.
|
||||||
|
This is probably a bug with SourceCred. Please report it on GitHub.
|
||||||
|
Old: ${NodeAddress.toString(existing)}
|
||||||
|
New: ${NodeAddress.toString(addr)}
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
map.set(url, addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new GithubReferenceDetector(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GithubReferenceDetector = MappedReferenceDetector;
|
|
@ -0,0 +1,75 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import {exampleRelationalView} from "./example/example";
|
||||||
|
import {RelationalView} from "./relationalView";
|
||||||
|
import {
|
||||||
|
GithubReferenceDetector,
|
||||||
|
fromRelationalViews,
|
||||||
|
} from "./referenceDetector";
|
||||||
|
import {MappedReferenceDetector} from "../../core/references";
|
||||||
|
import {NodeAddress} from "../../core/graph";
|
||||||
|
import dedent from "../../util/dedent";
|
||||||
|
|
||||||
|
describe("plugins/github/referenceDetector", () => {
|
||||||
|
describe("GithubReferenceDetector", () => {
|
||||||
|
it("should be a MappedReferenceDetector", () => {
|
||||||
|
// Given
|
||||||
|
const map = new Map();
|
||||||
|
|
||||||
|
// When
|
||||||
|
const refs = new GithubReferenceDetector(map);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
expect(refs).toBeInstanceOf(MappedReferenceDetector);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("fromRelationalViews", () => {
|
||||||
|
it("should use urlReferenceMap to create the instance", () => {
|
||||||
|
// Given
|
||||||
|
const rv = new RelationalView();
|
||||||
|
const urlReferenceMap = jest.spyOn(rv, "urlReferenceMap");
|
||||||
|
|
||||||
|
// When
|
||||||
|
const refs = fromRelationalViews([rv, rv]);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
expect(refs).toBeInstanceOf(MappedReferenceDetector);
|
||||||
|
expect(urlReferenceMap).toBeCalledTimes(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should deduplicate silently given the same entries", () => {
|
||||||
|
// Given
|
||||||
|
const rv = exampleRelationalView();
|
||||||
|
|
||||||
|
// When
|
||||||
|
const refs = fromRelationalViews([rv, rv]);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
expect(refs.map).toEqual(rv.urlReferenceMap());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should throw when encountering duplicate keys with different values", () => {
|
||||||
|
// Given
|
||||||
|
const url = "http://foo.bar";
|
||||||
|
const nodeA = NodeAddress.fromParts(["test", "A"]);
|
||||||
|
const nodeB = NodeAddress.fromParts(["test", "B"]);
|
||||||
|
const rv1 = new RelationalView();
|
||||||
|
const rv2 = new RelationalView();
|
||||||
|
const rv1Spy = jest.spyOn(rv1, "urlReferenceMap");
|
||||||
|
const rv2Spy = jest.spyOn(rv2, "urlReferenceMap");
|
||||||
|
rv1Spy.mockReturnValue(new Map([[url, nodeA]]));
|
||||||
|
rv2Spy.mockReturnValue(new Map([[url, nodeB]]));
|
||||||
|
|
||||||
|
// When
|
||||||
|
const fn = () => fromRelationalViews([rv1, rv2]);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
expect(fn).toThrow(dedent`\
|
||||||
|
An entry for http://foo.bar already existed, but with a different NodeAddressT.
|
||||||
|
This is probably a bug with SourceCred. Please report it on GitHub.
|
||||||
|
Old: NodeAddress["test","A"]
|
||||||
|
New: NodeAddress["test","B"]`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue