UNPKG

@specs-feup/lara

Version:

A js port of the popular framework for building source-to-source compilers

85 lines 3.5 kB
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