You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

191 lines
5.8 KiB

(function() {
"use strict";
var lib$dag$map$platform$$platform;
/* global self */
if (typeof self === 'object') {
lib$dag$map$platform$$platform = self;
/* global global */
} else if (typeof global === 'object') {
lib$dag$map$platform$$platform = global;
} else {
throw new Error('no global: `self` or `global` found');
}
var lib$dag$map$platform$$default = lib$dag$map$platform$$platform;
function lib$vertex$$Vertex(name) {
this.name = name;
this.incoming = {};
this.incomingNames = [];
this.hasOutgoing = false;
this.value = null;
}
var lib$vertex$$default = lib$vertex$$Vertex;
function lib$visit$$visit(vertex, fn, visited, path) {
var name = vertex.name;
var vertices = vertex.incoming;
var names = vertex.incomingNames;
var len = names.length;
var i;
if (!visited) {
visited = {};
}
if (!path) {
path = [];
}
if (visited.hasOwnProperty(name)) {
return;
}
path.push(name);
visited[name] = true;
for (i = 0; i < len; i++) {
lib$visit$$visit(vertices[names[i]], fn, visited, path);
}
fn(vertex, path);
path.pop();
}
var lib$visit$$default = lib$visit$$visit;
function lib$dag$map$$DAG() {
this.names = [];
this.vertices = Object.create(null);
}
var lib$dag$map$$default = lib$dag$map$$DAG;
/**
* Adds a vertex entry to the graph unless it is already added.
*
* @private
* @method add
* @param {String} name The name of the vertex to add
*/
lib$dag$map$$DAG.prototype.add = function(name) {
if (!name) {
throw new Error("Can't add Vertex without name");
}
if (this.vertices[name] !== undefined) {
return this.vertices[name];
}
var vertex = new lib$vertex$$default(name);
this.vertices[name] = vertex;
this.names.push(name);
return vertex;
};
/**
* Adds a vertex to the graph and sets its value.
*
* @private
* @method map
* @param {String} name The name of the vertex.
* @param value The value to put in the vertex.
*/
lib$dag$map$$DAG.prototype.map = function(name, value) {
this.add(name).value = value;
};
/**
* Connects the vertices with the given names, adding them to the graph if
* necessary, only if this does not produce is any circular dependency.
*
* @private
* @method addEdge
* @param {String} fromName The name the vertex where the edge starts.
* @param {String} toName The name the vertex where the edge ends.
*/
lib$dag$map$$DAG.prototype.addEdge = function(fromName, toName) {
if (!fromName || !toName || fromName === toName) {
return;
}
var from = this.add(fromName);
var to = this.add(toName);
if (to.incoming.hasOwnProperty(fromName)) {
return;
}
function checkCycle(vertex, path) {
if (vertex.name === toName) {
throw new Error("cycle detected: " + toName + " <- " + path.join(" <- "));
}
}
lib$visit$$default(from, checkCycle);
from.hasOutgoing = true;
to.incoming[fromName] = from;
to.incomingNames.push(fromName);
};
/**
* Visits all the vertex of the graph calling the given function with each one,
* ensuring that the vertices are visited respecting their precedence.
*
* @method topsort
* @param {Function} fn The function to be invoked on each vertex.
*/
lib$dag$map$$DAG.prototype.topsort = function(fn) {
var visited = {};
var vertices = this.vertices;
var names = this.names;
var len = names.length;
var i, vertex;
for (i = 0; i < len; i++) {
vertex = vertices[names[i]];
if (!vertex.hasOutgoing) {
lib$visit$$default(vertex, fn, visited);
}
}
};
/**
* Adds a vertex with the given name and value to the graph and joins it with the
* vertices referenced in _before_ and _after_. If there isn't vertices with those
* names, they are added too.
*
* If either _before_ or _after_ are falsy/empty, the added vertex will not have
* an incoming/outgoing edge.
*
* @method addEdges
* @param {String} name The name of the vertex to be added.
* @param value The value of that vertex.
* @param before An string or array of strings with the names of the vertices before
* which this vertex must be visited.
* @param after An string or array of strings with the names of the vertex after
* which this vertex must be visited.
*
*/
lib$dag$map$$DAG.prototype.addEdges = function(name, value, before, after) {
var i;
this.map(name, value);
if (before) {
if (typeof before === 'string') {
this.addEdge(name, before);
} else {
for (i = 0; i < before.length; i++) {
this.addEdge(name, before[i]);
}
}
}
if (after) {
if (typeof after === 'string') {
this.addEdge(after, name);
} else {
for (i = 0; i < after.length; i++) {
this.addEdge(after[i], name);
}
}
}
};
/* global define:true module:true window: true */
if (typeof define === 'function' && define.amd) {
define(function() { return lib$dag$map$$default; });
} else if (typeof module !== 'undefined' && module.exports) {
module.exports = lib$dag$map$$default;
} else if (typeof lib$dag$map$platform$$default !== 'undefined') {
lib$dag$map$platform$$default['DAG'] = lib$dag$map$$default;
}
}).call(this);
//# sourceMappingURL=dag-map.js.map