Add flow types for GitHub graphql query response (#140)
This commit adds flow typing for the JSON result from hitting the GitHub graphql api. We can't prove that the flow typing is correct, but since the type definition is colocated with the corresponding fragment definitions, we can hope that maintainers will maintain both together. We update the parser to consume the new flow types. There are no flow errors. Test plan: Inspect the flowtypes, verify that they correspond to the data in example-repo.json, and that there are no flow errors.
This commit is contained in:
parent
418b745d7c
commit
6a3e4d754c
|
@ -93,6 +93,22 @@ export type Continuation = {|
|
||||||
+destinationPath: $ReadOnlyArray<string | number>,
|
+destinationPath: $ReadOnlyArray<string | number>,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
|
export type ConnectionJSON<+T> = {|
|
||||||
|
+nodes: $ReadOnlyArray<T>,
|
||||||
|
+pageInfo: {|
|
||||||
|
+endCursor: ?string,
|
||||||
|
+hasNextPage: boolean,
|
||||||
|
|},
|
||||||
|
|};
|
||||||
|
|
||||||
|
export type RepositoryJSON = {|
|
||||||
|
+repository: {
|
||||||
|
+id: string,
|
||||||
|
+issues: ConnectionJSON<IssueJSON>,
|
||||||
|
+pullRequests: ConnectionJSON<PullRequestJSON>,
|
||||||
|
},
|
||||||
|
|};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The top-level GitHub query to request data about a repository.
|
* The top-level GitHub query to request data about a repository.
|
||||||
* Callers will also be interested in `createVariables`.
|
* Callers will also be interested in `createVariables`.
|
||||||
|
@ -607,25 +623,49 @@ function mergeDirect<T>(destination: T, source: any): T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export type AuthorJSON = {|
|
||||||
* These fragments are used to construct the root query, and also to
|
+__typename: "User" | "Bot" | "Organization",
|
||||||
* fetch more pages of specific entity types.
|
+id: string,
|
||||||
*/
|
+login: string,
|
||||||
export function createFragments(): FragmentDefinition[] {
|
+url: string,
|
||||||
|
|};
|
||||||
|
function makePageInfo() {
|
||||||
const b = build;
|
const b = build;
|
||||||
const makePageInfo = () =>
|
return b.field("pageInfo", {}, [
|
||||||
b.field("pageInfo", {}, [b.field("hasNextPage"), b.field("endCursor")]);
|
b.field("hasNextPage"),
|
||||||
const makeAuthor = () => b.field("author", {}, [b.fragmentSpread("whoami")]);
|
b.field("endCursor"),
|
||||||
return [
|
]);
|
||||||
b.fragment("whoami", "Actor", [
|
}
|
||||||
|
function makeAuthor() {
|
||||||
|
const b = build;
|
||||||
|
return b.field("author", {}, [b.fragmentSpread("whoami")]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function whoamiFragment(): FragmentDefinition {
|
||||||
|
const b = build;
|
||||||
|
return b.fragment("whoami", "Actor", [
|
||||||
b.field("__typename"),
|
b.field("__typename"),
|
||||||
b.field("login"),
|
b.field("login"),
|
||||||
b.field("url"),
|
b.field("url"),
|
||||||
b.inlineFragment("User", [b.field("id")]),
|
b.inlineFragment("User", [b.field("id")]),
|
||||||
b.inlineFragment("Organization", [b.field("id")]),
|
b.inlineFragment("Organization", [b.field("id")]),
|
||||||
b.inlineFragment("Bot", [b.field("id")]),
|
b.inlineFragment("Bot", [b.field("id")]),
|
||||||
]),
|
]);
|
||||||
b.fragment("issues", "IssueConnection", [
|
}
|
||||||
|
|
||||||
|
export type IssueJSON = {|
|
||||||
|
+id: string,
|
||||||
|
+url: string,
|
||||||
|
+title: string,
|
||||||
|
+body: string,
|
||||||
|
+number: number,
|
||||||
|
+author: AuthorJSON,
|
||||||
|
+comments: ConnectionJSON<CommentJSON>,
|
||||||
|
|};
|
||||||
|
|
||||||
|
function issuesFragment(): FragmentDefinition {
|
||||||
|
const b = build;
|
||||||
|
return b.fragment("issues", "IssueConnection", [
|
||||||
makePageInfo(),
|
makePageInfo(),
|
||||||
b.field("nodes", {}, [
|
b.field("nodes", {}, [
|
||||||
b.field("id"),
|
b.field("id"),
|
||||||
|
@ -638,8 +678,22 @@ export function createFragments(): FragmentDefinition[] {
|
||||||
b.fragmentSpread("comments"),
|
b.fragmentSpread("comments"),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
]),
|
]);
|
||||||
b.fragment("prs", "PullRequestConnection", [
|
}
|
||||||
|
|
||||||
|
export type PullRequestJSON = {|
|
||||||
|
+id: string,
|
||||||
|
+url: string,
|
||||||
|
+title: string,
|
||||||
|
+body: string,
|
||||||
|
+number: number,
|
||||||
|
+author: AuthorJSON,
|
||||||
|
+comments: ConnectionJSON<CommentJSON>,
|
||||||
|
+reviews: ConnectionJSON<PullRequestReviewJSON>,
|
||||||
|
|};
|
||||||
|
function pullRequestsFragment(): FragmentDefinition {
|
||||||
|
const b = build;
|
||||||
|
return b.fragment("prs", "PullRequestConnection", [
|
||||||
makePageInfo(),
|
makePageInfo(),
|
||||||
b.field("nodes", {}, [
|
b.field("nodes", {}, [
|
||||||
b.field("id"),
|
b.field("id"),
|
||||||
|
@ -655,19 +709,47 @@ export function createFragments(): FragmentDefinition[] {
|
||||||
b.fragmentSpread("reviews"),
|
b.fragmentSpread("reviews"),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
]),
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CommentJSON = {|
|
||||||
|
+id: string,
|
||||||
|
+url: string,
|
||||||
|
+body: string,
|
||||||
|
+author: AuthorJSON,
|
||||||
|
|};
|
||||||
|
function commentsFragment(): FragmentDefinition {
|
||||||
|
const b = build;
|
||||||
// (Note: issue comments and PR comments use the same connection type.)
|
// (Note: issue comments and PR comments use the same connection type.)
|
||||||
b.fragment("comments", "IssueCommentConnection", [
|
return b.fragment("comments", "IssueCommentConnection", [
|
||||||
makePageInfo(),
|
makePageInfo(),
|
||||||
b.field("nodes", {}, [
|
b.field("nodes", {}, [
|
||||||
b.field("id"),
|
b.field("id"),
|
||||||
b.field("url"),
|
b.field("url"),
|
||||||
makeAuthor(),
|
makeAuthor(),
|
||||||
b.field("body"),
|
b.field("body"),
|
||||||
b.field("url"),
|
|
||||||
]),
|
]),
|
||||||
]),
|
]);
|
||||||
b.fragment("reviews", "PullRequestReviewConnection", [
|
}
|
||||||
|
|
||||||
|
export type PullRequestReviewState =
|
||||||
|
| "CHANGES_REQUESTED"
|
||||||
|
| "APPROVED"
|
||||||
|
| "COMMENTED"
|
||||||
|
| "DISMISSED"
|
||||||
|
| "PENDING";
|
||||||
|
|
||||||
|
export type PullRequestReviewJSON = {|
|
||||||
|
+id: string,
|
||||||
|
+url: string,
|
||||||
|
+body: string,
|
||||||
|
+author: AuthorJSON,
|
||||||
|
+state: PullRequestReviewState,
|
||||||
|
+comments: ConnectionJSON<PullRequestReviewCommentJSON>,
|
||||||
|
|};
|
||||||
|
function reviewsFragment(): FragmentDefinition {
|
||||||
|
const b = build;
|
||||||
|
return b.fragment("reviews", "PullRequestReviewConnection", [
|
||||||
makePageInfo(),
|
makePageInfo(),
|
||||||
b.field("nodes", {}, [
|
b.field("nodes", {}, [
|
||||||
b.field("id"),
|
b.field("id"),
|
||||||
|
@ -679,8 +761,18 @@ export function createFragments(): FragmentDefinition[] {
|
||||||
b.fragmentSpread("reviewComments"),
|
b.fragmentSpread("reviewComments"),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
]),
|
]);
|
||||||
b.fragment("reviewComments", "PullRequestReviewCommentConnection", [
|
}
|
||||||
|
|
||||||
|
export type PullRequestReviewCommentJSON = {|
|
||||||
|
+id: string,
|
||||||
|
+url: string,
|
||||||
|
+body: string,
|
||||||
|
+author: AuthorJSON,
|
||||||
|
|};
|
||||||
|
function reviewCommentsFragment(): FragmentDefinition {
|
||||||
|
const b = build;
|
||||||
|
return b.fragment("reviewComments", "PullRequestReviewCommentConnection", [
|
||||||
makePageInfo(),
|
makePageInfo(),
|
||||||
b.field("nodes", {}, [
|
b.field("nodes", {}, [
|
||||||
b.field("id"),
|
b.field("id"),
|
||||||
|
@ -688,7 +780,22 @@ export function createFragments(): FragmentDefinition[] {
|
||||||
b.field("body"),
|
b.field("body"),
|
||||||
makeAuthor(),
|
makeAuthor(),
|
||||||
]),
|
]),
|
||||||
]),
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These fragments are used to construct the root query, and also to
|
||||||
|
* fetch more pages of specific entity types.
|
||||||
|
*/
|
||||||
|
export function createFragments(): FragmentDefinition[] {
|
||||||
|
const b = build;
|
||||||
|
return [
|
||||||
|
whoamiFragment(),
|
||||||
|
issuesFragment(),
|
||||||
|
pullRequestsFragment(),
|
||||||
|
commentsFragment(),
|
||||||
|
reviewsFragment(),
|
||||||
|
reviewCommentsFragment(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,17 @@ import type {
|
||||||
PullRequestNodePayload,
|
PullRequestNodePayload,
|
||||||
IssueNodePayload,
|
IssueNodePayload,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
|
import type {
|
||||||
|
RepositoryJSON,
|
||||||
|
PullRequestReviewJSON,
|
||||||
|
PullRequestJSON,
|
||||||
|
IssueJSON,
|
||||||
|
CommentJSON,
|
||||||
|
AuthorJSON,
|
||||||
|
PullRequestReviewCommentJSON,
|
||||||
|
} from "./graphql";
|
||||||
|
|
||||||
import type {Address} from "../../core/address";
|
import type {Address} from "../../core/address";
|
||||||
import {PLUGIN_NAME} from "./pluginName";
|
import {PLUGIN_NAME} from "./pluginName";
|
||||||
import {Graph, edgeID} from "../../core/graph";
|
import {Graph, edgeID} from "../../core/graph";
|
||||||
|
@ -54,7 +65,7 @@ export class GithubParser {
|
||||||
| PullRequestReviewCommentNodePayload
|
| PullRequestReviewCommentNodePayload
|
||||||
| PullRequestReviewNodePayload
|
| PullRequestReviewNodePayload
|
||||||
>,
|
>,
|
||||||
authorJson: *
|
authorJson: AuthorJSON
|
||||||
) {
|
) {
|
||||||
let authorPayload: AuthorNodePayload = {
|
let authorPayload: AuthorNodePayload = {
|
||||||
login: authorJson.login,
|
login: authorJson.login,
|
||||||
|
@ -102,7 +113,7 @@ export class GithubParser {
|
||||||
parentNode: Node<
|
parentNode: Node<
|
||||||
IssueNodePayload | PullRequestNodePayload | PullRequestReviewNodePayload
|
IssueNodePayload | PullRequestNodePayload | PullRequestReviewNodePayload
|
||||||
>,
|
>,
|
||||||
commentJson: *
|
commentJson: CommentJSON
|
||||||
) {
|
) {
|
||||||
let commentType: NodeType;
|
let commentType: NodeType;
|
||||||
switch (parentNode.address.type) {
|
switch (parentNode.address.type) {
|
||||||
|
@ -160,7 +171,7 @@ export class GithubParser {
|
||||||
this.graph.addEdge(containsEdge);
|
this.graph.addEdge(containsEdge);
|
||||||
}
|
}
|
||||||
|
|
||||||
addIssue(issueJson: *) {
|
addIssue(issueJson: IssueJSON) {
|
||||||
const issuePayload: IssueNodePayload = {
|
const issuePayload: IssueNodePayload = {
|
||||||
url: issueJson.url,
|
url: issueJson.url,
|
||||||
number: issueJson.number,
|
number: issueJson.number,
|
||||||
|
@ -178,7 +189,7 @@ export class GithubParser {
|
||||||
issueJson.comments.nodes.forEach((c) => this.addComment(issueNode, c));
|
issueJson.comments.nodes.forEach((c) => this.addComment(issueNode, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
addPullRequest(prJson: *) {
|
addPullRequest(prJson: PullRequestJSON) {
|
||||||
const pullRequestPayload: PullRequestNodePayload = {
|
const pullRequestPayload: PullRequestNodePayload = {
|
||||||
url: prJson.url,
|
url: prJson.url,
|
||||||
number: prJson.number,
|
number: prJson.number,
|
||||||
|
@ -201,7 +212,7 @@ export class GithubParser {
|
||||||
|
|
||||||
addPullRequestReview(
|
addPullRequestReview(
|
||||||
pullRequestNode: Node<PullRequestNodePayload>,
|
pullRequestNode: Node<PullRequestNodePayload>,
|
||||||
reviewJson: *
|
reviewJson: PullRequestReviewJSON
|
||||||
) {
|
) {
|
||||||
const reviewPayload: PullRequestReviewNodePayload = {
|
const reviewPayload: PullRequestReviewNodePayload = {
|
||||||
url: reviewJson.url,
|
url: reviewJson.url,
|
||||||
|
@ -218,7 +229,7 @@ export class GithubParser {
|
||||||
reviewJson.comments.nodes.forEach((c) => this.addComment(reviewNode, c));
|
reviewJson.comments.nodes.forEach((c) => this.addComment(reviewNode, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
addData(dataJson: *) {
|
addData(dataJson: RepositoryJSON) {
|
||||||
dataJson.repository.issues.nodes.forEach((i) => this.addIssue(i));
|
dataJson.repository.issues.nodes.forEach((i) => this.addIssue(i));
|
||||||
dataJson.repository.pullRequests.nodes.forEach((pr) =>
|
dataJson.repository.pullRequests.nodes.forEach((pr) =>
|
||||||
this.addPullRequest(pr)
|
this.addPullRequest(pr)
|
||||||
|
|
Loading…
Reference in New Issue