UNPKG

async-dependency-graph

Version:

A dependency graph that can traverse asynchronous nodes.

274 lines 20.1 kB
"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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