diff --git a/src/v3/plugins/github/relationalView.js b/src/v3/plugins/github/relationalView.js index 546c60a..4d5a428 100644 --- a/src/v3/plugins/github/relationalView.js +++ b/src/v3/plugins/github/relationalView.js @@ -1,5 +1,6 @@ // @flow +import {toCompat, fromCompat, type Compatible} from "../../util/compat"; import stringify from "json-stable-stringify"; import {parseReferences} from "./parseReferences"; import * as N from "./nodes"; @@ -22,6 +23,11 @@ import { reviewCommentUrlToId, } from "./urlIdParse"; +const COMPAT_INFO = { + type: "sourcecred/github/relationalView", + version: "0.1.0", +}; + export class RelationalView { _repos: Map; _issues: Map; @@ -164,6 +170,34 @@ export class RelationalView { yield* this.userlikes(); } + toJSON(): RelationalViewJSON { + const rawJSON = { + repos: addressMapToObject(this._repos), + issues: addressMapToObject(this._issues), + pulls: addressMapToObject(this._pulls), + reviews: addressMapToObject(this._reviews), + comments: addressMapToObject(this._comments), + userlikes: addressMapToObject(this._userlikes), + references: addressMapToObject(this._mapReferences), + referencedBy: addressMapToObject(this._mapReferencedBy), + }; + return toCompat(COMPAT_INFO, rawJSON); + } + + static fromJSON(compatJson: RelationalViewJSON): RelationalView { + const json = fromCompat(COMPAT_INFO, compatJson); + const rv = new RelationalView(); + rv._repos = objectToAddressMap(json.repos); + rv._issues = objectToAddressMap(json.issues); + rv._pulls = objectToAddressMap(json.pulls); + rv._reviews = objectToAddressMap(json.reviews); + rv._comments = objectToAddressMap(json.comments); + rv._userlikes = objectToAddressMap(json.userlikes); + rv._mapReferences = objectToAddressMap(json.references); + rv._mapReferencedBy = objectToAddressMap(json.referencedBy); + return rv; + } + _addRepo(json: Q.RepositoryJSON) { const address: RepoAddress = { type: N.REPO_TYPE, @@ -736,3 +770,36 @@ export type TextContentEntity = Issue | Pull | Review | Comment; export type ParentEntity = Repo | Issue | Pull | Review; export type ChildEntity = Issue | Pull | Review | Comment; export type ReferentEntity = Repo | Issue | Pull | Review | Comment | Userlike; + +function addressMapToObject( + x: Map +): AddressEntryMapJSON { + const result: {[N.RawAddress]: T} = {}; + for (const [address, entry] of x.entries()) { + result[address] = entry; + } + return result; +} + +function objectToAddressMap( + x: AddressEntryMapJSON +): Map { + const result = new Map(); + for (const key of Object.keys(x)) { + const address: N.RawAddress = (key: any); + result.set(address, x[address]); + } + return result; +} + +export opaque type AddressEntryMapJSON = {[N.RawAddress]: T}; +export opaque type RelationalViewJSON = Compatible<{| + +repos: AddressEntryMapJSON, + +issues: AddressEntryMapJSON, + +pulls: AddressEntryMapJSON, + +reviews: AddressEntryMapJSON, + +comments: AddressEntryMapJSON, + +userlikes: AddressEntryMapJSON, + +references: AddressEntryMapJSON, + +referencedBy: AddressEntryMapJSON, +|}>; diff --git a/src/v3/plugins/github/relationalView.test.js b/src/v3/plugins/github/relationalView.test.js index 929d076..62280ab 100644 --- a/src/v3/plugins/github/relationalView.test.js +++ b/src/v3/plugins/github/relationalView.test.js @@ -223,4 +223,13 @@ describe("plugins/github/relationalView", () => { // may be fragile expect(rv1).toEqual(rv2); }); + + describe("to/fromJSON", () => { + it("to->from->to is identity", () => { + const json1 = view.toJSON(); + const view1 = R.RelationalView.fromJSON(json1); + const json2 = view1.toJSON(); + expect(json1).toEqual(json2); + }); + }); });