diff --git a/packages/core/core/src/BundleGraph.js b/packages/core/core/src/BundleGraph.js index ca6aebbad01..6436d994b51 100644 --- a/packages/core/core/src/BundleGraph.js +++ b/packages/core/core/src/BundleGraph.js @@ -35,16 +35,16 @@ import {getBundleGroupId, getPublicId} from './utils'; import {ISOLATED_ENVS} from './public/Environment'; import {fromProjectPath} from './projectPath'; -type BundleGraphEdgeTypes = +export const bundleGraphEdgeTypes = { // A lack of an edge type indicates to follow the edge while traversing // the bundle's contents, e.g. `bundle.traverse()` during packaging. - | null + null: 1, // Used for constant-time checks of presence of a dependency or asset in a bundle, // avoiding bundle traversal in cases like `isAssetInAncestors` - | 'contains' + contains: 2, // Connections between bundles and bundle groups, for quick traversal of the // bundle hierarchy. - | 'bundle' + bundle: 3, // When dependency -> asset: Indicates that the asset a dependency references // is contained in another bundle. // When dependency -> bundle: Indicates the bundle is necessary for any bundles @@ -54,10 +54,13 @@ type BundleGraphEdgeTypes = // This type prevents referenced assets from being traversed from dependencies // along the untyped edge, and enables traversal to referenced bundles that are // not directly connected to bundle group nodes. - | 'references' + references: 4, // Signals that the dependency is internally resolvable via the bundle's ancestry, // and that the bundle connected to the dependency is not necessary for the source bundle. - | 'internal_async'; + internal_async: 5, +}; + +export type BundleGraphEdgeType = $Values; type InternalSymbolResolution = {| asset: Asset, @@ -73,7 +76,7 @@ type InternalExportSymbolResolution = {| type SerializedBundleGraph = {| $$raw: true, - graph: SerializedContentGraph, + graph: SerializedContentGraph, bundleContentHashes: Map, assetPublicIds: Set, publicIdByAssetId: Map, @@ -102,7 +105,7 @@ export default class BundleGraph { // BundlerRunner takes care of invalidating hashes when runtimes are applied, but this is not ideal. _bundleContentHashes: Map; _targetEntryRoots: Map = new Map(); - _graph: ContentGraph; + _graph: ContentGraph; constructor({ graph, @@ -110,7 +113,7 @@ export default class BundleGraph { assetPublicIds, bundleContentHashes, }: {| - graph: ContentGraph, + graph: ContentGraph, publicIdByAssetId: Map, assetPublicIds: Set, bundleContentHashes: Map, @@ -126,7 +129,7 @@ export default class BundleGraph { publicIdByAssetId: Map = new Map(), assetPublicIds: Set = new Set(), ): BundleGraph { - let graph = new ContentGraph(); + let graph = new ContentGraph(); let assetGroupIds = new Set(); let assetGraphNodeIdToBundleGraphNodeId = new Map(); @@ -166,14 +169,22 @@ export default class BundleGraph { for (let edge of assetGraph.getAllEdges()) { let fromIds; if (assetGroupIds.has(edge.from)) { - fromIds = [...assetGraph.inboundEdges.getEdges(edge.from, null)]; + fromIds = [ + ...assetGraph.inboundEdges.getEdges( + edge.from, + bundleGraphEdgeTypes.null, + ), + ]; } else { fromIds = [edge.from]; } for (let from of fromIds) { if (assetGroupIds.has(edge.to)) { - for (let to of assetGraph.outboundEdges.getEdges(edge.to, null)) { + for (let to of assetGraph.outboundEdges.getEdges( + edge.to, + bundleGraphEdgeTypes.null, + )) { graph.addEdge( nullthrows(assetGraphNodeIdToBundleGraphNodeId.get(from)), nullthrows(assetGraphNodeIdToBundleGraphNodeId.get(to)), @@ -240,7 +251,11 @@ export default class BundleGraph { } if (node.type === 'asset' || node.type === 'dependency') { - this._graph.addEdge(bundleNodeId, nodeId, 'contains'); + this._graph.addEdge( + bundleNodeId, + nodeId, + bundleGraphEdgeTypes.contains, + ); } if (node.type === 'dependency') { @@ -249,18 +264,26 @@ export default class BundleGraph { .map(id => [id, nullthrows(this._graph.getNode(id))]) .filter(([, node]) => node.type === 'bundle_group')) { invariant(bundleGroupNode.type === 'bundle_group'); - this._graph.addEdge(bundleNodeId, bundleGroupNodeId, 'bundle'); + this._graph.addEdge( + bundleNodeId, + bundleGroupNodeId, + bundleGraphEdgeTypes.bundle, + ); } // If the dependency references a target bundle, add a reference edge from // the source bundle to the dependency for easy traversal. if ( this._graph - .getNodeIdsConnectedFrom(nodeId, 'references') + .getNodeIdsConnectedFrom(nodeId, bundleGraphEdgeTypes.references) .map(id => nullthrows(this._graph.getNode(id))) .some(node => node.type === 'bundle') ) { - this._graph.addEdge(bundleNodeId, nodeId, 'references'); + this._graph.addEdge( + bundleNodeId, + nodeId, + bundleGraphEdgeTypes.references, + ); } } }, assetNodeId); @@ -286,7 +309,7 @@ export default class BundleGraph { this._graph.addEdge( this._graph.getNodeIdByContentKey(bundle.id), this._graph.getNodeIdByContentKey(dependency.id), - 'internal_async', + bundleGraphEdgeTypes.internal_async, ); this.removeExternalDependency(bundle, dependency); } @@ -301,7 +324,7 @@ export default class BundleGraph { return this._graph .getNodeIdsConnectedTo( this._graph.getNodeIdByContentKey(getBundleGroupId(bundleGroup)), - 'bundle', + bundleGraphEdgeTypes.bundle, ) .map(id => nullthrows(this._graph.getNode(id))) .filter(node => node.type === 'bundle') @@ -324,11 +347,15 @@ export default class BundleGraph { if ( bundleNodeId != null && - this._graph.hasEdge(bundleNodeId, depNodeId, 'internal_async') + this._graph.hasEdge( + bundleNodeId, + depNodeId, + bundleGraphEdgeTypes.internal_async, + ) ) { let referencedAssetNodeIds = this._graph.getNodeIdsConnectedFrom( depNodeId, - 'references', + bundleGraphEdgeTypes.references, ); let resolved; @@ -396,7 +423,10 @@ export default class BundleGraph { includeInline: true, }); let referenced = this._graph - .getNodeIdsConnectedFrom(dependencyNodeId, 'references') + .getNodeIdsConnectedFrom( + dependencyNodeId, + bundleGraphEdgeTypes.references, + ) .map(id => nullthrows(this._graph.getNode(id))) .find(node => node.type === 'asset'); @@ -426,11 +456,13 @@ export default class BundleGraph { return; } - if (this._graph.hasEdge(bundleNodeId, nodeId, 'contains')) { + if ( + this._graph.hasEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.contains) + ) { this._graph.removeEdge( bundleNodeId, nodeId, - 'contains', + bundleGraphEdgeTypes.contains, // Removing this contains edge should not orphan the connected node. This // is disabled for performance reasons as these edges are removed as part // of a traversal, and checking for orphans becomes quite expensive in @@ -455,11 +487,31 @@ export default class BundleGraph { if (node.type === 'dependency') { this.removeExternalDependency(bundle, node.value); - if (this._graph.hasEdge(bundleNodeId, nodeId, 'references')) { - this._graph.addEdge(bundleNodeId, nodeId, 'references'); + if ( + this._graph.hasEdge( + bundleNodeId, + nodeId, + bundleGraphEdgeTypes.references, + ) + ) { + this._graph.addEdge( + bundleNodeId, + nodeId, + bundleGraphEdgeTypes.references, + ); } - if (this._graph.hasEdge(bundleNodeId, nodeId, 'internal_async')) { - this._graph.removeEdge(bundleNodeId, nodeId, 'internal_async'); + if ( + this._graph.hasEdge( + bundleNodeId, + nodeId, + bundleGraphEdgeTypes.internal_async, + ) + ) { + this._graph.removeEdge( + bundleNodeId, + nodeId, + bundleGraphEdgeTypes.internal_async, + ); } } }, assetNodeId); @@ -478,7 +530,7 @@ export default class BundleGraph { let bundleGroupNodeIds = this._graph.getNodeIdsConnectedTo( bundleNodeId, - 'bundle', + bundleGraphEdgeTypes.bundle, ); this._graph.removeNode(bundleNodeId); @@ -551,7 +603,13 @@ export default class BundleGraph { bundleGroupNode.id, ); - if (!this._graph.hasEdge(bundleNodeId, bundleGroupNodeId, 'bundle')) { + if ( + !this._graph.hasEdge( + bundleNodeId, + bundleGroupNodeId, + bundleGraphEdgeTypes.bundle, + ) + ) { continue; } @@ -574,11 +632,15 @@ export default class BundleGraph { this._graph.hasEdge( bundleNodeId, this._graph.getNodeIdByContentKey(dependency.id), - 'internal_async', + bundleGraphEdgeTypes.internal_async, ), ) ) { - this._graph.removeEdge(bundleNodeId, bundleGroupNodeId, 'bundle'); + this._graph.removeEdge( + bundleNodeId, + bundleGroupNodeId, + bundleGraphEdgeTypes.bundle, + ); } } } @@ -591,9 +653,13 @@ export default class BundleGraph { let dependencyId = this._graph.getNodeIdByContentKey(dependency.id); let assetId = this._graph.getNodeIdByContentKey(asset.id); let bundleId = this._graph.getNodeIdByContentKey(bundle.id); - this._graph.addEdge(dependencyId, assetId, 'references'); + this._graph.addEdge(dependencyId, assetId, bundleGraphEdgeTypes.references); - this._graph.addEdge(dependencyId, bundleId, 'references'); + this._graph.addEdge( + dependencyId, + bundleId, + bundleGraphEdgeTypes.references, + ); if (this._graph.hasEdge(dependencyId, assetId)) { this._graph.removeEdge(dependencyId, assetId); } @@ -603,7 +669,7 @@ export default class BundleGraph { this._graph.addEdge( this._graph.getNodeIdByContentKey(from.id), this._graph.getNodeIdByContentKey(to.id), - 'references', + bundleGraphEdgeTypes.references, ); } @@ -611,7 +677,7 @@ export default class BundleGraph { return this._graph .getNodeIdsConnectedTo( this._graph.getNodeIdByContentKey(asset.id), - 'contains', + bundleGraphEdgeTypes.contains, ) .map(id => nullthrows(this._graph.getNode(id))) .filter(node => node.type === 'bundle') @@ -625,7 +691,7 @@ export default class BundleGraph { return this._graph .getNodeIdsConnectedTo( nullthrows(this._graph.getNodeIdByContentKey(dependency.id)), - 'contains', + bundleGraphEdgeTypes.contains, ) .map(id => nullthrows(this._graph.getNode(id))) .filter(node => node.type === 'bundle') @@ -670,7 +736,7 @@ export default class BundleGraph { } }, this._graph.getNodeIdByContentKey(dep.id), - 'references', + bundleGraphEdgeTypes.references, ); } @@ -701,7 +767,7 @@ export default class BundleGraph { if ( this._graph - .getNodeIdsConnectedTo(assetNodeId, 'references') + .getNodeIdsConnectedTo(assetNodeId, bundleGraphEdgeTypes.references) .map(id => this._graph.getNode(id)) .some( node => @@ -827,7 +893,7 @@ export default class BundleGraph { // Get a list of parent bundle nodes pointing to the bundle group let parentBundleNodes = this._graph.getNodeIdsConnectedTo( this._graph.getNodeIdByContentKey(getBundleGroupId(bundleGroup)), - 'bundle', + bundleGraphEdgeTypes.bundle, ); // Check that every parent bundle has a bundle group in its ancestry that contains the asset. @@ -875,7 +941,7 @@ export default class BundleGraph { } } }, - ['references', 'bundle'], + [bundleGraphEdgeTypes.references, bundleGraphEdgeTypes.bundle], ); return isReachable; @@ -901,7 +967,13 @@ export default class BundleGraph { } if (node.type === 'dependency' || node.type === 'asset') { - if (this._graph.hasEdge(bundleNodeId, nodeId, 'contains')) { + if ( + this._graph.hasEdge( + bundleNodeId, + nodeId, + bundleGraphEdgeTypes.contains, + ) + ) { return node; } } @@ -985,7 +1057,7 @@ export default class BundleGraph { }, visit, startBundle ? this._graph.getNodeIdByContentKey(startBundle.id) : null, - ['bundle', 'references'], + [bundleGraphEdgeTypes.bundle, bundleGraphEdgeTypes.references], ); } @@ -1030,7 +1102,7 @@ export default class BundleGraph { referencingBundles.add(node.value); } }, - 'references', + bundleGraphEdgeTypes.references, ); return [...referencingBundles]; @@ -1052,7 +1124,7 @@ export default class BundleGraph { return this._graph .getNodeIdsConnectedTo( nullthrows(this._graph.getNodeIdByContentKey(bundle.id)), - 'bundle', + bundleGraphEdgeTypes.bundle, ) .map(id => nullthrows(this._graph.getNode(id))) .filter(node => node.type === 'bundle_group') @@ -1069,7 +1141,7 @@ export default class BundleGraph { let bundles: Set = new Set(); for (let bundleNodeId of this._graph.getNodeIdsConnectedFrom( this._graph.getNodeIdByContentKey(getBundleGroupId(bundleGroup)), - 'bundle', + bundleGraphEdgeTypes.bundle, )) { let bundleNode = nullthrows(this._graph.getNode(bundleNodeId)); invariant(bundleNode.type === 'bundle'); @@ -1125,7 +1197,9 @@ export default class BundleGraph { // Shared bundles seem to depend on being used in the opposite order // they were added. // TODO: Should this be the case? - this._graph.getNodeIdsConnectedFrom(nodeId, 'references').reverse(), + this._graph + .getNodeIdsConnectedFrom(nodeId, bundleGraphEdgeTypes.references) + .reverse(), }); return [...referencedBundles]; @@ -1172,13 +1246,21 @@ export default class BundleGraph { bundleHasAsset(bundle: Bundle, asset: Asset): boolean { let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id); let assetNodeId = this._graph.getNodeIdByContentKey(asset.id); - return this._graph.hasEdge(bundleNodeId, assetNodeId, 'contains'); + return this._graph.hasEdge( + bundleNodeId, + assetNodeId, + bundleGraphEdgeTypes.contains, + ); } bundleHasDependency(bundle: Bundle, dependency: Dependency): boolean { let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id); let dependencyNodeId = this._graph.getNodeIdByContentKey(dependency.id); - return this._graph.hasEdge(bundleNodeId, dependencyNodeId, 'contains'); + return this._graph.hasEdge( + bundleNodeId, + dependencyNodeId, + bundleGraphEdgeTypes.contains, + ); } filteredTraverse( @@ -1493,13 +1575,23 @@ export default class BundleGraph { getBundleGroupId(bundleGroup), ); let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id); - if (this._graph.hasEdge(bundleGroupNodeId, bundleNodeId, 'bundle')) { + if ( + this._graph.hasEdge( + bundleGroupNodeId, + bundleNodeId, + bundleGraphEdgeTypes.bundle, + ) + ) { // Bundle group already has bundle return; } this._graph.addEdge(bundleGroupNodeId, bundleNodeId); - this._graph.addEdge(bundleGroupNodeId, bundleNodeId, 'bundle'); + this._graph.addEdge( + bundleGroupNodeId, + bundleNodeId, + bundleGraphEdgeTypes.bundle, + ); for (let entryAssetId of bundle.entryAssetIds) { let entryAssetNodeId = this._graph.getNodeIdByContentKey(entryAssetId); @@ -1575,7 +1667,7 @@ export default class BundleGraph { nullthrows( this._graph.getNodeIdByContentKey(getBundleGroupId(bundleGroup)), ), - 'bundle', + bundleGraphEdgeTypes.bundle, ) .map(id => nullthrows(this._graph.getNode(id))) .some(n => n.type === 'root'); @@ -1589,7 +1681,7 @@ export default class BundleGraph { let entryBundleGroupIds = this._graph.getNodeIdsConnectedFrom( nullthrows(this._graph.rootNodeId), - 'bundle', + bundleGraphEdgeTypes.bundle, ); let entries = []; diff --git a/packages/core/core/src/Parcel.js b/packages/core/core/src/Parcel.js index 9aa0d713faa..70b3b24d79f 100644 --- a/packages/core/core/src/Parcel.js +++ b/packages/core/core/src/Parcel.js @@ -31,7 +31,10 @@ import {AbortController} from 'abortcontroller-polyfill/dist/cjs-ponyfill'; import {PromiseQueue} from '@parcel/utils'; import ParcelConfig from './ParcelConfig'; import logger from '@parcel/logger'; -import RequestTracker, {getWatcherOptions} from './RequestTracker'; +import RequestTracker, { + getWatcherOptions, + requestGraphEdgeTypes, +} from './RequestTracker'; import createValidationRequest from './requests/ValidationRequest'; import createParcelBuildRequest from './requests/ParcelBuildRequest'; import {Disposable} from '@parcel/events'; @@ -274,8 +277,12 @@ export default class Parcel { this.#requestedAssetIds.clear(); - // $FlowFixMe - dumpGraphToGraphViz(this.#requestTracker.graph, 'RequestGraph'); + dumpGraphToGraphViz( + // $FlowFixMe + this.#requestTracker.graph, + 'RequestGraph', + requestGraphEdgeTypes, + ); let event = { type: 'buildSuccess', diff --git a/packages/core/core/src/RequestTracker.js b/packages/core/core/src/RequestTracker.js index 1d03e49a6cf..6fedb3cf09a 100644 --- a/packages/core/core/src/RequestTracker.js +++ b/packages/core/core/src/RequestTracker.js @@ -45,6 +45,16 @@ import { ERROR, } from './constants'; +export const requestGraphEdgeTypes = { + subrequest: 2, + invalidated_by_update: 3, + invalidated_by_delete: 4, + invalidated_by_create: 5, + invalidated_by_create_above: 6, + dirname: 7, +}; + +export type RequestGraphEdgeType = $Values; type SerializedRequestGraph = {| ...SerializedContentGraph, invalidNodeIds: Set, @@ -103,14 +113,6 @@ type RequestGraphNode = | EnvNode | OptionNode; -type RequestGraphEdgeType = - | 'subrequest' - | 'invalidated_by_update' - | 'invalidated_by_delete' - | 'invalidated_by_create' - | 'invalidated_by_create_above' - | 'dirname'; - export type RunAPI = {| invalidateOnFileCreate: InternalFileCreateInvalidation => void, invalidateOnFileDelete: ProjectPath => void, @@ -280,7 +282,7 @@ export class RequestGraph extends ContentGraph< requestNodeId, subrequestNodeIds, null, - 'subrequest', + requestGraphEdgeTypes.subrequest, ); } @@ -290,7 +292,10 @@ export class RequestGraph extends ContentGraph< node.invalidateReason |= reason; this.invalidNodeIds.add(nodeId); - let parentNodes = this.getNodeIdsConnectedTo(nodeId, 'subrequest'); + let parentNodes = this.getNodeIdsConnectedTo( + nodeId, + requestGraphEdgeTypes.subrequest, + ); for (let parentNode of parentNodes) { this.invalidateNode(parentNode, reason); } @@ -311,7 +316,7 @@ export class RequestGraph extends ContentGraph< if (env[node.value.key] !== node.value.value) { let parentNodes = this.getNodeIdsConnectedTo( nodeId, - 'invalidated_by_update', + requestGraphEdgeTypes.invalidated_by_update, ); for (let parentNode of parentNodes) { this.invalidateNode(parentNode, ENV_CHANGE); @@ -327,7 +332,7 @@ export class RequestGraph extends ContentGraph< if (hashFromOption(options[node.value.key]) !== node.value.hash) { let parentNodes = this.getNodeIdsConnectedTo( nodeId, - 'invalidated_by_update', + requestGraphEdgeTypes.invalidated_by_update, ); for (let parentNode of parentNodes) { this.invalidateNode(parentNode, OPTION_CHANGE); @@ -339,16 +344,36 @@ export class RequestGraph extends ContentGraph< invalidateOnFileUpdate(requestNodeId: NodeId, filePath: ProjectPath) { let fileNodeId = this.addNode(nodeFromFilePath(filePath)); - if (!this.hasEdge(requestNodeId, fileNodeId, 'invalidated_by_update')) { - this.addEdge(requestNodeId, fileNodeId, 'invalidated_by_update'); + if ( + !this.hasEdge( + requestNodeId, + fileNodeId, + requestGraphEdgeTypes.invalidated_by_update, + ) + ) { + this.addEdge( + requestNodeId, + fileNodeId, + requestGraphEdgeTypes.invalidated_by_update, + ); } } invalidateOnFileDelete(requestNodeId: NodeId, filePath: ProjectPath) { let fileNodeId = this.addNode(nodeFromFilePath(filePath)); - if (!this.hasEdge(requestNodeId, fileNodeId, 'invalidated_by_delete')) { - this.addEdge(requestNodeId, fileNodeId, 'invalidated_by_delete'); + if ( + !this.hasEdge( + requestNodeId, + fileNodeId, + requestGraphEdgeTypes.invalidated_by_delete, + ) + ) { + this.addEdge( + requestNodeId, + fileNodeId, + requestGraphEdgeTypes.invalidated_by_delete, + ); } } @@ -375,9 +400,17 @@ export class RequestGraph extends ContentGraph< let fileNameNodeId = this.addNode(fileNameNode); if ( lastNodeId != null && - !this.hasEdge(lastNodeId, fileNameNodeId, 'dirname') + !this.hasEdge( + lastNodeId, + fileNameNodeId, + requestGraphEdgeTypes.dirname, + ) ) { - this.addEdge(lastNodeId, fileNameNodeId, 'dirname'); + this.addEdge( + lastNodeId, + fileNameNodeId, + requestGraphEdgeTypes.dirname, + ); } lastNodeId = fileNameNodeId; @@ -399,13 +432,33 @@ export class RequestGraph extends ContentGraph< // node will be invalidated. let firstId = 'file_name:' + parts[0]; let firstNodeId = this.getNodeIdByContentKey(firstId); - if (!this.hasEdge(nodeId, firstNodeId, 'invalidated_by_create_above')) { - this.addEdge(nodeId, firstNodeId, 'invalidated_by_create_above'); + if ( + !this.hasEdge( + nodeId, + firstNodeId, + requestGraphEdgeTypes.invalidated_by_create_above, + ) + ) { + this.addEdge( + nodeId, + firstNodeId, + requestGraphEdgeTypes.invalidated_by_create_above, + ); } invariant(lastNodeId != null); - if (!this.hasEdge(lastNodeId, nodeId, 'invalidated_by_create_above')) { - this.addEdge(lastNodeId, nodeId, 'invalidated_by_create_above'); + if ( + !this.hasEdge( + lastNodeId, + nodeId, + requestGraphEdgeTypes.invalidated_by_create_above, + ) + ) { + this.addEdge( + lastNodeId, + nodeId, + requestGraphEdgeTypes.invalidated_by_create_above, + ); } } else if (input.filePath != null) { node = nodeFromFilePath(input.filePath); @@ -414,8 +467,18 @@ export class RequestGraph extends ContentGraph< } let nodeId = this.addNode(node); - if (!this.hasEdge(requestNodeId, nodeId, 'invalidated_by_create')) { - this.addEdge(requestNodeId, nodeId, 'invalidated_by_create'); + if ( + !this.hasEdge( + requestNodeId, + nodeId, + requestGraphEdgeTypes.invalidated_by_create, + ) + ) { + this.addEdge( + requestNodeId, + nodeId, + requestGraphEdgeTypes.invalidated_by_create, + ); } } @@ -432,8 +495,18 @@ export class RequestGraph extends ContentGraph< let envNode = nodeFromEnv(env, value); let envNodeId = this.addNode(envNode); - if (!this.hasEdge(requestNodeId, envNodeId, 'invalidated_by_update')) { - this.addEdge(requestNodeId, envNodeId, 'invalidated_by_update'); + if ( + !this.hasEdge( + requestNodeId, + envNodeId, + requestGraphEdgeTypes.invalidated_by_update, + ) + ) { + this.addEdge( + requestNodeId, + envNodeId, + requestGraphEdgeTypes.invalidated_by_update, + ); } } @@ -445,16 +518,41 @@ export class RequestGraph extends ContentGraph< let optionNode = nodeFromOption(option, value); let optionNodeId = this.addNode(optionNode); - if (!this.hasEdge(requestNodeId, optionNodeId, 'invalidated_by_update')) { - this.addEdge(requestNodeId, optionNodeId, 'invalidated_by_update'); + if ( + !this.hasEdge( + requestNodeId, + optionNodeId, + requestGraphEdgeTypes.invalidated_by_update, + ) + ) { + this.addEdge( + requestNodeId, + optionNodeId, + requestGraphEdgeTypes.invalidated_by_update, + ); } } clearInvalidations(nodeId: NodeId) { this.unpredicatableNodeIds.delete(nodeId); - this.replaceNodeIdsConnectedTo(nodeId, [], null, 'invalidated_by_update'); - this.replaceNodeIdsConnectedTo(nodeId, [], null, 'invalidated_by_delete'); - this.replaceNodeIdsConnectedTo(nodeId, [], null, 'invalidated_by_create'); + this.replaceNodeIdsConnectedTo( + nodeId, + [], + null, + requestGraphEdgeTypes.invalidated_by_update, + ); + this.replaceNodeIdsConnectedTo( + nodeId, + [], + null, + requestGraphEdgeTypes.invalidated_by_delete, + ); + this.replaceNodeIdsConnectedTo( + nodeId, + [], + null, + requestGraphEdgeTypes.invalidated_by_create, + ); } getInvalidations(requestNodeId: NodeId): Array { @@ -465,7 +563,7 @@ export class RequestGraph extends ContentGraph< // For now just handling updates. Could add creates/deletes later if needed. let invalidations = this.getNodeIdsConnectedFrom( requestNodeId, - 'invalidated_by_update', + requestGraphEdgeTypes.invalidated_by_update, ); return invalidations .map(nodeId => { @@ -487,7 +585,10 @@ export class RequestGraph extends ContentGraph< return []; } - let subRequests = this.getNodeIdsConnectedFrom(requestNodeId, 'subrequest'); + let subRequests = this.getNodeIdsConnectedFrom( + requestNodeId, + requestGraphEdgeTypes.subrequest, + ); return subRequests.map(nodeId => { let node = nullthrows(this.getNode(nodeId)); @@ -510,7 +611,11 @@ export class RequestGraph extends ContentGraph< for (let matchNode of matchNodes) { let matchNodeId = this.getNodeIdByContentKey(matchNode.id); if ( - this.hasEdge(nodeId, matchNodeId, 'invalidated_by_create_above') && + this.hasEdge( + nodeId, + matchNodeId, + requestGraphEdgeTypes.invalidated_by_create_above, + ) && isDirectoryInside( path.dirname(fromProjectPathRelative(matchNode.value.filePath)), dirname, @@ -518,7 +623,7 @@ export class RequestGraph extends ContentGraph< ) { let connectedNodes = this.getNodeIdsConnectedTo( matchNodeId, - 'invalidated_by_create', + requestGraphEdgeTypes.invalidated_by_create, ); for (let connectedNode of connectedNodes) { this.invalidateNode(connectedNode, FILE_CREATE); @@ -532,7 +637,11 @@ export class RequestGraph extends ContentGraph< let contentKey = 'file_name:' + basename; if (this.hasContentKey(contentKey)) { if ( - this.hasEdge(nodeId, this.getNodeIdByContentKey(contentKey), 'dirname') + this.hasEdge( + nodeId, + this.getNodeIdByContentKey(contentKey), + requestGraphEdgeTypes.dirname, + ) ) { let parent = nullthrows(this.getNodeByContentKey(contentKey)); invariant(parent.type === 'file_name'); @@ -570,7 +679,10 @@ export class RequestGraph extends ContentGraph< // then also invalidate nodes connected by invalidated_by_update edges. if (hasFileRequest && (type === 'create' || type === 'update')) { let nodeId = this.getNodeIdByContentKey(filePath); - let nodes = this.getNodeIdsConnectedTo(nodeId, 'invalidated_by_update'); + let nodes = this.getNodeIdsConnectedTo( + nodeId, + requestGraphEdgeTypes.invalidated_by_update, + ); for (let connectedNode of nodes) { didInvalidate = true; @@ -580,7 +692,7 @@ export class RequestGraph extends ContentGraph< if (type === 'create') { let nodes = this.getNodeIdsConnectedTo( nodeId, - 'invalidated_by_create', + requestGraphEdgeTypes.invalidated_by_create, ); for (let connectedNode of nodes) { didInvalidate = true; @@ -597,7 +709,7 @@ export class RequestGraph extends ContentGraph< // Find potential file nodes to be invalidated if this file name pattern matches let above = this.getNodeIdsConnectedTo( fileNameNodeId, - 'invalidated_by_create_above', + requestGraphEdgeTypes.invalidated_by_create_above, ).map(nodeId => { let node = nullthrows(this.getNode(nodeId)); invariant(node.type === 'file'); @@ -617,7 +729,7 @@ export class RequestGraph extends ContentGraph< if (isGlobMatch(filePath, fromProjectPathRelative(globNode.value))) { let connectedNodes = this.getNodeIdsConnectedTo( globeNodeId, - 'invalidated_by_create', + requestGraphEdgeTypes.invalidated_by_create, ); for (let connectedNode of connectedNodes) { didInvalidate = true; @@ -629,7 +741,7 @@ export class RequestGraph extends ContentGraph< let nodeId = this.getNodeIdByContentKey(filePath); for (let connectedNode of this.getNodeIdsConnectedTo( nodeId, - 'invalidated_by_delete', + requestGraphEdgeTypes.invalidated_by_delete, )) { didInvalidate = true; this.invalidateNode(connectedNode, FILE_DELETE); diff --git a/packages/core/core/src/applyRuntimes.js b/packages/core/core/src/applyRuntimes.js index 1bab6a64551..fcd2a9a6707 100644 --- a/packages/core/core/src/applyRuntimes.js +++ b/packages/core/core/src/applyRuntimes.js @@ -20,7 +20,7 @@ import invariant from 'assert'; import nullthrows from 'nullthrows'; import AssetGraph, {nodeFromAssetGroup} from './AssetGraph'; import BundleGraph from './public/BundleGraph'; -import InternalBundleGraph from './BundleGraph'; +import InternalBundleGraph, {bundleGraphEdgeTypes} from './BundleGraph'; import {NamedBundle} from './public/Bundle'; import {PluginLogger} from '@parcel/logger'; import {hashString} from '@parcel/hash'; @@ -218,7 +218,11 @@ export default async function applyRuntimes({ const bundleGraphNodeId = bundleGraph._graph.getNodeIdByContentKey( node.id, ); // the node id is not constant between graphs - bundleGraph._graph.addEdge(bundleNodeId, bundleGraphNodeId, 'contains'); + bundleGraph._graph.addEdge( + bundleNodeId, + bundleGraphNodeId, + bundleGraphEdgeTypes.contains, + ); } }, runtimesGraphRuntimeNodeId); diff --git a/packages/core/core/src/dumpGraphToGraphViz.js b/packages/core/core/src/dumpGraphToGraphViz.js index 05aaaaabb0a..65ec13025cd 100644 --- a/packages/core/core/src/dumpGraphToGraphViz.js +++ b/packages/core/core/src/dumpGraphToGraphViz.js @@ -2,6 +2,8 @@ import type {Graph} from '@parcel/graph'; import type {AssetGraphNode, BundleGraphNode, Environment} from './types'; +import {bundleGraphEdgeTypes} from './BundleGraph'; +import {requestGraphEdgeTypes} from './RequestTracker'; import path from 'path'; import {fromProjectPathRelative} from './projectPath'; @@ -32,6 +34,7 @@ export default async function dumpGraphToGraphViz( // $FlowFixMe graph: Graph | Graph, name: string, + edgeTypes?: typeof bundleGraphEdgeTypes | typeof requestGraphEdgeTypes, ): Promise { if ( process.env.PARCEL_BUILD_ENV === 'production' || @@ -129,9 +132,20 @@ export default async function dumpGraphToGraphViz( } n.set('label', label); } + + let edgeNames; + if (edgeTypes) { + edgeNames = Object.fromEntries( + Object.entries(edgeTypes).map(([k, v]) => [v, k]), + ); + } + for (let edge of graph.getAllEdges()) { let gEdge = g.addEdge(nodeId(edge.from), nodeId(edge.to)); - let color = edge.type != null ? TYPE_COLORS[edge.type] : null; + let color = null; + if (edge.type != 1 && edgeNames) { + color = TYPE_COLORS[edgeNames[edge.type]]; + } if (color != null) { gEdge.set('color', color); } diff --git a/packages/core/core/src/public/MutableBundleGraph.js b/packages/core/core/src/public/MutableBundleGraph.js index e90949ae3ae..e59a2d8ac9c 100644 --- a/packages/core/core/src/public/MutableBundleGraph.js +++ b/packages/core/core/src/public/MutableBundleGraph.js @@ -15,7 +15,7 @@ import invariant from 'assert'; import nullthrows from 'nullthrows'; import {hashString} from '@parcel/hash'; import BundleGraph from './BundleGraph'; -import InternalBundleGraph from '../BundleGraph'; +import InternalBundleGraph, {bundleGraphEdgeTypes} from '../BundleGraph'; import {Bundle, bundleToInternalBundle} from './Bundle'; import {assetFromValue, assetToAssetValue} from './Asset'; import {getBundleGroupId, getPublicId} from '../utils'; @@ -107,19 +107,23 @@ export default class MutableBundleGraph extends BundleGraph ); this.#graph._graph.addEdge(dependencyNodeId, bundleGroupNodeId); this.#graph._graph.replaceNodeIdsConnectedTo(bundleGroupNodeId, assetNodes); - this.#graph._graph.addEdge(dependencyNodeId, resolvedNodeId, 'references'); + this.#graph._graph.addEdge( + dependencyNodeId, + resolvedNodeId, + bundleGraphEdgeTypes.references, + ); this.#graph._graph.removeEdge(dependencyNodeId, resolvedNodeId); if (dependency.isEntry) { this.#graph._graph.addEdge( nullthrows(this.#graph._graph.rootNodeId), bundleGroupNodeId, - 'bundle', + bundleGraphEdgeTypes.bundle, ); } else { let inboundBundleNodeIds = this.#graph._graph.getNodeIdsConnectedTo( dependencyNodeId, - 'contains', + bundleGraphEdgeTypes.contains, ); for (let inboundBundleNodeId of inboundBundleNodeIds) { invariant( @@ -128,7 +132,7 @@ export default class MutableBundleGraph extends BundleGraph this.#graph._graph.addEdge( inboundBundleNodeId, bundleGroupNodeId, - 'bundle', + bundleGraphEdgeTypes.bundle, ); } } diff --git a/packages/core/core/src/requests/BundleGraphRequest.js b/packages/core/core/src/requests/BundleGraphRequest.js index dcca6df7a53..13da2f1dbac 100644 --- a/packages/core/core/src/requests/BundleGraphRequest.js +++ b/packages/core/core/src/requests/BundleGraphRequest.js @@ -18,7 +18,7 @@ import {PluginLogger} from '@parcel/logger'; import ThrowableDiagnostic, {errorToDiagnostic} from '@parcel/diagnostic'; import AssetGraph from '../AssetGraph'; import BundleGraph from '../public/BundleGraph'; -import InternalBundleGraph from '../BundleGraph'; +import InternalBundleGraph, {bundleGraphEdgeTypes} from '../BundleGraph'; import MutableBundleGraph from '../public/MutableBundleGraph'; import {Bundle, NamedBundle} from '../public/Bundle'; import {report} from '../ReporterRunner'; @@ -200,8 +200,12 @@ class BundlerRunner { } let internalBundleGraph = InternalBundleGraph.fromAssetGraph(graph); - // $FlowFixMe - await dumpGraphToGraphViz(internalBundleGraph._graph, 'before_bundle'); + await dumpGraphToGraphViz( + // $FlowFixMe + internalBundleGraph._graph, + 'before_bundle', + bundleGraphEdgeTypes, + ); let mutableBundleGraph = new MutableBundleGraph( internalBundleGraph, this.options, @@ -223,8 +227,12 @@ class BundlerRunner { }), }); } finally { - // $FlowFixMe[incompatible-call] - await dumpGraphToGraphViz(internalBundleGraph._graph, 'after_bundle'); + await dumpGraphToGraphViz( + // $FlowFixMe[incompatible-call] + internalBundleGraph._graph, + 'after_bundle', + bundleGraphEdgeTypes, + ); } if (this.pluginOptions.mode === 'production') { @@ -242,8 +250,12 @@ class BundlerRunner { }), }); } finally { - // $FlowFixMe[incompatible-call] - await dumpGraphToGraphViz(internalBundleGraph._graph, 'after_optimize'); + await dumpGraphToGraphViz( + // $FlowFixMe[incompatible-call] + internalBundleGraph._graph, + 'after_optimize', + bundleGraphEdgeTypes, + ); } } @@ -273,8 +285,12 @@ class BundlerRunner { configs: this.configs, }); - // $FlowFixMe - await dumpGraphToGraphViz(internalBundleGraph._graph, 'after_runtimes'); + await dumpGraphToGraphViz( + // $FlowFixMe + internalBundleGraph._graph, + 'after_runtimes', + bundleGraphEdgeTypes, + ); // Store the serialized bundle graph in an in memory cache so that we avoid serializing it // many times to send to each worker, and in build mode, when writing to cache on shutdown. diff --git a/packages/core/core/src/requests/ParcelBuildRequest.js b/packages/core/core/src/requests/ParcelBuildRequest.js index 56b690afe78..ea5a2a00215 100644 --- a/packages/core/core/src/requests/ParcelBuildRequest.js +++ b/packages/core/core/src/requests/ParcelBuildRequest.js @@ -14,6 +14,7 @@ import createBundleGraphRequest from './BundleGraphRequest'; import createWriteBundlesRequest from './WriteBundlesRequest'; import {assertSignalNotAborted} from '../utils'; import dumpGraphToGraphViz from '../dumpGraphToGraphViz'; +import {bundleGraphEdgeTypes} from '../BundleGraph'; type ParcelBuildRequestInput = {| optionsRef: SharedReference, @@ -75,7 +76,7 @@ async function run({input, api, options}: RunInput) { let bundleGraph = await api.runRequest(bundleGraphRequest); // $FlowFixMe Added in Flow 0.121.0 upgrade in #4381 (Windows only) - dumpGraphToGraphViz(bundleGraph._graph, 'BundleGraph'); + dumpGraphToGraphViz(bundleGraph._graph, 'BundleGraph', bundleGraphEdgeTypes); let writeBundlesRequest = createWriteBundlesRequest({ bundleGraph, diff --git a/packages/core/core/test/AssetGraph.test.js b/packages/core/core/test/AssetGraph.test.js index 36d27794b36..ce1ed9e500d 100644 --- a/packages/core/core/test/AssetGraph.test.js +++ b/packages/core/core/test/AssetGraph.test.js @@ -154,12 +154,12 @@ describe('AssetGraph', () => { { from: graph.rootNodeId, to: graph.getNodeIdByContentKey('entry_specifier:path/to/index1'), - type: null, + type: 1, }, { from: graph.rootNodeId, to: graph.getNodeIdByContentKey('entry_specifier:path/to/index2'), - type: null, + type: 1, }, { from: graph.getNodeIdByContentKey('entry_specifier:path/to/index1'), @@ -169,7 +169,7 @@ describe('AssetGraph', () => { packagePath: toProjectPath('/path/to/index1'), }).id, ), - type: null, + type: 1, }, { from: graph.getNodeIdByContentKey('entry_specifier:path/to/index2'), @@ -179,7 +179,7 @@ describe('AssetGraph', () => { packagePath: toProjectPath('/path/to/index2'), }).id, ), - type: null, + type: 1, }, { from: graph.getNodeIdByContentKey( @@ -196,7 +196,7 @@ describe('AssetGraph', () => { env: DEFAULT_ENV, }).id, ), - type: null, + type: 1, }, { from: graph.getNodeIdByContentKey( @@ -213,7 +213,7 @@ describe('AssetGraph', () => { env: DEFAULT_ENV, }).id, ), - type: null, + type: 1, }, ]); }); diff --git a/packages/core/graph/src/ContentGraph.js b/packages/core/graph/src/ContentGraph.js index 9cfdad0e651..e43da92cddc 100644 --- a/packages/core/graph/src/ContentGraph.js +++ b/packages/core/graph/src/ContentGraph.js @@ -4,16 +4,16 @@ import type {ContentKey, NodeId} from './types'; import Graph, {type GraphOpts} from './Graph'; import nullthrows from 'nullthrows'; -export type SerializedContentGraph = {| +export type SerializedContentGraph = {| ...GraphOpts, _contentKeyToNodeId: Map, _nodeIdToContentKey: Map, |}; -export default class ContentGraph< +export default class ContentGraph extends Graph< TNode, - TEdgeType: string | null = null, -> extends Graph { + TEdgeType, +> { _contentKeyToNodeId: Map; _nodeIdToContentKey: Map; diff --git a/packages/core/graph/src/Graph.js b/packages/core/graph/src/Graph.js index fe37bfa5023..d68ced59065 100644 --- a/packages/core/graph/src/Graph.js +++ b/packages/core/graph/src/Graph.js @@ -7,21 +7,22 @@ import type {TraversalActions, GraphVisitor} from '@parcel/types'; import assert from 'assert'; import nullthrows from 'nullthrows'; -export type GraphOpts = {| +type NullEdgeType = 1; +export type GraphOpts = {| nodes?: Map, - edges?: AdjacencyListMap, + edges?: AdjacencyListMap, rootNodeId?: ?NodeId, nextNodeId?: ?number, |}; export const ALL_EDGE_TYPES = '@@all_edge_types'; -export default class Graph { +export default class Graph { nodes: Map; - inboundEdges: AdjacencyList; - outboundEdges: AdjacencyList; + inboundEdges: AdjacencyList; + outboundEdges: AdjacencyList; rootNodeId: ?NodeId; - nextNodeId: number = 0; + nextNodeId: number = 1; constructor(opts: ?GraphOpts) { this.nodes = opts?.nodes || new Map(); @@ -71,7 +72,7 @@ export default class Graph { // Returns a list of all edges in the graph. This can be large, so iterating // the complete list can be costly in large graphs. Used when merging graphs. - getAllEdges(): Array> { + getAllEdges(): Array> { let edges = []; for (let [from, edgeList] of this.outboundEdges.getListMap()) { for (let [type, toNodes] of edgeList) { @@ -97,7 +98,7 @@ export default class Graph { return this.nodes.get(id); } - addEdge(from: NodeId, to: NodeId, type: TEdgeType | null = null): void { + addEdge(from: NodeId, to: NodeId, type: TEdgeType | NullEdgeType = 1): void { if (!this.getNode(from)) { throw new Error(`"from" node '${fromNodeId(from)}' not found`); } @@ -110,13 +111,17 @@ export default class Graph { this.inboundEdges.addEdge(to, from, type); } - hasEdge(from: NodeId, to: NodeId, type?: TEdgeType | null = null): boolean { + hasEdge( + from: NodeId, + to: NodeId, + type?: TEdgeType | NullEdgeType = 1, + ): boolean { return this.outboundEdges.hasEdge(from, to, type); } getNodeIdsConnectedTo( nodeId: NodeId, - type: TEdgeType | null | Array = null, + type: TEdgeType | NullEdgeType | Array = 1, ): Array { this._assertHasNodeId(nodeId); @@ -149,7 +154,7 @@ export default class Graph { getNodeIdsConnectedFrom( nodeId: NodeId, - type: TEdgeType | null | Array = null, + type: TEdgeType | NullEdgeType | Array = 1, ): Array { this._assertHasNodeId(nodeId); let outboundByType = this.outboundEdges.getEdgesByType(nodeId); @@ -206,7 +211,7 @@ export default class Graph { assert(wasRemoved); } - removeEdges(nodeId: NodeId, type: TEdgeType | null = null) { + removeEdges(nodeId: NodeId, type: TEdgeType | NullEdgeType = 1) { this._assertHasNodeId(nodeId); for (let to of this.outboundEdges.getEdges(nodeId, type)) { @@ -218,7 +223,7 @@ export default class Graph { removeEdge( from: NodeId, to: NodeId, - type: TEdgeType | null = null, + type: TEdgeType | NullEdgeType = 1, removeOrphans: boolean = true, ) { if (!this.outboundEdges.hasEdge(from, to, type)) { @@ -290,7 +295,7 @@ export default class Graph { replaceNode( fromNodeId: NodeId, toNodeId: NodeId, - type: TEdgeType | null = null, + type: TEdgeType | NullEdgeType = 1, ): void { this._assertHasNodeId(fromNodeId); for (let parent of this.inboundEdges.getEdges(fromNodeId, type)) { @@ -305,7 +310,7 @@ export default class Graph { fromNodeId: NodeId, toNodeIds: $ReadOnlyArray, replaceFilter?: null | (NodeId => boolean), - type?: TEdgeType | null = null, + type?: TEdgeType | NullEdgeType = 1, ): void { this._assertHasNodeId(fromNodeId); @@ -331,7 +336,7 @@ export default class Graph { traverse( visit: GraphVisitor, startNodeId: ?NodeId, - type: TEdgeType | null | Array = null, + type: TEdgeType | NullEdgeType | Array = 1, ): ?TContext { return this.dfs({ visit, @@ -344,7 +349,7 @@ export default class Graph { filter: (NodeId, TraversalActions) => ?TValue, visit: GraphVisitor, startNodeId: ?NodeId, - type?: TEdgeType | null | Array, + type?: TEdgeType | Array, ): ?TContext { return this.traverse(mapVisitor(filter, visit), startNodeId, type); } @@ -352,7 +357,7 @@ export default class Graph { traverseAncestors( startNodeId: ?NodeId, visit: GraphVisitor, - type: TEdgeType | null | Array = null, + type: TEdgeType | NullEdgeType | Array = 1, ): ?TContext { return this.dfs({ visit, diff --git a/packages/core/graph/src/types.js b/packages/core/graph/src/types.js index 2e8e4d501e9..355f02d08a8 100644 --- a/packages/core/graph/src/types.js +++ b/packages/core/graph/src/types.js @@ -11,7 +11,7 @@ export function fromNodeId(x: NodeId): number { export type ContentKey = string; -export type Edge = {| +export type Edge = {| from: NodeId, to: NodeId, type: TEdgeType, diff --git a/packages/core/graph/test/Graph.test.js b/packages/core/graph/test/Graph.test.js index f311d01996b..bbecc3a28ec 100644 --- a/packages/core/graph/test/Graph.test.js +++ b/packages/core/graph/test/Graph.test.js @@ -87,7 +87,7 @@ describe('Graph', () => { let nodeB = graph.addNode('b'); let nodeC = graph.addNode('c'); graph.addEdge(nodeA, nodeB); - graph.addEdge(nodeA, nodeC, 'edgetype'); + graph.addEdge(nodeA, nodeC, 1); assert(graph.isOrphanedNode(nodeA)); assert(!graph.isOrphanedNode(nodeB)); assert(!graph.isOrphanedNode(nodeC)); @@ -114,9 +114,7 @@ describe('Graph', () => { assert(graph.nodes.has(nodeD)); assert(!graph.nodes.has(nodeB)); assert(!graph.nodes.has(nodeC)); - assert.deepEqual(graph.getAllEdges(), [ - {from: nodeA, to: nodeD, type: null}, - ]); + assert.deepEqual(graph.getAllEdges(), [{from: nodeA, to: nodeD, type: 1}]); }); it('removing a node recursively deletes orphaned nodes', () => { @@ -157,8 +155,8 @@ describe('Graph', () => { assert.deepEqual([...graph.nodes.keys()], [nodeA, nodeC, nodeF]); assert.deepEqual(graph.getAllEdges(), [ - {from: nodeA, to: nodeC, type: null}, - {from: nodeC, to: nodeF, type: null}, + {from: nodeA, to: nodeC, type: 1}, + {from: nodeC, to: nodeF, type: 1}, ]); }); @@ -202,8 +200,8 @@ describe('Graph', () => { assert.deepEqual([...graph.nodes.keys()], [nodeA, nodeC, nodeF]); assert.deepEqual(graph.getAllEdges(), [ - {from: nodeA, to: nodeC, type: null}, - {from: nodeC, to: nodeF, type: null}, + {from: nodeA, to: nodeC, type: 1}, + {from: nodeC, to: nodeF, type: 1}, ]); }); @@ -237,11 +235,11 @@ describe('Graph', () => { assert.deepEqual(nodesBefore, getNodeIds()); assert.deepEqual(graph.getAllEdges(), [ - {from: nodeA, to: nodeB, type: null}, - {from: nodeB, to: nodeC, type: null}, - {from: nodeB, to: nodeD, type: null}, - {from: nodeD, to: nodeE, type: null}, - {from: nodeE, to: nodeB, type: null}, + {from: nodeA, to: nodeB, type: 1}, + {from: nodeB, to: nodeC, type: 1}, + {from: nodeB, to: nodeD, type: 1}, + {from: nodeD, to: nodeE, type: 1}, + {from: nodeE, to: nodeB, type: 1}, ]); }); @@ -280,8 +278,8 @@ describe('Graph', () => { assert(!graph.hasNode(nodeC)); assert(graph.hasNode(nodeD)); assert.deepEqual(graph.getAllEdges(), [ - {from: nodeA, to: nodeB, type: null}, - {from: nodeA, to: nodeD, type: null}, + {from: nodeA, to: nodeB, type: 1}, + {from: nodeA, to: nodeD, type: 1}, ]); }); @@ -292,10 +290,10 @@ describe('Graph', () => { let nodeC = graph.addNode('c'); let nodeD = graph.addNode('d'); - graph.addEdge(nodeA, nodeB, 'edgetype'); + graph.addEdge(nodeA, nodeB, 2); graph.addEdge(nodeA, nodeD); graph.addEdge(nodeB, nodeC); - graph.addEdge(nodeB, nodeD, 'edgetype'); + graph.addEdge(nodeB, nodeD, 2); graph.setRootNodeId(nodeA); @@ -305,7 +303,7 @@ describe('Graph', () => { visited.push(nodeId); }, null, // use root as startNode - 'edgetype', + 2, ); assert.deepEqual(visited, [nodeA, nodeB, nodeD]);