text: "use strict";
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.default = exports.bundleGraphEdgeTypes = void 0;
  
  function _assert() {
    const data = _interopRequireDefault(require("assert"));
  
    _assert = function () {
      return data;
    };
  
    return data;
  }
  
  function _nullthrows() {
    const data = _interopRequireDefault(require("nullthrows"));
  
    _nullthrows = function () {
      return data;
    };
  
    return data;
  }
  
  function _graph() {
    const data = require("@parcel/graph");
  
    _graph = function () {
      return data;
    };
  
    return data;
  }
  
  function _hash() {
    const data = require("@parcel/hash");
  
    _hash = function () {
      return data;
    };
  
    return data;
  }
  
  function _utils() {
    const data = require("@parcel/utils");
  
    _utils = function () {
      return data;
    };
  
    return data;
  }
  
  var _types = require("./types");
  
  var _utils2 = require("./utils");
  
  var _Environment = require("./public/Environment");
  
  var _projectPath = require("./projectPath");
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  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: 1,
    // Used for constant-time checks of presence of a dependency or asset in a bundle,
    // avoiding bundle traversal in cases like `isAssetInAncestors`
    contains: 2,
    // Connections between bundles and bundle groups, for quick traversal of the
    // bundle hierarchy.
    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
    //                           with the dependency.
    // When bundle -> bundle:    Indicates the target bundle is necessary for the
    //                           source bundle.
    // 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: 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: 5
  };
  exports.bundleGraphEdgeTypes = bundleGraphEdgeTypes;
  
  function makeReadOnlySet(set) {
    return new Proxy(set, {
      get(target, property) {
        if (property === 'delete' || property === 'add' || property === 'clear') {
          return undefined;
        } else {
          // $FlowFixMe[incompatible-type]
          let value = target[property];
          return typeof value === 'function' ? value.bind(target) : value;
        }
      }
  
    });
  }
  
  class BundleGraph {
    // TODO: These hashes are being invalidated in mutative methods, but this._graph is not a private
    // property so it is possible to reach in and mutate the graph without invalidating these hashes.
    // It needs to be exposed in BundlerRunner for now based on how applying runtimes works and the
    // BundlerRunner takes care of invalidating hashes when runtimes are applied, but this is not ideal.
    _targetEntryRoots = new Map();
  
    constructor({
      graph,
      publicIdByAssetId,
      assetPublicIds,
      bundleContentHashes,
      symbolPropagationRan
    }) {
      this._graph = graph;
      this._assetPublicIds = assetPublicIds;
      this._publicIdByAssetId = publicIdByAssetId;
      this._bundleContentHashes = bundleContentHashes;
      this._symbolPropagationRan = symbolPropagationRan;
    }
  
    static fromAssetGraph(assetGraph, publicIdByAssetId = new Map(), assetPublicIds = new Set()) {
      let graph = new (_graph().ContentGraph)();
      let assetGroupIds = new Set();
      let assetGraphNodeIdToBundleGraphNodeId = new Map();
      let assetGraphRootNode = assetGraph.rootNodeId != null ? assetGraph.getNode(assetGraph.rootNodeId) : null;
      (0, _assert().default)(assetGraphRootNode != null && assetGraphRootNode.type === 'root');
  
      for (let [nodeId, node] of assetGraph.nodes) {
        if (node.type === 'asset') {
          let {
            id: assetId
          } = node.value; // Generate a new, short public id for this asset to use.
          // If one already exists, use it.
  
          let publicId = publicIdByAssetId.get(assetId);
  
          if (publicId == null) {
            publicId = (0, _utils2.getPublicId)(assetId, existing => assetPublicIds.has(existing));
            publicIdByAssetId.set(assetId, publicId);
            assetPublicIds.add(publicId);
          }
        } // Don't copy over asset groups into the bundle graph.
  
  
        if (node.type === 'asset_group') {
          assetGroupIds.add(nodeId);
        } else {
          let bundleGraphNodeId = graph.addNodeByContentKey(node.id, node);
  
          if (node.id === (assetGraphRootNode === null || assetGraphRootNode === void 0 ? void 0 : assetGraphRootNode.id)) {
            graph.setRootNodeId(bundleGraphNodeId);
          }
  
          assetGraphNodeIdToBundleGraphNodeId.set(nodeId, bundleGraphNodeId);
        }
      }
  
      for (let edge of assetGraph.getAllEdges()) {
        let fromIds;
  
        if (assetGroupIds.has(edge.from)) {
          fromIds = [...assetGraph.getNodeIdsConnectedTo(edge.from, bundleGraphEdgeTypes.null)];
        } else {
          fromIds = [edge.from];
        }
  
        for (let from of fromIds) {
          if (assetGroupIds.has(edge.to)) {
            for (let to of assetGraph.getNodeIdsConnectedFrom(edge.to, bundleGraphEdgeTypes.null)) {
              graph.addEdge((0, _nullthrows().default)(assetGraphNodeIdToBundleGraphNodeId.get(from)), (0, _nullthrows().default)(assetGraphNodeIdToBundleGraphNodeId.get(to)));
            }
          } else {
            graph.addEdge((0, _nullthrows().default)(assetGraphNodeIdToBundleGraphNodeId.get(from)), (0, _nullthrows().default)(assetGraphNodeIdToBundleGraphNodeId.get(edge.to)));
          }
        }
      }
  
      return new BundleGraph({
        graph,
        assetPublicIds,
        bundleContentHashes: new Map(),
        publicIdByAssetId,
        symbolPropagationRan: assetGraph.symbolPropagationRan
      });
    }
  
    serialize() {
      return {
        $$raw: true,
        graph: this._graph.serialize(),
        assetPublicIds: this._assetPublicIds,
        bundleContentHashes: this._bundleContentHashes,
        publicIdByAssetId: this._publicIdByAssetId,
        symbolPropagationRan: this._symbolPropagationRan
      };
    }
  
    static deserialize(serialized) {
      return new BundleGraph({
        graph: _graph().ContentGraph.deserialize(serialized.graph),
        assetPublicIds: serialized.assetPublicIds,
        bundleContentHashes: serialized.bundleContentHashes,
        publicIdByAssetId: serialized.publicIdByAssetId,
        symbolPropagationRan: serialized.symbolPropagationRan
      });
    }
  
    addAssetToBundle(asset, bundle) {
      let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id);
  
      this._graph.addEdge(bundleNodeId, this._graph.getNodeIdByContentKey(asset.id), bundleGraphEdgeTypes.contains);
  
      this._graph.addEdge(bundleNodeId, this._graph.getNodeIdByContentKey(asset.id));
  
      let dependencies = this.getDependencies(asset);
  
      for (let dependency of dependencies) {
        let dependencyNodeId = this._graph.getNodeIdByContentKey(dependency.id);
  
        this._graph.addEdge(bundleNodeId, dependencyNodeId, bundleGraphEdgeTypes.contains);
  
        for (let [bundleGroupNodeId, bundleGroupNode] of this._graph.getNodeIdsConnectedFrom(dependencyNodeId).map(id => [id, (0, _nullthrows().default)(this._graph.getNode(id))]).filter(([, node]) => node.type === 'bundle_group')) {
          (0, _assert().default)(bundleGroupNode.type === 'bundle_group');
  
          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.
        // TODO: Consider bundle being created from dependency
  
  
        if (this._graph.getNodeIdsConnectedFrom(dependencyNodeId, bundleGraphEdgeTypes.references).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).some(node => node.type === 'bundle')) {
          this._graph.addEdge(bundleNodeId, dependencyNodeId, bundleGraphEdgeTypes.references);
        }
      }
    }
  
    addAssetGraphToBundle(asset, bundle, shouldSkipDependency = d => this.isDependencySkipped(d)) {
      let assetNodeId = this._graph.getNodeIdByContentKey(asset.id);
  
      let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id); // The root asset should be reached directly from the bundle in traversal.
      // Its children will be traversed from there.
  
  
      this._graph.addEdge(bundleNodeId, assetNodeId);
  
      this._graph.traverse((nodeId, _, actions) => {
        let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
  
        if (node.type === 'bundle_group') {
          actions.skipChildren();
          return;
        }
  
        if (node.type === 'dependency' && shouldSkipDependency(node.value)) {
          actions.skipChildren();
          return;
        }
  
        if (node.type === 'asset' || node.type === 'dependency') {
          this._graph.addEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.contains);
        }
  
        if (node.type === 'dependency') {
          for (let [bundleGroupNodeId, bundleGroupNode] of this._graph.getNodeIdsConnectedFrom(nodeId).map(id => [id, (0, _nullthrows().default)(this._graph.getNode(id))]).filter(([, node]) => node.type === 'bundle_group')) {
            (0, _assert().default)(bundleGroupNode.type === 'bundle_group');
  
            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, bundleGraphEdgeTypes.references).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).some(node => node.type === 'bundle')) {
            this._graph.addEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.references);
  
            this.markDependencyReferenceable(node.value); //all bundles that have this dependency need to have an edge from bundle to that dependency
          }
        }
      }, assetNodeId);
  
      this._bundleContentHashes.delete(bundle.id);
    }
  
    markDependencyReferenceable(dependency) {
      for (let bundle of this.getBundlesWithDependency(dependency)) {
        this._graph.addEdge(this._graph.getNodeIdByContentKey(bundle.id), this._graph.getNodeIdByContentKey(dependency.id), bundleGraphEdgeTypes.references);
      }
    }
  
    addEntryToBundle(asset, bundle, shouldSkipDependency) {
      this.addAssetGraphToBundle(asset, bundle, shouldSkipDependency);
  
      if (!bundle.entryAssetIds.includes(asset.id)) {
        bundle.entryAssetIds.push(asset.id);
      }
    }
  
    internalizeAsyncDependency(bundle, dependency) {
      if (dependency.priority === _types.Priority.sync) {
        throw new Error('Expected an async dependency');
      } // It's possible for internalized async dependencies to not have
      // reference edges and still have untyped edges.
      // TODO: Maybe don't use internalized async edges at all?
  
  
      let dependencyNodeId = this._graph.getNodeIdByContentKey(dependency.id);
  
      let resolved = this.getResolvedAsset(dependency);
  
      if (resolved) {
        let resolvedNodeId = this._graph.getNodeIdByContentKey(resolved.id);
  
        if (!this._graph.hasEdge(dependencyNodeId, resolvedNodeId, bundleGraphEdgeTypes.references)) {
          this._graph.addEdge(dependencyNodeId, resolvedNodeId, bundleGraphEdgeTypes.references);
  
          this._graph.removeEdge(dependencyNodeId, resolvedNodeId);
        }
      }
  
      this._graph.addEdge(this._graph.getNodeIdByContentKey(bundle.id), this._graph.getNodeIdByContentKey(dependency.id), bundleGraphEdgeTypes.internal_async);
  
      this.removeExternalDependency(bundle, dependency);
    }
  
    isDependencySkipped(dependency) {
      let node = this._graph.getNodeByContentKey(dependency.id);
  
      (0, _assert().default)(node && node.type === 'dependency');
      return !!node.hasDeferred || node.excluded;
    }
  
    getParentBundlesOfBundleGroup(bundleGroup) {
      return this._graph.getNodeIdsConnectedTo(this._graph.getNodeIdByContentKey((0, _utils2.getBundleGroupId)(bundleGroup)), bundleGraphEdgeTypes.bundle).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'bundle').map(node => {
        (0, _assert().default)(node.type === 'bundle');
        return node.value;
      });
    }
  
    resolveAsyncDependency(dependency, bundle) {
      let depNodeId = this._graph.getNodeIdByContentKey(dependency.id);
  
      let bundleNodeId = bundle != null ? this._graph.getNodeIdByContentKey(bundle.id) : null;
  
      if (bundleNodeId != null && this._graph.hasEdge(bundleNodeId, depNodeId, bundleGraphEdgeTypes.internal_async)) {
        let referencedAssetNodeIds = this._graph.getNodeIdsConnectedFrom(depNodeId, bundleGraphEdgeTypes.references);
  
        let resolved;
  
        if (referencedAssetNodeIds.length === 0) {
          resolved = this.getResolvedAsset(dependency, bundle);
        } else if (referencedAssetNodeIds.length === 1) {
          let referencedAssetNode = this._graph.getNode(referencedAssetNodeIds[0]); // If a referenced asset already exists, resolve this dependency to it.
  
  
          (0, _assert().default)((referencedAssetNode === null || referencedAssetNode === void 0 ? void 0 : referencedAssetNode.type) === 'asset');
          resolved = referencedAssetNode.value;
        } else {
          throw new Error('Dependencies can only reference one asset');
        }
  
        if (resolved == null) {
          return;
        } else {
          return {
            type: 'asset',
            value: resolved
          };
        }
      }
  
      let node = this._graph.getNodeIdsConnectedFrom(this._graph.getNodeIdByContentKey(dependency.id)).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).find(node => node.type === 'bundle_group');
  
      if (node == null) {
        return;
      }
  
      (0, _assert().default)(node.type === 'bundle_group');
      return {
        type: 'bundle_group',
        value: node.value
      };
    } // eslint-disable-next-line no-unused-vars
  
  
    getReferencedBundle(dependency) {
      let dependencyNodeId = this._graph.getNodeIdByContentKey(dependency.id); // If this dependency is async, there will be a bundle group attached to it.
  
  
      let node = this._graph.getNodeIdsConnectedFrom(dependencyNodeId).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).find(node => node.type === 'bundle_group');
  
      if (node != null) {
        (0, _assert().default)(node.type === 'bundle_group');
        return this.getBundlesInBundleGroup(node.value, {
          includeInline: true
        }).find(b => {
          let mainEntryId = b.entryAssetIds[b.entryAssetIds.length - 1];
          return mainEntryId != null && node.value.entryAssetId === mainEntryId;
        });
      } // Otherwise, find an attached bundle via a reference edge (e.g. from createAssetReference).
  
  
      let bundleNode = this._graph.getNodeIdsConnectedFrom(dependencyNodeId, bundleGraphEdgeTypes.references).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).find(node => node.type === 'bundle');
  
      if (bundleNode) {
        (0, _assert().default)(bundleNode.type === 'bundle');
        return bundleNode.value;
      }
    }
  
    removeAssetGraphFromBundle(asset, bundle) {
      let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id);
  
      let assetNodeId = this._graph.getNodeIdByContentKey(asset.id); // Remove all contains edges from the bundle to the nodes in the asset's
      // subgraph.
  
  
      this._graph.traverse((nodeId, context, actions) => {
        let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
  
        if (node.type === 'bundle_group') {
          actions.skipChildren();
          return;
        }
  
        if (node.type !== 'dependency' && node.type !== 'asset') {
          return;
        }
  
        if (this._graph.hasEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.contains)) {
          this._graph.removeEdge(bundleNodeId, nodeId, 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
          // aggregate.
          false
          /* removeOrphans */
          );
        } else {
          actions.skipChildren();
        }
  
        if (node.type === 'asset' && this._graph.hasEdge(bundleNodeId, nodeId)) {
          // Remove the untyped edge from the bundle to the node (it's an entry)
          this._graph.removeEdge(bundleNodeId, nodeId);
  
          let entryIndex = bundle.entryAssetIds.indexOf(node.value.id);
  
          if (entryIndex >= 0) {
            // Shared bundles have untyped edges to their asset graphs but don't
            // have entry assets. For those that have entry asset ids, remove them.
            bundle.entryAssetIds.splice(entryIndex, 1);
          }
        }
  
        if (node.type === 'dependency') {
          this.removeExternalDependency(bundle, node.value);
  
          if (this._graph.hasEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.references)) {
            this._graph.addEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.references);
  
            this.markDependencyReferenceable(node.value);
          }
  
          if (this._graph.hasEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.internal_async)) {
            this._graph.removeEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.internal_async);
          }
        }
      }, assetNodeId); // Remove bundle node if it no longer has any entry assets
  
  
      if (this._graph.getNodeIdsConnectedFrom(bundleNodeId).length === 0) {
        this.removeBundle(bundle);
      }
  
      this._bundleContentHashes.delete(bundle.id);
    }
  
    removeBundle(bundle) {
      // Remove bundle node if it no longer has any entry assets
      let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id);
  
      let bundleGroupNodeIds = this._graph.getNodeIdsConnectedTo(bundleNodeId, bundleGraphEdgeTypes.bundle);
  
      this._graph.removeNode(bundleNodeId);
  
      let removedBundleGroups = new Set(); // Remove bundle group node if it no longer has any bundles
  
      for (let bundleGroupNodeId of bundleGroupNodeIds) {
        let bundleGroupNode = (0, _nullthrows().default)(this._graph.getNode(bundleGroupNodeId));
        (0, _assert().default)(bundleGroupNode.type === 'bundle_group');
        let bundleGroup = bundleGroupNode.value;
  
        if ( // If the bundle group's entry asset belongs to this bundle, the group
        // was created because of this bundle. Remove the group.
        bundle.entryAssetIds.includes(bundleGroup.entryAssetId) || // If the bundle group is now empty, remove it.
        this.getBundlesInBundleGroup(bundleGroup, {
          includeInline: true
        }).length === 0) {
          removedBundleGroups.add(bundleGroup);
          this.removeBundleGroup(bundleGroup);
        }
      }
  
      this._bundleContentHashes.delete(bundle.id);
  
      return removedBundleGroups;
    }
  
    removeBundleGroup(bundleGroup) {
      let bundleGroupNode = (0, _nullthrows().default)(this._graph.getNodeByContentKey((0, _utils2.getBundleGroupId)(bundleGroup)));
      (0, _assert().default)(bundleGroupNode.type === 'bundle_group');
      let bundlesInGroup = this.getBundlesInBundleGroup(bundleGroupNode.value, {
        includeInline: true
      });
  
      for (let bundle of bundlesInGroup) {
        if (this.getBundleGroupsContainingBundle(bundle).length === 1) {
          let removedBundleGroups = this.removeBundle(bundle);
  
          if (removedBundleGroups.has(bundleGroup)) {
            // This function can be reentered through removeBundle above. In the case this
            // bundle group has already been removed, stop.
            return;
          }
        }
      } // This function can be reentered through removeBundle above. In this case,
      // the node may already been removed.
  
  
      if (this._graph.hasContentKey(bundleGroupNode.id)) {
        this._graph.removeNode(this._graph.getNodeIdByContentKey(bundleGroupNode.id));
      }
  
      (0, _assert().default)(bundlesInGroup.every(bundle => this.getBundleGroupsContainingBundle(bundle).length > 0));
    }
  
    removeExternalDependency(bundle, dependency) {
      let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id);
  
      for (let bundleGroupNode of this._graph.getNodeIdsConnectedFrom(this._graph.getNodeIdByContentKey(dependency.id)).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'bundle_group')) {
        let bundleGroupNodeId = this._graph.getNodeIdByContentKey(bundleGroupNode.id);
  
        if (!this._graph.hasEdge(bundleNodeId, bundleGroupNodeId, bundleGraphEdgeTypes.bundle)) {
          continue;
        }
  
        let inboundDependencies = this._graph.getNodeIdsConnectedTo(bundleGroupNodeId).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'dependency').map(node => {
          (0, _assert().default)(node.type === 'dependency');
          return node.value;
        }); // If every inbound dependency to this bundle group does not belong to this bundle,
        // or the dependency is internal to the bundle, then the connection between
        // this bundle and the group is safe to remove.
  
  
        if (inboundDependencies.every(dependency => !this.bundleHasDependency(bundle, dependency) || this._graph.hasEdge(bundleNodeId, this._graph.getNodeIdByContentKey(dependency.id), bundleGraphEdgeTypes.internal_async))) {
          this._graph.removeEdge(bundleNodeId, bundleGroupNodeId, bundleGraphEdgeTypes.bundle);
        }
      }
    }
  
    createAssetReference(dependency, asset, bundle) {
      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, bundleGraphEdgeTypes.references);
  
      this._graph.addEdge(dependencyId, bundleId, bundleGraphEdgeTypes.references);
  
      this.markDependencyReferenceable(dependency);
  
      if (this._graph.hasEdge(dependencyId, assetId)) {
        this._graph.removeEdge(dependencyId, assetId);
      }
    }
  
    createBundleReference(from, to) {
      this._graph.addEdge(this._graph.getNodeIdByContentKey(from.id), this._graph.getNodeIdByContentKey(to.id), bundleGraphEdgeTypes.references);
    }
  
    getBundlesWithAsset(asset) {
      return this._graph.getNodeIdsConnectedTo(this._graph.getNodeIdByContentKey(asset.id), bundleGraphEdgeTypes.contains).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'bundle').map(node => {
        (0, _assert().default)(node.type === 'bundle');
        return node.value;
      });
    }
  
    getBundlesWithDependency(dependency) {
      return this._graph.getNodeIdsConnectedTo((0, _nullthrows().default)(this._graph.getNodeIdByContentKey(dependency.id)), bundleGraphEdgeTypes.contains).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'bundle').map(node => {
        (0, _assert().default)(node.type === 'bundle');
        return node.value;
      });
    }
  
    getDependencyAssets(dependency) {
      return this._graph.getNodeIdsConnectedFrom(this._graph.getNodeIdByContentKey(dependency.id)).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'asset').map(node => {
        (0, _assert().default)(node.type === 'asset');
        return node.value;
      });
    }
  
    getResolvedAsset(dep, bundle) {
      let assets = this.getDependencyAssets(dep);
      let firstAsset = assets[0];
      let resolved = // If no bundle is specified, use the first concrete asset.
      bundle == null ? firstAsset : // Otherwise, find the first asset that belongs to this bundle.
      assets.find(asset => this.bundleHasAsset(bundle, asset)) || firstAsset; // If a resolution still hasn't been found, return the first referenced asset.
  
      if (resolved == null) {
        this._graph.traverse((nodeId, _, traversal) => {
          let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
  
          if (node.type === 'asset') {
            resolved = node.value;
            traversal.stop();
          } else if (node.id !== dep.id) {
            traversal.skipChildren();
          }
        }, this._graph.getNodeIdByContentKey(dep.id), bundleGraphEdgeTypes.references);
      }
  
      return resolved;
    }
  
    getDependencies(asset) {
      let nodeId = this._graph.getNodeIdByContentKey(asset.id);
  
      return this._graph.getNodeIdsConnectedFrom(nodeId).map(id => {
        let node = (0, _nullthrows().default)(this._graph.getNode(id));
        (0, _assert().default)(node.type === 'dependency');
        return node.value;
      });
    }
  
    traverseAssets(bundle, visit) {
      return this.traverseBundle(bundle, (0, _graph().mapVisitor)(node => node.type === 'asset' ? node.value : null, visit));
    }
  
    isAssetReferenced(bundle, asset) {
      let assetNodeId = (0, _nullthrows().default)(this._graph.getNodeIdByContentKey(asset.id));
  
      if (this._graph.getNodeIdsConnectedTo(assetNodeId, bundleGraphEdgeTypes.references).map(id => this._graph.getNode(id)).some(node => (node === null || node === void 0 ? void 0 : node.type) === 'dependency' && node.value.priority === _types.Priority.lazy && node.value.specifierType !== _types.SpecifierType.url)) {
        // If this asset is referenced by any async dependency, it's referenced.
        return true;
      }
  
      let dependencies = this._graph.getNodeIdsConnectedTo(assetNodeId).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'dependency').map(node => {
        (0, _assert().default)(node.type === 'dependency');
        return node.value;
      });
  
      const bundleHasReference = bundle => {
        return !this.bundleHasAsset(bundle, asset) && dependencies.some(dependency => this.bundleHasDependency(bundle, dependency));
      };
  
      let visitedBundles = new Set();
      let siblingBundles = new Set(this.getBundleGroupsContainingBundle(bundle).flatMap(bundleGroup => this.getBundlesInBundleGroup(bundleGroup, {
        includeInline: true
      }))); // Check if any of this bundle's descendants, referencers, bundles referenced
      // by referencers, or descendants of its referencers use the asset without
      // an explicit reference edge. This can happen if e.g. the asset has been
      // deduplicated.
  
      return [...siblingBundles].some(referencer => {
        let isReferenced = false;
        this.traverseBundles((descendant, _, actions) => {
          if (descendant.id === bundle.id) {
            return;
          }
  
          if (visitedBundles.has(descendant)) {
            actions.skipChildren();
            return;
          }
  
          visitedBundles.add(descendant);
  
          if (descendant.type !== bundle.type || descendant.env.context !== bundle.env.context) {
            actions.skipChildren();
            return;
          }
  
          if (bundleHasReference(descendant)) {
            isReferenced = true;
            actions.stop();
          }
        }, referencer);
        return isReferenced;
      });
    }
  
    hasParentBundleOfType(bundle, type) {
      let parents = this.getParentBundles(bundle);
      return parents.length > 0 && parents.every(parent => parent.type === type);
    }
  
    getParentBundles(bundle) {
      let parentBundles = new Set();
  
      for (let bundleGroup of this.getBundleGroupsContainingBundle(bundle)) {
        for (let parentBundle of this.getParentBundlesOfBundleGroup(bundleGroup)) {
          parentBundles.add(parentBundle);
        }
      }
  
      return [...parentBundles];
    }
  
    isAssetReachableFromBundle(asset, bundle) {
      // If a bundle's environment is isolated, it can't access assets present
      // in any ancestor bundles. Don't consider any assets reachable.
      if (_Environment.ISOLATED_ENVS.has(bundle.env.context) || !bundle.isSplittable || bundle.bundleBehavior === _types.BundleBehavior.isolated || bundle.bundleBehavior === _types.BundleBehavior.inline) {
        return false;
      } // For an asset to be reachable from a bundle, it must either exist in a sibling bundle,
      // or in an ancestor bundle group reachable from all parent bundles.
  
  
      let bundleGroups = this.getBundleGroupsContainingBundle(bundle);
      return bundleGroups.every(bundleGroup => {
        // If the asset is in any sibling bundles of the original bundle, it is reachable.
        let bundles = this.getBundlesInBundleGroup(bundleGroup);
  
        if (bundles.some(b => b.id !== bundle.id && b.bundleBehavior !== _types.BundleBehavior.isolated && b.bundleBehavior !== _types.BundleBehavior.inline && this.bundleHasAsset(b, asset))) {
          return true;
        } // Get a list of parent bundle nodes pointing to the bundle group
  
  
        let parentBundleNodes = this._graph.getNodeIdsConnectedTo(this._graph.getNodeIdByContentKey((0, _utils2.getBundleGroupId)(bundleGroup)), bundleGraphEdgeTypes.bundle); // Check that every parent bundle has a bundle group in its ancestry that contains the asset.
  
  
        return parentBundleNodes.every(bundleNodeId => {
          let bundleNode = (0, _nullthrows().default)(this._graph.getNode(bundleNodeId));
  
          if (bundleNode.type !== 'bundle' || bundleNode.value.bundleBehavior === _types.BundleBehavior.isolated || bundleNode.value.bundleBehavior === _types.BundleBehavior.inline) {
            return false;
          }
  
          let isReachable = true;
  
          this._graph.traverseAncestors(bundleNodeId, (nodeId, ctx, actions) => {
            let node = (0, _nullthrows().default)(this._graph.getNode(nodeId)); // If we've reached the root or a context change without
            // finding this asset in the ancestry, it is not reachable.
  
            if (node.type === 'root' || node.type === 'bundle' && (node.value.id === bundle.id || node.value.env.context !== bundle.env.context)) {
              isReachable = false;
              actions.stop();
              return;
            }
  
            if (node.type === 'bundle_group') {
              let childBundles = this.getBundlesInBundleGroup(node.value);
  
              if (childBundles.some(b => b.id !== bundle.id && b.bundleBehavior !== _types.BundleBehavior.isolated && b.bundleBehavior !== _types.BundleBehavior.inline && this.bundleHasAsset(b, asset))) {
                actions.skipChildren();
              }
            }
          }, [bundleGraphEdgeTypes.references, bundleGraphEdgeTypes.bundle]);
  
          return isReachable;
        });
      });
    }
  
    traverseBundle(bundle, visit) {
      let entries = true;
  
      let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id); // A modified DFS traversal which traverses entry assets in the same order
      // as their ids appear in `bundle.entryAssetIds`.
  
  
      return this._graph.dfs({
        visit: (0, _graph().mapVisitor)((nodeId, actions) => {
          let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
  
          if (nodeId === bundleNodeId) {
            return;
          }
  
          if (node.type === 'dependency' || node.type === 'asset') {
            if (this._graph.hasEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.contains)) {
              return node;
            }
          }
  
          actions.skipChildren();
        }, visit),
        startNodeId: bundleNodeId,
        getChildren: nodeId => {
          let children = this._graph.getNodeIdsConnectedFrom(nodeId).map(id => [id, (0, _nullthrows().default)(this._graph.getNode(id))]);
  
          let sorted = entries && bundle.entryAssetIds.length > 0 ? children.sort(([, a], [, b]) => {
            let aIndex = bundle.entryAssetIds.indexOf(a.id);
            let bIndex = bundle.entryAssetIds.indexOf(b.id);
  
            if (aIndex === bIndex) {
              // If both don't exist in the entry asset list, or
              // otherwise have the same index.
              return 0;
            } else if (aIndex === -1) {
              return 1;
            } else if (bIndex === -1) {
              return -1;
            }
  
            return aIndex - bIndex;
          }) : children;
          entries = false;
          return sorted.map(([id]) => id);
        }
      });
    }
  
    traverse(visit, start) {
      return this._graph.filteredTraverse(nodeId => {
        let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
  
        if (node.type === 'asset' || node.type === 'dependency') {
          return node;
        }
      }, visit, start ? this._graph.getNodeIdByContentKey(start.id) : undefined, // start with root
      _graph().ALL_EDGE_TYPES);
    }
  
    getChildBundles(bundle) {
      let siblings = new Set(this.getReferencedBundles(bundle));
      let bundles = [];
      this.traverseBundles((b, _, actions) => {
        if (bundle.id === b.id) {
          return;
        }
  
        if (!siblings.has(b)) {
          bundles.push(b);
        }
  
        actions.skipChildren();
      }, bundle);
      return bundles;
    }
  
    traverseBundles(visit, startBundle) {
      return this._graph.filteredTraverse(nodeId => {
        let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
        return node.type === 'bundle' ? node.value : null;
      }, visit, startBundle ? this._graph.getNodeIdByContentKey(startBundle.id) : null, [bundleGraphEdgeTypes.bundle, bundleGraphEdgeTypes.references]);
    }
  
    getBundles(opts) {
      let bundles = [];
      this.traverseBundles(bundle => {
        if (opts !== null && opts !== void 0 && opts.includeInline || bundle.bundleBehavior !== _types.BundleBehavior.inline) {
          bundles.push(bundle);
        }
      });
      return bundles;
    }
  
    getTotalSize(asset) {
      let size = 0;
  
      this._graph.traverse((nodeId, _, actions) => {
        let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
  
        if (node.type === 'bundle_group') {
          actions.skipChildren();
          return;
        }
  
        if (node.type === 'asset') {
          size += node.value.stats.size;
        }
      }, this._graph.getNodeIdByContentKey(asset.id));
  
      return size;
    }
  
    getReferencingBundles(bundle) {
      let referencingBundles = new Set();
  
      this._graph.traverseAncestors(this._graph.getNodeIdByContentKey(bundle.id), nodeId => {
        let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
  
        if (node.type === 'bundle' && node.value.id !== bundle.id) {
          referencingBundles.add(node.value);
        }
      }, bundleGraphEdgeTypes.references);
  
      return [...referencingBundles];
    }
  
    getBundleGroupsContainingBundle(bundle) {
      let bundleGroups = new Set();
  
      for (let currentBundle of [bundle, ...this.getReferencingBundles(bundle)]) {
        for (let bundleGroup of this.getDirectParentBundleGroups(currentBundle)) {
          bundleGroups.add(bundleGroup);
        }
      }
  
      return [...bundleGroups];
    }
  
    getDirectParentBundleGroups(bundle) {
      return this._graph.getNodeIdsConnectedTo((0, _nullthrows().default)(this._graph.getNodeIdByContentKey(bundle.id)), bundleGraphEdgeTypes.bundle).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'bundle_group').map(node => {
        (0, _assert().default)(node.type === 'bundle_group');
        return node.value;
      });
    }
  
    getBundlesInBundleGroup(bundleGroup, opts) {
      let bundles = new Set();
  
      for (let bundleNodeId of this._graph.getNodeIdsConnectedFrom(this._graph.getNodeIdByContentKey((0, _utils2.getBundleGroupId)(bundleGroup)), bundleGraphEdgeTypes.bundle)) {
        let bundleNode = (0, _nullthrows().default)(this._graph.getNode(bundleNodeId));
        (0, _assert().default)(bundleNode.type === 'bundle');
        let bundle = bundleNode.value;
  
        if (opts !== null && opts !== void 0 && opts.includeInline || bundle.bundleBehavior !== _types.BundleBehavior.inline) {
          bundles.add(bundle);
        }
  
        for (let referencedBundle of this.getReferencedBundles(bundle, {
          includeInline: true
        })) {
          bundles.add(referencedBundle);
        }
      }
  
      return [...bundles];
    }
  
    getReferencedBundles(bundle, opts) {
      var _opts$recursive, _opts$includeInline;
  
      let recursive = (_opts$recursive = opts === null || opts === void 0 ? void 0 : opts.recursive) !== null && _opts$recursive !== void 0 ? _opts$recursive : true;
      let includeInline = (_opts$includeInline = opts === null || opts === void 0 ? void 0 : opts.includeInline) !== null && _opts$includeInline !== void 0 ? _opts$includeInline : false;
      let referencedBundles = new Set();
  
      this._graph.dfs({
        visit: (nodeId, _, actions) => {
          let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
  
          if (node.type !== 'bundle') {
            return;
          }
  
          if (node.value.id === bundle.id) {
            return;
          }
  
          if (includeInline || node.value.bundleBehavior !== _types.BundleBehavior.inline) {
            referencedBundles.add(node.value);
          }
  
          if (!recursive) {
            actions.skipChildren();
          }
        },
        startNodeId: this._graph.getNodeIdByContentKey(bundle.id),
        getChildren: nodeId => // 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, bundleGraphEdgeTypes.references).reverse()
      });
  
      return [...referencedBundles];
    }
  
    getIncomingDependencies(asset) {
      if (!this._graph.hasContentKey(asset.id)) {
        return [];
      } // Dependencies can be a a parent node via an untyped edge (like in the AssetGraph but without AssetGroups)
      // or they can be parent nodes via a 'references' edge
  
  
      return this._graph.getNodeIdsConnectedTo(this._graph.getNodeIdByContentKey(asset.id), _graph().ALL_EDGE_TYPES).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(n => n.type === 'dependency').map(n => {
        (0, _assert().default)(n.type === 'dependency');
        return n.value;
      });
    }
  
    getAssetWithDependency(dep) {
      if (!this._graph.hasContentKey(dep.id)) {
        return null;
      }
  
      let res = this._graph.getNodeIdsConnectedTo(this._graph.getNodeIdByContentKey(dep.id));
  
      (0, _assert().default)(res.length <= 1, 'Expected a single asset to be connected to a dependency');
  
      let resNode = this._graph.getNode(res[0]);
  
      if ((resNode === null || resNode === void 0 ? void 0 : resNode.type) === 'asset') {
        return resNode.value;
      }
    }
  
    bundleHasAsset(bundle, asset) {
      let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id);
  
      let assetNodeId = this._graph.getNodeIdByContentKey(asset.id);
  
      return this._graph.hasEdge(bundleNodeId, assetNodeId, bundleGraphEdgeTypes.contains);
    }
  
    bundleHasDependency(bundle, dependency) {
      let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id);
  
      let dependencyNodeId = this._graph.getNodeIdByContentKey(dependency.id);
  
      return this._graph.hasEdge(bundleNodeId, dependencyNodeId, bundleGraphEdgeTypes.contains);
    }
  
    filteredTraverse(bundleNodeId, filter, visit) {
      return this._graph.filteredTraverse(filter, visit, bundleNodeId);
    }
  
    getSymbolResolution(asset, symbol, boundary) {
      var _asset$symbols, _asset$symbols$get;
  
      let assetOutside = boundary && !this.bundleHasAsset(boundary, asset);
      let identifier = (_asset$symbols = asset.symbols) === null || _asset$symbols === void 0 ? void 0 : (_asset$symbols$get = _asset$symbols.get(symbol)) === null || _asset$symbols$get === void 0 ? void 0 : _asset$symbols$get.local;
  
      if (symbol === '*') {
        var _asset$symbols2, _asset$symbols2$get;
  
        return {
          asset,
          exportSymbol: '*',
          symbol: identifier !== null && identifier !== void 0 ? identifier : null,
          loc: (_asset$symbols2 = asset.symbols) === null || _asset$symbols2 === void 0 ? void 0 : (_asset$symbols2$get = _asset$symbols2.get(symbol)) === null || _asset$symbols2$get === void 0 ? void 0 : _asset$symbols2$get.loc
        };
      }
  
      let found = false;
      let skipped = false;
      let deps = this.getDependencies(asset).reverse();
      let potentialResults = [];
  
      for (let dep of deps) {
        var _depSymbols$get;
  
        let depSymbols = dep.symbols;
  
        if (!depSymbols) {
          found = true;
          continue;
        } // If this is a re-export, find the original module.
  
  
        let symbolLookup = new Map([...depSymbols].map(([key, val]) => [val.local, key]));
        let depSymbol = symbolLookup.get(identifier);
  
        if (depSymbol != null) {
          let resolved = this.getResolvedAsset(dep);
  
          if (!resolved || resolved.id === asset.id) {
            var _asset$symbols3, _asset$symbols3$get;
  
            // External module or self-reference
            return {
              asset,
              exportSymbol: symbol,
              symbol: identifier,
              loc: (_asset$symbols3 = asset.symbols) === null || _asset$symbols3 === void 0 ? void 0 : (_asset$symbols3$get = _asset$symbols3.get(symbol)) === null || _asset$symbols3$get === void 0 ? void 0 : _asset$symbols3$get.loc
            };
          }
  
          if (assetOutside) {
            // We found the symbol, but `asset` is outside, return `asset` and the original symbol
            found = true;
            break;
          }
  
          if (this.isDependencySkipped(dep)) {
            // We found the symbol and `dep` was skipped
            skipped = true;
            break;
          }
  
          let {
            asset: resolvedAsset,
            symbol: resolvedSymbol,
            exportSymbol,
            loc
          } = this.getSymbolResolution(resolved, depSymbol, boundary);
  
          if (!loc) {
            var _asset$symbols4, _asset$symbols4$get;
  
            // Remember how we got there
            loc = (_asset$symbols4 = asset.symbols) === null || _asset$symbols4 === void 0 ? void 0 : (_asset$symbols4$get = _asset$symbols4.get(symbol)) === null || _asset$symbols4$get === void 0 ? void 0 : _asset$symbols4$get.loc;
          }
  
          return {
            asset: resolvedAsset,
            symbol: resolvedSymbol,
            exportSymbol,
            loc
          };
        } // If this module exports wildcards, resolve the original module.
        // Default exports are excluded from wildcard exports.
        // Wildcard reexports are never listed in the reexporting asset's symbols.
  
  
        if (identifier == null && ((_depSymbols$get = depSymbols.get('*')) === null || _depSymbols$get === void 0 ? void 0 : _depSymbols$get.local) === '*' && symbol !== 'default') {
          let resolved = this.getResolvedAsset(dep);
  
          if (!resolved) {
            continue;
          }
  
          let result = this.getSymbolResolution(resolved, symbol, boundary); // We found the symbol
  
          if (result.symbol != undefined) {
            var _resolved$symbols, _resolved$symbols$get;
  
            if (assetOutside) {
              // ..., but `asset` is outside, return `asset` and the original symbol
              found = true;
              break;
            }
  
            if (this.isDependencySkipped(dep)) {
              // We found the symbol and `dep` was skipped
              skipped = true;
              break;
            }
  
            return {
              asset: result.asset,
              symbol: result.symbol,
              exportSymbol: result.exportSymbol,
              loc: (_resolved$symbols = resolved.symbols) === null || _resolved$symbols === void 0 ? void 0 : (_resolved$symbols$get = _resolved$symbols.get(symbol)) === null || _resolved$symbols$get === void 0 ? void 0 : _resolved$symbols$get.loc
            };
          }
  
          if (result.symbol === null) {
            found = true;
  
            if (boundary && !this.bundleHasAsset(boundary, result.asset)) {
              // If the returned asset is outside (and it's the first asset that is outside), return it.
              if (!assetOutside) {
                var _resolved$symbols2, _resolved$symbols2$ge;
  
                return {
                  asset: result.asset,
                  symbol: result.symbol,
                  exportSymbol: result.exportSymbol,
                  loc: (_resolved$symbols2 = resolved.symbols) === null || _resolved$symbols2 === void 0 ? void 0 : (_resolved$symbols2$ge = _resolved$symbols2.get(symbol)) === null || _resolved$symbols2$ge === void 0 ? void 0 : _resolved$symbols2$ge.loc
                };
              } else {
                // Otherwise the original asset will be returned at the end.
                break;
              }
            } else {
              var _resolved$symbols3, _resolved$symbols3$ge;
  
              // We didn't find it in this dependency, but it might still be there: bailout.
              // Continue searching though, with the assumption that there are no conficting reexports
              // and there might be a another (re)export (where we might statically find the symbol).
              potentialResults.push({
                asset: result.asset,
                symbol: result.symbol,
                exportSymbol: result.exportSymbol,
                loc: (_resolved$symbols3 = resolved.symbols) === null || _resolved$symbols3 === void 0 ? void 0 : (_resolved$symbols3$ge = _resolved$symbols3.get(symbol)) === null || _resolved$symbols3$ge === void 0 ? void 0 : _resolved$symbols3$ge.loc
              });
            }
          }
        }
      } // We didn't find the exact symbol...
  
  
      if (potentialResults.length == 1) {
        // ..., but if it does exist, it has to be behind this one reexport.
        return potentialResults[0];
      } else {
        var _asset$symbols5, _asset$symbols6, _asset$symbols6$get;
  
        // ... and there is no single reexport, but `bailout` tells us if it might still be exported.
        return {
          asset,
          exportSymbol: symbol,
          symbol: skipped ? false : found ? null : identifier !== null && identifier !== void 0 ? identifier : (_asset$symbols5 = asset.symbols) !== null && _asset$symbols5 !== void 0 && _asset$symbols5.has('*') ? null : undefined,
          loc: (_asset$symbols6 = asset.symbols) === null || _asset$symbols6 === void 0 ? void 0 : (_asset$symbols6$get = _asset$symbols6.get(symbol)) === null || _asset$symbols6$get === void 0 ? void 0 : _asset$symbols6$get.loc
        };
      }
    }
  
    getAssetById(contentKey) {
      let node = this._graph.getNodeByContentKey(contentKey);
  
      if (node == null) {
        throw new Error('Node not found');
      } else if (node.type !== 'asset') {
        throw new Error('Node was not an asset');
      }
  
      return node.value;
    }
  
    getAssetPublicId(asset) {
      let publicId = this._publicIdByAssetId.get(asset.id);
  
      if (publicId == null) {
        throw new Error("Asset or it's public id not found");
      }
  
      return publicId;
    }
  
    getExportedSymbols(asset, boundary) {
      if (!asset.symbols) {
        return [];
      }
  
      let symbols = [];
  
      for (let symbol of asset.symbols.keys()) {
        symbols.push({ ...this.getSymbolResolution(asset, symbol, boundary),
          exportAs: symbol
        });
      }
  
      let deps = this.getDependencies(asset);
  
      for (let dep of deps) {
        var _depSymbols$get2;
  
        let depSymbols = dep.symbols;
        if (!depSymbols) continue;
  
        if (((_depSymbols$get2 = depSymbols.get('*')) === null || _depSymbols$get2 === void 0 ? void 0 : _depSymbols$get2.local) === '*') {
          let resolved = this.getResolvedAsset(dep);
          if (!resolved) continue;
          let exported = this.getExportedSymbols(resolved, boundary).filter(s => s.exportSymbol !== 'default').map(s => s.exportSymbol !== '*' ? { ...s,
            exportAs: s.exportSymbol
          } : s);
          symbols.push(...exported);
        }
      }
  
      return symbols;
    }
  
    getContentHash(bundle) {
      let existingHash = this._bundleContentHashes.get(bundle.id);
  
      if (existingHash != null) {
        return existingHash;
      }
  
      let hash = new (_hash().Hash)(); // TODO: sort??
  
      this.traverseAssets(bundle, asset => {
        {
          hash.writeString([this.getAssetPublicId(asset), asset.outputHash, asset.filePath, asset.query, asset.type, asset.uniqueKey].join(':'));
        }
      });
      let hashHex = hash.finish();
  
      this._bundleContentHashes.set(bundle.id, hashHex);
  
      return hashHex;
    }
  
    getInlineBundles(bundle) {
      let bundles = [];
      let seen = new Set();
  
      let addReferencedBundles = bundle => {
        if (seen.has(bundle.id)) {
          return;
        }
  
        seen.add(bundle.id);
        let referencedBundles = this.getReferencedBundles(bundle, {
          includeInline: true
        });
  
        for (let referenced of referencedBundles) {
          if (referenced.bundleBehavior === _types.BundleBehavior.inline) {
            bundles.push(referenced);
            addReferencedBundles(referenced);
          }
        }
      };
  
      addReferencedBundles(bundle);
      this.traverseBundles((childBundle, _, traversal) => {
        if (childBundle.bundleBehavior === _types.BundleBehavior.inline) {
          bundles.push(childBundle);
        } else if (childBundle.id !== bundle.id) {
          traversal.skipChildren();
        }
      }, bundle);
      return bundles;
    }
  
    getHash(bundle) {
      let hash = new (_hash().Hash)();
      hash.writeString(bundle.id + bundle.target.publicUrl + this.getContentHash(bundle));
      let inlineBundles = this.getInlineBundles(bundle);
  
      for (let inlineBundle of inlineBundles) {
        hash.writeString(this.getContentHash(inlineBundle));
      }
  
      for (let referencedBundle of this.getReferencedBundles(bundle)) {
        hash.writeString(referencedBundle.id);
      }
  
      hash.writeString(JSON.stringify((0, _utils().objectSortedEntriesDeep)(bundle.env)));
      return hash.finish();
    }
  
    getBundleGraphHash() {
      let hashes = '';
  
      for (let bundle of this.getBundles()) {
        hashes += this.getHash(bundle);
      }
  
      return (0, _hash().hashString)(hashes);
    }
  
    addBundleToBundleGroup(bundle, bundleGroup) {
      let bundleGroupNodeId = this._graph.getNodeIdByContentKey((0, _utils2.getBundleGroupId)(bundleGroup));
  
      let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id);
  
      if (this._graph.hasEdge(bundleGroupNodeId, bundleNodeId, bundleGraphEdgeTypes.bundle)) {
        // Bundle group already has bundle
        return;
      }
  
      this._graph.addEdge(bundleGroupNodeId, bundleNodeId);
  
      this._graph.addEdge(bundleGroupNodeId, bundleNodeId, bundleGraphEdgeTypes.bundle);
  
      for (let entryAssetId of bundle.entryAssetIds) {
        let entryAssetNodeId = this._graph.getNodeIdByContentKey(entryAssetId);
  
        if (this._graph.hasEdge(bundleGroupNodeId, entryAssetNodeId)) {
          this._graph.removeEdge(bundleGroupNodeId, entryAssetNodeId);
        }
      }
    }
  
    getUsedSymbolsAsset(asset) {
      let node = this._graph.getNodeByContentKey(asset.id);
  
      (0, _assert().default)(node && node.type === 'asset');
      return this._symbolPropagationRan ? makeReadOnlySet(node.usedSymbols) : null;
    }
  
    getUsedSymbolsDependency(dep) {
      let node = this._graph.getNodeByContentKey(dep.id);
  
      (0, _assert().default)(node && node.type === 'dependency');
      return this._symbolPropagationRan ? makeReadOnlySet(node.usedSymbolsUp) : null;
    }
  
    merge(other) {
      let otherGraphIdToThisNodeId = new Map();
  
      for (let [otherNodeId, otherNode] of other._graph.nodes) {
        if (this._graph.hasContentKey(otherNode.id)) {
          let existingNodeId = this._graph.getNodeIdByContentKey(otherNode.id);
  
          otherGraphIdToThisNodeId.set(otherNodeId, existingNodeId);
          let existingNode = (0, _nullthrows().default)(this._graph.getNode(existingNodeId)); // Merge symbols, recompute dep.exluded based on that
  
          if (existingNode.type === 'asset') {
            (0, _assert().default)(otherNode.type === 'asset');
            existingNode.usedSymbols = new Set([...existingNode.usedSymbols, ...otherNode.usedSymbols]);
          } else if (existingNode.type === 'dependency') {
            (0, _assert().default)(otherNode.type === 'dependency');
            existingNode.usedSymbolsDown = new Set([...existingNode.usedSymbolsDown, ...otherNode.usedSymbolsDown]);
            existingNode.usedSymbolsUp = new Set([...existingNode.usedSymbolsUp, ...otherNode.usedSymbolsUp]);
            existingNode.excluded = (existingNode.excluded || Boolean(existingNode.hasDeferred)) && (otherNode.excluded || Boolean(otherNode.hasDeferred));
          }
        } else {
          let updateNodeId = this._graph.addNodeByContentKey(otherNode.id, otherNode);
  
          otherGraphIdToThisNodeId.set(otherNodeId, updateNodeId);
        }
      }
  
      for (let edge of other._graph.getAllEdges()) {
        this._graph.addEdge((0, _nullthrows().default)(otherGraphIdToThisNodeId.get(edge.from)), (0, _nullthrows().default)(otherGraphIdToThisNodeId.get(edge.to)), edge.type);
      }
    }
  
    isEntryBundleGroup(bundleGroup) {
      return this._graph.getNodeIdsConnectedTo((0, _nullthrows().default)(this._graph.getNodeIdByContentKey((0, _utils2.getBundleGroupId)(bundleGroup))), bundleGraphEdgeTypes.bundle).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).some(n => n.type === 'root');
    }
  
    getEntryRoot(projectRoot, target) {
      let cached = this._targetEntryRoots.get(target.distDir);
  
      if (cached != null) {
        return cached;
      }
  
      let entryBundleGroupIds = this._graph.getNodeIdsConnectedFrom((0, _nullthrows().default)(this._graph.rootNodeId), bundleGraphEdgeTypes.bundle);
  
      let entries = [];
  
      for (let bundleGroupId of entryBundleGroupIds) {
        let bundleGroupNode = this._graph.getNode(bundleGroupId);
  
        (0, _assert().default)((bundleGroupNode === null || bundleGroupNode === void 0 ? void 0 : bundleGroupNode.type) === 'bundle_group');
  
        if (bundleGroupNode.value.target.distDir === target.distDir) {
          let entryAssetNode = this._graph.getNodeByContentKey(bundleGroupNode.value.entryAssetId);
  
          (0, _assert().default)((entryAssetNode === null || entryAssetNode === void 0 ? void 0 : entryAssetNode.type) === 'asset');
          entries.push((0, _projectPath.fromProjectPath)(projectRoot, entryAssetNode.value.filePath));
        }
      }
  
      let root = (0, _utils().getRootDir)(entries);
  
      this._targetEntryRoots.set(target.distDir, root);
  
      return root;
    }
  
  }
  
  exports.default = BundleGraph;