graphology
Advanced tools
Comparing version 0.1.1 to 0.2.0
# Changelog | ||
## 0.2.0 | ||
* Adding `#.hasNodeAttribute` & `#.hasEdgeAttribute`. | ||
* Adding `#.removeNodeAttribute` & `#.removeEdgeAttribute`. | ||
* Adding `#.mergeNode`. | ||
* Adding `#.mergeEdge`, `#.mergeEdgeWithKey` and friends. | ||
* Renaming `#.relatedNode` to `#.opposite`. | ||
* Dropping the `onDuplicateNode` & `onDuplicateEdge` options. | ||
## 0.1.1 | ||
@@ -4,0 +13,0 @@ |
@@ -118,2 +118,53 @@ 'use strict'; | ||
/** | ||
* Attach an attribute checker method onto the provided class. | ||
* | ||
* @param {function} Class - Target class. | ||
* @param {string} method - Method name. | ||
* @param {string} key - Key of the element's storage on instance. | ||
* @param {string} elementName - Name of target element for messages. | ||
* @param {string} checker - Name of the checker method to use. | ||
* @param {string} [finder] - Name of the finder method to use. | ||
*/ | ||
function attachAttributeChecker(Class, method, key, elementName, checker, finder) { | ||
/** | ||
* Checks whether the desired attribute is set for the given element (node or edge). | ||
* | ||
* Arity 2: | ||
* @param {any} element - Target element. | ||
* @param {string} name - Attribute's name. | ||
* | ||
* Arity 3 (only for edges): | ||
* @param {any} source - Source element. | ||
* @param {any} target - Target element. | ||
* @param {string} name - Attribute's name. | ||
* | ||
* @return {boolean} | ||
* | ||
* @throws {Error} - Will throw if too many arguments are provided. | ||
* @throws {Error} - Will throw if any of the elements is not found. | ||
*/ | ||
Class.prototype[method] = function (element, name) { | ||
if (arguments.length > 2) { | ||
if (!finder) throw new _errors.InvalidArgumentsGraphError('Graph.' + method + ': too many arguments provided.'); | ||
var source = element, | ||
target = name; | ||
name = arguments[2]; | ||
if (!this[checker](source, target)) throw new _errors.NotFoundGraphError('Graph.' + method + ': could not find an edge for the given path ("' + source + '" - "' + target + '").'); | ||
element = this[finder](source, target); | ||
} | ||
if (!this[checker](element)) throw new _errors.NotFoundGraphError('Graph.' + method + ': could not find the "' + element + '" ' + elementName + ' in the graph.'); | ||
var data = this[key].get(element); | ||
return data.attributes.hasOwnProperty(name); | ||
}; | ||
} | ||
/** | ||
* Attach an attribute setter method onto the provided class. | ||
@@ -401,2 +452,7 @@ * | ||
name: function name(element) { | ||
return 'has' + element + 'Attribute'; | ||
}, | ||
attacher: attachAttributeChecker | ||
}, { | ||
name: function name(element) { | ||
return 'set' + element + 'Attribute'; | ||
@@ -403,0 +459,0 @@ }, |
@@ -37,9 +37,2 @@ 'use strict'; | ||
// TODO: finish #.selfLoops (bunch iteration only) | ||
// TODO: solve the #.merge conundrum | ||
// TODO: add the option adding nodes when creating edges if non-existent | ||
// TODO: abstract set storing first element (override add) | ||
// TODO: refactor edge adding methods using a descriptor? | ||
// TODO: discuss .removeNodeAttribute & .hasNodeAttribute | ||
/** | ||
@@ -52,2 +45,35 @@ * Enums. | ||
var EDGE_ADD_METHODS = [{ | ||
name: function name(verb) { | ||
return verb + 'Edge'; | ||
}, | ||
generateKey: true | ||
}, { | ||
name: function name(verb) { | ||
return verb + 'DirectedEdge'; | ||
}, | ||
generateKey: true, | ||
type: 'directed' | ||
}, { | ||
name: function name(verb) { | ||
return verb + 'UndirectedEdge'; | ||
}, | ||
generateKey: true, | ||
type: 'undirected' | ||
}, { | ||
name: function name(verb) { | ||
return verb + 'EdgeWithKey'; | ||
} | ||
}, { | ||
name: function name(verb) { | ||
return verb + 'DirectedEdgeWithKey'; | ||
}, | ||
type: 'directed' | ||
}, { | ||
name: function name(verb) { | ||
return verb + 'UndirectedEdgeWithKey'; | ||
}, | ||
type: 'undirected' | ||
}]; | ||
/** | ||
@@ -62,4 +88,2 @@ * Default options. | ||
multi: false, | ||
onDuplicateEdge: null, | ||
onDuplicateNode: null, | ||
type: 'mixed' | ||
@@ -130,2 +154,3 @@ }; | ||
* @param {string} name - Name of the child method for errors. | ||
* @param {boolean} merge - Are we merging? | ||
* @param {boolean} mustGenerateId - Should the graph generate an id? | ||
@@ -144,3 +169,3 @@ * @param {boolean} undirected - Whether the edge is undirected. | ||
*/ | ||
function _addEdge(graph, name, mustGenerateId, undirected, edge, source, target, attributes) { | ||
function addEdge(graph, name, merge, mustGenerateId, undirected, edge, source, target, attributes) { | ||
@@ -158,6 +183,13 @@ // Checking validity of operation | ||
if (!graph.hasNode(source)) throw new _errors.NotFoundGraphError('Graph.' + name + ': source node "' + source + '" not found.'); | ||
var mustAddSource = false, | ||
mustAddTarget = false; | ||
if (!graph.hasNode(target)) throw new _errors.NotFoundGraphError('Graph.' + name + ': target node "' + target + '" not found.'); | ||
if (!graph.hasNode(source)) { | ||
if (!merge) throw new _errors.NotFoundGraphError('Graph.' + name + ': source node "' + source + '" not found.');else mustAddSource = true; | ||
} | ||
if (!graph.hasNode(target)) { | ||
if (!merge) throw new _errors.NotFoundGraphError('Graph.' + name + ': target node "' + target + '" not found.');else mustAddTarget = true; | ||
} | ||
if (!graph.allowSelfLoops && source === target) throw new _errors.UsageGraphError('Graph.' + name + ': source & target are the same, thus creating a loop explicitly forbidden by this graph \'allowSelfLoops\' option set to false.'); | ||
@@ -176,11 +208,18 @@ | ||
// Do we need to handle duplicate? | ||
var canHandleDuplicate = typeof graph._options.onDuplicateEdge === 'function'; | ||
var mustHandleDuplicate = false; | ||
var alreadyExistingEdge = null; | ||
// Here, we have a key collision | ||
if (graph.hasEdge(edge)) { | ||
if (!canHandleDuplicate) throw new _errors.UsageGraphError('Graph.' + name + ': the "' + edge + '" edge already exists in the graph.');else mustHandleDuplicate = true; | ||
if (!merge) { | ||
throw new _errors.UsageGraphError('Graph.' + name + ': the "' + edge + '" edge already exists in the graph.'); | ||
} else { | ||
alreadyExistingEdge = edge; | ||
} | ||
} | ||
// Here, we might have a source / target collision | ||
if (!graph.multi && (undirected ? graph.hasUndirectedEdge(source, target) : graph.hasDirectedEdge(source, target))) { | ||
if (!canHandleDuplicate) throw new _errors.UsageGraphError('Graph.' + name + ': an edge linking "' + source + '" to "' + target + '" already exists. If you really want to add multiple edges linking those nodes, you should create a multi graph by using the \'multi\' option. The \'onDuplicateEdge\' option might also interest you.');else mustHandleDuplicate = true; | ||
if (!merge) throw new _errors.UsageGraphError('Graph.' + name + ': an edge linking "' + source + '" to "' + target + '" already exists. If you really want to add multiple edges linking those nodes, you should create a multi graph by using the \'multi\' option.');else { | ||
alreadyExistingEdge = undirected ? graph.getUndirectedEdge(source, target) : graph.getDirectedEdge(source, target); | ||
} | ||
} | ||
@@ -192,14 +231,17 @@ | ||
// Handling duplicates | ||
if (mustHandleDuplicate) { | ||
graph._options.onDuplicateEdge(graph, { | ||
key: edge, | ||
attributes: attributes, | ||
source: source, | ||
target: target, | ||
undirected: undirected | ||
}); | ||
if (alreadyExistingEdge) { | ||
return edge; | ||
// If the key collides but the source & target are inconsistent, we throw | ||
if (graph.source(alreadyExistingEdge) !== source || graph.target(alreadyExistingEdge) !== target) { | ||
throw new _errors.UsageGraphError('Graph.' + name + ': inconsitency detected when attempting to merge the "' + edge + '" edge with "' + source + '" source & "' + target + '" target vs. (' + graph.source(alreadyExistingEdge) + ', ' + graph.target(alreadyExistingEdge) + ').'); | ||
} | ||
// Simply merging the attributes of the already existing edge | ||
graph.mergeEdgeAttributes(alreadyExistingEdge, attributes); | ||
return alreadyExistingEdge; | ||
} | ||
if (mustAddSource) graph.addNode(source); | ||
if (mustAddTarget) graph.addNode(target); | ||
// Storing some data | ||
@@ -327,6 +369,2 @@ var data = { | ||
if (options.onDuplicateEdge && typeof options.onDuplicateEdge !== 'function') throw new _errors.InvalidArgumentsGraphError('Graph.constructor: invalid \'onDuplicateEdge\' option. Expecting a function but got "' + options.onDuplicateEdge + '".'); | ||
if (options.onDuplicateNode && typeof options.onDuplicateNode !== 'function') throw new _errors.InvalidArgumentsGraphError('Graph.constructor: invalid \'onDuplicateNode\' option. Expecting a function but got "' + options.onDuplicateNode + '".'); | ||
//-- Private properties | ||
@@ -786,6 +824,6 @@ | ||
Graph.prototype.relatedNode = function relatedNode(node, edge) { | ||
if (!this.hasNode(node)) throw new _errors.NotFoundGraphError('Graph.relatedNode: could not find the "' + node + '" node in the graph.'); | ||
Graph.prototype.opposite = function opposite(node, edge) { | ||
if (!this.hasNode(node)) throw new _errors.NotFoundGraphError('Graph.opposite: could not find the "' + node + '" node in the graph.'); | ||
if (!this.hasEdge(edge)) throw new _errors.NotFoundGraphError('Graph.relatedNode: could not find the "' + edge + '" edge in the graph.'); | ||
if (!this.hasEdge(edge)) throw new _errors.NotFoundGraphError('Graph.opposite: could not find the "' + edge + '" edge in the graph.'); | ||
@@ -800,3 +838,3 @@ var _extremities = this.extremities(edge); | ||
if (node !== node1 && node !== node2) throw new _errors.NotFoundGraphError('Graph.relatedNode: the "' + node + '" node is not attached to the "' + edge + '" edge (' + node1 + ', ' + node2 + ').'); | ||
if (node !== node1 && node !== node2) throw new _errors.NotFoundGraphError('Graph.opposite: the "' + node + '" node is not attached to the "' + edge + '" edge (' + node1 + ', ' + node2 + ').'); | ||
@@ -879,14 +917,4 @@ return node === node1 ? node2 : node1; | ||
if (this.hasNode(node)) { | ||
if (this.hasNode(node)) throw new _errors.UsageGraphError('Graph.addNode: the "' + node + '" node already exist in the graph.'); | ||
// Triggering duplicate callback | ||
if (typeof this._options.onDuplicateNode === 'function') { | ||
this._options.onDuplicateNode(this, { key: node, attributes: attributes }); | ||
return node; | ||
} else { | ||
throw new _errors.UsageGraphError('Graph.addNode: the "' + node + '" node already exist in the graph. You might want to check out the \'onDuplicateNode\' option.'); | ||
} | ||
} | ||
var data = { | ||
@@ -927,2 +955,23 @@ attributes: attributes | ||
/** | ||
* Method used to merge a node into the graph. | ||
* | ||
* @param {any} node - The node. | ||
* @param {object} [attributes] - Optional attributes. | ||
* @return {any} - The node. | ||
*/ | ||
Graph.prototype.mergeNode = function mergeNode(node, attributes) { | ||
// If the node already exists, we merge the attributes | ||
if (this.hasNode(node)) { | ||
if (attributes) this.mergeNodeAttributes(node, attributes); | ||
return node; | ||
} | ||
// Else, we create it | ||
return this.addNode(node, attributes); | ||
}; | ||
/** | ||
* Method used to add a nodes from a bunch. | ||
@@ -950,94 +999,2 @@ * | ||
/** | ||
* Method used to add an edge of the type of the graph or directed if the | ||
* graph is mixed using the given key. | ||
* | ||
* @param {any} edge - The edge's key. | ||
* @param {any} source - The source node. | ||
* @param {any} target - The target node. | ||
* @param {object} [attributes] - Optional attributes. | ||
* @return {any} - The edge. | ||
*/ | ||
Graph.prototype.addEdgeWithKey = function addEdgeWithKey(edge, source, target, attributes) { | ||
return _addEdge(this, 'addEdgeWithKey', false, this.type === 'undirected', edge, source, target, attributes); | ||
}; | ||
/** | ||
* Method used to add a directed edge to the graph using the given key. | ||
* | ||
* @param {any} edge - The edge's key. | ||
* @param {any} source - The source node. | ||
* @param {any} target - The target node. | ||
* @param {object} [attributes] - Optional attributes. | ||
* @return {any} - The edge. | ||
*/ | ||
Graph.prototype.addDirectedEdgeWithKey = function addDirectedEdgeWithKey(edge, source, target, attributes) { | ||
return _addEdge(this, 'addDirectedEdgeWithKey', false, false, edge, source, target, attributes); | ||
}; | ||
/** | ||
* Method used to add an undirected edge to the graph using the given key. | ||
* | ||
* @param {any} edge - The edge's key. | ||
* @param {any} source - The source node. | ||
* @param {any} target - The target node. | ||
* @param {object} [attributes] - Optional attributes. | ||
* @return {any} - The edge. | ||
*/ | ||
Graph.prototype.addUndirectedEdgeWithKey = function addUndirectedEdgeWithKey(edge, source, target, attributes) { | ||
return _addEdge(this, 'addUndirectedEdgeWithKey', false, true, edge, source, target, attributes); | ||
}; | ||
/** | ||
* Method used to add an edge of the type of the graph or directed if the | ||
* graph is mixed. An id will automatically be created for it using the | ||
* 'edgeKeyGenerator' option. | ||
* | ||
* @param {any} source - The source node. | ||
* @param {any} target - The target node. | ||
* @param {object} [attributes] - Optional attributes. | ||
* @return {any} - The edge. | ||
*/ | ||
Graph.prototype.addEdge = function addEdge(source, target, attributes) { | ||
return _addEdge(this, 'addEdge', true, this.type === 'undirected', null, source, target, attributes); | ||
}; | ||
/** | ||
* Method used to add a directed edge to the graph. An id will automatically | ||
* be created for it using the 'edgeKeyGenerator' option. | ||
* | ||
* @param {any} source - The source node. | ||
* @param {any} target - The target node. | ||
* @param {object} [attributes] - Optional attributes. | ||
* @return {any} - The edge. | ||
*/ | ||
Graph.prototype.addDirectedEdge = function addDirectedEdge(source, target, attributes) { | ||
return _addEdge(this, 'addDirectedEdge', true, false, null, source, target, attributes); | ||
}; | ||
/** | ||
* Method used to add an undirected edge to the graph. An id will automatically | ||
* be created for it using the 'edgeKeyGenerator' option. | ||
* | ||
* @param {any} source - The source node. | ||
* @param {any} target - The target node. | ||
* @param {object} [attributes] - Optional attributes. | ||
* @return {any} - The edge. | ||
*/ | ||
Graph.prototype.addUndirectedEdge = function addUndirectedEdge(source, target, attributes) { | ||
return _addEdge(this, 'addUndirectedEdge', true, true, null, source, target, attributes); | ||
}; | ||
/** | ||
* Method used to drop a single node & all its attached edges from the graph. | ||
@@ -1719,3 +1676,3 @@ * | ||
/** | ||
* Attributes-related. | ||
* Related to edge addition. | ||
*/ | ||
@@ -1725,2 +1682,21 @@ | ||
exports.default = Graph; | ||
EDGE_ADD_METHODS.forEach(function (method) { | ||
['add', 'merge'].forEach(function (verb) { | ||
var name = method.name(verb); | ||
if (method.generateKey) { | ||
Graph.prototype[name] = function (source, target, attributes) { | ||
return addEdge(this, name, verb === 'merge', method.generateKey, (method.type || this.type) === 'undirected', null, source, target, attributes); | ||
}; | ||
} else { | ||
Graph.prototype[name] = function (edge, source, target, attributes) { | ||
return addEdge(this, name, verb === 'merge', method.generateKey, (method.type || this.type) === 'undirected', edge, source, target, attributes); | ||
}; | ||
} | ||
}); | ||
}); | ||
/** | ||
* Attributes-related. | ||
*/ | ||
(0, _attributes.attachAttributesMethods)(Graph); | ||
@@ -1727,0 +1703,0 @@ |
@@ -107,10 +107,19 @@ 'use strict'; | ||
* @param {object|undefined} map - Target object. | ||
* @param {string} key - Sub key. | ||
*/ | ||
function mergeEdges(edges, object) { | ||
function mergeEdges(edges, object, key) { | ||
if (!object) return; | ||
for (var k in object) { | ||
object[k].forEach(function (value) { | ||
if (key) { | ||
var target = object[key]; | ||
if (target) target.forEach(function (value) { | ||
return edges.add(value); | ||
}); | ||
} else { | ||
for (var k in object) { | ||
object[k].forEach(function (value) { | ||
return edges.add(value); | ||
}); | ||
} | ||
} | ||
@@ -223,2 +232,9 @@ } | ||
if (type === 'selfLoops') { | ||
mergeEdges(edges, nodeData.out, node); | ||
mergeEdges(edges, nodeData.undirectedOut, node); | ||
return; | ||
} | ||
if (type === 'mixed' || type === 'directed') { | ||
@@ -225,0 +241,0 @@ |
{ | ||
"name": "graphology", | ||
"version": "0.1.1", | ||
"version": "0.2.0", | ||
"description": "A robust and multipurpose Graph object for JavaScript.", | ||
@@ -20,3 +20,7 @@ "main": "dist/index.js", | ||
"keywords": [ | ||
"graph" | ||
"graph", | ||
"graph theory", | ||
"directed", | ||
"undirected", | ||
"network" | ||
], | ||
@@ -23,0 +27,0 @@ "repository": { |
@@ -5,4 +5,35 @@ [![Build Status](https://travis-ci.org/graphology/graphology.svg)](https://travis-ci.org/graphology/graphology) | ||
A robust & multipurpose Graph object for JavaScript. | ||
`graphology` is a specification for a robust & multipurpose JavaScript `Graph` object and aiming at supporting various kinds of graphs under a same unified interface. | ||
Current spec [here](https://graphology.github.io). | ||
You will also find here the source for the reference implementation of this specification. | ||
## Installation | ||
``` | ||
npm install graphology | ||
``` | ||
## Documentation | ||
Full documentation for the library/specs is available [here](https://graphology.github.io). | ||
## Contribution | ||
Contributions are obviously welcome. Just be sure to lint & add/run relevant unit tests. | ||
``` | ||
# Installing locally | ||
git clone git@github.com:graphology/graphology.git | ||
cd graphology | ||
npm install | ||
# Linting | ||
npm run lint | ||
# Running the unit tests | ||
npm test | ||
# Building & Distribution | ||
npm run build | ||
npm run dist | ||
``` |
@@ -24,3 +24,3 @@ 'use strict'; | ||
var METHODS = ['getNodeAttribute', 'getNodeAttributes', 'getEdgeAttribute', 'getEdgeAttributes', 'setNodeAttribute', 'setEdgeAttribute', 'updateNodeAttribute', 'updateEdgeAttribute', 'replaceNodeAttributes', 'replaceEdgeAttributes', 'mergeNodeAttributes', 'mergeEdgeAttributes']; | ||
var METHODS = ['getNodeAttribute', 'getNodeAttributes', 'hasNodeAttribute', 'getEdgeAttribute', 'getEdgeAttributes', 'hasEdgeAttribute', 'setNodeAttribute', 'setEdgeAttribute', 'updateNodeAttribute', 'updateEdgeAttribute', 'replaceNodeAttributes', 'replaceEdgeAttributes', 'mergeNodeAttributes', 'mergeEdgeAttributes']; | ||
@@ -135,2 +135,40 @@ function attributes(Graph, checkers) { | ||
'#.hasNodeAttribute': { | ||
'it should correctly return whether the attribute is set.': function itShouldCorrectlyReturnWhetherTheAttributeIsSet() { | ||
var graph = new Graph(); | ||
graph.addNode('John', { age: 20 }); | ||
_assert2.default.strictEqual(graph.hasNodeAttribute('John', 'age'), true); | ||
_assert2.default.strictEqual(graph.hasNodeAttribute('John', 'eyes'), false); | ||
}, | ||
'it does not fail with typical prototypal properties.': function itDoesNotFailWithTypicalPrototypalProperties() { | ||
var graph = new Graph(); | ||
graph.addNode('John', { age: 20 }); | ||
_assert2.default.strictEqual(graph.hasNodeAttribute('John', 'toString'), false); | ||
} | ||
}, | ||
'#.hasEdgeAttribute': { | ||
'it should correctly return whether the attribute is set.': function itShouldCorrectlyReturnWhetherTheAttributeIsSet() { | ||
var graph = new Graph(); | ||
graph.addNodesFrom(['John', 'Martha']); | ||
graph.addEdgeWithKey('J->M', 'John', 'Martha', { weight: 10 }); | ||
_assert2.default.strictEqual(graph.hasEdgeAttribute('J->M', 'weight'), true); | ||
_assert2.default.strictEqual(graph.hasEdgeAttribute('J->M', 'type'), false); | ||
}, | ||
'it does not fail with typical prototypal properties.': function itDoesNotFailWithTypicalPrototypalProperties() { | ||
var graph = new Graph(); | ||
graph.addNodesFrom(['John', 'Martha']); | ||
graph.addEdgeWithKey('J->M', 'John', 'Martha', { weight: 10 }); | ||
_assert2.default.strictEqual(graph.hasEdgeAttribute('J->M', 'toString'), false); | ||
} | ||
}, | ||
'#.setNodeAttribute': { | ||
@@ -137,0 +175,0 @@ |
@@ -169,83 +169,2 @@ 'use strict'; | ||
/** | ||
* onDuplicateEdge | ||
*/ | ||
'onDuplicateEdge': { | ||
'providing a non-function truthy value should throw.': function providingANonFunctionTruthyValueShouldThrow() { | ||
_assert2.default.throws(function () { | ||
var graph = new Graph(null, { onDuplicateEdge: 'test' }); | ||
}, invalid()); | ||
}, | ||
'the callback should fire if the user add the same edge twice.': function theCallbackShouldFireIfTheUserAddTheSameEdgeTwice() { | ||
var callback = (0, _helpers.spy)(function (g, data) { | ||
(0, _assert2.default)(g instanceof Graph); | ||
_assert2.default.deepEqual(data.attributes, { type: 'KNOWS' }); | ||
_assert2.default.strictEqual(data.source, 'John'); | ||
_assert2.default.strictEqual(data.target, 'Martha'); | ||
_assert2.default.strictEqual(data.undirected, false); | ||
g.updateEdgeAttribute(data.source, data.target, 'weight', function (x) { | ||
return (x || 1) + 1; | ||
}); | ||
}); | ||
var graph = new Graph(null, { onDuplicateEdge: callback }); | ||
graph.addNodesFrom(['John', 'Martha']); | ||
var edge = graph.addEdge('John', 'Martha', { type: 'KNOWS' }); | ||
_assert2.default.doesNotThrow(function () { | ||
graph.addEdge('John', 'Martha', { type: 'KNOWS' }); | ||
}); | ||
_assert2.default.strictEqual(graph.size, 1); | ||
_assert2.default.deepEqual(graph.getEdgeAttributes('John', 'Martha'), { type: 'KNOWS', weight: 2 }); | ||
(0, _assert2.default)(callback.called); | ||
(0, _assert2.default)(callback.times, 1); | ||
} | ||
}, | ||
/** | ||
* onDuplicateNode | ||
*/ | ||
'onDuplicateNode': { | ||
'providing a non-function truthy value should throw.': function providingANonFunctionTruthyValueShouldThrow() { | ||
_assert2.default.throws(function () { | ||
var graph = new Graph(null, { onDuplicateNode: 'test' }); | ||
}, invalid()); | ||
}, | ||
'the callback should fire if the user add the same node twice.': function theCallbackShouldFireIfTheUserAddTheSameNodeTwice() { | ||
var callback = (0, _helpers.spy)(function (g, data) { | ||
(0, _assert2.default)(g instanceof Graph); | ||
_assert2.default.strictEqual(data.key, 'John'); | ||
_assert2.default.deepEqual(data.attributes, { age: 34 }); | ||
g.updateNodeAttribute('John', 'occurrences', function (x) { | ||
return (x || 1) + 1; | ||
}); | ||
}); | ||
var graph = new Graph(null, { onDuplicateNode: callback }); | ||
graph.addNode('John', { age: 34 }); | ||
_assert2.default.doesNotThrow(function () { | ||
graph.addNode('John', { age: 34 }); | ||
}); | ||
_assert2.default.strictEqual(graph.order, 1); | ||
_assert2.default.deepEqual(graph.getNodeAttributes('John'), { age: 34, occurrences: 2 }); | ||
(0, _assert2.default)(callback.called); | ||
(0, _assert2.default)(callback.times, 1); | ||
} | ||
}, | ||
/** | ||
* type | ||
@@ -252,0 +171,0 @@ */ |
@@ -170,3 +170,3 @@ 'use strict'; | ||
var graphWithSelfLoops = new Graph(null, { multi: true }); | ||
graphWithSelfLoops.addNodesFrom(['John', 'Tabitha', 'Alone']); | ||
graphWithSelfLoops.addNodesFrom(['John', 'Tabitha', 'Marcia', 'Alone']); | ||
graphWithSelfLoops.addEdgeWithKey('J->T', 'John', 'Tabitha'); | ||
@@ -176,9 +176,14 @@ graphWithSelfLoops.addEdgeWithKey('J1', 'John', 'John'); | ||
graphWithSelfLoops.addEdgeWithKey('T1', 'Tabitha', 'Tabitha'); | ||
graphWithSelfLoops.addEdgeWithKey('M1', 'Marcia', 'Marcia'); | ||
var SELF_LOOPS_TEST_DATA = { | ||
selfLoops: { | ||
all: ['J1', 'J2', 'T1'], | ||
all: ['J1', 'J2', 'T1', 'M1'], | ||
node: { | ||
key: 'John', | ||
loops: ['J1', 'J2'] | ||
}, | ||
bunch: { | ||
keys: ['John', 'Tabitha'], | ||
edges: ['J1', 'J2', 'T1'] | ||
} | ||
@@ -302,2 +307,11 @@ } | ||
_assert2.default.deepEqual(graphWithSelfLoops[name]('Alone'), []); | ||
}, | ||
'it should return a bunch of nodes\' relevant edges.': function itShouldReturnABunchOfNodesRelevantEdges() { | ||
(0, _helpers.testBunches)(data.bunch.keys, function (bunch) { | ||
var edges = graphWithSelfLoops[name](bunch); | ||
(0, _assert2.default)((0, _helpers.sameMembers)(edges, data.bunch.edges)); | ||
_assert2.default.deepEqual(graphWithSelfLoops[name](['Alone']), []); | ||
}); | ||
} | ||
@@ -316,2 +330,10 @@ }), _defineProperty(_ref3, '#.' + counterName, { | ||
_assert2.default.deepEqual(graphWithSelfLoops[counterName]('Alone'), 0); | ||
}, | ||
'it should count a bunch of nodes\' relevant edges.': function itShouldCountABunchOfNodesRelevantEdges() { | ||
(0, _helpers.testBunches)(data.bunch.keys, function (bunch) { | ||
_assert2.default.strictEqual(graphWithSelfLoops[counterName](bunch), data.bunch.edges.length); | ||
_assert2.default.deepEqual(graphWithSelfLoops[counterName](['Alone']), 0); | ||
}); | ||
} | ||
@@ -318,0 +340,0 @@ }), _ref3; |
@@ -65,2 +65,32 @@ 'use strict'; | ||
'#.mergeNode': { | ||
'it should add the node if it does not exist yet.': function itShouldAddTheNodeIfItDoesNotExistYet() { | ||
var graph = new Graph(); | ||
graph.mergeNode('John'); | ||
_assert2.default.deepEqual(graph.nodes(), ['John']); | ||
}, | ||
'it should do nothing if the node already exists.': function itShouldDoNothingIfTheNodeAlreadyExists() { | ||
var graph = new Graph(); | ||
graph.addNode('John'); | ||
graph.mergeNode('John'); | ||
_assert2.default.deepEqual(graph.nodes(), ['John']); | ||
}, | ||
'it should merge the attributes.': function itShouldMergeTheAttributes() { | ||
var graph = new Graph(); | ||
graph.addNode('John', { eyes: 'blue' }); | ||
graph.mergeNode('John', { age: 15 }); | ||
_assert2.default.deepEqual(graph.nodes(), ['John']); | ||
_assert2.default.deepEqual(graph.getNodeAttributes('John'), { | ||
eyes: 'blue', | ||
age: 15 | ||
}); | ||
} | ||
}, | ||
'#.addNodesFrom': { | ||
@@ -288,2 +318,59 @@ | ||
'#.mergeEdge': { | ||
'it should add the edge if it does not yet exist.': function itShouldAddTheEdgeIfItDoesNotYetExist() { | ||
var graph = new Graph(); | ||
graph.addNodesFrom(['John', 'Martha']); | ||
graph.mergeEdge('John', 'Martha'); | ||
_assert2.default.strictEqual(graph.size, 1); | ||
_assert2.default.strictEqual(graph.hasEdge('John', 'Martha'), true); | ||
}, | ||
'it should do nothing if the edge already exists.': function itShouldDoNothingIfTheEdgeAlreadyExists() { | ||
var graph = new Graph(); | ||
graph.addNodesFrom(['John', 'Martha']); | ||
graph.addEdge('John', 'Martha'); | ||
graph.mergeEdge('John', 'Martha'); | ||
_assert2.default.strictEqual(graph.size, 1); | ||
_assert2.default.strictEqual(graph.hasEdge('John', 'Martha'), true); | ||
}, | ||
'it should merge existing attributes if any.': function itShouldMergeExistingAttributesIfAny() { | ||
var graph = new Graph(); | ||
graph.addNodesFrom(['John', 'Martha']); | ||
graph.addEdge('John', 'Martha', { type: 'KNOWS' }); | ||
graph.mergeEdge('John', 'Martha', { weight: 2 }); | ||
_assert2.default.strictEqual(graph.size, 1); | ||
_assert2.default.strictEqual(graph.hasEdge('John', 'Martha'), true); | ||
_assert2.default.deepEqual(graph.getEdgeAttributes('John', 'Martha'), { | ||
type: 'KNOWS', | ||
weight: 2 | ||
}); | ||
}, | ||
'it should add missing nodes in the path.': function itShouldAddMissingNodesInThePath() { | ||
var graph = new Graph(); | ||
graph.mergeEdge('John', 'Martha'); | ||
_assert2.default.strictEqual(graph.order, 2); | ||
_assert2.default.strictEqual(graph.size, 1); | ||
_assert2.default.deepEqual(graph.nodes(), ['John', 'Martha']); | ||
}, | ||
'it should throw in case of inconsistencies.': function itShouldThrowInCaseOfInconsistencies() { | ||
var graph = new Graph(); | ||
graph.mergeEdgeWithKey('J->M', 'John', 'Martha'); | ||
_assert2.default.throws(function () { | ||
graph.mergeEdgeWithKey('J->M', 'John', 'Thomas'); | ||
}, usage()); | ||
} | ||
}, | ||
'#.dropEdge': { | ||
@@ -290,0 +377,0 @@ |
@@ -253,3 +253,3 @@ 'use strict'; | ||
'#.relatedNode': { | ||
'#.opposite': { | ||
@@ -261,7 +261,7 @@ 'it should throw if either the node or the edge is not found in the graph.': function itShouldThrowIfEitherTheNodeOrTheEdgeIsNotFoundInTheGraph() { | ||
_assert2.default.throws(function () { | ||
graph.relatedNode('Jeremy', 'T->J'); | ||
graph.opposite('Jeremy', 'T->J'); | ||
}, notFound()); | ||
_assert2.default.throws(function () { | ||
graph.relatedNode('Thomas', 'T->J'); | ||
graph.opposite('Thomas', 'T->J'); | ||
}, notFound()); | ||
@@ -276,3 +276,3 @@ }, | ||
_assert2.default.throws(function () { | ||
graph.relatedNode('Thomas', 'I->E'); | ||
graph.opposite('Thomas', 'I->E'); | ||
}, notFound()); | ||
@@ -286,3 +286,3 @@ }, | ||
_assert2.default.strictEqual(graph.relatedNode('Thomas', edge), 'Estelle'); | ||
_assert2.default.strictEqual(graph.opposite('Thomas', edge), 'Estelle'); | ||
} | ||
@@ -289,0 +289,0 @@ }, |
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
243688
5317
39