"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.propagateSymbols = propagateSymbols;
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 _utils() {
  const data = require("@parcel/utils");
  _utils = function () {
    return data;
  };
  return data;
}
function _logger() {
  const data = _interopRequireDefault(require("@parcel/logger"));
  _logger = function () {
    return data;
  };
  return data;
}
function _diagnostic() {
  const data = require("@parcel/diagnostic");
  _diagnostic = function () {
    return data;
  };
  return data;
}
var _types = require("./types");
var _projectPath = require("./projectPath");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function propagateSymbols({
  options,
  assetGraph,
  changedAssetsPropagation,
  assetGroupsWithRemovedParents,
  previousErrors
}) {
  let changedAssets = new Set([...changedAssetsPropagation].map(id => assetGraph.getNodeIdByContentKey(id)));

  // To reorder once at the end
  let changedDeps = new Set();

  // For the down traversal, the nodes with `usedSymbolsDownDirty = true` are exactly
  // `changedAssetsPropagation` (= asset and therefore potentially dependencies changed) or the
  // asset children of `assetGroupsWithRemovedParents` (= fewer incoming dependencies causing less
  // used symbols).
  //
  // The up traversal has to consider all nodes that changed in the down traversal
  // (`useSymbolsUpDirtyDown = true`) which are listed in `changedDepsUsedSymbolsUpDirtyDown`
  // (more or less requested symbols) and in `changedAssetsPropagation` (changing an asset might
  // change exports).

  // The dependencies that changed in the down traversal causing an update in the up traversal.
  let changedDepsUsedSymbolsUpDirtyDown = new Set();

  // Propagate the requested symbols down from the root to the leaves
  propagateSymbolsDown(assetGraph, changedAssets, assetGroupsWithRemovedParents, (assetNode, incomingDeps, outgoingDeps) => {
    // exportSymbol -> identifier
    let assetSymbols = assetNode.value.symbols;
    // identifier -> exportSymbol
    let assetSymbolsInverse;
    if (assetSymbols) {
      assetSymbolsInverse = new Map();
      for (let [s, {
        local
      }] of assetSymbols) {
        let set = assetSymbolsInverse.get(local);
        if (!set) {
          set = new Set();
          assetSymbolsInverse.set(local, set);
        }
        set.add(s);
      }
    }
    let hasNamespaceOutgoingDeps = outgoingDeps.some(d => {
      var _d$value$symbols;
      return ((_d$value$symbols = d.value.symbols) === null || _d$value$symbols === void 0 || (_d$value$symbols = _d$value$symbols.get('*')) === null || _d$value$symbols === void 0 ? void 0 : _d$value$symbols.local) === '*';
    });

    // 1) Determine what the incomingDeps requests from the asset
    // ----------------------------------------------------------

    let isEntry = false;
    let addAll = false;

    // Used symbols that are exported or reexported (symbol will be removed again later) by asset.
    assetNode.usedSymbols = new Set();

    // Symbols that have to be namespace reexported by outgoingDeps.
    let namespaceReexportedSymbols = new Set();
    if (incomingDeps.length === 0) {
      // Root in the runtimes Graph
      assetNode.usedSymbols.add('*');
      namespaceReexportedSymbols.add('*');
    } else {
      for (let incomingDep of incomingDeps) {
        if (incomingDep.value.symbols == null) {
          if (incomingDep.value.sourceAssetId == null) {
            // The root dependency on non-library builds
            isEntry = true;
          } else {
            // A regular dependency with cleared symbols
            addAll = true;
          }
          continue;
        }
        for (let exportSymbol of incomingDep.usedSymbolsDown) {
          if (exportSymbol === '*') {
            assetNode.usedSymbols.add('*');
            namespaceReexportedSymbols.add('*');
          }
          if (!assetSymbols || assetSymbols.has(exportSymbol) || assetSymbols.has('*')) {
            // An own symbol or a non-namespace reexport
            assetNode.usedSymbols.add(exportSymbol);
          }
          // A namespace reexport
          // (but only if we actually have namespace-exporting outgoing dependencies,
          // This usually happens with a reexporting asset with many namespace exports which means that
          // we cannot match up the correct asset with the used symbol at this level.)
          else if (hasNamespaceOutgoingDeps && exportSymbol !== 'default') {
            namespaceReexportedSymbols.add(exportSymbol);
          }
        }
      }
    }

    // Incomding dependency with cleared symbols, add everything
    if (addAll) {
      assetSymbols === null || assetSymbols === void 0 || assetSymbols.forEach((_, exportSymbol) => assetNode.usedSymbols.add(exportSymbol));
    }

    // 2) Distribute the symbols to the outgoing dependencies
    // ----------------------------------------------------------
    for (let dep of outgoingDeps) {
      let depUsedSymbolsDownOld = dep.usedSymbolsDown;
      let depUsedSymbolsDown = new Set();
      dep.usedSymbolsDown = depUsedSymbolsDown;
      if (assetNode.value.sideEffects ||
      // Incoming dependency with cleared symbols
      addAll ||
      // For entries, we still need to add dep.value.symbols of the entry (which are "used" but not according to the symbols data)
      isEntry ||
      // If not a single symbol is used, we can say the entire subgraph is not used.
      // This is e.g. needed when some symbol is imported and then used for a export which isn't used (= "semi-weak" reexport)
      //    index.js:     `import {bar} from "./lib"; ...`
      //    lib/index.js: `export * from "./foo.js"; export * from "./bar.js";`
      //    lib/foo.js:   `import { data } from "./bar.js"; export const foo = data + " esm2";`
      assetNode.usedSymbols.size > 0 || namespaceReexportedSymbols.size > 0) {
        var _depSymbols$get;
        let depSymbols = dep.value.symbols;
        if (!depSymbols) continue;
        if (((_depSymbols$get = depSymbols.get('*')) === null || _depSymbols$get === void 0 ? void 0 : _depSymbols$get.local) === '*') {
          if (addAll) {
            depUsedSymbolsDown.add('*');
          } else {
            for (let s of namespaceReexportedSymbols) {
              // We need to propagate the namespaceReexportedSymbols to all namespace dependencies (= even wrong ones because we don't know yet)
              depUsedSymbolsDown.add(s);
            }
          }
        }
        for (let [symbol, {
          local
        }] of depSymbols) {
          var _depSymbols$get2;
          // Was already handled above
          if (local === '*') continue;
          if (!assetSymbolsInverse || !((_depSymbols$get2 = depSymbols.get(symbol)) !== null && _depSymbols$get2 !== void 0 && _depSymbols$get2.isWeak)) {
            // Bailout or non-weak symbol (= used in the asset itself = not a reexport)
            depUsedSymbolsDown.add(symbol);
          } else {
            let reexportedExportSymbols = assetSymbolsInverse.get(local);
            if (reexportedExportSymbols == null) {
              // not reexported = used in asset itself
              depUsedSymbolsDown.add(symbol);
            } else if (assetNode.usedSymbols.has('*')) {
              // we need everything
              depUsedSymbolsDown.add(symbol);
              [...reexportedExportSymbols].forEach(s => assetNode.usedSymbols.delete(s));
            } else {
              let usedReexportedExportSymbols = [...reexportedExportSymbols].filter(s => assetNode.usedSymbols.has(s));
              if (usedReexportedExportSymbols.length > 0) {
                // The symbol is indeed a reexport, so it's not used from the asset itself
                depUsedSymbolsDown.add(symbol);
                usedReexportedExportSymbols.forEach(s => assetNode.usedSymbols.delete(s));
              }
            }
          }
        }
      } else {
        depUsedSymbolsDown.clear();
      }
      if (!(0, _utils().setEqual)(depUsedSymbolsDownOld, depUsedSymbolsDown)) {
        dep.usedSymbolsDownDirty = true;
        dep.usedSymbolsUpDirtyDown = true;
        changedDepsUsedSymbolsUpDirtyDown.add(dep.id);
      }
      if (dep.usedSymbolsUpDirtyDown) {
        // Set on node creation
        changedDepsUsedSymbolsUpDirtyDown.add(dep.id);
      }
    }
  });
  const logFallbackNamespaceInsertion = (assetNode, symbol, depNode1, depNode2) => {
    if (options.logLevel === 'verbose') {
      _logger().default.warn({
        message: `${(0, _projectPath.fromProjectPathRelative)(assetNode.value.filePath)} reexports "${symbol}", which could be resolved either to the dependency "${depNode1.value.specifier}" or "${depNode2.value.specifier}" at runtime. Adding a namespace object to fall back on.`,
        origin: '@parcel/core'
      });
    }
  };

  // Because namespace reexports introduce ambiguity, go up the graph from the leaves to the
  // root and remove requested symbols that aren't actually exported
  let errors = propagateSymbolsUp(assetGraph, changedAssets, changedDepsUsedSymbolsUpDirtyDown, previousErrors, (assetNode, incomingDeps, outgoingDeps) => {
    let assetSymbols = assetNode.value.symbols;
    let assetSymbolsInverse = null;
    if (assetSymbols) {
      assetSymbolsInverse = new Map();
      for (let [s, {
        local
      }] of assetSymbols) {
        let set = assetSymbolsInverse.get(local);
        if (!set) {
          set = new Set();
          assetSymbolsInverse.set(local, set);
        }
        set.add(s);
      }
    }

    // the symbols that are reexported (not used in `asset`) -> asset they resolved to
    let reexportedSymbols = new Map();
    // the symbols that are reexported (not used in `asset`) -> the corresponding outgoingDep(s)
    // To generate the diagnostic when there are multiple dependencies with non-statically
    // analyzable exports
    let reexportedSymbolsSource = new Map();
    for (let outgoingDep of outgoingDeps) {
      var _outgoingDepSymbols$g;
      let outgoingDepSymbols = outgoingDep.value.symbols;
      if (!outgoingDepSymbols) continue;
      let isExcluded = assetGraph.getNodeIdsConnectedFrom(assetGraph.getNodeIdByContentKey(outgoingDep.id)).length === 0;
      // excluded, assume everything that is requested exists
      if (isExcluded) {
        outgoingDep.usedSymbolsDown.forEach((_, s) => outgoingDep.usedSymbolsUp.set(s, null));
      }
      if (((_outgoingDepSymbols$g = outgoingDepSymbols.get('*')) === null || _outgoingDepSymbols$g === void 0 ? void 0 : _outgoingDepSymbols$g.local) === '*') {
        outgoingDep.usedSymbolsUp.forEach((sResolved, s) => {
          if (s === 'default') {
            return;
          }

          // If the symbol could come from multiple assets at runtime, assetNode's
          // namespace will be needed at runtime to perform the lookup on.
          if (reexportedSymbols.has(s)) {
            if (!assetNode.usedSymbols.has('*')) {
              logFallbackNamespaceInsertion(assetNode, s, (0, _nullthrows().default)(reexportedSymbolsSource.get(s)), outgoingDep);
            }
            assetNode.usedSymbols.add('*');
            reexportedSymbols.set(s, {
              asset: assetNode.id,
              symbol: s
            });
          } else {
            reexportedSymbols.set(s, sResolved);
            reexportedSymbolsSource.set(s, outgoingDep);
          }
        });
      }
      for (let [s, sResolved] of outgoingDep.usedSymbolsUp) {
        var _outgoingDepSymbols$g2, _assetSymbolsInverse;
        if (!outgoingDep.usedSymbolsDown.has(s)) {
          // usedSymbolsDown is a superset of usedSymbolsUp
          continue;
        }
        let local = (_outgoingDepSymbols$g2 = outgoingDepSymbols.get(s)) === null || _outgoingDepSymbols$g2 === void 0 ? void 0 : _outgoingDepSymbols$g2.local;
        if (local == null) {
          // Caused by '*' => '*', already handled
          continue;
        }
        let reexported = (_assetSymbolsInverse = assetSymbolsInverse) === null || _assetSymbolsInverse === void 0 ? void 0 : _assetSymbolsInverse.get(local);
        if (reexported != null) {
          reexported.forEach(s => {
            // see same code above
            if (reexportedSymbols.has(s)) {
              if (!assetNode.usedSymbols.has('*')) {
                logFallbackNamespaceInsertion(assetNode, s, (0, _nullthrows().default)(reexportedSymbolsSource.get(s)), outgoingDep);
              }
              assetNode.usedSymbols.add('*');
              reexportedSymbols.set(s, {
                asset: assetNode.id,
                symbol: s
              });
            } else {
              reexportedSymbols.set(s, sResolved);
              reexportedSymbolsSource.set(s, outgoingDep);
            }
          });
        }
      }
    }
    let errors = [];
    function usedSymbolsUpAmbiguous(old, current, s, value) {
      if (old.has(s)) {
        let valueOld = old.get(s);
        if (valueOld !== value && !((valueOld === null || valueOld === void 0 ? void 0 : valueOld.asset) === value.asset && (valueOld === null || valueOld === void 0 ? void 0 : valueOld.symbol) === value.symbol)) {
          // The dependency points to multiple assets (via an asset group).
          current.set(s, undefined);
          return;
        }
      }
      current.set(s, value);
    }
    for (let incomingDep of incomingDeps) {
      var _incomingDepSymbols$g;
      let incomingDepUsedSymbolsUpOld = incomingDep.usedSymbolsUp;
      incomingDep.usedSymbolsUp = new Map();
      let incomingDepSymbols = incomingDep.value.symbols;
      if (!incomingDepSymbols) continue;
      let hasNamespaceReexport = ((_incomingDepSymbols$g = incomingDepSymbols.get('*')) === null || _incomingDepSymbols$g === void 0 ? void 0 : _incomingDepSymbols$g.local) === '*';
      for (let s of incomingDep.usedSymbolsDown) {
        if (assetSymbols == null ||
        // Assume everything could be provided if symbols are cleared
        assetNode.value.bundleBehavior === _types.BundleBehavior.isolated || assetNode.value.bundleBehavior === _types.BundleBehavior.inline || s === '*' || assetNode.usedSymbols.has(s)) {
          usedSymbolsUpAmbiguous(incomingDepUsedSymbolsUpOld, incomingDep.usedSymbolsUp, s, {
            asset: assetNode.id,
            symbol: s
          });
        } else if (reexportedSymbols.has(s)) {
          let reexport = reexportedSymbols.get(s);
          let v =
          // Forward a reexport only if the current asset is side-effect free and not external
          !assetNode.value.sideEffects && reexport != null ? reexport : {
            asset: assetNode.id,
            symbol: s
          };
          usedSymbolsUpAmbiguous(incomingDepUsedSymbolsUpOld, incomingDep.usedSymbolsUp, s, v);
        } else if (!hasNamespaceReexport) {
          var _incomingDep$value$sy;
          let loc = (_incomingDep$value$sy = incomingDep.value.symbols) === null || _incomingDep$value$sy === void 0 || (_incomingDep$value$sy = _incomingDep$value$sy.get(s)) === null || _incomingDep$value$sy === void 0 ? void 0 : _incomingDep$value$sy.loc;
          let [resolutionNodeId] = assetGraph.getNodeIdsConnectedFrom(assetGraph.getNodeIdByContentKey(incomingDep.id));
          let resolution = (0, _nullthrows().default)(assetGraph.getNode(resolutionNodeId));
          (0, _assert().default)(resolution && (resolution.type === 'asset_group' || resolution.type === 'asset'));
          errors.push({
            message: (0, _diagnostic().md)`${(0, _projectPath.fromProjectPathRelative)(resolution.value.filePath)} does not export '${s}'`,
            origin: '@parcel/core',
            codeFrames: loc ? [{
              filePath: (0, _projectPath.fromProjectPath)(options.projectRoot, loc === null || loc === void 0 ? void 0 : loc.filePath) ?? undefined,
              language: incomingDep.value.sourceAssetType ?? undefined,
              codeHighlights: [(0, _diagnostic().convertSourceLocationToHighlight)(loc)]
            }] : undefined
          });
        }
      }
      if (!equalMap(incomingDepUsedSymbolsUpOld, incomingDep.usedSymbolsUp)) {
        changedDeps.add(incomingDep);
        incomingDep.usedSymbolsUpDirtyUp = true;
      }
      incomingDep.excluded = false;
      if (incomingDep.value.symbols != null && incomingDep.usedSymbolsUp.size === 0) {
        let assetGroups = assetGraph.getNodeIdsConnectedFrom(assetGraph.getNodeIdByContentKey(incomingDep.id));
        if (assetGroups.length === 1) {
          let [assetGroupId] = assetGroups;
          let assetGroup = (0, _nullthrows().default)(assetGraph.getNode(assetGroupId));
          if (assetGroup.type === 'asset_group' && assetGroup.value.sideEffects === false) {
            incomingDep.excluded = true;
          }
        } else {
          (0, _assert().default)(assetGroups.length === 0);
        }
      }
    }
    return errors;
  });

  // Sort usedSymbolsUp so they are a consistent order across builds.
  // This ensures a consistent ordering of these symbols when packaging.
  // See https://github.com/parcel-bundler/parcel/pull/8212
  for (let dep of changedDeps) {
    dep.usedSymbolsUp = new Map([...dep.usedSymbolsUp].sort(([a], [b]) => a.localeCompare(b)));
  }
  return errors;
}
function propagateSymbolsDown(assetGraph, changedAssets, assetGroupsWithRemovedParents, visit) {
  if (changedAssets.size === 0 && assetGroupsWithRemovedParents.size === 0) {
    return;
  }

  // We care about changed assets and their changed dependencies. So start with the first changed
  // asset or dependency and continue while the symbols change. If the queue becomes empty,
  // continue with the next unvisited changed asset.
  //
  // In the end, nodes, which are neither listed in changedAssets nor in
  // assetGroupsWithRemovedParents nor reached via a dirty flag, don't have to be visited at all.
  //
  // In the worst case, some nodes have to be revisited because we don't want to sort the assets
  // into topological order. For example in a diamond graph where the join point is visited twice
  // via each parent (the numbers signifiying the order of re/visiting, `...` being unvisited).
  // However, this only continues as long as there are changes in the used symbols that influence
  // child nodes.
  //
  //             |
  //            ...
  //          /     \
  //          1     4
  //          \     /
  //            2+5
  //             |
  //            3+6
  //             |
  //            ...
  //             |
  //

  let unreachedAssets = new Set([...changedAssets, ...assetGroupsWithRemovedParents]);
  let queue = new Set([setPop(unreachedAssets)]);
  while (queue.size > 0) {
    let queuedNodeId = setPop(queue);
    unreachedAssets.delete(queuedNodeId);
    let outgoing = assetGraph.getNodeIdsConnectedFrom(queuedNodeId);
    let node = (0, _nullthrows().default)(assetGraph.getNode(queuedNodeId));
    let wasNodeDirty = false;
    if (node.type === 'dependency' || node.type === 'asset_group') {
      wasNodeDirty = node.usedSymbolsDownDirty;
      node.usedSymbolsDownDirty = false;
    } else if (node.type === 'asset' && node.usedSymbolsDownDirty) {
      visit(node, assetGraph.getIncomingDependencies(node.value).map(d => {
        let dep = assetGraph.getNodeByContentKey(d.id);
        (0, _assert().default)(dep && dep.type === 'dependency');
        return dep;
      }), outgoing.map(dep => {
        let depNode = (0, _nullthrows().default)(assetGraph.getNode(dep));
        (0, _assert().default)(depNode.type === 'dependency');
        return depNode;
      }));
      node.usedSymbolsDownDirty = false;
    }
    for (let child of outgoing) {
      let childNode = (0, _nullthrows().default)(assetGraph.getNode(child));
      let childDirty = false;
      if ((childNode.type === 'asset' || childNode.type === 'asset_group') && wasNodeDirty) {
        childNode.usedSymbolsDownDirty = true;
        childDirty = true;
      } else if (childNode.type === 'dependency') {
        childDirty = childNode.usedSymbolsDownDirty;
      }
      if (childDirty) {
        queue.add(child);
      }
    }
    if (queue.size === 0 && unreachedAssets.size > 0) {
      queue.add(setPop(unreachedAssets));
    }
  }
}
function propagateSymbolsUp(assetGraph, changedAssets, changedDepsUsedSymbolsUpDirtyDown, previousErrors, visit) {
  // For graphs in general (so with cyclic dependencies), some nodes will have to be revisited. So
  // run a regular queue-based BFS for anything that's still dirty.
  //
  // (Previously, there was first a recursive post-order DFS, with the idea that all children of a
  // node should be processed first. With a tree, this would result in a minimal amount of work by
  // processing every asset exactly once and then the remaining cycles would have been handled
  // with the loop. This was slightly faster for initial builds but had O(project) instead of
  // O(changes).)

  let errors = previousErrors ?
  // Some nodes might have been removed since the last build
  new Map([...previousErrors].filter(([n]) => assetGraph.hasNode(n))) : new Map();
  let changedDepsUsedSymbolsUpDirtyDownAssets = new Set([...[...changedDepsUsedSymbolsUpDirtyDown].reverse().flatMap(id => getDependencyResolution(assetGraph, id)), ...changedAssets]);

  // Do a more efficient full traversal (less recomputations) if more than half of the assets
  // changed.
  let runFullPass =
  // If there are n nodes in the graph, then the asset count is approximately
  // n/6 (for every asset, there are ~4 dependencies and ~1 asset_group).
  assetGraph.nodes.length * (1 / 6) * 0.5 < changedDepsUsedSymbolsUpDirtyDownAssets.size;
  let dirtyDeps;
  if (runFullPass) {
    dirtyDeps = new Set();
    let rootNodeId = (0, _nullthrows().default)(assetGraph.rootNodeId, 'A root node is required to traverse');
    const nodeVisitor = nodeId => {
      let node = (0, _nullthrows().default)(assetGraph.getNode(nodeId));
      let outgoing = assetGraph.getNodeIdsConnectedFrom(nodeId);
      for (let childId of outgoing) {
        let child = (0, _nullthrows().default)(assetGraph.getNode(childId));
        if (node.type === 'asset') {
          (0, _assert().default)(child.type === 'dependency');
          if (child.usedSymbolsUpDirtyUp) {
            node.usedSymbolsUpDirty = true;
            child.usedSymbolsUpDirtyUp = false;
          }
        }
      }
      if (node.type === 'asset') {
        let incoming = assetGraph.getIncomingDependencies(node.value).map(d => {
          let n = assetGraph.getNodeByContentKey(d.id);
          (0, _assert().default)(n && n.type === 'dependency');
          return n;
        });
        for (let dep of incoming) {
          if (dep.usedSymbolsUpDirtyDown) {
            dep.usedSymbolsUpDirtyDown = false;
            node.usedSymbolsUpDirty = true;
          }
        }
        if (node.usedSymbolsUpDirty) {
          let e = visit(node, incoming, outgoing.map(depNodeId => {
            let depNode = (0, _nullthrows().default)(assetGraph.getNode(depNodeId));
            (0, _assert().default)(depNode.type === 'dependency');
            return depNode;
          }));
          if (e.length > 0) {
            node.usedSymbolsUpDirty = true;
            errors.set(nodeId, e);
          } else {
            node.usedSymbolsUpDirty = false;
            errors.delete(nodeId);
          }
        }
      } else {
        if (node.type === 'dependency') {
          if (node.usedSymbolsUpDirtyUp) {
            dirtyDeps.add(nodeId);
          } else {
            dirtyDeps.delete(nodeId);
          }
        }
      }
    };
    assetGraph.postOrderDfsFast(nodeVisitor, rootNodeId);
  }
  let queue = dirtyDeps ?? changedDepsUsedSymbolsUpDirtyDownAssets;
  while (queue.size > 0) {
    let queuedNodeId = setPop(queue);
    let node = (0, _nullthrows().default)(assetGraph.getNode(queuedNodeId));
    if (node.type === 'asset') {
      let incoming = assetGraph.getIncomingDependencies(node.value).map(dep => {
        let depNode = assetGraph.getNodeByContentKey(dep.id);
        (0, _assert().default)(depNode && depNode.type === 'dependency');
        return depNode;
      });
      for (let dep of incoming) {
        if (dep.usedSymbolsUpDirtyDown) {
          dep.usedSymbolsUpDirtyDown = false;
          node.usedSymbolsUpDirty = true;
        }
      }
      let outgoing = assetGraph.getNodeIdsConnectedFrom(queuedNodeId).map(depNodeId => {
        let depNode = (0, _nullthrows().default)(assetGraph.getNode(depNodeId));
        (0, _assert().default)(depNode.type === 'dependency');
        return depNode;
      });
      for (let dep of outgoing) {
        if (dep.usedSymbolsUpDirtyUp) {
          node.usedSymbolsUpDirty = true;
          dep.usedSymbolsUpDirtyUp = false;
        }
      }
      if (node.usedSymbolsUpDirty) {
        let e = visit(node, incoming, outgoing);
        if (e.length > 0) {
          node.usedSymbolsUpDirty = true;
          errors.set(queuedNodeId, e);
        } else {
          node.usedSymbolsUpDirty = false;
          errors.delete(queuedNodeId);
        }
      }
      for (let i of incoming) {
        if (i.usedSymbolsUpDirtyUp) {
          queue.add(assetGraph.getNodeIdByContentKey(i.id));
        }
      }
    } else {
      let connectedNodes = assetGraph.getNodeIdsConnectedTo(queuedNodeId);
      if (connectedNodes.length > 0) {
        queue.add(...connectedNodes);
      }
    }
  }
  return errors;
}
function getDependencyResolution(graph, depId) {
  let depNodeId = graph.getNodeIdByContentKey(depId);
  let connected = graph.getNodeIdsConnectedFrom(depNodeId);
  (0, _assert().default)(connected.length <= 1);
  let child = connected[0];
  if (child) {
    let childNode = (0, _nullthrows().default)(graph.getNode(child));
    if (childNode.type === 'asset_group') {
      return graph.getNodeIdsConnectedFrom(child);
    } else {
      return [child];
    }
  }
  return [];
}
function equalMap(a, b) {
  if (a.size !== b.size) return false;
  for (let [k, v] of a) {
    if (!b.has(k)) return false;
    let vB = b.get(k);
    if ((vB === null || vB === void 0 ? void 0 : vB.asset) !== (v === null || v === void 0 ? void 0 : v.asset) || (vB === null || vB === void 0 ? void 0 : vB.symbol) !== (v === null || v === void 0 ? void 0 : v.symbol)) return false;
  }
  return true;
}
function setPop(set) {
  let v = (0, _nullthrows().default)(set.values().next().value);
  set.delete(v);
  return v;
}