Use AdapterSets in the cred explorer (#642)
This takes the code from #640 and puts it into production. Test plan: Unit tests pass. The observable behavior in the cred explorer is unchanged; i.e. the addition of the FallbackAdapter did not produce new entries in the WeightConfig or in the Pagerank table options. The WeightConfig is untested, so we don't have verification of that behavior (other than that I tested it and am reporting it here). The PagerankTable code is tested, and a snapshot would fail if another option group had appeared.
This commit is contained in:
parent
9edd7ac069
commit
05c9f81cc0
|
@ -1,9 +1,9 @@
|
|||
// @flow
|
||||
|
||||
import type {StaticPluginAdapter} from "./pluginAdapter";
|
||||
import {StaticAdapterSet} from "./adapterSet";
|
||||
import {StaticPluginAdapter as GitAdapter} from "../../plugins/git/pluginAdapter";
|
||||
import {StaticPluginAdapter as GithubAdapter} from "../../plugins/github/pluginAdapter";
|
||||
|
||||
export function defaultStaticAdapters(): $ReadOnlyArray<StaticPluginAdapter> {
|
||||
return [new GitAdapter(), new GithubAdapter()];
|
||||
export function defaultStaticAdapters(): StaticAdapterSet {
|
||||
return new StaticAdapterSet([new GitAdapter(), new GithubAdapter()]);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import {
|
||||
Graph,
|
||||
NodeAddress,
|
||||
EdgeAddress,
|
||||
type NodeAddressT,
|
||||
type EdgeAddressT,
|
||||
} from "../../core/graph";
|
||||
import {Graph, type NodeAddressT, type EdgeAddressT} from "../../core/graph";
|
||||
import type {Repo} from "../../core/repo";
|
||||
|
||||
export type EdgeType = {|
|
||||
|
@ -35,77 +29,3 @@ export interface DynamicPluginAdapter {
|
|||
nodeDescription(NodeAddressT): string;
|
||||
static (): StaticPluginAdapter;
|
||||
}
|
||||
|
||||
function findUniqueMatch<T>(
|
||||
xs: $ReadOnlyArray<T>,
|
||||
predicate: (T) => boolean
|
||||
): T {
|
||||
const results = xs.filter(predicate);
|
||||
if (results.length > 1) {
|
||||
throw new Error("Multiple entities match predicate");
|
||||
}
|
||||
if (results.length === 0) {
|
||||
throw new Error("No entity matches predicate");
|
||||
}
|
||||
return results[0];
|
||||
}
|
||||
|
||||
export function staticDispatchByNode(
|
||||
adapters: $ReadOnlyArray<StaticPluginAdapter>,
|
||||
x: NodeAddressT
|
||||
): StaticPluginAdapter {
|
||||
return findUniqueMatch(adapters, (a) =>
|
||||
NodeAddress.hasPrefix(x, a.nodePrefix())
|
||||
);
|
||||
}
|
||||
|
||||
export function staticDispatchByEdge(
|
||||
adapters: $ReadOnlyArray<StaticPluginAdapter>,
|
||||
x: EdgeAddressT
|
||||
): StaticPluginAdapter {
|
||||
return findUniqueMatch(adapters, (a) =>
|
||||
EdgeAddress.hasPrefix(x, a.edgePrefix())
|
||||
);
|
||||
}
|
||||
|
||||
export function dynamicDispatchByNode(
|
||||
adapters: $ReadOnlyArray<DynamicPluginAdapter>,
|
||||
x: NodeAddressT
|
||||
): DynamicPluginAdapter {
|
||||
return findUniqueMatch(adapters, (a) =>
|
||||
NodeAddress.hasPrefix(x, a.static().nodePrefix())
|
||||
);
|
||||
}
|
||||
|
||||
export function dynamicDispatchByEdge(
|
||||
adapters: $ReadOnlyArray<DynamicPluginAdapter>,
|
||||
x: EdgeAddressT
|
||||
): DynamicPluginAdapter {
|
||||
return findUniqueMatch(adapters, (a) =>
|
||||
EdgeAddress.hasPrefix(x, a.static().edgePrefix())
|
||||
);
|
||||
}
|
||||
|
||||
export function findNodeType(
|
||||
adapter: StaticPluginAdapter,
|
||||
x: NodeAddressT
|
||||
): NodeType {
|
||||
if (!NodeAddress.hasPrefix(x, adapter.nodePrefix())) {
|
||||
throw new Error("Trying to find NodeType from the wrong plugin adapter");
|
||||
}
|
||||
return findUniqueMatch(adapter.nodeTypes(), (t) =>
|
||||
NodeAddress.hasPrefix(x, t.prefix)
|
||||
);
|
||||
}
|
||||
|
||||
export function findEdgeType(
|
||||
adapter: StaticPluginAdapter,
|
||||
x: EdgeAddressT
|
||||
): EdgeType {
|
||||
if (!EdgeAddress.hasPrefix(x, adapter.edgePrefix())) {
|
||||
throw new Error("Trying to find EdgeType from the wrong plugin adapter");
|
||||
}
|
||||
return findUniqueMatch(adapter.edgeTypes(), (t) =>
|
||||
EdgeAddress.hasPrefix(x, t.prefix)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,205 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import {
|
||||
Graph,
|
||||
NodeAddress,
|
||||
EdgeAddress,
|
||||
type NodeAddressT,
|
||||
} from "../../core/graph";
|
||||
import {
|
||||
type StaticPluginAdapter,
|
||||
type DynamicPluginAdapter,
|
||||
staticDispatchByNode,
|
||||
staticDispatchByEdge,
|
||||
dynamicDispatchByNode,
|
||||
dynamicDispatchByEdge,
|
||||
findNodeType,
|
||||
findEdgeType,
|
||||
} from "./pluginAdapter";
|
||||
|
||||
describe("app/adapters/pluginAdapter", () => {
|
||||
function example() {
|
||||
const staticFooAdapter: StaticPluginAdapter = {
|
||||
name: () => "foo",
|
||||
nodePrefix: () => NodeAddress.fromParts(["foo"]),
|
||||
edgePrefix: () => EdgeAddress.fromParts(["foo"]),
|
||||
nodeTypes: () => [
|
||||
{
|
||||
name: "zap",
|
||||
prefix: NodeAddress.fromParts(["foo", "zap"]),
|
||||
defaultWeight: 0,
|
||||
},
|
||||
{
|
||||
name: "kif",
|
||||
prefix: NodeAddress.fromParts(["foo", "kif"]),
|
||||
defaultWeight: 0,
|
||||
},
|
||||
{
|
||||
name: "bad-duplicate-1",
|
||||
prefix: NodeAddress.fromParts(["foo", "bad"]),
|
||||
defaultWeight: 0,
|
||||
},
|
||||
{
|
||||
name: "bad-duplicate-2",
|
||||
prefix: NodeAddress.fromParts(["foo", "bad"]),
|
||||
defaultWeight: 0,
|
||||
},
|
||||
],
|
||||
edgeTypes: () => [
|
||||
{
|
||||
forwardName: "kifs",
|
||||
backwardName: "kiffed by",
|
||||
prefix: EdgeAddress.fromParts(["foo", "kif"]),
|
||||
},
|
||||
{
|
||||
forwardName: "zaps",
|
||||
backwardName: "zapped by",
|
||||
prefix: EdgeAddress.fromParts(["foo", "zap"]),
|
||||
},
|
||||
{
|
||||
forwardName: "bad1",
|
||||
backwardName: "bad1'd by",
|
||||
prefix: EdgeAddress.fromParts(["foo", "bad"]),
|
||||
},
|
||||
{
|
||||
forwardName: "bad2",
|
||||
backwardName: "bad2'd by",
|
||||
prefix: EdgeAddress.fromParts(["foo", "bad"]),
|
||||
},
|
||||
],
|
||||
load: (_unused_repo) => Promise.resolve(dynamicFooAdapter),
|
||||
};
|
||||
const dynamicFooAdapter: DynamicPluginAdapter = {
|
||||
graph: () => new Graph(),
|
||||
nodeDescription: (x: NodeAddressT) => NodeAddress.toString(x),
|
||||
static: () => staticFooAdapter,
|
||||
};
|
||||
const staticBarAdapter: StaticPluginAdapter = {
|
||||
name: () => "bar",
|
||||
nodePrefix: () => NodeAddress.fromParts(["bar"]),
|
||||
edgePrefix: () => EdgeAddress.fromParts(["bar"]),
|
||||
nodeTypes: () => [],
|
||||
edgeTypes: () => [],
|
||||
load: (_unused_repo) => Promise.resolve(dynamicBarAdapter),
|
||||
};
|
||||
const dynamicBarAdapter: DynamicPluginAdapter = {
|
||||
graph: () => new Graph(),
|
||||
nodeDescription: (x) => NodeAddress.toString(x),
|
||||
static: () => staticBarAdapter,
|
||||
};
|
||||
const statics = [staticFooAdapter, staticBarAdapter];
|
||||
const dynamics = [dynamicFooAdapter, dynamicBarAdapter];
|
||||
return {
|
||||
statics,
|
||||
dynamics,
|
||||
staticFooAdapter,
|
||||
dynamicFooAdapter,
|
||||
};
|
||||
}
|
||||
|
||||
describe("dispatching", () => {
|
||||
describe("error handling", () => {
|
||||
// Just testing staticDispatchByNode is fine, as they all call the same
|
||||
// implementation
|
||||
it("errors if it cannot match", () => {
|
||||
const {statics} = example();
|
||||
const zod = NodeAddress.fromParts(["zod"]);
|
||||
expect(() => staticDispatchByNode(statics, zod)).toThrowError(
|
||||
"No entity matches"
|
||||
);
|
||||
});
|
||||
it("errors if there are multiple matches", () => {
|
||||
const {staticFooAdapter} = example();
|
||||
const statics = [staticFooAdapter, staticFooAdapter];
|
||||
const foo = NodeAddress.fromParts(["foo"]);
|
||||
expect(() => staticDispatchByNode(statics, foo)).toThrowError(
|
||||
"Multiple entities match"
|
||||
);
|
||||
});
|
||||
});
|
||||
it("staticDispatchByNode works", () => {
|
||||
const {statics, staticFooAdapter} = example();
|
||||
const fooSubnode = NodeAddress.fromParts(["foo", "sub"]);
|
||||
expect(staticDispatchByNode(statics, fooSubnode)).toBe(staticFooAdapter);
|
||||
});
|
||||
it("staticDispatchByEdge works", () => {
|
||||
const {statics, staticFooAdapter} = example();
|
||||
const fooSubedge = EdgeAddress.fromParts(["foo", "sub"]);
|
||||
expect(staticDispatchByEdge(statics, fooSubedge)).toBe(staticFooAdapter);
|
||||
});
|
||||
it("dynamicDispatchByNode works", () => {
|
||||
const {dynamics, dynamicFooAdapter} = example();
|
||||
const fooSubnode = NodeAddress.fromParts(["foo", "sub"]);
|
||||
expect(dynamicDispatchByNode(dynamics, fooSubnode)).toBe(
|
||||
dynamicFooAdapter
|
||||
);
|
||||
});
|
||||
it("dynamicDispatchByEdge works", () => {
|
||||
const {dynamics, dynamicFooAdapter} = example();
|
||||
const fooSubedge = EdgeAddress.fromParts(["foo", "sub"]);
|
||||
expect(dynamicDispatchByEdge(dynamics, fooSubedge)).toBe(
|
||||
dynamicFooAdapter
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("findNodeType", () => {
|
||||
it("works in a simple case", () => {
|
||||
const {staticFooAdapter} = example();
|
||||
const kifNode = NodeAddress.fromParts(["foo", "kif", "node"]);
|
||||
expect(findNodeType(staticFooAdapter, kifNode).name).toEqual("kif");
|
||||
});
|
||||
it("errors if node doesn't match the plugin", () => {
|
||||
const {staticFooAdapter} = example();
|
||||
const wrongNode = NodeAddress.fromParts(["bar", "kif", "node"]);
|
||||
expect(() => findNodeType(staticFooAdapter, wrongNode)).toThrowError(
|
||||
"wrong plugin adapter"
|
||||
);
|
||||
});
|
||||
it("errors if there's no matching type", () => {
|
||||
const {staticFooAdapter} = example();
|
||||
const wrongNode = NodeAddress.fromParts(["foo", "leela", "node"]);
|
||||
expect(() => findNodeType(staticFooAdapter, wrongNode)).toThrowError(
|
||||
"No entity matches"
|
||||
);
|
||||
});
|
||||
it("errors if there's multiple matching types", () => {
|
||||
const {staticFooAdapter} = example();
|
||||
const wrongNode = NodeAddress.fromParts(["foo", "bad", "brannigan"]);
|
||||
expect(() => findNodeType(staticFooAdapter, wrongNode)).toThrowError(
|
||||
"Multiple entities match"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("findEdgeType", () => {
|
||||
it("works in a simple case", () => {
|
||||
const {staticFooAdapter} = example();
|
||||
const kifEdge = EdgeAddress.fromParts(["foo", "kif", "edge"]);
|
||||
expect(findEdgeType(staticFooAdapter, kifEdge).forwardName).toEqual(
|
||||
"kifs"
|
||||
);
|
||||
});
|
||||
it("errors if edge doesn't match the plugin", () => {
|
||||
const {staticFooAdapter} = example();
|
||||
const wrongEdge = EdgeAddress.fromParts(["bar", "kif", "edge"]);
|
||||
expect(() => findEdgeType(staticFooAdapter, wrongEdge)).toThrowError(
|
||||
"wrong plugin adapter"
|
||||
);
|
||||
});
|
||||
it("errors if there's no matching type", () => {
|
||||
const {staticFooAdapter} = example();
|
||||
const wrongEdge = EdgeAddress.fromParts(["foo", "leela", "edge"]);
|
||||
expect(() => findEdgeType(staticFooAdapter, wrongEdge)).toThrowError(
|
||||
"No entity matches"
|
||||
);
|
||||
});
|
||||
it("errors if there's multiple matching types", () => {
|
||||
const {staticFooAdapter} = example();
|
||||
const wrongEdge = EdgeAddress.fromParts(["foo", "bad", "brannigan"]);
|
||||
expect(() => findEdgeType(staticFooAdapter, wrongEdge)).toThrowError(
|
||||
"Multiple entities match"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -6,6 +6,7 @@ import {shallow} from "enzyme";
|
|||
import {Graph} from "../../core/graph";
|
||||
import {makeRepo} from "../../core/repo";
|
||||
import testLocalStore from "../testLocalStore";
|
||||
import {DynamicAdapterSet, StaticAdapterSet} from "../adapters/adapterSet";
|
||||
|
||||
import RepositorySelect from "./RepositorySelect";
|
||||
import {PagerankTable} from "./pagerankTable/Table";
|
||||
|
@ -65,6 +66,7 @@ describe("app/credExplorer/App", () => {
|
|||
};
|
||||
}
|
||||
|
||||
const emptyAdapters = new DynamicAdapterSet(new StaticAdapterSet([]), []);
|
||||
const exampleStates = {
|
||||
uninitialized: initialState,
|
||||
readyToLoadGraph: (loadingState) => {
|
||||
|
@ -79,7 +81,7 @@ describe("app/credExplorer/App", () => {
|
|||
initialized({
|
||||
type: "READY_TO_RUN_PAGERANK",
|
||||
loading: loadingState,
|
||||
graphWithAdapters: {graph: new Graph(), adapters: []},
|
||||
graphWithAdapters: {graph: new Graph(), adapters: emptyAdapters},
|
||||
});
|
||||
},
|
||||
pagerankEvaluated: (loadingState) => {
|
||||
|
@ -87,7 +89,7 @@ describe("app/credExplorer/App", () => {
|
|||
initialized({
|
||||
type: "PAGERANK_EVALUATED",
|
||||
loading: loadingState,
|
||||
graphWithAdapters: {graph: new Graph(), adapters: []},
|
||||
graphWithAdapters: {graph: new Graph(), adapters: emptyAdapters},
|
||||
pagerankNodeDecomposition: new Map(),
|
||||
});
|
||||
},
|
||||
|
|
|
@ -27,10 +27,12 @@ type UserEdgeWeight = {|+logWeight: number, +directionality: number|};
|
|||
const EDGE_WEIGHTS_KEY = "edgeWeights";
|
||||
const defaultEdgeWeights = (): EdgeWeights => {
|
||||
const result = new Map();
|
||||
for (const adapter of defaultStaticAdapters()) {
|
||||
for (const {prefix} of adapter.edgeTypes()) {
|
||||
result.set(prefix, {logWeight: 0, directionality: 0.5});
|
||||
for (const {prefix} of defaultStaticAdapters().edgeTypes()) {
|
||||
if (prefix === EdgeAddress.empty) {
|
||||
// We haven't decided how to deal with the FallbackAdapter's fallback type.
|
||||
continue;
|
||||
}
|
||||
result.set(prefix, {logWeight: 0, directionality: 0.5});
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
@ -40,10 +42,12 @@ type UserNodeWeight = number /* in log space */;
|
|||
const NODE_WEIGHTS_KEY = "nodeWeights";
|
||||
const defaultNodeWeights = (): NodeWeights => {
|
||||
const result = new Map();
|
||||
for (const adapter of defaultStaticAdapters()) {
|
||||
for (const {prefix, defaultWeight} of adapter.nodeTypes()) {
|
||||
result.set(prefix, Math.log2(defaultWeight));
|
||||
for (const {prefix, defaultWeight} of defaultStaticAdapters().nodeTypes()) {
|
||||
if (prefix === NodeAddress.empty) {
|
||||
// We haven't decided how to deal with the FallbackAdapter's fallback type.
|
||||
continue;
|
||||
}
|
||||
result.set(prefix, Math.log2(defaultWeight));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@ import * as NullUtil from "../../../util/null";
|
|||
import type {NodeAddressT} from "../../../core/graph";
|
||||
import type {Connection} from "../../../core/attribution/graphToMarkovChain";
|
||||
import type {ScoredConnection} from "../../../core/attribution/pagerankNodeDecomposition";
|
||||
import type {DynamicPluginAdapter} from "../../adapters/pluginAdapter";
|
||||
import {DynamicAdapterSet} from "../../adapters/adapterSet";
|
||||
|
||||
import {
|
||||
edgeVerb,
|
||||
|
@ -115,7 +115,7 @@ export class ConnectionRow extends React.PureComponent<
|
|||
|
||||
export class ConnectionView extends React.PureComponent<{|
|
||||
+connection: Connection,
|
||||
+adapters: $ReadOnlyArray<DynamicPluginAdapter>,
|
||||
+adapters: DynamicAdapterSet,
|
||||
|}> {
|
||||
render() {
|
||||
const {connection, adapters} = this.props;
|
||||
|
|
|
@ -5,13 +5,15 @@ import sortBy from "lodash.sortby";
|
|||
|
||||
import {type NodeAddressT, NodeAddress} from "../../../core/graph";
|
||||
import type {PagerankNodeDecomposition} from "../../../core/attribution/pagerankNodeDecomposition";
|
||||
import {DynamicAdapterSet} from "../../adapters/adapterSet";
|
||||
import type {DynamicPluginAdapter} from "../../adapters/pluginAdapter";
|
||||
import {FALLBACK_NAME} from "../../adapters/fallbackAdapter";
|
||||
|
||||
import {NodeRowList} from "./Node";
|
||||
|
||||
type PagerankTableProps = {|
|
||||
+pnd: PagerankNodeDecomposition,
|
||||
+adapters: $ReadOnlyArray<DynamicPluginAdapter>,
|
||||
+adapters: DynamicAdapterSet,
|
||||
+maxEntriesPerList: number,
|
||||
|};
|
||||
type PagerankTableState = {|topLevelFilter: NodeAddressT|};
|
||||
|
@ -69,9 +71,11 @@ export class PagerankTable extends React.PureComponent<
|
|||
}}
|
||||
>
|
||||
<option value={NodeAddress.empty}>Show all</option>
|
||||
{sortBy(adapters, (a: DynamicPluginAdapter) => a.static().name()).map(
|
||||
optionGroup
|
||||
)}
|
||||
{sortBy(adapters.adapters(), (a: DynamicPluginAdapter) =>
|
||||
a.static().name()
|
||||
)
|
||||
.filter((a) => a.static().name() !== FALLBACK_NAME)
|
||||
.map(optionGroup)}
|
||||
</select>
|
||||
</label>
|
||||
);
|
||||
|
|
|
@ -6,20 +6,15 @@ import {
|
|||
NodeAddress,
|
||||
} from "../../../core/graph";
|
||||
|
||||
import type {PagerankNodeDecomposition} from "../../../core/attribution/pagerankNodeDecomposition";
|
||||
import {DynamicAdapterSet} from "../../adapters/adapterSet";
|
||||
|
||||
import {
|
||||
type DynamicPluginAdapter,
|
||||
dynamicDispatchByNode,
|
||||
dynamicDispatchByEdge,
|
||||
findEdgeType,
|
||||
} from "../../adapters/pluginAdapter";
|
||||
import type {PagerankNodeDecomposition} from "../../../core/attribution/pagerankNodeDecomposition";
|
||||
|
||||
export function nodeDescription(
|
||||
address: NodeAddressT,
|
||||
adapters: $ReadOnlyArray<DynamicPluginAdapter>
|
||||
adapters: DynamicAdapterSet
|
||||
): string {
|
||||
const adapter = dynamicDispatchByNode(adapters, address);
|
||||
const adapter = adapters.adapterMatchingNode(address);
|
||||
try {
|
||||
return adapter.nodeDescription(address);
|
||||
} catch (e) {
|
||||
|
@ -32,10 +27,9 @@ export function nodeDescription(
|
|||
export function edgeVerb(
|
||||
address: EdgeAddressT,
|
||||
direction: "FORWARD" | "BACKWARD",
|
||||
adapters: $ReadOnlyArray<DynamicPluginAdapter>
|
||||
adapters: DynamicAdapterSet
|
||||
): string {
|
||||
const adapter = dynamicDispatchByEdge(adapters, address);
|
||||
const edgeType = findEdgeType(adapter.static(), address);
|
||||
const edgeType = adapters.static().typeMatchingEdge(address);
|
||||
return direction === "FORWARD" ? edgeType.forwardName : edgeType.backwardName;
|
||||
}
|
||||
|
||||
|
@ -45,7 +39,7 @@ export function scoreDisplay(score: number) {
|
|||
|
||||
export type SharedProps = {|
|
||||
+pnd: PagerankNodeDecomposition,
|
||||
+adapters: $ReadOnlyArray<DynamicPluginAdapter>,
|
||||
+adapters: DynamicAdapterSet,
|
||||
+maxEntriesPerList: number,
|
||||
|};
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import {Graph, NodeAddress, EdgeAddress} from "../../../core/graph";
|
||||
|
||||
import {StaticAdapterSet, DynamicAdapterSet} from "../../adapters/adapterSet";
|
||||
import type {DynamicPluginAdapter} from "../../adapters/pluginAdapter";
|
||||
import {pagerank} from "../../../core/attribution/pagerank";
|
||||
|
||||
|
@ -34,7 +35,7 @@ export async function example() {
|
|||
barF: addEdge(["bar", "f"], nodes.bar1, nodes.xox),
|
||||
};
|
||||
|
||||
const adapters: DynamicPluginAdapter[] = [
|
||||
const dynamicAdapters: DynamicPluginAdapter[] = [
|
||||
{
|
||||
static: () => ({
|
||||
name: () => "foo",
|
||||
|
@ -132,6 +133,12 @@ export async function example() {
|
|||
},
|
||||
];
|
||||
|
||||
const staticAdapters = dynamicAdapters.map((x) => x.static());
|
||||
const adapters = new DynamicAdapterSet(
|
||||
new StaticAdapterSet(staticAdapters),
|
||||
dynamicAdapters
|
||||
);
|
||||
|
||||
const pnd = await pagerank(graph, (_unused_Edge) => ({
|
||||
toWeight: 1,
|
||||
froWeight: 1,
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
pagerank,
|
||||
} from "../../core/attribution/pagerank";
|
||||
|
||||
import type {DynamicPluginAdapter} from "../adapters/pluginAdapter";
|
||||
import {DynamicAdapterSet} from "../adapters/adapterSet";
|
||||
|
||||
import {defaultStaticAdapters} from "../adapters/defaultPlugins";
|
||||
|
||||
|
@ -247,12 +247,11 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
|
|||
|
||||
export type GraphWithAdapters = {|
|
||||
+graph: Graph,
|
||||
+adapters: $ReadOnlyArray<DynamicPluginAdapter>,
|
||||
+adapters: DynamicAdapterSet,
|
||||
|};
|
||||
export function loadGraphWithAdapters(repo: Repo): Promise<GraphWithAdapters> {
|
||||
const statics = defaultStaticAdapters();
|
||||
return Promise.all(statics.map((a) => a.load(repo))).then((adapters) => {
|
||||
const graph = Graph.merge(adapters.map((x) => x.graph()));
|
||||
return {graph, adapters};
|
||||
});
|
||||
export async function loadGraphWithAdapters(
|
||||
repo: Repo
|
||||
): Promise<GraphWithAdapters> {
|
||||
const adapters = await defaultStaticAdapters().load(repo);
|
||||
return {graph: adapters.graph(), adapters};
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
import {Graph} from "../../core/graph";
|
||||
import {makeRepo, type Repo} from "../../core/repo";
|
||||
import {type EdgeEvaluator} from "../../core/attribution/pagerank";
|
||||
import {StaticAdapterSet, DynamicAdapterSet} from "../adapters/adapterSet";
|
||||
import type {
|
||||
PagerankNodeDecomposition,
|
||||
PagerankOptions,
|
||||
|
@ -66,7 +67,10 @@ describe("app/credExplorer/state", () => {
|
|||
return (_unused_Edge) => ({toWeight: 3, froWeight: 4});
|
||||
}
|
||||
function graphWithAdapters(): GraphWithAdapters {
|
||||
return {graph: new Graph(), adapters: []};
|
||||
return {
|
||||
graph: new Graph(),
|
||||
adapters: new DynamicAdapterSet(new StaticAdapterSet([]), []),
|
||||
};
|
||||
}
|
||||
function pagerankNodeDecomposition() {
|
||||
return new Map();
|
||||
|
|
Loading…
Reference in New Issue