Change WeightedTypes to contain maps (#795)
This will make it easier to re-organize the weight components so that the WeightedTypes have a single source of truth, as described in https://github.com/sourcecred/sourcecred/pull/792#issuecomment-419234721 Test plan: Unit tests suffice.
This commit is contained in:
parent
ad5ea761ea
commit
ead0157960
|
@ -1,7 +1,7 @@
|
|||
// @flow
|
||||
|
||||
import React from "react";
|
||||
import deepEqual from "lodash.isequal";
|
||||
import * as MapUtil from "../../../util/map";
|
||||
import {NodeTypeConfig} from "./NodeTypeConfig";
|
||||
import {EdgeTypeConfig} from "./EdgeTypeConfig";
|
||||
import {StaticPluginAdapter} from "../../adapters/pluginAdapter";
|
||||
|
@ -37,45 +37,53 @@ export class PluginWeightConfig extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
_renderNodeWeightControls() {
|
||||
return this.state.weights.nodes.map((wnt: WeightedNodeType) => {
|
||||
const onChange = (newType: WeightedNodeType) => {
|
||||
const index = this.state.weights.nodes.findIndex((x) =>
|
||||
deepEqual(x.type, wnt.type)
|
||||
return Array.from(this.state.weights.nodes.values()).map(
|
||||
(wnt: WeightedNodeType) => {
|
||||
const onChange = (newType: WeightedNodeType) => {
|
||||
this.setState(
|
||||
(state) => {
|
||||
const newNodes = MapUtil.copy(state.weights.nodes);
|
||||
newNodes.set(newType.type.prefix, newType);
|
||||
const weights = {...state.weights, nodes: newNodes};
|
||||
return {weights};
|
||||
},
|
||||
() => this.fire()
|
||||
);
|
||||
};
|
||||
return (
|
||||
<NodeTypeConfig
|
||||
key={wnt.type.prefix}
|
||||
weightedType={wnt}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
const newNodes = this.state.weights.nodes.slice();
|
||||
newNodes[index] = newType;
|
||||
const weights = {nodes: newNodes, edges: this.state.weights.edges};
|
||||
this.setState({weights}, () => this.fire());
|
||||
};
|
||||
return (
|
||||
<NodeTypeConfig
|
||||
key={wnt.type.prefix}
|
||||
weightedType={wnt}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_renderEdgeWeightControls() {
|
||||
return this.state.weights.edges.map((wnt: WeightedEdgeType) => {
|
||||
const onChange = (newType: WeightedEdgeType) => {
|
||||
const index = this.state.weights.edges.findIndex((x) =>
|
||||
deepEqual(x.type, wnt.type)
|
||||
return Array.from(this.state.weights.edges.values()).map(
|
||||
(wnt: WeightedEdgeType) => {
|
||||
const onChange = (newType: WeightedEdgeType) => {
|
||||
this.setState(
|
||||
(state) => {
|
||||
const newEdges = MapUtil.copy(state.weights.edges);
|
||||
newEdges.set(newType.type.prefix, newType);
|
||||
const weights = {...state.weights, edges: newEdges};
|
||||
return {weights};
|
||||
},
|
||||
() => this.fire()
|
||||
);
|
||||
};
|
||||
return (
|
||||
<EdgeTypeConfig
|
||||
key={wnt.type.prefix}
|
||||
weightedType={wnt}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
const newEdges = this.state.weights.edges.slice();
|
||||
newEdges[index] = newType;
|
||||
const weights = {nodes: this.state.weights.nodes, edges: newEdges};
|
||||
this.setState({weights}, () => this.fire());
|
||||
};
|
||||
return (
|
||||
<EdgeTypeConfig
|
||||
key={wnt.type.prefix}
|
||||
weightedType={wnt}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -55,8 +55,10 @@ describe("src/app/credExplorer/weights/PluginWeightConfig", () => {
|
|||
const newWeightedType = {...nodes[0], weight: 707};
|
||||
const newNodes = [newWeightedType, ...nodes.slice(1)];
|
||||
const expected = {
|
||||
nodes: newNodes,
|
||||
edges: adapter.edgeTypes().map(defaultWeightedEdgeType),
|
||||
nodes: new Map(newNodes.map((x) => [x.type.prefix, x])),
|
||||
edges: new Map(
|
||||
adapter.edgeTypes().map((x) => [x.prefix, defaultWeightedEdgeType(x)])
|
||||
),
|
||||
};
|
||||
ntc.props().onChange(newWeightedType);
|
||||
expect(onChange).toHaveBeenCalledTimes(2);
|
||||
|
@ -69,8 +71,10 @@ describe("src/app/credExplorer/weights/PluginWeightConfig", () => {
|
|||
const newWeightedType = {...edges[0], weight: 707};
|
||||
const newEdges = [newWeightedType, ...edges.slice(1)];
|
||||
const expected = {
|
||||
nodes: adapter.nodeTypes().map(defaultWeightedNodeType),
|
||||
edges: newEdges,
|
||||
nodes: new Map(
|
||||
adapter.nodeTypes().map((x) => [x.prefix, defaultWeightedNodeType(x)])
|
||||
),
|
||||
edges: new Map(newEdges.map((x) => [x.type.prefix, x])),
|
||||
};
|
||||
ntc.props().onChange(newWeightedType);
|
||||
expect(onChange).toHaveBeenCalledTimes(2);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
|
||||
import {NodeAddress, EdgeAddress} from "../../../core/graph";
|
||||
import * as MapUtil from "../../../util/map";
|
||||
import {type NodeAddressT, type EdgeAddressT} from "../../../core/graph";
|
||||
import type {NodeType, EdgeType} from "../../adapters/pluginAdapter";
|
||||
import type {StaticPluginAdapter} from "../../adapters/pluginAdapter";
|
||||
import type {StaticAdapterSet} from "../../adapters/adapterSet";
|
||||
|
@ -14,8 +15,9 @@ export type WeightedEdgeType = {|
|
|||
|};
|
||||
|
||||
export type WeightedTypes = {|
|
||||
+nodes: $ReadOnlyArray<WeightedNodeType>,
|
||||
+edges: $ReadOnlyArray<WeightedEdgeType>,
|
||||
// Map from the weighted type's prefix to the type
|
||||
+nodes: Map<NodeAddressT, WeightedNodeType>,
|
||||
+edges: Map<EdgeAddressT, WeightedEdgeType>,
|
||||
|};
|
||||
|
||||
export function defaultWeightedNodeType(type: NodeType): WeightedNodeType {
|
||||
|
@ -37,34 +39,22 @@ export function defaultWeightsForAdapter(
|
|||
adapter: StaticPluginAdapter
|
||||
): WeightedTypes {
|
||||
return {
|
||||
nodes: adapter.nodeTypes().map(defaultWeightedNodeType),
|
||||
edges: adapter.edgeTypes().map(defaultWeightedEdgeType),
|
||||
nodes: new Map(
|
||||
adapter.nodeTypes().map((x) => [x.prefix, defaultWeightedNodeType(x)])
|
||||
),
|
||||
edges: new Map(
|
||||
adapter.edgeTypes().map((x) => [x.prefix, defaultWeightedEdgeType(x)])
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
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};
|
||||
return {
|
||||
nodes: MapUtil.merge(ws.map((x) => x.nodes)),
|
||||
edges: MapUtil.merge(ws.map((x) => x.edges)),
|
||||
};
|
||||
}
|
||||
|
||||
export function defaultWeightsForAdapterSet(
|
||||
|
|
|
@ -34,8 +34,12 @@ describe("app/credExplorer/weights/weights", () => {
|
|||
it("works on the demo adapter", () => {
|
||||
const adapter = new FactorioStaticAdapter();
|
||||
const expected = {
|
||||
nodes: adapter.nodeTypes().map(defaultWeightedNodeType),
|
||||
edges: adapter.edgeTypes().map(defaultWeightedEdgeType),
|
||||
nodes: new Map(
|
||||
adapter.nodeTypes().map((x) => [x.prefix, defaultWeightedNodeType(x)])
|
||||
),
|
||||
edges: new Map(
|
||||
adapter.edgeTypes().map((x) => [x.prefix, defaultWeightedEdgeType(x)])
|
||||
),
|
||||
};
|
||||
expect(defaultWeightsForAdapter(adapter)).toEqual(expected);
|
||||
});
|
||||
|
@ -43,15 +47,27 @@ describe("app/credExplorer/weights/weights", () => {
|
|||
describe("combineWeights", () => {
|
||||
const defaultWeights = () =>
|
||||
defaultWeightsForAdapter(new FactorioStaticAdapter());
|
||||
const emptyWeights = () => ({nodes: [], edges: []});
|
||||
const emptyWeights = () => ({nodes: new Map(), edges: new Map()});
|
||||
it("successfully combines WeightedTypes", () => {
|
||||
const weights1 = {
|
||||
nodes: [defaultWeightedNodeType(inserterNodeType)],
|
||||
edges: [defaultWeightedEdgeType(assemblesEdgeType)],
|
||||
nodes: new Map().set(
|
||||
inserterNodeType.prefix,
|
||||
defaultWeightedNodeType(inserterNodeType)
|
||||
),
|
||||
edges: new Map().set(
|
||||
assemblesEdgeType.prefix,
|
||||
defaultWeightedEdgeType(assemblesEdgeType)
|
||||
),
|
||||
};
|
||||
const weights2 = {
|
||||
nodes: [defaultWeightedNodeType(machineNodeType)],
|
||||
edges: [defaultWeightedEdgeType(transportsEdgeType)],
|
||||
nodes: new Map().set(
|
||||
machineNodeType.prefix,
|
||||
defaultWeightedNodeType(machineNodeType)
|
||||
),
|
||||
edges: new Map().set(
|
||||
transportsEdgeType.prefix,
|
||||
defaultWeightedEdgeType(transportsEdgeType)
|
||||
),
|
||||
};
|
||||
expect(combineWeights([weights1, weights2])).toEqual(defaultWeights());
|
||||
});
|
||||
|
@ -62,20 +78,26 @@ describe("app/credExplorer/weights/weights", () => {
|
|||
});
|
||||
it("errors on duplicate edge prefix", () => {
|
||||
const weights = {
|
||||
nodes: [],
|
||||
edges: [defaultWeightedEdgeType(assemblesEdgeType)],
|
||||
nodes: new Map(),
|
||||
edges: new Map().set(
|
||||
assemblesEdgeType.prefix,
|
||||
defaultWeightedEdgeType(assemblesEdgeType)
|
||||
),
|
||||
};
|
||||
expect(() => combineWeights([weights, weights])).toThrowError(
|
||||
"Duplicate prefix"
|
||||
"duplicate key"
|
||||
);
|
||||
});
|
||||
it("errors on duplicate node prefix", () => {
|
||||
const weights = {
|
||||
nodes: [defaultWeightedNodeType(inserterNodeType)],
|
||||
edges: [],
|
||||
nodes: new Map().set(
|
||||
inserterNodeType.prefix,
|
||||
defaultWeightedNodeType(inserterNodeType)
|
||||
),
|
||||
edges: new Map(),
|
||||
};
|
||||
expect(() => combineWeights([weights, weights])).toThrowError(
|
||||
"Duplicate prefix"
|
||||
"duplicate key"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,11 +7,11 @@ import {NodeTrie, EdgeTrie} from "../../../core/trie";
|
|||
|
||||
export function weightsToEdgeEvaluator(weights: WeightedTypes): EdgeEvaluator {
|
||||
const nodeTrie = new NodeTrie();
|
||||
for (const {type, weight} of weights.nodes) {
|
||||
for (const {type, weight} of weights.nodes.values()) {
|
||||
nodeTrie.add(type.prefix, weight);
|
||||
}
|
||||
const edgeTrie = new EdgeTrie();
|
||||
for (const {type, forwardWeight, backwardWeight} of weights.edges) {
|
||||
for (const {type, forwardWeight, backwardWeight} of weights.edges.values()) {
|
||||
edgeTrie.add(type.prefix, {forwardWeight, backwardWeight});
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ describe("app/credExplorer/weights/weightsToEdgeEvaluator", () => {
|
|||
{weight: NullUtil.orElse(machine, 1), type: machineNodeType},
|
||||
{weight: NullUtil.orElse(baseNode, 1), type: fallbackNodeType},
|
||||
];
|
||||
const nodesMap = new Map(nodes.map((x) => [x.type.prefix, x]));
|
||||
const edges = [
|
||||
{
|
||||
forwardWeight: NullUtil.orElse(assemblesForward, 1),
|
||||
|
@ -50,7 +51,8 @@ describe("app/credExplorer/weights/weightsToEdgeEvaluator", () => {
|
|||
type: fallbackEdgeType,
|
||||
},
|
||||
];
|
||||
return {nodes, edges};
|
||||
const edgesMap = new Map(edges.map((x) => [x.type.prefix, x]));
|
||||
return {nodes: nodesMap, edges: edgesMap};
|
||||
}
|
||||
function exampleEdgeWeights(weightArgs: WeightArgs) {
|
||||
const ws = weights(weightArgs);
|
||||
|
|
Loading…
Reference in New Issue