"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.run = run; function _fs() { const data = _interopRequireDefault(require("fs")); _fs = function () { return data; }; return data; } function _path() { const data = _interopRequireDefault(require("path")); _path = function () { return data; }; return data; } function _url() { const data = _interopRequireDefault(require("url")); _url = function () { return data; }; return data; } function _progress() { const data = _interopRequireDefault(require("progress")); _progress = function () { return data; }; return data; } function _last() { const data = _interopRequireDefault(require("lodash/last")); _last = function () { return data; }; return data; } function _compact() { const data = _interopRequireDefault(require("lodash/compact")); _compact = function () { return data; }; return data; } function _findLastIndex() { const data = _interopRequireDefault(require("lodash/findLastIndex")); _findLastIndex = function () { return data; }; return data; } function _boxen() { const data = _interopRequireDefault(require("boxen")); _boxen = function () { return data; }; return data; } function _bunyan() { const data = _interopRequireDefault(require("@expo/bunyan")); _bunyan = function () { return data; }; return data; } function _chalk() { const data = _interopRequireDefault(require("chalk")); _chalk = function () { return data; }; return data; } function _ora() { const data = _interopRequireDefault(require("ora")); _ora = function () { return data; }; return data; } function _simpleSpinner() { const data = _interopRequireDefault(require("@expo/simple-spinner")); _simpleSpinner = function () { return data; }; return data; } function _getenv() { const data = _interopRequireDefault(require("getenv")); _getenv = function () { return data; }; return data; } function _commander() { const data = _interopRequireWildcard(require("commander")); _commander = function () { return data; }; return data; } function _xdl() { const data = require("@expo/xdl"); _xdl = function () { return data; }; return data; } function ConfigUtils() { const data = _interopRequireWildcard(require("@expo/config")); ConfigUtils = function () { return data; }; return data; } function _accounts() { const data = require("./accounts"); _accounts = function () { return data; }; return data; } function _log() { const data = _interopRequireDefault(require("./log")); _log = function () { return data; }; return data; } function _update() { const data = _interopRequireDefault(require("./update")); _update = function () { return data; }; return data; } function _urlOpts() { const data = _interopRequireDefault(require("./urlOpts")); _urlOpts = function () { return data; }; return data; } function _package() { const data = _interopRequireDefault(require("../package.json")); _package = function () { return data; }; return data; } function _commands() { const data = require("./commands"); _commands = 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 }; } _xdl().Api.setClientName(_package().default.version); _xdl().ApiV2.setClientName(_package().default.version); // The following prototyped functions are not used here, but within in each file found in `./commands` // Extending commander to easily add more options to certain command line arguments _commander().Command.prototype.urlOpts = function () { _urlOpts().default.addOptions(this); return this; }; _commander().Command.prototype.allowOffline = function () { this.option('--offline', 'Allows this command to run while offline'); return this; }; _commander().default.on('--help', () => { (0, _log().default)(`To learn more about a specific command and its options use 'expo [command] --help'\n`); }); // asyncAction is a wrapper for all commands/actions to be executed after commander is done // parsing the command input _commander().Command.prototype.asyncAction = function (asyncFn, skipUpdateCheck) { return this.action(async (...args) => { if (!skipUpdateCheck) { try { await checkCliVersionAsync(); } catch (e) {} } try { let options = (0, _last().default)(args); if (options.output === 'raw') { _log().default.config.raw = true; } if (options.offline) { _xdl().Config.offline = true; } await asyncFn(...args); // After a command, flush the analytics queue so the program will not have any active timers // This allows node js to exit immediately _xdl().Analytics.flush(); } catch (err) { // TODO: Find better ways to consolidate error messages if (err.isCommandError) { _log().default.error(err.message); } else if (err._isApiError) { _log().default.error(_chalk().default.red(err.message)); } else if (err.isXDLError) { _log().default.error(err.message); } else { _log().default.error(err.message); // TODO: Is there a better way to do this? EXPO_DEBUG needs to be set to view the stack trace if (_getenv().default.boolish('EXPO_DEBUG', false)) { _log().default.error(_chalk().default.gray(err.stack)); } else { _log().default.error(_chalk().default.grey('Set EXPO_DEBUG=true in your env to view the stack trace.')); } } process.exit(1); } }); }; // asyncActionProjectDir captures the projectDirectory from the command line, // setting it to cwd if it is not provided. // Commands such as `start` and `publish` use this. // It does several things: // - Everything in asyncAction // - Checks if the user is logged in or out // - Checks for updates // - Attaches the bundling logger // - Checks if the project directory is valid or not // - Runs AsyncAction with the projectDir as an argument _commander().Command.prototype.asyncActionProjectDir = function (asyncFn, skipProjectValidation, skipAuthCheck) { this.option('--config [file]', 'Specify a path to app.json'); return this.asyncAction(async (projectDir, ...args) => { const opts = args[0]; if (!projectDir) { projectDir = process.cwd(); } else { projectDir = _path().default.resolve(process.cwd(), projectDir); } if (opts.config) { const pathToConfig = _path().default.resolve(process.cwd(), opts.config); if (!_fs().default.existsSync(pathToConfig)) { throw new Error(`File at provide config path does not exist: ${pathToConfig}`); } ConfigUtils().setCustomConfigPath(projectDir, pathToConfig); } const logLines = (msg, logFn) => { if (typeof msg === 'string') { for (let line of msg.split('\n')) { logFn(line); } } else { logFn(msg); } }; const logStackTrace = (chunk, logFn, nestedLogFn) => { let traceInfo; try { traceInfo = JSON.parse(chunk.msg); } catch (e) { return logFn(chunk.msg); } let { message, stack } = traceInfo; _log().default.addNewLineIfNone(); logFn(_chalk().default.bold(message)); const isLibraryFrame = line => { return line.startsWith('node_modules'); }; const stackFrames = (0, _compact().default)(stack.split('\n')); let lastAppCodeFrameIndex = (0, _findLastIndex().default)(stackFrames, line => { return !isLibraryFrame(line); }); let lastFrameIndexToLog = Math.min(stackFrames.length - 1, lastAppCodeFrameIndex + 2 // show max two more frames after last app code frame ); let unloggedFrames = stackFrames.length - lastFrameIndexToLog; // If we're only going to exclude one frame, just log them all if (unloggedFrames === 1) { lastFrameIndexToLog = stackFrames.length - 1; unloggedFrames = 0; } for (let i = 0; i <= lastFrameIndexToLog; i++) { let line = stackFrames[i]; if (!line) { continue; } else if (line.match(/react-native\/.*YellowBox.js/)) { continue; } if (line.startsWith('node_modules')) { nestedLogFn('- ' + line); } else { nestedLogFn('* ' + line); } } if (unloggedFrames > 0) { nestedLogFn(`- ... ${unloggedFrames} more stack frames from framework internals`); } _log().default.printNewLineBeforeNextLog(); }; const logWithLevel = chunk => { if (!chunk.msg) { return; } if (chunk.level <= _bunyan().default.INFO) { if (chunk.includesStack) { logStackTrace(chunk, _log().default, _log().default.nested); } else { logLines(chunk.msg, _log().default); } } else if (chunk.level === _bunyan().default.WARN) { if (chunk.includesStack) { logStackTrace(chunk, _log().default.warn, _log().default.nestedWarn); } else { logLines(chunk.msg, _log().default.warn); } } else { if (chunk.includesStack) { logStackTrace(chunk, _log().default.error, _log().default.nestedError); } else { logLines(chunk.msg, _log().default.error); } } }; let bar; // eslint-disable-next-line no-new new (_xdl().PackagerLogsStream)({ projectRoot: projectDir, onStartBuildBundle: () => { bar = new (_progress().default)('Building JavaScript bundle [:bar] :percent', { total: 100, clear: true, complete: '=', incomplete: ' ' }); _log().default.setBundleProgressBar(bar); }, onProgressBuildBundle: percent => { if (!bar || bar.complete) return; let ticks = percent - bar.curr; ticks > 0 && bar.tick(ticks); }, onFinishBuildBundle: (err, startTime, endTime) => { if (bar && !bar.complete) { bar.tick(100 - bar.curr); } if (bar) { _log().default.setBundleProgressBar(null); bar = null; if (err) { (0, _log().default)(_chalk().default.red('Failed building JavaScript bundle.')); } else { (0, _log().default)(_chalk().default.green(`Finished building JavaScript bundle in ${endTime.getTime() - startTime.getTime()}ms.`)); } } }, updateLogs: updater => { let newLogChunks = updater([]); newLogChunks.forEach(newLogChunk => { if (newLogChunk.issueId && newLogChunk.issueCleared) { return; } logWithLevel(newLogChunk); }); } }); // needed for validation logging to function _xdl().ProjectUtils.attachLoggerStream(projectDir, { stream: { write: chunk => { if (chunk.tag === 'device') { logWithLevel(chunk); } } }, type: 'raw' }); // The existing CLI modules only pass one argument to this function, so skipProjectValidation // will be undefined in most cases. we can explicitly pass a truthy value here to avoid // validation (eg for init) // // If the packager/manifest server is running and healthy, there is no need // to rerun Doctor because the directory was already checked previously // This is relevant for command such as `send` if (!skipProjectValidation && (await _xdl().Project.currentStatus(projectDir)) !== 'running') { let spinner = (0, _ora().default)('Making sure project is set up correctly...').start(); _log().default.setSpinner(spinner); // validate that this is a good projectDir before we try anything else let status = await _xdl().Doctor.validateLowLatencyAsync(projectDir); if (status === _xdl().Doctor.FATAL) { throw new Error(`There is an error with your project. See above logs for information.`); } spinner.stop(); _log().default.setSpinner(null); } // the existing CLI modules only pass one argument to this function, so skipProjectValidation // will be undefined in most cases. we can explicitly pass a truthy value here to avoid validation (eg for init) return asyncFn(projectDir, ...args); }); }; function runAsync(programName) { try { // Setup analytics _xdl().Analytics.setSegmentNodeKey('vGu92cdmVaggGA26s3lBX6Y5fILm8SQ7'); _xdl().Analytics.setVersionName(_package().default.version); _registerLogs(); _xdl().UserManager.setInteractiveAuthenticationCallback(_accounts().loginOrRegisterIfLoggedOut); if (process.env.SERVER_URL) { let serverUrl = process.env.SERVER_URL; if (!serverUrl.startsWith('http')) { serverUrl = `http://${serverUrl}`; } let parsedUrl = _url().default.parse(serverUrl); const port = parseInt(parsedUrl.port || ''); if (parsedUrl.hostname && port) { _xdl().Config.api.host = parsedUrl.hostname; _xdl().Config.api.port = port; } else { throw new Error('Environment variable SERVER_URL is not a valid url'); } } _xdl().Config.developerTool = _package().default.name; // Setup our commander instance _commander().default.name(programName); _commander().default.version(_package().default.version).option('-o, --output [format]', 'Output format. pretty (default), raw').option('--non-interactive', 'Fail, if an interactive prompt would be required to continue. Enabled by default if stdin is not a TTY.'); // Load each module found in ./commands by 'registering' it with our commander instance (0, _commands().registerCommands)(_commander().default); let subCommand = process.argv[2]; let argv = process.argv.filter(arg => { // Remove deprecated `--github` option here in order to fallback to password login/signup. if (subCommand === 'login' && arg === '--github') { _log().default.nestedWarn('GitHub login is not currently available.\nPlease log in with your Expo account.'); return false; } if (subCommand === 'register' && arg === '--github') { _log().default.nestedWarn('GitHub sign up is not currently available.'); return false; } return true; }); _commander().default.parse(argv); if (typeof _commander().default.nonInteractive === 'undefined') { // Commander doesn't initialize boolean args with default values. _commander().default.nonInteractive = !process.stdin.isTTY; } // Display a message if the user does not input a valid command if (subCommand) { let commands = []; _commander().default.commands.forEach(command => { commands.push(command['_name']); let alias = command['_alias']; if (alias) { commands.push(alias); } }); if (!commands.includes(subCommand)) { _log().default.warn(`"${subCommand}" is not an ${programName} command. See "${programName} --help" for the full list of commands.`); if (subCommand === 'detach') { (0, _log().default)('To eject your project to ExpoKit (previously "detach"), use `expo eject`.'); } } } else { _commander().default.help(); } } catch (e) { console.error(e); throw e; } } async function checkCliVersionAsync() { let { updateIsAvailable, current, latest, deprecated } = await _update().default.checkForUpdateAsync(); if (updateIsAvailable) { _log().default.nestedWarn((0, _boxen().default)(_chalk().default.green(`There is a new version of ${_package().default.name} available (${latest}). You are currently using ${_package().default.name} ${current} Install expo-cli globally using the package manager of your choice; for example: \`npm install -g ${_package().default.name}\` to get the latest version`), { borderColor: 'green', padding: 1 })); } if (deprecated) { _log().default.nestedWarn((0, _boxen().default)(_chalk().default.red(`This version of expo-cli is not supported anymore. It's highly recommended to update to the newest version. The API endpoints used in this version of expo-cli might not exist, any interaction with Expo servers may result in unexpected behaviour.`), { borderColor: 'red', padding: 1 })); } } function _registerLogs() { let stream = { stream: { write: chunk => { if (chunk.code) { switch (chunk.code) { case _xdl().NotificationCode.START_LOADING: _simpleSpinner().default.start(); return; case _xdl().NotificationCode.STOP_LOADING: _simpleSpinner().default.stop(); return; case _xdl().NotificationCode.DOWNLOAD_CLI_PROGRESS: return; } } if (chunk.level === _bunyan().default.INFO) { (0, _log().default)(chunk.msg); } else if (chunk.level === _bunyan().default.WARN) { _log().default.warn(chunk.msg); } else if (chunk.level >= _bunyan().default.ERROR) { _log().default.error(chunk.msg); } } }, type: 'raw' }; _xdl().Logger.notifications.addStream(stream); _xdl().Logger.global.addStream(stream); } async function writePathAsync() { let subCommand = process.argv[2]; if (subCommand === 'prepare-detached-build') { // This is being run from Android Studio or Xcode. Don't want to write PATH in this case. return; } await _xdl().Binaries.writePathToUserSettingsAsync(); } // This is the entry point of the CLI function run(programName) { (async function () { await Promise.all([writePathAsync(), runAsync(programName)]); })().catch(e => { console.error('Uncaught Error', e); process.exit(1); }); } //# sourceMappingURL=__sourcemaps__/exp.js.map