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

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.
@@ -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
  });