text: "use strict";
  // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
  // See LICENSE in the project root for license information.
  Object.defineProperty(exports, "__esModule", { value: true });
  const colors = require("colors");
  const fsx = require("fs-extra");
  const os = require("os");
  const semver = require("semver");
  const npmPackageArg = require("npm-package-arg");
  const Utilities_1 = require("../../utilities/Utilities");
  const RushConstants_1 = require("../../RushConstants");
  /**
   * This class is a parser for NPM's npm-shrinkwrap.json file format.
   */
  class ShrinkwrapFile {
      constructor(shrinkwrapJson) {
          this._alreadyWarnedSpecs = new Set();
          this._shrinkwrapJson = shrinkwrapJson;
          // Normalize the data
          if (!this._shrinkwrapJson.version) {
              this._shrinkwrapJson.version = '';
          }
          if (!this._shrinkwrapJson.name) {
              this._shrinkwrapJson.name = '';
          }
          if (!this._shrinkwrapJson.dependencies) {
              this._shrinkwrapJson.dependencies = {};
          }
      }
      static loadFromFile(shrinkwrapJsonFilename) {
          let data = undefined;
          try {
              if (!fsx.existsSync(shrinkwrapJsonFilename)) {
                  return undefined; // file does not exist
              }
              // We don't use JsonFile/jju here because shrinkwrap.json is a special NPM file format
              // and typically very large, so we want to load it the same way that NPM does.
              data = fsx.readFileSync(shrinkwrapJsonFilename).toString();
              if (data.charCodeAt(0) === 0xFEFF) {
                  data = data.slice(1);
              }
              return new ShrinkwrapFile(JSON.parse(data));
          }
          catch (error) {
              throw new Error(`Error reading "${shrinkwrapJsonFilename}":` + os.EOL + `  ${error.message}`);
          }
      }
      static tryGetValue(dictionary, key) {
          if (dictionary.hasOwnProperty(key)) {
              return dictionary[key];
          }
          return undefined;
      }
      /**
       * Returns the list of temp projects defined in this file.
       * Example: [ '@rush-temp/project1', '@rush-temp/project2' ]
       */
      getTempProjectNames() {
          const result = [];
          for (const key of Object.keys(this._shrinkwrapJson.dependencies)) {
              // If it starts with @rush-temp, then include it:
              if (Utilities_1.default.parseScopedPackageName(key).scope === RushConstants_1.RushConstants.rushTempNpmScope) {
                  result.push(key);
              }
          }
          result.sort(); // make the result deterministic
          return result;
      }
      /**
       * Returns true if the shrinkwrap file includes a package that would satisfiying the specified
       * package name and SemVer version range.  By default, the dependencies are resolved by looking
       * at the root of the node_modules folder described by the shrinkwrap file.  However, if
       * tempProjectName is specified, then the resolution will start in that subfolder.
       *
       * Consider this example:
       *
       * - node_modules\
       *   - temp-project\
       *     - lib-a@1.2.3
       *     - lib-b@1.0.0
       *   - lib-b@2.0.0
       *
       * In this example, hasCompatibleDependency("lib-b", ">= 1.1.0", "temp-project") would fail
       * because it finds lib-b@1.0.0 which does not satisfy the pattern ">= 1.1.0".
       */
      hasCompatibleDependency(dependencyName, versionRange, tempProjectName) {
          // First, check under tempProjectName, as this is the first place "rush link" looks.
          let dependencyJson = undefined;
          if (tempProjectName) {
              const tempDependency = ShrinkwrapFile.tryGetValue(this._shrinkwrapJson.dependencies, tempProjectName);
              if (tempDependency && tempDependency.dependencies) {
                  dependencyJson = ShrinkwrapFile.tryGetValue(tempDependency.dependencies, dependencyName);
              }
          }
          // Otherwise look at the root of the shrinkwrap file
          if (!dependencyJson) {
              dependencyJson = ShrinkwrapFile.tryGetValue(this._shrinkwrapJson.dependencies, dependencyName);
          }
          if (!dependencyJson) {
              return false;
          }
          const result = npmPackageArg.resolve(dependencyName, versionRange);
          switch (result.type) {
              case 'version':
              case 'range':
                  // If it's a SemVer pattern, then require that the shrinkwrapped version must be compatible
                  return semver.satisfies(dependencyJson.version, versionRange);
              default:
                  // Only warn once for each spec
                  if (!this._alreadyWarnedSpecs.has(result.rawSpec)) {
                      this._alreadyWarnedSpecs.add(result.rawSpec);
                      console.log(colors.yellow(`WARNING: Not validating ${result.type}-based specifier: "${result.rawSpec}"`));
                  }
                  return true;
          }
      }
  }
  exports.default = ShrinkwrapFile;
  
  //# sourceMappingURL=ShrinkwrapFile.js.map
  