mirror of
https://github.com/status-im/sourcecred.git
synced 2025-01-14 14:46:30 +00:00
Create a weights
module with types and utils (#787)
This commit creates a central `weights` module that defines all of the weight-related types, and provides some utilities for dealing with them. This way users of weight-concepts do not need to depend on a lot of random modules just to get the relevant types. The utility methods are implicitly defined a few places in the codebase: now we can avoid re-writing them, and test them more thoroughly. Test plan: Unit tests pass.
This commit is contained in:
parent
d77c76082d
commit
b40c1d078d
@ -1,22 +1,18 @@
|
||||
// @flow
|
||||
|
||||
import React from "react";
|
||||
import * as NullUtil from "../../util/null";
|
||||
|
||||
import {type EdgeEvaluator} from "../../core/attribution/pagerank";
|
||||
import {weightsToEdgeEvaluator} from "./weights/weightsToEdgeEvaluator";
|
||||
import type {StaticPluginAdapter} from "../adapters/pluginAdapter";
|
||||
import type {StaticAdapterSet} from "../adapters/adapterSet";
|
||||
import {
|
||||
type WeightedTypes,
|
||||
PluginWeightConfig,
|
||||
} from "./weights/PluginWeightConfig";
|
||||
import {
|
||||
type WeightedNodeType,
|
||||
defaultWeightedNodeType,
|
||||
} from "./weights/NodeTypeConfig";
|
||||
import {
|
||||
type WeightedEdgeType,
|
||||
defaultWeightedEdgeType,
|
||||
} from "./weights/EdgeTypeConfig";
|
||||
defaultWeightsForAdapter,
|
||||
combineWeights,
|
||||
} from "./weights/weights";
|
||||
import {PluginWeightConfig} from "./weights/PluginWeightConfig";
|
||||
import {FALLBACK_NAME} from "../adapters/fallbackAdapter";
|
||||
|
||||
type Props = {|
|
||||
@ -88,23 +84,16 @@ export class WeightConfig extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
fire() {
|
||||
let nodeWeights: WeightedNodeType[] = [];
|
||||
let edgeWeights: WeightedEdgeType[] = [];
|
||||
for (const adapter of this.props.adapters.adapters()) {
|
||||
const weights = this.state.pluginNameToWeights.get(adapter.name());
|
||||
const newNodeWeights =
|
||||
weights == null
|
||||
? adapter.nodeTypes().map(defaultWeightedNodeType)
|
||||
: weights.nodes;
|
||||
const newEdgeWeights =
|
||||
weights == null
|
||||
? adapter.edgeTypes().map(defaultWeightedEdgeType)
|
||||
: weights.edges;
|
||||
nodeWeights = nodeWeights.concat(newNodeWeights);
|
||||
edgeWeights = edgeWeights.concat(newEdgeWeights);
|
||||
}
|
||||
|
||||
const weights = {nodes: nodeWeights, edges: edgeWeights};
|
||||
const weights = combineWeights(
|
||||
this.props.adapters
|
||||
.adapters()
|
||||
.map((adapter: StaticPluginAdapter) =>
|
||||
NullUtil.orElse(
|
||||
this.state.pluginNameToWeights.get(adapter.name()),
|
||||
defaultWeightsForAdapter(adapter)
|
||||
)
|
||||
)
|
||||
);
|
||||
const edgeEvaluator = weightsToEdgeEvaluator(weights);
|
||||
this.props.onChange(edgeEvaluator);
|
||||
}
|
||||
|
@ -2,21 +2,8 @@
|
||||
|
||||
import React from "react";
|
||||
import {WeightSlider, type Props as WeightSliderProps} from "./WeightSlider";
|
||||
import {type EdgeType} from "../../adapters/pluginAdapter";
|
||||
|
||||
export type WeightedEdgeType = {|
|
||||
+type: EdgeType,
|
||||
+forwardWeight: number,
|
||||
+backwardWeight: number,
|
||||
|};
|
||||
|
||||
export function defaultWeightedEdgeType(type: EdgeType): WeightedEdgeType {
|
||||
return {
|
||||
type,
|
||||
forwardWeight: type.defaultForwardWeight,
|
||||
backwardWeight: type.defaultBackwardWeight,
|
||||
};
|
||||
}
|
||||
import type {WeightedEdgeType} from "./weights";
|
||||
|
||||
export class EdgeTypeConfig extends React.Component<{
|
||||
+weightedType: WeightedEdgeType,
|
||||
|
@ -4,23 +4,12 @@ import React from "react";
|
||||
import {shallow} from "enzyme";
|
||||
|
||||
import {WeightSlider} from "./WeightSlider";
|
||||
import {
|
||||
defaultWeightedEdgeType,
|
||||
EdgeTypeConfig,
|
||||
EdgeWeightSlider,
|
||||
} from "./EdgeTypeConfig";
|
||||
import {EdgeTypeConfig, EdgeWeightSlider} from "./EdgeTypeConfig";
|
||||
import {assemblesEdgeType} from "../../adapters/demoAdapters";
|
||||
|
||||
require("../../testUtil").configureEnzyme();
|
||||
|
||||
describe("app/credExplorer/weights/EdgeTypeConfig", () => {
|
||||
describe("defaultWeightedEdgeType", () => {
|
||||
it("sets default weights as specified in the type", () => {
|
||||
const wet = defaultWeightedEdgeType(assemblesEdgeType);
|
||||
expect(wet.forwardWeight).toEqual(wet.type.defaultForwardWeight);
|
||||
expect(wet.backwardWeight).toEqual(wet.type.defaultBackwardWeight);
|
||||
});
|
||||
});
|
||||
describe("EdgeTypeConfig", () => {
|
||||
function example() {
|
||||
const onChange = jest.fn();
|
||||
|
@ -2,16 +2,7 @@
|
||||
|
||||
import React from "react";
|
||||
import {WeightSlider} from "./WeightSlider";
|
||||
import {type NodeType} from "../../adapters/pluginAdapter";
|
||||
|
||||
export type WeightedNodeType = {|+type: NodeType, +weight: number|};
|
||||
|
||||
export function defaultWeightedNodeType(type: NodeType): WeightedNodeType {
|
||||
return {
|
||||
type,
|
||||
weight: type.defaultWeight,
|
||||
};
|
||||
}
|
||||
import type {WeightedNodeType} from "./weights";
|
||||
|
||||
export class NodeTypeConfig extends React.Component<{
|
||||
+weightedType: WeightedNodeType,
|
||||
|
@ -4,18 +4,12 @@ import React from "react";
|
||||
import {shallow} from "enzyme";
|
||||
|
||||
import {WeightSlider} from "./WeightSlider";
|
||||
import {defaultWeightedNodeType, NodeTypeConfig} from "./NodeTypeConfig";
|
||||
import {NodeTypeConfig} from "./NodeTypeConfig";
|
||||
import {inserterNodeType} from "../../adapters/demoAdapters";
|
||||
|
||||
require("../../testUtil").configureEnzyme();
|
||||
|
||||
describe("app/credExplorer/weights/NodeTypeConfig", () => {
|
||||
describe("defaultWeightedNodeType", () => {
|
||||
it("sets default weight as specified in type", () => {
|
||||
const wnt = defaultWeightedNodeType(inserterNodeType);
|
||||
expect(wnt.weight).toEqual(wnt.type.defaultWeight);
|
||||
});
|
||||
});
|
||||
describe("NodeTypeConfig", () => {
|
||||
function example() {
|
||||
const onChange = jest.fn();
|
||||
|
@ -2,23 +2,17 @@
|
||||
|
||||
import React from "react";
|
||||
import deepEqual from "lodash.isequal";
|
||||
import {
|
||||
NodeTypeConfig,
|
||||
defaultWeightedNodeType,
|
||||
type WeightedNodeType,
|
||||
} from "./NodeTypeConfig";
|
||||
import {
|
||||
EdgeTypeConfig,
|
||||
defaultWeightedEdgeType,
|
||||
type WeightedEdgeType,
|
||||
} from "./EdgeTypeConfig";
|
||||
import {NodeTypeConfig} from "./NodeTypeConfig";
|
||||
import {EdgeTypeConfig} from "./EdgeTypeConfig";
|
||||
import {StaticPluginAdapter} from "../../adapters/pluginAdapter";
|
||||
import {styledVariable} from "./EdgeTypeConfig";
|
||||
|
||||
export type WeightedTypes = {|
|
||||
+nodes: $ReadOnlyArray<WeightedNodeType>,
|
||||
+edges: $ReadOnlyArray<WeightedEdgeType>,
|
||||
|};
|
||||
import {
|
||||
type WeightedTypes,
|
||||
type WeightedEdgeType,
|
||||
type WeightedNodeType,
|
||||
defaultWeightedNodeType,
|
||||
defaultWeightedEdgeType,
|
||||
} from "./weights";
|
||||
|
||||
export type Props = {|
|
||||
+adapter: StaticPluginAdapter,
|
||||
|
@ -4,8 +4,13 @@ import React from "react";
|
||||
import {shallow} from "enzyme";
|
||||
import {PluginWeightConfig} from "./PluginWeightConfig";
|
||||
import {FactorioStaticAdapter} from "../../adapters/demoAdapters";
|
||||
import {NodeTypeConfig, defaultWeightedNodeType} from "./NodeTypeConfig";
|
||||
import {EdgeTypeConfig, defaultWeightedEdgeType} from "./EdgeTypeConfig";
|
||||
import {NodeTypeConfig} from "./NodeTypeConfig";
|
||||
import {EdgeTypeConfig} from "./EdgeTypeConfig";
|
||||
import {
|
||||
defaultWeightsForAdapter,
|
||||
defaultWeightedNodeType,
|
||||
defaultWeightedEdgeType,
|
||||
} from "./weights";
|
||||
|
||||
require("../../testUtil").configureEnzyme();
|
||||
|
||||
@ -21,10 +26,7 @@ describe("src/app/credExplorer/weights/PluginWeightConfig", () => {
|
||||
}
|
||||
it("fires plugin's default weights on mount", () => {
|
||||
const {onChange, adapter} = example();
|
||||
const expected = {
|
||||
nodes: adapter.nodeTypes().map(defaultWeightedNodeType),
|
||||
edges: adapter.edgeTypes().map(defaultWeightedEdgeType),
|
||||
};
|
||||
const expected = defaultWeightsForAdapter(adapter);
|
||||
expect(onChange).toHaveBeenCalledWith(expected);
|
||||
});
|
||||
it("renders a NodeTypeConfig for each node type", () => {
|
||||
|
74
src/app/credExplorer/weights/weights.js
Normal file
74
src/app/credExplorer/weights/weights.js
Normal file
@ -0,0 +1,74 @@
|
||||
// @flow
|
||||
|
||||
import {NodeAddress, EdgeAddress} from "../../../core/graph";
|
||||
import type {NodeType, EdgeType} from "../../adapters/pluginAdapter";
|
||||
import type {StaticPluginAdapter} from "../../adapters/pluginAdapter";
|
||||
import type {StaticAdapterSet} from "../../adapters/adapterSet";
|
||||
|
||||
export type WeightedNodeType = {|+type: NodeType, +weight: number|};
|
||||
|
||||
export type WeightedEdgeType = {|
|
||||
+type: EdgeType,
|
||||
+forwardWeight: number,
|
||||
+backwardWeight: number,
|
||||
|};
|
||||
|
||||
export type WeightedTypes = {|
|
||||
+nodes: $ReadOnlyArray<WeightedNodeType>,
|
||||
+edges: $ReadOnlyArray<WeightedEdgeType>,
|
||||
|};
|
||||
|
||||
export function defaultWeightedNodeType(type: NodeType): WeightedNodeType {
|
||||
return {
|
||||
type,
|
||||
weight: type.defaultWeight,
|
||||
};
|
||||
}
|
||||
|
||||
export function defaultWeightedEdgeType(type: EdgeType): WeightedEdgeType {
|
||||
return {
|
||||
type,
|
||||
forwardWeight: type.defaultForwardWeight,
|
||||
backwardWeight: type.defaultBackwardWeight,
|
||||
};
|
||||
}
|
||||
|
||||
export function defaultWeightsForAdapter(
|
||||
adapter: StaticPluginAdapter
|
||||
): WeightedTypes {
|
||||
return {
|
||||
nodes: adapter.nodeTypes().map(defaultWeightedNodeType),
|
||||
edges: adapter.edgeTypes().map(defaultWeightedEdgeType),
|
||||
};
|
||||
}
|
||||
|
||||
export function combineWeights(
|
||||
ws: $ReadOnlyArray<WeightedTypes>
|
||||
): WeightedTypes {
|
||||
const seenPrefixes = new Set();
|
||||
const nodes = [].concat(...ws.map((x) => x.nodes));
|
||||
for (const {
|
||||
type: {prefix},
|
||||
} of nodes) {
|
||||
if (seenPrefixes.has(prefix)) {
|
||||
throw new Error(`Duplicate prefix: ${NodeAddress.toString(prefix)}`);
|
||||
}
|
||||
seenPrefixes.add(prefix);
|
||||
}
|
||||
const edges = [].concat(...ws.map((x) => x.edges));
|
||||
for (const {
|
||||
type: {prefix},
|
||||
} of edges) {
|
||||
if (seenPrefixes.has(prefix)) {
|
||||
throw new Error(`Duplicate prefix: ${EdgeAddress.toString(prefix)}`);
|
||||
}
|
||||
seenPrefixes.add(prefix);
|
||||
}
|
||||
return {nodes, edges};
|
||||
}
|
||||
|
||||
export function defaultWeightsForAdapterSet(
|
||||
adapters: StaticAdapterSet
|
||||
): WeightedTypes {
|
||||
return combineWeights(adapters.adapters().map(defaultWeightsForAdapter));
|
||||
}
|
93
src/app/credExplorer/weights/weights.test.js
Normal file
93
src/app/credExplorer/weights/weights.test.js
Normal file
@ -0,0 +1,93 @@
|
||||
// @flow
|
||||
|
||||
import {
|
||||
defaultWeightedNodeType,
|
||||
defaultWeightedEdgeType,
|
||||
defaultWeightsForAdapter,
|
||||
combineWeights,
|
||||
defaultWeightsForAdapterSet,
|
||||
} from "./weights";
|
||||
import {
|
||||
inserterNodeType,
|
||||
machineNodeType,
|
||||
assemblesEdgeType,
|
||||
transportsEdgeType,
|
||||
FactorioStaticAdapter,
|
||||
staticAdapterSet,
|
||||
} from "../../adapters/demoAdapters";
|
||||
|
||||
describe("app/credExplorer/weights/weights", () => {
|
||||
describe("defaultWeightedNodeType", () => {
|
||||
it("sets default weight as specified in type", () => {
|
||||
const wnt = defaultWeightedNodeType(inserterNodeType);
|
||||
expect(wnt.weight).toEqual(wnt.type.defaultWeight);
|
||||
});
|
||||
});
|
||||
describe("defaultWeightedEdgeType", () => {
|
||||
it("sets default weights as specified in the type", () => {
|
||||
const wet = defaultWeightedEdgeType(assemblesEdgeType);
|
||||
expect(wet.forwardWeight).toEqual(wet.type.defaultForwardWeight);
|
||||
expect(wet.backwardWeight).toEqual(wet.type.defaultBackwardWeight);
|
||||
});
|
||||
});
|
||||
describe("defaultWeightsForAdapter", () => {
|
||||
it("works on the demo adapter", () => {
|
||||
const adapter = new FactorioStaticAdapter();
|
||||
const expected = {
|
||||
nodes: adapter.nodeTypes().map(defaultWeightedNodeType),
|
||||
edges: adapter.edgeTypes().map(defaultWeightedEdgeType),
|
||||
};
|
||||
expect(defaultWeightsForAdapter(adapter)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
describe("combineWeights", () => {
|
||||
const defaultWeights = () =>
|
||||
defaultWeightsForAdapter(new FactorioStaticAdapter());
|
||||
const emptyWeights = () => ({nodes: [], edges: []});
|
||||
it("successfully combines WeightedTypes", () => {
|
||||
const weights1 = {
|
||||
nodes: [defaultWeightedNodeType(inserterNodeType)],
|
||||
edges: [defaultWeightedEdgeType(assemblesEdgeType)],
|
||||
};
|
||||
const weights2 = {
|
||||
nodes: [defaultWeightedNodeType(machineNodeType)],
|
||||
edges: [defaultWeightedEdgeType(transportsEdgeType)],
|
||||
};
|
||||
expect(combineWeights([weights1, weights2])).toEqual(defaultWeights());
|
||||
});
|
||||
it("treats empty weights as an identity", () => {
|
||||
expect(
|
||||
combineWeights([emptyWeights(), defaultWeights(), emptyWeights()])
|
||||
).toEqual(defaultWeights());
|
||||
});
|
||||
it("errors on duplicate edge prefix", () => {
|
||||
const weights = {
|
||||
nodes: [],
|
||||
edges: [defaultWeightedEdgeType(assemblesEdgeType)],
|
||||
};
|
||||
expect(() => combineWeights([weights, weights])).toThrowError(
|
||||
"Duplicate prefix"
|
||||
);
|
||||
});
|
||||
it("errors on duplicate node prefix", () => {
|
||||
const weights = {
|
||||
nodes: [defaultWeightedNodeType(inserterNodeType)],
|
||||
edges: [],
|
||||
};
|
||||
expect(() => combineWeights([weights, weights])).toThrowError(
|
||||
"Duplicate prefix"
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("defaultWeightsForAdapterSet", () => {
|
||||
it("works on a demo adapter set", () => {
|
||||
expect(defaultWeightsForAdapterSet(staticAdapterSet())).toEqual(
|
||||
combineWeights(
|
||||
staticAdapterSet()
|
||||
.adapters()
|
||||
.map(defaultWeightsForAdapter)
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import type {Edge} from "../../../core/graph";
|
||||
import type {WeightedTypes} from "./PluginWeightConfig";
|
||||
import type {WeightedTypes} from "./weights";
|
||||
import type {EdgeEvaluator} from "../../../core/attribution/pagerank";
|
||||
import {NodeTrie, EdgeTrie} from "../../../core/trie";
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user