@atlaspack/graph 3.2.1-canary.3565 → 3.2.1-canary.3567

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.
@@ -268,7 +268,7 @@ class AdjacencyList {
268
268
  * Returns `true` if the edge was added,
269
269
  * or `false` if the edge already exists.
270
270
  */
271
- addEdge(from, to, type = 1) {
271
+ addEdge(from, to, type = _Graph.NULL_EDGE_TYPE) {
272
272
  (0, _assert().default)(from < this.#nodes.nextId, `Node ${from} does not exist.`);
273
273
  (0, _assert().default)(to < this.#nodes.nextId, `Node ${to} does not exist.`);
274
274
  (0, _assert().default)(type > 0, `Unsupported edge type ${type}`);
@@ -316,7 +316,7 @@ class AdjacencyList {
316
316
  /**
317
317
  * Check if the graph has an edge connecting the `from` and `to` nodes.
318
318
  */
319
- hasEdge(from, to, type = 1) {
319
+ hasEdge(from, to, type = _Graph.NULL_EDGE_TYPE) {
320
320
  let hasEdge = type => {
321
321
  let hash = this.#edges.hash(from, to, type);
322
322
  return this.#edges.addressOf(hash, from, to, type) !== null;
@@ -335,7 +335,7 @@ class AdjacencyList {
335
335
  *
336
336
  * This method will increment the edge delete count.
337
337
  */
338
- removeEdge(from, to, type = 1) {
338
+ removeEdge(from, to, type = _Graph.NULL_EDGE_TYPE) {
339
339
  let hash = this.#edges.hash(from, to, type);
340
340
  let edge = this.#edges.addressOf(hash, from, to, type);
341
341
 
@@ -429,7 +429,7 @@ class AdjacencyList {
429
429
  * If `type` is an array, return nodes connected by edges of any of those types.
430
430
  * If `type` is `AllEdgeTypes` (`-1`), return nodes connected by edges of any type.
431
431
  */
432
- getNodeIdsConnectedFrom(from, type = 1) {
432
+ getNodeIdsConnectedFrom(from, type = _Graph.NULL_EDGE_TYPE) {
433
433
  let matches = node => type === _Graph.ALL_EDGE_TYPES || (Array.isArray(type) ? type.includes(this.#nodes.typeOf(node)) : type === this.#nodes.typeOf(node));
434
434
  let nodes = [];
435
435
  let seen = new Set();
@@ -467,14 +467,19 @@ class AdjacencyList {
467
467
  node = this.#nodes.next(node);
468
468
  }
469
469
  }
470
- forEachNodeIdConnectedTo(to, fn) {
470
+ forEachNodeIdConnectedTo(to, fn, type = _Graph.NULL_EDGE_TYPE) {
471
+ const matches = node => type === _Graph.ALL_EDGE_TYPES || type === this.#nodes.typeOf(node);
471
472
  let node = this.#nodes.head(to);
472
473
  while (node !== null) {
473
- let edge = this.#nodes.firstIn(node);
474
- while (edge !== null) {
475
- let from = this.#edges.from(edge);
476
- fn(from);
477
- edge = this.#edges.nextIn(edge);
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);
482
+ }
478
483
  }
479
484
  node = this.#nodes.next(node);
480
485
  }
@@ -487,7 +492,7 @@ class AdjacencyList {
487
492
  * If `type` is an array, return nodes connected by edges of any of those types.
488
493
  * If `type` is `AllEdgeTypes` (`-1`), return nodes connected by edges of any type.
489
494
  */
490
- getNodeIdsConnectedTo(to, type = 1) {
495
+ getNodeIdsConnectedTo(to, type = _Graph.NULL_EDGE_TYPE) {
491
496
  let matches = node => type === _Graph.ALL_EDGE_TYPES || (Array.isArray(type) ? type.includes(this.#nodes.typeOf(node)) : type === this.#nodes.typeOf(node));
492
497
  let nodes = [];
493
498
  let seen = new Set();
package/lib/Graph.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = exports.ALL_EDGE_TYPES = void 0;
6
+ exports.default = exports.NULL_EDGE_TYPE = exports.ALL_EDGE_TYPES = void 0;
7
7
  exports.mapVisitor = mapVisitor;
8
8
  var _types = require("./types");
9
9
  var _AdjacencyList = _interopRequireDefault(require("./AdjacencyList"));
@@ -16,6 +16,7 @@ function _nullthrows() {
16
16
  return data;
17
17
  }
18
18
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
+ const NULL_EDGE_TYPE = exports.NULL_EDGE_TYPE = 1;
19
20
  const ALL_EDGE_TYPES = exports.ALL_EDGE_TYPES = -1;
20
21
 
21
22
  /**
@@ -70,7 +71,7 @@ class Graph {
70
71
  getNode(id) {
71
72
  return this.nodes[id];
72
73
  }
73
- addEdge(from, to, type = 1) {
74
+ addEdge(from, to, type = NULL_EDGE_TYPE) {
74
75
  if (Number(type) === 0) {
75
76
  throw new Error(`Edge type "${type}" not allowed`);
76
77
  }
@@ -82,25 +83,25 @@ class Graph {
82
83
  }
83
84
  return this.adjacencyList.addEdge(from, to, type);
84
85
  }
85
- hasEdge(from, to, type = 1) {
86
+ hasEdge(from, to, type = NULL_EDGE_TYPE) {
86
87
  return this.adjacencyList.hasEdge(from, to, type);
87
88
  }
88
- forEachNodeIdConnectedTo(to, fn) {
89
+ forEachNodeIdConnectedTo(to, fn, type = NULL_EDGE_TYPE) {
89
90
  this._assertHasNodeId(to);
90
- this.adjacencyList.forEachNodeIdConnectedTo(to, fn);
91
+ this.adjacencyList.forEachNodeIdConnectedTo(to, fn, type);
91
92
  }
92
- forEachNodeIdConnectedFrom(from, fn, type = ALL_EDGE_TYPES) {
93
+ forEachNodeIdConnectedFrom(from, fn, type = NULL_EDGE_TYPE) {
93
94
  this._assertHasNodeId(from);
94
95
  this.adjacencyList.forEachNodeIdConnectedFromReverse(from, id => {
95
96
  fn(id);
96
97
  return false;
97
98
  }, type);
98
99
  }
99
- getNodeIdsConnectedTo(nodeId, type = 1) {
100
+ getNodeIdsConnectedTo(nodeId, type = NULL_EDGE_TYPE) {
100
101
  this._assertHasNodeId(nodeId);
101
102
  return this.adjacencyList.getNodeIdsConnectedTo(nodeId, type);
102
103
  }
103
- getNodeIdsConnectedFrom(nodeId, type = 1) {
104
+ getNodeIdsConnectedFrom(nodeId, type = NULL_EDGE_TYPE) {
104
105
  this._assertHasNodeId(nodeId);
105
106
  return this.adjacencyList.getNodeIdsConnectedFrom(nodeId, type);
106
107
  }
@@ -127,7 +128,7 @@ class Graph {
127
128
  }
128
129
  this.nodes[nodeId] = null;
129
130
  }
130
- removeEdges(nodeId, type = 1) {
131
+ removeEdges(nodeId, type = NULL_EDGE_TYPE) {
131
132
  if (!this.hasNode(nodeId)) {
132
133
  return;
133
134
  }
@@ -135,7 +136,7 @@ class Graph {
135
136
  this._removeEdge(nodeId, to, type);
136
137
  }
137
138
  }
138
- removeEdge(from, to, type = 1, removeOrphans = true) {
139
+ removeEdge(from, to, type = NULL_EDGE_TYPE, removeOrphans = true) {
139
140
  if (!this.adjacencyList.hasEdge(from, to, type)) {
140
141
  throw new Error(`Edge from ${(0, _types.fromNodeId)(from)} to ${(0, _types.fromNodeId)(to)} not found!`);
141
142
  }
@@ -143,7 +144,7 @@ class Graph {
143
144
  }
144
145
 
145
146
  // Removes edge and node the edge is to if the node is orphaned
146
- _removeEdge(from, to, type = 1, removeOrphans = true) {
147
+ _removeEdge(from, to, type = NULL_EDGE_TYPE, removeOrphans = true) {
147
148
  if (!this.adjacencyList.hasEdge(from, to, type)) {
148
149
  return;
149
150
  }
@@ -183,7 +184,7 @@ class Graph {
183
184
  }
184
185
 
185
186
  // Update a node's downstream nodes making sure to prune any orphaned branches
186
- replaceNodeIdsConnectedTo(fromNodeId, toNodeIds, replaceFilter, type = 1) {
187
+ replaceNodeIdsConnectedTo(fromNodeId, toNodeIds, replaceFilter, type = NULL_EDGE_TYPE) {
187
188
  this._assertHasNodeId(fromNodeId);
188
189
  let outboundEdges = this.getNodeIdsConnectedFrom(fromNodeId, type);
189
190
  let childrenToRemove = new Set(replaceFilter ? outboundEdges.filter(toNodeId => replaceFilter(toNodeId)) : outboundEdges);
@@ -197,7 +198,7 @@ class Graph {
197
198
  this._removeEdge(fromNodeId, child, type);
198
199
  }
199
200
  }
200
- traverse(visit, startNodeId, type = 1) {
201
+ traverse(visit, startNodeId, type = NULL_EDGE_TYPE) {
201
202
  let enter = typeof visit === 'function' ? visit : visit.enter;
202
203
  if (type === ALL_EDGE_TYPES && enter && (typeof visit === 'function' || !visit.exit)) {
203
204
  return this.dfsFast(enter, startNodeId);
@@ -212,7 +213,7 @@ class Graph {
212
213
  filteredTraverse(filter, visit, startNodeId, type) {
213
214
  return this.traverse(mapVisitor(filter, visit), startNodeId, type);
214
215
  }
215
- traverseAncestors(startNodeId, visit, type = 1) {
216
+ traverseAncestors(startNodeId, visit, type = NULL_EDGE_TYPE) {
216
217
  return this.dfs({
217
218
  visit,
218
219
  startNodeId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaspack/graph",
3
- "version": "3.2.1-canary.3565+2b1e35dc3",
3
+ "version": "3.2.1-canary.3567+e0effea53",
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-canary.3565+2b1e35dc3",
19
+ "@atlaspack/feature-flags": "2.12.1-canary.3567+e0effea53",
20
20
  "nullthrows": "^1.1.1"
21
21
  },
22
- "gitHead": "2b1e35dc3d51843fba13edcb958c01406ff355e4"
22
+ "gitHead": "e0effea53c21b3c3e3bc9d368468c562e5f80531"
23
23
  }
@@ -3,7 +3,12 @@ import assert from 'assert';
3
3
  import nullthrows from 'nullthrows';
4
4
  import {SharedBuffer} from './shared-buffer';
5
5
  import {fromNodeId, toNodeId} from './types';
6
- import {ALL_EDGE_TYPES, type NullEdgeType, type AllEdgeTypes} from './Graph';
6
+ import {
7
+ ALL_EDGE_TYPES,
8
+ NULL_EDGE_TYPE,
9
+ type NullEdgeType,
10
+ type AllEdgeTypes,
11
+ } from './Graph';
7
12
  import type {NodeId} from './types';
8
13
 
9
14
  /** The address of the node in the nodes map. */
@@ -116,7 +121,7 @@ const MAX_LINK_TRIES: 3 = 3;
116
121
  * `getInboundEdgesByType` methods.
117
122
  *
118
123
  */
119
- export default class AdjacencyList<TEdgeType: number = 1> {
124
+ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
120
125
  #nodes: NodeTypeMap<TEdgeType | NullEdgeType>;
121
126
  #edges: EdgeTypeMap<TEdgeType | NullEdgeType>;
122
127
 
@@ -363,7 +368,7 @@ export default class AdjacencyList<TEdgeType: number = 1> {
363
368
  addEdge(
364
369
  from: NodeId,
365
370
  to: NodeId,
366
- type: TEdgeType | NullEdgeType = 1,
371
+ type: TEdgeType | NullEdgeType = NULL_EDGE_TYPE,
367
372
  ): boolean {
368
373
  assert(from < this.#nodes.nextId, `Node ${from} does not exist.`);
369
374
  assert(to < this.#nodes.nextId, `Node ${to} does not exist.`);
@@ -433,7 +438,10 @@ export default class AdjacencyList<TEdgeType: number = 1> {
433
438
  hasEdge(
434
439
  from: NodeId,
435
440
  to: NodeId,
436
- type: TEdgeType | NullEdgeType | Array<TEdgeType | NullEdgeType> = 1,
441
+ type:
442
+ | TEdgeType
443
+ | NullEdgeType
444
+ | Array<TEdgeType | NullEdgeType> = NULL_EDGE_TYPE,
437
445
  ): boolean {
438
446
  let hasEdge = (type: TEdgeType | NullEdgeType) => {
439
447
  let hash = this.#edges.hash(from, to, type);
@@ -458,7 +466,7 @@ export default class AdjacencyList<TEdgeType: number = 1> {
458
466
  removeEdge(
459
467
  from: NodeId,
460
468
  to: NodeId,
461
- type: TEdgeType | NullEdgeType = 1,
469
+ type: TEdgeType | NullEdgeType = NULL_EDGE_TYPE,
462
470
  ): void {
463
471
  let hash = this.#edges.hash(from, to, type);
464
472
  let edge = this.#edges.addressOf(hash, from, to, type);
@@ -568,7 +576,7 @@ export default class AdjacencyList<TEdgeType: number = 1> {
568
576
  | AllEdgeTypes
569
577
  | TEdgeType
570
578
  | NullEdgeType
571
- | Array<TEdgeType | NullEdgeType> = 1,
579
+ | Array<TEdgeType | NullEdgeType> = NULL_EDGE_TYPE,
572
580
  ): NodeId[] {
573
581
  let matches = (node) =>
574
582
  type === ALL_EDGE_TYPES ||
@@ -619,14 +627,25 @@ export default class AdjacencyList<TEdgeType: number = 1> {
619
627
  }
620
628
  }
621
629
 
622
- forEachNodeIdConnectedTo(to: NodeId, fn: (nodeId: NodeId) => void) {
630
+ forEachNodeIdConnectedTo(
631
+ to: NodeId,
632
+ fn: (nodeId: NodeId) => boolean | void,
633
+ type: AllEdgeTypes | TEdgeType | NullEdgeType = NULL_EDGE_TYPE,
634
+ ) {
635
+ const matches = (node) =>
636
+ type === ALL_EDGE_TYPES || type === this.#nodes.typeOf(node);
637
+
623
638
  let node = this.#nodes.head(to);
624
639
  while (node !== null) {
625
- let edge = this.#nodes.firstIn(node);
626
- while (edge !== null) {
627
- let from = this.#edges.from(edge);
628
- fn(from);
629
- edge = this.#edges.nextIn(edge);
640
+ if (matches(node)) {
641
+ let edge = this.#nodes.firstIn(node);
642
+ while (edge !== null) {
643
+ let from = this.#edges.from(edge);
644
+ if (fn(from)) {
645
+ return;
646
+ }
647
+ edge = this.#edges.nextIn(edge);
648
+ }
630
649
  }
631
650
  node = this.#nodes.next(node);
632
651
  }
@@ -645,7 +664,7 @@ export default class AdjacencyList<TEdgeType: number = 1> {
645
664
  | AllEdgeTypes
646
665
  | TEdgeType
647
666
  | NullEdgeType
648
- | Array<TEdgeType | NullEdgeType> = 1,
667
+ | Array<TEdgeType | NullEdgeType> = NULL_EDGE_TYPE,
649
668
  ): NodeId[] {
650
669
  let matches = (node) =>
651
670
  type === ALL_EDGE_TYPES ||
package/src/Graph.js CHANGED
@@ -13,14 +13,15 @@ import {BitSet} from './BitSet';
13
13
  import nullthrows from 'nullthrows';
14
14
 
15
15
  export type NullEdgeType = 1;
16
- export type GraphOpts<TNode, TEdgeType: number = 1> = {|
16
+ export const NULL_EDGE_TYPE: NullEdgeType = 1;
17
+ export type GraphOpts<TNode, TEdgeType: number = NullEdgeType> = {|
17
18
  nodes?: Array<TNode | null>,
18
19
  adjacencyList?: SerializedAdjacencyList<TEdgeType>,
19
20
  rootNodeId?: ?NodeId,
20
21
  initialCapacity?: number,
21
22
  |};
22
23
 
23
- export type SerializedGraph<TNode, TEdgeType: number = 1> = {|
24
+ export type SerializedGraph<TNode, TEdgeType: number = NullEdgeType> = {|
24
25
  nodes: Array<TNode | null>,
25
26
  adjacencyList: SerializedAdjacencyList<TEdgeType>,
26
27
  rootNodeId: ?NodeId,
@@ -74,7 +75,7 @@ export type DFSParams<TContext> = {|
74
75
  startNodeId?: ?NodeId,
75
76
  |};
76
77
 
77
- export default class Graph<TNode, TEdgeType: number = 1> {
78
+ export default class Graph<TNode, TEdgeType: number = NullEdgeType> {
78
79
  nodes: Array<TNode | null>;
79
80
  adjacencyList: AdjacencyList<TEdgeType>;
80
81
  rootNodeId: ?NodeId;
@@ -138,7 +139,7 @@ export default class Graph<TNode, TEdgeType: number = 1> {
138
139
  addEdge(
139
140
  from: NodeId,
140
141
  to: NodeId,
141
- type: TEdgeType | NullEdgeType = 1,
142
+ type: TEdgeType | NullEdgeType = NULL_EDGE_TYPE,
142
143
  ): boolean {
143
144
  if (Number(type) === 0) {
144
145
  throw new Error(`Edge type "${type}" not allowed`);
@@ -158,21 +159,28 @@ export default class Graph<TNode, TEdgeType: number = 1> {
158
159
  hasEdge(
159
160
  from: NodeId,
160
161
  to: NodeId,
161
- type?: TEdgeType | NullEdgeType | Array<TEdgeType | NullEdgeType> = 1,
162
+ type?:
163
+ | TEdgeType
164
+ | NullEdgeType
165
+ | Array<TEdgeType | NullEdgeType> = NULL_EDGE_TYPE,
162
166
  ): boolean {
163
167
  return this.adjacencyList.hasEdge(from, to, type);
164
168
  }
165
169
 
166
- forEachNodeIdConnectedTo(to: NodeId, fn: (nodeId: NodeId) => void) {
170
+ forEachNodeIdConnectedTo(
171
+ to: NodeId,
172
+ fn: (nodeId: NodeId) => boolean | void,
173
+ type: AllEdgeTypes | TEdgeType | NullEdgeType = NULL_EDGE_TYPE,
174
+ ) {
167
175
  this._assertHasNodeId(to);
168
176
 
169
- this.adjacencyList.forEachNodeIdConnectedTo(to, fn);
177
+ this.adjacencyList.forEachNodeIdConnectedTo(to, fn, type);
170
178
  }
171
179
 
172
180
  forEachNodeIdConnectedFrom(
173
181
  from: NodeId,
174
182
  fn: (nodeId: NodeId) => void,
175
- type: AllEdgeTypes | TEdgeType | NullEdgeType = ALL_EDGE_TYPES,
183
+ type: AllEdgeTypes | TEdgeType | NullEdgeType = NULL_EDGE_TYPE,
176
184
  ) {
177
185
  this._assertHasNodeId(from);
178
186
 
@@ -192,7 +200,7 @@ export default class Graph<TNode, TEdgeType: number = 1> {
192
200
  | TEdgeType
193
201
  | NullEdgeType
194
202
  | Array<TEdgeType | NullEdgeType>
195
- | AllEdgeTypes = 1,
203
+ | AllEdgeTypes = NULL_EDGE_TYPE,
196
204
  ): Array<NodeId> {
197
205
  this._assertHasNodeId(nodeId);
198
206
 
@@ -205,7 +213,7 @@ export default class Graph<TNode, TEdgeType: number = 1> {
205
213
  | TEdgeType
206
214
  | NullEdgeType
207
215
  | Array<TEdgeType | NullEdgeType>
208
- | AllEdgeTypes = 1,
216
+ | AllEdgeTypes = NULL_EDGE_TYPE,
209
217
  ): Array<NodeId> {
210
218
  this._assertHasNodeId(nodeId);
211
219
 
@@ -236,7 +244,7 @@ export default class Graph<TNode, TEdgeType: number = 1> {
236
244
  this.nodes[nodeId] = null;
237
245
  }
238
246
 
239
- removeEdges(nodeId: NodeId, type: TEdgeType | NullEdgeType = 1) {
247
+ removeEdges(nodeId: NodeId, type: TEdgeType | NullEdgeType = NULL_EDGE_TYPE) {
240
248
  if (!this.hasNode(nodeId)) {
241
249
  return;
242
250
  }
@@ -249,7 +257,7 @@ export default class Graph<TNode, TEdgeType: number = 1> {
249
257
  removeEdge(
250
258
  from: NodeId,
251
259
  to: NodeId,
252
- type: TEdgeType | NullEdgeType = 1,
260
+ type: TEdgeType | NullEdgeType = NULL_EDGE_TYPE,
253
261
  removeOrphans: boolean = true,
254
262
  ) {
255
263
  if (!this.adjacencyList.hasEdge(from, to, type)) {
@@ -265,7 +273,7 @@ export default class Graph<TNode, TEdgeType: number = 1> {
265
273
  _removeEdge(
266
274
  from: NodeId,
267
275
  to: NodeId,
268
- type: TEdgeType | NullEdgeType = 1,
276
+ type: TEdgeType | NullEdgeType = NULL_EDGE_TYPE,
269
277
  removeOrphans: boolean = true,
270
278
  ) {
271
279
  if (!this.adjacencyList.hasEdge(from, to, type)) {
@@ -321,7 +329,7 @@ export default class Graph<TNode, TEdgeType: number = 1> {
321
329
  fromNodeId: NodeId,
322
330
  toNodeIds: $ReadOnlyArray<NodeId>,
323
331
  replaceFilter?: null | ((NodeId) => boolean),
324
- type?: TEdgeType | NullEdgeType = 1,
332
+ type?: TEdgeType | NullEdgeType = NULL_EDGE_TYPE,
325
333
  ): void {
326
334
  this._assertHasNodeId(fromNodeId);
327
335
 
@@ -351,7 +359,7 @@ export default class Graph<TNode, TEdgeType: number = 1> {
351
359
  | TEdgeType
352
360
  | NullEdgeType
353
361
  | Array<TEdgeType | NullEdgeType>
354
- | AllEdgeTypes = 1,
362
+ | AllEdgeTypes = NULL_EDGE_TYPE,
355
363
  ): ?TContext {
356
364
  let enter = typeof visit === 'function' ? visit : visit.enter;
357
365
  if (
@@ -385,7 +393,7 @@ export default class Graph<TNode, TEdgeType: number = 1> {
385
393
  | TEdgeType
386
394
  | NullEdgeType
387
395
  | Array<TEdgeType | NullEdgeType>
388
- | AllEdgeTypes = 1,
396
+ | AllEdgeTypes = NULL_EDGE_TYPE,
389
397
  ): ?TContext {
390
398
  return this.dfs({
391
399
  visit,
@@ -7,6 +7,7 @@ import {Worker} from 'worker_threads';
7
7
 
8
8
  import AdjacencyList, {NodeTypeMap, EdgeTypeMap} from '../src/AdjacencyList';
9
9
  import {toNodeId} from '../src/types';
10
+ import {ALL_EDGE_TYPES} from '../src/Graph';
10
11
 
11
12
  describe('AdjacencyList', () => {
12
13
  it('constructor should initialize an empty graph', () => {
@@ -306,6 +307,26 @@ describe('AdjacencyList', () => {
306
307
  assert.deepEqual(nodeIds, [a, c]);
307
308
  });
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
+
309
330
  it('terminates if the graph is cyclic', () => {
310
331
  const graph = new AdjacencyList();
311
332
  const a = graph.addNode();
@@ -323,6 +344,44 @@ describe('AdjacencyList', () => {
323
344
 
324
345
  assert.deepEqual(nodeIds, [a, c, b]);
325
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
+ });
326
385
  });
327
386
 
328
387
  describe('forEachNodeIdConnectedFromReverse', () => {