Add GitHub prefixes and const types (#395)

- Switch string constant node and edge types (e.g. "REPO") to exported
consts (eg `export const REPO_TYPE`).
- Add (and internally use) a `_Prefix` psuedomodule which contains
per-type address prefixes
- Test that constructing a StructuredAddress with the wrong type is an
error.

Test plan:
Unit tests pass, snapshots unchanged.

Paired with @wchargin
This commit is contained in:
Dandelion Mané 2018-06-14 15:01:33 -07:00 committed by GitHub
parent a8bf6a36bf
commit ed3397f654
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 192 additions and 115 deletions

View File

@ -11,21 +11,39 @@ import * as GithubNode from "./nodes";
export opaque type RawAddress: EdgeAddressT = EdgeAddressT; export opaque type RawAddress: EdgeAddressT = EdgeAddressT;
export const AUTHORS_TYPE = "AUTHORS";
export const MERGED_AS_TYPE = "MERGED_AS";
export const HAS_PARENT_TYPE = "HAS_PARENT";
export const REFERENCES_TYPE = "REFERENCES";
const GITHUB_PREFIX = EdgeAddress.fromParts(["sourcecred", "github"]);
function githubEdgeAddress(...parts: string[]): RawAddress {
return EdgeAddress.append(GITHUB_PREFIX, ...parts);
}
export const _Prefix = Object.freeze({
base: GITHUB_PREFIX,
authors: githubEdgeAddress(AUTHORS_TYPE),
mergedAs: githubEdgeAddress(MERGED_AS_TYPE),
references: githubEdgeAddress(REFERENCES_TYPE),
hasParent: githubEdgeAddress(HAS_PARENT_TYPE),
});
export type AuthorsAddress = {| export type AuthorsAddress = {|
+type: "AUTHORS", +type: typeof AUTHORS_TYPE,
+author: GithubNode.UserlikeAddress, +author: GithubNode.UserlikeAddress,
+content: GithubNode.AuthorableAddress, +content: GithubNode.AuthorableAddress,
|}; |};
export type MergedAsAddress = {| export type MergedAsAddress = {|
+type: "MERGED_AS", +type: typeof MERGED_AS_TYPE,
+pull: GithubNode.PullAddress, +pull: GithubNode.PullAddress,
|}; |};
export type HasParentAddress = {| export type HasParentAddress = {|
+type: "HAS_PARENT", +type: typeof HAS_PARENT_TYPE,
+child: GithubNode.ChildAddress, +child: GithubNode.ChildAddress,
|}; |};
export type ReferencesAddress = {| export type ReferencesAddress = {|
+type: "REFERENCES", +type: typeof REFERENCES_TYPE,
+referrer: GithubNode.TextContentAddress, +referrer: GithubNode.TextContentAddress,
+referent: GithubNode.ReferentAddress, +referent: GithubNode.ReferentAddress,
|}; |};
@ -41,7 +59,7 @@ export const createEdge = Object.freeze({
author: GithubNode.UserlikeAddress, author: GithubNode.UserlikeAddress,
content: GithubNode.AuthorableAddress content: GithubNode.AuthorableAddress
): Edge => ({ ): Edge => ({
address: toRaw({type: "AUTHORS", author, content}), address: toRaw({type: AUTHORS_TYPE, author, content}),
src: GithubNode.toRaw(author), src: GithubNode.toRaw(author),
dst: GithubNode.toRaw(content), dst: GithubNode.toRaw(content),
}), }),
@ -49,7 +67,7 @@ export const createEdge = Object.freeze({
pull: GithubNode.PullAddress, pull: GithubNode.PullAddress,
commitAddress: NodeAddressT /* TODO: Make this a Git commit node address. */ commitAddress: NodeAddressT /* TODO: Make this a Git commit node address. */
): Edge => ({ ): Edge => ({
address: toRaw({type: "MERGED_AS", pull}), address: toRaw({type: MERGED_AS_TYPE, pull}),
src: GithubNode.toRaw(pull), src: GithubNode.toRaw(pull),
dst: commitAddress, dst: commitAddress,
}), }),
@ -57,7 +75,7 @@ export const createEdge = Object.freeze({
child: GithubNode.ChildAddress, child: GithubNode.ChildAddress,
parent: GithubNode.ParentAddress parent: GithubNode.ParentAddress
): Edge => ({ ): Edge => ({
address: toRaw({type: "HAS_PARENT", child}), address: toRaw({type: HAS_PARENT_TYPE, child}),
src: GithubNode.toRaw(child), src: GithubNode.toRaw(child),
dst: GithubNode.toRaw(parent), dst: GithubNode.toRaw(parent),
}), }),
@ -65,7 +83,7 @@ export const createEdge = Object.freeze({
referrer: GithubNode.TextContentAddress, referrer: GithubNode.TextContentAddress,
referent: GithubNode.ReferentAddress referent: GithubNode.ReferentAddress
): Edge => ({ ): Edge => ({
address: toRaw({type: "REFERENCES", referrer, referent}), address: toRaw({type: REFERENCES_TYPE, referrer, referent}),
src: GithubNode.toRaw(referrer), src: GithubNode.toRaw(referrer),
dst: GithubNode.toRaw(referent), dst: GithubNode.toRaw(referent),
}), }),
@ -74,10 +92,6 @@ export const createEdge = Object.freeze({
const NODE_PREFIX_LENGTH = NodeAddress.toParts(GithubNode._githubAddress()) const NODE_PREFIX_LENGTH = NodeAddress.toParts(GithubNode._githubAddress())
.length; .length;
const GITHUB_PREFIX = EdgeAddress.fromParts(["sourcecred", "github"]);
function githubEdgeAddress(...parts: string[]): RawAddress {
return EdgeAddress.append(GITHUB_PREFIX, ...parts);
}
function lengthEncode(x: GithubNode.RawAddress): $ReadOnlyArray<string> { function lengthEncode(x: GithubNode.RawAddress): $ReadOnlyArray<string> {
const baseParts = NodeAddress.toParts(x).slice(NODE_PREFIX_LENGTH); const baseParts = NodeAddress.toParts(x).slice(NODE_PREFIX_LENGTH);
return [String(baseParts.length), ...baseParts]; return [String(baseParts.length), ...baseParts];
@ -121,7 +135,7 @@ export function fromRaw(x: RawAddress): StructuredAddress {
} }
const [_unused_sc, _unused_gh, kind, ...rest] = EdgeAddress.toParts(x); const [_unused_sc, _unused_gh, kind, ...rest] = EdgeAddress.toParts(x);
switch (kind) { switch (kind) {
case "AUTHORS": { case AUTHORS_TYPE: {
const parts = multiLengthDecode(rest, fail); const parts = multiLengthDecode(rest, fail);
if (parts.length !== 2) { if (parts.length !== 2) {
throw fail(); throw fail();
@ -133,9 +147,9 @@ export function fromRaw(x: RawAddress): StructuredAddress {
const content: GithubNode.AuthorableAddress = (GithubNode.fromRaw( const content: GithubNode.AuthorableAddress = (GithubNode.fromRaw(
GithubNode._githubAddress(...contentParts) GithubNode._githubAddress(...contentParts)
): any); ): any);
return ({type: "AUTHORS", author, content}: AuthorsAddress); return ({type: AUTHORS_TYPE, author, content}: AuthorsAddress);
} }
case "MERGED_AS": { case MERGED_AS_TYPE: {
const parts = multiLengthDecode(rest, fail); const parts = multiLengthDecode(rest, fail);
if (parts.length !== 1) { if (parts.length !== 1) {
throw fail(); throw fail();
@ -144,9 +158,9 @@ export function fromRaw(x: RawAddress): StructuredAddress {
const pull: GithubNode.PullAddress = (GithubNode.fromRaw( const pull: GithubNode.PullAddress = (GithubNode.fromRaw(
GithubNode._githubAddress(...pullParts) GithubNode._githubAddress(...pullParts)
): any); ): any);
return ({type: "MERGED_AS", pull}: MergedAsAddress); return ({type: MERGED_AS_TYPE, pull}: MergedAsAddress);
} }
case "HAS_PARENT": { case HAS_PARENT_TYPE: {
const parts = multiLengthDecode(rest, fail); const parts = multiLengthDecode(rest, fail);
if (parts.length !== 1) { if (parts.length !== 1) {
throw fail(); throw fail();
@ -155,9 +169,9 @@ export function fromRaw(x: RawAddress): StructuredAddress {
const child: GithubNode.ChildAddress = (GithubNode.fromRaw( const child: GithubNode.ChildAddress = (GithubNode.fromRaw(
GithubNode._githubAddress(...childParts) GithubNode._githubAddress(...childParts)
): any); ): any);
return ({type: "HAS_PARENT", child}: HasParentAddress); return ({type: HAS_PARENT_TYPE, child}: HasParentAddress);
} }
case "REFERENCES": { case REFERENCES_TYPE: {
const parts = multiLengthDecode(rest, fail); const parts = multiLengthDecode(rest, fail);
if (parts.length !== 2) { if (parts.length !== 2) {
throw fail(); throw fail();
@ -169,7 +183,7 @@ export function fromRaw(x: RawAddress): StructuredAddress {
const referent: GithubNode.ReferentAddress = (GithubNode.fromRaw( const referent: GithubNode.ReferentAddress = (GithubNode.fromRaw(
GithubNode._githubAddress(...referentParts) GithubNode._githubAddress(...referentParts)
): any); ): any);
return ({type: "REFERENCES", referrer, referent}: ReferencesAddress); return ({type: REFERENCES_TYPE, referrer, referent}: ReferencesAddress);
} }
default: default:
throw fail(); throw fail();
@ -178,25 +192,25 @@ export function fromRaw(x: RawAddress): StructuredAddress {
export function toRaw(x: StructuredAddress): RawAddress { export function toRaw(x: StructuredAddress): RawAddress {
switch (x.type) { switch (x.type) {
case "AUTHORS": case AUTHORS_TYPE:
return githubEdgeAddress( return EdgeAddress.append(
"AUTHORS", _Prefix.authors,
...lengthEncode(GithubNode.toRaw(x.author)), ...lengthEncode(GithubNode.toRaw(x.author)),
...lengthEncode(GithubNode.toRaw(x.content)) ...lengthEncode(GithubNode.toRaw(x.content))
); );
case "MERGED_AS": case MERGED_AS_TYPE:
return githubEdgeAddress( return EdgeAddress.append(
"MERGED_AS", _Prefix.mergedAs,
...lengthEncode(GithubNode.toRaw(x.pull)) ...lengthEncode(GithubNode.toRaw(x.pull))
); );
case "HAS_PARENT": case HAS_PARENT_TYPE:
return githubEdgeAddress( return EdgeAddress.append(
"HAS_PARENT", _Prefix.hasParent,
...lengthEncode(GithubNode.toRaw(x.child)) ...lengthEncode(GithubNode.toRaw(x.child))
); );
case "REFERENCES": case REFERENCES_TYPE:
return githubEdgeAddress( return EdgeAddress.append(
"REFERENCES", _Prefix.references,
...lengthEncode(GithubNode.toRaw(x.referrer)), ...lengthEncode(GithubNode.toRaw(x.referrer)),
...lengthEncode(GithubNode.toRaw(x.referent)) ...lengthEncode(GithubNode.toRaw(x.referent))
); );

View File

@ -2,57 +2,63 @@
import {NodeAddress, EdgeAddress, edgeToString} from "../../core/graph"; import {NodeAddress, EdgeAddress, edgeToString} from "../../core/graph";
import {createEdge, fromRaw, toRaw} from "./edges"; import {createEdge, fromRaw, toRaw} from "./edges";
import * as GE from "./edges";
import * as GN from "./nodes";
describe("plugins/github/edges", () => { describe("plugins/github/edges", () => {
const nodeExamples = { const nodeExamples = {
repo: () => ({ repo: () => ({
type: "REPO", type: GN.REPO_TYPE,
owner: "sourcecred", owner: "sourcecred",
name: "example-github", name: "example-github",
}), }),
issue: () => ({type: "ISSUE", repo: nodeExamples.repo(), number: "2"}), issue: () => ({
pull: () => ({type: "PULL", repo: nodeExamples.repo(), number: "5"}), type: GN.ISSUE_TYPE,
repo: nodeExamples.repo(),
number: "2",
}),
pull: () => ({type: GN.PULL_TYPE, repo: nodeExamples.repo(), number: "5"}),
review: () => ({ review: () => ({
type: "REVIEW", type: GN.REVIEW_TYPE,
pull: nodeExamples.pull(), pull: nodeExamples.pull(),
id: "100313899", id: "100313899",
}), }),
issueComment: () => ({ issueComment: () => ({
type: "COMMENT", type: GN.COMMENT_TYPE,
parent: nodeExamples.issue(), parent: nodeExamples.issue(),
id: "373768703", id: "373768703",
}), }),
pullComment: () => ({ pullComment: () => ({
type: "COMMENT", type: GN.COMMENT_TYPE,
parent: nodeExamples.pull(), parent: nodeExamples.pull(),
id: "396430464", id: "396430464",
}), }),
reviewComment: () => ({ reviewComment: () => ({
type: "COMMENT", type: GN.COMMENT_TYPE,
parent: nodeExamples.review(), parent: nodeExamples.review(),
id: "171460198", id: "171460198",
}), }),
user: () => ({type: "USERLIKE", login: "decentralion"}), user: () => ({type: GN.USERLIKE_TYPE, login: "decentralion"}),
}; };
const edgeExamples = { const edgeExamples = {
authors: () => ({ authors: () => ({
type: "AUTHORS", type: GE.AUTHORS_TYPE,
author: nodeExamples.user(), author: nodeExamples.user(),
content: nodeExamples.pull(), content: nodeExamples.pull(),
}), }),
mergedAs: () => ({ mergedAs: () => ({
type: "MERGED_AS", type: GE.MERGED_AS_TYPE,
pull: nodeExamples.pull(), pull: nodeExamples.pull(),
}), }),
hasParent: () => ({ hasParent: () => ({
type: "HAS_PARENT", type: GE.HAS_PARENT_TYPE,
child: nodeExamples.reviewComment(), child: nodeExamples.reviewComment(),
}), }),
references: () => ({ references: () => ({
type: "REFERENCES", type: GE.REFERENCES_TYPE,
referrer: nodeExamples.issue(), referrer: nodeExamples.issue(),
referent: {type: "ISSUE", repo: nodeExamples.repo(), number: "1"}, referent: {type: GN.ISSUE_TYPE, repo: nodeExamples.repo(), number: "1"},
}), }),
}; };

View File

@ -9,33 +9,53 @@ export function _githubAddress(...parts: string[]): RawAddress {
return NodeAddress.append(GITHUB_PREFIX, ...parts); return NodeAddress.append(GITHUB_PREFIX, ...parts);
} }
export const REPO_TYPE: "REPO" = "REPO";
export const ISSUE_TYPE: "ISSUE" = "ISSUE";
export const PULL_TYPE: "PULL" = "PULL";
export const REVIEW_TYPE: "REVIEW" = "REVIEW";
export const COMMENT_TYPE: "COMMENT" = "COMMENT";
export const USERLIKE_TYPE: "USERLIKE" = "USERLIKE";
export const _Prefix = Object.freeze({
base: GITHUB_PREFIX,
repo: _githubAddress(REPO_TYPE),
issue: _githubAddress(ISSUE_TYPE),
pull: _githubAddress(PULL_TYPE),
review: _githubAddress(REVIEW_TYPE),
comment: _githubAddress(COMMENT_TYPE),
userlike: _githubAddress(USERLIKE_TYPE),
reviewComment: _githubAddress(COMMENT_TYPE, REVIEW_TYPE),
issueComment: _githubAddress(COMMENT_TYPE, ISSUE_TYPE),
pullComment: _githubAddress(COMMENT_TYPE, PULL_TYPE),
});
export type RepoAddress = {| export type RepoAddress = {|
+type: "REPO", +type: typeof REPO_TYPE,
+owner: string, +owner: string,
+name: string, +name: string,
|}; |};
export type IssueAddress = {| export type IssueAddress = {|
+type: "ISSUE", +type: typeof ISSUE_TYPE,
+repo: RepoAddress, +repo: RepoAddress,
+number: string, +number: string,
|}; |};
export type PullAddress = {| export type PullAddress = {|
+type: "PULL", +type: typeof PULL_TYPE,
+repo: RepoAddress, +repo: RepoAddress,
+number: string, +number: string,
|}; |};
export type ReviewAddress = {| export type ReviewAddress = {|
+type: "REVIEW", +type: typeof REVIEW_TYPE,
+pull: PullAddress, +pull: PullAddress,
+id: string, +id: string,
|}; |};
export type CommentAddress = {| export type CommentAddress = {|
+type: "COMMENT", +type: typeof COMMENT_TYPE,
+parent: CommentableAddress, +parent: CommentableAddress,
+id: string, +id: string,
|}; |};
export type UserlikeAddress = {| export type UserlikeAddress = {|
+type: "USERLIKE", +type: typeof USERLIKE_TYPE,
+login: string, +login: string,
|}; |};
@ -105,82 +125,82 @@ export function fromRaw(x: RawAddress): StructuredAddress {
} }
const [_unused_sc, _unused_gh, kind, ...rest] = NodeAddress.toParts(x); const [_unused_sc, _unused_gh, kind, ...rest] = NodeAddress.toParts(x);
switch (kind) { switch (kind) {
case "REPO": { case REPO_TYPE: {
if (rest.length !== 2) { if (rest.length !== 2) {
throw fail(); throw fail();
} }
const [owner, name] = rest; const [owner, name] = rest;
return {type: "REPO", owner, name}; return {type: REPO_TYPE, owner, name};
} }
case "ISSUE": { case ISSUE_TYPE: {
if (rest.length !== 3) { if (rest.length !== 3) {
throw fail(); throw fail();
} }
const [owner, name, number] = rest; const [owner, name, number] = rest;
const repo = {type: "REPO", owner, name}; const repo = {type: REPO_TYPE, owner, name};
return {type: "ISSUE", repo, number}; return {type: ISSUE_TYPE, repo, number};
} }
case "PULL": { case PULL_TYPE: {
if (rest.length !== 3) { if (rest.length !== 3) {
throw fail(); throw fail();
} }
const [owner, name, number] = rest; const [owner, name, number] = rest;
const repo = {type: "REPO", owner, name}; const repo = {type: REPO_TYPE, owner, name};
return {type: "PULL", repo, number}; return {type: PULL_TYPE, repo, number};
} }
case "REVIEW": { case REVIEW_TYPE: {
if (rest.length !== 4) { if (rest.length !== 4) {
throw fail(); throw fail();
} }
const [owner, name, pullNumber, id] = rest; const [owner, name, pullNumber, id] = rest;
const repo = {type: "REPO", owner, name}; const repo = {type: REPO_TYPE, owner, name};
const pull = {type: "PULL", repo, number: pullNumber}; const pull = {type: PULL_TYPE, repo, number: pullNumber};
return {type: "REVIEW", pull, id}; return {type: REVIEW_TYPE, pull, id};
} }
case "COMMENT": { case COMMENT_TYPE: {
if (rest.length < 1) { if (rest.length < 1) {
throw fail(); throw fail();
} }
const [subkind, ...subrest] = rest; const [subkind, ...subrest] = rest;
switch (subkind) { switch (subkind) {
case "ISSUE": { case ISSUE_TYPE: {
if (subrest.length !== 4) { if (subrest.length !== 4) {
throw fail(); throw fail();
} }
const [owner, name, issueNumber, id] = subrest; const [owner, name, issueNumber, id] = subrest;
const repo = {type: "REPO", owner, name}; const repo = {type: REPO_TYPE, owner, name};
const issue = {type: "ISSUE", repo, number: issueNumber}; const issue = {type: ISSUE_TYPE, repo, number: issueNumber};
return {type: "COMMENT", parent: issue, id}; return {type: COMMENT_TYPE, parent: issue, id};
} }
case "PULL": { case PULL_TYPE: {
if (subrest.length !== 4) { if (subrest.length !== 4) {
throw fail(); throw fail();
} }
const [owner, name, pullNumber, id] = subrest; const [owner, name, pullNumber, id] = subrest;
const repo = {type: "REPO", owner, name}; const repo = {type: REPO_TYPE, owner, name};
const pull = {type: "PULL", repo, number: pullNumber}; const pull = {type: PULL_TYPE, repo, number: pullNumber};
return {type: "COMMENT", parent: pull, id}; return {type: COMMENT_TYPE, parent: pull, id};
} }
case "REVIEW": { case REVIEW_TYPE: {
if (subrest.length !== 5) { if (subrest.length !== 5) {
throw fail(); throw fail();
} }
const [owner, name, pullNumber, reviewFragment, id] = subrest; const [owner, name, pullNumber, reviewFragment, id] = subrest;
const repo = {type: "REPO", owner, name}; const repo = {type: REPO_TYPE, owner, name};
const pull = {type: "PULL", repo, number: pullNumber}; const pull = {type: PULL_TYPE, repo, number: pullNumber};
const review = {type: "REVIEW", pull, id: reviewFragment}; const review = {type: REVIEW_TYPE, pull, id: reviewFragment};
return {type: "COMMENT", parent: review, id}; return {type: COMMENT_TYPE, parent: review, id};
} }
default: default:
throw fail(); throw fail();
} }
} }
case "USERLIKE": { case USERLIKE_TYPE: {
if (rest.length !== 1) { if (rest.length !== 1) {
throw fail(); throw fail();
} }
const [login] = rest; const [login] = rest;
return {type: "USERLIKE", login}; return {type: USERLIKE_TYPE, login};
} }
default: default:
throw fail(); throw fail();
@ -189,44 +209,51 @@ export function fromRaw(x: RawAddress): StructuredAddress {
export function toRaw(x: StructuredAddress): RawAddress { export function toRaw(x: StructuredAddress): RawAddress {
switch (x.type) { switch (x.type) {
case "REPO": case REPO_TYPE:
return _githubAddress("REPO", x.owner, x.name); return NodeAddress.append(_Prefix.repo, x.owner, x.name);
case "ISSUE": case ISSUE_TYPE:
return _githubAddress("ISSUE", x.repo.owner, x.repo.name, x.number); return NodeAddress.append(
case "PULL": _Prefix.issue,
return _githubAddress("PULL", x.repo.owner, x.repo.name, x.number); x.repo.owner,
case "REVIEW": x.repo.name,
return _githubAddress( x.number
"REVIEW", );
case PULL_TYPE:
return NodeAddress.append(
_Prefix.pull,
x.repo.owner,
x.repo.name,
x.number
);
case REVIEW_TYPE:
return NodeAddress.append(
_Prefix.review,
x.pull.repo.owner, x.pull.repo.owner,
x.pull.repo.name, x.pull.repo.name,
x.pull.number, x.pull.number,
x.id x.id
); );
case "COMMENT": case COMMENT_TYPE:
switch (x.parent.type) { switch (x.parent.type) {
case "ISSUE": case ISSUE_TYPE:
return _githubAddress( return NodeAddress.append(
"COMMENT", _Prefix.issueComment,
"ISSUE",
x.parent.repo.owner, x.parent.repo.owner,
x.parent.repo.name, x.parent.repo.name,
x.parent.number, x.parent.number,
x.id x.id
); );
case "PULL": case PULL_TYPE:
return _githubAddress( return NodeAddress.append(
"COMMENT", _Prefix.pullComment,
"PULL",
x.parent.repo.owner, x.parent.repo.owner,
x.parent.repo.name, x.parent.repo.name,
x.parent.number, x.parent.number,
x.id x.id
); );
case "REVIEW": case REVIEW_TYPE:
return _githubAddress( return NodeAddress.append(
"COMMENT", _Prefix.reviewComment,
"REVIEW",
x.parent.pull.repo.owner, x.parent.pull.repo.owner,
x.parent.pull.repo.name, x.parent.pull.repo.name,
x.parent.pull.number, x.parent.pull.number,
@ -238,8 +265,8 @@ export function toRaw(x: StructuredAddress): RawAddress {
(x.parent.type: empty); (x.parent.type: empty);
throw new Error(`Bad comment parent type: ${x.parent.type}`); throw new Error(`Bad comment parent type: ${x.parent.type}`);
} }
case "USERLIKE": case USERLIKE_TYPE:
return _githubAddress("USERLIKE", x.login); return NodeAddress.append(_Prefix.userlike, x.login);
default: default:
// eslint-disable-next-line no-unused-expressions // eslint-disable-next-line no-unused-expressions
(x.type: empty); (x.type: empty);

View File

@ -1,33 +1,50 @@
// @flow // @flow
import {NodeAddress} from "../../core/graph"; import {NodeAddress} from "../../core/graph";
import * as GN from "./nodes";
import {fromRaw, toRaw} from "./nodes"; import {fromRaw, toRaw} from "./nodes";
describe("plugins/github/nodes", () => { describe("plugins/github/nodes", () => {
const repo = () => ({ const repo = (): GN.RepoAddress => ({
type: "REPO", type: GN.REPO_TYPE,
owner: "sourcecred", owner: "sourcecred",
name: "example-github", name: "example-github",
}); });
const issue = () => ({type: "ISSUE", repo: repo(), number: "2"}); const issue = (): GN.IssueAddress => ({
const pull = () => ({type: "PULL", repo: repo(), number: "5"}); type: GN.ISSUE_TYPE,
const review = () => ({type: "REVIEW", pull: pull(), id: "100313899"}); repo: repo(),
const issueComment = () => ({ number: "2",
type: "COMMENT", });
const pull = (): GN.PullAddress => ({
type: GN.PULL_TYPE,
repo: repo(),
number: "5",
});
const review = (): GN.ReviewAddress => ({
type: GN.REVIEW_TYPE,
pull: pull(),
id: "100313899",
});
const issueComment = (): GN.CommentAddress => ({
type: GN.COMMENT_TYPE,
parent: issue(), parent: issue(),
id: "373768703", id: "373768703",
}); });
const pullComment = () => ({ const pullComment = (): GN.CommentAddress => ({
type: "COMMENT", type: GN.COMMENT_TYPE,
parent: pull(), parent: pull(),
id: "396430464", id: "396430464",
}); });
const reviewComment = () => ({ const reviewComment = (): GN.CommentAddress => ({
type: "COMMENT", type: GN.COMMENT_TYPE,
parent: review(), parent: review(),
id: "171460198", id: "171460198",
}); });
const user = () => ({type: "USERLIKE", login: "decentralion"}); const user = (): GN.UserlikeAddress => ({
type: GN.USERLIKE_TYPE,
login: "decentralion",
});
const examples = { const examples = {
repo, repo,
issue, issue,
@ -39,6 +56,19 @@ describe("plugins/github/nodes", () => {
user, user,
}; };
// Incorrect types should be caught statically, either due to being
// totally invalid...
// $ExpectFlowError
const _unused_badRepo: GN.RepoAddress = {
type: "REPOSITORY",
owner: "foo",
name: "bar",
};
// ...or due to being annotated with the type of a distinct structured
// address:
// $ExpectFlowError
const _unused_badIssue: GN.IssueAddress = {...pull()};
describe("`fromRaw` after `toRaw` is identity", () => { describe("`fromRaw` after `toRaw` is identity", () => {
Object.keys(examples).forEach((example) => { Object.keys(examples).forEach((example) => {
it(example, () => { it(example, () => {