import assert = require ( 'assert' ) ; import { AbstractGraph } from './abstractGraph' ; import { FindCycles } from './DFSLib' ; import { Node , NodeGroup , NodeImpl , ScalarNode } from './Nodedefs' ; export class ComponentGraph extends AbstractGraph { private _groupMap : Map < ScalarNode , NodeGroup > = new Map < ScalarNode , NodeGroup > ( ) ; public removeCycles ( ) { let remover ; let cycles ; do { remover = new FindCycles ( this ) ; remover . run ( ) ; cycles = remover . cycles ; for ( const backEdge of cycles ) { if ( backEdge [ 1 ] ) { const src = this . getNode ( backEdge [ 0 ] . name ) ; const dst = this . getNode ( backEdge [ 1 ] . name ) ; if ( src && dst ) { this . combineNodes ( src , dst ) ; } } } } while ( cycles . length > 0 ) ; } public getEdges ( node ) { const edges = new Set < Node > ( ) ; ( node as NodeImpl ) . getAdjacency ( ) . forEach ( elt => { let mapped ; if ( elt instanceof ScalarNode ) { mapped = this . _groupMap . get ( elt ) ; } edges . add ( mapped ? mapped : elt ) ; } ) ; if ( node instanceof ScalarNode ) { edges . delete ( this . _groupMap . get ( node ) ) ; } return edges . values ( ) ; } public combineNodes ( node1 , node2 ) { assert . ok ( this . nodesMap . has ( node1 . name ) , node1 . name + ' doesn\'t exist' ) ; assert . ok ( this . nodesMap . has ( node2 . name ) , node2 . name + ' doesn\'t exist' ) ; if ( node1 === node2 ) { return ; } this . nodesMap . delete ( node1 . name ) ; this . nodesMap . delete ( node2 . name ) ; const ng = ( node1 as NodeImpl ) . combineWith ( node2 as NodeImpl ) ; if ( node1 instanceof ScalarNode ) { this . _groupMap . set ( node1 , ng ) ; } if ( node2 instanceof ScalarNode ) { this . _groupMap . set ( node2 , ng ) ; } this . nodesMap . set ( ng . name , ng ) ; return ng ; } }