graphology
Advanced tools
Comparing version 0.0.2 to 0.0.3
@@ -66,3 +66,4 @@ 'use strict'; | ||
// Handling target | ||
// Handling target (we won't add the edge because it was already taken | ||
// care of with source above) | ||
targetData[inKey] = targetData[inKey] || (map ? new Map() : {}); | ||
@@ -72,6 +73,4 @@ | ||
if (!targetData[inKey].has(source)) targetData[inKey].set(source, commonSet); | ||
targetData[inKey].get(source).add(edge); | ||
} else { | ||
if (!(source in targetData[inKey])) targetData[inKey][source] = commonSet; | ||
targetData[inKey][source].add(edge); | ||
} | ||
@@ -78,0 +77,0 @@ } |
@@ -25,3 +25,2 @@ 'use strict'; | ||
counter: 'countEdges', | ||
element: 'Edge', | ||
type: 'mixed' | ||
@@ -31,3 +30,2 @@ }, { | ||
counter: 'countInEdges', | ||
element: 'InEdge', | ||
type: 'directed', | ||
@@ -38,3 +36,2 @@ direction: 'in' | ||
counter: 'countOutEdges', | ||
element: 'OutEdge', | ||
type: 'directed', | ||
@@ -45,3 +42,2 @@ direction: 'out' | ||
counter: 'countInboundEdges', | ||
element: 'InboundEdge', | ||
type: 'mixed', | ||
@@ -52,3 +48,2 @@ direction: 'in' | ||
counter: 'countOutboundEdges', | ||
element: 'OutbounEdge', | ||
type: 'mixed', | ||
@@ -59,3 +54,2 @@ direction: 'out' | ||
counter: 'countDirectedEdges', | ||
element: 'DirectedEdge', | ||
type: 'directed' | ||
@@ -65,4 +59,7 @@ }, { | ||
counter: 'countUndirectedEdges', | ||
element: 'UndirectedEdge', | ||
type: 'undirected' | ||
}, { | ||
name: 'selfLoops', | ||
counter: 'countSelfLoops', | ||
type: 'selfLoops' | ||
}]; | ||
@@ -209,3 +206,3 @@ | ||
if (data.undirected === (type === 'undirected')) { | ||
if (type === 'selfLoops' === (data.source === data.target) && !!data.undirected === (type === 'undirected')) { | ||
@@ -223,3 +220,3 @@ if (!count) list.push(edge); | ||
if (data.undirected === (type === 'undirected')) { | ||
if (type === 'selfLoops' === (data.source === data.target) && !!data.undirected === (type === 'undirected')) { | ||
@@ -260,22 +257,31 @@ if (!count) list.push(edge); | ||
if (type === 'mixed' || type === 'directed') { | ||
if (type === 'mixed' || type === 'directed' || type === 'selfLoops') { | ||
if (!direction || direction === 'in') { | ||
if (count) nb += countEdges(nodeData.in);else edges = edges.concat(collectEdges(nodeData.in)); | ||
if (count && type !== 'selfLoops') nb += countEdges(nodeData.in);else edges = edges.concat(collectEdges(nodeData.in)); | ||
} | ||
if (!direction || direction === 'out') { | ||
if (count) nb += countEdges(nodeData.out);else edges = edges.concat(collectEdges(nodeData.out)); | ||
if (count && type !== 'selfLoops') nb += countEdges(nodeData.out);else edges = edges.concat(collectEdges(nodeData.out)); | ||
} | ||
} | ||
if (type === 'mixed' || type === 'undirected') { | ||
if (type === 'mixed' || type === 'undirected' || type === 'selfLoops') { | ||
if (!direction || direction === 'in') { | ||
if (count) nb += countEdges(nodeData.undirectedIn);else edges = edges.concat(collectEdges(nodeData.undirectedIn)); | ||
if (count && type !== 'selfLoops') nb += countEdges(nodeData.undirectedIn);else edges = edges.concat(collectEdges(nodeData.undirectedIn)); | ||
} | ||
if (!direction || direction === 'out') { | ||
if (count) nb += countEdges(nodeData.undirectedOut);else edges = edges.concat(collectEdges(nodeData.undirectedOut)); | ||
if (count && type !== 'selfLoops') nb += countEdges(nodeData.undirectedOut);else edges = edges.concat(collectEdges(nodeData.undirectedOut)); | ||
} | ||
} | ||
// NOTE: this is hardly optimal | ||
if (type === 'selfLoops') { | ||
edges = edges.filter(function (edge) { | ||
return graph.source(edge) === graph.target(edge); | ||
}); | ||
nb = edges.length; | ||
} | ||
return count ? nb : edges; | ||
@@ -282,0 +288,0 @@ } |
@@ -12,4 +12,2 @@ 'use strict'; | ||
// TODO: use boolean constants for direction & type to optimize? | ||
/** | ||
@@ -28,3 +26,2 @@ * Definitions. | ||
counter: 'countNeighbors', | ||
element: 'Neighbor', | ||
type: 'mixed' | ||
@@ -34,3 +31,2 @@ }, { | ||
counter: 'countInNeighbors', | ||
element: 'InNeighbor', | ||
type: 'directed', | ||
@@ -41,3 +37,2 @@ direction: 'in' | ||
counter: 'countOutNeighbors', | ||
element: 'OutNeighbor', | ||
type: 'directed', | ||
@@ -48,3 +43,2 @@ direction: 'out' | ||
counter: 'countInboundNeighbors', | ||
element: 'InboundNeighbor', | ||
type: 'mixed', | ||
@@ -55,3 +49,2 @@ direction: 'in' | ||
counter: 'countOutboundNeighbors', | ||
element: 'OutboundNeighbor', | ||
type: 'mixed', | ||
@@ -62,3 +55,2 @@ direction: 'out' | ||
counter: 'countDirectedNeighbors', | ||
element: 'DirectedNeighbor', | ||
type: 'directed' | ||
@@ -68,3 +60,2 @@ }, { | ||
counter: 'countUndirectedNeighbors', | ||
element: 'UndirectedNeighbor', | ||
type: 'undirected' | ||
@@ -71,0 +62,0 @@ }]; |
@@ -43,5 +43,9 @@ 'use strict'; | ||
* Serialized Node: | ||
* [key, ?attributes] | ||
* {key, ?attributes} | ||
* | ||
* Serialized Edge: | ||
* {key?, source, target, attributes?, undirected?} | ||
* | ||
* Serialized Graph: | ||
* {nodes[], edges?[]} | ||
*/ | ||
@@ -48,0 +52,0 @@ function serializeEdge(key, data) { |
@@ -34,21 +34,22 @@ 'use strict'; | ||
* | ||
* @param {object} [...objects] - Target objects. | ||
* @param {object} target - First object. | ||
* @param {object} [...objects] - Objects to merge. | ||
* @return {object} | ||
*/ | ||
function assign() { | ||
for (var _len = arguments.length, objects = Array(_len), _key = 0; _key < _len; _key++) { | ||
objects[_key] = arguments[_key]; | ||
function assign(target) { | ||
target = target || {}; | ||
for (var _len = arguments.length, objects = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
objects[_key - 1] = arguments[_key]; | ||
} | ||
var o = objects[0] || {}; | ||
for (var i = 1, l = objects.length; i < l; i++) { | ||
for (var i = 0, l = objects.length; i < l; i++) { | ||
if (!objects[i]) continue; | ||
for (var k in objects[i]) { | ||
o[k] = objects[i][k]; | ||
target[k] = objects[i][k]; | ||
} | ||
} | ||
return o; | ||
return target; | ||
} | ||
@@ -55,0 +56,0 @@ |
{ | ||
"name": "graphology", | ||
"version": "0.0.2", | ||
"description": "A robust & multipurpose Graph object for JavaScript.", | ||
"version": "0.0.3", | ||
"description": "A robust and multipurpose Graph object for JavaScript.", | ||
"main": "dist/index.js", | ||
@@ -17,3 +17,3 @@ "scripts": { | ||
"postpublish": "npm run clean", | ||
"prepublish": "npm run dist", | ||
"prepublish": "npm run test && npm run lint && npm run dist", | ||
"test": "mocha -u exports --compilers js:babel-core/register ./test.js" | ||
@@ -20,0 +20,0 @@ }, |
@@ -0,1 +1,3 @@ | ||
[![Build Status](https://travis-ci.org/graphology/graphology.svg)](https://travis-ci.org/graphology/graphology) | ||
# Graphology | ||
@@ -2,0 +4,0 @@ |
@@ -12,5 +12,7 @@ 'use strict'; | ||
var _helpers = require('./helpers'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var CONSTRUCTORS = ['DirectedGraph', 'UndirectedGraph', 'MultiDirectedGraph', 'MultiUndirectedGraph', 'GraphMap', 'DirectedGraphMap', 'UndirectedGraphMap', 'MultiDirectedGraphMap', 'MultiUndirectedGraphMap']; /* eslint no-unused-vars: 0 */ | ||
/* eslint no-unused-vars: 0 */ | ||
/** | ||
@@ -22,4 +24,4 @@ * Graphology Instantiation Specs | ||
*/ | ||
var CONSTRUCTORS = ['DirectedGraph', 'UndirectedGraph', 'MultiDirectedGraph', 'MultiUndirectedGraph', 'GraphMap', 'DirectedGraphMap', 'UndirectedGraphMap', 'MultiDirectedGraphMap', 'MultiUndirectedGraphMap']; | ||
var OPTIONS = [{ map: false, multi: false, type: 'directed' }, { map: false, multi: false, type: 'undirected' }, { map: false, multi: true, type: 'directed' }, { map: false, multi: true, type: 'undirected' }, { map: true, multi: false, type: 'mixed' }, { map: true, multi: false, type: 'directed' }, { map: true, multi: false, type: 'undirected' }, { map: true, multi: true, type: 'directed' }, { map: true, multi: true, type: 'undirected' }]; | ||
@@ -59,2 +61,72 @@ | ||
/** | ||
* allowSelfLoops | ||
*/ | ||
'allowSelfLoops': { | ||
'providing a non-boolean value should throw.': function providingANonBooleanValueShouldThrow() { | ||
_assert2.default.throws(function () { | ||
var graph = new Graph(null, { allowSelfLoops: 'test' }); | ||
}, invalid()); | ||
} | ||
}, | ||
/** | ||
* defaultEdgeAttributes | ||
*/ | ||
'defaultEdgeAttributes': { | ||
'providing something other than a plain object should throw.': function providingSomethingOtherThanAPlainObjectShouldThrow() { | ||
_assert2.default.throws(function () { | ||
var graph = new Graph(null, { defaultEdgeAttributes: 'test' }); | ||
}, invalid()); | ||
}, | ||
'it should set default attributes on edges.': function itShouldSetDefaultAttributesOnEdges() { | ||
var graph = new Graph(null, { defaultEdgeAttributes: { type: 'KNOWS' }, multi: true }); | ||
graph.addNodesFrom(['John', 'Martha']); | ||
var edge = graph.addEdge('John', 'Martha'); | ||
_assert2.default.deepEqual(graph.getEdgeAttributes(edge), { type: 'KNOWS' }); | ||
edge = graph.addEdge('John', 'Martha', { weight: 3 }); | ||
_assert2.default.deepEqual(graph.getEdgeAttributes(edge), { weight: 3, type: 'KNOWS' }); | ||
edge = graph.addEdge('John', 'Martha', { type: 'LIKES' }); | ||
_assert2.default.deepEqual(graph.getEdgeAttributes(edge), { type: 'LIKES' }); | ||
} | ||
}, | ||
/** | ||
* defaultNodeAttributes | ||
*/ | ||
'defaultNodeAttributes': { | ||
'providing something other than a plain object should throw.': function providingSomethingOtherThanAPlainObjectShouldThrow() { | ||
_assert2.default.throws(function () { | ||
var graph = new Graph(null, { defaultNodeAttributes: 'test' }); | ||
}, invalid()); | ||
}, | ||
'it should set default attributes on nodes.': function itShouldSetDefaultAttributesOnNodes() { | ||
var graph = new Graph(null, { defaultNodeAttributes: { eyes: 'blue' } }); | ||
graph.addNode('John'); | ||
_assert2.default.deepEqual(graph.getNodeAttributes('John'), { eyes: 'blue' }); | ||
graph.addNode('Thomas', { age: 23 }); | ||
_assert2.default.deepEqual(graph.getNodeAttributes('Thomas'), { age: 23, eyes: 'blue' }); | ||
graph.addNode('Martha', { eyes: 'green' }); | ||
_assert2.default.deepEqual(graph.getNodeAttributes('Martha'), { eyes: 'green' }); | ||
} | ||
}, | ||
/** | ||
* edgeKeyGenerator | ||
@@ -96,10 +168,41 @@ */ | ||
/** | ||
* type | ||
* onDuplicateEdge | ||
*/ | ||
'type': { | ||
'onDuplicateEdge': { | ||
'providing an invalid type should throw.': function providingAnInvalidTypeShouldThrow() { | ||
'providing a non-function truthy value should throw.': function providingANonFunctionTruthyValueShouldThrow() { | ||
_assert2.default.throws(function () { | ||
var graph = new Graph(null, { type: 'test' }); | ||
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); | ||
} | ||
@@ -109,11 +212,49 @@ }, | ||
/** | ||
* selfLoops | ||
* onDuplicateNode | ||
*/ | ||
'selfLoops': { | ||
'onDuplicateNode': { | ||
'providing a non-boolean value should throw.': function providingANonBooleanValueShouldThrow() { | ||
'providing a non-function truthy value should throw.': function providingANonFunctionTruthyValueShouldThrow() { | ||
_assert2.default.throws(function () { | ||
var graph = new Graph(null, { allowSelfLoops: 'test' }); | ||
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 | ||
*/ | ||
'type': { | ||
'providing an invalid type should throw.': function providingAnInvalidTypeShouldThrow() { | ||
_assert2.default.throws(function () { | ||
var graph = new Graph(null, { type: 'test' }); | ||
}, invalid()); | ||
} | ||
} | ||
@@ -120,0 +261,0 @@ }, |
@@ -26,2 +26,6 @@ 'use strict'; | ||
var SELF_LOOPS_METHODS = ['selfLoops']; | ||
var ALL_METHODS = METHODS.concat(SELF_LOOPS_METHODS); | ||
function edgesIteration(Graph, checkers) { | ||
@@ -166,2 +170,19 @@ var invalid = checkers.invalid; | ||
var graphWithSelfLoops = new Graph(null, { multi: true }); | ||
graphWithSelfLoops.addNodesFrom(['John', 'Tabitha', 'Alone']); | ||
graphWithSelfLoops.addEdgeWithKey('J->T', 'John', 'Tabitha'); | ||
graphWithSelfLoops.addEdgeWithKey('J1', 'John', 'John'); | ||
graphWithSelfLoops.addEdgeWithKey('J2', 'John', 'John'); | ||
graphWithSelfLoops.addEdgeWithKey('T1', 'Tabitha', 'Tabitha'); | ||
var SELF_LOOPS_TEST_DATA = { | ||
selfLoops: { | ||
all: ['J1', 'J2', 'T1'], | ||
node: { | ||
key: 'John', | ||
loops: ['J1', 'J2'] | ||
} | ||
} | ||
}; | ||
function commonTests(name) { | ||
@@ -264,9 +285,43 @@ return _defineProperty({}, '#.' + name, { | ||
function selfLoopsTests(name, data) { | ||
var _ref3; | ||
var counterName = 'count' + (0, _helpers.capitalize)(name); | ||
return _ref3 = {}, _defineProperty(_ref3, '#.' + name, { | ||
'it should return all the relevant edges.': function itShouldReturnAllTheRelevantEdges() { | ||
var edges = graphWithSelfLoops[name](); | ||
_assert2.default.deepEqual(edges, data.all); | ||
}, | ||
'it should return a node\'s relevant self-loops.': function itShouldReturnANodeSRelevantSelfLoops() { | ||
var edges = graphWithSelfLoops[name](data.node.key); | ||
_assert2.default.deepEqual(edges, data.node.loops); | ||
_assert2.default.deepEqual(graphWithSelfLoops[name]('Alone'), []); | ||
} | ||
}), _defineProperty(_ref3, '#.' + counterName, { | ||
'it should count all the relevant edges.': function itShouldCountAllTheRelevantEdges() { | ||
var nb = graphWithSelfLoops[counterName](); | ||
_assert2.default.strictEqual(nb, data.all.length); | ||
}, | ||
'it should count all the relevant self-loops of a node.': function itShouldCountAllTheRelevantSelfLoopsOfANode() { | ||
var nb = graphWithSelfLoops[counterName](data.node.key); | ||
_assert2.default.strictEqual(nb, data.node.loops.length); | ||
_assert2.default.deepEqual(graphWithSelfLoops[counterName]('Alone'), 0); | ||
} | ||
}), _ref3; | ||
} | ||
var tests = {}; | ||
// Common tests | ||
METHODS.forEach(function (name) { | ||
ALL_METHODS.forEach(function (name) { | ||
return (0, _helpers.deepMerge)(tests, commonTests(name)); | ||
}); | ||
METHODS.forEach(function (name) { | ||
ALL_METHODS.forEach(function (name) { | ||
return (0, _helpers.deepMerge)(tests, commonTests('count' + (0, _helpers.capitalize)(name))); | ||
@@ -278,3 +333,5 @@ }); | ||
(0, _helpers.deepMerge)(tests, specificTests(name, TEST_DATA[name])); | ||
}for (var _name in SELF_LOOPS_TEST_DATA) { | ||
(0, _helpers.deepMerge)(tests, selfLoopsTests(_name, SELF_LOOPS_TEST_DATA[_name])); | ||
}return tests; | ||
} |
@@ -289,4 +289,5 @@ 'use strict'; | ||
'it should throw if the edge is not found in the graph.': function itShouldThrowIfTheEdgeIsNotFoundInTheGraph() { | ||
'it should throw if the edge or nodes in the path are not found in the graph.': function itShouldThrowIfTheEdgeOrNodesInThePathAreNotFoundInTheGraph() { | ||
var graph = new Graph(); | ||
graph.addNodesFrom(['John', 'Martha']); | ||
@@ -296,2 +297,14 @@ _assert2.default.throws(function () { | ||
}, notFound()); | ||
_assert2.default.throws(function () { | ||
graph.dropEdge('Forever', 'Alone'); | ||
}, notFound()); | ||
_assert2.default.throws(function () { | ||
graph.dropEdge('John', 'Test'); | ||
}, notFound()); | ||
_assert2.default.throws(function () { | ||
graph.dropEdge('John', 'Martha'); | ||
}, notFound()); | ||
}, | ||
@@ -312,2 +325,17 @@ | ||
_assert2.default.strictEqual(graph.hasDirectedEdge('John', 'Margaret'), false); | ||
}, | ||
'it should be possible to remove an edge using source & target.': function itShouldBePossibleToRemoveAnEdgeUsingSourceTarget() { | ||
var graph = new Graph(); | ||
graph.addNodesFrom(['John', 'Margaret']); | ||
graph.addEdge('John', 'Margaret'); | ||
graph.dropEdge('John', 'Margaret'); | ||
_assert2.default.strictEqual(graph.order, 2); | ||
_assert2.default.strictEqual(graph.size, 0); | ||
_assert2.default.strictEqual(graph.degree('John'), 0); | ||
_assert2.default.strictEqual(graph.degree('Margaret'), 0); | ||
_assert2.default.strictEqual(graph.hasEdge('John', 'Margaret'), false); | ||
_assert2.default.strictEqual(graph.hasDirectedEdge('John', 'Margaret'), false); | ||
} | ||
@@ -380,2 +408,19 @@ }, | ||
_assert2.default.strictEqual(graph.hasEdge(edge), false); | ||
}, | ||
'it should drop every edges between source & target.': function itShouldDropEveryEdgesBetweenSourceTarget() { | ||
var graph = new Graph(null, { multi: true }); | ||
graph.addNodesFrom(['Lindsay', 'Martha']); | ||
graph.addEdge('Lindsay', 'Martha'); | ||
graph.addEdge('Lindsay', 'Martha'); | ||
_assert2.default.strictEqual(graph.size, 2); | ||
_assert2.default.strictEqual(graph.countEdges('Lindsay', 'Martha'), 2); | ||
graph.dropEdges('Lindsay', 'Martha'); | ||
_assert2.default.strictEqual(graph.order, 2); | ||
_assert2.default.strictEqual(graph.size, 0); | ||
_assert2.default.strictEqual(graph.countEdges('Lindsay', 'Martha'), 0); | ||
} | ||
@@ -382,0 +427,0 @@ }, |
@@ -325,2 +325,24 @@ 'use strict'; | ||
'#.selfLoop': { | ||
'it should throw if the edge is not in the graph.': function itShouldThrowIfTheEdgeIsNotInTheGraph() { | ||
var graph = new Graph(); | ||
_assert2.default.throws(function () { | ||
graph.selfLoop('test'); | ||
}, notFound()); | ||
}, | ||
'it should correctly return whether the edge is a self-loop or not.': function itShouldCorrectlyReturnWhetherTheEdgeIsASelfLoopOrNot() { | ||
var graph = new Graph(); | ||
graph.addNode('John'); | ||
graph.addNode('Rachel'); | ||
var selfLoop = graph.addDirectedEdge('John', 'John'), | ||
edge = graph.addUndirectedEdge('John', 'Rachel'); | ||
_assert2.default.strictEqual(graph.selfLoop(selfLoop), true); | ||
_assert2.default.strictEqual(graph.selfLoop(edge), false); | ||
} | ||
}, | ||
'Degree': { | ||
@@ -327,0 +349,0 @@ '#.inDegree': { |
Sorry, the diff of this file is too big to display
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
252555
5422
8