Add the demo plugin (#965)

* Add the demo plugin

This ports the ad-hoc demo adapter defined in
`src/app/adapters/demoAdapters.js` into its own demo plugin.

This has the benefit that the demo plugin can now be depended on outside
the app module, e.g. for the analysis module as well. Correspondingly,
I've added a demo analysis adapter.

Test plan: `yarn test`. Note that no unit tests were added, as the demo
plugin is trivial.

* Delete `src/app/adapters/demoAdapters.js`

Now that we have an explicit demo plugin at `src/plugins/demo/`, we can
remove the legacy declaration of that plugin within the `app` module.

This commit deletes the old version, and re-writes all references to
point to the standalone plugin.

Test plan: `yarn test`
This commit is contained in:
Dandelion Mané 2018-10-31 13:23:46 -07:00 committed by GitHub
parent 6b789d61d6
commit 86a5b532f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 194 additions and 148 deletions

View File

@ -1,7 +1,7 @@
// @flow
import {NodeAddress, EdgeAddress, Graph} from "../../core/graph";
import {FactorioStaticAdapter} from "./demoAdapters";
import {FactorioStaticAdapter} from "../../plugins/demo/appAdapter";
import {StaticAdapterSet} from "./adapterSet";
import {
FallbackStaticAdapter,
@ -103,8 +103,7 @@ describe("app/adapters/adapterSet", () => {
});
it("loads a dynamicAdapterSet", async () => {
const {x, sas} = example();
x.loadingMock = jest.fn();
x.loadingMock.mockResolvedValue();
x.loadingMock = jest.fn().mockResolvedValue();
expect(x.loadingMock).toHaveBeenCalledTimes(0);
const assets = new Assets("/my/gateway/");
const repoId = makeRepoId("foo", "bar");

View File

@ -1,126 +0,0 @@
// @flow
import {Assets} from "../assets";
import {
Graph,
NodeAddress,
type NodeAddressT,
EdgeAddress,
} from "../../core/graph";
import type {StaticAppAdapter, DynamicAppAdapter} from "./appAdapter";
import type {EdgeType, NodeType} from "../../analysis/types";
import type {PluginDeclaration} from "../../analysis/pluginDeclaration";
import {StaticAdapterSet} from "./adapterSet";
import {makeRepoId, type RepoId} from "../../core/repoId";
export const inserterNodeType: NodeType = Object.freeze({
name: "inserter",
pluralName: "inserters",
prefix: NodeAddress.fromParts(["factorio", "inserter"]),
defaultWeight: 1,
});
export const machineNodeType: NodeType = Object.freeze({
name: "machine",
pluralName: "machines",
prefix: NodeAddress.fromParts(["factorio", "machine"]),
defaultWeight: 2,
});
export const assemblesEdgeType: EdgeType = Object.freeze({
forwardName: "assembles",
defaultForwardWeight: 2,
backwardName: "is assembled by",
defaultBackwardWeight: 2 ** -2,
prefix: EdgeAddress.fromParts(["factorio", "assembles"]),
});
export const transportsEdgeType: EdgeType = Object.freeze({
forwardName: "transports",
defaultForwardWeight: 1,
backwardName: "is transported by",
defaultBackwardWeight: 2 ** -1,
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 StaticAppAdapter {
loadingMock: Function;
declaration() {
return declaration;
}
async load(assets: Assets, repoId: RepoId): Promise<DynamicAppAdapter> {
if (this.loadingMock) {
return this.loadingMock(assets, repoId).then(
() => new FactorioDynamicAdapter()
);
}
return Promise.resolve(new FactorioDynamicAdapter());
}
}
export const factorioNodes = Object.freeze({
inserter1: NodeAddress.fromParts(["factorio", "inserter", "1"]),
machine1: NodeAddress.fromParts(["factorio", "machine", "1"]),
inserter2: NodeAddress.fromParts(["factorio", "inserter", "2"]),
machine2: NodeAddress.fromParts(["factorio", "machine", "2"]),
});
export const factorioEdges = Object.freeze({
transports1: Object.freeze({
src: factorioNodes.inserter1,
dst: factorioNodes.machine1,
address: EdgeAddress.fromParts(["factorio", "transports", "1"]),
}),
assembles1: Object.freeze({
src: factorioNodes.machine1,
dst: factorioNodes.inserter2,
address: EdgeAddress.fromParts(["factorio", "assembles", "1"]),
}),
transports2: Object.freeze({
src: factorioNodes.inserter2,
dst: factorioNodes.machine2,
address: EdgeAddress.fromParts(["factorio", "assembles", "2"]),
}),
});
export function factorioGraph() {
return new Graph()
.addNode(factorioNodes.inserter1)
.addNode(factorioNodes.inserter2)
.addNode(factorioNodes.machine1)
.addNode(factorioNodes.machine2)
.addEdge(factorioEdges.transports1)
.addEdge(factorioEdges.transports2)
.addEdge(factorioEdges.assembles1);
}
export class FactorioDynamicAdapter implements DynamicAppAdapter {
graph() {
return factorioGraph();
}
nodeDescription(x: NodeAddressT) {
return NodeAddress.toString(x);
}
static() {
return new FactorioStaticAdapter();
}
}
export function staticAdapterSet() {
return new StaticAdapterSet([new FactorioStaticAdapter()]);
}
export async function dynamicAdapterSet() {
return await staticAdapterSet().load(
new Assets("/gateway/"),
makeRepoId("foo", "bar")
);
}

View File

@ -8,7 +8,7 @@ import {makeRepoId} from "../../core/repoId";
import {Assets} from "../assets";
import testLocalStore from "../testLocalStore";
import {DynamicAdapterSet, StaticAdapterSet} from "../adapters/adapterSet";
import {FactorioStaticAdapter} from "../adapters/demoAdapters";
import {FactorioStaticAdapter} from "../../plugins/demo/appAdapter";
import {defaultWeightsForAdapter} from "./weights/weights";
import RepositorySelect from "./RepositorySelect";

View File

@ -16,7 +16,7 @@ import {Badge} from "./shared";
import {example} from "./sharedTestUtils";
import {aggregateFlat, type FlatAggregation} from "./aggregate";
import {TableRow} from "./TableRow";
import {factorioNodes} from "../../adapters/demoAdapters";
import {nodes as factorioNodes} from "../../../plugins/demo/graph";
require("../../testUtil").configureEnzyme();

View File

@ -9,7 +9,7 @@ import {ConnectionRowList, ConnectionRow, ConnectionView} from "./Connection";
import {example} from "./sharedTestUtils";
import {TableRow} from "./TableRow";
import {NodeRow} from "./Node";
import {factorioNodes} from "../../adapters/demoAdapters";
import {nodes as factorioNodes} from "../../../plugins/demo/graph";
require("../../testUtil").configureEnzyme();
@ -196,7 +196,7 @@ describe("app/credExplorer/pagerankTable/Connection", () => {
const description = outerSpan.children().find("span");
expect(badge.children().text()).toEqual("is transported by");
expect(description.text()).toEqual(
'NodeAddress["factorio","inserter","1"]'
'[factorio]: NodeAddress["factorio","inserter","1"]'
);
});
it("for outward connections, renders a `Badge` and description", async () => {
@ -207,7 +207,7 @@ describe("app/credExplorer/pagerankTable/Connection", () => {
const description = outerSpan.children().find("span");
expect(badge.children().text()).toEqual("assembles");
expect(description.text()).toEqual(
'NodeAddress["factorio","inserter","2"]'
'[factorio]: NodeAddress["factorio","inserter","2"]'
);
});
it("for synthetic connections, renders only a `Badge`", async () => {

View File

@ -12,7 +12,7 @@ import type {NodeAddressT} from "../../../core/graph";
import {nodeDescription} from "./shared";
import {example} from "./sharedTestUtils";
import {NodeRowList, NodeRow, type NodeRowProps} from "./Node";
import {factorioNodes} from "../../adapters/demoAdapters";
import {nodes as factorioNodes} from "../../../plugins/demo/graph";
require("../../testUtil").configureEnzyme();

View File

@ -10,7 +10,7 @@ import {example, COLUMNS} from "./sharedTestUtils";
import {NodeRowList} from "./Node";
import {WeightConfig} from "../weights/WeightConfig";
import {defaultWeightsForAdapter} from "../weights/weights";
import {FactorioStaticAdapter} from "../../adapters/demoAdapters";
import {FactorioStaticAdapter} from "../../../plugins/demo/appAdapter";
require("../../testUtil").configureEnzyme();
describe("app/credExplorer/pagerankTable/Table", () => {

View File

@ -1,8 +1,8 @@
// @flow
import {dynamicAdapterSet} from "../../adapters/demoAdapters";
import {pagerank} from "../../../analysis/pagerank";
import {defaultWeightsForAdapterSet} from "../weights/weights";
import {dynamicAdapterSet} from "../../../plugins/demo/appAdapter";
export const COLUMNS = () => ["Description", "", "Cred"];

View File

@ -20,7 +20,7 @@ import type {
PagerankNodeDecomposition,
PagerankOptions,
} from "../../analysis/pagerank";
import {staticAdapterSet} from "../adapters/demoAdapters";
import {staticAdapterSet} from "../../plugins/demo/appAdapter";
describe("app/credExplorer/state", () => {
function example(startingState: AppState) {

View File

@ -5,7 +5,7 @@ import {shallow} from "enzyme";
import {WeightSlider} from "./WeightSlider";
import {EdgeTypeConfig, EdgeWeightSlider} from "./EdgeTypeConfig";
import {assemblesEdgeType} from "../../adapters/demoAdapters";
import {assemblesEdgeType} from "../../../plugins/demo/declaration";
require("../../testUtil").configureEnzyme();

View File

@ -5,7 +5,7 @@ import {shallow} from "enzyme";
import {WeightSlider} from "./WeightSlider";
import {NodeTypeConfig} from "./NodeTypeConfig";
import {inserterNodeType} from "../../adapters/demoAdapters";
import {inserterNodeType} from "../../../plugins/demo/declaration";
require("../../testUtil").configureEnzyme();

View File

@ -4,10 +4,10 @@ import React from "react";
import {shallow} from "enzyme";
import {PluginWeightConfig} from "./PluginWeightConfig";
import {
FactorioStaticAdapter,
inserterNodeType,
assemblesEdgeType,
} from "../../adapters/demoAdapters";
} from "../../../plugins/demo/declaration";
import {FactorioStaticAdapter} from "../../../plugins/demo/appAdapter";
import {
fallbackNodeType,
fallbackEdgeType,

View File

@ -4,10 +4,10 @@ import React from "react";
import {shallow} from "enzyme";
import {PluginWeightConfig} from "./PluginWeightConfig";
import {
staticAdapterSet,
inserterNodeType,
FactorioStaticAdapter,
} from "../../adapters/demoAdapters";
staticAdapterSet,
} from "../../../plugins/demo/appAdapter";
import {inserterNodeType} from "../../../plugins/demo/declaration";
import {FALLBACK_NAME} from "../../adapters/fallbackAdapter";
import {defaultWeightsForAdapterSet, defaultWeightsForAdapter} from "./weights";
import {WeightConfig} from "./WeightConfig";

View File

@ -12,9 +12,11 @@ import {
machineNodeType,
assemblesEdgeType,
transportsEdgeType,
} from "../../../plugins/demo/declaration";
import {
FactorioStaticAdapter,
staticAdapterSet,
} from "../../adapters/demoAdapters";
} from "../../../plugins/demo/appAdapter";
describe("app/credExplorer/weights/weights", () => {
describe("defaultWeightedNodeType", () => {

View File

@ -9,8 +9,8 @@ import {
inserterNodeType,
machineNodeType,
assemblesEdgeType,
factorioEdges,
} from "../../adapters/demoAdapters";
} from "../../../plugins/demo/declaration";
import {edges as factorioEdges} from "../../../plugins/demo/graph";
import {weightsToEdgeEvaluator} from "./weightsToEdgeEvaluator";
describe("app/credExplorer/weights/weightsToEdgeEvaluator", () => {

View File

@ -0,0 +1,14 @@
# The Demo Plugin
This plugin exists for testing convenience. It's nice sometimes to have a super
lightweight plugin, with a few basic node types, basic (and mockable) adapters,
and a simple graph.
Note: This plugin is **not** intended to be a model for what a canonical plugin
would look like. It only exists to test code that depends on having some plugin
available.
The plugin is loosely based on the wonderful video game [Factorio], which the
SourceCred developers heartily recommend.
[Factorio]: https://www.factorio.com/

View File

@ -0,0 +1,23 @@
// @flow
import {Graph} from "../../core/graph";
import type {RepoId} from "../../core/repoId";
import type {PluginDeclaration} from "../../analysis/pluginDeclaration";
import type {IAnalysisAdapter} from "../../analysis/analysisAdapter";
import {declaration} from "./declaration";
import {graph} from "./graph";
export class AnalysisAdapter implements IAnalysisAdapter {
loadingMock: (sourcecredDirectory: string, repoId: RepoId) => Promise<mixed>;
declaration(): PluginDeclaration {
return declaration;
}
load(sourcecredDirectory: string, repoId: RepoId): Promise<Graph> {
if (this.loadingMock) {
return this.loadingMock(sourcecredDirectory, repoId).then(() => graph());
}
return Promise.resolve(graph());
}
}

View File

@ -0,0 +1,50 @@
// @flow
import type {PluginDeclaration} from "../../analysis/pluginDeclaration";
import {declaration} from "./declaration";
import type {
StaticAppAdapter,
DynamicAppAdapter,
} from "../../app/adapters/appAdapter";
import {StaticAdapterSet} from "../../app/adapters/adapterSet";
import {Assets} from "../../app/assets";
import {type RepoId, makeRepoId} from "../../core/repoId";
import {NodeAddress, type NodeAddressT} from "../../core/graph";
import {graph} from "./graph";
export class FactorioStaticAdapter implements StaticAppAdapter {
loadingMock: (assets: Assets, repoId: RepoId) => Promise<mixed>;
declaration(): PluginDeclaration {
return declaration;
}
async load(assets: Assets, repoId: RepoId): Promise<FactorioDynamicAdapter> {
const result: FactorioDynamicAdapter = new FactorioDynamicAdapter();
if (this.loadingMock) {
return this.loadingMock(assets, repoId).then(() => result);
}
return Promise.resolve(result);
}
}
export class FactorioDynamicAdapter implements DynamicAppAdapter {
graph() {
return graph();
}
nodeDescription(x: NodeAddressT) {
return `[factorio]: ${NodeAddress.toString(x)}`;
}
static() {
return new FactorioStaticAdapter();
}
}
export function staticAdapterSet() {
return new StaticAdapterSet([new FactorioStaticAdapter()]);
}
export async function dynamicAdapterSet() {
return await staticAdapterSet().load(
new Assets("/gateway/"),
makeRepoId("foo", "bar")
);
}

View File

@ -0,0 +1,45 @@
// @flow
import {NodeAddress, EdgeAddress} from "../../core/graph";
import type {PluginDeclaration} from "../../analysis/pluginDeclaration";
import type {EdgeType, NodeType} from "../../analysis/types";
export const inserterNodeType: NodeType = Object.freeze({
name: "inserter",
pluralName: "inserters",
prefix: NodeAddress.fromParts(["factorio", "inserter"]),
defaultWeight: 1,
});
export const machineNodeType: NodeType = Object.freeze({
name: "machine",
pluralName: "machines",
prefix: NodeAddress.fromParts(["factorio", "machine"]),
defaultWeight: 2,
});
export const assemblesEdgeType: EdgeType = Object.freeze({
forwardName: "assembles",
defaultForwardWeight: 2,
backwardName: "is assembled by",
defaultBackwardWeight: 2 ** -2,
prefix: EdgeAddress.fromParts(["factorio", "assembles"]),
});
export const transportsEdgeType: EdgeType = Object.freeze({
forwardName: "transports",
defaultForwardWeight: 1,
backwardName: "is transported by",
defaultBackwardWeight: 2 ** -1,
prefix: EdgeAddress.fromParts(["factorio", "transports"]),
});
export const declaration: PluginDeclaration = Object.freeze({
name: "Factorio demo adapter",
nodePrefix: NodeAddress.fromParts(["factorio"]),
nodeTypes: Object.freeze([inserterNodeType, machineNodeType]),
edgePrefix: EdgeAddress.fromParts(["factorio"]),
edgeTypes: Object.freeze([assemblesEdgeType, transportsEdgeType]),
});

39
src/plugins/demo/graph.js Normal file
View File

@ -0,0 +1,39 @@
// @flow
import {Graph, NodeAddress, EdgeAddress} from "../../core/graph";
export const nodes = Object.freeze({
inserter1: NodeAddress.fromParts(["factorio", "inserter", "1"]),
machine1: NodeAddress.fromParts(["factorio", "machine", "1"]),
inserter2: NodeAddress.fromParts(["factorio", "inserter", "2"]),
machine2: NodeAddress.fromParts(["factorio", "machine", "2"]),
});
export const edges = Object.freeze({
transports1: Object.freeze({
src: nodes.inserter1,
dst: nodes.machine1,
address: EdgeAddress.fromParts(["factorio", "transports", "1"]),
}),
assembles1: Object.freeze({
src: nodes.machine1,
dst: nodes.inserter2,
address: EdgeAddress.fromParts(["factorio", "assembles", "1"]),
}),
transports2: Object.freeze({
src: nodes.inserter2,
dst: nodes.machine2,
address: EdgeAddress.fromParts(["factorio", "assembles", "2"]),
}),
});
export function graph() {
return new Graph()
.addNode(nodes.inserter1)
.addNode(nodes.inserter2)
.addNode(nodes.machine1)
.addNode(nodes.machine2)
.addEdge(edges.transports1)
.addEdge(edges.transports2)
.addEdge(edges.assembles1);
}