@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.
- package/lib/AdjacencyList.js +16 -11
- package/lib/Graph.js +15 -14
- package/package.json +3 -3
- package/src/AdjacencyList.js +32 -13
- package/src/Graph.js +24 -16
- package/test/AdjacencyList.test.js +59 -0
package/lib/AdjacencyList.js
CHANGED
|
@@ -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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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.
|
|
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.
|
|
19
|
+
"@atlaspack/feature-flags": "2.12.1-canary.3567+e0effea53",
|
|
20
20
|
"nullthrows": "^1.1.1"
|
|
21
21
|
},
|
|
22
|
-
"gitHead": "
|
|
22
|
+
"gitHead": "e0effea53c21b3c3e3bc9d368468c562e5f80531"
|
|
23
23
|
}
|
package/src/AdjacencyList.js
CHANGED
|
@@ -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 {
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 =
|
|
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> =
|
|
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(
|
|
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
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
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> =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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?:
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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', () => {
|