This commit is contained in:
Tutur33
2023-11-24 22:35:41 +01:00
parent 3c0b507a93
commit 7644b2a0f7
45165 changed files with 4803356 additions and 3 deletions
+20
View File
@@ -0,0 +1,20 @@
Copyright (c) 2014 Kris Selden and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+48
View File
@@ -0,0 +1,48 @@
# dag-map [![Build Status](https://travis-ci.org/krisselden/dag-map.png?branch=master)](https://travis-ci.org/krisselden/dag-map)
A [directed acyclic graph](http://en.wikipedia.org/wiki/Directed_acyclic_graph) library for JavaScript.
In addition to being a DAG implmentation, it also provides value storage on the
vertices. So in-short, it is a key/value DAG.
## Downloads
## API
```js
// create a new draph;
var graph = new DAG();
// add some nodes
graph.add('foo');
graph.add('bar');
graph.add('baz');
// currently, no edges exist between these nodes, so lets add some
graph.addEdge('foo', 'bar');
// we now have an edge from 'foo' -> 'bar';
graph.addEdge('bar', 'baz');
// we now have an edge from 'foo' -> 'bar' -> 'baz';
// to have the graph calculate this topSort for us, we can use the topSort
// iterator, to build an ordered
var vertices = [];
graph.topsort(function(vertex, path){
vertices.push(vertex.name);
});
vertices === [ 'foo', 'bar', 'baz' ];
```
## Developing
* `npm install`
* `npm test` runs the tests headless
* `npm run test:server` runs the tests and the development server
* `npm build` builds the development dist
* `npm build:production` builds the production dist
+191
View File
@@ -0,0 +1,191 @@
(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
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
(function(){"use strict";var lib$dag$map$platform$$platform;if(typeof self==="object"){lib$dag$map$platform$$platform=self}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;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};lib$dag$map$$DAG.prototype.map=function(name,value){this.add(name).value=value};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)};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)}}};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)}}}};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);
File diff suppressed because one or more lines are too long
+139
View File
@@ -0,0 +1,139 @@
import Vertex from './vertex';
import visit from './visit';
/**
* DAG stands for Directed acyclic graph.
*
* It is used to build a graph of dependencies checking that there isn't circular
* dependencies. p.e Registering initializers with a certain precedence order.
*
* @class DAG
* @constructor
*/
export default function DAG() {
this.names = [];
this.vertices = Object.create(null);
}
/**
* 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
*/
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 Vertex(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.
*/
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.
*/
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(" <- "));
}
}
visit(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.
*/
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) {
visit(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.
*
*/
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);
}
}
}
};
+11
View File
@@ -0,0 +1,11 @@
import platform from './dag-map/platform';
import DAG from './dag-map';
/* global define:true module:true window: true */
if (typeof define === 'function' && define.amd) {
define(function() { return DAG; });
} else if (typeof module !== 'undefined' && module.exports) {
module.exports = DAG;
} else if (typeof platform !== 'undefined') {
platform['DAG'] = DAG;
}
+14
View File
@@ -0,0 +1,14 @@
var platform;
/* global self */
if (typeof self === 'object') {
platform = self;
/* global global */
} else if (typeof global === 'object') {
platform = global;
} else {
throw new Error('no global: `self` or `global` found');
}
export default platform;
+15
View File
@@ -0,0 +1,15 @@
/**
* DAG Vertex
*
* @class Vertex
* @constructor
*/
export default function Vertex(name) {
this.name = name;
this.incoming = {};
this.incomingNames = [];
this.hasOutgoing = false;
this.value = null;
}
+25
View File
@@ -0,0 +1,25 @@
export default function 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++) {
visit(vertices[names[i]], fn, visited, path);
}
fn(vertex, path);
path.pop();
}
+28
View File
@@ -0,0 +1,28 @@
{
"name": "dag-map",
"version": "1.0.2",
"description": "DAG stands for Directed acyclic graph. It is used to build a graph of dependencies checking that there isn't circular dependencies",
"main": "dist/dag-map.js",
"repository": {
"type": "git",
"url": "https://github.com/krisselden/dag-map.git"
},
"scripts": {
"build": "ember build",
"build:production": "ember build --environment=production",
"test": "ember test",
"test:server": "ember test --server",
"prepublish": "ember build --environment production"
},
"author": "Kris Selden",
"license": "MIT",
"readmeFilename": "README.md",
"devDependencies": {
"broccoli-es6-module-transpiler": "^0.5.0",
"broccoli-stew": "^0.2.1",
"broccoli-uglify-js": "^0.1.3",
"ember-cli": "^0.2.0",
"es6-module-transpiler-amd-formatter": "^0.3.0",
"qunitjs": "^1.17.1"
}
}