"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.createForProject = createForProject;
exports.YarnPackageManager = exports.NpmPackageManager = void 0;

function _ansiRegex() {
  const data = _interopRequireDefault(require("ansi-regex"));

  _ansiRegex = function () {
    return data;
  };

  return data;
}

function _config() {
  const data = require("@expo/config");

  _config = function () {
    return data;
  };

  return data;
}

function _spawnAsync() {
  const data = _interopRequireDefault(require("@expo/spawn-async"));

  _spawnAsync = function () {
    return data;
  };

  return data;
}

function _split() {
  const data = _interopRequireDefault(require("split"));

  _split = function () {
    return data;
  };

  return data;
}

function _stream() {
  const data = require("stream");

  _stream = function () {
    return data;
  };

  return data;
}

function _npmPackageArg() {
  const data = _interopRequireDefault(require("npm-package-arg"));

  _npmPackageArg = function () {
    return data;
  };

  return data;
}

function _fsExtra() {
  const data = _interopRequireDefault(require("fs-extra"));

  _fsExtra = function () {
    return data;
  };

  return data;
}

function _path() {
  const data = _interopRequireDefault(require("path"));

  _path = function () {
    return data;
  };

  return data;
}

function _detectIndent() {
  const data = _interopRequireDefault(require("detect-indent"));

  _detectIndent = function () {
    return data;
  };

  return data;
}

function _detectNewline() {
  const data = _interopRequireDefault(require("detect-newline"));

  _detectNewline = function () {
    return data;
  };

  return data;
}

function _log() {
  const data = _interopRequireDefault(require("./log"));

  _log = function () {
    return data;
  };

  return data;
}

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

const ansi = `(?:${(0, _ansiRegex().default)().source})*`;
const npmPeerDependencyWarningPattern = new RegExp(`${ansi}npm${ansi} ${ansi}WARN${ansi}.+You must install peer dependencies yourself\\.\n`, 'g');
const yarnPeerDependencyWarningPattern = new RegExp(`${ansi}warning${ansi} "[^"]+" has (?:unmet|incorrect) peer dependency "[^"]+"\\.\n`, 'g');

class NpmStderrTransform extends _stream().Transform {
  _transform(chunk, encoding, callback) {
    this.push(chunk.toString().replace(npmPeerDependencyWarningPattern, ''));
    callback();
  }

}

class YarnStderrTransform extends _stream().Transform {
  _transform(chunk, encoding, callback) {
    this.push(chunk.toString().replace(yarnPeerDependencyWarningPattern, ''));
    callback();
  }

}

class NpmPackageManager {
  constructor({
    cwd
  }) {
    this.options = {
      cwd,
      stdio: ['inherit', 'inherit', 'pipe']
    };
  }

  get name() {
    return 'npm';
  }

  async installAsync() {
    await this._runAsync(['install']);
  }

  async addAsync(...names) {
    const {
      versioned,
      unversioned
    } = this._parseSpecs(names);

    if (versioned.length) {
      await this._patchAsync(versioned, 'dependencies');
      await this._runAsync(['install']);
    }

    if (unversioned.length) {
      await this._runAsync(['install', '--save', ...unversioned.map(spec => spec.raw)]);
    }
  }

  async addDevAsync(...names) {
    const {
      versioned,
      unversioned
    } = this._parseSpecs(names);

    if (versioned.length) {
      await this._patchAsync(versioned, 'devDependencies');
      await this._runAsync(['install']);
    }

    if (unversioned.length) {
      await this._runAsync(['install', '--save-dev', ...unversioned.map(spec => spec.raw)]);
    }
  } // Private


  async _runAsync(args) {
    (0, _log().default)(`> npm ${args.join(' ')}`);
    const promise = (0, _spawnAsync().default)('npm', [...args], this.options);

    if (promise.child.stderr) {
      promise.child.stderr.pipe((0, _split().default)(/\r?\n/, line => line + '\n')).pipe(new NpmStderrTransform()).pipe(process.stderr);
    }

    await promise;
  }

  _parseSpecs(names) {
    const result = {
      versioned: [],
      unversioned: []
    };
    names.map(name => (0, _npmPackageArg().default)(name)).forEach(spec => {
      if (spec.rawSpec) {
        result.versioned.push(spec);
      } else {
        result.unversioned.push(spec);
      }
    });
    return result;
  }

  async _patchAsync(specs, packageType) {
    const pkgPath = _path().default.join(this.options.cwd || '.', 'package.json');

    const pkgRaw = await _fsExtra().default.readFile(pkgPath, {
      encoding: 'utf8',
      flag: 'r'
    });
    const pkg = JSON.parse(pkgRaw);
    specs.forEach(spec => {
      pkg[packageType] = pkg[packageType] || {};
      pkg[packageType][spec.name] = spec.rawSpec;
    });
    await _fsExtra().default.writeJson(pkgPath, pkg, {
      spaces: (0, _detectIndent().default)(pkgRaw).indent,
      EOL: (0, _detectNewline().default)(pkgRaw)
    });
  }

}

exports.NpmPackageManager = NpmPackageManager;

class YarnPackageManager {
  constructor({
    cwd
  }) {
    this.options = {
      cwd,
      stdio: ['inherit', 'inherit', 'pipe']
    };
  }

  get name() {
    return 'Yarn';
  }

  async installAsync() {
    await this._runAsync(['install']);
  }

  async addAsync(...names) {
    await this._runAsync(['add', ...names]);
  }

  async addDevAsync(...names) {
    await this._runAsync(['add', '--dev', ...names]);
  } // Private


  async _runAsync(args) {
    (0, _log().default)(`> yarn ${args.join(' ')}`);
    const promise = (0, _spawnAsync().default)('yarnpkg', args, this.options);

    if (promise.child.stderr) {
      promise.child.stderr.pipe(new YarnStderrTransform()).pipe(process.stderr);
    }

    await promise;
  }

}

exports.YarnPackageManager = YarnPackageManager;

function createForProject(projectRoot, options = {}) {
  let PackageManager;

  if (options.npm) {
    PackageManager = NpmPackageManager;
  } else if (options.yarn) {
    PackageManager = YarnPackageManager;
  } else if ((0, _config().isUsingYarn)(projectRoot)) {
    PackageManager = YarnPackageManager;
  } else {
    PackageManager = NpmPackageManager;
  }

  return new PackageManager({
    cwd: projectRoot
  });
}
//# sourceMappingURL=__sourcemaps__/PackageManager.js.map