@atlaspack/graph 3.2.1-dev.3520 → 3.2.1-dev.3566
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/AdjacencyList.js +28 -7
- package/lib/Graph.js +15 -1
- package/package.json +3 -3
- package/src/AdjacencyList.js +38 -6
- package/src/Graph.js +32 -1
- package/test/AdjacencyList.test.js +214 -0
- package/test/Graph.test.js +48 -0
package/lib/AdjacencyList.js
CHANGED
|
@@ -450,16 +450,36 @@ class AdjacencyList {
|
|
|
450
450
|
}
|
|
451
451
|
return nodes;
|
|
452
452
|
}
|
|
453
|
-
forEachNodeIdConnectedFromReverse(from, fn) {
|
|
453
|
+
forEachNodeIdConnectedFromReverse(from, fn, type = _Graph.ALL_EDGE_TYPES) {
|
|
454
|
+
const matches = node => type === _Graph.ALL_EDGE_TYPES || type === this.#nodes.typeOf(node);
|
|
454
455
|
let node = this.#nodes.head(from);
|
|
455
456
|
while (node !== null) {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
457
|
+
if (matches(node)) {
|
|
458
|
+
let edge = this.#nodes.lastOut(node);
|
|
459
|
+
while (edge !== null) {
|
|
460
|
+
let to = this.#edges.to(edge);
|
|
461
|
+
if (fn(to)) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
edge = this.#edges.prevOut(edge);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
node = this.#nodes.next(node);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
forEachNodeIdConnectedTo(to, fn, type = 1) {
|
|
471
|
+
const matches = node => type === _Graph.ALL_EDGE_TYPES || type === this.#nodes.typeOf(node);
|
|
472
|
+
let node = this.#nodes.head(to);
|
|
473
|
+
while (node !== null) {
|
|
474
|
+
if (matches(node)) {
|
|
475
|
+
let edge = this.#nodes.firstIn(node);
|
|
476
|
+
while (edge !== null) {
|
|
477
|
+
let from = this.#edges.from(edge);
|
|
478
|
+
if (fn(from)) {
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
edge = this.#edges.nextIn(edge);
|
|
461
482
|
}
|
|
462
|
-
edge = this.#edges.prevOut(edge);
|
|
463
483
|
}
|
|
464
484
|
node = this.#nodes.next(node);
|
|
465
485
|
}
|
|
@@ -813,6 +833,7 @@ class SharedTypeMap {
|
|
|
813
833
|
// Trick Flow into believing in `Symbol.iterator`.
|
|
814
834
|
// See https://github.com/facebook/flow/issues/1163#issuecomment-353523840
|
|
815
835
|
/*:: @@iterator(): Iterator<TAddress> { return ({}: any); } */
|
|
836
|
+
|
|
816
837
|
// $FlowFixMe[unsupported-syntax]
|
|
817
838
|
*[Symbol.iterator]() {
|
|
818
839
|
let max = this.count;
|
package/lib/Graph.js
CHANGED
|
@@ -31,7 +31,10 @@ class Graph {
|
|
|
31
31
|
this.nodes = (opts === null || opts === void 0 ? void 0 : opts.nodes) || [];
|
|
32
32
|
this.setRootNodeId(opts === null || opts === void 0 ? void 0 : opts.rootNodeId);
|
|
33
33
|
let adjacencyList = opts === null || opts === void 0 ? void 0 : opts.adjacencyList;
|
|
34
|
-
|
|
34
|
+
let initialCapacity = opts === null || opts === void 0 ? void 0 : opts.initialCapacity;
|
|
35
|
+
this.adjacencyList = adjacencyList ? _AdjacencyList.default.deserialize(adjacencyList) : new _AdjacencyList.default(typeof initialCapacity === 'number' ? {
|
|
36
|
+
initialCapacity
|
|
37
|
+
} : undefined);
|
|
35
38
|
}
|
|
36
39
|
setRootNodeId(id) {
|
|
37
40
|
this.rootNodeId = id;
|
|
@@ -82,6 +85,17 @@ class Graph {
|
|
|
82
85
|
hasEdge(from, to, type = 1) {
|
|
83
86
|
return this.adjacencyList.hasEdge(from, to, type);
|
|
84
87
|
}
|
|
88
|
+
forEachNodeIdConnectedTo(to, fn, type = ALL_EDGE_TYPES) {
|
|
89
|
+
this._assertHasNodeId(to);
|
|
90
|
+
this.adjacencyList.forEachNodeIdConnectedTo(to, fn, type);
|
|
91
|
+
}
|
|
92
|
+
forEachNodeIdConnectedFrom(from, fn, type = ALL_EDGE_TYPES) {
|
|
93
|
+
this._assertHasNodeId(from);
|
|
94
|
+
this.adjacencyList.forEachNodeIdConnectedFromReverse(from, id => {
|
|
95
|
+
fn(id);
|
|
96
|
+
return false;
|
|
97
|
+
}, type);
|
|
98
|
+
}
|
|
85
99
|
getNodeIdsConnectedTo(nodeId, type = 1) {
|
|
86
100
|
this._assertHasNodeId(nodeId);
|
|
87
101
|
return this.adjacencyList.getNodeIdsConnectedTo(nodeId, type);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaspack/graph",
|
|
3
|
-
"version": "3.2.1-dev.
|
|
3
|
+
"version": "3.2.1-dev.3566+facdfb05f",
|
|
4
4
|
"description": "Blazing fast, zero configuration web application bundler",
|
|
5
5
|
"license": "(MIT OR Apache-2.0)",
|
|
6
6
|
"publishConfig": {
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"node": ">= 16.0.0"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@atlaspack/feature-flags": "2.12.1-dev.
|
|
19
|
+
"@atlaspack/feature-flags": "2.12.1-dev.3566+facdfb05f",
|
|
20
20
|
"nullthrows": "^1.1.1"
|
|
21
21
|
},
|
|
22
|
-
"gitHead": "
|
|
22
|
+
"gitHead": "facdfb05f693e50037a82a4afa101adf093fd8c9"
|
|
23
23
|
}
|
package/src/AdjacencyList.js
CHANGED
|
@@ -598,16 +598,46 @@ export default class AdjacencyList<TEdgeType: number = 1> {
|
|
|
598
598
|
forEachNodeIdConnectedFromReverse(
|
|
599
599
|
from: NodeId,
|
|
600
600
|
fn: (nodeId: NodeId) => boolean,
|
|
601
|
+
type: AllEdgeTypes | TEdgeType | NullEdgeType = ALL_EDGE_TYPES,
|
|
601
602
|
) {
|
|
603
|
+
const matches = (node) =>
|
|
604
|
+
type === ALL_EDGE_TYPES || type === this.#nodes.typeOf(node);
|
|
605
|
+
|
|
602
606
|
let node = this.#nodes.head(from);
|
|
603
607
|
while (node !== null) {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
608
|
+
if (matches(node)) {
|
|
609
|
+
let edge = this.#nodes.lastOut(node);
|
|
610
|
+
while (edge !== null) {
|
|
611
|
+
let to = this.#edges.to(edge);
|
|
612
|
+
if (fn(to)) {
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
edge = this.#edges.prevOut(edge);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
node = this.#nodes.next(node);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
forEachNodeIdConnectedTo(
|
|
623
|
+
to: NodeId,
|
|
624
|
+
fn: (nodeId: NodeId) => boolean | void,
|
|
625
|
+
type: AllEdgeTypes | TEdgeType | NullEdgeType = 1,
|
|
626
|
+
) {
|
|
627
|
+
const matches = (node) =>
|
|
628
|
+
type === ALL_EDGE_TYPES || type === this.#nodes.typeOf(node);
|
|
629
|
+
|
|
630
|
+
let node = this.#nodes.head(to);
|
|
631
|
+
while (node !== null) {
|
|
632
|
+
if (matches(node)) {
|
|
633
|
+
let edge = this.#nodes.firstIn(node);
|
|
634
|
+
while (edge !== null) {
|
|
635
|
+
let from = this.#edges.from(edge);
|
|
636
|
+
if (fn(from)) {
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
edge = this.#edges.nextIn(edge);
|
|
609
640
|
}
|
|
610
|
-
edge = this.#edges.prevOut(edge);
|
|
611
641
|
}
|
|
612
642
|
node = this.#nodes.next(node);
|
|
613
643
|
}
|
|
@@ -973,6 +1003,7 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
973
1003
|
// Trick Flow into believing in `Symbol.iterator`.
|
|
974
1004
|
// See https://github.com/facebook/flow/issues/1163#issuecomment-353523840
|
|
975
1005
|
/*:: @@iterator(): Iterator<TAddress> { return ({}: any); } */
|
|
1006
|
+
|
|
976
1007
|
// $FlowFixMe[unsupported-syntax]
|
|
977
1008
|
*[Symbol.iterator](): Iterator<TAddress> {
|
|
978
1009
|
let max = this.count;
|
|
@@ -1086,6 +1117,7 @@ export class NodeTypeMap<TEdgeType> extends SharedTypeMap<
|
|
|
1086
1117
|
get nextId(): NodeId {
|
|
1087
1118
|
return toNodeId(this.data[NodeTypeMap.#NEXT_ID]);
|
|
1088
1119
|
}
|
|
1120
|
+
|
|
1089
1121
|
set nextId(nextId: NodeId) {
|
|
1090
1122
|
this.data[NodeTypeMap.#NEXT_ID] = fromNodeId(nextId);
|
|
1091
1123
|
}
|
package/src/Graph.js
CHANGED
|
@@ -17,6 +17,7 @@ export type GraphOpts<TNode, TEdgeType: number = 1> = {|
|
|
|
17
17
|
nodes?: Array<TNode | null>,
|
|
18
18
|
adjacencyList?: SerializedAdjacencyList<TEdgeType>,
|
|
19
19
|
rootNodeId?: ?NodeId,
|
|
20
|
+
initialCapacity?: number,
|
|
20
21
|
|};
|
|
21
22
|
|
|
22
23
|
export type SerializedGraph<TNode, TEdgeType: number = 1> = {|
|
|
@@ -84,9 +85,12 @@ export default class Graph<TNode, TEdgeType: number = 1> {
|
|
|
84
85
|
this.setRootNodeId(opts?.rootNodeId);
|
|
85
86
|
|
|
86
87
|
let adjacencyList = opts?.adjacencyList;
|
|
88
|
+
let initialCapacity = opts?.initialCapacity;
|
|
87
89
|
this.adjacencyList = adjacencyList
|
|
88
90
|
? AdjacencyList.deserialize(adjacencyList)
|
|
89
|
-
: new AdjacencyList<TEdgeType>(
|
|
91
|
+
: new AdjacencyList<TEdgeType>(
|
|
92
|
+
typeof initialCapacity === 'number' ? {initialCapacity} : undefined,
|
|
93
|
+
);
|
|
90
94
|
}
|
|
91
95
|
|
|
92
96
|
setRootNodeId(id: ?NodeId) {
|
|
@@ -159,6 +163,33 @@ export default class Graph<TNode, TEdgeType: number = 1> {
|
|
|
159
163
|
return this.adjacencyList.hasEdge(from, to, type);
|
|
160
164
|
}
|
|
161
165
|
|
|
166
|
+
forEachNodeIdConnectedTo(
|
|
167
|
+
to: NodeId,
|
|
168
|
+
fn: (nodeId: NodeId) => boolean | void,
|
|
169
|
+
type: AllEdgeTypes | TEdgeType | NullEdgeType = ALL_EDGE_TYPES,
|
|
170
|
+
) {
|
|
171
|
+
this._assertHasNodeId(to);
|
|
172
|
+
|
|
173
|
+
this.adjacencyList.forEachNodeIdConnectedTo(to, fn, type);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
forEachNodeIdConnectedFrom(
|
|
177
|
+
from: NodeId,
|
|
178
|
+
fn: (nodeId: NodeId) => void,
|
|
179
|
+
type: AllEdgeTypes | TEdgeType | NullEdgeType = ALL_EDGE_TYPES,
|
|
180
|
+
) {
|
|
181
|
+
this._assertHasNodeId(from);
|
|
182
|
+
|
|
183
|
+
this.adjacencyList.forEachNodeIdConnectedFromReverse(
|
|
184
|
+
from,
|
|
185
|
+
(id) => {
|
|
186
|
+
fn(id);
|
|
187
|
+
return false;
|
|
188
|
+
},
|
|
189
|
+
type,
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
162
193
|
getNodeIdsConnectedTo(
|
|
163
194
|
nodeId: NodeId,
|
|
164
195
|
type:
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// @flow strict-local
|
|
2
2
|
|
|
3
3
|
import assert from 'assert';
|
|
4
|
+
import sinon from 'sinon';
|
|
4
5
|
import path from 'path';
|
|
5
6
|
import {Worker} from 'worker_threads';
|
|
6
7
|
|
|
7
8
|
import AdjacencyList, {NodeTypeMap, EdgeTypeMap} from '../src/AdjacencyList';
|
|
8
9
|
import {toNodeId} from '../src/types';
|
|
10
|
+
import {ALL_EDGE_TYPES} from '../src/Graph';
|
|
9
11
|
|
|
10
12
|
describe('AdjacencyList', () => {
|
|
11
13
|
it('constructor should initialize an empty graph', () => {
|
|
@@ -272,6 +274,218 @@ describe('AdjacencyList', () => {
|
|
|
272
274
|
assert.ok(graph.hasEdge(b, c, [2, 3]));
|
|
273
275
|
});
|
|
274
276
|
|
|
277
|
+
describe('forEachNodeIdConnectedTo', () => {
|
|
278
|
+
it('iterates no edges if there are none', () => {
|
|
279
|
+
const graph = new AdjacencyList();
|
|
280
|
+
const a = graph.addNode();
|
|
281
|
+
const b = graph.addNode();
|
|
282
|
+
const c = graph.addNode();
|
|
283
|
+
|
|
284
|
+
graph.addEdge(a, b);
|
|
285
|
+
graph.addEdge(c, b);
|
|
286
|
+
|
|
287
|
+
const callback = sinon.spy(() => {});
|
|
288
|
+
graph.forEachNodeIdConnectedTo(c, callback);
|
|
289
|
+
|
|
290
|
+
assert.equal(callback.callCount, 0);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('iterates incoming edges to a node', () => {
|
|
294
|
+
const graph = new AdjacencyList();
|
|
295
|
+
const a = graph.addNode();
|
|
296
|
+
const b = graph.addNode();
|
|
297
|
+
const c = graph.addNode();
|
|
298
|
+
|
|
299
|
+
graph.addEdge(a, b);
|
|
300
|
+
graph.addEdge(c, b);
|
|
301
|
+
|
|
302
|
+
const nodeIds = [];
|
|
303
|
+
graph.forEachNodeIdConnectedTo(b, (id) => {
|
|
304
|
+
nodeIds.push(id);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
assert.deepEqual(nodeIds, [a, c]);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('stops traversal if the return value is true', () => {
|
|
311
|
+
const graph = new AdjacencyList();
|
|
312
|
+
const a = graph.addNode();
|
|
313
|
+
const b = graph.addNode();
|
|
314
|
+
const c = graph.addNode();
|
|
315
|
+
const d = graph.addNode();
|
|
316
|
+
|
|
317
|
+
graph.addEdge(a, d);
|
|
318
|
+
graph.addEdge(b, d);
|
|
319
|
+
graph.addEdge(c, d);
|
|
320
|
+
|
|
321
|
+
const nodeIds = [];
|
|
322
|
+
graph.forEachNodeIdConnectedTo(d, (nodeId) => {
|
|
323
|
+
nodeIds.push(nodeId);
|
|
324
|
+
return true;
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
assert.deepEqual(nodeIds, [a]);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it('terminates if the graph is cyclic', () => {
|
|
331
|
+
const graph = new AdjacencyList();
|
|
332
|
+
const a = graph.addNode();
|
|
333
|
+
const b = graph.addNode();
|
|
334
|
+
const c = graph.addNode();
|
|
335
|
+
|
|
336
|
+
graph.addEdge(a, b);
|
|
337
|
+
graph.addEdge(c, b);
|
|
338
|
+
graph.addEdge(b, b);
|
|
339
|
+
|
|
340
|
+
const nodeIds = [];
|
|
341
|
+
graph.forEachNodeIdConnectedTo(b, (id) => {
|
|
342
|
+
nodeIds.push(id);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
assert.deepEqual(nodeIds, [a, c, b]);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it('respects the edge type', () => {
|
|
349
|
+
const graph = new AdjacencyList();
|
|
350
|
+
const a = graph.addNode();
|
|
351
|
+
const b = graph.addNode();
|
|
352
|
+
const c = graph.addNode();
|
|
353
|
+
|
|
354
|
+
graph.addEdge(a, b);
|
|
355
|
+
graph.addEdge(c, b, 2);
|
|
356
|
+
|
|
357
|
+
const nodeIds = [];
|
|
358
|
+
graph.forEachNodeIdConnectedTo(b, (id) => {
|
|
359
|
+
nodeIds.push(id);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
assert.deepEqual(nodeIds, [a]);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it('iterates all edges if all edge type is provided', () => {
|
|
366
|
+
const graph = new AdjacencyList();
|
|
367
|
+
const a = graph.addNode();
|
|
368
|
+
const b = graph.addNode();
|
|
369
|
+
const c = graph.addNode();
|
|
370
|
+
|
|
371
|
+
graph.addEdge(a, b);
|
|
372
|
+
graph.addEdge(c, b, 2);
|
|
373
|
+
|
|
374
|
+
const nodeIds = [];
|
|
375
|
+
graph.forEachNodeIdConnectedTo(
|
|
376
|
+
b,
|
|
377
|
+
(id) => {
|
|
378
|
+
nodeIds.push(id);
|
|
379
|
+
},
|
|
380
|
+
ALL_EDGE_TYPES,
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
assert.deepEqual(nodeIds, [a, c]);
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
describe('forEachNodeIdConnectedFromReverse', () => {
|
|
388
|
+
it('iterates no edges if there are none', () => {
|
|
389
|
+
const graph = new AdjacencyList();
|
|
390
|
+
const a = graph.addNode();
|
|
391
|
+
const b = graph.addNode();
|
|
392
|
+
const c = graph.addNode();
|
|
393
|
+
|
|
394
|
+
graph.addEdge(a, b);
|
|
395
|
+
graph.addEdge(b, c);
|
|
396
|
+
|
|
397
|
+
const callback = sinon.spy(() => false);
|
|
398
|
+
graph.forEachNodeIdConnectedFromReverse(c, callback);
|
|
399
|
+
|
|
400
|
+
assert.equal(callback.callCount, 0);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it('iterates outgoing edges from a node', () => {
|
|
404
|
+
const graph = new AdjacencyList();
|
|
405
|
+
const a = graph.addNode();
|
|
406
|
+
const b = graph.addNode();
|
|
407
|
+
const c = graph.addNode();
|
|
408
|
+
const d = graph.addNode();
|
|
409
|
+
const e = graph.addNode();
|
|
410
|
+
|
|
411
|
+
graph.addEdge(a, b, 1);
|
|
412
|
+
graph.addEdge(a, c, 2);
|
|
413
|
+
graph.addEdge(b, d, 3);
|
|
414
|
+
graph.addEdge(c, e, 4);
|
|
415
|
+
|
|
416
|
+
const nodeIds = [];
|
|
417
|
+
graph.forEachNodeIdConnectedFromReverse(a, (nodeId) => {
|
|
418
|
+
nodeIds.push(nodeId);
|
|
419
|
+
return false;
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
assert.deepEqual(nodeIds, [b, c]);
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
it('terminates if the graph is cyclic', () => {
|
|
426
|
+
const graph = new AdjacencyList();
|
|
427
|
+
const a = graph.addNode();
|
|
428
|
+
const b = graph.addNode();
|
|
429
|
+
const c = graph.addNode();
|
|
430
|
+
|
|
431
|
+
graph.addEdge(a, b);
|
|
432
|
+
graph.addEdge(a, c);
|
|
433
|
+
graph.addEdge(a, a);
|
|
434
|
+
|
|
435
|
+
const nodeIds = [];
|
|
436
|
+
graph.forEachNodeIdConnectedFromReverse(a, (nodeId) => {
|
|
437
|
+
nodeIds.push(nodeId);
|
|
438
|
+
return false;
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
assert.deepEqual(nodeIds, [a, c, b]);
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
it('stops traversal if the return value is true', () => {
|
|
445
|
+
const graph = new AdjacencyList();
|
|
446
|
+
const a = graph.addNode();
|
|
447
|
+
const b = graph.addNode();
|
|
448
|
+
const c = graph.addNode();
|
|
449
|
+
const d = graph.addNode();
|
|
450
|
+
|
|
451
|
+
graph.addEdge(a, b);
|
|
452
|
+
graph.addEdge(a, c);
|
|
453
|
+
graph.addEdge(a, d);
|
|
454
|
+
|
|
455
|
+
const nodeIds = [];
|
|
456
|
+
graph.forEachNodeIdConnectedFromReverse(a, (nodeId) => {
|
|
457
|
+
nodeIds.push(nodeId);
|
|
458
|
+
return true;
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
assert.deepEqual(nodeIds, [d]);
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it('filters edges by type', () => {
|
|
465
|
+
const graph = new AdjacencyList();
|
|
466
|
+
const a = graph.addNode();
|
|
467
|
+
const b = graph.addNode();
|
|
468
|
+
const c = graph.addNode();
|
|
469
|
+
const d = graph.addNode();
|
|
470
|
+
|
|
471
|
+
graph.addEdge(a, b, 2);
|
|
472
|
+
graph.addEdge(a, c, 2);
|
|
473
|
+
graph.addEdge(a, d);
|
|
474
|
+
|
|
475
|
+
const nodeIds = [];
|
|
476
|
+
graph.forEachNodeIdConnectedFromReverse(
|
|
477
|
+
a,
|
|
478
|
+
(nodeId) => {
|
|
479
|
+
nodeIds.push(nodeId);
|
|
480
|
+
return false;
|
|
481
|
+
},
|
|
482
|
+
2,
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
assert.deepEqual(nodeIds, [c, b]);
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
|
|
275
489
|
describe('deserialize', function () {
|
|
276
490
|
this.timeout(10000);
|
|
277
491
|
|
package/test/Graph.test.js
CHANGED
|
@@ -556,4 +556,52 @@ describe('Graph', () => {
|
|
|
556
556
|
});
|
|
557
557
|
});
|
|
558
558
|
});
|
|
559
|
+
|
|
560
|
+
describe('forEachNodeConnectedTo', () => {
|
|
561
|
+
it('calls the callback for each node connected to the given node', () => {
|
|
562
|
+
const graph = new Graph();
|
|
563
|
+
const a = graph.addNode('0');
|
|
564
|
+
const b = graph.addNode('1');
|
|
565
|
+
const c = graph.addNode('2');
|
|
566
|
+
const d = graph.addNode('3');
|
|
567
|
+
graph.addNode('disconnected-1');
|
|
568
|
+
graph.addNode('disconnected-2');
|
|
569
|
+
graph.addEdge(a, b);
|
|
570
|
+
graph.addEdge(b, c);
|
|
571
|
+
graph.addEdge(b, d);
|
|
572
|
+
graph.addEdge(a, c);
|
|
573
|
+
graph.addEdge(c, d);
|
|
574
|
+
|
|
575
|
+
const order = [];
|
|
576
|
+
graph.forEachNodeIdConnectedTo(d, (node) => {
|
|
577
|
+
order.push(node);
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
assert.deepEqual(order, [b, c]);
|
|
581
|
+
});
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
describe('forEachNodeConnectedFrom', () => {
|
|
585
|
+
it('calls the callback for each node connected from the given node', () => {
|
|
586
|
+
const graph = new Graph();
|
|
587
|
+
const a = graph.addNode('0');
|
|
588
|
+
const b = graph.addNode('1');
|
|
589
|
+
const c = graph.addNode('2');
|
|
590
|
+
const d = graph.addNode('3');
|
|
591
|
+
graph.addNode('disconnected-1');
|
|
592
|
+
graph.addNode('disconnected-2');
|
|
593
|
+
graph.addEdge(a, b);
|
|
594
|
+
graph.addEdge(b, c);
|
|
595
|
+
graph.addEdge(b, d);
|
|
596
|
+
graph.addEdge(a, c);
|
|
597
|
+
graph.addEdge(c, d);
|
|
598
|
+
|
|
599
|
+
const order = [];
|
|
600
|
+
graph.forEachNodeIdConnectedFrom(a, (node) => {
|
|
601
|
+
order.push(node);
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
assert.deepEqual(order, [c, b]);
|
|
605
|
+
});
|
|
606
|
+
});
|
|
559
607
|
});
|