@parcel/graph 2.0.2-nightly.2534 → 2.0.2-nightly.2548

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.
@@ -0,0 +1,280 @@
1
+ // @flow strict-local
2
+
3
+ import assert from 'assert';
4
+ import path from 'path';
5
+ import {Worker} from 'worker_threads';
6
+
7
+ import AdjacencyList, {NodeTypeMap, EdgeTypeMap} from '../src/AdjacencyList';
8
+ import {toNodeId} from '../src/types';
9
+
10
+ describe('AdjacencyList', () => {
11
+ it('constructor should initialize an empty graph', () => {
12
+ let stats = new AdjacencyList().stats;
13
+ assert(stats.nodes === 0);
14
+ assert(stats.edges === 0);
15
+ });
16
+
17
+ it('addNode should add a node to the graph', () => {
18
+ let graph = new AdjacencyList();
19
+ let id = graph.addNode();
20
+ assert.equal(id, 0);
21
+ assert.equal(graph.stats.nodes, 1);
22
+ });
23
+
24
+ it('addNode should resize nodes array when necessary', () => {
25
+ let graph = new AdjacencyList();
26
+ let size = graph.serialize().nodes.byteLength;
27
+ let a = graph.addNode();
28
+ let b = graph.addNode();
29
+ assert(size < (size = graph.serialize().nodes.byteLength));
30
+ graph.addEdge(a, b, 1);
31
+ graph.addEdge(a, b, 2);
32
+ graph.addEdge(a, b, 3);
33
+ graph.addEdge(a, b, 4);
34
+ assert(size < graph.serialize().nodes.byteLength);
35
+ });
36
+
37
+ it('removeEdge should remove an edge from the graph', () => {
38
+ let graph = new AdjacencyList();
39
+ let node0 = graph.addNode();
40
+ let node1 = graph.addNode();
41
+ let node2 = graph.addNode();
42
+ let node3 = graph.addNode();
43
+ let node4 = graph.addNode();
44
+ let node5 = graph.addNode();
45
+ let node6 = graph.addNode();
46
+ graph.addEdge(node0, node1);
47
+ graph.addEdge(node2, node1);
48
+ // this will get removed
49
+ graph.addEdge(node3, node1);
50
+ graph.addEdge(node4, node1);
51
+ graph.addEdge(node5, node1);
52
+ graph.addEdge(node6, node1);
53
+
54
+ assert.deepEqual(graph.getNodeIdsConnectedTo(node1), [0, 2, 3, 4, 5, 6]);
55
+
56
+ graph.removeEdge(node3, node1);
57
+ assert.deepEqual(graph.getNodeIdsConnectedTo(node1), [0, 2, 4, 5, 6]);
58
+ });
59
+
60
+ it('removeEdge should remove an edge of a specific type from the graph', () => {
61
+ let graph = new AdjacencyList();
62
+ let a = graph.addNode();
63
+ let b = graph.addNode();
64
+ let c = graph.addNode();
65
+ let d = graph.addNode();
66
+ graph.addEdge(a, b);
67
+ graph.addEdge(a, b, 2);
68
+ graph.addEdge(a, b, 3);
69
+ graph.addEdge(a, c);
70
+ graph.addEdge(a, d, 3);
71
+ assert.equal(graph.stats.edges, 5);
72
+ assert.ok(graph.hasEdge(a, b));
73
+ assert.ok(graph.hasEdge(a, b, 2));
74
+ assert.ok(graph.hasEdge(a, b, 3));
75
+ assert.ok(graph.hasEdge(a, c));
76
+ assert.ok(graph.hasEdge(a, d, 3));
77
+ assert.deepEqual(Array.from(graph.getAllEdges()), [
78
+ {from: a, to: b, type: 1},
79
+ {from: a, to: b, type: 2},
80
+ {from: a, to: b, type: 3},
81
+ {from: a, to: c, type: 1},
82
+ {from: a, to: d, type: 3},
83
+ ]);
84
+
85
+ graph.removeEdge(a, b, 2);
86
+ assert.equal(graph.stats.edges, 4);
87
+ assert.ok(graph.hasEdge(a, b));
88
+ assert.equal(graph.hasEdge(a, b, 2), false);
89
+ assert.ok(graph.hasEdge(a, b, 3));
90
+ assert.ok(graph.hasEdge(a, c));
91
+ assert.ok(graph.hasEdge(a, d, 3));
92
+ assert.deepEqual(Array.from(graph.getAllEdges()), [
93
+ {from: a, to: b, type: 1},
94
+ {from: a, to: b, type: 3},
95
+ {from: a, to: c, type: 1},
96
+ {from: a, to: d, type: 3},
97
+ ]);
98
+ });
99
+
100
+ it('addEdge should add an edge to the graph', () => {
101
+ let graph = new AdjacencyList();
102
+ let a = graph.addNode();
103
+ let b = graph.addNode();
104
+ graph.addEdge(a, b);
105
+ assert.equal(graph.stats.nodes, 2);
106
+ assert.equal(graph.stats.edges, 1);
107
+ assert.ok(graph.hasEdge(a, b));
108
+ });
109
+
110
+ it('addEdge should add multiple edges from a node in order', () => {
111
+ let graph = new AdjacencyList();
112
+ let a = graph.addNode();
113
+ let b = graph.addNode();
114
+ let c = graph.addNode();
115
+ let d = graph.addNode();
116
+ graph.addEdge(a, b);
117
+ graph.addEdge(a, d);
118
+ graph.addEdge(a, c);
119
+ assert.deepEqual(graph.getNodeIdsConnectedFrom(a), [b, d, c]);
120
+ });
121
+
122
+ it('addEdge should add multiple edges to a node in order', () => {
123
+ let graph = new AdjacencyList();
124
+ let a = graph.addNode();
125
+ let b = graph.addNode();
126
+ let c = graph.addNode();
127
+ let d = graph.addNode();
128
+ graph.addEdge(a, b);
129
+ graph.addEdge(d, b);
130
+ graph.addEdge(a, d);
131
+ graph.addEdge(c, b);
132
+ assert.deepEqual(graph.getNodeIdsConnectedTo(b), [a, d, c]);
133
+ });
134
+
135
+ it('addEdge should add multiple edges of different types in order', () => {
136
+ let graph = new AdjacencyList();
137
+ let a = graph.addNode();
138
+ let b = graph.addNode();
139
+ graph.addEdge(a, b);
140
+ graph.addEdge(a, b, 1);
141
+ graph.addEdge(a, b, 4);
142
+ graph.addEdge(a, b, 3);
143
+ assert.deepEqual(graph.getNodeIdsConnectedFrom(a), [b]);
144
+ assert.deepEqual(Array.from(graph.getAllEdges()), [
145
+ {from: a, to: b, type: 1},
146
+ {from: a, to: b, type: 4},
147
+ {from: a, to: b, type: 3},
148
+ ]);
149
+ });
150
+
151
+ it('addEdge should return false if an edge is already added', () => {
152
+ let graph = new AdjacencyList();
153
+ let a = graph.addNode();
154
+ let b = graph.addNode();
155
+ assert.equal(graph.addEdge(a, b), true);
156
+ assert.equal(graph.addEdge(a, b), false);
157
+ });
158
+
159
+ it('addEdge should resize edges array when necessary', () => {
160
+ let graph = new AdjacencyList();
161
+ let size = graph.serialize().edges.byteLength;
162
+ let a = graph.addNode();
163
+ let b = graph.addNode();
164
+ graph.addEdge(a, b, 1);
165
+ graph.addEdge(a, b, 2);
166
+ graph.addEdge(a, b, 3);
167
+ assert(size < graph.serialize().edges.byteLength);
168
+ });
169
+
170
+ it('addEdge should error when a node has not been added to the graph', () => {
171
+ let graph = new AdjacencyList();
172
+ assert.throws(() => graph.addEdge(toNodeId(0), toNodeId(1)));
173
+ graph.addNode();
174
+ assert.throws(() => graph.addEdge(toNodeId(0), toNodeId(1)));
175
+ graph.addNode();
176
+ assert.doesNotThrow(() => graph.addEdge(toNodeId(0), toNodeId(1)));
177
+ assert.throws(() => graph.addEdge(toNodeId(0), toNodeId(2)));
178
+ });
179
+
180
+ it('addEdge should error when an unsupported edge type is provided', () => {
181
+ let graph = new AdjacencyList();
182
+ let a = graph.addNode();
183
+ let b = graph.addNode();
184
+ assert.throws(() => graph.addEdge(a, b, 0));
185
+ assert.throws(() => graph.addEdge(a, b, -1));
186
+ assert.doesNotThrow(() => graph.addEdge(a, b, 1));
187
+ });
188
+
189
+ it('addEdge should not replace a deleted edge if the edge was already added', () => {
190
+ // Mock hash fn to generate collisions
191
+ // $FlowFixMe[prop-missing]
192
+ let originalHash = AdjacencyList.prototype.hash;
193
+ // $FlowFixMe[prop-missing]
194
+ AdjacencyList.prototype.hash = () => 1;
195
+
196
+ let graph = new AdjacencyList();
197
+ let n0 = graph.addNode();
198
+ let n1 = graph.addNode();
199
+ let n2 = graph.addNode();
200
+ graph.addEdge(n0, n1, 1);
201
+ graph.addEdge(n1, n2, 1);
202
+ graph.removeEdge(n1, n2, 1);
203
+ assert(graph.addEdge(n0, n1, 1) === false);
204
+ assert(graph.stats.edges === 1);
205
+
206
+ // $FlowFixMe[prop-missing]
207
+ AdjacencyList.prototype.hash = originalHash;
208
+ });
209
+
210
+ it('addEdge should replace a deleted edge', () => {
211
+ // Mock hash fn to generate collisions
212
+ // $FlowFixMe[prop-missing]
213
+ let originalHash = AdjacencyList.prototype.hash;
214
+ // $FlowFixMe[prop-missing]
215
+ AdjacencyList.prototype.hash = () => 1;
216
+
217
+ let graph = new AdjacencyList();
218
+ let n0 = graph.addNode();
219
+ let n1 = graph.addNode();
220
+ graph.addEdge(n0, n1, 2);
221
+ graph.removeEdge(n0, n1, 2);
222
+ assert(graph.addEdge(n0, n1, 2));
223
+ assert(graph.stats.edges === 1);
224
+ assert(graph.stats.deleted === 1);
225
+ // Resize to reclaim deleted edge space.
226
+ graph.resizeEdges(4);
227
+ assert(graph.stats.edges === 1);
228
+ assert(graph.stats.deleted === 0);
229
+
230
+ // $FlowFixMe[prop-missing]
231
+ AdjacencyList.prototype.hash = originalHash;
232
+ });
233
+
234
+ describe('deserialize', function () {
235
+ this.timeout(10000);
236
+
237
+ it('should share the underlying data across worker threads', async () => {
238
+ let graph = new AdjacencyList();
239
+ let n0 = graph.addNode();
240
+ let n1 = graph.addNode();
241
+ graph.addEdge(n0, n1, 1);
242
+ graph.addEdge(n0, n1, 2);
243
+
244
+ let worker = new Worker(
245
+ path.join(__dirname, 'integration/adjacency-list-shared-array.js'),
246
+ );
247
+
248
+ let originalSerialized = graph.serialize();
249
+ let originalNodes = [...originalSerialized.nodes];
250
+ let originalEdges = [...originalSerialized.edges];
251
+ let work = new Promise(resolve => worker.on('message', resolve));
252
+ worker.postMessage(originalSerialized);
253
+ let received = AdjacencyList.deserialize(await work);
254
+ await worker.terminate();
255
+
256
+ assert.deepEqual(received.serialize().nodes, graph.serialize().nodes);
257
+ assert.deepEqual(received.serialize().edges, graph.serialize().edges);
258
+
259
+ originalNodes.forEach((v, i) => {
260
+ if (i < NodeTypeMap.HEADER_SIZE) {
261
+ assert.equal(v, received.serialize().nodes[i]);
262
+ assert.equal(v, graph.serialize().nodes[i]);
263
+ } else {
264
+ assert.equal(v * 2, received.serialize().nodes[i]);
265
+ assert.equal(v * 2, graph.serialize().nodes[i]);
266
+ }
267
+ });
268
+
269
+ originalEdges.forEach((v, i) => {
270
+ if (i < EdgeTypeMap.HEADER_SIZE) {
271
+ assert.equal(v, received.serialize().edges[i]);
272
+ assert.equal(v, graph.serialize().edges[i]);
273
+ } else {
274
+ assert.equal(v * 2, received.serialize().edges[i]);
275
+ assert.equal(v * 2, graph.serialize().edges[i]);
276
+ }
277
+ });
278
+ });
279
+ });
280
+ });
@@ -10,7 +10,7 @@ describe('Graph', () => {
10
10
  it('constructor should initialize an empty graph', () => {
11
11
  let graph = new Graph();
12
12
  assert.deepEqual(graph.nodes, new Map());
13
- assert.deepEqual(graph.getAllEdges(), []);
13
+ assert.deepEqual([...graph.getAllEdges()], []);
14
14
  });
15
15
 
16
16
  it('addNode should add a node to the graph', () => {
@@ -114,7 +114,10 @@ describe('Graph', () => {
114
114
  assert(graph.nodes.has(nodeD));
115
115
  assert(!graph.nodes.has(nodeB));
116
116
  assert(!graph.nodes.has(nodeC));
117
- assert.deepEqual(graph.getAllEdges(), [{from: nodeA, to: nodeD, type: 1}]);
117
+ assert.deepEqual(
118
+ [...graph.getAllEdges()],
119
+ [{from: nodeA, to: nodeD, type: 1}],
120
+ );
118
121
  });
119
122
 
120
123
  it('removing a node recursively deletes orphaned nodes', () => {
@@ -154,7 +157,7 @@ describe('Graph', () => {
154
157
  graph.removeNode(nodeB);
155
158
 
156
159
  assert.deepEqual([...graph.nodes.keys()], [nodeA, nodeC, nodeF]);
157
- assert.deepEqual(graph.getAllEdges(), [
160
+ assert.deepEqual(Array.from(graph.getAllEdges()), [
158
161
  {from: nodeA, to: nodeC, type: 1},
159
162
  {from: nodeC, to: nodeF, type: 1},
160
163
  ]);
@@ -199,7 +202,7 @@ describe('Graph', () => {
199
202
  graph.removeNode(nodeB);
200
203
 
201
204
  assert.deepEqual([...graph.nodes.keys()], [nodeA, nodeC, nodeF]);
202
- assert.deepEqual(graph.getAllEdges(), [
205
+ assert.deepEqual(Array.from(graph.getAllEdges()), [
203
206
  {from: nodeA, to: nodeC, type: 1},
204
207
  {from: nodeC, to: nodeF, type: 1},
205
208
  ]);
@@ -234,7 +237,7 @@ describe('Graph', () => {
234
237
  graph.removeEdge(nodeC, nodeE);
235
238
 
236
239
  assert.deepEqual(nodesBefore, getNodeIds());
237
- assert.deepEqual(graph.getAllEdges(), [
240
+ assert.deepEqual(Array.from(graph.getAllEdges()), [
238
241
  {from: nodeA, to: nodeB, type: 1},
239
242
  {from: nodeB, to: nodeC, type: 1},
240
243
  {from: nodeB, to: nodeD, type: 1},
@@ -277,7 +280,7 @@ describe('Graph', () => {
277
280
  assert(graph.hasNode(nodeB));
278
281
  assert(!graph.hasNode(nodeC));
279
282
  assert(graph.hasNode(nodeD));
280
- assert.deepEqual(graph.getAllEdges(), [
283
+ assert.deepEqual(Array.from(graph.getAllEdges()), [
281
284
  {from: nodeA, to: nodeB, type: 1},
282
285
  {from: nodeA, to: nodeD, type: 1},
283
286
  ]);
@@ -0,0 +1,20 @@
1
+ require('@parcel/babel-register');
2
+ const {parentPort} = require('worker_threads');
3
+ const {
4
+ default: AdjacencyList,
5
+ NodeTypeMap,
6
+ EdgeTypeMap,
7
+ } = require('../../src/AdjacencyList');
8
+
9
+ parentPort.once('message', (serialized) => {
10
+ let graph = AdjacencyList.deserialize(serialized);
11
+ serialized.nodes.forEach((v, i) => {
12
+ if (i < NodeTypeMap.HEADER_SIZE) return;
13
+ serialized.nodes[i] = v * 2;
14
+ });
15
+ serialized.edges.forEach((v, i) => {
16
+ if (i < EdgeTypeMap.HEADER_SIZE) return;
17
+ serialized.edges[i] = v * 2;
18
+ });
19
+ parentPort.postMessage(graph.serialize());
20
+ });