import { Set } from "."; export class Graph { private outgoing = new Map>(); private incoming = new Map>(); private _nodes: Set; constructor(private getIdentifier: (item: T) => string) { this._nodes = new Set(getIdentifier); } public addEdge(fromNode: T, toNode: T) { this._nodes.add(fromNode); this._nodes.add(toNode); if (!this.outgoing.has(fromNode)) { this.outgoing.set(fromNode, new Set(this.getIdentifier)); } if (!this.incoming.has(toNode)) { this.incoming.set(toNode, new Set(this.getIdentifier)); } this.outgoing.get(fromNode).add(toNode); this.incoming.get(toNode).add(fromNode); } // tslint:disable-next-line: prefer-array-literal public get nodes() { return this._nodes.items; } public topoSort(): T[] { const sorted: T[] = []; const work = new Set(this.getIdentifier, ...this.nodes.filter(n => !this.incoming.has(n))); while (!work.empty) { const n = work.pop(); sorted.push(n); if (this.outgoing.has(n)) { this.outgoing.get(n).items.forEach(m => { this.outgoing.get(n).remove(m); this.incoming.get(m).remove(n); if (this.incoming.get(m).empty) { work.add(m); } }); } } return sorted; } }