@parcel/graph 3.2.1-dev.3188 → 3.2.1-dev.3189

Sign up to get free protection for your applications and to get access to all the features.
@@ -240,7 +240,7 @@ class AdjacencyList {
240
240
  *
241
241
  * Note that this method does not increment the node count
242
242
  * (that only happens in `addEdge`), it _may_ preemptively resize
243
- * the nodes array if it is at capacity, under the assumption that
243
+ * the nodes array if it is at capacity, under the asumption that
244
244
  * at least 1 edge to or from this new node will be added.
245
245
  *
246
246
  * Returns the id of the added node.
package/lib/Graph.js CHANGED
@@ -17,15 +17,6 @@ function _nullthrows() {
17
17
  }
18
18
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
19
  const ALL_EDGE_TYPES = exports.ALL_EDGE_TYPES = -1;
20
-
21
- /**
22
- * Internal type used for queue iterative DFS implementation.
23
- */
24
-
25
- /**
26
- * Options for DFS traversal.
27
- */
28
-
29
20
  class Graph {
30
21
  constructor(opts) {
31
22
  this.nodes = (opts === null || opts === void 0 ? void 0 : opts.nodes) || [];
@@ -188,7 +179,7 @@ class Graph {
188
179
  if (type === ALL_EDGE_TYPES && enter && (typeof visit === 'function' || !visit.exit)) {
189
180
  return this.dfsFast(enter, startNodeId);
190
181
  } else {
191
- return this.dfsNew({
182
+ return this.dfs({
192
183
  visit,
193
184
  startNodeId,
194
185
  getChildren: nodeId => this.getNodeIdsConnectedFrom(nodeId, type)
@@ -206,7 +197,7 @@ class Graph {
206
197
  });
207
198
  }
208
199
  dfsFast(visit, startNodeId) {
209
- let traversalStartNode = (0, _nullthrows().default)(startNodeId !== null && startNodeId !== void 0 ? startNodeId : this.rootNodeId, 'A start node is required to traverse');
200
+ let traversalStartNode = (0, _nullthrows().default)(startNodeId ?? this.rootNodeId, 'A start node is required to traverse');
210
201
  this._assertHasNodeId(traversalStartNode);
211
202
  let visited;
212
203
  if (!this._visited || this._visited.capacity < this.nodes.length) {
@@ -268,7 +259,7 @@ class Graph {
268
259
 
269
260
  // A post-order implementation of dfsFast
270
261
  postOrderDfsFast(visit, startNodeId) {
271
- let traversalStartNode = (0, _nullthrows().default)(startNodeId !== null && startNodeId !== void 0 ? startNodeId : this.rootNodeId, 'A start node is required to traverse');
262
+ let traversalStartNode = (0, _nullthrows().default)(startNodeId ?? this.rootNodeId, 'A start node is required to traverse');
272
263
  this._assertHasNodeId(traversalStartNode);
273
264
  let visited;
274
265
  if (!this._visited || this._visited.capacity < this.nodes.length) {
@@ -310,114 +301,12 @@ class Graph {
310
301
  }
311
302
  this._visited = visited;
312
303
  }
313
-
314
- /**
315
- * Iterative implementation of DFS that supports all use-cases.
316
- */
317
- dfsNew({
318
- visit,
319
- startNodeId,
320
- getChildren
321
- }) {
322
- let traversalStartNode = (0, _nullthrows().default)(startNodeId !== null && startNodeId !== void 0 ? startNodeId : this.rootNodeId, 'A start node is required to traverse');
323
- this._assertHasNodeId(traversalStartNode);
324
- let visited;
325
- if (!this._visited || this._visited.capacity < this.nodes.length) {
326
- this._visited = new _BitSet.BitSet(this.nodes.length);
327
- visited = this._visited;
328
- } else {
329
- visited = this._visited;
330
- visited.clear();
331
- }
332
- // Take shared instance to avoid re-entrancy issues.
333
- this._visited = null;
334
- let stopped = false;
335
- let skipped = false;
336
- let actions = {
337
- skipChildren() {
338
- skipped = true;
339
- },
340
- stop() {
341
- stopped = true;
342
- }
343
- };
344
- const queue = [{
345
- nodeId: traversalStartNode,
346
- context: null
347
- }];
348
- while (queue.length !== 0) {
349
- const command = queue.pop();
350
- if (command.exit != null) {
351
- let {
352
- nodeId,
353
- context,
354
- exit
355
- } = command;
356
- let newContext = exit(nodeId, command.context, actions);
357
- if (typeof newContext !== 'undefined') {
358
- // $FlowFixMe[reassign-const]
359
- context = newContext;
360
- }
361
- if (skipped) {
362
- continue;
363
- }
364
- if (stopped) {
365
- this._visited = visited;
366
- return context;
367
- }
368
- } else {
369
- let {
370
- nodeId,
371
- context
372
- } = command;
373
- if (!this.hasNode(nodeId) || visited.has(nodeId)) continue;
374
- visited.add(nodeId);
375
- skipped = false;
376
- let enter = typeof visit === 'function' ? visit : visit.enter;
377
- if (enter) {
378
- let newContext = enter(nodeId, context, actions);
379
- if (typeof newContext !== 'undefined') {
380
- // $FlowFixMe[reassign-const]
381
- context = newContext;
382
- }
383
- }
384
- if (skipped) {
385
- continue;
386
- }
387
- if (stopped) {
388
- this._visited = visited;
389
- return context;
390
- }
391
- if (typeof visit !== 'function' && visit.exit) {
392
- queue.push({
393
- nodeId,
394
- exit: visit.exit,
395
- context
396
- });
397
- }
398
-
399
- // TODO turn into generator function
400
- const children = getChildren(nodeId);
401
- for (let i = children.length - 1; i > -1; i -= 1) {
402
- const child = children[i];
403
- if (visited.has(child)) {
404
- continue;
405
- }
406
- queue.push({
407
- nodeId: child,
408
- context
409
- });
410
- }
411
- }
412
- }
413
- this._visited = visited;
414
- }
415
304
  dfs({
416
305
  visit,
417
306
  startNodeId,
418
307
  getChildren
419
308
  }) {
420
- let traversalStartNode = (0, _nullthrows().default)(startNodeId !== null && startNodeId !== void 0 ? startNodeId : this.rootNodeId, 'A start node is required to traverse');
309
+ let traversalStartNode = (0, _nullthrows().default)(startNodeId ?? this.rootNodeId, 'A start node is required to traverse');
421
310
  this._assertHasNodeId(traversalStartNode);
422
311
  let visited;
423
312
  if (!this._visited || this._visited.capacity < this.nodes.length) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parcel/graph",
3
- "version": "3.2.1-dev.3188+c422b7ff3",
3
+ "version": "3.2.1-dev.3189+406c0ceef",
4
4
  "description": "Blazing fast, zero configuration web application bundler",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -17,10 +17,10 @@
17
17
  "main": "lib/index.js",
18
18
  "source": "src/index.js",
19
19
  "engines": {
20
- "node": ">= 12.0.0"
20
+ "node": ">= 16.0.0"
21
21
  },
22
22
  "dependencies": {
23
23
  "nullthrows": "^1.1.1"
24
24
  },
25
- "gitHead": "c422b7ff3c383779781ea5169d86191508b01e5b"
25
+ "gitHead": "406c0ceefb854ea98435f97e4e317164150c9883"
26
26
  }
@@ -30,7 +30,7 @@ export type AdjacencyListOptions<TEdgeType> = {|
30
30
  minGrowFactor?: number,
31
31
  /** The size after which to grow the capacity by the minimum factor. */
32
32
  peakCapacity?: number,
33
- /** The percentage of deleted edges above which the capacity should shrink. */
33
+ /** The percentage of deleted edges above which the capcity should shink. */
34
34
  unloadFactor?: number,
35
35
  /** The amount by which to shrink the capacity. */
36
36
  shrinkFactor?: number,
@@ -328,7 +328,7 @@ export default class AdjacencyList<TEdgeType: number = 1> {
328
328
  *
329
329
  * Note that this method does not increment the node count
330
330
  * (that only happens in `addEdge`), it _may_ preemptively resize
331
- * the nodes array if it is at capacity, under the assumption that
331
+ * the nodes array if it is at capacity, under the asumption that
332
332
  * at least 1 edge to or from this new node will be added.
333
333
  *
334
334
  * Returns the id of the added node.
package/src/Graph.js CHANGED
@@ -28,51 +28,6 @@ export type SerializedGraph<TNode, TEdgeType: number = 1> = {|
28
28
  export type AllEdgeTypes = -1;
29
29
  export const ALL_EDGE_TYPES: AllEdgeTypes = -1;
30
30
 
31
- type DFSCommandVisit<TContext> = {|
32
- nodeId: NodeId,
33
- context: TContext | null,
34
- |};
35
-
36
- type DFSCommandExit<TContext> = {|
37
- nodeId: NodeId,
38
- exit: GraphTraversalCallback<NodeId, TContext>,
39
- context: TContext | null,
40
- |};
41
-
42
- /**
43
- * Internal type used for queue iterative DFS implementation.
44
- */
45
- type DFSCommand<TContext> =
46
- | DFSCommandVisit<TContext>
47
- | DFSCommandExit<TContext>;
48
-
49
- /**
50
- * Options for DFS traversal.
51
- */
52
- export type DFSParams<TContext> = {|
53
- visit: GraphVisitor<NodeId, TContext>,
54
- /**
55
- * Custom function to get next entries to visit.
56
- *
57
- * This can be a performance bottle-neck as arrays are created on every node visit.
58
- *
59
- * @deprecated This will be replaced by a static `traversalType` set of orders in the future
60
- *
61
- * Currently this is only used in 3 ways:
62
- *
63
- * - Traversing down the tree (normal DFS)
64
- * - Traversing up the tree (ancestors)
65
- * - Filtered version of traversal; which does not need to exist at the DFS level as the visitor
66
- * can handle filtering
67
- * - Sorted traversal of BundleGraph entries, which does not have a clear use-case, but may
68
- * not be safe to remove
69
- *
70
- * Only due to the latter we aren't replacing this.
71
- */
72
- getChildren: (nodeId: NodeId) => Array<NodeId>,
73
- startNodeId?: ?NodeId,
74
- |};
75
-
76
31
  export default class Graph<TNode, TEdgeType: number = 1> {
77
32
  nodes: Array<TNode | null>;
78
33
  adjacencyList: AdjacencyList<TEdgeType>;
@@ -334,7 +289,7 @@ export default class Graph<TNode, TEdgeType: number = 1> {
334
289
  ) {
335
290
  return this.dfsFast(enter, startNodeId);
336
291
  } else {
337
- return this.dfsNew({
292
+ return this.dfs({
338
293
  visit,
339
294
  startNodeId,
340
295
  getChildren: nodeId => this.getNodeIdsConnectedFrom(nodeId, type),
@@ -494,117 +449,15 @@ export default class Graph<TNode, TEdgeType: number = 1> {
494
449
  return;
495
450
  }
496
451
 
497
- /**
498
- * Iterative implementation of DFS that supports all use-cases.
499
- */
500
- dfsNew<TContext>({
501
- visit,
502
- startNodeId,
503
- getChildren,
504
- }: DFSParams<TContext>): ?TContext {
505
- let traversalStartNode = nullthrows(
506
- startNodeId ?? this.rootNodeId,
507
- 'A start node is required to traverse',
508
- );
509
- this._assertHasNodeId(traversalStartNode);
510
-
511
- let visited;
512
- if (!this._visited || this._visited.capacity < this.nodes.length) {
513
- this._visited = new BitSet(this.nodes.length);
514
- visited = this._visited;
515
- } else {
516
- visited = this._visited;
517
- visited.clear();
518
- }
519
- // Take shared instance to avoid re-entrancy issues.
520
- this._visited = null;
521
-
522
- let stopped = false;
523
- let skipped = false;
524
- let actions: TraversalActions = {
525
- skipChildren() {
526
- skipped = true;
527
- },
528
- stop() {
529
- stopped = true;
530
- },
531
- };
532
-
533
- const queue: DFSCommand<TContext>[] = [
534
- {nodeId: traversalStartNode, context: null},
535
- ];
536
- while (queue.length !== 0) {
537
- const command = queue.pop();
538
-
539
- if (command.exit != null) {
540
- let {nodeId, context, exit} = command;
541
- let newContext = exit(nodeId, command.context, actions);
542
- if (typeof newContext !== 'undefined') {
543
- // $FlowFixMe[reassign-const]
544
- context = newContext;
545
- }
546
-
547
- if (skipped) {
548
- continue;
549
- }
550
-
551
- if (stopped) {
552
- this._visited = visited;
553
- return context;
554
- }
555
- } else {
556
- let {nodeId, context} = command;
557
- if (!this.hasNode(nodeId) || visited.has(nodeId)) continue;
558
- visited.add(nodeId);
559
-
560
- skipped = false;
561
- let enter = typeof visit === 'function' ? visit : visit.enter;
562
- if (enter) {
563
- let newContext = enter(nodeId, context, actions);
564
- if (typeof newContext !== 'undefined') {
565
- // $FlowFixMe[reassign-const]
566
- context = newContext;
567
- }
568
- }
569
-
570
- if (skipped) {
571
- continue;
572
- }
573
-
574
- if (stopped) {
575
- this._visited = visited;
576
- return context;
577
- }
578
-
579
- if (typeof visit !== 'function' && visit.exit) {
580
- queue.push({
581
- nodeId,
582
- exit: visit.exit,
583
- context,
584
- });
585
- }
586
-
587
- // TODO turn into generator function
588
- const children = getChildren(nodeId);
589
- for (let i = children.length - 1; i > -1; i -= 1) {
590
- const child = children[i];
591
- if (visited.has(child)) {
592
- continue;
593
- }
594
-
595
- queue.push({nodeId: child, context});
596
- }
597
- }
598
- }
599
-
600
- this._visited = visited;
601
- }
602
-
603
452
  dfs<TContext>({
604
453
  visit,
605
454
  startNodeId,
606
455
  getChildren,
607
- }: DFSParams<TContext>): ?TContext {
456
+ }: {|
457
+ visit: GraphVisitor<NodeId, TContext>,
458
+ getChildren(nodeId: NodeId): Array<NodeId>,
459
+ startNodeId?: ?NodeId,
460
+ |}): ?TContext {
608
461
  let traversalStartNode = nullthrows(
609
462
  startNodeId ?? this.rootNodeId,
610
463
  'A start node is required to traverse',
@@ -2,10 +2,9 @@
2
2
 
3
3
  import assert from 'assert';
4
4
  import sinon from 'sinon';
5
- import type {TraversalActions} from '@parcel/types-internal';
6
5
 
7
- import Graph, {type DFSParams} from '../src/Graph';
8
- import {toNodeId, type NodeId} from '../src/types';
6
+ import Graph from '../src/Graph';
7
+ import {toNodeId} from '../src/types';
9
8
 
10
9
  describe('Graph', () => {
11
10
  it('constructor should initialize an empty graph', () => {
@@ -341,229 +340,4 @@ describe('Graph', () => {
341
340
  assert.deepEqual(graph.nodes.filter(Boolean), ['root']);
342
341
  assert.deepStrictEqual(Array.from(graph.getAllEdges()), []);
343
342
  });
344
-
345
- describe('dfs(...)', () => {
346
- function testSuite(
347
- name: string,
348
- dfsImpl: (graph: Graph<string>, DFSParams<mixed>) => mixed | null | void,
349
- ) {
350
- it(`${name} throws if the graph is empty`, () => {
351
- const graph = new Graph();
352
- const visit = sinon.stub();
353
- const getChildren = sinon.stub();
354
- assert.throws(() => {
355
- dfsImpl(graph, {
356
- visit,
357
- startNodeId: 0,
358
- getChildren,
359
- });
360
- }, /Does not have node 0/);
361
- });
362
-
363
- it(`${name} visits a single node`, () => {
364
- const graph = new Graph();
365
- graph.addNode('root');
366
- const visit = sinon.stub();
367
- const getChildren = () => [];
368
- dfsImpl(graph, {
369
- visit,
370
- startNodeId: 0,
371
- getChildren,
372
- });
373
-
374
- assert(visit.calledOnce);
375
- });
376
-
377
- it(`${name} visits all connected nodes in DFS order`, () => {
378
- const graph = new Graph();
379
- graph.addNode('0');
380
- graph.addNode('1');
381
- graph.addNode('2');
382
- graph.addNode('3');
383
- graph.addNode('disconnected-1');
384
- graph.addNode('disconnected-2');
385
- graph.addEdge(0, 1);
386
- graph.addEdge(0, 2);
387
- graph.addEdge(1, 3);
388
- graph.addEdge(2, 3);
389
-
390
- const order = [];
391
- const visit = (node: NodeId) => {
392
- order.push(node);
393
- };
394
- const getChildren = (node: NodeId) =>
395
- graph.getNodeIdsConnectedFrom(node);
396
- dfsImpl(graph, {
397
- visit,
398
- startNodeId: 0,
399
- getChildren,
400
- });
401
-
402
- assert.deepEqual(order, [0, 1, 3, 2]);
403
- });
404
-
405
- describe(`${name} actions tests`, () => {
406
- it(`${name} skips children if skip is called on a node`, () => {
407
- const graph = new Graph();
408
- graph.addNode('0');
409
- graph.addNode('1');
410
- graph.addNode('2');
411
- graph.addNode('3');
412
- graph.addNode('disconnected-1');
413
- graph.addNode('disconnected-2');
414
- graph.addEdge(0, 1);
415
- graph.addEdge(1, 2);
416
- graph.addEdge(0, 3);
417
-
418
- const order = [];
419
- const visit = (
420
- node: NodeId,
421
- context: mixed | null,
422
- actions: TraversalActions,
423
- ) => {
424
- if (node === 1) actions.skipChildren();
425
- order.push(node);
426
- };
427
- const getChildren = (node: NodeId) =>
428
- graph.getNodeIdsConnectedFrom(node);
429
- dfsImpl(graph, {
430
- visit,
431
- startNodeId: 0,
432
- getChildren,
433
- });
434
-
435
- assert.deepEqual(order, [0, 1, 3]);
436
- });
437
-
438
- it(`${name} stops the traversal if stop is called`, () => {
439
- const graph = new Graph();
440
- graph.addNode('0');
441
- graph.addNode('1');
442
- graph.addNode('2');
443
- graph.addNode('3');
444
- graph.addNode('disconnected-1');
445
- graph.addNode('disconnected-2');
446
- graph.addEdge(0, 1);
447
- graph.addEdge(1, 2);
448
- graph.addEdge(1, 3);
449
- graph.addEdge(0, 2);
450
- graph.addEdge(2, 3);
451
-
452
- const order = [];
453
- const visit = (
454
- node: NodeId,
455
- context: mixed | null,
456
- actions: TraversalActions,
457
- ) => {
458
- order.push(node);
459
- if (node === 1) {
460
- actions.stop();
461
- return 'result';
462
- }
463
- return 'other';
464
- };
465
- const getChildren = (node: NodeId) =>
466
- graph.getNodeIdsConnectedFrom(node);
467
- const result = dfsImpl(graph, {
468
- visit,
469
- startNodeId: 0,
470
- getChildren,
471
- });
472
-
473
- assert.deepEqual(order, [0, 1]);
474
- assert.equal(result, 'result');
475
- });
476
- });
477
-
478
- describe(`${name} context tests`, () => {
479
- it(`${name} passes the context between visitors`, () => {
480
- const graph = new Graph();
481
- graph.addNode('0');
482
- graph.addNode('1');
483
- graph.addNode('2');
484
- graph.addNode('3');
485
- graph.addNode('disconnected-1');
486
- graph.addNode('disconnected-2');
487
- graph.addEdge(0, 1);
488
- graph.addEdge(1, 2);
489
- graph.addEdge(1, 3);
490
- graph.addEdge(0, 2);
491
- graph.addEdge(2, 3);
492
-
493
- const contexts = [];
494
- const visit = (node: NodeId, context: mixed | null) => {
495
- contexts.push([node, context]);
496
- return `node-${node}-created-context`;
497
- };
498
- const getChildren = (node: NodeId) =>
499
- graph.getNodeIdsConnectedFrom(node);
500
- const result = dfsImpl(graph, {
501
- visit,
502
- startNodeId: 0,
503
- getChildren,
504
- });
505
-
506
- assert.deepEqual(contexts, [
507
- [0, undefined],
508
- [1, 'node-0-created-context'],
509
- [2, 'node-1-created-context'],
510
- [3, 'node-2-created-context'],
511
- ]);
512
- assert.equal(result, undefined);
513
- });
514
- });
515
-
516
- describe(`${name} exit visitor tests`, () => {
517
- it(`${name} calls the exit visitor`, () => {
518
- const graph = new Graph();
519
- graph.addNode('0');
520
- graph.addNode('1');
521
- graph.addNode('2');
522
- graph.addNode('3');
523
- graph.addNode('disconnected-1');
524
- graph.addNode('disconnected-2');
525
- graph.addEdge(0, 1);
526
- graph.addEdge(1, 2);
527
- graph.addEdge(1, 3);
528
- graph.addEdge(0, 2);
529
-
530
- const contexts = [];
531
- const visit = (node: NodeId, context: mixed | null) => {
532
- contexts.push([node, context]);
533
- return `node-${node}-created-context`;
534
- };
535
- const visitExit = (node: NodeId, context: mixed | null) => {
536
- contexts.push(['exit', node, context]);
537
- return `node-exit-${node}-created-context`;
538
- };
539
- const getChildren = (node: NodeId) =>
540
- graph.getNodeIdsConnectedFrom(node);
541
- const result = dfsImpl(graph, {
542
- visit: {
543
- enter: visit,
544
- exit: visitExit,
545
- },
546
- startNodeId: 0,
547
- getChildren,
548
- });
549
-
550
- assert.deepEqual(contexts, [
551
- [0, undefined],
552
- [1, 'node-0-created-context'],
553
- [2, 'node-1-created-context'],
554
- ['exit', 2, 'node-2-created-context'],
555
- [3, 'node-1-created-context'],
556
- ['exit', 3, 'node-3-created-context'],
557
- ['exit', 1, 'node-1-created-context'],
558
- ['exit', 0, 'node-0-created-context'],
559
- ]);
560
- assert.equal(result, undefined);
561
- });
562
- });
563
- }
564
-
565
- testSuite('dfs', (graph, params) => graph.dfs(params));
566
-
567
- testSuite('dfsNew', (graph, params) => graph.dfsNew(params));
568
- });
569
343
  });