"use strict";

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

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

  _path = function () {
    return data;
  };

  return data;
}

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

  ConfigUtils = function () {
    return data;
  };

  return data;
}

function _devTools() {
  const data = require("@expo/dev-tools");

  _devTools = function () {
    return data;
  };

  return data;
}

function _jsonFile() {
  const data = _interopRequireDefault(require("@expo/json-file"));

  _jsonFile = function () {
    return data;
  };

  return data;
}

function _xdl() {
  const data = require("@expo/xdl");

  _xdl = function () {
    return data;
  };

  return data;
}

function _chalk() {
  const data = _interopRequireDefault(require("chalk"));

  _chalk = function () {
    return data;
  };

  return data;
}

function _openBrowser() {
  const data = _interopRequireDefault(require("react-dev-utils/openBrowser"));

  _openBrowser = function () {
    return data;
  };

  return data;
}

function _intersection() {
  const data = _interopRequireDefault(require("lodash/intersection"));

  _intersection = function () {
    return data;
  };

  return data;
}

function _semver() {
  const data = _interopRequireDefault(require("semver"));

  _semver = function () {
    return data;
  };

  return data;
}

function _attempt() {
  const data = _interopRequireDefault(require("lodash/attempt"));

  _attempt = function () {
    return data;
  };

  return data;
}

function _isError() {
  const data = _interopRequireDefault(require("lodash/isError"));

  _isError = function () {
    return data;
  };

  return data;
}

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

  _log = function () {
    return data;
  };

  return data;
}

function _sendTo() {
  const data = _interopRequireDefault(require("../sendTo"));

  _sendTo = function () {
    return data;
  };

  return data;
}

function _exit() {
  const data = require("../exit");

  _exit = function () {
    return data;
  };

  return data;
}

function _urlOpts() {
  const data = _interopRequireDefault(require("../urlOpts"));

  _urlOpts = function () {
    return data;
  };

  return data;
}

function TerminalUI() {
  const data = _interopRequireWildcard(require("./start/TerminalUI"));

  TerminalUI = function () {
    return data;
  };

  return data;
}

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }

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

function parseStartOptions(projectDir, options) {
  let startOpts = {};

  if (options.clear) {
    startOpts.reset = true;
  }

  if (options.nonInteractive) {
    startOpts.nonInteractive = true;
  }

  if (options.webOnly) {
    startOpts.webOnly = true;
  }

  if (options.maxWorkers) {
    startOpts.maxWorkers = options.maxWorkers;
  }

  return startOpts;
}

async function startWebAction(projectDir, options) {
  const {
    exp,
    rootPath
  } = await configureProjectAsync(projectDir, options);
  const startOpts = parseStartOptions(projectDir, options);
  await _xdl().Project.startAsync(rootPath, startOpts);
  await _urlOpts().default.handleMobileOptsAsync(projectDir, options);

  if (!options.nonInteractive && !exp.isDetached) {
    await TerminalUI().startAsync(projectDir, startOpts);
  }
}

async function action(projectDir, options) {
  const {
    exp,
    pkg,
    rootPath
  } = await configureProjectAsync(projectDir, options);
  await validateDependenciesVersions(projectDir, exp, pkg);
  const startOpts = parseStartOptions(projectDir, options);
  await _xdl().Project.startAsync(rootPath, startOpts);
  const url = await _xdl().UrlUtils.constructManifestUrlAsync(projectDir);
  const recipient = await _sendTo().default.getRecipient(options.sendTo);

  if (recipient) {
    await _sendTo().default.sendUrlAsync(url, recipient);
  }

  await _urlOpts().default.handleMobileOptsAsync(projectDir, options);

  if (!startOpts.nonInteractive && !exp.isDetached) {
    await TerminalUI().startAsync(projectDir, startOpts);
  } else {
    if (!exp.isDetached) {
      _log().default.newLine();

      _urlOpts().default.printQRCode(url);
    }

    (0, _log().default)(`Your native app is running at ${_chalk().default.underline(url)}`);
  }

  _log().default.nested(_chalk().default.green('Logs for your project will appear below. Press Ctrl+C to exit.'));
}

async function validateDependenciesVersions(projectDir, exp, pkg) {
  if (!_xdl().Versions.gteSdkVersion(exp, '33.0.0')) {
    return;
  }

  const bundleNativeModulesPath = (0, _attempt().default)(() => ConfigUtils().resolveModule('expo/bundledNativeModules.json', projectDir, exp));

  if ((0, _isError().default)(bundleNativeModulesPath)) {
    _log().default.warn(`Your project is in SDK version >= 33.0.0, but the ${_chalk().default.underline('expo')} package version seems to be older.`);

    return;
  }

  const bundledNativeModules = await _jsonFile().default.readAsync(bundleNativeModulesPath);
  const bundledNativeModulesNames = Object.keys(bundledNativeModules);
  const projectDependencies = Object.keys(pkg.dependencies);
  const modulesToCheck = (0, _intersection().default)(bundledNativeModulesNames, projectDependencies);
  const incorrectDeps = [];

  for (const moduleName of modulesToCheck) {
    const expectedRange = bundledNativeModules[moduleName];
    const actualRange = pkg.dependencies[moduleName];

    if ((_semver().default.valid(actualRange) || _semver().default.validRange(actualRange)) && !_semver().default.intersects(expectedRange, actualRange)) {
      incorrectDeps.push({
        moduleName,
        expectedRange,
        actualRange
      });
    }
  }

  if (incorrectDeps.length > 0) {
    _log().default.warn("Some of your project's dependencies are not compatible with currently installed expo package version:");

    incorrectDeps.forEach(({
      moduleName,
      expectedRange,
      actualRange
    }) => {
      _log().default.warn(` - ${_chalk().default.underline(moduleName)} - expected version range: ${_chalk().default.underline(expectedRange)} - actual version installed: ${_chalk().default.underline(actualRange)}`);
    });

    _log().default.warn('Your project may not work correctly until you install the correct versions of the packages.\n' + `To install the correct versions of these packages, please run: ${_chalk().default.inverse('expo install [package-name ...]')}`);
  }
}

async function normalizeOptionsAsync(projectDir, options) {
  const nonInteractive = options.parent && options.parent.nonInteractive;
  let webOnly = false;

  if (typeof options.webOnly !== 'undefined') {
    webOnly = options.webOnly;
  } else {
    webOnly = await _xdl().Web.onlySupportsWebAsync(projectDir);
  }

  return { ...options,
    webOnly,
    nonInteractive
  };
}

async function tryOpeningDevToolsAsync({
  rootPath,
  exp,
  options
}) {
  const devToolsUrl = await _devTools().DevToolsServer.startAsync(rootPath);
  (0, _log().default)(`Expo DevTools is running at ${_chalk().default.underline(devToolsUrl)}`);

  if (!options.nonInteractive && !exp.isDetached) {
    if (await _xdl().UserSettings.getAsync('openDevToolsAtStartup', true)) {
      (0, _log().default)(`Opening DevTools in the browser... (press ${_chalk().default.bold`shift-d`} to disable)`);
      (0, _openBrowser().default)(devToolsUrl);
    } else {
      (0, _log().default)(`Press ${_chalk().default.bold`d`} to open DevTools now, or ${_chalk().default.bold`shift-d`} to always open it automatically.`);
    }
  }
}

async function configureProjectAsync(projectDir, options) {
  if (options.webOnly) {
    (0, _exit().installExitHooks)(projectDir, _xdl().Project.stopWebOnlyAsync);
  } else {
    (0, _exit().installExitHooks)(projectDir);
  }

  await _urlOpts().default.optsAsync(projectDir, options);
  (0, _log().default)(_chalk().default.gray(`Starting project at ${projectDir}`));
  const {
    exp,
    pkg
  } = await _xdl().ProjectUtils.readConfigJsonAsync(projectDir, options.webOnly);

  if (exp === null) {
    _log().default.warn(`No Expo configuration found. Are you sure this is a project directory?`);

    process.exit(1);
  }

  const rootPath = _path().default.resolve(projectDir);

  await tryOpeningDevToolsAsync({
    rootPath,
    exp,
    options
  });
  return {
    rootPath,
    exp,
    pkg
  };
}

var _default = program => {
  program.command('start [project-dir]').alias('r').description('Starts or restarts a local server for your app and gives you a URL to it').option('-s, --send-to [dest]', 'An email address to send a link to').option('-c, --clear', 'Clear the React Native packager cache').option('--web-only', 'Only start the Webpack dev server for web. [Deprecated]: use `expo start:web`') // TODO(anp) set a default for this dynamically based on whether we're inside a container?
  .option('--max-workers [num]', 'Maximum number of tasks to allow Metro to spawn.').urlOpts().allowOffline().asyncActionProjectDir(async (projectDir, options) => {
    const normalizedOptions = await normalizeOptionsAsync(projectDir, options);

    if (normalizedOptions.webOnly) {
      return await startWebAction(projectDir, normalizedOptions);
    }

    return await action(projectDir, normalizedOptions);
  },
  /* skipProjectValidation: */
  true,
  /* skipAuthCheck: */
  true);
  program.command('start:web [project-dir]').alias('web').description('Starts the Webpack dev server for web projects').urlOpts().allowOffline().asyncActionProjectDir(async (projectDir, options) => {
    return startWebAction(projectDir, (await normalizeOptionsAsync(projectDir, { ...options,
      webOnly: true
    })));
  },
  /* skipProjectValidation: */
  true,
  /* skipAuthCheck: */
  true);
};

exports.default = _default;
//# sourceMappingURL=../__sourcemaps__/commands/start.js.map