@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.
@@ -1,14 +1,18 @@
1
1
  // @flow strict-local
2
2
  import type {ContentKey, NodeId} from './types';
3
3
 
4
- import Graph, {type GraphOpts} from './Graph';
4
+ import Graph, {type SerializedGraph, type GraphOpts} from './Graph';
5
5
  import nullthrows from 'nullthrows';
6
6
 
7
- export type SerializedContentGraph<TNode, TEdgeType: number = 1> = {|
7
+ export type ContentGraphOpts<TNode, TEdgeType: number = 1> = {|
8
8
  ...GraphOpts<TNode, TEdgeType>,
9
9
  _contentKeyToNodeId: Map<ContentKey, NodeId>,
10
10
  _nodeIdToContentKey: Map<NodeId, ContentKey>,
11
11
  |};
12
+ export type SerializedContentGraph<TNode, TEdgeType: number = 1> = {|
13
+ ...SerializedGraph<TNode, TEdgeType>,
14
+ _contentKeyToNodeId: Map<ContentKey, NodeId>,
15
+ |};
12
16
 
13
17
  export default class ContentGraph<TNode, TEdgeType: number = 1> extends Graph<
14
18
  TNode,
@@ -17,7 +21,7 @@ export default class ContentGraph<TNode, TEdgeType: number = 1> extends Graph<
17
21
  _contentKeyToNodeId: Map<ContentKey, NodeId>;
18
22
  _nodeIdToContentKey: Map<NodeId, ContentKey>;
19
23
 
20
- constructor(opts: ?SerializedContentGraph<TNode, TEdgeType>) {
24
+ constructor(opts: ?ContentGraphOpts<TNode, TEdgeType>) {
21
25
  if (opts) {
22
26
  let {_contentKeyToNodeId, _nodeIdToContentKey, ...rest} = opts;
23
27
  super(rest);
@@ -32,13 +36,14 @@ export default class ContentGraph<TNode, TEdgeType: number = 1> extends Graph<
32
36
 
33
37
  // $FlowFixMe[prop-missing]
34
38
  static deserialize(
35
- opts: SerializedContentGraph<TNode, TEdgeType>,
39
+ opts: ContentGraphOpts<TNode, TEdgeType>,
36
40
  ): ContentGraph<TNode, TEdgeType> {
37
41
  return new ContentGraph(opts);
38
42
  }
39
43
 
40
44
  // $FlowFixMe[prop-missing]
41
45
  serialize(): SerializedContentGraph<TNode, TEdgeType> {
46
+ // $FlowFixMe[prop-missing]
42
47
  return {
43
48
  ...super.serialize(),
44
49
  _contentKeyToNodeId: this._contentKeyToNodeId,
package/src/Graph.js CHANGED
@@ -1,49 +1,42 @@
1
1
  // @flow strict-local
2
2
 
3
- import {toNodeId, fromNodeId} from './types';
3
+ import {fromNodeId} from './types';
4
+ import AdjacencyList, {type SerializedAdjacencyList} from './AdjacencyList';
4
5
  import type {Edge, NodeId} from './types';
5
6
  import type {TraversalActions, GraphVisitor} from '@parcel/types';
6
7
 
7
8
  import assert from 'assert';
8
9
  import nullthrows from 'nullthrows';
9
10
 
10
- type NullEdgeType = 1;
11
+ export type NullEdgeType = 1;
11
12
  export type GraphOpts<TNode, TEdgeType: number = 1> = {|
12
13
  nodes?: Map<NodeId, TNode>,
13
- edges?: AdjacencyListMap<TEdgeType | NullEdgeType>,
14
+ adjacencyList?: SerializedAdjacencyList<TEdgeType>,
14
15
  rootNodeId?: ?NodeId,
15
- nextNodeId?: ?number,
16
16
  |};
17
17
 
18
- export const ALL_EDGE_TYPES = '@@all_edge_types';
18
+ export type SerializedGraph<TNode, TEdgeType: number = 1> = {|
19
+ nodes: Map<NodeId, TNode>,
20
+ adjacencyList: SerializedAdjacencyList<TEdgeType>,
21
+ rootNodeId: ?NodeId,
22
+ |};
23
+
24
+ export type AllEdgeTypes = -1;
25
+ export const ALL_EDGE_TYPES: AllEdgeTypes = -1;
19
26
 
20
27
  export default class Graph<TNode, TEdgeType: number = 1> {
21
28
  nodes: Map<NodeId, TNode>;
22
- inboundEdges: AdjacencyList<TEdgeType | NullEdgeType>;
23
- outboundEdges: AdjacencyList<TEdgeType | NullEdgeType>;
29
+ adjacencyList: AdjacencyList<TEdgeType>;
24
30
  rootNodeId: ?NodeId;
25
- nextNodeId: number = 1;
26
31
 
27
32
  constructor(opts: ?GraphOpts<TNode, TEdgeType>) {
28
33
  this.nodes = opts?.nodes || new Map();
29
34
  this.setRootNodeId(opts?.rootNodeId);
30
- this.nextNodeId = opts?.nextNodeId ?? 0;
31
-
32
- let edges = opts?.edges;
33
- if (edges != null) {
34
- this.inboundEdges = new AdjacencyList();
35
- this.outboundEdges = new AdjacencyList(edges);
36
- for (let [from, edgeList] of edges) {
37
- for (let [type, toNodes] of edgeList) {
38
- for (let to of toNodes) {
39
- this.inboundEdges.addEdge(to, from, type);
40
- }
41
- }
42
- }
43
- } else {
44
- this.inboundEdges = new AdjacencyList();
45
- this.outboundEdges = new AdjacencyList();
46
- }
35
+
36
+ let adjacencyList = opts?.adjacencyList;
37
+ this.adjacencyList = adjacencyList
38
+ ? AdjacencyList.deserialize(adjacencyList)
39
+ : new AdjacencyList<TEdgeType>();
47
40
  }
48
41
 
49
42
  setRootNodeId(id: ?NodeId) {
@@ -55,37 +48,27 @@ export default class Graph<TNode, TEdgeType: number = 1> {
55
48
  ): Graph<TNode, TEdgeType> {
56
49
  return new this({
57
50
  nodes: opts.nodes,
58
- edges: opts.edges,
51
+ adjacencyList: opts.adjacencyList,
59
52
  rootNodeId: opts.rootNodeId,
60
- nextNodeId: opts.nextNodeId,
61
53
  });
62
54
  }
63
55
 
64
- serialize(): GraphOpts<TNode, TEdgeType> {
56
+ serialize(): SerializedGraph<TNode, TEdgeType> {
65
57
  return {
66
58
  nodes: this.nodes,
67
- edges: this.outboundEdges.getListMap(),
59
+ adjacencyList: this.adjacencyList.serialize(),
68
60
  rootNodeId: this.rootNodeId,
69
- nextNodeId: this.nextNodeId,
70
61
  };
71
62
  }
72
63
 
73
- // Returns a list of all edges in the graph. This can be large, so iterating
64
+ // Returns an iterator of all edges in the graph. This can be large, so iterating
74
65
  // the complete list can be costly in large graphs. Used when merging graphs.
75
- getAllEdges(): Array<Edge<TEdgeType | NullEdgeType>> {
76
- let edges = [];
77
- for (let [from, edgeList] of this.outboundEdges.getListMap()) {
78
- for (let [type, toNodes] of edgeList) {
79
- for (let to of toNodes) {
80
- edges.push({from, to, type});
81
- }
82
- }
83
- }
84
- return edges;
66
+ getAllEdges(): Iterator<Edge<TEdgeType | NullEdgeType>> {
67
+ return this.adjacencyList.getAllEdges();
85
68
  }
86
69
 
87
70
  addNode(node: TNode): NodeId {
88
- let id = toNodeId(this.nextNodeId++);
71
+ let id = this.adjacencyList.addNode();
89
72
  this.nodes.set(id, node);
90
73
  return id;
91
74
  }
@@ -98,7 +81,15 @@ export default class Graph<TNode, TEdgeType: number = 1> {
98
81
  return this.nodes.get(id);
99
82
  }
100
83
 
101
- addEdge(from: NodeId, to: NodeId, type: TEdgeType | NullEdgeType = 1): void {
84
+ addEdge(
85
+ from: NodeId,
86
+ to: NodeId,
87
+ type: TEdgeType | NullEdgeType = 1,
88
+ ): boolean {
89
+ if (Number(type) === 0) {
90
+ throw new Error(`Edge type "${type}" not allowed`);
91
+ }
92
+
102
93
  if (!this.getNode(from)) {
103
94
  throw new Error(`"from" node '${fromNodeId(from)}' not found`);
104
95
  }
@@ -107,8 +98,7 @@ export default class Graph<TNode, TEdgeType: number = 1> {
107
98
  throw new Error(`"to" node '${fromNodeId(to)}' not found`);
108
99
  }
109
100
 
110
- this.outboundEdges.addEdge(from, to, type);
111
- this.inboundEdges.addEdge(to, from, type);
101
+ return this.adjacencyList.addEdge(from, to, type);
112
102
  }
113
103
 
114
104
  hasEdge(
@@ -116,95 +106,52 @@ export default class Graph<TNode, TEdgeType: number = 1> {
116
106
  to: NodeId,
117
107
  type?: TEdgeType | NullEdgeType = 1,
118
108
  ): boolean {
119
- return this.outboundEdges.hasEdge(from, to, type);
109
+ return this.adjacencyList.hasEdge(from, to, type);
120
110
  }
121
111
 
122
112
  getNodeIdsConnectedTo(
123
113
  nodeId: NodeId,
124
- type: TEdgeType | NullEdgeType | Array<TEdgeType | NullEdgeType> = 1,
114
+ type:
115
+ | TEdgeType
116
+ | NullEdgeType
117
+ | Array<TEdgeType | NullEdgeType>
118
+ | AllEdgeTypes = 1,
125
119
  ): Array<NodeId> {
126
120
  this._assertHasNodeId(nodeId);
127
121
 
128
- let inboundByType = this.inboundEdges.getEdgesByType(nodeId);
129
- if (inboundByType == null) {
130
- return [];
131
- }
132
-
133
- let nodes;
134
- if (type === ALL_EDGE_TYPES) {
135
- nodes = new Set();
136
- for (let [, typeNodes] of inboundByType) {
137
- for (let node of typeNodes) {
138
- nodes.add(node);
139
- }
140
- }
141
- } else if (Array.isArray(type)) {
142
- nodes = new Set();
143
- for (let typeName of type) {
144
- for (let node of inboundByType.get(typeName)?.values() ?? []) {
145
- nodes.add(node);
146
- }
147
- }
148
- } else {
149
- nodes = new Set(inboundByType.get(type)?.values() ?? []);
150
- }
151
-
152
- return [...nodes];
122
+ return this.adjacencyList.getNodeIdsConnectedTo(nodeId, type);
153
123
  }
154
124
 
155
125
  getNodeIdsConnectedFrom(
156
126
  nodeId: NodeId,
157
- type: TEdgeType | NullEdgeType | Array<TEdgeType | NullEdgeType> = 1,
127
+ type:
128
+ | TEdgeType
129
+ | NullEdgeType
130
+ | Array<TEdgeType | NullEdgeType>
131
+ | AllEdgeTypes = 1,
158
132
  ): Array<NodeId> {
159
133
  this._assertHasNodeId(nodeId);
160
- let outboundByType = this.outboundEdges.getEdgesByType(nodeId);
161
- if (outboundByType == null) {
162
- return [];
163
- }
164
134
 
165
- let nodes;
166
- if (type === ALL_EDGE_TYPES) {
167
- nodes = new Set();
168
- for (let [, typeNodes] of outboundByType) {
169
- for (let node of typeNodes) {
170
- nodes.add(node);
171
- }
172
- }
173
- } else if (Array.isArray(type)) {
174
- nodes = new Set();
175
- for (let typeName of type) {
176
- for (let node of outboundByType.get(typeName)?.values() ?? []) {
177
- nodes.add(node);
178
- }
179
- }
180
- } else {
181
- nodes = new Set(outboundByType.get(type)?.values() ?? []);
182
- }
183
-
184
- return [...nodes];
135
+ return this.adjacencyList.getNodeIdsConnectedFrom(nodeId, type);
185
136
  }
186
137
 
187
138
  // Removes node and any edges coming from or to that node
188
139
  removeNode(nodeId: NodeId) {
189
140
  this._assertHasNodeId(nodeId);
190
141
 
191
- for (let [type, nodesForType] of this.inboundEdges.getEdgesByType(nodeId)) {
192
- for (let from of nodesForType) {
193
- this.removeEdge(
194
- from,
195
- nodeId,
196
- type,
197
- // Do not allow orphans to be removed as this node could be one
198
- // and is already being removed.
199
- false /* removeOrphans */,
200
- );
201
- }
142
+ for (let {type, from} of this.adjacencyList.getInboundEdgesByType(nodeId)) {
143
+ this.removeEdge(
144
+ from,
145
+ nodeId,
146
+ type,
147
+ // Do not allow orphans to be removed as this node could be one
148
+ // and is already being removed.
149
+ false,
150
+ );
202
151
  }
203
152
 
204
- for (let [type, toNodes] of this.outboundEdges.getEdgesByType(nodeId)) {
205
- for (let to of toNodes) {
206
- this.removeEdge(nodeId, to, type);
207
- }
153
+ for (let {type, to} of this.adjacencyList.getOutboundEdgesByType(nodeId)) {
154
+ this.removeEdge(nodeId, to, type);
208
155
  }
209
156
 
210
157
  let wasRemoved = this.nodes.delete(nodeId);
@@ -214,7 +161,7 @@ export default class Graph<TNode, TEdgeType: number = 1> {
214
161
  removeEdges(nodeId: NodeId, type: TEdgeType | NullEdgeType = 1) {
215
162
  this._assertHasNodeId(nodeId);
216
163
 
217
- for (let to of this.outboundEdges.getEdges(nodeId, type)) {
164
+ for (let to of this.getNodeIdsConnectedFrom(nodeId, type)) {
218
165
  this.removeEdge(nodeId, to, type);
219
166
  }
220
167
  }
@@ -226,23 +173,13 @@ export default class Graph<TNode, TEdgeType: number = 1> {
226
173
  type: TEdgeType | NullEdgeType = 1,
227
174
  removeOrphans: boolean = true,
228
175
  ) {
229
- if (!this.outboundEdges.hasEdge(from, to, type)) {
176
+ if (!this.adjacencyList.hasEdge(from, to, type)) {
230
177
  throw new Error(
231
- `Outbound edge from ${fromNodeId(from)} to ${fromNodeId(
232
- to,
233
- )} not found!`,
178
+ `Edge from ${fromNodeId(from)} to ${fromNodeId(to)} not found!`,
234
179
  );
235
180
  }
236
181
 
237
- if (!this.inboundEdges.hasEdge(to, from, type)) {
238
- throw new Error(
239
- `Inbound edge from ${fromNodeId(to)} to ${fromNodeId(from)} not found!`,
240
- );
241
- }
242
-
243
- this.outboundEdges.removeEdge(from, to, type);
244
- this.inboundEdges.removeEdge(to, from, type);
245
-
182
+ this.adjacencyList.removeEdge(from, to, type);
246
183
  if (removeOrphans && this.isOrphanedNode(to)) {
247
184
  this.removeNode(to);
248
185
  }
@@ -254,14 +191,7 @@ export default class Graph<TNode, TEdgeType: number = 1> {
254
191
  if (this.rootNodeId == null) {
255
192
  // If the graph does not have a root, and there are inbound edges,
256
193
  // this node should not be considered orphaned.
257
- // return false;
258
- for (let [, inboundNodeIds] of this.inboundEdges.getEdgesByType(nodeId)) {
259
- if (inboundNodeIds.size > 0) {
260
- return false;
261
- }
262
- }
263
-
264
- return true;
194
+ return !this.adjacencyList.hasInboundEdges(nodeId);
265
195
  }
266
196
 
267
197
  // Otherwise, attempt to traverse backwards to the root. If there is a path,
@@ -276,7 +206,6 @@ export default class Graph<TNode, TEdgeType: number = 1> {
276
206
  actions.stop();
277
207
  }
278
208
  },
279
- // $FlowFixMe
280
209
  ALL_EDGE_TYPES,
281
210
  );
282
211
 
@@ -292,19 +221,6 @@ export default class Graph<TNode, TEdgeType: number = 1> {
292
221
  this.nodes.set(nodeId, node);
293
222
  }
294
223
 
295
- replaceNode(
296
- fromNodeId: NodeId,
297
- toNodeId: NodeId,
298
- type: TEdgeType | NullEdgeType = 1,
299
- ): void {
300
- this._assertHasNodeId(fromNodeId);
301
- for (let parent of this.inboundEdges.getEdges(fromNodeId, type)) {
302
- this.addEdge(parent, toNodeId, type);
303
- this.removeEdge(parent, fromNodeId, type);
304
- }
305
- this.removeNode(fromNodeId);
306
- }
307
-
308
224
  // Update a node's downstream nodes making sure to prune any orphaned branches
309
225
  replaceNodeIdsConnectedTo(
310
226
  fromNodeId: NodeId,
@@ -314,10 +230,10 @@ export default class Graph<TNode, TEdgeType: number = 1> {
314
230
  ): void {
315
231
  this._assertHasNodeId(fromNodeId);
316
232
 
317
- let outboundEdges = this.outboundEdges.getEdges(fromNodeId, type);
233
+ let outboundEdges = this.getNodeIdsConnectedFrom(fromNodeId, type);
318
234
  let childrenToRemove = new Set(
319
235
  replaceFilter
320
- ? [...outboundEdges].filter(toNodeId => replaceFilter(toNodeId))
236
+ ? outboundEdges.filter(toNodeId => replaceFilter(toNodeId))
321
237
  : outboundEdges,
322
238
  );
323
239
  for (let toNodeId of toNodeIds) {
@@ -336,7 +252,11 @@ export default class Graph<TNode, TEdgeType: number = 1> {
336
252
  traverse<TContext>(
337
253
  visit: GraphVisitor<NodeId, TContext>,
338
254
  startNodeId: ?NodeId,
339
- type: TEdgeType | NullEdgeType | Array<TEdgeType | NullEdgeType> = 1,
255
+ type:
256
+ | TEdgeType
257
+ | NullEdgeType
258
+ | Array<TEdgeType | NullEdgeType>
259
+ | AllEdgeTypes = 1,
340
260
  ): ?TContext {
341
261
  return this.dfs({
342
262
  visit,
@@ -349,7 +269,7 @@ export default class Graph<TNode, TEdgeType: number = 1> {
349
269
  filter: (NodeId, TraversalActions) => ?TValue,
350
270
  visit: GraphVisitor<TValue, TContext>,
351
271
  startNodeId: ?NodeId,
352
- type?: TEdgeType | Array<TEdgeType | NullEdgeType>,
272
+ type?: TEdgeType | Array<TEdgeType | NullEdgeType> | AllEdgeTypes,
353
273
  ): ?TContext {
354
274
  return this.traverse(mapVisitor(filter, visit), startNodeId, type);
355
275
  }
@@ -357,7 +277,11 @@ export default class Graph<TNode, TEdgeType: number = 1> {
357
277
  traverseAncestors<TContext>(
358
278
  startNodeId: ?NodeId,
359
279
  visit: GraphVisitor<NodeId, TContext>,
360
- type: TEdgeType | NullEdgeType | Array<TEdgeType | NullEdgeType> = 1,
280
+ type:
281
+ | TEdgeType
282
+ | NullEdgeType
283
+ | Array<TEdgeType | NullEdgeType>
284
+ | AllEdgeTypes = 1,
361
285
  ): ?TContext {
362
286
  return this.dfs({
363
287
  visit,
@@ -574,47 +498,3 @@ export function mapVisitor<NodeId, TValue, TContext>(
574
498
 
575
499
  return mapped;
576
500
  }
577
-
578
- type AdjacencyListMap<TEdgeType> = Map<NodeId, Map<TEdgeType, Set<NodeId>>>;
579
- class AdjacencyList<TEdgeType> {
580
- _listMap: AdjacencyListMap<TEdgeType>;
581
-
582
- constructor(listMap?: AdjacencyListMap<TEdgeType>) {
583
- this._listMap = listMap ?? new Map();
584
- }
585
-
586
- getListMap(): AdjacencyListMap<TEdgeType> {
587
- return this._listMap;
588
- }
589
-
590
- getEdges(from: NodeId, type: TEdgeType): $ReadOnlySet<NodeId> {
591
- return this._listMap.get(from)?.get(type) ?? new Set();
592
- }
593
-
594
- getEdgesByType(from: NodeId): $ReadOnlyMap<TEdgeType, $ReadOnlySet<NodeId>> {
595
- return this._listMap.get(from) ?? new Map();
596
- }
597
-
598
- hasEdge(from: NodeId, to: NodeId, type: TEdgeType): boolean {
599
- return Boolean(this._listMap.get(from)?.get(type)?.has(to));
600
- }
601
-
602
- addEdge(from: NodeId, to: NodeId, type: TEdgeType): void {
603
- let types = this._listMap.get(from);
604
- if (types == null) {
605
- types = new Map<TEdgeType, Set<NodeId>>();
606
- this._listMap.set(from, types);
607
- }
608
-
609
- let adjacent = types.get(type);
610
- if (adjacent == null) {
611
- adjacent = new Set<NodeId>();
612
- types.set(type, adjacent);
613
- }
614
- adjacent.add(to);
615
- }
616
-
617
- removeEdge(from: NodeId, to: NodeId, type: TEdgeType): void {
618
- this._listMap.get(from)?.get(type)?.delete(to);
619
- }
620
- }
package/src/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  // @flow strict-local
2
2
 
3
3
  export type {NodeId, ContentKey, Edge} from './types';
4
+ export type {GraphOpts} from './Graph';
5
+ export type {ContentGraphOpts, SerializedContentGraph} from './ContentGraph';
4
6
  export {toNodeId, fromNodeId} from './types';
5
- export {default as Graph, ALL_EDGE_TYPES, GraphOpts, mapVisitor} from './Graph';
6
- export {default as ContentGraph, SerializedContentGraph} from './ContentGraph';
7
+ export {default as Graph, ALL_EDGE_TYPES, mapVisitor} from './Graph';
8
+ export {default as ContentGraph} from './ContentGraph';