ngraph.graph
Advanced tools
Comparing version 19.1.0 to 20.0.0
@@ -25,3 +25,3 @@ /** | ||
dfs(graph, node.id, otherNode => { | ||
let componentId = nodeIdToComponentId.get(otherNode.id) | ||
let componentId = nodeIdToComponentId.get(otherNode.id); | ||
if (componentId !== undefined && componentId === lastComponentId) { | ||
@@ -44,3 +44,3 @@ // this is possible when we have a loop. Just ignore the node. | ||
return connectedComponents; | ||
} | ||
}; | ||
@@ -47,0 +47,0 @@ function dfs(graph, startFromNodeId, visitor) { |
150
index.d.ts
@@ -1,6 +0,9 @@ | ||
// Type definitions for ngraph.graph v18.0.0 | ||
// Type definitions for ngraph.graph v20.0.0 | ||
// Project: https://github.com/anvaka/ngraph.graph | ||
// Definitions by: Nathan Westlake <https://github.com/CorayThan> | ||
// Definitions by: Nathan Westlake <https://github.com/CorayThan> and Anvaka <https://github.com/anvaka> | ||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped | ||
/** | ||
* A graph data structure for javascript. | ||
*/ | ||
declare module "ngraph.graph" { | ||
@@ -12,40 +15,169 @@ import { EventedType } from 'ngraph.events' | ||
/** | ||
* A single link (edge) of the graph | ||
*/ | ||
export interface Link<Data = any> { | ||
/** | ||
* Unique identifier of this link | ||
*/ | ||
id: LinkId, | ||
/** | ||
* Node identifer where this links starts | ||
*/ | ||
fromId: NodeId, | ||
/** | ||
* Node identifer where this link points to | ||
*/ | ||
toId: NodeId, | ||
/** | ||
* Arbitrary data associated with this link | ||
*/ | ||
data: Data | ||
} | ||
/** | ||
* A single node of a graph. | ||
*/ | ||
export interface Node<Data = any> { | ||
/** | ||
* Unique identifier of this node | ||
*/ | ||
id: NodeId, | ||
links: Link[], | ||
/** | ||
* Set of incoming/outgoing links (edges) to/from this node. | ||
* | ||
* For the sake of memory consumption preservation, this property | ||
* is null when this node has no links. | ||
* | ||
* Link instance is referentially equal throughout the API. | ||
*/ | ||
links: Set<Link<any>> | null, | ||
/** | ||
* Associated data connected to this node. | ||
*/ | ||
data: Data | ||
} | ||
/** | ||
* A graph data structure | ||
*/ | ||
export interface Graph<NodeData = any, LinkData = any> { | ||
/** | ||
* Adds a new node to the graph. If node with such id already exists | ||
* its data is overwritten with the new data | ||
*/ | ||
addNode: (node: NodeId, data?: NodeData) => Node<NodeData> | ||
/** | ||
* Adds a new link to the graph. If link already exists and the graph | ||
* is not a multigraph, then link's data is overwritten with a new data. | ||
* | ||
* When graph is a multigraph, then a new link is always added between the | ||
* nodes. | ||
*/ | ||
addLink: (from: NodeId, to: NodeId, data?: LinkData) => Link<LinkData> | ||
/** | ||
* Removes a link from the graph. You'll need to pass an actual link instance | ||
* to remove it. If you pass two arguments, the function assumes they represent | ||
* from/to node ids, and removes the corresponding link. | ||
* | ||
* Returns true if link is found and removed. False otherwise. | ||
*/ | ||
removeLink: (link: Link<LinkData>) => boolean | ||
/** | ||
* Removes node by node id. Returns true if node was removed, | ||
* false otherwise (e.g. no such node exists in the graph) | ||
*/ | ||
removeNode: (nodeId: NodeId) => boolean | ||
/** | ||
* Returns a node by its identifier. Undefined value is returned if node | ||
* with such identifer does not exist. | ||
*/ | ||
getNode: (nodeId: NodeId) => Node<NodeData> | undefined | ||
/** | ||
* Checks whether given node exists in the graph. Return the node | ||
* or undefined if no such node exist. | ||
*/ | ||
hasNode: (nodeId: NodeId) => Node<NodeData> | undefined | ||
getLink: (fromNodeId: NodeId, toNodeId: NodeId) => Link<LinkData> | null | ||
hasLink: (fromNodeId: NodeId, toNodeId: NodeId) => Link<LinkData> | null | ||
/** | ||
* Returns a link between two nodes | ||
*/ | ||
getLink: (fromNodeId: NodeId, toNodeId: NodeId) => Link<LinkData> | undefined | ||
/** | ||
* Checks if link is present in the graph | ||
*/ | ||
hasLink: (fromNodeId: NodeId, toNodeId: NodeId) => Link<LinkData> | undefined | ||
/** | ||
* Returns number of nodes in the graph | ||
*/ | ||
getNodesCount: () => number | ||
/** | ||
* Returns number of nodes in the graph | ||
*/ | ||
getNodeCount: () => number | ||
/** | ||
* Returns number of links (edges) in the graph | ||
*/ | ||
getLinksCount: () => number | ||
getNodeCount: () => number | ||
/** | ||
* Returns number of links (edges) in the graph | ||
*/ | ||
getLinkCount: () => number | ||
getLinks: (nodeId: NodeId) => Link<LinkData>[] | null | ||
/** To stop the iteration return true in the callback */ | ||
/** | ||
* Returns all links associated with this node | ||
*/ | ||
getLinks: (nodeId: NodeId) => Set<Link<LinkData>> | null | ||
/** | ||
* Iterates over every single node in the graph, passing the node to a callback. | ||
* | ||
* If callback function returns "true"-like value, enumeration stops. | ||
**/ | ||
forEachNode: (callbackPerNode: (node: Node<NodeData>) => void | undefined | null | boolean) => void | ||
/** | ||
* Iterates over every single link in the graph, passing the link to a callback. | ||
* If callback function returns "true"-like value, enumeration stops. | ||
*/ | ||
forEachLink: (callbackPerLink: (link: Link<LinkData>) => void | undefined | boolean) => void | ||
forEachLinkedNode: (nodeId: NodeId, callbackPerNode: (node: Node<NodeData>, link: Link<LinkData>) => void, oriented: boolean) => void | ||
forEachLink: (callbackPerLink: (link: Link<LinkData>) => void) => void | ||
/** | ||
* Suspend all notifications about graph changes until | ||
* endUpdate is called. | ||
*/ | ||
beginUpdate: () => void | ||
/** | ||
* Resumes all notifications about graph changes and fires | ||
* graph 'changed' event in case there are any pending changes. | ||
*/ | ||
endUpdate: () => void | ||
/** | ||
* Removes all nodes and links from the graph. | ||
*/ | ||
clear: () => void | ||
} | ||
/** | ||
* Creates a new instance of a graph. | ||
*/ | ||
export default function createGraph<NodeData = any, LinkData = any>(options?: { multigraph: boolean }): Graph<NodeData, LinkData> & EventedType | ||
} |
147
index.js
@@ -52,9 +52,9 @@ /** | ||
var nodes = new Map(); | ||
var links = [], | ||
var nodes = new Map(); // nodeId => Node | ||
var links = new Map(); // linkId => Link | ||
// Hash of multi-edges. Used to track ids of edges between same nodes | ||
multiEdges = {}, | ||
suspendEvents = 0, | ||
var multiEdges = {}; | ||
var suspendEvents = 0; | ||
createLink = options.multigraph ? createUniqueLink : createSingleLink, | ||
var createLink = options.multigraph ? createUniqueLink : createSingleLink, | ||
@@ -81,2 +81,8 @@ // Our graph API provides means to listen to graph changes. Users can subscribe | ||
/** | ||
* Sometimes duck typing could be slow. Giving clients a hint about data structure | ||
* via explicit version number here: | ||
*/ | ||
version: 20.0, | ||
/** | ||
* Adds node to the graph. If node with given id already exists in the graph | ||
@@ -147,2 +153,7 @@ * its data is extended with whatever comes in 'data' argument. | ||
/** | ||
* Gets total number of links in the graph. | ||
*/ | ||
getEdgeCount: getLinkCount, | ||
/** | ||
* Synonym for `getLinkCount()` | ||
@@ -163,3 +174,3 @@ */ | ||
* | ||
* @return Array of links from and to requested node if such node exists; | ||
* @return Set of links from and to requested node if such node exists; | ||
* otherwise null is returned. | ||
@@ -220,3 +231,3 @@ */ | ||
* Operation complexity is O(n) where n - number of links of a node. | ||
* NOTE: this function is synonim for getLink() | ||
* NOTE: this function is synonym for getLink() | ||
* | ||
@@ -231,3 +242,3 @@ * @returns link if there is one. null otherwise. | ||
* Operation complexity is O(1) | ||
* NOTE: this function is synonim for getNode() | ||
* NOTE: this function is synonym for getNode() | ||
* | ||
@@ -245,3 +256,3 @@ * @returns node if there is one; Falsy value otherwise. | ||
* | ||
* @returns link if there is one. null otherwise. | ||
* @returns link if there is one; undefined otherwise. | ||
*/ | ||
@@ -329,9 +340,7 @@ getLink: getLink | ||
if (prevLinks) { | ||
prevLinks.forEach(removeLinkInstance); | ||
node.links = null; | ||
for(var i = 0; i < prevLinks.length; ++i) { | ||
removeLink(prevLinks[i]); | ||
} | ||
} | ||
nodes.delete(nodeId) | ||
nodes.delete(nodeId); | ||
@@ -353,4 +362,5 @@ recordNodeChange(node, 'remove'); | ||
var link = createLink(fromId, toId, data); | ||
var isUpdate = links.has(link.id); | ||
links.push(link); | ||
links.set(link.id, link); | ||
@@ -364,3 +374,3 @@ // TODO: this is not cool. On large graphs potentially would consume more memory. | ||
recordLinkChange(link, 'add'); | ||
recordLinkChange(link, isUpdate ? 'update' : 'add'); | ||
@@ -374,2 +384,8 @@ exitModification(); | ||
var linkId = makeLinkId(fromId, toId); | ||
var prevLink = links.get(linkId); | ||
if (prevLink) { | ||
prevLink.data = data; | ||
return prevLink; | ||
} | ||
return new Link(fromId, toId, data, linkId); | ||
@@ -379,3 +395,3 @@ } | ||
function createUniqueLink(fromId, toId, data) { | ||
// TODO: Get rid of this method. | ||
// TODO: Find a better/faster way to store multigraphs | ||
var linkId = makeLinkId(fromId, toId); | ||
@@ -399,3 +415,3 @@ var isMultiEdge = multiEdges.hasOwnProperty(linkId); | ||
function getLinkCount() { | ||
return links.length; | ||
return links.size; | ||
} | ||
@@ -408,14 +424,18 @@ | ||
function removeLink(link) { | ||
function removeLink(link, otherId) { | ||
if (otherId !== undefined) { | ||
link = getLink(link, otherId); | ||
} | ||
return removeLinkInstance(link); | ||
} | ||
function removeLinkInstance(link) { | ||
if (!link) { | ||
return false; | ||
} | ||
var idx = indexOfElementInArray(link, links); | ||
if (idx < 0) { | ||
return false; | ||
} | ||
if (!links.get(link.id)) return false; | ||
enterModification(); | ||
links.splice(idx, 1); | ||
links.delete(link.id); | ||
@@ -426,13 +446,7 @@ var fromNode = getNode(link.fromId); | ||
if (fromNode) { | ||
idx = indexOfElementInArray(link, fromNode.links); | ||
if (idx >= 0) { | ||
fromNode.links.splice(idx, 1); | ||
} | ||
fromNode.links.delete(link); | ||
} | ||
if (toNode) { | ||
idx = indexOfElementInArray(link, toNode.links); | ||
if (idx >= 0) { | ||
toNode.links.splice(idx, 1); | ||
} | ||
toNode.links.delete(link); | ||
} | ||
@@ -448,17 +462,4 @@ | ||
function getLink(fromNodeId, toNodeId) { | ||
// TODO: Use sorted links to speed this up | ||
var node = getNode(fromNodeId), | ||
i; | ||
if (!node || !node.links) { | ||
return null; | ||
} | ||
for (i = 0; i < node.links.length; ++i) { | ||
var link = node.links[i]; | ||
if (link.fromId === fromNodeId && link.toId === toNodeId) { | ||
return link; | ||
} | ||
} | ||
return null; // no link. | ||
if (fromNodeId === undefined || toNodeId === undefined) return undefined; | ||
return links.get(makeLinkId(fromNodeId, toNodeId)); | ||
} | ||
@@ -475,6 +476,10 @@ | ||
function forEachLink(callback) { | ||
var i, length; | ||
if (typeof callback === 'function') { | ||
for (i = 0, length = links.length; i < length; ++i) { | ||
callback(links[i]); | ||
var valuesIterator = links.values(); | ||
var nextValue = valuesIterator.next(); | ||
while (!nextValue.done) { | ||
if (callback(nextValue.value)) { | ||
return true; // client doesn't want to proceed. Return. | ||
} | ||
nextValue = valuesIterator.next(); | ||
} | ||
@@ -496,8 +501,11 @@ } | ||
// eslint-disable-next-line no-shadow | ||
function forEachNonOrientedLink(links, nodeId, callback) { | ||
var quitFast; | ||
for (var i = 0; i < links.length; ++i) { | ||
var link = links[i]; | ||
var valuesIterator = links.values(); | ||
var nextValue = valuesIterator.next(); | ||
while (!nextValue.done) { | ||
var link = nextValue.value; | ||
var linkedNodeId = link.fromId === nodeId ? link.toId : link.fromId; | ||
quitFast = callback(nodes.get(linkedNodeId), link); | ||
@@ -507,11 +515,15 @@ if (quitFast) { | ||
} | ||
nextValue = valuesIterator.next(); | ||
} | ||
} | ||
// eslint-disable-next-line no-shadow | ||
function forEachOrientedLink(links, nodeId, callback) { | ||
var quitFast; | ||
for (var i = 0; i < links.length; ++i) { | ||
var link = links[i]; | ||
var valuesIterator = links.values(); | ||
var nextValue = valuesIterator.next(); | ||
while (!nextValue.done) { | ||
var link = nextValue.value; | ||
if (link.fromId === nodeId) { | ||
quitFast = callback(nodes.get(link.toId), link) | ||
quitFast = callback(nodes.get(link.toId), link); | ||
if (quitFast) { | ||
@@ -521,2 +533,3 @@ return true; // Client does not need more iterations. Break now. | ||
} | ||
nextValue = valuesIterator.next(); | ||
} | ||
@@ -558,22 +571,2 @@ } | ||
// need this for old browsers. Should this be a separate module? | ||
function indexOfElementInArray(element, array) { | ||
if (!array) return -1; | ||
if (array.indexOf) { | ||
return array.indexOf(element); | ||
} | ||
var len = array.length, | ||
i; | ||
for (i = 0; i < len; i += 1) { | ||
if (array[i] === element) { | ||
return i; | ||
} | ||
} | ||
return -1; | ||
} | ||
/** | ||
@@ -590,5 +583,5 @@ * Internal structure to represent node; | ||
if (node.links) { | ||
node.links.push(link); | ||
node.links.add(link); | ||
} else { | ||
node.links = [link]; | ||
node.links = new Set([link]); | ||
} | ||
@@ -595,0 +588,0 @@ } |
{ | ||
"name": "ngraph.graph", | ||
"version": "19.1.0", | ||
"version": "20.0.0", | ||
"description": "graph data structure", | ||
@@ -10,4 +10,4 @@ "main": "index.js", | ||
"build": "browserify index.js -s createGraph -o dist/ngraph.graph.js && uglifyjs dist/ngraph.graph.js -o dist/ngraph.graph.min.js", | ||
"test": "tap test/*.js", | ||
"cover": "tap --coverage-report=html --no-browser test/*.js" | ||
"test": "tap --branches=90 --lines=90 --statements=90 --functions=90 test/*.js", | ||
"cover": "tap --branches=80 --lines=80 --statements=80 --functions=80 --coverage-report=html --no-browser test/*.js" | ||
}, | ||
@@ -37,6 +37,7 @@ "repository": { | ||
"benchmark": "^2.1.4", | ||
"browserify": "^16.5.0", | ||
"ngraph.random": "^1.0.0", | ||
"tap": "^14.10.7", | ||
"uglify-js": "^3.8.0" | ||
"browserify": "^17.0.0", | ||
"eslint": "^7.25.0", | ||
"ngraph.random": "^1.1.0", | ||
"tap": "^15.0.9", | ||
"uglify-js": "^3.13.5" | ||
}, | ||
@@ -43,0 +44,0 @@ "dependencies": { |
var createGraph = require('../'); | ||
var randomAPI = require('ngraph.random').random | ||
var randomAPI = require('ngraph.random').random; | ||
var Benchmark = require('benchmark'); | ||
@@ -4,0 +4,0 @@ var suite = new Benchmark.Suite; |
var createGraph = require('../'); | ||
var randomAPI = require('ngraph.random').random | ||
var randomAPI = require('ngraph.random').random; | ||
var Benchmark = require('benchmark'); | ||
@@ -40,3 +40,3 @@ var suite = new Benchmark.Suite; | ||
} | ||
}) | ||
}); | ||
@@ -75,3 +75,3 @@ suite.add('Adding 5,000 random edges and randomly removing them', function() { | ||
} | ||
}) | ||
}); | ||
@@ -96,3 +96,3 @@ suite.add('Removing all edges one by one from 5k graph', function() { | ||
} | ||
}) | ||
}); | ||
@@ -117,3 +117,3 @@ suite.add('Removing all edges one by one from 5k multigraph graph', function() { | ||
} | ||
}) | ||
}); | ||
@@ -120,0 +120,0 @@ suite.on('cycle', function(event) { |
@@ -7,4 +7,21 @@ ngraph.graph | ||
[![build status](https://secure.travis-ci.org/anvaka/ngraph.graph.png)](http://travis-ci.org/anvaka/ngraph.graph) | ||
[![build status](https://github.com/anvaka/ngraph.graph/actions/workflows/tests.yaml/badge.svg)](https://github.com/anvaka/ngraph.graph/actions/workflows/tests.yaml) | ||
Install | ||
======= | ||
With [npm](http://npmjs.org) do: | ||
``` | ||
npm install ngraph.graph | ||
``` | ||
Or download from CDN: | ||
``` html | ||
<script src='https://unpkg.com/ngraph.graph@19.0.0/dist/ngraph.graph.min.js'></script> | ||
``` | ||
If you download from CDN the library will be available under `createGraph` global name. | ||
## Creating a graph | ||
@@ -179,21 +196,5 @@ Create a graph with no edges and no nodes: | ||
Install | ||
======= | ||
With [npm](http://npmjs.org) do: | ||
``` | ||
npm install ngraph.graph | ||
``` | ||
Or download from CDN: | ||
``` html | ||
<script src='https://unpkg.com/ngraph.graph@19.0.0/dist/ngraph.graph.min.js'></script> | ||
``` | ||
If you download from CDN the library will be available under `createGraph` global name. | ||
License | ||
======= | ||
BSD 3-clause |
@@ -48,6 +48,13 @@ var test = require('tap').test, | ||
t.equals(graph.getLink, graph.hasLink, 'hasLink is synonim for getLink'); | ||
t.equal(graph.getLink, graph.hasLink, 'hasLink is synonym for getLink'); | ||
t.end(); | ||
}); | ||
test('it considers uniqueLinkId as multigraph', function (t) { | ||
var options = {uniqueLinkId: true}; | ||
createGraph(options); | ||
t.equal(options.multigraph, true, 'multigraph is set'); | ||
t.end(); | ||
}); | ||
test('it throw if no node id is passed', function(t) { | ||
@@ -73,5 +80,5 @@ var graph = createGraph(); | ||
var change = changes[0]; | ||
t.equals(change.node.id, 1); | ||
t.equals(change.node.data, 'world'); | ||
t.equals(change.changeType, 'update'); | ||
t.equal(change.node.id, 1); | ||
t.equal(change.node.data, 'world'); | ||
t.equal(change.changeType, 'update'); | ||
} | ||
@@ -91,4 +98,4 @@ }); | ||
t.ok(graph.hasLink('watch', 'constructor')); | ||
t.equals(graph.getLinksCount(), 1, 'one link'); | ||
t.equals(iterated, 2, 'has two nodes'); | ||
t.equal(graph.getLinksCount(), 1, 'one link'); | ||
t.equal(iterated, 2, 'has two nodes'); | ||
t.end(); | ||
@@ -106,6 +113,6 @@ }); | ||
t.equal(graph.getLinksCount(), 1, 'One link'); | ||
t.equal(firstNodeLinks.length, 1, 'number of links of the first node is wrong'); | ||
t.equal(secondNodeLinks.length, 1, 'number of links of the second node is wrong'); | ||
t.equal(link, firstNodeLinks[0], 'invalid link in the first node'); | ||
t.equal(link, secondNodeLinks[0], 'invalid link in the second node'); | ||
t.equal(firstNodeLinks.size, 1, 'number of links of the first node is wrong'); | ||
t.equal(secondNodeLinks.size, 1, 'number of links of the second node is wrong'); | ||
t.equal(link, Array.from(firstNodeLinks)[0], 'invalid link in the first node'); | ||
t.equal(link, Array.from(secondNodeLinks)[0], 'invalid link in the second node'); | ||
t.end(); | ||
@@ -132,3 +139,4 @@ }); | ||
test('it can produce unique link ids', function (t) { | ||
t.test('by default links are not unique', function (t) { | ||
// eslint-disable-next-line no-shadow | ||
t.test('by default links are de-duped', function (t) { | ||
var seen = {}; | ||
@@ -142,4 +150,6 @@ var graph = createGraph(); | ||
var link = graph.getLink(1, 2); | ||
t.equals(seen[link.id], 3, 'Link 1->2 seen 3 times') | ||
t.equal(seen[link.id], 1, 'Link 1->2 seen 1 time'); | ||
t.equal(link.data, 'third', 'Last link wins'); | ||
// eslint-disable-next-line no-shadow | ||
function verifyLinksAreNotUnique(link) { | ||
@@ -151,2 +161,3 @@ seen[link.id] = (seen[link.id] || 0) + 1; | ||
// eslint-disable-next-line no-shadow | ||
t.test('You can create multigraph', function (t) { | ||
@@ -162,3 +173,3 @@ var graph = createGraph({ | ||
graph.forEachLink(verifyLinkIsUnique); | ||
t.equals(graph.getLinksCount(), 3, 'All three links are here'); | ||
t.equal(graph.getLinksCount(), 3, 'All three links are here'); | ||
t.end(); | ||
@@ -172,19 +183,2 @@ | ||
t.test('you can sacrifice uniqueness in favor of performance', function (t) { | ||
var graph = createGraph({ }); | ||
var seen = {}; | ||
graph.addLink(1, 2, 'first'); | ||
graph.addLink(1, 2, 'second'); | ||
graph.addLink(1, 2, 'third'); | ||
graph.forEachLink(noticeLink); | ||
t.equals(Object.keys(seen).length, 1, 'Only one link id'); | ||
t.end(); | ||
function noticeLink(link) { | ||
seen[link.id] = true; | ||
} | ||
}); | ||
t.end(); | ||
@@ -260,4 +254,4 @@ }); | ||
t.equal(graph.getLinksCount(), 0, 'No Links'); | ||
t.equal(graph.getLinks(1).length, 0, 'link should be removed from the first node'); | ||
t.equal(graph.getLinks(2).length, 0, 'link should be removed from the second node'); | ||
t.equal(graph.getLinks(1).size, 0, 'link should be removed from the first node'); | ||
t.equal(graph.getLinks(2).size, 0, 'link should be removed from the second node'); | ||
t.ok(linkIsRemoved, 'Link removal is successful'); | ||
@@ -272,2 +266,21 @@ | ||
test('it can remove link by from/to ids', function(t) { | ||
var graph = createGraph(); | ||
graph.addLink(1, 2); | ||
var linkIsRemoved = graph.removeLink(1, 2); | ||
t.equal(graph.getNodesCount(), 2, 'remove link should not remove nodes'); | ||
t.equal(graph.getLinksCount(), 0, 'No Links'); | ||
t.equal(graph.getLinks(1).size, 0, 'link should be removed from the first node'); | ||
t.equal(graph.getLinks(2).size, 0, 'link should be removed from the second node'); | ||
t.ok(linkIsRemoved, 'Link removal is successful'); | ||
graph.forEachLink(function() { | ||
test.ok(false, 'No links should be in graph'); | ||
}); | ||
t.end(); | ||
}); | ||
test('remove link returns false if no link removed', function (t) { | ||
@@ -343,4 +356,4 @@ var graph = createGraph(); | ||
t.equal(graph.getLinks(1), null, 'link should be removed from the first node'); | ||
t.equal(graph.getLinks(2).length, 0, 'link should be removed from the second node'); | ||
t.equal(graph.getLinks(3).length, 0, 'link should be removed from the third node'); | ||
t.equal(graph.getLinks(2).size, 0, 'link should be removed from the second node'); | ||
t.equal(graph.getLinks(3).size, 0, 'link should be removed from the third node'); | ||
graph.forEachLink(function() { | ||
@@ -380,6 +393,6 @@ test.ok(false, 'No links should be in graph'); | ||
graph.addNode(1); | ||
t.equals(changedCount, 0, 'Begin update freezes updates until `endUpdate()`'); | ||
t.equal(changedCount, 0, 'Begin update freezes updates until `endUpdate()`'); | ||
graph.endUpdate(); | ||
t.equals(changedCount, 1, 'event is fired only after endUpdate()'); | ||
t.equal(changedCount, 1, 'event is fired only after endUpdate()'); | ||
t.end(); | ||
}); |
@@ -19,8 +19,8 @@ var test = require('tap').test; | ||
t.equal(components.length, 4, 'all components found'); | ||
t.deepEqual(components[0], [1, 2, 3], 'first component found') | ||
t.deepEqual(components[1], [5, 6], 'second component found') | ||
t.deepEqual(components[2], [8], 'third component found') | ||
t.deepEqual(components[3], [9], 'fourth component found') | ||
t.same(components[0], [1, 2, 3], 'first component found'); | ||
t.same(components[1], [5, 6], 'second component found'); | ||
t.same(components[2], [8], 'third component found'); | ||
t.same(components[3], [9], 'fourth component found'); | ||
t.end(); | ||
}); |
@@ -45,3 +45,2 @@ var test = require('tap').test, | ||
test('forEachLinkedNode can quit fast for oriented graphs', function(t) { | ||
t.plan(1); | ||
var graph = createGraph(); | ||
@@ -52,10 +51,13 @@ var oriented = true; | ||
var visited = 0; | ||
graph.forEachLinkedNode(1, function() { | ||
t.ok(true, 'Visited first link'); | ||
visited += 1; | ||
return true; // We want to stop right now! | ||
}, oriented); | ||
t.equal(visited, 1, 'One link is visited'); | ||
t.end(); | ||
}); | ||
test('forEachLinkedNode can quit fast for non-oriented graphs', function(t) { | ||
t.plan(1); | ||
var graph = createGraph(); | ||
@@ -66,6 +68,11 @@ var oriented = false; | ||
var visited = 0; | ||
graph.forEachLinkedNode(1, function() { | ||
t.ok(true, 'Visited first link'); | ||
visited += 1; | ||
return true; // We want to stop right now! | ||
}, oriented); | ||
t.equal(visited, 1, 'One link is visited'); | ||
t.end(); | ||
}); | ||
@@ -111,3 +118,3 @@ | ||
graph.forEachNode(function(node) { | ||
t.equals(node.id, 1, 'We visit only one node'); | ||
t.equal(node.id, 1, 'We visit only one node'); | ||
return true; // we want to stop now! | ||
@@ -123,3 +130,3 @@ }); | ||
var fastQuit = graph.forEachNode(function(node) { | ||
t.equals(node.id, 1, 'We visit only one node'); | ||
t.equal(node.id, 1, 'We visit only one node'); | ||
return true; // we want to stop now! | ||
@@ -134,1 +141,24 @@ }); // no callback? No worries | ||
}); | ||
test('forEachNode throws when callback is not a function', function(t) { | ||
var graph = createGraph(); | ||
graph.addLink(1, 2); | ||
t.throws(function() { | ||
graph.forEachNode('not a function'); | ||
}); | ||
t.end(); | ||
}); | ||
test('forEachLink stops when requested', function(t) { | ||
var graph = createGraph(); | ||
graph.addLink(1, 2); | ||
graph.addLink(2, 3); | ||
var visitCount = 0; | ||
graph.forEachLink(function() { | ||
visitCount += 1; | ||
return true; | ||
}); | ||
t.equal(visitCount, 1, 'only one link visited'); | ||
t.end(); | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
83498
19
1888
199
6