diff --git a/src/api/load.js b/src/api/load.js index 18dd182..4073cb5 100644 --- a/src/api/load.js +++ b/src/api/load.js @@ -91,10 +91,13 @@ export async function load( const pluginGraphs = await Promise.all(pluginGraphPromises); let graph = Graph.merge(pluginGraphs); const {identities, discourseServer} = project; - if (identities.length) { - const serverUrl = - discourseServer == null ? null : discourseServer.serverUrl; - const contractions = nodeContractions(identities, serverUrl); + const identitySpec = { + identities, + discourseServerUrl: + discourseServer == null ? null : discourseServer.serverUrl, + }; + if (identitySpec.identities.length) { + const contractions = nodeContractions(identitySpec); // Only apply contractions if identities have been specified, since it involves // a full Graph copy graph = graph.contractNodes(contractions); diff --git a/src/api/load.test.js b/src/api/load.test.js index 9b484f8..8ba3d4e 100644 --- a/src/api/load.test.js +++ b/src/api/load.test.js @@ -218,8 +218,9 @@ describe("api/load", () => { ); const graphFile = path.join(projectDirectory, "graph.json"); const graphJSON = JSON.parse(await fs.readFile(graphFile)); + const identitySpec = {identities: [identity], discourseServerUrl}; const identityGraph = combinedGraph().contractNodes( - nodeContractions([identity], discourseServerUrl) + nodeContractions(identitySpec) ); const expectedJSON = identityGraph.toJSON(); expect(graphJSON).toEqual(expectedJSON); diff --git a/src/plugins/identity/contractIdentities.js b/src/plugins/identity/contractIdentities.js index 7f151ed..84908be 100644 --- a/src/plugins/identity/contractIdentities.js +++ b/src/plugins/identity/contractIdentities.js @@ -4,7 +4,7 @@ import * as Weights from "../../core/weights"; import {type WeightedGraph as WeightedGraphT} from "../../core/weightedGraph"; import {type NodeContraction, NodeAddress} from "../../core/graph"; import {nodeContractions} from "./nodeContractions"; -import {type Identity} from "./identity"; +import {type IdentitySpec} from "./identity"; /** * Applies nodeContractions to a WeightedGraph. @@ -60,8 +60,7 @@ export function _contractWeightedGraph( */ export function contractIdentities( wg: WeightedGraphT, - identities: $ReadOnlyArray, - discourseUrl: string | null + identitySpec: IdentitySpec ): WeightedGraphT { - return _contractWeightedGraph(wg, nodeContractions(identities, discourseUrl)); + return _contractWeightedGraph(wg, nodeContractions(identitySpec)); } diff --git a/src/plugins/identity/identity.js b/src/plugins/identity/identity.js index 452d116..1f34331 100644 --- a/src/plugins/identity/identity.js +++ b/src/plugins/identity/identity.js @@ -19,6 +19,17 @@ export type Identity = {| +aliases: $ReadOnlyArray, |}; +/** + * Fully specifies all Identity information. + * + * The discourseServerurl is needed if any Discourse aliases are present + * in the included identities. + */ +export type IdentitySpec = {| + +identities: $ReadOnlyArray, + +discourseServerUrl: string | null, +|}; + /** * Create a new node representing an identity. */ diff --git a/src/plugins/identity/nodeContractions.js b/src/plugins/identity/nodeContractions.js index e6d8b8e..8335d1b 100644 --- a/src/plugins/identity/nodeContractions.js +++ b/src/plugins/identity/nodeContractions.js @@ -1,7 +1,7 @@ // @flow import {type NodeContraction} from "../../core/graph"; -import {type Identity, identityNode} from "./identity"; +import {type Identity, identityNode, type IdentitySpec} from "./identity"; import {resolveAlias} from "./alias"; /** @@ -20,10 +20,7 @@ import {resolveAlias} from "./alias"; * refactor this method so it no longer takes a Discourse server url as a * special argument. */ -export function nodeContractions( - identities: $ReadOnlyArray, - discourseUrl: string | null -): NodeContraction[] { +export function nodeContractions(spec: IdentitySpec): NodeContraction[] { function errorOnDuplicate(xs: $ReadOnlyArray, kind: string) { const s = new Set(); for (const x of xs) { @@ -33,11 +30,12 @@ export function nodeContractions( s.add(x); } } + const {identities, discourseServerUrl} = spec; const usernames = identities.map((x) => x.username); errorOnDuplicate(usernames, "username"); const aliases = [].concat(...identities.map((x) => x.aliases)); errorOnDuplicate(aliases, "alias"); - return identities.map((i) => _contraction(i, discourseUrl)); + return identities.map((i) => _contraction(i, discourseServerUrl)); } /** diff --git a/src/plugins/identity/nodeContractions.test.js b/src/plugins/identity/nodeContractions.test.js index 616c5f1..6b117f1 100644 --- a/src/plugins/identity/nodeContractions.test.js +++ b/src/plugins/identity/nodeContractions.test.js @@ -41,27 +41,27 @@ describe("src/plugins/identity/nodeContractions", () => { {username: "foo", aliases: ["github/foo", "github/bar"]}, {username: "foo", aliases: []}, ]; - expect(() => nodeContractions(identities, null)).toThrowError( - "Duplicate username" - ); + expect(() => + nodeContractions({identities, discourseServerUrl: null}) + ).toThrowError("Duplicate username"); }); it("errors if any alias is duplicated", () => { const identities = [ {username: "foo", aliases: ["github/foo", "github/bar"]}, {username: "bar", aliases: ["github/foo"]}, ]; - expect(() => nodeContractions(identities, null)).toThrowError( - "Duplicate alias" - ); + expect(() => + nodeContractions({identities, discourseServerUrl: null}) + ).toThrowError("Duplicate alias"); }); it("produces a contraction for each identity", () => { const identities = [ {username: "foo", aliases: ["discourse/foo"]}, {username: "bar", aliases: ["github/bar"]}, ]; - const url = "https://example.com"; - expect(nodeContractions(identities, url)).toEqual( - identities.map((i) => _contraction(i, url)) + const spec = {identities, discourseServerUrl: "https://example.com"}; + expect(nodeContractions(spec)).toEqual( + identities.map((i) => _contraction(i, spec.discourseServerUrl)) ); }); });