diff --git a/src/plugins/initiatives/initiativesDirectory.js b/src/plugins/initiatives/initiativesDirectory.js index b324d03..2ee3825 100644 --- a/src/plugins/initiatives/initiativesDirectory.js +++ b/src/plugins/initiatives/initiativesDirectory.js @@ -1,8 +1,17 @@ // @flow import {type ReferenceDetector} from "../../core/references"; +import {type NodeAddressT, NodeAddress} from "../../core/graph"; import {type Compatible, fromCompat, toCompat} from "../../util/compat"; -import {type InitiativeRepository, type URL} from "./initiative"; +import {initiativeNodeType} from "./declaration"; +import { + type InitiativeId, + type InitiativeRepository, + type URL, + createId, +} from "./initiative"; + +export const INITIATIVE_FILE_SUBTYPE = "INITIATIVE_FILE"; /** * Represents an Initiatives directory. @@ -61,3 +70,31 @@ export function fromJSON(j: Compatible): InitiativeFile { export function toJSON(m: InitiativeFile): Compatible { return toCompat(COMPAT_INFO, m); } + +/** + * When provided with the initiative NodeAddressT of an InitiativeFile this extracts + * the URL from it. Or null when the address is not for an InitiativeFile. + */ +export function initiativeFileURL(address: NodeAddressT): string | null { + const initiativeFilePrefix = NodeAddress.append( + initiativeNodeType.prefix, + INITIATIVE_FILE_SUBTYPE + ); + + if (!NodeAddress.hasPrefix(address, initiativeFilePrefix)) { + return null; + } + + const parts = NodeAddress.toParts(address); + const remoteUrl = parts[4]; + const fileName = parts[5]; + return `${remoteUrl}/${fileName}`; +} + +// Creates the InitiativeId for an InitiativeFile. +export function _initiativeFileId( + {remoteUrl}: InitiativesDirectory, + fileName: string +): InitiativeId { + return createId(INITIATIVE_FILE_SUBTYPE, remoteUrl, fileName); +} diff --git a/src/plugins/initiatives/initiativesDirectory.test.js b/src/plugins/initiatives/initiativesDirectory.test.js index 90d6e38..8a8f4d8 100644 --- a/src/plugins/initiatives/initiativesDirectory.test.js +++ b/src/plugins/initiatives/initiativesDirectory.test.js @@ -1,6 +1,15 @@ // @flow -import {type InitiativeFile, fromJSON, toJSON} from "./initiativesDirectory"; +import {NodeAddress} from "../../core/graph"; +import {createId, addressFromId} from "./initiative"; +import { + type InitiativeFile, + type InitiativesDirectory, + fromJSON, + toJSON, + initiativeFileURL, + _initiativeFileId, +} from "./initiativesDirectory"; const exampleInitiativeFile = (): InitiativeFile => ({ title: "Sample initiative", @@ -25,4 +34,49 @@ describe("plugins/initiatives/initiativesDirectory", () => { expect(actual).toEqual(initiativeFile); }); }); + + describe("initiativeFileURL", () => { + it("should return null for a different prefix", () => { + // Given + const address = NodeAddress.fromParts(["foobar"]); + + // When + const url = initiativeFileURL(address); + + // Then + expect(url).toEqual(null); + }); + + it("should detect the correct prefix and create a URL", () => { + // Given + const remoteUrl = "http://foo.bar/dir"; + const fileName = "sample.json"; + const address = addressFromId( + createId("INITIATIVE_FILE", remoteUrl, fileName) + ); + + // When + const url = initiativeFileURL(address); + + // Then + expect(url).toEqual(`${remoteUrl}/${fileName}`); + }); + }); + + describe("_initiativeFileId", () => { + it("should add the correct prefix to a remoteUrl and fileName", () => { + // Given + const dir: InitiativesDirectory = { + localPath: "should-not-be-used", + remoteUrl: "http://foo.bar/dir", + }; + const fileName = "sample.json"; + + // When + const id = _initiativeFileId(dir, fileName); + + // Then + expect(id).toEqual(createId("INITIATIVE_FILE", dir.remoteUrl, fileName)); + }); + }); });