mirror of
https://github.com/status-im/sourcecred.git
synced 2025-01-14 22:54:46 +00:00
Refactor PluginAdapter abstraction (#512)
- PluginAdapters no longer expose a Renderer; instead, the render methods are inlined on the PluginAdapter. The extra abstraction didn't provide any lift in the current architecture. - The edgeVerb function has been removed. - PluginAdapters now enumerate EdgeTypes. Each has a prefix, and a forward and a backward name. Test plan: `yarn travis`, plus manual testing of the frontend and the weight config.
This commit is contained in:
parent
28100275c4
commit
3c14ef8a43
@ -32,7 +32,7 @@ export function nodeDescription(
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return adapter.renderer().nodeDescription(address);
|
return adapter.nodeDescription(address);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const result = NodeAddress.toString(address);
|
const result = NodeAddress.toString(address);
|
||||||
console.error(`Error getting description for ${result}: ${e.message}`);
|
console.error(`Error getting description for ${result}: ${e.message}`);
|
||||||
@ -54,13 +54,15 @@ function edgeVerb(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
const edgeType = adapter
|
||||||
return adapter.renderer().edgeVerb(address, direction);
|
.edgeTypes()
|
||||||
} catch (e) {
|
.find(({prefix}) => EdgeAddress.hasPrefix(address, prefix));
|
||||||
|
if (edgeType == null) {
|
||||||
const result = EdgeAddress.toString(address);
|
const result = EdgeAddress.toString(address);
|
||||||
console.error(`Error getting description for ${result}: ${e.message}`);
|
console.warn(`No edge type for ${result}`);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
return direction === "FORWARD" ? edgeType.forwardName : edgeType.backwardName;
|
||||||
}
|
}
|
||||||
|
|
||||||
function scoreDisplay(probability: number) {
|
function scoreDisplay(probability: number) {
|
||||||
|
@ -61,57 +61,66 @@ function example() {
|
|||||||
throw new Error("unused");
|
throw new Error("unused");
|
||||||
},
|
},
|
||||||
renderer: () => ({
|
renderer: () => ({
|
||||||
nodeDescription: (x) => `foo: ${NodeAddress.toString(x)}`,
|
|
||||||
edgeVerb: (_unused_e, direction) =>
|
edgeVerb: (_unused_e, direction) =>
|
||||||
direction === "FORWARD" ? "foos" : "is fooed by",
|
direction === "FORWARD" ? "foos" : "is fooed by",
|
||||||
}),
|
}),
|
||||||
|
nodeDescription: (x) => `foo: ${NodeAddress.toString(x)}`,
|
||||||
nodePrefix: () => NodeAddress.fromParts(["foo"]),
|
nodePrefix: () => NodeAddress.fromParts(["foo"]),
|
||||||
edgePrefix: () => EdgeAddress.fromParts(["foo"]),
|
edgePrefix: () => EdgeAddress.fromParts(["foo"]),
|
||||||
nodeTypes: () => [
|
nodeTypes: () => [
|
||||||
{name: "alpha", prefix: NodeAddress.fromParts(["foo", "a"])},
|
{name: "alpha", prefix: NodeAddress.fromParts(["foo", "a"])},
|
||||||
{name: "beta", prefix: NodeAddress.fromParts(["foo", "b"])},
|
{name: "beta", prefix: NodeAddress.fromParts(["foo", "b"])},
|
||||||
],
|
],
|
||||||
|
edgeTypes: () => [
|
||||||
|
{
|
||||||
|
prefix: EdgeAddress.fromParts(["foo"]),
|
||||||
|
forwardName: "foos",
|
||||||
|
backwardName: "is fooed by",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: () => "bar",
|
name: () => "bar",
|
||||||
graph: () => {
|
graph: () => {
|
||||||
throw new Error("unused");
|
throw new Error("unused");
|
||||||
},
|
},
|
||||||
renderer: () => ({
|
nodeDescription: (x) => `bar: ${NodeAddress.toString(x)}`,
|
||||||
nodeDescription: (x) => `bar: ${NodeAddress.toString(x)}`,
|
|
||||||
edgeVerb: (_unused_e, direction) =>
|
|
||||||
direction === "FORWARD" ? "bars" : "is barred by",
|
|
||||||
}),
|
|
||||||
nodePrefix: () => NodeAddress.fromParts(["bar"]),
|
nodePrefix: () => NodeAddress.fromParts(["bar"]),
|
||||||
edgePrefix: () => EdgeAddress.fromParts(["bar"]),
|
edgePrefix: () => EdgeAddress.fromParts(["bar"]),
|
||||||
nodeTypes: () => [
|
nodeTypes: () => [
|
||||||
{name: "alpha", prefix: NodeAddress.fromParts(["bar", "a"])},
|
{name: "alpha", prefix: NodeAddress.fromParts(["bar", "a"])},
|
||||||
],
|
],
|
||||||
|
edgeTypes: () => [
|
||||||
|
{
|
||||||
|
prefix: EdgeAddress.fromParts(["bar"]),
|
||||||
|
forwardName: "bars",
|
||||||
|
backwardName: "is barred by",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: () => "xox",
|
name: () => "xox",
|
||||||
graph: () => {
|
graph: () => {
|
||||||
throw new Error("unused");
|
throw new Error("unused");
|
||||||
},
|
},
|
||||||
renderer: () => ({
|
nodeDescription: (_unused_arg) => `xox node!`,
|
||||||
nodeDescription: (_unused_arg) => `xox node!`,
|
|
||||||
edgeVerb: (_unused_e, _unused_direction) => `xox'd`,
|
|
||||||
}),
|
|
||||||
nodePrefix: () => NodeAddress.fromParts(["xox"]),
|
nodePrefix: () => NodeAddress.fromParts(["xox"]),
|
||||||
edgePrefix: () => EdgeAddress.fromParts(["xox"]),
|
edgePrefix: () => EdgeAddress.fromParts(["xox"]),
|
||||||
nodeTypes: () => [],
|
nodeTypes: () => [],
|
||||||
|
edgeTypes: () => [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: () => "unused",
|
name: () => "unused",
|
||||||
graph: () => {
|
graph: () => {
|
||||||
throw new Error("unused");
|
throw new Error("unused");
|
||||||
},
|
},
|
||||||
renderer: () => {
|
nodeDescription: () => {
|
||||||
throw new Error("Impossible!");
|
throw new Error("Unused");
|
||||||
},
|
},
|
||||||
nodePrefix: () => NodeAddress.fromParts(["unused"]),
|
nodePrefix: () => NodeAddress.fromParts(["unused"]),
|
||||||
edgePrefix: () => EdgeAddress.fromParts(["unused"]),
|
edgePrefix: () => EdgeAddress.fromParts(["unused"]),
|
||||||
nodeTypes: () => [],
|
nodeTypes: () => [],
|
||||||
|
edgeTypes: () => [],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -2,19 +2,19 @@
|
|||||||
|
|
||||||
import type {Graph, NodeAddressT, EdgeAddressT} from "../core/graph";
|
import type {Graph, NodeAddressT, EdgeAddressT} from "../core/graph";
|
||||||
|
|
||||||
export interface Renderer {
|
|
||||||
nodeDescription(NodeAddressT): string;
|
|
||||||
edgeVerb(EdgeAddressT, "FORWARD" | "BACKWARD"): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PluginAdapter {
|
export interface PluginAdapter {
|
||||||
name(): string;
|
name(): string;
|
||||||
graph(): Graph;
|
graph(): Graph;
|
||||||
renderer(): Renderer;
|
|
||||||
nodePrefix(): NodeAddressT;
|
nodePrefix(): NodeAddressT;
|
||||||
edgePrefix(): EdgeAddressT;
|
edgePrefix(): EdgeAddressT;
|
||||||
nodeTypes(): Array<{|
|
nodeTypes(): Array<{|
|
||||||
+name: string,
|
+name: string,
|
||||||
+prefix: NodeAddressT,
|
+prefix: NodeAddressT,
|
||||||
|}>;
|
|}>;
|
||||||
|
nodeDescription(NodeAddressT): string;
|
||||||
|
edgeTypes(): Array<{|
|
||||||
|
+forwardName: string,
|
||||||
|
+backwardName: string,
|
||||||
|
+prefix: EdgeAddressT,
|
||||||
|
|}>;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import type {
|
import type {PluginAdapter as IPluginAdapter} from "../../app/pluginAdapter";
|
||||||
PluginAdapter as IPluginAdapter,
|
|
||||||
Renderer as IRenderer,
|
|
||||||
} from "../../app/pluginAdapter";
|
|
||||||
import {Graph} from "../../core/graph";
|
import {Graph} from "../../core/graph";
|
||||||
import * as N from "./nodes";
|
import * as N from "./nodes";
|
||||||
import * as E from "./edges";
|
import * as E from "./edges";
|
||||||
import {description, edgeVerb} from "./render";
|
import {description} from "./render";
|
||||||
|
|
||||||
export async function createPluginAdapter(
|
export async function createPluginAdapter(
|
||||||
repoOwner: string,
|
repoOwner: string,
|
||||||
@ -33,15 +30,18 @@ class PluginAdapter implements IPluginAdapter {
|
|||||||
graph() {
|
graph() {
|
||||||
return this._graph;
|
return this._graph;
|
||||||
}
|
}
|
||||||
renderer() {
|
|
||||||
return new Renderer();
|
|
||||||
}
|
|
||||||
nodePrefix() {
|
nodePrefix() {
|
||||||
return N._Prefix.base;
|
return N._Prefix.base;
|
||||||
}
|
}
|
||||||
edgePrefix() {
|
edgePrefix() {
|
||||||
return E._Prefix.base;
|
return E._Prefix.base;
|
||||||
}
|
}
|
||||||
|
nodeDescription(node) {
|
||||||
|
// This cast is unsound, and might throw at runtime, but won't have
|
||||||
|
// silent failures or cause problems down the road.
|
||||||
|
const address = N.fromRaw((node: any));
|
||||||
|
return description(address);
|
||||||
|
}
|
||||||
nodeTypes() {
|
nodeTypes() {
|
||||||
return [
|
return [
|
||||||
{name: "Blob", prefix: N._Prefix.blob},
|
{name: "Blob", prefix: N._Prefix.blob},
|
||||||
@ -50,16 +50,33 @@ class PluginAdapter implements IPluginAdapter {
|
|||||||
{name: "Tree entry", prefix: N._Prefix.treeEntry},
|
{name: "Tree entry", prefix: N._Prefix.treeEntry},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
edgeTypes() {
|
||||||
|
return [
|
||||||
class Renderer implements IRenderer {
|
{
|
||||||
nodeDescription(node) {
|
forwardName: "has tree",
|
||||||
// This cast is unsound, and might throw at runtime, but won't have
|
backwardName: "owned by",
|
||||||
// silent failures or cause problems down the road.
|
prefix: E._Prefix.hasTree,
|
||||||
const address = N.fromRaw((node: any));
|
},
|
||||||
return description(address);
|
{
|
||||||
}
|
forwardName: "has parent",
|
||||||
edgeVerb(edgeAddress, direction) {
|
backwardName: "is parent of",
|
||||||
return edgeVerb(E.fromRaw((edgeAddress: any)), direction);
|
prefix: E._Prefix.hasParent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
forwardName: "includes",
|
||||||
|
backwardName: "is included by",
|
||||||
|
prefix: E._Prefix.includes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
forwardName: "evolves to",
|
||||||
|
backwardName: "evolves from",
|
||||||
|
prefix: E._Prefix.becomes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
forwardName: "has contents",
|
||||||
|
backwardName: "is contents of",
|
||||||
|
prefix: E._Prefix.hasContents,
|
||||||
|
},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as N from "./nodes";
|
import * as N from "./nodes";
|
||||||
import * as E from "./edges";
|
|
||||||
|
|
||||||
export function description(address: N.StructuredAddress) {
|
export function description(address: N.StructuredAddress) {
|
||||||
switch (address.type) {
|
switch (address.type) {
|
||||||
@ -19,24 +18,3 @@ export function description(address: N.StructuredAddress) {
|
|||||||
throw new Error(`unknown type: ${(address.type: empty)}`);
|
throw new Error(`unknown type: ${(address.type: empty)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function edgeVerb(
|
|
||||||
address: E.StructuredAddress,
|
|
||||||
direction: "FORWARD" | "BACKWARD"
|
|
||||||
) {
|
|
||||||
const forward = direction === "FORWARD";
|
|
||||||
switch (address.type) {
|
|
||||||
case "HAS_TREE":
|
|
||||||
return forward ? "has tree" : "owned by";
|
|
||||||
case "HAS_PARENT":
|
|
||||||
return forward ? "has parent" : "is parent of";
|
|
||||||
case "INCLUDES":
|
|
||||||
return forward ? "includes" : "is included by";
|
|
||||||
case "BECOMES":
|
|
||||||
return forward ? "evolves to" : "evolves from";
|
|
||||||
case "HAS_CONTENTS":
|
|
||||||
return forward ? "has contents" : "is contents of";
|
|
||||||
default:
|
|
||||||
throw new Error(`unknown type: ${(address.type: empty)}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import type {
|
import type {PluginAdapter as IPluginAdapter} from "../../app/pluginAdapter";
|
||||||
PluginAdapter as IPluginAdapter,
|
|
||||||
Renderer as IRenderer,
|
|
||||||
} from "../../app/pluginAdapter";
|
|
||||||
import {type Graph, NodeAddress} from "../../core/graph";
|
import {type Graph, NodeAddress} from "../../core/graph";
|
||||||
import {createGraph} from "./createGraph";
|
import {createGraph} from "./createGraph";
|
||||||
import * as N from "./nodes";
|
import * as N from "./nodes";
|
||||||
import * as E from "./edges";
|
import * as E from "./edges";
|
||||||
import {RelationalView} from "./relationalView";
|
import {RelationalView} from "./relationalView";
|
||||||
import {description, edgeVerb} from "./render";
|
import {description} from "./render";
|
||||||
|
|
||||||
export async function createPluginAdapter(
|
export async function createPluginAdapter(
|
||||||
repoOwner: string,
|
repoOwner: string,
|
||||||
@ -35,12 +32,19 @@ class PluginAdapter implements IPluginAdapter {
|
|||||||
name() {
|
name() {
|
||||||
return "GitHub";
|
return "GitHub";
|
||||||
}
|
}
|
||||||
|
nodeDescription(node) {
|
||||||
|
// This cast is unsound, and might throw at runtime, but won't have
|
||||||
|
// silent failures or cause problems down the road.
|
||||||
|
const address = N.fromRaw((node: any));
|
||||||
|
const entity = this._view.entity(address);
|
||||||
|
if (entity == null) {
|
||||||
|
throw new Error(`unknown entity: ${NodeAddress.toString(node)}`);
|
||||||
|
}
|
||||||
|
return description(entity);
|
||||||
|
}
|
||||||
graph() {
|
graph() {
|
||||||
return this._graph;
|
return this._graph;
|
||||||
}
|
}
|
||||||
renderer() {
|
|
||||||
return new Renderer(this._view);
|
|
||||||
}
|
|
||||||
nodePrefix() {
|
nodePrefix() {
|
||||||
return N._Prefix.base;
|
return N._Prefix.base;
|
||||||
}
|
}
|
||||||
@ -57,24 +61,28 @@ class PluginAdapter implements IPluginAdapter {
|
|||||||
{name: "User", prefix: N._Prefix.userlike},
|
{name: "User", prefix: N._Prefix.userlike},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
edgeTypes() {
|
||||||
|
return [
|
||||||
class Renderer implements IRenderer {
|
{
|
||||||
+_view: RelationalView;
|
forwardName: "authors",
|
||||||
constructor(view) {
|
backwardName: "is authored by",
|
||||||
this._view = view;
|
prefix: E._Prefix.authors,
|
||||||
}
|
},
|
||||||
nodeDescription(node) {
|
{
|
||||||
// This cast is unsound, and might throw at runtime, but won't have
|
forwardName: "has parent",
|
||||||
// silent failures or cause problems down the road.
|
backwardName: "has child",
|
||||||
const address = N.fromRaw((node: any));
|
prefix: E._Prefix.hasParent,
|
||||||
const entity = this._view.entity(address);
|
},
|
||||||
if (entity == null) {
|
{
|
||||||
throw new Error(`unknown entity: ${NodeAddress.toString(node)}`);
|
forwardName: "merges",
|
||||||
}
|
backwardName: "is merged by",
|
||||||
return description(entity);
|
prefix: E._Prefix.mergedAs,
|
||||||
}
|
},
|
||||||
edgeVerb(edgeAddress, direction) {
|
{
|
||||||
return edgeVerb(E.fromRaw((edgeAddress: any)), direction);
|
forwardName: "references",
|
||||||
|
backwardName: "is referenced by",
|
||||||
|
prefix: E._Prefix.references,
|
||||||
|
},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as R from "./relationalView";
|
import * as R from "./relationalView";
|
||||||
import * as E from "./edges";
|
|
||||||
|
|
||||||
export function description(e: R.Entity) {
|
export function description(e: R.Entity) {
|
||||||
const withAuthors = (x: R.AuthoredEntity) => {
|
const withAuthors = (x: R.AuthoredEntity) => {
|
||||||
@ -25,22 +24,3 @@ export function description(e: R.Entity) {
|
|||||||
};
|
};
|
||||||
return R.match(handlers, e);
|
return R.match(handlers, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function edgeVerb(
|
|
||||||
e: E.StructuredAddress,
|
|
||||||
direction: "FORWARD" | "BACKWARD"
|
|
||||||
) {
|
|
||||||
const forward = direction === "FORWARD";
|
|
||||||
switch (e.type) {
|
|
||||||
case "AUTHORS":
|
|
||||||
return forward ? "authors" : "is authored by";
|
|
||||||
case "MERGED_AS":
|
|
||||||
return forward ? "merges" : "is merged by";
|
|
||||||
case "HAS_PARENT":
|
|
||||||
return forward ? "has parent" : "has child";
|
|
||||||
case "REFERENCES":
|
|
||||||
return forward ? "references" : "is referenced by";
|
|
||||||
default:
|
|
||||||
throw new Error(`Unexpected type ${(e.type: empty)}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user