123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- !function() {
- "use strict";
- /**
- * Topological sort class.
- * Original by Marcel Klehr, contributed by Gustavo Henke.
- *
- * @class
- * @since 0.1.0
- * @see https://github.com/marcelklehr/toposort
- * @author Marcel Klehr <mklehr@gmx.net>
- *
- * @see https://github.com/gustavohenke/toposort
- * @author Gustavo Henke <gustavo@injoin.com.br>
- */
- function Toposort() {
- var self = this;
- var edges = [];
- /**
- * Adds dependency edges.
- *
- * @since 0.1.0
- * @param {String} item An dependent name. Must be an string and not empty
- * @param {String[]|String} [deps] An dependency or array of dependencies
- * @returns {Toposort} The Toposort instance
- */
- self.add = function( item, deps ) {
- if( typeof item !== "string" || !item ) {
- throw new TypeError( "Dependent name must be given as a not empty string" );
- }
- deps = Array.isArray( deps ) ? deps.slice() : [deps];
- if( deps.length ) {
- deps.forEach( function( dep ) {
- if( typeof dep !== "string" || !dep ) {
- throw new TypeError(
- "Dependency name must be given as a not empty string"
- );
- }
- edges.push( [item, dep] );
- } );
- } else {
- edges.push( [item] );
- }
- return self;
- };
- /**
- * Runs the toposorting and return an ordered array of strings
- *
- * @since 0.1.0
- * @returns {String[]} The list of items topologically sorted.
- */
- self.sort = function() {
- var nodes = [];
- var sorted = [];
- edges.forEach( function( edge ) {
- edge.forEach( function( n ) {
- if( nodes.indexOf( n ) === -1 ) {
- nodes.push( n );
- }
- } );
- } );
- function visit( node, predecessors, i ) {
- var index, predsCopy;
- predecessors = predecessors || [];
- if( predecessors.indexOf( node ) > -1 ) {
- throw new Error(
- "Cyclic dependency found. '" + node + "' is dependent of itself.\n" +
- "Dependency Chain: " + predecessors.join( " -> " ) + " => " + node
- );
- }
- index = nodes.indexOf( node );
- if( index === -1 ) {
- return i;
- }
- nodes.splice( index, 1 );
- if( predecessors.length === 0 ) {
- i--;
- }
- predsCopy = predecessors.slice();
- predsCopy.push( node );
- edges.filter( function( e ) {
- return e[0] === node;
- } ).forEach( function( e ) {
- i = visit( e[1], predsCopy, i );
- } );
- sorted.unshift( node );
- return i;
- }
- for( var i = 0; i < nodes.length; i++ ) {
- i = visit( nodes[i], null, i );
- }
- return sorted;
- };
- }
- if( typeof module === "object" && module && typeof module.exports === "object" ) {
- // Expose toposort to CommonJS loaders (aka Node)
- module.exports = exports.Toposort = Toposort;
- } else {
- // Expose toposort to AMD loaders (aka Require.js)
- if( typeof define === "function" && define.amd ) {
- define( function() {
- return Toposort;
- } );
- }
- // Expose toposort as a browser global
- if( typeof window === "object" ) {
- window.Toposort = Toposort;
- }
- }
- }();
|