mirror of
https://github.com/status-im/sourcecred.git
synced 2025-01-12 21:54:37 +00:00
Factor out plugin declarations (#947)
The plugin adapters are specific to `app/` and have logic for fetching data from the backend, producing React nodes for descriptions, et cetera. However, they also have information that is generic to the plugin itself: its name, its node/edge prefixes, and its types. This method factors out the generic info into a `PluginDeclaration`, which is a type (rather than an interface). Then, the plugin adapter has a `declaration` method which returns the declaration. Current users of the plugin adapters get additional mechanical complexity because they need to call `.declaration().property` rather than `.property()`, but this is not too significant. The main benefit is that #704 is unblocked, as the cli `analyze` command will be able to get necessary information from the declaration. As an added benefit, the organization of plugin code is somewhat improved. Test plan: `yarn test` sufficies, but I also ran `yarn start` and checked the UI behavior to be safe.
This commit is contained in:
parent
5f2cc56172
commit
cb30023a02
12
src/analysis/pluginDeclaration.js
Normal file
12
src/analysis/pluginDeclaration.js
Normal file
@ -0,0 +1,12 @@
|
||||
// @flow
|
||||
|
||||
import {type NodeAddressT, type EdgeAddressT} from "../core/graph";
|
||||
import type {EdgeType, NodeType} from "./types";
|
||||
|
||||
export type PluginDeclaration = {|
|
||||
+name: string,
|
||||
+nodePrefix: NodeAddressT,
|
||||
+edgePrefix: EdgeAddressT,
|
||||
+nodeTypes: $ReadOnlyArray<NodeType>,
|
||||
+edgeTypes: $ReadOnlyArray<EdgeType>,
|
||||
|};
|
@ -25,13 +25,13 @@ export class StaticAdapterSet {
|
||||
this._typeEdgeTrie = new EdgeTrie();
|
||||
const usedPluginNames = new Set();
|
||||
this._adapters.forEach((a) => {
|
||||
const name = a.name();
|
||||
const name = a.declaration().name;
|
||||
if (usedPluginNames.has(name)) {
|
||||
throw new Error(`Multiple plugins with name "${name}"`);
|
||||
}
|
||||
usedPluginNames.add(name);
|
||||
this._adapterNodeTrie.add(a.nodePrefix(), a);
|
||||
this._adapterEdgeTrie.add(a.edgePrefix(), a);
|
||||
this._adapterNodeTrie.add(a.declaration().nodePrefix, a);
|
||||
this._adapterEdgeTrie.add(a.declaration().edgePrefix, a);
|
||||
});
|
||||
this.nodeTypes().forEach((t) => this._typeNodeTrie.add(t.prefix, t));
|
||||
this.edgeTypes().forEach((t) => this._typeEdgeTrie.add(t.prefix, t));
|
||||
@ -42,11 +42,11 @@ export class StaticAdapterSet {
|
||||
}
|
||||
|
||||
nodeTypes(): NodeType[] {
|
||||
return [].concat(...this._adapters.map((x) => x.nodeTypes()));
|
||||
return [].concat(...this._adapters.map((x) => x.declaration().nodeTypes));
|
||||
}
|
||||
|
||||
edgeTypes(): EdgeType[] {
|
||||
return [].concat(...this._adapters.map((x) => x.edgeTypes()));
|
||||
return [].concat(...this._adapters.map((x) => x.declaration().edgeTypes));
|
||||
}
|
||||
|
||||
adapterMatchingNode(x: NodeAddressT): StaticPluginAdapter {
|
||||
@ -87,8 +87,8 @@ export class DynamicAdapterSet {
|
||||
this._adapterNodeTrie = new NodeTrie();
|
||||
this._adapterEdgeTrie = new EdgeTrie();
|
||||
this._adapters.forEach((a) => {
|
||||
this._adapterNodeTrie.add(a.static().nodePrefix(), a);
|
||||
this._adapterEdgeTrie.add(a.static().edgePrefix(), a);
|
||||
this._adapterNodeTrie.add(a.static().declaration().nodePrefix, a);
|
||||
this._adapterEdgeTrie.add(a.static().declaration().edgePrefix, a);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -27,26 +27,26 @@ describe("app/adapters/adapterSet", () => {
|
||||
});
|
||||
it("always includes the fallback plugin", () => {
|
||||
const {sas} = example();
|
||||
expect(sas.adapters()[0].name()).toBe(FALLBACK_NAME);
|
||||
expect(sas.adapters()[0].declaration().name).toBe(FALLBACK_NAME);
|
||||
});
|
||||
it("includes the manually provided plugin adapters", () => {
|
||||
const {x, sas} = example();
|
||||
expect(sas.adapters()[1].name()).toBe(x.name());
|
||||
expect(sas.adapters()[1].declaration().name).toBe(x.declaration().name);
|
||||
});
|
||||
it("aggregates NodeTypes across plugins", () => {
|
||||
const {sas} = example();
|
||||
const nodeTypes = sas.nodeTypes();
|
||||
const expectedNumNodeTypes =
|
||||
new FactorioStaticAdapter().nodeTypes().length +
|
||||
new FallbackStaticAdapter().nodeTypes().length;
|
||||
new FactorioStaticAdapter().declaration().nodeTypes.length +
|
||||
new FallbackStaticAdapter().declaration().nodeTypes.length;
|
||||
expect(nodeTypes).toHaveLength(expectedNumNodeTypes);
|
||||
});
|
||||
it("aggregates EdgeTypes across plugins", () => {
|
||||
const {sas} = example();
|
||||
const edgeTypes = sas.edgeTypes();
|
||||
const expectedNumEdgeTypes =
|
||||
new FactorioStaticAdapter().edgeTypes().length +
|
||||
new FallbackStaticAdapter().edgeTypes().length;
|
||||
new FactorioStaticAdapter().declaration().edgeTypes.length +
|
||||
new FallbackStaticAdapter().declaration().edgeTypes.length;
|
||||
expect(edgeTypes).toHaveLength(expectedNumEdgeTypes);
|
||||
});
|
||||
it("finds adapter matching a node", () => {
|
||||
@ -54,24 +54,24 @@ describe("app/adapters/adapterSet", () => {
|
||||
const matching = sas.adapterMatchingNode(
|
||||
NodeAddress.fromParts(["factorio", "inserter"])
|
||||
);
|
||||
expect(matching.name()).toBe(x.name());
|
||||
expect(matching.declaration().name).toBe(x.declaration().name);
|
||||
});
|
||||
it("finds adapter matching an edge", () => {
|
||||
const {x, sas} = example();
|
||||
const matching = sas.adapterMatchingEdge(
|
||||
EdgeAddress.fromParts(["factorio", "assembles"])
|
||||
);
|
||||
expect(matching.name()).toBe(x.name());
|
||||
expect(matching.declaration().name).toBe(x.declaration().name);
|
||||
});
|
||||
it("finds fallback adapter for unregistered node", () => {
|
||||
const {sas} = example();
|
||||
const adapter = sas.adapterMatchingNode(NodeAddress.fromParts(["weird"]));
|
||||
expect(adapter.name()).toBe(FALLBACK_NAME);
|
||||
expect(adapter.declaration().name).toBe(FALLBACK_NAME);
|
||||
});
|
||||
it("finds fallback adapter for unregistered edge", () => {
|
||||
const {sas} = example();
|
||||
const adapter = sas.adapterMatchingEdge(EdgeAddress.fromParts(["weird"]));
|
||||
expect(adapter.name()).toBe(FALLBACK_NAME);
|
||||
expect(adapter.declaration().name).toBe(FALLBACK_NAME);
|
||||
});
|
||||
it("finds type matching a node", () => {
|
||||
const {sas} = example();
|
||||
@ -133,8 +133,8 @@ describe("app/adapters/adapterSet", () => {
|
||||
});
|
||||
it("allows accessing the dynamic adapters", async () => {
|
||||
const {sas, das} = await example();
|
||||
expect(das.adapters().map((a) => a.static().name())).toEqual(
|
||||
sas.adapters().map((a) => a.name())
|
||||
expect(das.adapters().map((a) => a.static().declaration().name)).toEqual(
|
||||
sas.adapters().map((a) => a.declaration().name)
|
||||
);
|
||||
});
|
||||
it("allows retrieval of the aggregated graph", async () => {
|
||||
@ -147,24 +147,24 @@ describe("app/adapters/adapterSet", () => {
|
||||
const matching = das.adapterMatchingNode(
|
||||
NodeAddress.fromParts(["factorio", "inserter"])
|
||||
);
|
||||
expect(matching.static().name()).toBe(x.name());
|
||||
expect(matching.static().declaration().name).toBe(x.declaration().name);
|
||||
});
|
||||
it("finds adapter matching an edge", async () => {
|
||||
const {x, das} = await example();
|
||||
const matching = das.adapterMatchingEdge(
|
||||
EdgeAddress.fromParts(["factorio", "assembles"])
|
||||
);
|
||||
expect(matching.static().name()).toBe(x.name());
|
||||
expect(matching.static().declaration().name).toBe(x.declaration().name);
|
||||
});
|
||||
it("finds fallback adapter for unregistered node", async () => {
|
||||
const {das} = await example();
|
||||
const adapter = das.adapterMatchingNode(NodeAddress.fromParts(["weird"]));
|
||||
expect(adapter.static().name()).toBe(FALLBACK_NAME);
|
||||
expect(adapter.static().declaration().name).toBe(FALLBACK_NAME);
|
||||
});
|
||||
it("finds fallback adapter for unregistered edge", async () => {
|
||||
const {das} = await example();
|
||||
const adapter = das.adapterMatchingEdge(EdgeAddress.fromParts(["weird"]));
|
||||
expect(adapter.static().name()).toBe(FALLBACK_NAME);
|
||||
expect(adapter.static().declaration().name).toBe(FALLBACK_NAME);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
} from "../../core/graph";
|
||||
import type {StaticPluginAdapter, DynamicPluginAdapter} from "./pluginAdapter";
|
||||
import type {EdgeType, NodeType} from "../../analysis/types";
|
||||
import type {PluginDeclaration} from "../../analysis/pluginDeclaration";
|
||||
|
||||
import {StaticAdapterSet} from "./adapterSet";
|
||||
import {makeRepoId, type RepoId} from "../../core/repoId";
|
||||
@ -43,22 +44,18 @@ export const transportsEdgeType: EdgeType = Object.freeze({
|
||||
prefix: EdgeAddress.fromParts(["factorio", "transports"]),
|
||||
});
|
||||
|
||||
export const declaration: PluginDeclaration = Object.freeze({
|
||||
name: "Factorio demo adapter",
|
||||
nodePrefix: NodeAddress.fromParts(["factorio"]),
|
||||
nodeTypes: [inserterNodeType, machineNodeType],
|
||||
edgePrefix: EdgeAddress.fromParts(["factorio"]),
|
||||
edgeTypes: [assemblesEdgeType, transportsEdgeType],
|
||||
});
|
||||
|
||||
export class FactorioStaticAdapter implements StaticPluginAdapter {
|
||||
loadingMock: Function;
|
||||
name() {
|
||||
return "Factorio demo adapter";
|
||||
}
|
||||
nodePrefix() {
|
||||
return NodeAddress.fromParts(["factorio"]);
|
||||
}
|
||||
nodeTypes() {
|
||||
return [inserterNodeType, machineNodeType];
|
||||
}
|
||||
edgePrefix() {
|
||||
return EdgeAddress.fromParts(["factorio"]);
|
||||
}
|
||||
edgeTypes() {
|
||||
return [assemblesEdgeType, transportsEdgeType];
|
||||
declaration() {
|
||||
return declaration;
|
||||
}
|
||||
async load(assets: Assets, repoId: RepoId): Promise<DynamicPluginAdapter> {
|
||||
if (this.loadingMock) {
|
||||
|
@ -28,25 +28,17 @@ export const fallbackEdgeType = Object.freeze({
|
||||
prefix: EdgeAddress.empty,
|
||||
});
|
||||
|
||||
export const fallbackDeclaration = Object.freeze({
|
||||
name: FALLBACK_NAME,
|
||||
nodePrefix: NodeAddress.empty,
|
||||
edgePrefix: EdgeAddress.empty,
|
||||
nodeTypes: [fallbackNodeType],
|
||||
edgeTypes: [fallbackEdgeType],
|
||||
});
|
||||
|
||||
export class FallbackStaticAdapter implements StaticPluginAdapter {
|
||||
name() {
|
||||
return FALLBACK_NAME;
|
||||
}
|
||||
|
||||
nodePrefix() {
|
||||
return NodeAddress.empty;
|
||||
}
|
||||
|
||||
edgePrefix() {
|
||||
return EdgeAddress.empty;
|
||||
}
|
||||
|
||||
nodeTypes() {
|
||||
return [fallbackNodeType];
|
||||
}
|
||||
|
||||
edgeTypes() {
|
||||
return [fallbackEdgeType];
|
||||
declaration() {
|
||||
return fallbackDeclaration;
|
||||
}
|
||||
|
||||
load(_unused_assets: Assets, _unused_repoId: RepoId) {
|
||||
|
@ -1,17 +1,13 @@
|
||||
// @flow
|
||||
|
||||
import {type Node as ReactNode} from "react";
|
||||
import {Graph, type NodeAddressT, type EdgeAddressT} from "../../core/graph";
|
||||
import {Graph, type NodeAddressT} from "../../core/graph";
|
||||
import type {Assets} from "../assets";
|
||||
import type {RepoId} from "../../core/repoId";
|
||||
import type {EdgeType, NodeType} from "../../analysis/types";
|
||||
import type {PluginDeclaration} from "../../analysis/pluginDeclaration";
|
||||
|
||||
export interface StaticPluginAdapter {
|
||||
name(): string;
|
||||
nodePrefix(): NodeAddressT;
|
||||
edgePrefix(): EdgeAddressT;
|
||||
nodeTypes(): NodeType[];
|
||||
edgeTypes(): EdgeType[];
|
||||
declaration(): PluginDeclaration;
|
||||
load(assets: Assets, repoId: RepoId): Promise<DynamicPluginAdapter>;
|
||||
}
|
||||
|
||||
|
@ -95,17 +95,17 @@ export class PagerankTable extends React.PureComponent<
|
||||
function optionGroup(adapter: DynamicPluginAdapter) {
|
||||
const header = (
|
||||
<option
|
||||
key={adapter.static().nodePrefix()}
|
||||
value={adapter.static().nodePrefix()}
|
||||
key={adapter.static().declaration().nodePrefix}
|
||||
value={adapter.static().declaration().nodePrefix}
|
||||
style={{fontWeight: "bold"}}
|
||||
>
|
||||
{adapter.static().name()}
|
||||
{adapter.static().declaration().name}
|
||||
</option>
|
||||
);
|
||||
const entries = adapter
|
||||
.static()
|
||||
.nodeTypes()
|
||||
.map((type) => (
|
||||
.declaration()
|
||||
.nodeTypes.map((type) => (
|
||||
<option key={type.prefix} value={type.prefix}>
|
||||
{"\u2003" + type.name}
|
||||
</option>
|
||||
@ -122,10 +122,11 @@ export class PagerankTable extends React.PureComponent<
|
||||
}}
|
||||
>
|
||||
<option value={NodeAddress.empty}>Show all</option>
|
||||
{sortBy(adapters.adapters(), (a: DynamicPluginAdapter) =>
|
||||
a.static().name()
|
||||
{sortBy(
|
||||
adapters.adapters(),
|
||||
(a: DynamicPluginAdapter) => a.static().declaration().name
|
||||
)
|
||||
.filter((a) => a.static().name() !== FALLBACK_NAME)
|
||||
.filter((a) => a.static().declaration().name !== FALLBACK_NAME)
|
||||
.map(optionGroup)}
|
||||
</select>
|
||||
</label>
|
||||
|
@ -66,14 +66,14 @@ export class PluginWeightConfig extends React.Component<Props> {
|
||||
|
||||
_validateWeightedTypesWithAdapter() {
|
||||
const expectedNodePrefixes = new Set(
|
||||
this.props.adapter.nodeTypes().map((x) => x.prefix)
|
||||
this.props.adapter.declaration().nodeTypes.map((x) => x.prefix)
|
||||
);
|
||||
const actualNodePrefixes = new Set(this.props.weightedTypes.nodes.keys());
|
||||
if (!deepEqual(expectedNodePrefixes, actualNodePrefixes)) {
|
||||
throw new Error("weightedTypes has wrong node prefixes for adapter");
|
||||
}
|
||||
const expectedEdgePrefixes = new Set(
|
||||
this.props.adapter.edgeTypes().map((x) => x.prefix)
|
||||
this.props.adapter.declaration().edgeTypes.map((x) => x.prefix)
|
||||
);
|
||||
const actualEdgePrefixes = new Set(this.props.weightedTypes.edges.keys());
|
||||
if (!deepEqual(expectedEdgePrefixes, actualEdgePrefixes)) {
|
||||
@ -85,7 +85,7 @@ export class PluginWeightConfig extends React.Component<Props> {
|
||||
this._validateWeightedTypesWithAdapter();
|
||||
return (
|
||||
<div>
|
||||
<h3>{this.props.adapter.name()}</h3>
|
||||
<h3>{this.props.adapter.declaration().name}</h3>
|
||||
<h4 style={{marginBottom: "0.3em"}}>Node weights</h4>
|
||||
{this._renderNodeWeightControls()}
|
||||
<h4 style={{marginBottom: "0.3em"}}>Edge weights</h4>
|
||||
|
@ -41,7 +41,7 @@ describe("app/credExplorer/weights/PluginWeightConfig", () => {
|
||||
it("renders a NodeTypeConfig for each node type", () => {
|
||||
const {el, adapter} = example();
|
||||
const ntc = el.find(NodeTypeConfig);
|
||||
const nodeTypes = adapter.nodeTypes();
|
||||
const nodeTypes = adapter.declaration().nodeTypes;
|
||||
for (let i = 0; i < nodeTypes.length; i++) {
|
||||
const weightedType = defaultWeightedNodeType(nodeTypes[i]);
|
||||
expect(ntc.at(i).props().weightedType).toEqual(weightedType);
|
||||
@ -50,7 +50,7 @@ describe("app/credExplorer/weights/PluginWeightConfig", () => {
|
||||
it("renders a EdgeTypeConfig for each edge type", () => {
|
||||
const {el, adapter} = example();
|
||||
const ntc = el.find(EdgeTypeConfig);
|
||||
const edgeTypes = adapter.edgeTypes();
|
||||
const edgeTypes = adapter.declaration().edgeTypes;
|
||||
for (let i = 0; i < edgeTypes.length; i++) {
|
||||
const weightedType = defaultWeightedEdgeType(edgeTypes[i]);
|
||||
expect(ntc.at(i).props().weightedType).toEqual(weightedType);
|
||||
@ -60,13 +60,17 @@ describe("app/credExplorer/weights/PluginWeightConfig", () => {
|
||||
const {el, adapter, onChange} = example();
|
||||
const ntc = el.find(NodeTypeConfig).at(0);
|
||||
|
||||
const nodes = adapter.nodeTypes().map(defaultWeightedNodeType);
|
||||
const nodes = adapter
|
||||
.declaration()
|
||||
.nodeTypes.map(defaultWeightedNodeType);
|
||||
const newWeightedType = {...nodes[0], weight: 707};
|
||||
const newNodes = [newWeightedType, ...nodes.slice(1)];
|
||||
const expected = {
|
||||
nodes: new Map(newNodes.map((x) => [x.type.prefix, x])),
|
||||
edges: new Map(
|
||||
adapter.edgeTypes().map((x) => [x.prefix, defaultWeightedEdgeType(x)])
|
||||
adapter
|
||||
.declaration()
|
||||
.edgeTypes.map((x) => [x.prefix, defaultWeightedEdgeType(x)])
|
||||
),
|
||||
};
|
||||
ntc.props().onChange(newWeightedType);
|
||||
@ -76,12 +80,16 @@ describe("app/credExplorer/weights/PluginWeightConfig", () => {
|
||||
it("EdgeTypeConfig onChange wired properly", () => {
|
||||
const {el, adapter, onChange} = example();
|
||||
const ntc = el.find(EdgeTypeConfig).at(0);
|
||||
const edges = adapter.edgeTypes().map(defaultWeightedEdgeType);
|
||||
const edges = adapter
|
||||
.declaration()
|
||||
.edgeTypes.map(defaultWeightedEdgeType);
|
||||
const newWeightedType = {...edges[0], weight: 707};
|
||||
const newEdges = [newWeightedType, ...edges.slice(1)];
|
||||
const expected = {
|
||||
nodes: new Map(
|
||||
adapter.nodeTypes().map((x) => [x.prefix, defaultWeightedNodeType(x)])
|
||||
adapter
|
||||
.declaration()
|
||||
.nodeTypes.map((x) => [x.prefix, defaultWeightedNodeType(x)])
|
||||
),
|
||||
edges: new Map(newEdges.map((x) => [x.type.prefix, x])),
|
||||
};
|
||||
|
@ -39,7 +39,7 @@ export class WeightConfig extends React.Component<Props> {
|
||||
_renderPluginWeightConfigs() {
|
||||
return this.props.adapters
|
||||
.adapters()
|
||||
.filter((x) => x.name() !== FALLBACK_NAME)
|
||||
.filter((x) => x.declaration().name !== FALLBACK_NAME)
|
||||
.map((adapter) => {
|
||||
const onChange = (weightedTypes) => {
|
||||
const newWeightedTypes = {
|
||||
@ -58,13 +58,13 @@ export class WeightConfig extends React.Component<Props> {
|
||||
nodes: new Map(),
|
||||
edges: new Map(),
|
||||
};
|
||||
for (const {prefix} of adapter.nodeTypes()) {
|
||||
for (const {prefix} of adapter.declaration().nodeTypes) {
|
||||
pluginScopedWeightedTypes.nodes.set(
|
||||
prefix,
|
||||
NullUtil.get(this.props.weightedTypes.nodes.get(prefix))
|
||||
);
|
||||
}
|
||||
for (const {prefix} of adapter.edgeTypes()) {
|
||||
for (const {prefix} of adapter.declaration().edgeTypes) {
|
||||
pluginScopedWeightedTypes.edges.set(
|
||||
prefix,
|
||||
NullUtil.get(this.props.weightedTypes.edges.get(prefix))
|
||||
@ -72,7 +72,7 @@ export class WeightConfig extends React.Component<Props> {
|
||||
}
|
||||
return (
|
||||
<PluginWeightConfig
|
||||
key={adapter.name()}
|
||||
key={adapter.declaration().name}
|
||||
adapter={adapter}
|
||||
onChange={onChange}
|
||||
weightedTypes={pluginScopedWeightedTypes}
|
||||
|
@ -38,11 +38,12 @@ describe("app/credExplorer/weights/WeightConfig", () => {
|
||||
const pwcs = el.find(PluginWeightConfig);
|
||||
expect(pwcs).toHaveLength(adapters.adapters().length - 1);
|
||||
for (const adapter of adapters.adapters()) {
|
||||
if (adapter.name() === FALLBACK_NAME) {
|
||||
if (adapter.declaration().name === FALLBACK_NAME) {
|
||||
continue;
|
||||
}
|
||||
const pwc = pwcs.findWhere(
|
||||
(x) => x.props().adapter.name() === adapter.name()
|
||||
(x) =>
|
||||
x.props().adapter.declaration().name === adapter.declaration().name
|
||||
);
|
||||
expect(pwc).toHaveLength(1);
|
||||
}
|
||||
@ -52,7 +53,9 @@ describe("app/credExplorer/weights/WeightConfig", () => {
|
||||
const pwc = el
|
||||
.find(PluginWeightConfig)
|
||||
.findWhere(
|
||||
(x) => x.props().adapter.name() === new FactorioStaticAdapter().name()
|
||||
(x) =>
|
||||
x.props().adapter.declaration().name ===
|
||||
new FactorioStaticAdapter().declaration().name
|
||||
);
|
||||
expect(pwc).toHaveLength(1);
|
||||
const expectedTypes = defaultWeightsForAdapter(
|
||||
@ -84,7 +87,9 @@ describe("app/credExplorer/weights/WeightConfig", () => {
|
||||
const factorioConfig = el
|
||||
.find(PluginWeightConfig)
|
||||
.findWhere(
|
||||
(x) => x.props().adapter.name() === new FactorioStaticAdapter().name()
|
||||
(x) =>
|
||||
x.props().adapter.declaration().name ===
|
||||
new FactorioStaticAdapter().declaration().name
|
||||
);
|
||||
factorioConfig.props().onChange(newFactorioWeights);
|
||||
expect(onChange).toHaveBeenCalledTimes(1);
|
||||
|
@ -40,10 +40,14 @@ export function defaultWeightsForAdapter(
|
||||
): WeightedTypes {
|
||||
return {
|
||||
nodes: new Map(
|
||||
adapter.nodeTypes().map((x) => [x.prefix, defaultWeightedNodeType(x)])
|
||||
adapter
|
||||
.declaration()
|
||||
.nodeTypes.map((x) => [x.prefix, defaultWeightedNodeType(x)])
|
||||
),
|
||||
edges: new Map(
|
||||
adapter.edgeTypes().map((x) => [x.prefix, defaultWeightedEdgeType(x)])
|
||||
adapter
|
||||
.declaration()
|
||||
.edgeTypes.map((x) => [x.prefix, defaultWeightedEdgeType(x)])
|
||||
),
|
||||
};
|
||||
}
|
||||
|
@ -35,10 +35,14 @@ describe("app/credExplorer/weights/weights", () => {
|
||||
const adapter = new FactorioStaticAdapter();
|
||||
const expected = {
|
||||
nodes: new Map(
|
||||
adapter.nodeTypes().map((x) => [x.prefix, defaultWeightedNodeType(x)])
|
||||
adapter
|
||||
.declaration()
|
||||
.nodeTypes.map((x) => [x.prefix, defaultWeightedNodeType(x)])
|
||||
),
|
||||
edges: new Map(
|
||||
adapter.edgeTypes().map((x) => [x.prefix, defaultWeightedEdgeType(x)])
|
||||
adapter
|
||||
.declaration()
|
||||
.edgeTypes.map((x) => [x.prefix, defaultWeightedEdgeType(x)])
|
||||
),
|
||||
};
|
||||
expect(defaultWeightsForAdapter(adapter)).toEqual(expected);
|
||||
|
31
src/plugins/git/declaration.js
Normal file
31
src/plugins/git/declaration.js
Normal file
@ -0,0 +1,31 @@
|
||||
// @flow
|
||||
|
||||
import type {PluginDeclaration} from "../../analysis/pluginDeclaration";
|
||||
import * as N from "./nodes";
|
||||
import * as E from "./edges";
|
||||
|
||||
const commitNodeType = Object.freeze({
|
||||
name: "Commit",
|
||||
pluralName: "Commits",
|
||||
prefix: N.Prefix.commit,
|
||||
defaultWeight: 2,
|
||||
});
|
||||
|
||||
const hasParentEdgeType = Object.freeze({
|
||||
forwardName: "has parent",
|
||||
backwardName: "is parent of",
|
||||
prefix: E.Prefix.hasParent,
|
||||
defaultForwardWeight: 1,
|
||||
defaultBackwardWeight: 1,
|
||||
});
|
||||
|
||||
const nodeTypes = Object.freeze([commitNodeType]);
|
||||
const edgeTypes = Object.freeze([hasParentEdgeType]);
|
||||
|
||||
export const declaration: PluginDeclaration = Object.freeze({
|
||||
name: "Git",
|
||||
nodePrefix: N.Prefix.base,
|
||||
edgePrefix: E.Prefix.base,
|
||||
nodeTypes,
|
||||
edgeTypes,
|
||||
});
|
@ -5,12 +5,13 @@ import type {
|
||||
} from "../../app/adapters/pluginAdapter";
|
||||
import {Graph} from "../../core/graph";
|
||||
import * as N from "./nodes";
|
||||
import * as E from "./edges";
|
||||
import {description} from "./render";
|
||||
import type {Assets} from "../../app/assets";
|
||||
import type {RepoId} from "../../core/repoId";
|
||||
import type {Repository} from "./types";
|
||||
import type {GitGateway} from "./gitGateway";
|
||||
import type {PluginDeclaration} from "../../analysis/pluginDeclaration";
|
||||
import {declaration} from "./declaration";
|
||||
|
||||
export class StaticPluginAdapter implements IStaticPluginAdapter {
|
||||
_gitGateway: GitGateway;
|
||||
@ -18,35 +19,8 @@ export class StaticPluginAdapter implements IStaticPluginAdapter {
|
||||
constructor(gg: GitGateway): void {
|
||||
this._gitGateway = gg;
|
||||
}
|
||||
name() {
|
||||
return "Git";
|
||||
}
|
||||
nodePrefix() {
|
||||
return N.Prefix.base;
|
||||
}
|
||||
edgePrefix() {
|
||||
return E.Prefix.base;
|
||||
}
|
||||
nodeTypes() {
|
||||
return [
|
||||
{
|
||||
name: "Commit",
|
||||
pluralName: "Commits",
|
||||
prefix: N.Prefix.commit,
|
||||
defaultWeight: 2,
|
||||
},
|
||||
];
|
||||
}
|
||||
edgeTypes() {
|
||||
return [
|
||||
{
|
||||
forwardName: "has parent",
|
||||
backwardName: "is parent of",
|
||||
prefix: E.Prefix.hasParent,
|
||||
defaultForwardWeight: 1,
|
||||
defaultBackwardWeight: 1,
|
||||
},
|
||||
];
|
||||
declaration(): PluginDeclaration {
|
||||
return declaration;
|
||||
}
|
||||
async load(assets: Assets, repoId: RepoId): Promise<IDynamicPluginAdapter> {
|
||||
const baseUrl = `/api/v1/data/data/${repoId.owner}/${repoId.name}/git/`;
|
||||
|
151
src/plugins/github/declaration.js
Normal file
151
src/plugins/github/declaration.js
Normal file
@ -0,0 +1,151 @@
|
||||
// @flow
|
||||
|
||||
import type {PluginDeclaration} from "../../analysis/pluginDeclaration";
|
||||
import * as N from "./nodes";
|
||||
import * as E from "./edges";
|
||||
|
||||
const repoNodeType = Object.freeze({
|
||||
name: "Repository",
|
||||
pluralName: "Repositories",
|
||||
prefix: N.Prefix.repo,
|
||||
defaultWeight: 4,
|
||||
});
|
||||
|
||||
const issueNodeType = Object.freeze({
|
||||
name: "Issue",
|
||||
pluralName: "Issues",
|
||||
prefix: N.Prefix.issue,
|
||||
defaultWeight: 2,
|
||||
});
|
||||
|
||||
const pullNodeType = Object.freeze({
|
||||
name: "Pull request",
|
||||
pluralName: "Pull requests",
|
||||
prefix: N.Prefix.pull,
|
||||
defaultWeight: 4,
|
||||
});
|
||||
|
||||
const reviewNodeType = Object.freeze({
|
||||
name: "Pull request review",
|
||||
pluralName: "Pull request reviews",
|
||||
prefix: N.Prefix.review,
|
||||
defaultWeight: 1,
|
||||
});
|
||||
|
||||
const commentNodeType = Object.freeze({
|
||||
name: "Comment",
|
||||
pluralName: "Comments",
|
||||
prefix: N.Prefix.comment,
|
||||
defaultWeight: 1,
|
||||
});
|
||||
|
||||
const userNodeType = Object.freeze({
|
||||
name: "User",
|
||||
pluralName: "Users",
|
||||
prefix: N.Prefix.user,
|
||||
defaultWeight: 1,
|
||||
});
|
||||
|
||||
const botNodeType = Object.freeze({
|
||||
name: "Bot",
|
||||
pluralName: "Bots",
|
||||
prefix: N.Prefix.bot,
|
||||
defaultWeight: 0.25,
|
||||
});
|
||||
|
||||
const nodeTypes = Object.freeze([
|
||||
repoNodeType,
|
||||
issueNodeType,
|
||||
pullNodeType,
|
||||
reviewNodeType,
|
||||
commentNodeType,
|
||||
userNodeType,
|
||||
botNodeType,
|
||||
]);
|
||||
|
||||
const authorsEdgeType = Object.freeze({
|
||||
forwardName: "authors",
|
||||
backwardName: "is authored by",
|
||||
defaultForwardWeight: 1 / 2,
|
||||
defaultBackwardWeight: 1,
|
||||
prefix: E.Prefix.authors,
|
||||
});
|
||||
|
||||
const hasParentEdgeType = Object.freeze({
|
||||
forwardName: "has parent",
|
||||
backwardName: "has child",
|
||||
defaultForwardWeight: 1,
|
||||
defaultBackwardWeight: 1 / 4,
|
||||
prefix: E.Prefix.hasParent,
|
||||
});
|
||||
|
||||
const mergedAsEdgeType = Object.freeze({
|
||||
forwardName: "merges",
|
||||
backwardName: "is merged by",
|
||||
defaultForwardWeight: 1 / 2,
|
||||
defaultBackwardWeight: 1,
|
||||
prefix: E.Prefix.mergedAs,
|
||||
});
|
||||
|
||||
const referencesEdgeType = Object.freeze({
|
||||
forwardName: "references",
|
||||
backwardName: "is referenced by",
|
||||
defaultForwardWeight: 1,
|
||||
defaultBackwardWeight: 1 / 16,
|
||||
prefix: E.Prefix.references,
|
||||
});
|
||||
|
||||
const mentionsAuthorEdgeType = Object.freeze({
|
||||
forwardName: "mentions author of",
|
||||
backwardName: "has author mentioned by",
|
||||
defaultForwardWeight: 1,
|
||||
// TODO(#811): Probably change this to 0
|
||||
defaultBackwardWeight: 1 / 32,
|
||||
prefix: E.Prefix.mentionsAuthor,
|
||||
});
|
||||
|
||||
const reactsHeartEdgeType = Object.freeze({
|
||||
forwardName: "reacted ❤️ to",
|
||||
backwardName: "got ❤️ from",
|
||||
defaultForwardWeight: 2,
|
||||
// TODO(#811): Probably change this to 0
|
||||
defaultBackwardWeight: 1 / 32,
|
||||
prefix: E.Prefix.reactsHeart,
|
||||
});
|
||||
|
||||
const reactsThumbsUpEdgeType = Object.freeze({
|
||||
forwardName: "reacted 👍 to",
|
||||
backwardName: "got 👍 from",
|
||||
defaultForwardWeight: 1,
|
||||
// TODO(#811): Probably change this to 0
|
||||
defaultBackwardWeight: 1 / 32,
|
||||
prefix: E.Prefix.reactsThumbsUp,
|
||||
});
|
||||
|
||||
const reactsHoorayEdgeType = Object.freeze({
|
||||
forwardName: "reacted 🎉 to",
|
||||
backwardName: "got 🎉 from",
|
||||
defaultForwardWeight: 4,
|
||||
// TODO(#811): Probably change this to 0
|
||||
defaultBackwardWeight: 1 / 32,
|
||||
prefix: E.Prefix.reactsHooray,
|
||||
});
|
||||
|
||||
const edgeTypes = Object.freeze([
|
||||
authorsEdgeType,
|
||||
hasParentEdgeType,
|
||||
mergedAsEdgeType,
|
||||
referencesEdgeType,
|
||||
mentionsAuthorEdgeType,
|
||||
reactsThumbsUpEdgeType,
|
||||
reactsHeartEdgeType,
|
||||
reactsHoorayEdgeType,
|
||||
]);
|
||||
|
||||
export const declaration: PluginDeclaration = Object.freeze({
|
||||
name: "GitHub",
|
||||
nodePrefix: N.Prefix.base,
|
||||
edgePrefix: E.Prefix.base,
|
||||
nodeTypes: nodeTypes,
|
||||
edgeTypes: edgeTypes,
|
||||
});
|
@ -8,131 +8,16 @@ import type {
|
||||
import {type Graph, NodeAddress} from "../../core/graph";
|
||||
import {createGraph} from "./createGraph";
|
||||
import * as N from "./nodes";
|
||||
import * as E from "./edges";
|
||||
import {RelationalView} from "./relationalView";
|
||||
import {description} from "./render";
|
||||
import type {Assets} from "../../app/assets";
|
||||
import type {RepoId} from "../../core/repoId";
|
||||
import type {PluginDeclaration} from "../../analysis/pluginDeclaration";
|
||||
import {declaration} from "./declaration";
|
||||
|
||||
export class StaticPluginAdapter implements IStaticPluginAdapter {
|
||||
name() {
|
||||
return "GitHub";
|
||||
}
|
||||
nodePrefix() {
|
||||
return N.Prefix.base;
|
||||
}
|
||||
edgePrefix() {
|
||||
return E.Prefix.base;
|
||||
}
|
||||
nodeTypes() {
|
||||
return [
|
||||
{
|
||||
name: "Repository",
|
||||
pluralName: "Repositories",
|
||||
prefix: N.Prefix.repo,
|
||||
defaultWeight: 4,
|
||||
},
|
||||
{
|
||||
name: "Issue",
|
||||
pluralName: "Issues",
|
||||
prefix: N.Prefix.issue,
|
||||
defaultWeight: 2,
|
||||
},
|
||||
{
|
||||
name: "Pull request",
|
||||
pluralName: "Pull requests",
|
||||
prefix: N.Prefix.pull,
|
||||
defaultWeight: 4,
|
||||
},
|
||||
{
|
||||
name: "Pull request review",
|
||||
pluralName: "Pull request reviews",
|
||||
prefix: N.Prefix.review,
|
||||
defaultWeight: 1,
|
||||
},
|
||||
{
|
||||
name: "Comment",
|
||||
pluralName: "Comments",
|
||||
prefix: N.Prefix.comment,
|
||||
defaultWeight: 1,
|
||||
},
|
||||
{
|
||||
name: "User",
|
||||
pluralName: "Users",
|
||||
prefix: N.Prefix.user,
|
||||
defaultWeight: 1,
|
||||
},
|
||||
{
|
||||
name: "Bot",
|
||||
pluralName: "Bots",
|
||||
prefix: N.Prefix.bot,
|
||||
defaultWeight: 0.25,
|
||||
},
|
||||
];
|
||||
}
|
||||
edgeTypes() {
|
||||
return [
|
||||
{
|
||||
forwardName: "authors",
|
||||
backwardName: "is authored by",
|
||||
defaultForwardWeight: 1 / 2,
|
||||
defaultBackwardWeight: 1,
|
||||
prefix: E.Prefix.authors,
|
||||
},
|
||||
{
|
||||
forwardName: "has parent",
|
||||
backwardName: "has child",
|
||||
defaultForwardWeight: 1,
|
||||
defaultBackwardWeight: 1 / 4,
|
||||
prefix: E.Prefix.hasParent,
|
||||
},
|
||||
{
|
||||
forwardName: "merges",
|
||||
backwardName: "is merged by",
|
||||
defaultForwardWeight: 1 / 2,
|
||||
defaultBackwardWeight: 1,
|
||||
prefix: E.Prefix.mergedAs,
|
||||
},
|
||||
{
|
||||
forwardName: "references",
|
||||
backwardName: "is referenced by",
|
||||
defaultForwardWeight: 1,
|
||||
defaultBackwardWeight: 1 / 16,
|
||||
prefix: E.Prefix.references,
|
||||
},
|
||||
{
|
||||
forwardName: "mentions author of",
|
||||
backwardName: "has author mentioned by",
|
||||
defaultForwardWeight: 1,
|
||||
// TODO(#811): Probably change this to 0
|
||||
defaultBackwardWeight: 1 / 32,
|
||||
prefix: E.Prefix.mentionsAuthor,
|
||||
},
|
||||
{
|
||||
forwardName: "reacted ❤️ to",
|
||||
backwardName: "got ❤️ from",
|
||||
defaultForwardWeight: 2,
|
||||
// TODO(#811): Probably change this to 0
|
||||
defaultBackwardWeight: 1 / 32,
|
||||
prefix: E.Prefix.reactsHeart,
|
||||
},
|
||||
{
|
||||
forwardName: "reacted 👍 to",
|
||||
backwardName: "got 👍 from",
|
||||
defaultForwardWeight: 1,
|
||||
// TODO(#811): Probably change this to 0
|
||||
defaultBackwardWeight: 1 / 32,
|
||||
prefix: E.Prefix.reactsThumbsUp,
|
||||
},
|
||||
{
|
||||
forwardName: "reacted 🎉 to",
|
||||
backwardName: "got 🎉 from",
|
||||
defaultForwardWeight: 4,
|
||||
// TODO(#811): Probably change this to 0
|
||||
defaultBackwardWeight: 1 / 32,
|
||||
prefix: E.Prefix.reactsHooray,
|
||||
},
|
||||
];
|
||||
declaration(): PluginDeclaration {
|
||||
return declaration;
|
||||
}
|
||||
async load(assets: Assets, repoId: RepoId): Promise<IDynamicPluginAdapater> {
|
||||
const url = assets.resolve(
|
||||
|
Loading…
x
Reference in New Issue
Block a user