@atlaspack/graph 3.2.1-canary.3354
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/LICENSE +201 -0
- package/lib/AdjacencyList.js +1415 -0
- package/lib/BitSet.js +80 -0
- package/lib/ContentGraph.js +80 -0
- package/lib/Graph.js +521 -0
- package/lib/index.js +54 -0
- package/lib/shared-buffer.js +28 -0
- package/lib/types.js +14 -0
- package/package.json +23 -0
- package/src/AdjacencyList.js +1655 -0
- package/src/BitSet.js +98 -0
- package/src/ContentGraph.js +96 -0
- package/src/Graph.js +740 -0
- package/src/index.js +9 -0
- package/src/shared-buffer.js +23 -0
- package/src/types.js +18 -0
- package/test/AdjacencyList.test.js +322 -0
- package/test/BitSet.test.js +110 -0
- package/test/ContentGraph.test.js +42 -0
- package/test/Graph.test.js +559 -0
- package/test/integration/adjacency-list-shared-array.js +20 -0
package/src/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// @flow strict-local
|
|
2
|
+
|
|
3
|
+
export type {NodeId, ContentKey, Edge} from './types';
|
|
4
|
+
export type {GraphOpts} from './Graph';
|
|
5
|
+
export type {ContentGraphOpts, SerializedContentGraph} from './ContentGraph';
|
|
6
|
+
export {toNodeId, fromNodeId} from './types';
|
|
7
|
+
export {default as Graph, ALL_EDGE_TYPES, mapVisitor} from './Graph';
|
|
8
|
+
export {default as ContentGraph} from './ContentGraph';
|
|
9
|
+
export {BitSet} from './BitSet';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
// Copy from @atlaspack/utils to fix: https://github.com/stackblitz/core/issues/1855
|
|
3
|
+
export let SharedBuffer: Class<ArrayBuffer> | Class<SharedArrayBuffer>;
|
|
4
|
+
|
|
5
|
+
// $FlowFixMe[prop-missing]
|
|
6
|
+
if (process.browser) {
|
|
7
|
+
SharedBuffer = ArrayBuffer;
|
|
8
|
+
// Safari has removed the constructor
|
|
9
|
+
if (typeof SharedArrayBuffer !== 'undefined') {
|
|
10
|
+
let channel = new MessageChannel();
|
|
11
|
+
try {
|
|
12
|
+
// Firefox might throw when sending the Buffer over a MessagePort
|
|
13
|
+
channel.port1.postMessage(new SharedArrayBuffer(0));
|
|
14
|
+
SharedBuffer = SharedArrayBuffer;
|
|
15
|
+
} catch (_) {
|
|
16
|
+
// NOOP
|
|
17
|
+
}
|
|
18
|
+
channel.port1.close();
|
|
19
|
+
channel.port2.close();
|
|
20
|
+
}
|
|
21
|
+
} else {
|
|
22
|
+
SharedBuffer = SharedArrayBuffer;
|
|
23
|
+
}
|
package/src/types.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// @flow strict-local
|
|
2
|
+
|
|
3
|
+
// forcing NodeId to be opaque as it should only be created once
|
|
4
|
+
export type NodeId = number;
|
|
5
|
+
export function toNodeId(x: number): NodeId {
|
|
6
|
+
return x;
|
|
7
|
+
}
|
|
8
|
+
export function fromNodeId(x: NodeId): number {
|
|
9
|
+
return x;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ContentKey = string;
|
|
13
|
+
|
|
14
|
+
export type Edge<TEdgeType: number> = {|
|
|
15
|
+
from: NodeId,
|
|
16
|
+
to: NodeId,
|
|
17
|
+
type: TEdgeType,
|
|
18
|
+
|};
|
|
@@ -0,0 +1,322 @@
|
|
|
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
|
+
let id2 = graph.addNode();
|
|
23
|
+
assert.equal(id2, 1);
|
|
24
|
+
assert.equal(graph.stats.nodes, 2);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('addNode should resize nodes array', () => {
|
|
28
|
+
let graph = new AdjacencyList();
|
|
29
|
+
let size = graph.serialize().nodes.byteLength;
|
|
30
|
+
graph.addNode();
|
|
31
|
+
graph.addNode();
|
|
32
|
+
graph.addNode();
|
|
33
|
+
graph.addNode();
|
|
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('getNodeIdsConnectedTo and getNodeIdsConnectedFrom should remove duplicate values', () => {
|
|
61
|
+
let graph = new AdjacencyList();
|
|
62
|
+
let a = graph.addNode();
|
|
63
|
+
let b = graph.addNode();
|
|
64
|
+
let c = graph.addNode();
|
|
65
|
+
graph.addEdge(a, b);
|
|
66
|
+
graph.addEdge(a, c);
|
|
67
|
+
graph.addEdge(a, b, 2);
|
|
68
|
+
assert.deepEqual(graph.getNodeIdsConnectedFrom(a, -1), [b, c]);
|
|
69
|
+
assert.deepEqual(graph.getNodeIdsConnectedTo(b, -1), [a]);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('removeEdge should remove an edge of a specific type from the graph', () => {
|
|
73
|
+
let graph = new AdjacencyList();
|
|
74
|
+
let a = graph.addNode();
|
|
75
|
+
let b = graph.addNode();
|
|
76
|
+
let c = graph.addNode();
|
|
77
|
+
let d = graph.addNode();
|
|
78
|
+
graph.addEdge(a, b);
|
|
79
|
+
graph.addEdge(a, b, 2);
|
|
80
|
+
graph.addEdge(a, b, 3);
|
|
81
|
+
graph.addEdge(a, c);
|
|
82
|
+
graph.addEdge(a, d, 3);
|
|
83
|
+
assert.equal(graph.stats.edges, 5);
|
|
84
|
+
assert.ok(graph.hasEdge(a, b));
|
|
85
|
+
assert.ok(graph.hasEdge(a, b, 2));
|
|
86
|
+
assert.ok(graph.hasEdge(a, b, 3));
|
|
87
|
+
assert.ok(graph.hasEdge(a, c));
|
|
88
|
+
assert.ok(graph.hasEdge(a, d, 3));
|
|
89
|
+
assert.deepEqual(Array.from(graph.getAllEdges()), [
|
|
90
|
+
{from: a, to: b, type: 1},
|
|
91
|
+
{from: a, to: b, type: 2},
|
|
92
|
+
{from: a, to: b, type: 3},
|
|
93
|
+
{from: a, to: c, type: 1},
|
|
94
|
+
{from: a, to: d, type: 3},
|
|
95
|
+
]);
|
|
96
|
+
|
|
97
|
+
graph.removeEdge(a, b, 2);
|
|
98
|
+
assert.equal(graph.stats.edges, 4);
|
|
99
|
+
assert.ok(graph.hasEdge(a, b));
|
|
100
|
+
assert.equal(graph.hasEdge(a, b, 2), false);
|
|
101
|
+
assert.ok(graph.hasEdge(a, b, 3));
|
|
102
|
+
assert.ok(graph.hasEdge(a, c));
|
|
103
|
+
assert.ok(graph.hasEdge(a, d, 3));
|
|
104
|
+
assert.deepEqual(Array.from(graph.getAllEdges()), [
|
|
105
|
+
{from: a, to: b, type: 1},
|
|
106
|
+
{from: a, to: b, type: 3},
|
|
107
|
+
{from: a, to: c, type: 1},
|
|
108
|
+
{from: a, to: d, type: 3},
|
|
109
|
+
]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('addEdge should add an edge to the graph', () => {
|
|
113
|
+
let graph = new AdjacencyList();
|
|
114
|
+
let a = graph.addNode();
|
|
115
|
+
let b = graph.addNode();
|
|
116
|
+
graph.addEdge(a, b);
|
|
117
|
+
assert.equal(graph.stats.nodes, 2);
|
|
118
|
+
assert.equal(graph.stats.edges, 1);
|
|
119
|
+
assert.ok(graph.hasEdge(a, b));
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('addEdge should add multiple edges from 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(a, d);
|
|
130
|
+
graph.addEdge(a, c);
|
|
131
|
+
assert.deepEqual(graph.getNodeIdsConnectedFrom(a), [b, d, c]);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('addEdge should add multiple edges to a node in order', () => {
|
|
135
|
+
let graph = new AdjacencyList();
|
|
136
|
+
let a = graph.addNode();
|
|
137
|
+
let b = graph.addNode();
|
|
138
|
+
let c = graph.addNode();
|
|
139
|
+
let d = graph.addNode();
|
|
140
|
+
graph.addEdge(a, b);
|
|
141
|
+
graph.addEdge(d, b);
|
|
142
|
+
graph.addEdge(a, d);
|
|
143
|
+
graph.addEdge(c, b);
|
|
144
|
+
assert.deepEqual(graph.getNodeIdsConnectedTo(b), [a, d, c]);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('addEdge should add multiple edges of different types in order', () => {
|
|
148
|
+
let graph = new AdjacencyList();
|
|
149
|
+
let a = graph.addNode();
|
|
150
|
+
let b = graph.addNode();
|
|
151
|
+
graph.addEdge(a, b);
|
|
152
|
+
graph.addEdge(a, b, 1);
|
|
153
|
+
graph.addEdge(a, b, 4);
|
|
154
|
+
graph.addEdge(a, b, 3);
|
|
155
|
+
assert.deepEqual(graph.getNodeIdsConnectedFrom(a), [b]);
|
|
156
|
+
assert.deepEqual(Array.from(graph.getAllEdges()), [
|
|
157
|
+
{from: a, to: b, type: 1},
|
|
158
|
+
{from: a, to: b, type: 4},
|
|
159
|
+
{from: a, to: b, type: 3},
|
|
160
|
+
]);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('addEdge should return false if an edge is already added', () => {
|
|
164
|
+
let graph = new AdjacencyList();
|
|
165
|
+
let a = graph.addNode();
|
|
166
|
+
let b = graph.addNode();
|
|
167
|
+
assert.equal(graph.addEdge(a, b), true);
|
|
168
|
+
assert.equal(graph.addEdge(a, b), false);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('addEdge should resize nodes array when necessary', () => {
|
|
172
|
+
let graph = new AdjacencyList();
|
|
173
|
+
let a = graph.addNode();
|
|
174
|
+
let b = graph.addNode();
|
|
175
|
+
let size = graph.serialize().nodes.byteLength;
|
|
176
|
+
graph.addEdge(a, b, 1);
|
|
177
|
+
graph.addEdge(a, b, 2);
|
|
178
|
+
graph.addEdge(a, b, 3);
|
|
179
|
+
graph.addEdge(a, b, 4);
|
|
180
|
+
assert(size < graph.serialize().nodes.byteLength);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('addEdge should resize edges array when necessary', () => {
|
|
184
|
+
let graph = new AdjacencyList();
|
|
185
|
+
let size = graph.serialize().edges.byteLength;
|
|
186
|
+
let a = graph.addNode();
|
|
187
|
+
let b = graph.addNode();
|
|
188
|
+
graph.addEdge(a, b, 1);
|
|
189
|
+
graph.addEdge(a, b, 2);
|
|
190
|
+
graph.addEdge(a, b, 3);
|
|
191
|
+
assert(size < graph.serialize().edges.byteLength);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('addEdge should error when a node has not been added to the graph', () => {
|
|
195
|
+
let graph = new AdjacencyList();
|
|
196
|
+
assert.throws(() => graph.addEdge(toNodeId(0), toNodeId(1)));
|
|
197
|
+
graph.addNode();
|
|
198
|
+
assert.throws(() => graph.addEdge(toNodeId(0), toNodeId(1)));
|
|
199
|
+
graph.addNode();
|
|
200
|
+
assert.doesNotThrow(() => graph.addEdge(toNodeId(0), toNodeId(1)));
|
|
201
|
+
assert.throws(() => graph.addEdge(toNodeId(0), toNodeId(2)));
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('addEdge should error when an unsupported edge type is provided', () => {
|
|
205
|
+
let graph = new AdjacencyList();
|
|
206
|
+
let a = graph.addNode();
|
|
207
|
+
let b = graph.addNode();
|
|
208
|
+
assert.throws(() => graph.addEdge(a, b, 0));
|
|
209
|
+
assert.throws(() => graph.addEdge(a, b, -1));
|
|
210
|
+
assert.doesNotThrow(() => graph.addEdge(a, b, 1));
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('addEdge should not replace a deleted edge if the edge was already added', () => {
|
|
214
|
+
// Mock hash fn to generate collisions
|
|
215
|
+
// $FlowFixMe[prop-missing]
|
|
216
|
+
let originalHash = AdjacencyList.prototype.hash;
|
|
217
|
+
// $FlowFixMe[prop-missing]
|
|
218
|
+
AdjacencyList.prototype.hash = () => 1;
|
|
219
|
+
|
|
220
|
+
let graph = new AdjacencyList();
|
|
221
|
+
let n0 = graph.addNode();
|
|
222
|
+
let n1 = graph.addNode();
|
|
223
|
+
let n2 = graph.addNode();
|
|
224
|
+
graph.addEdge(n0, n1, 1);
|
|
225
|
+
graph.addEdge(n1, n2, 1);
|
|
226
|
+
graph.removeEdge(n1, n2, 1);
|
|
227
|
+
assert(graph.addEdge(n0, n1, 1) === false);
|
|
228
|
+
assert(graph.stats.edges === 1);
|
|
229
|
+
|
|
230
|
+
// $FlowFixMe[prop-missing]
|
|
231
|
+
AdjacencyList.prototype.hash = originalHash;
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('addEdge should replace a deleted edge', () => {
|
|
235
|
+
// Mock hash fn to generate collisions
|
|
236
|
+
// $FlowFixMe[prop-missing]
|
|
237
|
+
let originalHash = AdjacencyList.prototype.hash;
|
|
238
|
+
// $FlowFixMe[prop-missing]
|
|
239
|
+
AdjacencyList.prototype.hash = () => 1;
|
|
240
|
+
|
|
241
|
+
try {
|
|
242
|
+
let graph = new AdjacencyList({initialCapacity: 3});
|
|
243
|
+
let n0 = graph.addNode();
|
|
244
|
+
let n1 = graph.addNode();
|
|
245
|
+
graph.addEdge(n0, n1, 2);
|
|
246
|
+
graph.removeEdge(n0, n1, 2);
|
|
247
|
+
assert(graph.addEdge(n0, n1, 2));
|
|
248
|
+
assert(graph.stats.edges === 1);
|
|
249
|
+
assert(graph.stats.deleted === 1);
|
|
250
|
+
// Resize to reclaim deleted edge space.
|
|
251
|
+
graph.resizeEdges(2);
|
|
252
|
+
assert(graph.stats.edges === 1);
|
|
253
|
+
assert(graph.stats.deleted === 0);
|
|
254
|
+
} finally {
|
|
255
|
+
// $FlowFixMe[prop-missing]
|
|
256
|
+
AdjacencyList.prototype.hash = originalHash;
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('hasEdge should accept an array of edge types', () => {
|
|
261
|
+
let graph = new AdjacencyList();
|
|
262
|
+
let a = graph.addNode();
|
|
263
|
+
let b = graph.addNode();
|
|
264
|
+
let c = graph.addNode();
|
|
265
|
+
|
|
266
|
+
graph.addEdge(a, b, 1);
|
|
267
|
+
graph.addEdge(b, c, 2);
|
|
268
|
+
|
|
269
|
+
assert.ok(!graph.hasEdge(a, b, [2, 3]));
|
|
270
|
+
assert.ok(graph.hasEdge(a, b, [1, 2]));
|
|
271
|
+
assert.ok(!graph.hasEdge(b, c, [1, 3]));
|
|
272
|
+
assert.ok(graph.hasEdge(b, c, [2, 3]));
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
describe('deserialize', function () {
|
|
276
|
+
this.timeout(10000);
|
|
277
|
+
|
|
278
|
+
it('should share the underlying data across worker threads', async () => {
|
|
279
|
+
let graph = new AdjacencyList();
|
|
280
|
+
let n0 = graph.addNode();
|
|
281
|
+
let n1 = graph.addNode();
|
|
282
|
+
graph.addEdge(n0, n1, 1);
|
|
283
|
+
graph.addEdge(n0, n1, 2);
|
|
284
|
+
|
|
285
|
+
let worker = new Worker(
|
|
286
|
+
path.join(__dirname, 'integration/adjacency-list-shared-array.js'),
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
let originalSerialized = graph.serialize();
|
|
290
|
+
let originalNodes = [...originalSerialized.nodes];
|
|
291
|
+
let originalEdges = [...originalSerialized.edges];
|
|
292
|
+
let work = new Promise(resolve => worker.on('message', resolve));
|
|
293
|
+
worker.postMessage(originalSerialized);
|
|
294
|
+
let received = AdjacencyList.deserialize(await work);
|
|
295
|
+
// eslint-disable-next-line no-unused-vars
|
|
296
|
+
const _terminatePromise = worker.terminate();
|
|
297
|
+
|
|
298
|
+
assert.deepEqual(received.serialize().nodes, graph.serialize().nodes);
|
|
299
|
+
assert.deepEqual(received.serialize().edges, graph.serialize().edges);
|
|
300
|
+
|
|
301
|
+
originalNodes.forEach((v, i) => {
|
|
302
|
+
if (i < NodeTypeMap.HEADER_SIZE) {
|
|
303
|
+
assert.equal(v, received.serialize().nodes[i]);
|
|
304
|
+
assert.equal(v, graph.serialize().nodes[i]);
|
|
305
|
+
} else {
|
|
306
|
+
assert.equal(v * 2, received.serialize().nodes[i]);
|
|
307
|
+
assert.equal(v * 2, graph.serialize().nodes[i]);
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
originalEdges.forEach((v, i) => {
|
|
312
|
+
if (i < EdgeTypeMap.HEADER_SIZE) {
|
|
313
|
+
assert.equal(v, received.serialize().edges[i]);
|
|
314
|
+
assert.equal(v, graph.serialize().edges[i]);
|
|
315
|
+
} else {
|
|
316
|
+
assert.equal(v * 2, received.serialize().edges[i]);
|
|
317
|
+
assert.equal(v * 2, graph.serialize().edges[i]);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// @flow strict-local
|
|
2
|
+
|
|
3
|
+
import assert from 'assert';
|
|
4
|
+
import {BitSet} from '../src/BitSet';
|
|
5
|
+
|
|
6
|
+
function assertValues(set: BitSet, values: Array<number>) {
|
|
7
|
+
let setValues = [];
|
|
8
|
+
set.forEach(bit => {
|
|
9
|
+
setValues.push(bit);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
for (let value of values) {
|
|
13
|
+
assert(set.has(value), 'Set.has returned false');
|
|
14
|
+
assert(
|
|
15
|
+
setValues.some(v => v === value),
|
|
16
|
+
'Set values is missing value',
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
assert(
|
|
21
|
+
setValues.length === values.length,
|
|
22
|
+
`Expected ${values.length} values but got ${setValues.length}`,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe('BitSet', () => {
|
|
27
|
+
it('clone should return a set with the same values', () => {
|
|
28
|
+
let set1 = new BitSet(5);
|
|
29
|
+
set1.add(1);
|
|
30
|
+
set1.add(3);
|
|
31
|
+
|
|
32
|
+
let set2 = set1.clone();
|
|
33
|
+
|
|
34
|
+
assertValues(set2, [1, 3]);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('clear should remove all values from the set', () => {
|
|
38
|
+
let set1 = new BitSet(5);
|
|
39
|
+
set1.add(1);
|
|
40
|
+
set1.add(3);
|
|
41
|
+
|
|
42
|
+
set1.clear();
|
|
43
|
+
|
|
44
|
+
assertValues(set1, []);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('delete should remove values from the set', () => {
|
|
48
|
+
let set1 = new BitSet(5);
|
|
49
|
+
set1.add(1);
|
|
50
|
+
set1.add(3);
|
|
51
|
+
set1.add(5);
|
|
52
|
+
|
|
53
|
+
set1.delete(3);
|
|
54
|
+
|
|
55
|
+
assertValues(set1, [1, 5]);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('empty should check if there are no values set', () => {
|
|
59
|
+
let set1 = new BitSet(5);
|
|
60
|
+
|
|
61
|
+
assert(set1.empty());
|
|
62
|
+
|
|
63
|
+
set1.add(3);
|
|
64
|
+
assert(!set1.empty());
|
|
65
|
+
|
|
66
|
+
set1.delete(3);
|
|
67
|
+
assert(set1.empty());
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should intersect with another BitSet', () => {
|
|
71
|
+
let set1 = new BitSet(5);
|
|
72
|
+
set1.add(1);
|
|
73
|
+
set1.add(3);
|
|
74
|
+
|
|
75
|
+
let set2 = new BitSet(5);
|
|
76
|
+
set2.add(3);
|
|
77
|
+
set2.add(5);
|
|
78
|
+
|
|
79
|
+
set1.intersect(set2);
|
|
80
|
+
assertValues(set1, [3]);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should union with another BitSet', () => {
|
|
84
|
+
let set1 = new BitSet(5);
|
|
85
|
+
set1.add(1);
|
|
86
|
+
set1.add(3);
|
|
87
|
+
|
|
88
|
+
let set2 = new BitSet(5);
|
|
89
|
+
set2.add(3);
|
|
90
|
+
set2.add(5);
|
|
91
|
+
|
|
92
|
+
set1.union(set2);
|
|
93
|
+
assertValues(set1, [1, 3, 5]);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('BitSet.union should create a new BitSet with the union', () => {
|
|
97
|
+
let set1 = new BitSet(5);
|
|
98
|
+
set1.add(1);
|
|
99
|
+
set1.add(3);
|
|
100
|
+
|
|
101
|
+
let set2 = new BitSet(5);
|
|
102
|
+
set2.add(3);
|
|
103
|
+
set2.add(5);
|
|
104
|
+
|
|
105
|
+
let set3 = BitSet.union(set1, set2);
|
|
106
|
+
assertValues(set1, [1, 3]);
|
|
107
|
+
assertValues(set2, [3, 5]);
|
|
108
|
+
assertValues(set3, [1, 3, 5]);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// @flow strict-local
|
|
2
|
+
|
|
3
|
+
import assert from 'assert';
|
|
4
|
+
import ContentGraph from '../src/ContentGraph';
|
|
5
|
+
|
|
6
|
+
describe('ContentGraph', () => {
|
|
7
|
+
it('should addNodeByContentKey if no node exists with the content key', () => {
|
|
8
|
+
let graph = new ContentGraph();
|
|
9
|
+
|
|
10
|
+
const node = {};
|
|
11
|
+
|
|
12
|
+
const nodeId1 = graph.addNodeByContentKey('contentKey', node);
|
|
13
|
+
|
|
14
|
+
assert.deepEqual(graph.getNode(nodeId1), node);
|
|
15
|
+
assert(graph.hasContentKey('contentKey'));
|
|
16
|
+
assert.deepEqual(graph.getNodeByContentKey('contentKey'), node);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should throw if a node with the content key already exists', () => {
|
|
20
|
+
let graph = new ContentGraph();
|
|
21
|
+
|
|
22
|
+
graph.addNodeByContentKey('contentKey', {});
|
|
23
|
+
|
|
24
|
+
assert.throws(() => {
|
|
25
|
+
graph.addNodeByContentKey('contentKey', {});
|
|
26
|
+
}, /already has content key/);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should remove the content key from graph when node is removed', () => {
|
|
30
|
+
let graph = new ContentGraph();
|
|
31
|
+
|
|
32
|
+
const node1 = {};
|
|
33
|
+
const nodeId1 = graph.addNodeByContentKey('contentKey', node1);
|
|
34
|
+
|
|
35
|
+
assert.equal(graph.getNode(nodeId1), node1);
|
|
36
|
+
assert(graph.hasContentKey('contentKey'));
|
|
37
|
+
|
|
38
|
+
graph.removeNode(nodeId1);
|
|
39
|
+
|
|
40
|
+
assert(!graph.hasContentKey('contentKey'));
|
|
41
|
+
});
|
|
42
|
+
});
|