UNPKG

@abaplint/core

Version:
154 lines 4.82 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FlowGraph = exports.FLOW_EDGE_TYPE = void 0; var FLOW_EDGE_TYPE; (function (FLOW_EDGE_TYPE) { FLOW_EDGE_TYPE["true"] = "true"; FLOW_EDGE_TYPE["false"] = "false"; FLOW_EDGE_TYPE["undefined"] = "undefined"; })(FLOW_EDGE_TYPE || (exports.FLOW_EDGE_TYPE = FLOW_EDGE_TYPE = {})); class FlowGraph { constructor(counter) { this.edges = {}; this.label = "undefined"; this.startNode = "start#" + counter; this.endNode = "end#" + counter; } getStart() { return this.startNode; } getLabel() { return this.label; } getEnd() { return this.endNode; } addEdge(from, to, type) { if (this.edges[from] === undefined) { this.edges[from] = {}; } this.edges[from][to] = type; } removeEdge(from, to) { if (this.edges[from] === undefined) { return; } delete this.edges[from][to]; if (Object.keys(this.edges[from]).length === 0) { delete this.edges[from]; } } listEdges() { const list = []; for (const from of Object.keys(this.edges)) { for (const to of Object.keys(this.edges[from])) { list.push({ from, to, type: this.edges[from][to] }); } } return list; } listNodes() { const set = new Set(); for (const l of this.listEdges()) { set.add(l.from); set.add(l.to); } return Array.from(set.values()); } hasEdges() { return Object.keys(this.edges).length > 0; } /** return value: end node of to graph */ addGraph(from, to, type) { if (to.hasEdges() === false) { return from; } this.addEdge(from, to.getStart(), type); to.listEdges().forEach(e => this.addEdge(e.from, e.to, e.type)); return to.getEnd(); } toJSON() { return JSON.stringify(this.edges); } toTextEdges() { let graph = ""; for (const l of this.listEdges()) { const label = l.type === FLOW_EDGE_TYPE.undefined ? "" : ` [label="${l.type}"]`; graph += `"${l.from}" -> "${l.to}"${label};\n`; } return graph.trim(); } setLabel(label) { this.label = label; } toDigraph() { return `digraph G { labelloc="t"; label="${this.label}"; graph [fontname = "helvetica"]; node [fontname = "helvetica", shape="box"]; edge [fontname = "helvetica"]; ${this.toTextEdges()} }`; } listSources(node) { const set = []; for (const l of this.listEdges()) { if (node === l.to) { set.push({ name: l.from, type: l.type }); } } return set; } listTargets(node) { const set = []; for (const l of this.listEdges()) { if (node === l.from) { set.push({ name: l.to, type: l.type }); } } return set; } /** removes all nodes containing "#" that have one in-going and one out-going edge */ reduce() { for (const node of this.listNodes()) { if (node.includes("#") === false) { continue; } const sources = this.listSources(node); const targets = this.listTargets(node); if (sources.length > 0 && targets.length > 0) { // hash node in the middle of the graph for (const s of sources) { this.removeEdge(s.name, node); } for (const t of targets) { this.removeEdge(node, t.name); } for (const s of sources) { for (const t of targets) { let type = FLOW_EDGE_TYPE.undefined; if (s.type !== FLOW_EDGE_TYPE.undefined) { type = s.type; } if (t.type !== FLOW_EDGE_TYPE.undefined) { if (type !== FLOW_EDGE_TYPE.undefined) { throw new Error("reduce: cannot merge, different edge types"); } type = t.type; } this.addEdge(s.name, t.name, type); } } } if (node.startsWith("end#") && sources.length === 0) { for (const t of targets) { this.removeEdge(node, t.name); } } } return this; } } exports.FlowGraph = FlowGraph; //# sourceMappingURL=flow_graph.js.map