text: "use strict";
  Object.defineProperty(exports, "__esModule", { value: true });
  var _ = require("lodash");
  var graphlib = require("graphlib");
  var create_from_json_1 = require("./create-from-json");
  var DepGraphImpl = /** @class */ (function () {
      function DepGraphImpl(graph, rootNodeId, pkgs, pkgNodes, pkgManager) {
          this._countNodePathsToRootCache = new Map();
          this._graph = graph;
          this._pkgs = pkgs;
          this._pkgNodes = pkgNodes;
          this._pkgManager = pkgManager;
          this._rootNodeId = rootNodeId;
          this._rootPkgId = graph.node(rootNodeId).pkgId;
          this._pkgList = _.values(pkgs);
      }
      DepGraphImpl.getPkgId = function (pkg) {
          return pkg.name + "@" + (pkg.version || '');
      };
      Object.defineProperty(DepGraphImpl.prototype, "pkgManager", {
          get: function () {
              return this._pkgManager;
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(DepGraphImpl.prototype, "rootPkg", {
          get: function () {
              return this._pkgs[this._rootPkgId];
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(DepGraphImpl.prototype, "rootNodeId", {
          get: function () {
              return this._rootNodeId;
          },
          enumerable: true,
          configurable: true
      });
      DepGraphImpl.prototype.getPkgs = function () {
          return this._pkgList;
      };
      DepGraphImpl.prototype.getNode = function (nodeId) {
          return this.getGraphNode(nodeId).info || {};
      };
      DepGraphImpl.prototype.getNodePkg = function (nodeId) {
          return this._pkgs[this.getGraphNode(nodeId).pkgId];
      };
      DepGraphImpl.prototype.getPkgNodeIds = function (pkg) {
          var pkgId = DepGraphImpl.getPkgId(pkg);
          if (!this._pkgs[pkgId]) {
              throw new Error("no such pkg: " + pkgId);
          }
          return Array.from(this._pkgNodes[pkgId]);
      };
      DepGraphImpl.prototype.getNodeDepsNodeIds = function (nodeId) {
          var deps = this._graph.successors(nodeId);
          if (!deps) {
              throw new Error("no such node: " + nodeId);
          }
          return deps;
      };
      DepGraphImpl.prototype.getNodeParentsNodeIds = function (nodeId) {
          var parents = this._graph.predecessors(nodeId);
          if (!parents) {
              throw new Error("no such node: " + nodeId);
          }
          return parents;
      };
      DepGraphImpl.prototype.hasCycles = function () {
          // `isAcyclic` is expensive, so memoize
          if (this._hasCycles === undefined) {
              this._hasCycles = !graphlib.alg.isAcyclic(this._graph);
          }
          return this._hasCycles;
      };
      DepGraphImpl.prototype.pkgPathsToRoot = function (pkg) {
          // TODO: implement cycles support
          if (this.hasCycles()) {
              throw new Error('pkgPathsToRoot does not support cyclic graphs yet');
          }
          var pathsToRoot = [];
          for (var _i = 0, _a = this.getPkgNodeIds(pkg); _i < _a.length; _i++) {
              var id = _a[_i];
              pathsToRoot.push.apply(pathsToRoot, this.pathsFromNodeToRoot(id));
          }
          // note: sorting to get shorter paths first -
          //  it's nicer - and better resembles older behaviour
          return pathsToRoot.sort(function (a, b) { return a.length - b.length; });
      };
      DepGraphImpl.prototype.countPathsToRoot = function (pkg) {
          // TODO: implement cycles support
          if (this.hasCycles()) {
              throw new Error('countPathsToRoot does not support cyclic graphs yet');
          }
          var count = 0;
          for (var _i = 0, _a = this.getPkgNodeIds(pkg); _i < _a.length; _i++) {
              var nodeId = _a[_i];
              count += this.countNodePathsToRoot(nodeId);
          }
          return count;
      };
      DepGraphImpl.prototype.equals = function (other, _a) {
          var _b = (_a === void 0 ? {} : _a).compareRoot, compareRoot = _b === void 0 ? true : _b;
          var otherDepGraph;
          if (other instanceof DepGraphImpl) {
              otherDepGraph = other;
          }
          else {
              // At runtime theoretically we can have multiple versions of
              // @snyk/dep-graph. If "other" is not an instance of the same class it is
              // safer to rebuild it from JSON.
              otherDepGraph = create_from_json_1.createFromJSON(other.toJSON());
          }
          return this.nodeEquals(this, this.rootNodeId, otherDepGraph, otherDepGraph.rootNodeId, compareRoot);
      };
      DepGraphImpl.prototype.toJSON = function () {
          var _this = this;
          var nodeIds = this._graph.nodes();
          var nodes = nodeIds.reduce(function (acc, nodeId) {
              var deps = (_this._graph.successors(nodeId) || [])
                  .map(function (depNodeId) { return ({ nodeId: depNodeId }); });
              var node = _this._graph.node(nodeId);
              var elem = {
                  nodeId: nodeId,
                  pkgId: node.pkgId,
                  deps: deps,
              };
              if (!_.isEmpty(node.info)) {
                  elem.info = node.info;
              }
              acc.push(elem);
              return acc;
          }, []);
          var pkgs = _.keys(this._pkgs)
              .map(function (pkgId) { return ({
              id: pkgId,
              info: _this._pkgs[pkgId],
          }); });
          return {
              schemaVersion: DepGraphImpl.SCHEMA_VERSION,
              pkgManager: this._pkgManager,
              pkgs: pkgs,
              graph: {
                  rootNodeId: this._rootNodeId,
                  nodes: nodes,
              },
          };
      };
      DepGraphImpl.prototype.nodeEquals = function (graphA, nodeIdA, graphB, nodeIdB, compareRoot, traversedPairs) {
          if (traversedPairs === void 0) { traversedPairs = new Set(); }
          // Skip root nodes comparision if needed.
          if (compareRoot || (nodeIdA !== graphA.rootNodeId && nodeIdB !== graphB.rootNodeId)) {
              var pkgA = graphA.getNodePkg(nodeIdA);
              var pkgB = graphB.getNodePkg(nodeIdB);
              // Compare PkgInfo (name and version).
              if (!_.isEqual(pkgA, pkgB)) {
                  return false;
              }
              var infoA = graphA.getNode(nodeIdA);
              var infoB = graphB.getNode(nodeIdB);
              // Compare NodeInfo (VersionProvenance and labels).
              if (!_.isEqual(infoA, infoB)) {
                  return false;
              }
          }
          var depsA = graphA.getNodeDepsNodeIds(nodeIdA);
          var depsB = graphB.getNodeDepsNodeIds(nodeIdA);
          // Number of dependencies should be the same.
          if (depsA.length !== depsB.length) {
              return false;
          }
          // Sort dependencies by name@version string.
          var sortFn = function (graph) { return function (idA, idB) {
              var pkgA = graph.getNodePkg(idA);
              var pkgB = graph.getNodePkg(idB);
              return DepGraphImpl.getPkgId(pkgA).localeCompare(DepGraphImpl.getPkgId(pkgB));
          }; };
          depsA = depsA.sort(sortFn(graphA));
          depsB = depsB.sort(sortFn(graphB));
          // Compare Each dependency recursively.
          for (var i = 0; i < depsA.length; i++) {
              var pairKey = depsA[i] + "_" + depsB[i];
              // Prevent cycles.
              if (traversedPairs.has(pairKey)) {
                  continue;
              }
              traversedPairs.add(pairKey);
              if (!this.nodeEquals(graphA, depsA[i], graphB, depsB[i], compareRoot, traversedPairs)) {
                  return false;
              }
          }
          return true;
      };
      DepGraphImpl.prototype.getGraphNode = function (nodeId) {
          var node = this._graph.node(nodeId);
          if (!node) {
              throw new Error("no such node: " + nodeId);
          }
          return node;
      };
      DepGraphImpl.prototype.pathsFromNodeToRoot = function (nodeId) {
          var _this = this;
          var parentNodesIds = this.getNodeParentsNodeIds(nodeId);
          if (parentNodesIds.length === 0) {
              return [[this.getNodePkg(nodeId)]];
          }
          var allPaths = [];
          parentNodesIds.map(function (id) {
              var out = _this.pathsFromNodeToRoot(id).map(function (path) {
                  return [_this.getNodePkg(nodeId)].concat(path);
              });
              allPaths.push.apply(allPaths, out);
          });
          return allPaths;
      };
      DepGraphImpl.prototype.countNodePathsToRoot = function (nodeId) {
          var _this = this;
          if (this._countNodePathsToRootCache.has(nodeId)) {
              return this._countNodePathsToRootCache.get(nodeId) || 0;
          }
          var parentNodesIds = this.getNodeParentsNodeIds(nodeId);
          if (parentNodesIds.length === 0) {
              this._countNodePathsToRootCache.set(nodeId, 1);
              return 1;
          }
          var count = parentNodesIds.reduce(function (acc, parentNodeId) {
              return acc + _this.countNodePathsToRoot(parentNodeId);
          }, 0);
          this._countNodePathsToRootCache.set(nodeId, count);
          return count;
      };
      DepGraphImpl.SCHEMA_VERSION = '1.2.0';
      return DepGraphImpl;
  }());
  exports.DepGraphImpl = DepGraphImpl;
  //# sourceMappingURL=dep-graph.js.map