@specs-feup/lara
Version:
A js port of the popular framework for building source-to-source compilers
85 lines • 3.5 kB
JavaScript
import DotFormatter from "./DotFormatter.js";
import EdgeData from "./EdgeData.js";
import NodeData from "./NodeData.js";
import cytoscape from "../../libs/cytoscape-3.26.0.js";
/**
* Utility class related with graph creation and manipulation.
*
* Current implementation uses Cytoscape.js (https://js.cytoscape.org/)
*/
export default class Graphs {
/**
* @param config - Configuration for the graph, according to what Cytoscape accepts as configuration object
*/
static newGraph(config = {}) {
return cytoscape(config);
}
/**
* @deprecated Does nothing. Cytoscape should be loaded by the user.
*/
static loadLibrary() { }
static addNode(graph, nodeData) {
if (!(nodeData instanceof NodeData)) {
nodeData = Object.assign(new NodeData(), nodeData);
}
return graph.add({ group: "nodes", data: nodeData });
}
static addEdge(graph, sourceNode, targetNode, edgeData) {
if (!(edgeData instanceof EdgeData)) {
edgeData = Object.assign(new EdgeData(), edgeData);
}
edgeData.source = sourceNode.id();
edgeData.target = targetNode.id();
return graph.add({ group: "edges", data: edgeData });
}
static toDot(graph, dotFormatter = new DotFormatter()) {
let dot = "digraph test {\n";
// Declare nodes
for (const node of graph.nodes()) {
dot += `"${node.id()}" [label="${dotFormatter.getNodeLabel(node)}" shape=box`;
// Add node attributes
const nodeAttrs = dotFormatter.getNodeAttributes(node);
dot += nodeAttrs.length === 0 ? "" : " " + nodeAttrs;
dot += "];\n";
}
for (const edge of graph.edges()) {
const edgeData = edge.data();
dot += `"${edgeData.source}" -> "${edgeData.target}" [label="${dotFormatter.getEdgeLabel(edge)}"`;
// Get edge attributes
const edgeAttrs = dotFormatter.getEdgeAttributes(edge);
dot += edgeAttrs.length === 0 ? "" : " " + edgeAttrs;
dot += "];\n";
}
dot += "}\n";
return dot;
}
/**
* @returns True if the outdegree (number of edges with this node as source) is zero, false otherwise. By default, if a node has a connection to itself (loop) it is not considered a leaf
*/
static isLeaf(node, loopsAreLeafs = false) {
const includeLoops = !loopsAreLeafs;
return node.outdegree(includeLoops) === 0;
}
/**
* Removes a node from the graph. Before removing the node, creates connections between all connecting sources and targets.
*
* @param graph -
* @param node -
* @param edgeMap - function that receives the incoming edge and the outgoing edge, and returns a new EdgeData that replaces both edges
*/
static removeNode(graph, node, edgeMapper) {
// Get edges of node
const edges = node.connectedEdges();
const incomingEdges = edges.filter((edge) => edge.target() === node);
const outgoingEdges = edges.filter((edge) => edge.source() === node);
for (const incoming of incomingEdges) {
for (const outgoing of outgoingEdges) {
const newEdgeData = edgeMapper(incoming, outgoing);
Graphs.addEdge(graph, incoming.source(), outgoing.target(), newEdgeData);
}
}
// Remove node
node.remove();
}
}
//# sourceMappingURL=Graphs.js.map