async-dependency-graph
Version:
A dependency graph that can traverse asynchronous nodes.
274 lines • 20.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Node = exports.Graph = void 0;
var mutex_1 = require("./mutex");
/**
* Base dependency graph class.
*/
var Graph = /** @class */ (function () {
function Graph() {
this.nodes = {};
this.outgoingEdges = {};
this.incomingEdges = {};
}
/**
* Add a node to the graph.
* @param node Node object.
*/
Graph.prototype.addNode = function (node) {
if (this.hasNode(node.name))
throw new Error("A node with the name of \"" + node.name + "\" already exists in the graph!");
this.nodes[node.name] = node;
this.outgoingEdges[node.name] = [];
this.incomingEdges[node.name] = [];
};
/**
* Remove a node by name from the graph.
* @param name Node name.
*/
Graph.prototype.removeNode = function (name) {
if (!this.hasNode(name))
throw new Error("A node with the name of \"" + name + "\" does not exist in the graph!");
delete this.nodes[name];
delete this.outgoingEdges[name];
delete this.incomingEdges[name];
for (var dependent in this.incomingEdges) {
if (this.incomingEdges[dependent].includes(name))
this.incomingEdges[dependent].splice(dependent.indexOf(name), 1);
}
for (var dependency in this.outgoingEdges) {
if (this.outgoingEdges[dependency].includes(name))
this.outgoingEdges[dependency].splice(dependency.indexOf(name), 1);
}
};
/**
* Checks to see if the graph contains a Node by name.
* @param name Node name.
*/
Graph.prototype.hasNode = function (name) {
return this.nodes.hasOwnProperty(name);
};
Object.defineProperty(Graph.prototype, "size", {
/**
* Returns the number of nodes in a graph.
*/
get: function () {
return Object.keys(this.nodes).length;
},
enumerable: false,
configurable: true
});
/**
* Returns the Node instance given a node name.
* @param name Node name.
*/
Graph.prototype.getNode = function (name) {
if (this.hasNode(name))
return this.nodes[name];
throw new Error("Node \"" + name + "\" not found!");
};
/**
* Adds a node dependence. "from" is dependent on "to"
* @param from Node name.
* @param to Node name.
*/
Graph.prototype.addDependency = function (from, to) {
if (!this.hasNode(from))
throw new Error("Node does not exist: " + from);
if (!this.hasNode(to))
throw new Error("Node does not exist: " + to);
if (from === to)
throw new Error("Cannot add self dependency: " + to);
if (!this.outgoingEdges[from].includes(to)) {
this.outgoingEdges[from].push(to);
}
if (!this.incomingEdges[to].includes(from)) {
this.incomingEdges[to].push(from);
}
};
/**
* Removes a node dependence. "from" is no longer dependent on "to".
* @param from Node name.
* @param to Node name.
* @todo Test this function.
*/
Graph.prototype.removeDependency = function (from, to) {
console.warn('removeDependency() has not been tested.');
if (!this.hasNode(from))
throw new Error("Node does not exist: " + from);
if (!this.hasNode(to))
throw new Error("Node does not exist: " + to);
if (from === to)
throw new Error("Cannot remove self dependency: " + to);
if (!this.outgoingEdges[from].includes(to)) {
this.outgoingEdges[from].splice(this.outgoingEdges[from].indexOf(to), 1);
}
if (!this.incomingEdges[to].includes(from)) {
this.incomingEdges[to].splice(this.incomingEdges[to].indexOf(to), 1);
}
};
/**
* Get dependency node names for a Node by name. (Required nodes for this node to execute).
* @param name Node name.
*/
Graph.prototype.dependenciesOf = function (name) {
return this.outgoingEdges[name];
};
/**
* Get dependents node names for a Node by name. (Nodes that require this node to complete).
* @param name Node name.
*/
Graph.prototype.dependentsOf = function (name) {
return this.incomingEdges[name];
};
/**
* Breadth first search.
*/
Graph.prototype.traverse = function () {
var _this = this;
// Clear all complete node mutexes.
Object.keys(this.nodes).map(function (name) { return _this.getNode(name).clearMutex(); });
// Visiting a node recursively calls visit on each node's dependents.
var visit = function (node) {
// First await all dependencies
return Promise.all(_this.dependenciesOf(node.name).map(function (dependencyName) { return _this.nodes[dependencyName].awaitData(); }))
.then(function () {
node.signalDependenciesReady();
if (_this.dependentsOf(node.name).length > 0) {
// Then recursively visit all dependents
return Promise.all(_this.dependentsOf(node.name).map(function (dependentName) { return visit(_this.getNode(dependentName)); }));
}
else {
// node has no dependents so await data
return node.awaitData();
}
});
};
// Find nodes with no dependencies
var rootNodeNames = Object.keys(this.nodes).filter(function (name) { return _this.dependenciesOf(name).length === 0; });
if (rootNodeNames.length === 0 && Object.keys(this.nodes).length > 0)
return Promise.reject(new Error('The graph is circular. Cannot traverse graph due to no root node.'));
// Start recursive traversal from root nodes.
return Promise.all(rootNodeNames.map(function (name) { return visit(_this.nodes[name]); }));
};
/**
* Clears the value of a node and the values of dependent nodes
* @param name Node name.
*/
Graph.prototype.clearNodeAndDependents = function (name) {
var _this = this;
var node = this.getNode(name);
var visitAndClear = function (node) {
if (node.hasData()) {
node.clearData();
return Promise.all(_this.dependentsOf(node.name).map(function (dependentName) { return visitAndClear(_this.getNode(dependentName)); }));
}
else {
return Promise.resolve();
}
};
return visitAndClear(node);
};
/**
* Resets the graph by resetting each node in the graph.
*/
Graph.prototype.reset = function () {
for (var name in this.nodes) {
this.nodes[name].reset();
}
};
/**
* Prints graph nodes and node dependents.
*/
Graph.prototype.ls = function () {
for (var name in this.nodes) {
console.log(name);
console.log(this.dependentsOf(name));
}
};
return Graph;
}());
exports.Graph = Graph;
var Node = /** @class */ (function () {
function Node(name, promise) {
this.locked = false;
this._name = name;
this._promise = promise;
}
Object.defineProperty(Node.prototype, "name", {
get: function () {
return this._name;
},
enumerable: false,
configurable: true
});
/**
* Await data.
* @returns A `Promise<T | null>` that resolves when the node's data is ready.
*/
Node.prototype.awaitData = function () {
var _this = this;
if (!this.mutex) {
this.mutex = new mutex_1.Mutex(function () { return _this._data !== undefined; });
}
return new Promise(function (resolve, reject) {
_this.mutex.await(function (error) {
if (error)
return reject(error);
resolve(_this._data);
});
});
};
Node.prototype.signalDependenciesReady = function () {
var _this = this;
if (!this.mutex) {
this.mutex = new mutex_1.Mutex(function () { return _this._data !== undefined; });
}
if (this._data === undefined) {
// Only allow to _promise once
if (this.locked === true)
return;
this.locked = true;
var promise = this._promise();
if (promise === undefined)
throw new Error("Node \"" + this._name + "\" has undefined promise.");
promise.then(function (data) {
_this._data = data;
_this.locked = false;
_this.mutex.ready();
}).catch(function (error) {
_this._data = null;
_this.locked = false;
_this.mutex.ready(error);
});
}
else {
// Allow _data to be set externally from promise
this.mutex.ready();
}
};
Node.prototype.setData = function (data) {
this._data = data;
this.signalDependenciesReady();
};
/**
* Resets node. Clears all node data and resets its mutex.
*/
Node.prototype.reset = function () {
this.clearData();
this.clearMutex();
};
Node.prototype.clearMutex = function () {
if (this.hasData())
this.mutex = undefined;
};
Node.prototype.hasData = function () {
return this._data !== undefined;
};
Node.prototype.clearData = function () {
this._data = undefined;
};
return Node;
}());
exports.Node = Node;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JhcGguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZ3JhcGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaUNBQWdDO0FBRWhDOztHQUVHO0FBQ0g7SUFBQTtRQUNZLFVBQUssR0FBNkIsRUFBRSxDQUFDO1FBQ3JDLGtCQUFhLEdBQWlDLEVBQUUsQ0FBQztRQUNqRCxrQkFBYSxHQUFpQyxFQUFFLENBQUM7SUFpTDdELENBQUM7SUEvS0c7OztPQUdHO0lBQ0ksdUJBQU8sR0FBZCxVQUFlLElBQVU7UUFDckIsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLCtCQUE0QixJQUFJLENBQUMsSUFBSSxvQ0FBZ0MsQ0FBQyxDQUFDO1FBQ3BILElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQztRQUM3QixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDbkMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ3ZDLENBQUM7SUFFRDs7O09BR0c7SUFDSSwwQkFBVSxHQUFqQixVQUFrQixJQUFZO1FBQzFCLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQztZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsK0JBQTRCLElBQUksb0NBQWdDLENBQUMsQ0FBQztRQUMzRyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDeEIsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNoQyxLQUFLLElBQU0sU0FBUyxJQUFJLElBQUksQ0FBQyxhQUFhLEVB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