text: "use strict";
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
      return new (P || (P = Promise))(function (resolve, reject) {
          function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
          function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
          function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
          step((generator = generator.apply(thisArg, _arguments || [])).next());
      });
  };
  Object.defineProperty(exports, "__esModule", { value: true });
  const Debug = require("debug");
  const depGraphLib = require("@snyk/dep-graph");
  const snyk = require("../lib");
  const api_token_1 = require("./api-token");
  const request = require("./request");
  const config = require("./config");
  const os = require("os");
  const _ = require("lodash");
  const is_ci_1 = require("./is-ci");
  const analytics = require("./analytics");
  const projectMetadata = require("./project-metadata");
  const path = require("path");
  const errors_1 = require("./errors");
  const debug = Debug('snyk');
  function dropEmptyDeps(node) {
      if (node.dependencies) {
          const keys = Object.keys(node.dependencies);
          if (keys.length === 0) {
              delete node.dependencies;
          }
          else {
              for (const k of keys) {
                  dropEmptyDeps(node.dependencies[k]);
              }
          }
      }
  }
  function countTotalDependenciesInTree(depTree) {
      let count = 0;
      if (depTree.dependencies) {
          for (const name of Object.keys(depTree.dependencies)) {
              const dep = depTree.dependencies[name];
              if (dep) {
                  count += 1 + countTotalDependenciesInTree(dep);
              }
          }
      }
      return count;
  }
  function pruneTree(tree, packageManagerName) {
      return __awaiter(this, void 0, void 0, function* () {
          debug('pruning dep tree');
          // Pruning requires conversion to the graph first.
          // This is slow.
          const graph = yield depGraphLib.legacy.depTreeToGraph(tree, packageManagerName);
          const prunedTree = yield depGraphLib.legacy
              .graphToDepTree(graph, packageManagerName, { deduplicateWithinTopLevelDeps: true });
          // Transplant pruned dependencies in the original tree (we want to keep all other fields):
          tree.dependencies = prunedTree.dependencies;
          debug('finished pruning dep tree');
          return tree;
      });
  }
  function monitor(root, meta, info, targetFile) {
      return __awaiter(this, void 0, void 0, function* () {
          api_token_1.apiTokenExists();
          let prePruneDepCount;
          if (meta.prune) {
              debug('prune used, counting total dependencies');
              prePruneDepCount = countTotalDependenciesInTree(info.package);
              analytics.add('prePruneDepCount', prePruneDepCount);
              debug('total dependencies: %d', prePruneDepCount);
          }
          const pkg = meta.prune
              ? yield pruneTree(info.package, meta.packageManager)
              : info.package;
          const pluginMeta = info.plugin;
          let policy;
          const policyPath = meta['policy-path'] || root;
          const policyLocations = [policyPath].concat(pluckPolicies(pkg))
              .filter(Boolean);
          // docker doesn't have a policy as it can be run from anywhere
          if (!meta.isDocker || !policyLocations.length) {
              yield snyk.policy.create();
          }
          policy = yield snyk.policy.load(policyLocations, { loose: true });
          const packageManager = meta.packageManager;
          analytics.add('packageManager', packageManager);
          analytics.add('isDocker', !!meta.isDocker);
          const target = yield projectMetadata.getInfo(pkg);
          const targetFileRelativePath = targetFile ? path.relative(root, targetFile) : '';
          if (target && target.branch) {
              analytics.add('targetBranch', target.branch);
          }
          dropEmptyDeps(pkg);
          // TODO(kyegupov): async/await
          return new Promise((resolve, reject) => {
              request({
                  body: {
                      meta: {
                          method: meta.method,
                          hostname: os.hostname(),
                          id: snyk.id || pkg.name,
                          ci: is_ci_1.isCI(),
                          pid: process.pid,
                          node: process.version,
                          master: snyk.config.isMaster,
                          name: pkg.name,
                          version: pkg.version,
                          org: config.org ? decodeURIComponent(config.org) : undefined,
                          pluginName: pluginMeta.name,
                          pluginRuntime: pluginMeta.runtime,
                          dockerImageId: pluginMeta.dockerImageId,
                          dockerBaseImage: pkg.docker ? pkg.docker.baseImage : undefined,
                          dockerfileLayers: pkg.docker ? pkg.docker.dockerfileLayers : undefined,
                          projectName: meta['project-name'],
                          prePruneDepCount,
                      },
                      policy: policy ? policy.toString() : undefined,
                      package: pkg,
                      // we take the targetFile from the plugin,
                      // because we want to send it only for specific package-managers
                      target,
                      targetFile: pluginMeta.targetFile,
                      targetFileRelativePath,
                  },
                  gzip: true,
                  method: 'PUT',
                  headers: {
                      'authorization': 'token ' + snyk.api,
                      'content-encoding': 'gzip',
                  },
                  url: config.API + '/monitor/' + packageManager,
                  json: true,
              }, (error, res, body) => {
                  if (error) {
                      return reject(error);
                  }
                  if (res.statusCode === 200 || res.statusCode === 201) {
                      resolve(body);
                  }
                  else {
                      let err;
                      const userMessage = body && body.userMessage;
                      if (!userMessage && res.statusCode === 504) {
                          err = new errors_1.ConnectionTimeoutError();
                      }
                      else {
                          err = new errors_1.MonitorError(res.statusCode, userMessage);
                      }
                      reject(err);
                  }
              });
          });
      });
  }
  exports.monitor = monitor;
  function pluckPolicies(pkg) {
      if (!pkg) {
          return null;
      }
      if (pkg.snyk) {
          return pkg.snyk;
      }
      if (!pkg.dependencies) {
          return null;
      }
      return _.flatten(Object.keys(pkg.dependencies).map((name) => {
          return pluckPolicies(pkg.dependencies[name]);
      }).filter(Boolean));
  }
  //# sourceMappingURL=monitor.js.map