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
|
// @flow
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import deepEqual from "lodash.isequal";
|
import * as MapUtil from "../../../util/map";
|
||||||
import {NodeTypeConfig} from "./NodeTypeConfig";
|
import {NodeTypeConfig} from "./NodeTypeConfig";
|
||||||
import {EdgeTypeConfig} from "./EdgeTypeConfig";
|
import {EdgeTypeConfig} from "./EdgeTypeConfig";
|
||||||
import {StaticPluginAdapter} from "../../adapters/pluginAdapter";
|
import {StaticPluginAdapter} from "../../adapters/pluginAdapter";
|
||||||
|
@ -37,15 +37,18 @@ export class PluginWeightConfig extends React.Component<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderNodeWeightControls() {
|
_renderNodeWeightControls() {
|
||||||
return this.state.weights.nodes.map((wnt: WeightedNodeType) => {
|
return Array.from(this.state.weights.nodes.values()).map(
|
||||||
|
(wnt: WeightedNodeType) => {
|
||||||
const onChange = (newType: WeightedNodeType) => {
|
const onChange = (newType: WeightedNodeType) => {
|
||||||
const index = this.state.weights.nodes.findIndex((x) =>
|
this.setState(
|
||||||
deepEqual(x.type, wnt.type)
|
(state) => {
|
||||||
|
const newNodes = MapUtil.copy(state.weights.nodes);
|
||||||
|
newNodes.set(newType.type.prefix, newType);
|
||||||
|
const weights = {...state.weights, nodes: newNodes};
|
||||||
|
return {weights};
|
||||||
|
},
|
||||||
|
() => this.fire()
|
||||||
);
|
);
|
||||||
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 (
|
return (
|
||||||
<NodeTypeConfig
|
<NodeTypeConfig
|
||||||
|
@ -54,19 +57,23 @@ export class PluginWeightConfig extends React.Component<Props, State> {
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderEdgeWeightControls() {
|
_renderEdgeWeightControls() {
|
||||||
return this.state.weights.edges.map((wnt: WeightedEdgeType) => {
|
return Array.from(this.state.weights.edges.values()).map(
|
||||||
|
(wnt: WeightedEdgeType) => {
|
||||||
const onChange = (newType: WeightedEdgeType) => {
|
const onChange = (newType: WeightedEdgeType) => {
|
||||||
const index = this.state.weights.edges.findIndex((x) =>
|
this.setState(
|
||||||
deepEqual(x.type, wnt.type)
|
(state) => {
|
||||||
|
const newEdges = MapUtil.copy(state.weights.edges);
|
||||||
|
newEdges.set(newType.type.prefix, newType);
|
||||||
|
const weights = {...state.weights, edges: newEdges};
|
||||||
|
return {weights};
|
||||||
|
},
|
||||||
|
() => this.fire()
|
||||||
);
|
);
|
||||||
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 (
|
return (
|
||||||
<EdgeTypeConfig
|
<EdgeTypeConfig
|
||||||
|
@ -75,7 +82,8 @@ export class PluginWeightConfig extends React.Component<Props, State> {
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -55,8 +55,10 @@ describe("src/app/credExplorer/weights/PluginWeightConfig", () => {
|
||||||
const newWeightedType = {...nodes[0], weight: 707};
|
const newWeightedType = {...nodes[0], weight: 707};
|
||||||
const newNodes = [newWeightedType, ...nodes.slice(1)];
|
const newNodes = [newWeightedType, ...nodes.slice(1)];
|
||||||
const expected = {
|
const expected = {
|
||||||
nodes: newNodes,
|
nodes: new Map(newNodes.map((x) => [x.type.prefix, x])),
|
||||||
edges: adapter.edgeTypes().map(defaultWeightedEdgeType),
|
edges: new Map(
|
||||||
|
adapter.edgeTypes().map((x) => [x.prefix, defaultWeightedEdgeType(x)])
|
||||||
|
),
|
||||||
};
|
};
|
||||||
ntc.props().onChange(newWeightedType);
|
ntc.props().onChange(newWeightedType);
|
||||||
expect(onChange).toHaveBeenCalledTimes(2);
|
expect(onChange).toHaveBeenCalledTimes(2);
|
||||||
|
@ -69,8 +71,10 @@ describe("src/app/credExplorer/weights/PluginWeightConfig", () => {
|
||||||
const newWeightedType = {...edges[0], weight: 707};
|
const newWeightedType = {...edges[0], weight: 707};
|
||||||
const newEdges = [newWeightedType, ...edges.slice(1)];
|
const newEdges = [newWeightedType, ...edges.slice(1)];
|
||||||
const expected = {
|
const expected = {
|
||||||
nodes: adapter.nodeTypes().map(defaultWeightedNodeType),
|
nodes: new Map(
|
||||||
edges: newEdges,
|
adapter.nodeTypes().map((x) => [x.prefix, defaultWeightedNodeType(x)])
|
||||||
|
),
|
||||||
|
edges: new Map(newEdges.map((x) => [x.type.prefix, x])),
|
||||||
};
|
};
|
||||||
ntc.props().onChange(newWeightedType);
|
ntc.props().onChange(newWeightedType);
|
||||||
expect(onChange).toHaveBeenCalledTimes(2);
|
expect(onChange).toHaveBeenCalledTimes(2);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// @flow
|
// @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 {NodeType, EdgeType} from "../../adapters/pluginAdapter";
|
||||||
import type {StaticPluginAdapter} from "../../adapters/pluginAdapter";
|
import type {StaticPluginAdapter} from "../../adapters/pluginAdapter";
|
||||||
import type {StaticAdapterSet} from "../../adapters/adapterSet";
|
import type {StaticAdapterSet} from "../../adapters/adapterSet";
|
||||||
|
@ -14,8 +15,9 @@ export type WeightedEdgeType = {|
|
||||||
|};
|
|};
|
||||||
|
|
||||||
export type WeightedTypes = {|
|
export type WeightedTypes = {|
|
||||||
+nodes: $ReadOnlyArray<WeightedNodeType>,
|
// Map from the weighted type's prefix to the type
|
||||||
+edges: $ReadOnlyArray<WeightedEdgeType>,
|
+nodes: Map<NodeAddressT, WeightedNodeType>,
|
||||||
|
+edges: Map<EdgeAddressT, WeightedEdgeType>,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
export function defaultWeightedNodeType(type: NodeType): WeightedNodeType {
|
export function defaultWeightedNodeType(type: NodeType): WeightedNodeType {
|
||||||
|
@ -37,34 +39,22 @@ export function defaultWeightsForAdapter(
|
||||||
adapter: StaticPluginAdapter
|
adapter: StaticPluginAdapter
|
||||||
): WeightedTypes {
|
): WeightedTypes {
|
||||||
return {
|
return {
|
||||||
nodes: adapter.nodeTypes().map(defaultWeightedNodeType),
|
nodes: new Map(
|
||||||
edges: adapter.edgeTypes().map(defaultWeightedEdgeType),
|
adapter.nodeTypes().map((x) => [x.prefix, defaultWeightedNodeType(x)])
|
||||||
|
),
|
||||||
|
edges: new Map(
|
||||||
|
adapter.edgeTypes().map((x) => [x.prefix, defaultWeightedEdgeType(x)])
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function combineWeights(
|
export function combineWeights(
|
||||||
ws: $ReadOnlyArray<WeightedTypes>
|
ws: $ReadOnlyArray<WeightedTypes>
|
||||||
): WeightedTypes {
|
): WeightedTypes {
|
||||||
const seenPrefixes = new Set();
|
return {
|
||||||
const nodes = [].concat(...ws.map((x) => x.nodes));
|
nodes: MapUtil.merge(ws.map((x) => x.nodes)),
|
||||||
for (const {
|
edges: MapUtil.merge(ws.map((x) => x.edges)),
|
||||||
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(
|
export function defaultWeightsForAdapterSet(
|
||||||
|
|
|
@ -34,8 +34,12 @@ describe("app/credExplorer/weights/weights", () => {
|
||||||
it("works on the demo adapter", () => {
|
it("works on the demo adapter", () => {
|
||||||
const adapter = new FactorioStaticAdapter();
|
const adapter = new FactorioStaticAdapter();
|
||||||
const expected = {
|
const expected = {
|
||||||
nodes: adapter.nodeTypes().map(defaultWeightedNodeType),
|
nodes: new Map(
|
||||||
edges: adapter.edgeTypes().map(defaultWeightedEdgeType),
|
adapter.nodeTypes().map((x) => [x.prefix, defaultWeightedNodeType(x)])
|
||||||
|
),
|
||||||
|
edges: new Map(
|
||||||
|
adapter.edgeTypes().map((x) => [x.prefix, defaultWeightedEdgeType(x)])
|
||||||
|
),
|
||||||
};
|
};
|
||||||
expect(defaultWeightsForAdapter(adapter)).toEqual(expected);
|
expect(defaultWeightsForAdapter(adapter)).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
@ -43,15 +47,27 @@ describe("app/credExplorer/weights/weights", () => {
|
||||||
describe("combineWeights", () => {
|
describe("combineWeights", () => {
|
||||||
const defaultWeights = () =>
|
const defaultWeights = () =>
|
||||||
defaultWeightsForAdapter(new FactorioStaticAdapter());
|
defaultWeightsForAdapter(new FactorioStaticAdapter());
|
||||||
const emptyWeights = () => ({nodes: [], edges: []});
|
const emptyWeights = () => ({nodes: new Map(), edges: new Map()});
|
||||||
it("successfully combines WeightedTypes", () => {
|
it("successfully combines WeightedTypes", () => {
|
||||||
const weights1 = {
|
const weights1 = {
|
||||||
nodes: [defaultWeightedNodeType(inserterNodeType)],
|
nodes: new Map().set(
|
||||||
edges: [defaultWeightedEdgeType(assemblesEdgeType)],
|
inserterNodeType.prefix,
|
||||||
|
defaultWeightedNodeType(inserterNodeType)
|
||||||
|
),
|
||||||
|
edges: new Map().set(
|
||||||
|
assemblesEdgeType.prefix,
|
||||||
|
defaultWeightedEdgeType(assemblesEdgeType)
|
||||||
|
),
|
||||||
};
|
};
|
||||||
const weights2 = {
|
const weights2 = {
|
||||||
nodes: [defaultWeightedNodeType(machineNodeType)],
|
nodes: new Map().set(
|
||||||
edges: [defaultWeightedEdgeType(transportsEdgeType)],
|
machineNodeType.prefix,
|
||||||
|
defaultWeightedNodeType(machineNodeType)
|
||||||
|
),
|
||||||
|
edges: new Map().set(
|
||||||
|
transportsEdgeType.prefix,
|
||||||
|
defaultWeightedEdgeType(transportsEdgeType)
|
||||||
|
),
|
||||||
};
|
};
|
||||||
expect(combineWeights([weights1, weights2])).toEqual(defaultWeights());
|
expect(combineWeights([weights1, weights2])).toEqual(defaultWeights());
|
||||||
});
|
});
|
||||||
|
@ -62,20 +78,26 @@ describe("app/credExplorer/weights/weights", () => {
|
||||||
});
|
});
|
||||||
it("errors on duplicate edge prefix", () => {
|
it("errors on duplicate edge prefix", () => {
|
||||||
const weights = {
|
const weights = {
|
||||||
nodes: [],
|
nodes: new Map(),
|
||||||
edges: [defaultWeightedEdgeType(assemblesEdgeType)],
|
edges: new Map().set(
|
||||||
|
assemblesEdgeType.prefix,
|
||||||
|
defaultWeightedEdgeType(assemblesEdgeType)
|
||||||
|
),
|
||||||
};
|
};
|
||||||
expect(() => combineWeights([weights, weights])).toThrowError(
|
expect(() => combineWeights([weights, weights])).toThrowError(
|
||||||
"Duplicate prefix"
|
"duplicate key"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("errors on duplicate node prefix", () => {
|
it("errors on duplicate node prefix", () => {
|
||||||
const weights = {
|
const weights = {
|
||||||
nodes: [defaultWeightedNodeType(inserterNodeType)],
|
nodes: new Map().set(
|
||||||
edges: [],
|
inserterNodeType.prefix,
|
||||||
|
defaultWeightedNodeType(inserterNodeType)
|
||||||
|
),
|
||||||
|
edges: new Map(),
|
||||||
};
|
};
|
||||||
expect(() => combineWeights([weights, weights])).toThrowError(
|
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 {
|
export function weightsToEdgeEvaluator(weights: WeightedTypes): EdgeEvaluator {
|
||||||
const nodeTrie = new NodeTrie();
|
const nodeTrie = new NodeTrie();
|
||||||
for (const {type, weight} of weights.nodes) {
|
for (const {type, weight} of weights.nodes.values()) {
|
||||||
nodeTrie.add(type.prefix, weight);
|
nodeTrie.add(type.prefix, weight);
|
||||||
}
|
}
|
||||||
const edgeTrie = new EdgeTrie();
|
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});
|
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(machine, 1), type: machineNodeType},
|
||||||
{weight: NullUtil.orElse(baseNode, 1), type: fallbackNodeType},
|
{weight: NullUtil.orElse(baseNode, 1), type: fallbackNodeType},
|
||||||
];
|
];
|
||||||
|
const nodesMap = new Map(nodes.map((x) => [x.type.prefix, x]));
|
||||||
const edges = [
|
const edges = [
|
||||||
{
|
{
|
||||||
forwardWeight: NullUtil.orElse(assemblesForward, 1),
|
forwardWeight: NullUtil.orElse(assemblesForward, 1),
|
||||||
|
@ -50,7 +51,8 @@ describe("app/credExplorer/weights/weightsToEdgeEvaluator", () => {
|
||||||
type: fallbackEdgeType,
|
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) {
|
function exampleEdgeWeights(weightArgs: WeightArgs) {
|
||||||
const ws = weights(weightArgs);
|
const ws = weights(weightArgs);
|
||||||
|
|
Loading…
Reference in New Issue