dao-governance-framework/forum-network/src/classes/wdag.js

153 lines
4.1 KiB
JavaScript

export class Vertex {
constructor(id, data) {
this.id = id;
this.data = data;
this.edges = {
from: [],
to: [],
};
}
getEdges(label, away) {
return this.edges[away ? 'from' : 'to'].filter(
(edge) => edge.label === label,
);
}
}
export class Edge {
constructor(label, from, to, weight) {
this.from = from;
this.to = to;
this.label = label;
this.weight = weight;
}
}
export class WDAG {
constructor(scene) {
this.scene = scene;
this.vertices = new Map();
this.edgeLabels = new Map();
this.nextVertexId = 0;
this.flowchart = scene?.flowchart ?? null;
}
withFlowchart() {
this.scene.withAdditionalFlowchart();
this.flowchart = this.scene.lastFlowchart();
return this;
}
addVertex(id, data, label) {
// Support simple case of auto-incremented numeric ids
if (typeof id === 'object') {
data = id;
id = this.nextVertexId++;
}
if (this.vertices.has(id)) {
throw new Error(`Vertex already exists with id: ${id}`);
}
const vertex = new Vertex(id, data);
this.vertices.set(id, vertex);
this.flowchart?.log(`${id}[${label ?? id}]`);
return this;
}
setVertexLabel(id, label) {
this.flowchart?.log(`${id}[${label}]`);
}
getVertex(id) {
return this.vertices.get(id);
}
getVertexData(id) {
return this.getVertex(id)?.data;
}
getVerticesData() {
return Array.from(this.vertices.values()).map(({ data }) => data);
}
static getEdgeKey({ from, to }) {
return btoa([from.id, to.id]).replaceAll(/[^A-Z]+/g, '');
}
getEdge(label, from, to) {
from = from instanceof Vertex ? from : this.getVertex(from);
to = to instanceof Vertex ? to : this.getVertex(to);
if (!from || !to) {
return undefined;
}
const edges = this.edgeLabels.get(label);
const edgeKey = WDAG.getEdgeKey({ from, to });
return edges?.get(edgeKey);
}
getEdgeWeight(label, from, to) {
return this.getEdge(label, from, to)?.weight;
}
getEdgeHtml({ from, to }) {
let html = '<table>';
for (const { label, weight } of this.getEdges(null, from, to)) {
html += `<tr><td>${label}</td><td>${weight}</td></tr>`;
}
html += '</table>';
return html;
}
getEdgeFlowchartNode(edge) {
const edgeKey = WDAG.getEdgeKey(edge);
return `${edgeKey}(${this.getEdgeHtml(edge)})`;
}
setEdgeWeight(label, from, to, weight) {
from = from instanceof Vertex ? from : this.getVertex(from);
to = to instanceof Vertex ? to : this.getVertex(to);
const edge = new Edge(label, from, to, weight);
let edges = this.edgeLabels.get(label);
if (!edges) {
edges = new Map();
this.edgeLabels.set(label, edges);
}
const edgeKey = WDAG.getEdgeKey(edge);
edges.set(edgeKey, edge);
this.flowchart?.log(this.getEdgeFlowchartNode(edge));
return edge;
}
addEdge(label, from, to, weight) {
from = from instanceof Vertex ? from : this.getVertex(from);
to = to instanceof Vertex ? to : this.getVertex(to);
if (this.getEdge(label, from, to)) {
throw new Error(`Edge ${label} from ${from} to ${to} already exists`);
}
const edge = this.setEdgeWeight(label, from, to, weight);
from.edges.from.push(edge);
to.edges.to.push(edge);
this.flowchart?.log(`${from.id} --- ${this.getEdgeFlowchartNode(edge)} --> ${to.id}`);
this.flowchart?.log(`class ${WDAG.getEdgeKey(edge)} edge`);
return this;
}
getEdges(label, from, to) {
from = from instanceof Vertex ? from : this.getVertex(from);
to = to instanceof Vertex ? to : this.getVertex(to);
const edgeLabels = label ? [label] : Array.from(this.edgeLabels.keys());
return edgeLabels.flatMap((edgeLabel) => {
const edges = this.edgeLabels.get(edgeLabel);
return Array.from(edges?.values() || []).filter((edge) => {
const matchFrom = from === null || from === undefined || from === edge.from;
const matchTo = to === null || to === undefined || to === edge.to;
return matchFrom && matchTo;
});
});
}
countVertices() {
return this.vertices.size;
}
}